Permalink
Browse files

Merge pull request #6124

ffd75ad Enable CHECKLOCKTIMEVERIFY as a standard script verify flag (Peter Todd)
bc60b2b Replace NOP2 with CHECKLOCKTIMEVERIFY (BIP65) (Peter Todd)
48e9c57 Move LOCKTIME_THRESHOLD to src/script/script.h (Peter Todd)
99088d6 Make CScriptNum() take nMaxNumSize as an argument (Peter Todd)
  • Loading branch information...
laanwj committed Jun 26, 2015
2 parents 5aa34c7 + ffd75ad commit 41076aad0cbdfa4c4cf376e345114a5c29086f81
@@ -12,7 +12,5 @@ static const unsigned int MAX_BLOCK_SIZE = 1000000;
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
-/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
-static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
#endif // BITCOIN_CONSENSUS_CONSENSUS_H
View
@@ -335,9 +335,51 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Control
//
case OP_NOP:
- break;
+ break;
+
+ case OP_CHECKLOCKTIMEVERIFY:
+ {
+ if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
+ // not enabled; treat as a NOP2
+ 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 elsewhere numeric opcodes are limited to
+ // operands in the range -2**31+1 to 2**31-1, however it is
+ // legal for opcodes to produce results exceeding that
+ // range. This limitation is implemented by CScriptNum's
+ // default 4-byte limit.
+ //
+ // If we kept to that limit we'd have a year 2038 problem,
+ // even though the nLockTime field in transactions
+ // themselves is uint32 which only becomes meaningless
+ // after the year 2106.
+ //
+ // Thus as a special case we tell CScriptNum to accept up
+ // to 5-byte bignums, which are good until 2**39-1, well
+ // beyond the 2**32-1 limit of the nLockTime field itself.
+ const CScriptNum nLockTime(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 CHECKLOCKTIMEVERIFY.
+ if (nLockTime < 0)
+ return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);
+
+ // Actually compare the specified lock time with the transaction.
+ if (!checker.CheckLockTime(nLockTime))
+ return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);
+
+ break;
+ }
- 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:
{
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
@@ -1084,6 +1126,43 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
return true;
}
+bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
+{
+ // There are two times of nLockTime: lock-by-blockheight
+ // and lock-by-blocktime, distinguished by whether
+ // nLockTime < LOCKTIME_THRESHOLD.
+ //
+ // 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)
+ ))
+ 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)
+ 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;
+
+ return true;
+}
+
+
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
View
@@ -76,6 +76,11 @@ enum
// (softfork safe, BIP62 rule 6)
// Note: CLEANSTACK should never be used without P2SH.
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
+
+ // Verify CHECKLOCKTIMEVERIFY
+ //
+ // See BIP65 for details.
+ SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
@@ -88,6 +93,11 @@ class BaseSignatureChecker
return false;
}
+ virtual bool CheckLockTime(const CScriptNum& nLockTime) const
+ {
+ return false;
+ }
+
virtual ~BaseSignatureChecker() {}
};
@@ -103,6 +113,7 @@ class TransactionSignatureChecker : public BaseSignatureChecker
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;
};
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
View
@@ -19,6 +19,10 @@
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
+// Threshold for nLockTime: below this value it is interpreted as block number,
+// otherwise as UNIX timestamp.
+static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
+
template <typename T>
std::vector<unsigned char> ToByteVector(const T& in)
{
@@ -151,6 +155,7 @@ enum opcodetype
// expansion
OP_NOP1 = 0xb0,
OP_NOP2 = 0xb1,
+ OP_CHECKLOCKTIMEVERIFY = OP_NOP2,
OP_NOP3 = 0xb2,
OP_NOP4 = 0xb3,
OP_NOP5 = 0xb4,
@@ -196,7 +201,10 @@ class CScriptNum
m_value = n;
}
- explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal)
+ static const size_t nDefaultMaxNumSize = 4;
+
+ explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal,
+ const size_t nMaxNumSize = nDefaultMaxNumSize)
{
if (vch.size() > nMaxNumSize) {
throw scriptnum_error("script number overflow");
@@ -319,8 +327,6 @@ class CScriptNum
return result;
}
- static const size_t nMaxNumSize = 4;
-
private:
static int64_t set_vch(const std::vector<unsigned char>& vch)
{
@@ -47,6 +47,10 @@ const char* ScriptErrorString(const ScriptError serror)
return "OP_RETURN was encountered";
case SCRIPT_ERR_UNBALANCED_CONDITIONAL:
return "Invalid OP_IF construction";
+ case SCRIPT_ERR_NEGATIVE_LOCKTIME:
+ return "Negative locktime";
+ case SCRIPT_ERR_UNSATISFIED_LOCKTIME:
+ return "Locktime requirement not satisfied";
case SCRIPT_ERR_SIG_HASHTYPE:
return "Signature hash type missing or not understood";
case SCRIPT_ERR_SIG_DER:
@@ -35,6 +35,10 @@ typedef enum ScriptError_t
SCRIPT_ERR_INVALID_ALTSTACK_OPERATION,
SCRIPT_ERR_UNBALANCED_CONDITIONAL,
+ /* OP_CHECKLOCKTIMEVERIFY */
+ SCRIPT_ERR_NEGATIVE_LOCKTIME,
+ SCRIPT_ERR_UNSATISFIED_LOCKTIME,
+
/* BIP62 */
SCRIPT_ERR_SIG_HASHTYPE,
SCRIPT_ERR_SIG_DER,
View
@@ -50,7 +50,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
SCRIPT_VERIFY_MINIMALDATA |
SCRIPT_VERIFY_NULLDUMMY |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
- SCRIPT_VERIFY_CLEANSTACK;
+ SCRIPT_VERIFY_CLEANSTACK |
+ SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
/** For convenience, standard but not mandatory verify flags. */
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
@@ -120,6 +120,70 @@
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510100ffffffff010000000000000000016a00000000", "P2SH"],
+["CHECKLOCKTIMEVERIFY tests"],
+
+["By-height locks, with argument just beyond tx nLockTime"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["By-time locks, with argument just beyond tx nLockTime (but within numerical boundries)"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument missing"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument negative with by-blockheight nLockTime=0"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument negative with by-blocktime nLockTime=500,000,000"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Input locked"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"] ,
+ ["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]],
+"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument/tx height/time mismatch, both versions"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument 2^32 with nLockTime=2^32-1"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Same, but with nLockTime=2^31-1"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["6 byte non-minimally-encoded arguments are invalid even in their contents are valid"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Failure due to failing CHECKLOCKTIMEVERIFY in redeemScript"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
@@ -187,5 +187,47 @@
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
+["CHECKLOCKTIMEVERIFY tests"],
+
+["By-height locks, with argument == 0 and == tx nLockTime"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["By-time locks, with argument just beyond tx nLockTime (but within numerical boundries)"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Any non-maxint nSequence is fine"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["The argument can be calculated rather than created directly by a PUSHDATA"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["5 byte non-minimally-encoded arguments are valid"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Valid CHECKLOCKTIMEVERIFY in scriptSig"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Valid CHECKLOCKTIMEVERIFY in redeemScript"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
@@ -145,7 +145,7 @@ static void RunCreate(const int64_t& num)
{
CheckCreateInt(num);
CScriptNum scriptnum(num);
- if (scriptnum.getvch().size() <= CScriptNum::nMaxNumSize)
+ if (scriptnum.getvch().size() <= CScriptNum::nDefaultMaxNumSize)
CheckCreateVch(num);
else
{
Oops, something went wrong.

0 comments on commit 41076aa

Please sign in to comment.