1
0
Fork 0
mirror of https://github.com/bitcoin/bips.git synced 2025-03-04 03:03:53 +01:00

Add type field to CHECKLOCKTIMEVERIFY (BIP65)

Allows for future upgrades, e.g. relative CLTV.
This commit is contained in:
Peter Todd 2015-05-09 04:22:02 -04:00
parent 2ea19daaa0
commit 400f79095d
No known key found for this signature in database
GPG key ID: 2481403DA5F091FB

View file

@ -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
@ -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
@ -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
@ -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
@ -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
@ -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.
@ -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
@ -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==