Showing with 211 additions and 9 deletions.
  1. +1 −1 src/core.h
  2. +18 −0 src/main.cpp
  3. +0 −2 src/main.h
  4. +71 −1 src/script/interpreter.cpp
  5. +1 −0 src/script/interpreter.h
  6. +8 −3 src/script/script.h
  7. +2 −1 src/script/standard.h
  8. +66 −0 src/test/data/tx_invalid.json
  9. +42 −0 src/test/data/tx_valid.json
  10. +1 −1 src/test/scriptnum_tests.cpp
  11. +1 −0 src/test/transaction_tests.cpp
2 changes: 1 addition & 1 deletion src/core.h
Expand Up @@ -431,7 +431,7 @@ class CBlockHeader
{
public:
// header
static const int32_t CURRENT_VERSION=2;
static const int32_t CURRENT_VERSION=3;
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
Expand Down
18 changes: 18 additions & 0 deletions src/main.cpp
Expand Up @@ -1653,6 +1653,16 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
unsigned int flags = SCRIPT_VERIFY_NOCACHE |
(fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE);

// NOP2 is redefined as CHECKLOCKTIMEVERIFY in blocks with nVersion >= 3
//
// However the block.nVersion=3 rule is not enforced until 750 of the last
// 1,000 blocks are version 3 or greater (51/100 if testnet):
if (block.nVersion >= 3 &&
CBlockIndex::IsSuperMajority(3, pindex->pprev, Params().EnforceBlockUpgradeMajority()))
{
flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
}

CBlockUndo blockundo;

CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
Expand Down Expand Up @@ -2383,6 +2393,14 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"),
REJECT_OBSOLETE, "bad-version");
}

// Reject block.nVersion=2 blocks when 95% (75% on testnet) of the network has upgraded:
if (block.nVersion < 3 &&
CBlockIndex::IsSuperMajority(3, pindexPrev, Params().RejectBlockOutdatedMajority()))
{
return state.Invalid(error("AcceptBlock() : rejected nVersion=2 block"),
REJECT_OBSOLETE, "bad-version");
}
}

if (pindex == NULL)
Expand Down
2 changes: 0 additions & 2 deletions src/main.h
Expand Up @@ -63,8 +63,6 @@ static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
/** 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
/** Maximum number of script-checking threads allowed */
static const int MAX_SCRIPTCHECK_THREADS = 16;
/** -par default (number of script-checking threads, 0 = auto) */
Expand Down
72 changes: 71 additions & 1 deletion src/script/interpreter.cpp
Expand Up @@ -217,7 +217,77 @@ bool EvalScript(vector<vector<unsigned char> >& 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:
break;
case OP_NOP2:
{
// CHECKLOCKTIMEVERIFY
//
// (nLockTime -- nLockTime )

if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY))
break; // not enabled; treat as a NOP

if (stack.size() < 1)
return false;

// 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**32-1, the
// same limit as the nLockTime field itself.
const CScriptNum nLockTime(stacktop(-1), 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 false;

// 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;

break;

}
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;

Expand Down
1 change: 1 addition & 0 deletions src/script/interpreter.h
Expand Up @@ -32,6 +32,7 @@ enum
SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) 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_CHECKLOCKTIMEVERIFY = (1U << 5), // support CHECKLOCKTIMEVERIFY opcode
};

bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);
Expand Down
11 changes: 8 additions & 3 deletions src/script/script.h
Expand Up @@ -16,6 +16,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

/** Script opcodes */
enum opcodetype
{
Expand Down Expand Up @@ -185,7 +189,10 @@ class CScriptNum
m_value = n;
}

explicit CScriptNum(const std::vector<unsigned char>& vch)
static const size_t nDefaultMaxNumSize = 4;

explicit CScriptNum(const std::vector<unsigned char>& vch,
const size_t nMaxNumSize = nDefaultMaxNumSize)
{
if (vch.size() > nMaxNumSize)
throw scriptnum_error("CScriptNum(const std::vector<unsigned char>&) : overflow");
Expand Down Expand Up @@ -289,8 +296,6 @@ class CScriptNum
return result;
}

static const size_t nMaxNumSize = 4;

private:
static int64_t set_vch(const std::vector<unsigned char>& vch)
{
Expand Down
3 changes: 2 additions & 1 deletion src/script/standard.h
Expand Up @@ -22,7 +22,8 @@ static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes
//
// Failing one of these tests may trigger a DoS ban - see CheckInputs() for
// details.
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH |
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;

// Standard script verification flags that standard transactions will comply
// with. However scripts violating these flags may still be present in valid
Expand Down
66 changes: 66 additions & 0 deletions src/test/data/tx_invalid.json
Expand Up @@ -103,5 +103,71 @@
[[["ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b", 0, "0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT"]],
"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", "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"]
]
42 changes: 42 additions & 0 deletions src/test/data/tx_valid.json
Expand Up @@ -178,5 +178,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"]
]
2 changes: 1 addition & 1 deletion src/test/scriptnum_tests.cpp
Expand Up @@ -142,7 +142,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
{
Expand Down
1 change: 1 addition & 0 deletions src/test/transaction_tests.cpp
Expand Up @@ -40,6 +40,7 @@ unsigned int ParseScriptFlags(string strFlags){
mapFlagNames["STRICTENC"] = SCRIPT_VERIFY_STRICTENC;
mapFlagNames["LOW_S"] = SCRIPT_VERIFY_LOW_S;
mapFlagNames["NULLDUMMY"] = SCRIPT_VERIFY_NULLDUMMY;
mapFlagNames["CHECKLOCKTIMEVERIFY"] = SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
}

BOOST_FOREACH(string word, words)
Expand Down