From dd536eb94079058f0f2d780e99bea51bbaf4a90c Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Sun, 21 Feb 2016 18:02:40 +0300 Subject: [PATCH] Add OP_CHECKLOCKTIMEVERIFY support. --- src/main.cpp | 8 +++++++- src/script.cpp | 41 +++++++++++++++++++++++++++++++++++++++-- src/script.h | 6 ++++-- src/timestamps.h | 2 +- 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8a96379..95927c8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1758,8 +1758,14 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) if (!tx.IsCoinStake()) nFees += nTxValueIn - nTxValueOut; + unsigned int nFlags = SCRIPT_VERIFY_NOCACHE | SCRIPT_VERIFY_P2SH; + + if (tx.nTime >= CHECKLOCKTIMEVERIFY_SWITCH_TIME) { + nFlags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; + } + std::vector vChecks; - if (!tx.ConnectInputs(txdb, mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fScriptChecks, SCRIPT_VERIFY_NOCACHE | SCRIPT_VERIFY_P2SH, nScriptCheckThreads ? &vChecks : NULL)) + if (!tx.ConnectInputs(txdb, mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fScriptChecks, nFlags, nScriptCheckThreads ? &vChecks : NULL)) return false; control.Add(vChecks); } diff --git a/src/script.cpp b/src/script.cpp index c7c2b29..6b8e163 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -148,6 +148,7 @@ const char* GetOpName(opcodetype opcode) case OP_ENDIF : return "OP_ENDIF"; case OP_VERIFY : return "OP_VERIFY"; case OP_RETURN : return "OP_RETURN"; + case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY"; // stack ops case OP_TOALTSTACK : return "OP_TOALTSTACK"; @@ -230,7 +231,6 @@ const char* GetOpName(opcodetype opcode) // expanson case OP_NOP1 : return "OP_NOP1"; - case OP_NOP2 : return "OP_NOP2"; case OP_NOP3 : return "OP_NOP3"; case OP_NOP4 : return "OP_NOP4"; case OP_NOP5 : return "OP_NOP5"; @@ -422,7 +422,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // Control // case OP_NOP: - case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: + case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: break; @@ -481,6 +481,43 @@ bool EvalScript(vector >& stack, const CScript& script, co } break; + case OP_CHECKLOCKTIMEVERIFY: + { + // CHECKLOCKTIMEVERIFY + // + // (nLockTime -- nLockTime) + if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) + break; // treat as a NOP is not enabled + if (stack.size() < 1) + return false; + const CBigNum nLockTime = CastToBigNum(stacktop(-1)); + if (nLockTime < 0) + return false; // Negative argument is senseless. + + if (!( // We can have either lock-by-blockheight or lock-by-blocktime. + (txTo.nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) || + (txTo.nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD) + )) + return false; + + // Now we can perform a simple numerical comparison + if (nLockTime > (int64_t)txTo.nLockTime) + return false; + + // Finally 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 + // the opcode ineffective. + // + // Testing if this vin is not final is sufficient to + // 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()) + return false; + break; + } // // Stack ops diff --git a/src/script.h b/src/script.h index ef13bf4..e9afde8 100644 --- a/src/script.h +++ b/src/script.h @@ -47,7 +47,9 @@ enum SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values in signatures (depends on STRICTENC) SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it) - SCRIPT_VERIFY_NULLDUMMY = (1U << 4) // verify dummy stack item consumed by CHECKMULTISIG is of zero-length + SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length + SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9) + }; // Strict verification: @@ -125,6 +127,7 @@ enum opcodetype OP_ENDIF = 0x68, OP_VERIFY = 0x69, OP_RETURN = 0x6a, + OP_CHECKLOCKTIMEVERIFY = 0xb1, // stack ops OP_TOALTSTACK = 0x6b, @@ -210,7 +213,6 @@ enum opcodetype // expansion OP_NOP1 = 0xb0, - OP_NOP2 = 0xb1, OP_NOP3 = 0xb2, OP_NOP4 = 0xb3, OP_NOP5 = 0xb4, diff --git a/src/timestamps.h b/src/timestamps.h index 0da5341..eb45fa4 100644 --- a/src/timestamps.h +++ b/src/timestamps.h @@ -4,5 +4,5 @@ static const unsigned int TARGETS_SWITCH_TIME = 1374278400; // Saturday, 20-Jul-2013 00:00:00 UTC static const unsigned int COINBASE_SIGOPS_SWITCH_TIME = 1447977600; // Friday, 20-Nov-15 00:00:00 UTC static const unsigned int SMALLDATA_SWITCH_TIME = 1458432000; // Sunday, 20-Mar-16 00:00:00 UTC - +static const unsigned int CHECKLOCKTIMEVERIFY_SWITCH_TIME = 1461110400; // Wednesday, 20-Apr-16 00:00:00 UTC #endif -- 1.7.1