Skip to content

Commit ab0f54f

Browse files
committed
Replace NOP2 with CHECKLOCKTIMEVERIFY
<nLockTime> CHECKLOCKTIMEVERIFY -> <nLockTime> Fails if tx.nLockTime < nLockTime, allowing the funds in a txout to be locked until some block height or block time in the future is reached. Only the logic and unittests are implemented; this commit does not have any actual soft-fork logic in it. Credit goes to Gregory Maxwell for the suggestion of comparing the argument against the transaction nLockTime rather than the current time/blockheight directly.
1 parent b49b972 commit ab0f54f

File tree

5 files changed

+181
-1
lines changed

5 files changed

+181
-1
lines changed

src/script/interpreter.cpp

+71-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,77 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
217217
// Control
218218
//
219219
case OP_NOP:
220-
case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
220+
case OP_NOP1:
221+
break;
222+
case OP_NOP2:
223+
{
224+
// CHECKLOCKTIMEVERIFY
225+
//
226+
// (nLockTime -- nLockTime )
227+
228+
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY))
229+
break; // not enabled; treat as a NOP
230+
231+
if (stack.size() < 1)
232+
return false;
233+
234+
// Note that elsewhere numeric opcodes are limited to
235+
// operands in the range -2**31+1 to 2**31-1, however it is
236+
// legal for opcodes to produce results exceeding that
237+
// range. This limitation is implemented by CScriptNum's
238+
// default 4-byte limit.
239+
//
240+
// If we kept to that limit we'd have a year 2038 problem,
241+
// even though the nLockTime field in transactions
242+
// themselves is uint32 which only becomes meaningless
243+
// after the year 2106.
244+
//
245+
// Thus as a special case we tell CScriptNum to accept up
246+
// to 5-byte bignums, which are good until 2**32-1, the
247+
// same limit as the nLockTime field itself.
248+
const CScriptNum nLockTime(stacktop(-1), 5);
249+
250+
// In the rare event that the argument may be < 0 due to
251+
// some arithmetic being done first, you can always use
252+
// 0 MAX CHECKLOCKTIMEVERIFY.
253+
if (nLockTime < 0)
254+
return false;
255+
256+
// There are two times of nLockTime: lock-by-blockheight
257+
// and lock-by-blocktime, distinguished by whether
258+
// nLockTime < LOCKTIME_THRESHOLD.
259+
//
260+
// We want to compare apples to apples, so fail the script
261+
// unless the type of nLockTime being tested is the same as
262+
// the nLockTime in the transaction.
263+
if (!(
264+
(txTo.nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
265+
(txTo.nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
266+
))
267+
return false;
268+
269+
// Now that we know we're comparing apples-to-apples, the
270+
// comparison is a simple numeric one.
271+
if (nLockTime > (int64_t)txTo.nLockTime)
272+
return false;
273+
274+
// Finally the nLockTime feature can be disabled and thus
275+
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
276+
// finalized by setting nSequence to maxint. The
277+
// transaction would be allowed into the blockchain, making
278+
// the opcode ineffective.
279+
//
280+
// Testing if this vin is not final is sufficient to
281+
// prevent this condition. Alternatively we could test all
282+
// inputs, but testing just this input minimizes the data
283+
// required to prove correct CHECKLOCKTIMEVERIFY execution.
284+
if (txTo.vin[nIn].IsFinal())
285+
return false;
286+
287+
break;
288+
289+
}
290+
case OP_NOP3: case OP_NOP4: case OP_NOP5:
221291
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
222292
break;
223293

src/script/interpreter.h

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ enum
3232
SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC)
3333
SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it)
3434
SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
35+
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 5), // support CHECKLOCKTIMEVERIFY opcode
3536
};
3637

3738
bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);

src/test/data/tx_invalid.json

+66
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,71 @@
103103
[[["ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b", 0, "0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT"]],
104104
"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", "P2SH"],
105105

106+
107+
["CHECKLOCKTIMEVERIFY tests"],
108+
109+
["By-height locks, with argument just beyond tx nLockTime"],
110+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP2 1"]],
111+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
112+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
113+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
114+
115+
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundries)"],
116+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP2 1"]],
117+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
118+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
119+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
120+
121+
["Argument missing"],
122+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP2 1"]],
123+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
124+
125+
["Argument negative with by-blockheight nLockTime=0"],
126+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
127+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
128+
129+
["Argument negative with by-blocktime nLockTime=500,000,000"],
130+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
131+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
132+
133+
["Input locked"],
134+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
135+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
136+
137+
["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"],
138+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"] ,
139+
["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]],
140+
"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
141+
142+
["Argument/tx height/time mismatch, both versions"],
143+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
144+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
145+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
146+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
147+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
148+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
149+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
150+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
151+
152+
["Argument 2^32 with nLockTime=2^32-1"],
153+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP2 1"]],
154+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
155+
156+
["Same, but with nLockTime=2^31-1"],
157+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP2 1"]],
158+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"],
159+
160+
["6 byte non-minimally-encoded arguments are invalid even in their contents are valid"],
161+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP2 1"]],
162+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
163+
164+
["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"],
165+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
166+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
167+
168+
["Failure due to failing CHECKLOCKTIMEVERIFY in redeemScript"],
169+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
170+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
171+
106172
["Make diffs cleaner by leaving a comment here without comma at the end"]
107173
]

src/test/data/tx_valid.json

+42
Original file line numberDiff line numberDiff line change
@@ -178,5 +178,47 @@
178178
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
179179

180180

181+
["CHECKLOCKTIMEVERIFY tests"],
182+
183+
["By-height locks, with argument == 0 and == tx nLockTime"],
184+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
185+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
186+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
187+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
188+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
189+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
190+
191+
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundries)"],
192+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
193+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
194+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
195+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
196+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
197+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
198+
199+
["Any non-maxint nSequence is fine"],
200+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
201+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
202+
203+
["The argument can be calculated rather than created directly by a PUSHDATA"],
204+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP2 1"]],
205+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
206+
207+
["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"],
208+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD NOP2 1"]],
209+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
210+
211+
["5 byte non-minimally-encoded arguments are valid"],
212+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP2 1"]],
213+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
214+
215+
["Valid CHECKLOCKTIMEVERIFY in scriptSig"],
216+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
217+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
218+
219+
["Valid CHECKLOCKTIMEVERIFY in redeemScript"],
220+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
221+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
222+
181223
["Make diffs cleaner by leaving a comment here without comma at the end"]
182224
]

src/test/transaction_tests.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ unsigned int ParseScriptFlags(string strFlags){
4040
mapFlagNames["STRICTENC"] = SCRIPT_VERIFY_STRICTENC;
4141
mapFlagNames["LOW_S"] = SCRIPT_VERIFY_LOW_S;
4242
mapFlagNames["NULLDUMMY"] = SCRIPT_VERIFY_NULLDUMMY;
43+
mapFlagNames["CHECKLOCKTIMEVERIFY"] = SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
4344
}
4445

4546
BOOST_FOREACH(string word, words)

0 commit comments

Comments
 (0)