mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
Replace NOP3 with CHECKSEQUENCEVERIFY (BIPXX)
<nInvSequence> CHECKSEQUENCEVERIFY -> <nInvSequence> Fails if ~txin.nSequence < nInvSequence (the nSequence field of the txin is bit-inverted before the comparison), allowing funds of a txout to be locked for a number of blocks or a duration of time after its inclusion in a block. Only the logic and unit tests are implemented; this commit does not have changes to policy or consensus behavior.
This commit is contained in:
parent
2affed549a
commit
23f42e61dd
6 changed files with 175 additions and 10 deletions
|
|
@ -379,7 +379,47 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
|||
break;
|
||||
}
|
||||
|
||||
case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5:
|
||||
case OP_CHECKSEQUENCEVERIFY:
|
||||
{
|
||||
if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
|
||||
// not enabled; treat as a NOP3
|
||||
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
||||
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (stack.size() < 1)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
// Note that unlike CHECKLOCKTIMEVERIFY we do not need to
|
||||
// accept 5-byte bignums since any value greater than or
|
||||
// equal to SEQUENCE_THRESHOLD (= 1 << 31) will be rejected
|
||||
// anyway. This limitation just happens to coincide with
|
||||
// CScriptNum's default 4-byte limit with an explicit sign
|
||||
// bit.
|
||||
//
|
||||
// This means there is a maximum relative lock time of 52
|
||||
// years, even though the nSequence field in transactions
|
||||
// themselves is uint32_t and could allow a relative lock
|
||||
// time of up to 120 years.
|
||||
const CScriptNum nInvSequence(stacktop(-1), fRequireMinimal);
|
||||
|
||||
// In the rare event that the argument may be < 0 due to
|
||||
// some arithmetic being done first, you can always use
|
||||
// 0 MAX CHECKSEQUENCEVERIFY.
|
||||
if (nInvSequence < 0)
|
||||
return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);
|
||||
|
||||
// Actually compare the specified inverse sequence number
|
||||
// with the input.
|
||||
if (!checker.CheckLockTime(nInvSequence, true))
|
||||
return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_NOP1: case OP_NOP4: case OP_NOP5:
|
||||
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
|
||||
{
|
||||
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
|
|
@ -1125,8 +1165,21 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
|
|||
return true;
|
||||
}
|
||||
|
||||
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
|
||||
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime, bool fSequence) const
|
||||
{
|
||||
// Relative lock times are supported by comparing the passed
|
||||
// in lock time to the sequence number of the input. All other
|
||||
// logic is the same, all that differs is what we are comparing
|
||||
// the lock time to.
|
||||
int64_t txToLockTime;
|
||||
if (fSequence) {
|
||||
txToLockTime = (int64_t)~txTo->vin[nIn].nSequence;
|
||||
if (txToLockTime >= SEQUENCE_THRESHOLD)
|
||||
return false;
|
||||
} else {
|
||||
txToLockTime = (int64_t)txTo->nLockTime;
|
||||
}
|
||||
|
||||
// There are two types of nLockTime: lock-by-blockheight
|
||||
// and lock-by-blocktime, distinguished by whether
|
||||
// nLockTime < LOCKTIME_THRESHOLD.
|
||||
|
|
@ -1135,14 +1188,14 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
|
|||
// 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)
|
||||
(txToLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
|
||||
(txToLockTime >= 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 > txToLockTime)
|
||||
return false;
|
||||
|
||||
// Finally the nLockTime feature can be disabled and thus
|
||||
|
|
@ -1155,7 +1208,7 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
|
|||
// 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].nSequence)
|
||||
if (!fSequence && !~txTo->vin[nIn].nSequence)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,10 @@ enum
|
|||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
|
||||
|
||||
// Verify CHECKLOCKTIMEVERIFY (BIP65)
|
||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9)
|
||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
|
||||
|
||||
// support CHECKSEQUENCEVERIFY opcode
|
||||
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10)
|
||||
};
|
||||
|
||||
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
|
|
@ -84,7 +87,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool CheckLockTime(const CScriptNum& nLockTime) const
|
||||
virtual bool CheckLockTime(const CScriptNum& nLockTime, bool fSequence = false) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -104,7 +107,7 @@ protected:
|
|||
public:
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
|
||||
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
|
||||
bool CheckLockTime(const CScriptNum& nLockTime) const;
|
||||
bool CheckLockTime(const CScriptNum& nLockTime, bool fSequence = false) const;
|
||||
};
|
||||
|
||||
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ enum opcodetype
|
|||
OP_NOP2 = 0xb1,
|
||||
OP_CHECKLOCKTIMEVERIFY = OP_NOP2,
|
||||
OP_NOP3 = 0xb2,
|
||||
OP_CHECKSEQUENCEVERIFY = OP_NOP3,
|
||||
OP_NOP4 = 0xb3,
|
||||
OP_NOP5 = 0xb4,
|
||||
OP_NOP6 = 0xb5,
|
||||
|
|
|
|||
|
|
@ -168,5 +168,72 @@
|
|||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
|
||||
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||
|
||||
["CHECKSEQUENCEVERIFY tests"],
|
||||
|
||||
["By-height locks, with argument just beyond ~txin.nSequence"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000019b32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["By-time locks, with argument just beyond ~txin.nSequence (but within numerical boundries)"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Argument missing"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Argument negative with by-blockheight ~txin.nSequence=0"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Argument negative with by-blocktime ~txin.nSequence=500,000,000"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Another input being unlocked isn't sufficient; the CHECKSEQUENCEVERIFY-using input must be unlocked"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"] ,
|
||||
["0000000000000000000000000000000000000000000000000000000000000200", 1, "0 NOP3 1"]],
|
||||
"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Argument/tx height/time mismatch, both versions"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000009b32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Argument 2^32 with nLockTime=2^32-1"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Same, but with nLockTime=2^31-1"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["An ADD producing a 5-byte result that is out of bounds"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 1ADD NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["5 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Failure due to failing CHECKSEQUENCEVERIFY in scriptSig"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Failure due to failing CHECKSEQUENCEVERIFY in redeemScript"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]],
|
||||
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -220,5 +220,45 @@
|
|||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
|
||||
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||
|
||||
["CHECKSEQUENCEVERIFY tests"],
|
||||
|
||||
["By-height locks, with argument == 0 and == ~txin.nSequence"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000009b32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000009b32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["By-time locks, with argument just beyond ~txin.nSequence (but within numerical boundries)"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Any non-maxint nSequence is fine"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Input locked"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["The argument can be calculated rather than created directly by a PUSHDATA"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP3 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Valid CHECKSEQUENCEVERIFY in scriptSig"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Valid CHECKSEQUENCEVERIFY in redeemScript"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]],
|
||||
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
|
|||
(string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA)
|
||||
(string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY)
|
||||
(string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
(string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY);
|
||||
(string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
||||
(string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY);
|
||||
|
||||
unsigned int ParseScriptFlags(string strFlags)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue