diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2016-02-16 10:46:22 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2016-02-16 10:46:34 +0100 |
commit | 93c85d458ac3e2c496c1a053e1f5925f55e29100 (patch) | |
tree | 6b26e898d0a727e57faa0c9b1d02f968b34b554c /src/script | |
parent | 2d4f73f47e527520a541880c855220b9d5857f47 (diff) | |
parent | a38107643f3f01cd92a4e6da9e7a9d025770ff37 (diff) |
Merge #7524: BIP-112: Mempool-only CHECKSEQUENCEVERIFY
a381076 Code style fix. (BtcDrak)
c3c3752 Separate CheckLockTime() and CheckSequence() logic (BtcDrak)
53e53a3 BIP112: Implement CHECKSEQUENCEVERIFY (Mark Friedenbach)
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/interpreter.cpp | 84 | ||||
-rw-r--r-- | src/script/interpreter.h | 11 | ||||
-rw-r--r-- | src/script/script.h | 12 | ||||
-rw-r--r-- | src/script/script_error.h | 2 |
4 files changed, 107 insertions, 2 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 901f901f01..149a4f0156 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -373,7 +373,44 @@ 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); + + // nSequence, like nLockTime, is a 32-bit unsigned integer + // field. See the comment in CHECKLOCKTIMEVERIFY regarding + // 5-byte numeric operands. + const CScriptNum nSequence(stacktop(-1), 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 CHECKSEQUENCEVERIFY. + if (nSequence < 0) + return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME); + + // To provide for future soft-fork extensibility, if the + // operand has the disabled lock-time flag set, + // CHECKSEQUENCEVERIFY behaves as a NOP. + if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) + break; + + // Compare the specified sequence number with the input. + if (!checker.CheckSequence(nSequence)) + 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) @@ -1156,6 +1193,51 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con return true; } +bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const +{ + // Relative lock times are supported by comparing the passed + // in operand to the sequence number of the input. + const int64_t txToSequence = (int64_t)txTo->vin[nIn].nSequence; + + // Fail if the transaction's version number is not set high + // enough to trigger BIP 68 rules. + if (static_cast<uint32_t>(txTo->nVersion) < 2) + return false; + + // Sequence numbers with their most significant bit set are not + // consensus constrained. Testing that the transaction's sequence + // number do not have this bit set prevents using this property + // to get around a CHECKSEQUENCEVERIFY check. + if (txToSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) + return false; + + // Mask off any bits that do not have consensus-enforced meaning + // before doing the integer comparisons + const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK; + const int64_t txToSequenceMasked = txToSequence & nLockTimeMask; + const CScriptNum nSequenceMasked = nSequence & nLockTimeMask; + + // There are two kinds of nSequence: lock-by-blockheight + // and lock-by-blocktime, distinguished by whether + // nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG. + // + // We want to compare apples to apples, so fail the script + // unless the type of nSequenceMasked being tested is the same as + // the nSequenceMasked in the transaction. + if (!( + (txToSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) || + (txToSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) + )) { + return false; + } + + // Now that we know we're comparing apples-to-apples, the + // comparison is a simple numeric one. + if (nSequenceMasked > txToSequenceMasked) + return false; + + return true; +} bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 7b34547ffb..e5cb7290f2 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -81,6 +81,11 @@ enum // // See BIP65 for details. SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), + + // support CHECKSEQUENCEVERIFY opcode + // + // See BIP112 for details + SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10), }; bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror); @@ -100,6 +105,11 @@ public: return false; } + virtual bool CheckSequence(const CScriptNum& nSequence) const + { + return false; + } + virtual ~BaseSignatureChecker() {} }; @@ -116,6 +126,7 @@ 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 CheckSequence(const CScriptNum& nSequence) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/script/script.h b/src/script/script.h index 6551eea30d..d2a68a07ba 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -165,6 +165,7 @@ enum opcodetype OP_CHECKLOCKTIMEVERIFY = 0xb1, OP_NOP2 = OP_CHECKLOCKTIMEVERIFY, OP_NOP3 = 0xb2, + OP_CHECKSEQUENCEVERIFY = OP_NOP3, OP_NOP4 = 0xb3, OP_NOP5 = 0xb4, OP_NOP6 = 0xb5, @@ -259,6 +260,11 @@ public: inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); } inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); } + inline CScriptNum operator&( const int64_t& rhs) const { return CScriptNum(m_value & rhs);} + inline CScriptNum operator&( const CScriptNum& rhs) const { return operator&(rhs.m_value); } + + inline CScriptNum& operator&=( const CScriptNum& rhs) { return operator&=(rhs.m_value); } + inline CScriptNum operator-() const { assert(m_value != std::numeric_limits<int64_t>::min()); @@ -287,6 +293,12 @@ public: return *this; } + inline CScriptNum& operator&=( const int64_t& rhs) + { + m_value &= rhs; + return *this; + } + int getint() const { if (m_value > std::numeric_limits<int>::max()) diff --git a/src/script/script_error.h b/src/script/script_error.h index bb10b8a293..26df33932f 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -35,7 +35,7 @@ typedef enum ScriptError_t SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, SCRIPT_ERR_UNBALANCED_CONDITIONAL, - /* OP_CHECKLOCKTIMEVERIFY */ + /* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */ SCRIPT_ERR_NEGATIVE_LOCKTIME, SCRIPT_ERR_UNSATISFIED_LOCKTIME, |