Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 59 additions & 27 deletions bip-0065.mediawiki
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ some point in the future.

==Summary==

CHECKLOCKTIMEVERIFY redefines the existing NOP2 opcode. When executed it
compares the top item on the stack to the nLockTime field of the transaction
containing the scriptSig. If that top stack item is greater than the transaction
nLockTime the script fails immediately, otherwise script evaluation continues
as though a NOP was executed.
CHECKLOCKTIMEVERIFY redefines the existing NOP2 opcode. When executed with the
top item of the stack set to 1 it compares the second from top item on the
stack to the nLockTime field of the transaction containing the scriptSig. If
that stack item is greater than the transaction nLockTime the script fails
immediately, otherwise script evaluation continues as though a NOP was
executed.

The nLockTime field in a transaction prevents the transaction from being mined
until either a certain block height, or block time, has been reached. By
Expand Down Expand Up @@ -64,7 +65,7 @@ However with CHECKLOCKTIMEVERIFY the funds can be stored in scriptPubKeys of
the form:

IF
<now + 3 months> CHECKLOCKTIMEVERIFY DROP
<now + 3 months> 1 CHECKLOCKTIMEVERIFY DROP
<Lenny's pubkey> CHECKSIGVERIFY
1
ELSE
Expand Down Expand Up @@ -113,7 +114,7 @@ scriptPubKeys of the following form are used instead:
IF
<service pubkey> CHECKSIGVERIFY
ELSE
<expiry time> CHECKLOCKTIMEVERIFY DROP
<expiry time> 1 CHECKLOCKTIMEVERIFY DROP
ENDIF
<user pubkey> CHECKSIG

Expand Down Expand Up @@ -149,7 +150,7 @@ scriptPubKeys of the following form:
HASH160 <Hash160(encryption key)> EQUALVERIFY
<publisher pubkey> CHECKSIG
ELSE
<expiry time> CHECKLOCKTIMEVERIFY DROP
<expiry time> 1 CHECKLOCKTIMEVERIFY DROP
<buyer pubkey> CHECKSIG
ENDIF

Expand Down Expand Up @@ -188,17 +189,38 @@ transaction output ''can'' be spent.
Refer to the reference implementation, reproduced below, for the precise
semantics and detailed rationale for those semantics.

case OP_NOP2:
{
// CHECKLOCKTIMEVERIFY
//
// (nLockTime -- nLockTime )

if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY))
break; // not enabled; treat as a NOP
case OP_CHECKLOCKTIMEVERIFY:
{
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
// not enabled; treat as a NOP2
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
}
break;
}

if (stack.size() < 1)
return false;
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);

// Type of locktime to verify. Currently the only type
// defined is 1, which is to verify the nLockTime
// absolutely. If the type is not recognised, the opcode is
// treated as a NOP to allow for upgrades in the future.
//
// That said, for simplicity sake, we *do* require the
// argument to be a (possibly minimal) number within the
// numerical limits.
const CScriptNum nType(stacktop(-1), fRequireMinimal);
if (nType != 1)
break;

// Only if the type is recognised do we require the stack
// to have the second argument. The alternative, requiring
// the stack to always have both arguments, would prohibit
// future CLTV upgrades that don't need two arguments.
if (stack.size() < 2)
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);

// Note that elsewhere numeric opcodes are limited to
// operands in the range -2**31+1 to 2**31-1, however it is
Expand All @@ -214,14 +236,24 @@ semantics and detailed rationale for those semantics.
// Thus as a special case we tell CScriptNum to accept up
// to 5-byte bignums, which are good until 2**32-1, the
// same limit as the nLockTime field itself.
const CScriptNum nLockTime(stacktop(-1), 5);
const CScriptNum nLockTime(stacktop(-2), fRequireMinimal, 5);

// In the rare event that the argument may be < 0 due to
// some arithmetic being done first, you can always use
// 0 MAX CHECKLOCKTIMEVERIFY.
// 0 MAX 1 CHECKLOCKTIMEVERIFY.
if (nLockTime < 0)
return false;
return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);

// Actually compare the specified lock time with the transaction.
if (!checker.CheckLockTime(nLockTime))
return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);

break;
}


bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
{
// There are two times of nLockTime: lock-by-blockheight
// and lock-by-blocktime, distinguished by whether
// nLockTime < LOCKTIME_THRESHOLD.
Expand All @@ -230,14 +262,14 @@ semantics and detailed rationale for those semantics.
// unless the type of nLockTime being tested is the same as
// the nLockTime in the transaction.
if (!(
(txTo.nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
(txTo.nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
))
(txTo->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
(txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
))
return false;

// Now that we know we're comparing apples-to-apples, the
// comparison is a simple numeric one.
if (nLockTime > (int64_t)txTo.nLockTime)
if (nLockTime > (int64_t)txTo->nLockTime)
return false;

// Finally the nLockTime feature can be disabled and thus
Expand All @@ -250,14 +282,14 @@ semantics and detailed rationale for those semantics.
// prevent this condition. Alternatively we could test all
// inputs, but testing just this input minimizes the data
// required to prove correct CHECKLOCKTIMEVERIFY execution.
if (txTo.vin[nIn].IsFinal())
if (txTo->vin[nIn].IsFinal())
return false;

break;

return true;
}

https://github.com/petertodd/bitcoin/commit/ab0f54f38e08ee1e50ff72f801680ee84d0f1bf4

https://github.com/petertodd/bitcoin/commit/dc17027f2c37b97ce5b40154a64f18c16a72ee18


==Upgrade and Testing Plan==
Expand Down