mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 14:53:43 +01:00
BIP112: Implement CHECKSEQUENCEVERIFY
- Replace NOP3 with CHECKSEQUENCEVERIFY (BIP112) <nSequence> CHECKSEQUENCEVERIFY -> <nSequence> - Fails if txin.nSequence < nSequence, allowing funds of a txout to be locked for a number of blocks or a duration of time after its inclusion in a block. - Pull most of CheckLockTime() out into VerifyLockTime(), a local function that will be reused for CheckSequence() - Add bitwise AND operator to CScriptNum - Enable CHECKSEQUENCEVERIFY as a standard script verify flag - Transactions that fail CSV verification will be rejected from the mempool, making it easy to test the feature. However blocks containing "invalid" CSV-using transactions will still be accepted; this is *not* the soft-fork required to actually enable CSV for production use.
This commit is contained in:
committed by
BtcDrak
parent
80d1f2e483
commit
53e53a33c9
@@ -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)
|
||||
@@ -1120,27 +1157,33 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
|
||||
static bool VerifyLockTime(int64_t txToLockTime, int64_t nThreshold, const CScriptNum& nLockTime)
|
||||
{
|
||||
// There are two kinds of nLockTime: lock-by-blockheight
|
||||
// and lock-by-blocktime, distinguished by whether
|
||||
// nLockTime < LOCKTIME_THRESHOLD.
|
||||
// nLockTime < nThreshold (either LOCKTIME_THRESHOLD or
|
||||
// CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG).
|
||||
//
|
||||
// We want to compare apples to apples, so fail the script
|
||||
// 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 < nThreshold && nLockTime < nThreshold) ||
|
||||
(txToLockTime >= nThreshold && nLockTime >= nThreshold)
|
||||
))
|
||||
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
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
|
||||
{
|
||||
// The nLockTime feature can be disabled and thus
|
||||
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
|
||||
// finalized by setting nSequence to maxint. The
|
||||
// transaction would be allowed into the blockchain, making
|
||||
@@ -1153,6 +1196,38 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
|
||||
if (CTxIn::SEQUENCE_FINAL == txTo->vin[nIn].nSequence)
|
||||
return false;
|
||||
|
||||
if (!::VerifyLockTime((int64_t)txTo->nLockTime, LOCKTIME_THRESHOLD, nLockTime))
|
||||
return false;
|
||||
|
||||
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 of ::VerifyLockTime.
|
||||
const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG
|
||||
| CTxIn::SEQUENCE_LOCKTIME_MASK;
|
||||
|
||||
if (!::VerifyLockTime(txToSequence & nLockTimeMask, CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG, nSequence & nLockTimeMask))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user