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:
Mark Friedenbach 2015-05-18 17:20:46 -07:00
parent 9d0c08e3bf
commit f2d5631be0
7 changed files with 190 additions and 10 deletions

View file

@ -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)
@ -1126,8 +1166,30 @@ 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) {
// Fail under all circumstances if the transaction's version
// number is not set high enough to enable enforced sequence
// number rules.
if (txTo->nVersion < 2)
return false;
// Sequence number must be inverted to convert it into a
// relative lock-time.
txToLockTime = (int64_t)~txTo->vin[nIn].nSequence;
// Sequence numbers under SEQUENCE_THRESHOLD are not consensus
// constrained.
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.
@ -1136,14 +1198,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
@ -1156,7 +1218,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].IsFinal())
if (!fSequence && txTo->vin[nIn].IsFinal())
return false;
return true;

View file

@ -80,6 +80,9 @@ enum
// Verify CHECKLOCKTIMEVERIFY (BIP65)
//
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);
@ -92,7 +95,7 @@ public:
return false;
}
virtual bool CheckLockTime(const CScriptNum& nLockTime) const
virtual bool CheckLockTime(const CScriptNum& nLockTime, bool fSequence = false) const
{
return false;
}
@ -112,7 +115,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

View file

@ -161,6 +161,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,

View file

@ -35,7 +35,7 @@ typedef enum ScriptError_t
SCRIPT_ERR_INVALID_ALTSTACK_OPERATION,
SCRIPT_ERR_UNBALANCED_CONDITIONAL,
/* CheckLockTime */
/* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */
SCRIPT_ERR_NEGATIVE_LOCKTIME,
SCRIPT_ERR_UNSATISFIED_LOCKTIME,

View file

@ -185,5 +185,78 @@
[[["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"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000019b32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["By-time locks, with argument just beyond ~txin.nSequence (but within numerical boundries)"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument missing"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument negative with by-blockheight ~txin.nSequence=0"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument negative with by-blocktime ~txin.nSequence=500,000,000"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "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"]],
"030000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument/tx height/time mismatch, both versions"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000009b32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument 2^32 with nLockTime=2^32-1"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Same, but with nLockTime=2^31-1"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["An ADD producing a 5-byte result that is out of bounds"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 1ADD NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["5 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Failure due to failing CHECKSEQUENCEVERIFY in scriptSig"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
"03000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Failure due to failing CHECKSEQUENCEVERIFY in redeemScript"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]],
"0300000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Failure due to insufficient tx.nVersion (<=2)"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Make diffs cleaner by leaving a comment here without comma at the end"]
]

View file

@ -229,5 +229,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"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000009b32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000009b32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["By-time locks, with argument just beyond ~txin.nSequence (but within numerical boundries)"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Any non-maxint nSequence is fine"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Input locked"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["The argument can be calculated rather than created directly by a PUSHDATA"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP3 1"]],
"030000000100010000000000000000000000000000000000000000000000000000000000000000000000ff9a32e20100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Valid CHECKSEQUENCEVERIFY in scriptSig"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
"03000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Valid CHECKSEQUENCEVERIFY in redeemScript"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]],
"0300000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Make diffs cleaner by leaving a comment here without comma at the end"]
]

View file

@ -41,7 +41,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
(string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY)
(string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
(string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK)
(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)
{