mirror of
https://github.com/bitcoin/bips.git
synced 2025-03-04 11:08:05 +01:00
Add type field to CHECKLOCKTIMEVERIFY (BIP65)
Allows for future upgrades, e.g. relative CLTV.
This commit is contained in:
parent
2ea19daaa0
commit
400f79095d
1 changed files with 59 additions and 27 deletions
|
@ -16,11 +16,12 @@ some point in the future.
|
||||||
|
|
||||||
==Summary==
|
==Summary==
|
||||||
|
|
||||||
CHECKLOCKTIMEVERIFY redefines the existing NOP2 opcode. When executed it
|
CHECKLOCKTIMEVERIFY redefines the existing NOP2 opcode. When executed with the
|
||||||
compares the top item on the stack to the nLockTime field of the transaction
|
top item of the stack set to 1 it compares the second from top item on the
|
||||||
containing the scriptSig. If that top stack item is greater than the transaction
|
stack to the nLockTime field of the transaction containing the scriptSig. If
|
||||||
nLockTime the script fails immediately, otherwise script evaluation continues
|
that stack item is greater than the transaction nLockTime the script fails
|
||||||
as though a NOP was executed.
|
immediately, otherwise script evaluation continues as though a NOP was
|
||||||
|
executed.
|
||||||
|
|
||||||
The nLockTime field in a transaction prevents the transaction from being mined
|
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
|
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:
|
the form:
|
||||||
|
|
||||||
IF
|
IF
|
||||||
<now + 3 months> CHECKLOCKTIMEVERIFY DROP
|
<now + 3 months> 1 CHECKLOCKTIMEVERIFY DROP
|
||||||
<Lenny's pubkey> CHECKSIGVERIFY
|
<Lenny's pubkey> CHECKSIGVERIFY
|
||||||
1
|
1
|
||||||
ELSE
|
ELSE
|
||||||
|
@ -113,7 +114,7 @@ scriptPubKeys of the following form are used instead:
|
||||||
IF
|
IF
|
||||||
<service pubkey> CHECKSIGVERIFY
|
<service pubkey> CHECKSIGVERIFY
|
||||||
ELSE
|
ELSE
|
||||||
<expiry time> CHECKLOCKTIMEVERIFY DROP
|
<expiry time> 1 CHECKLOCKTIMEVERIFY DROP
|
||||||
ENDIF
|
ENDIF
|
||||||
<user pubkey> CHECKSIG
|
<user pubkey> CHECKSIG
|
||||||
|
|
||||||
|
@ -149,7 +150,7 @@ scriptPubKeys of the following form:
|
||||||
HASH160 <Hash160(encryption key)> EQUALVERIFY
|
HASH160 <Hash160(encryption key)> EQUALVERIFY
|
||||||
<publisher pubkey> CHECKSIG
|
<publisher pubkey> CHECKSIG
|
||||||
ELSE
|
ELSE
|
||||||
<expiry time> CHECKLOCKTIMEVERIFY DROP
|
<expiry time> 1 CHECKLOCKTIMEVERIFY DROP
|
||||||
<buyer pubkey> CHECKSIG
|
<buyer pubkey> CHECKSIG
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
|
@ -188,17 +189,38 @@ transaction output ''can'' be spent.
|
||||||
Refer to the reference implementation, reproduced below, for the precise
|
Refer to the reference implementation, reproduced below, for the precise
|
||||||
semantics and detailed rationale for those semantics.
|
semantics and detailed rationale for those semantics.
|
||||||
|
|
||||||
case OP_NOP2:
|
|
||||||
{
|
|
||||||
// CHECKLOCKTIMEVERIFY
|
|
||||||
//
|
|
||||||
// (nLockTime -- nLockTime )
|
|
||||||
|
|
||||||
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY))
|
case OP_CHECKLOCKTIMEVERIFY:
|
||||||
break; // not enabled; treat as a NOP
|
{
|
||||||
|
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)
|
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
|
// Note that elsewhere numeric opcodes are limited to
|
||||||
// operands in the range -2**31+1 to 2**31-1, however it is
|
// 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
|
// Thus as a special case we tell CScriptNum to accept up
|
||||||
// to 5-byte bignums, which are good until 2**32-1, the
|
// to 5-byte bignums, which are good until 2**32-1, the
|
||||||
// same limit as the nLockTime field itself.
|
// 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
|
// In the rare event that the argument may be < 0 due to
|
||||||
// some arithmetic being done first, you can always use
|
// some arithmetic being done first, you can always use
|
||||||
// 0 MAX CHECKLOCKTIMEVERIFY.
|
// 0 MAX 1 CHECKLOCKTIMEVERIFY.
|
||||||
if (nLockTime < 0)
|
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
|
// There are two times of nLockTime: lock-by-blockheight
|
||||||
// and lock-by-blocktime, distinguished by whether
|
// and lock-by-blocktime, distinguished by whether
|
||||||
// nLockTime < LOCKTIME_THRESHOLD.
|
// 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
|
// unless the type of nLockTime being tested is the same as
|
||||||
// the nLockTime in the transaction.
|
// the nLockTime in the transaction.
|
||||||
if (!(
|
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;
|
return false;
|
||||||
|
|
||||||
// Now that we know we're comparing apples-to-apples, the
|
// Now that we know we're comparing apples-to-apples, the
|
||||||
// comparison is a simple numeric one.
|
// comparison is a simple numeric one.
|
||||||
if (nLockTime > (int64_t)txTo.nLockTime)
|
if (nLockTime > (int64_t)txTo->nLockTime)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Finally the nLockTime feature can be disabled and thus
|
// 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
|
// prevent this condition. Alternatively we could test all
|
||||||
// inputs, but testing just this input minimizes the data
|
// inputs, but testing just this input minimizes the data
|
||||||
// required to prove correct CHECKLOCKTIMEVERIFY execution.
|
// required to prove correct CHECKLOCKTIMEVERIFY execution.
|
||||||
if (txTo.vin[nIn].IsFinal())
|
if (txTo->vin[nIn].IsFinal())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
break;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
https://github.com/petertodd/bitcoin/commit/ab0f54f38e08ee1e50ff72f801680ee84d0f1bf4
|
|
||||||
|
https://github.com/petertodd/bitcoin/commit/dc17027f2c37b97ce5b40154a64f18c16a72ee18
|
||||||
|
|
||||||
|
|
||||||
==Upgrade and Testing Plan==
|
==Upgrade and Testing Plan==
|
||||||
|
|
Loading…
Add table
Reference in a new issue