Skip to content

Commit dc17027

Browse files
committed
Replace NOP2 with CHECKLOCKTIMEVERIFY (BIP65)
<nLockTime> 1 CHECKLOCKTIMEVERIFY -> <nLockTime> 1 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. Thanks to Pieter Wuille for rebase. 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 48e9c57 commit dc17027

File tree

8 files changed

+247
-3
lines changed

8 files changed

+247
-3
lines changed

src/script/interpreter.cpp

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,70 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
335335
// Control
336336
//
337337
case OP_NOP:
338-
break;
338+
break;
339+
340+
case OP_CHECKLOCKTIMEVERIFY:
341+
{
342+
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
343+
// not enabled; treat as a NOP2
344+
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
345+
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
346+
}
347+
break;
348+
}
349+
350+
if (stack.size() < 1)
351+
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
352+
353+
// Type of locktime to verify. Currently the only type
354+
// defined is 1, which is to verify the nLockTime
355+
// absolutely. If the type is not recognised, the opcode is
356+
// treated as a NOP to allow for upgrades in the future.
357+
//
358+
// That said, for simplicity sake, we *do* require the
359+
// argument to be a (possibly minimal) number within the
360+
// numerical limits.
361+
const CScriptNum nType(stacktop(-1), fRequireMinimal);
362+
if (nType != 1)
363+
break;
364+
365+
// Only if the type is recognised do we require the stack
366+
// to have the second argument. The alternative, requiring
367+
// the stack to always have both arguments, would prohibit
368+
// future CLTV upgrades that don't need two arguments.
369+
if (stack.size() < 2)
370+
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
339371

340-
case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
372+
// Note that elsewhere numeric opcodes are limited to
373+
// operands in the range -2**31+1 to 2**31-1, however it is
374+
// legal for opcodes to produce results exceeding that
375+
// range. This limitation is implemented by CScriptNum's
376+
// default 4-byte limit.
377+
//
378+
// If we kept to that limit we'd have a year 2038 problem,
379+
// even though the nLockTime field in transactions
380+
// themselves is uint32 which only becomes meaningless
381+
// after the year 2106.
382+
//
383+
// Thus as a special case we tell CScriptNum to accept up
384+
// to 5-byte bignums, which are good until 2**32-1, the
385+
// same limit as the nLockTime field itself.
386+
const CScriptNum nLockTime(stacktop(-2), fRequireMinimal, 5);
387+
388+
// In the rare event that the argument may be < 0 due to
389+
// some arithmetic being done first, you can always use
390+
// 0 MAX 1 CHECKLOCKTIMEVERIFY.
391+
if (nLockTime < 0)
392+
return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);
393+
394+
// Actually compare the specified lock time with the transaction.
395+
if (!checker.CheckLockTime(nLockTime))
396+
return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);
397+
398+
break;
399+
}
400+
401+
case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5:
341402
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
342403
{
343404
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
@@ -1084,6 +1145,43 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
10841145
return true;
10851146
}
10861147

1148+
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
1149+
{
1150+
// There are two times of nLockTime: lock-by-blockheight
1151+
// and lock-by-blocktime, distinguished by whether
1152+
// nLockTime < LOCKTIME_THRESHOLD.
1153+
//
1154+
// We want to compare apples to apples, so fail the script
1155+
// unless the type of nLockTime being tested is the same as
1156+
// the nLockTime in the transaction.
1157+
if (!(
1158+
(txTo->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
1159+
(txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
1160+
))
1161+
return false;
1162+
1163+
// Now that we know we're comparing apples-to-apples, the
1164+
// comparison is a simple numeric one.
1165+
if (nLockTime > (int64_t)txTo->nLockTime)
1166+
return false;
1167+
1168+
// Finally the nLockTime feature can be disabled and thus
1169+
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
1170+
// finalized by setting nSequence to maxint. The
1171+
// transaction would be allowed into the blockchain, making
1172+
// the opcode ineffective.
1173+
//
1174+
// Testing if this vin is not final is sufficient to
1175+
// prevent this condition. Alternatively we could test all
1176+
// inputs, but testing just this input minimizes the data
1177+
// required to prove correct CHECKLOCKTIMEVERIFY execution.
1178+
if (txTo->vin[nIn].IsFinal())
1179+
return false;
1180+
1181+
return true;
1182+
}
1183+
1184+
10871185
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
10881186
{
10891187
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);

src/script/interpreter.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ enum
7676
// (softfork safe, BIP62 rule 6)
7777
// Note: CLEANSTACK should never be used without P2SH.
7878
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
79+
80+
// Verify CHECKLOCKTIMEVERIFY (BIP65)
81+
//
82+
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
7983
};
8084

8185
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
@@ -88,6 +92,11 @@ class BaseSignatureChecker
8892
return false;
8993
}
9094

95+
virtual bool CheckLockTime(const CScriptNum& nLockTime) const
96+
{
97+
return false;
98+
}
99+
91100
virtual ~BaseSignatureChecker() {}
92101
};
93102

@@ -103,6 +112,7 @@ class TransactionSignatureChecker : public BaseSignatureChecker
103112
public:
104113
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
105114
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
115+
bool CheckLockTime(const CScriptNum& nLockTime) const;
106116
};
107117

108118
class MutableTransactionSignatureChecker : public TransactionSignatureChecker

src/script/script.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ enum opcodetype
154154
// expansion
155155
OP_NOP1 = 0xb0,
156156
OP_NOP2 = 0xb1,
157+
OP_CHECKLOCKTIMEVERIFY = OP_NOP2,
157158
OP_NOP3 = 0xb2,
158159
OP_NOP4 = 0xb3,
159160
OP_NOP5 = 0xb4,

src/script/script_error.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ const char* ScriptErrorString(const ScriptError serror)
4747
return "OP_RETURN was encountered";
4848
case SCRIPT_ERR_UNBALANCED_CONDITIONAL:
4949
return "Invalid OP_IF construction";
50+
case SCRIPT_ERR_NEGATIVE_LOCKTIME:
51+
return "Negative locktime";
52+
case SCRIPT_ERR_UNSATISFIED_LOCKTIME:
53+
return "Locktime requirement not satisfied";
5054
case SCRIPT_ERR_SIG_HASHTYPE:
5155
return "Signature hash type missing or not understood";
5256
case SCRIPT_ERR_SIG_DER:

src/script/script_error.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ typedef enum ScriptError_t
3535
SCRIPT_ERR_INVALID_ALTSTACK_OPERATION,
3636
SCRIPT_ERR_UNBALANCED_CONDITIONAL,
3737

38+
/* OP_CHECKLOCKTIMEVERIFY */
39+
SCRIPT_ERR_NEGATIVE_LOCKTIME,
40+
SCRIPT_ERR_UNSATISFIED_LOCKTIME,
41+
3842
/* BIP62 */
3943
SCRIPT_ERR_SIG_HASHTYPE,
4044
SCRIPT_ERR_SIG_DER,

src/test/data/tx_invalid.json

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,78 @@
120120
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
121121
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510100ffffffff010000000000000000016a00000000", "P2SH"],
122122

123+
["CHECKLOCKTIMEVERIFY tests"],
124+
125+
["By-height locks, with argument just beyond tx nLockTime"],
126+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 1 NOP2"]],
127+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
128+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1 NOP2"]],
129+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
130+
131+
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundries)"],
132+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 1 NOP2"]],
133+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
134+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 1 NOP2"]],
135+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
136+
137+
["Argument missing"],
138+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP2"]],
139+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
140+
141+
["Argument negative with by-blockheight nLockTime=0"],
142+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 1 NOP2"]],
143+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
144+
145+
["Argument negative with by-blocktime nLockTime=500,000,000"],
146+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 1 NOP2"]],
147+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
148+
149+
["Input locked"],
150+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 1 NOP2"]],
151+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
152+
153+
["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"],
154+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 1 NOP2"] ,
155+
["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]],
156+
"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
157+
158+
["Argument/tx height/time mismatch, both versions"],
159+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 1 NOP2"]],
160+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
161+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1 NOP2"]],
162+
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
163+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 1 NOP2"]],
164+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
165+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 1 NOP2"]],
166+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
167+
168+
["Argument 2^32 with nLockTime=2^32-1"],
169+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 1 NOP2"]],
170+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
171+
172+
["Same, but with nLockTime=2^31-1"],
173+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 1 NOP2"]],
174+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"],
175+
176+
["6 byte non-minimally-encoded arguments are invalid even in their contents are valid"],
177+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 1 NOP2"]],
178+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
179+
180+
["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"],
181+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, ""]],
182+
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000035151b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
183+
184+
["Failure due to failing CHECKLOCKTIMEVERIFY in redeemScript"],
185+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x9c0876b427ee3c9389be376e0071730a76714818 EQUAL"]],
186+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000004035151b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
187+
188+
["The type argument must be a valid number within numerical limits"],
189+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 2147483648 NOP2 1"]],
190+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
191+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 -2147483648 NOP2 1"]],
192+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
193+
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 0x05 0100000000 NOP2 1"]],
194+
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
123195

124196
["Make diffs cleaner by leaving a comment here without comma at the end"]
125197
]

0 commit comments

Comments
 (0)