Changeset View
Changeset View
Standalone View
Standalone View
src/test/txvalidationcache_tests.cpp
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | for (int i = 0; i < 2; i++) { | ||||
spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetId(); | spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetId(); | ||||
spends[i].vin[0].prevout.n = 0; | spends[i].vin[0].prevout.n = 0; | ||||
spends[i].vout.resize(1); | spends[i].vout.resize(1); | ||||
spends[i].vout[0].nValue = 11 * CENT; | spends[i].vout[0].nValue = 11 * CENT; | ||||
spends[i].vout[0].scriptPubKey = scriptPubKey; | spends[i].vout[0].scriptPubKey = scriptPubKey; | ||||
// Sign: | // Sign: | ||||
std::vector<uint8_t> vchSig; | std::vector<uint8_t> vchSig; | ||||
uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, | uint256 hash = SignatureHash(scriptPubKey, CTransaction(spends[i]), 0, | ||||
SigHashType().withForkId(true), | SigHashType().withForkId(true), | ||||
coinbaseTxns[0].vout[0].nValue); | coinbaseTxns[0].vout[0].nValue); | ||||
BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); | BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); | ||||
vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | ||||
spends[i].vin[0].scriptSig << vchSig; | spends[i].vin[0].scriptSig << vchSig; | ||||
} | } | ||||
CBlock block; | CBlock block; | ||||
Show All 31 Lines | |||||
// CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY (and future NOP codes that may | // CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY (and future NOP codes that may | ||||
// get reassigned) have an interaction with DISCOURAGE_UPGRADABLE_NOPS: if the | // get reassigned) have an interaction with DISCOURAGE_UPGRADABLE_NOPS: if the | ||||
// script flags used contain DISCOURAGE_UPGRADABLE_NOPS but don't contain | // script flags used contain DISCOURAGE_UPGRADABLE_NOPS but don't contain | ||||
// CHECKLOCKTIMEVERIFY (or CHECKSEQUENCEVERIFY), but the script does contain | // CHECKLOCKTIMEVERIFY (or CHECKSEQUENCEVERIFY), but the script does contain | ||||
// OP_CHECKLOCKTIMEVERIFY (or OP_CHECKSEQUENCEVERIFY), then script execution | // OP_CHECKLOCKTIMEVERIFY (or OP_CHECKSEQUENCEVERIFY), then script execution | ||||
// should fail. | // should fail. | ||||
// Capture this interaction with the upgraded_nop argument: set it when | // Capture this interaction with the upgraded_nop argument: set it when | ||||
// evaluating any script flag that is implemented as an upgraded NOP code. | // evaluating any script flag that is implemented as an upgraded NOP code. | ||||
void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, | void ValidateCheckInputsForAllFlags(const CMutableTransaction &mutableTx, | ||||
uint32_t failing_flags, bool add_to_cache, | uint32_t failing_flags, bool add_to_cache, | ||||
bool upgraded_nop) { | bool upgraded_nop) { | ||||
const CTransaction tx(mutableTx); | |||||
PrecomputedTransactionData txdata(tx); | PrecomputedTransactionData txdata(tx); | ||||
// If we add many more flags, this loop can get too expensive, but we can | // If we add many more flags, this loop can get too expensive, but we can | ||||
// rewrite in the future to randomly pick a set of flags to evaluate. | // rewrite in the future to randomly pick a set of flags to evaluate. | ||||
for (size_t test_flags = 0; test_flags < (1U << 17); test_flags += 1) { | for (size_t test_flags = 0; test_flags < (1U << 17); test_flags += 1) { | ||||
CValidationState state; | CValidationState state; | ||||
// Make sure the mandatory flags are enabled. | // Make sure the mandatory flags are enabled. | ||||
test_flags |= MANDATORY_SCRIPT_VERIFY_FLAGS; | test_flags |= MANDATORY_SCRIPT_VERIFY_FLAGS; | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) { | ||||
keystore.AddCScript(p2pk_scriptPubKey); | keystore.AddCScript(p2pk_scriptPubKey); | ||||
// flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, | // flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, | ||||
// SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, SCRIPT_VERIFY_NULLDUMMY, uncompressed | // SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, SCRIPT_VERIFY_NULLDUMMY, uncompressed | ||||
// pubkey thing | // pubkey thing | ||||
// Create 2 outputs that match the three scripts above, spending the first | // Create 2 outputs that match the three scripts above, spending the first | ||||
// coinbase tx. | // coinbase tx. | ||||
CMutableTransaction spend_tx; | CMutableTransaction mutableSpend_tx; | ||||
spend_tx.nVersion = 1; | mutableSpend_tx.nVersion = 1; | ||||
spend_tx.vin.resize(1); | mutableSpend_tx.vin.resize(1); | ||||
spend_tx.vin[0].prevout.hash = coinbaseTxns[0].GetId(); | mutableSpend_tx.vin[0].prevout.hash = coinbaseTxns[0].GetId(); | ||||
spend_tx.vin[0].prevout.n = 0; | mutableSpend_tx.vin[0].prevout.n = 0; | ||||
spend_tx.vout.resize(4); | mutableSpend_tx.vout.resize(4); | ||||
spend_tx.vout[0].nValue = 11 * CENT; | mutableSpend_tx.vout[0].nValue = 11 * CENT; | ||||
spend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey; | mutableSpend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey; | ||||
spend_tx.vout[1].nValue = 11 * CENT; | mutableSpend_tx.vout[1].nValue = 11 * CENT; | ||||
spend_tx.vout[1].scriptPubKey = | mutableSpend_tx.vout[1].scriptPubKey = | ||||
CScript() << OP_CHECKLOCKTIMEVERIFY << OP_DROP | CScript() << OP_CHECKLOCKTIMEVERIFY << OP_DROP | ||||
<< ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; | << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; | ||||
spend_tx.vout[2].nValue = 11 * CENT; | mutableSpend_tx.vout[2].nValue = 11 * CENT; | ||||
spend_tx.vout[2].scriptPubKey = | mutableSpend_tx.vout[2].scriptPubKey = | ||||
CScript() << OP_CHECKSEQUENCEVERIFY << OP_DROP | CScript() << OP_CHECKSEQUENCEVERIFY << OP_DROP | ||||
<< ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; | << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; | ||||
spend_tx.vout[3].nValue = 11 * CENT; | mutableSpend_tx.vout[3].nValue = 11 * CENT; | ||||
spend_tx.vout[3].scriptPubKey = p2sh_scriptPubKey; | mutableSpend_tx.vout[3].scriptPubKey = p2sh_scriptPubKey; | ||||
// Sign, and push an extra element on the stack. | // Sign, and push an extra element on the stack. | ||||
{ | { | ||||
std::vector<uint8_t> vchSig; | std::vector<uint8_t> vchSig; | ||||
uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, | uint256 hash = SignatureHash( | ||||
SigHashType().withForkId(true), | p2pk_scriptPubKey, CTransaction(mutableSpend_tx), 0, | ||||
coinbaseTxns[0].vout[0].nValue); | SigHashType().withForkId(true), coinbaseTxns[0].vout[0].nValue); | ||||
BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); | BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); | ||||
vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | ||||
spend_tx.vin[0].scriptSig << OP_TRUE << vchSig; | mutableSpend_tx.vin[0].scriptSig << OP_TRUE << vchSig; | ||||
} | } | ||||
const CTransaction spend_tx(mutableSpend_tx); | |||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// Test that invalidity under a set of flags doesn't preclude validity under | // Test that invalidity under a set of flags doesn't preclude validity under | ||||
// other (eg consensus) flags. | // other (eg consensus) flags. | ||||
// spend_tx is invalid according to DERSIG | // spend_tx is invalid according to DERSIG | ||||
CValidationState state; | CValidationState state; | ||||
{ | { | ||||
PrecomputedTransactionData ptd_spend_tx(spend_tx); | PrecomputedTransactionData ptd_spend_tx(spend_tx); | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | // Test CHECKLOCKTIMEVERIFY | ||||
invalid_with_cltv_tx.vin[0].nSequence = 0; | invalid_with_cltv_tx.vin[0].nSequence = 0; | ||||
invalid_with_cltv_tx.vout.resize(1); | invalid_with_cltv_tx.vout.resize(1); | ||||
invalid_with_cltv_tx.vout[0].nValue = 11 * CENT; | invalid_with_cltv_tx.vout[0].nValue = 11 * CENT; | ||||
invalid_with_cltv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; | invalid_with_cltv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; | ||||
// Sign | // Sign | ||||
std::vector<uint8_t> vchSig; | std::vector<uint8_t> vchSig; | ||||
uint256 hash = SignatureHash( | uint256 hash = SignatureHash( | ||||
spend_tx.vout[1].scriptPubKey, invalid_with_cltv_tx, 0, | spend_tx.vout[1].scriptPubKey, CTransaction(invalid_with_cltv_tx), | ||||
SigHashType().withForkId(true), spend_tx.vout[1].nValue); | 0, SigHashType().withForkId(true), spend_tx.vout[1].nValue); | ||||
BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); | BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); | ||||
vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | ||||
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; | invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; | ||||
ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, | ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, | ||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, | ||||
true); | true); | ||||
// Make it valid, and check again | // Make it valid, and check again | ||||
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; | invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; | ||||
CValidationState state; | CValidationState state; | ||||
PrecomputedTransactionData txdata(invalid_with_cltv_tx); | |||||
BOOST_CHECK(CheckInputs(invalid_with_cltv_tx, state, pcoinsTip, true, | CTransaction transaction(invalid_with_cltv_tx); | ||||
PrecomputedTransactionData txdata(transaction); | |||||
BOOST_CHECK(CheckInputs(transaction, state, pcoinsTip, true, | |||||
MANDATORY_SCRIPT_VERIFY_FLAGS | | MANDATORY_SCRIPT_VERIFY_FLAGS | | ||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, | ||||
true, true, txdata, nullptr)); | true, true, txdata, nullptr)); | ||||
} | } | ||||
// TEST CHECKSEQUENCEVERIFY | // TEST CHECKSEQUENCEVERIFY | ||||
{ | { | ||||
CMutableTransaction invalid_with_csv_tx; | CMutableTransaction invalid_with_csv_tx; | ||||
invalid_with_csv_tx.nVersion = 2; | invalid_with_csv_tx.nVersion = 2; | ||||
invalid_with_csv_tx.vin.resize(1); | invalid_with_csv_tx.vin.resize(1); | ||||
invalid_with_csv_tx.vin[0].prevout.hash = spend_tx.GetId(); | invalid_with_csv_tx.vin[0].prevout.hash = spend_tx.GetId(); | ||||
invalid_with_csv_tx.vin[0].prevout.n = 2; | invalid_with_csv_tx.vin[0].prevout.n = 2; | ||||
invalid_with_csv_tx.vin[0].nSequence = 100; | invalid_with_csv_tx.vin[0].nSequence = 100; | ||||
invalid_with_csv_tx.vout.resize(1); | invalid_with_csv_tx.vout.resize(1); | ||||
invalid_with_csv_tx.vout[0].nValue = 11 * CENT; | invalid_with_csv_tx.vout[0].nValue = 11 * CENT; | ||||
invalid_with_csv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; | invalid_with_csv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; | ||||
// Sign | // Sign | ||||
std::vector<uint8_t> vchSig; | std::vector<uint8_t> vchSig; | ||||
uint256 hash = SignatureHash( | uint256 hash = SignatureHash( | ||||
spend_tx.vout[2].scriptPubKey, invalid_with_csv_tx, 0, | spend_tx.vout[2].scriptPubKey, CTransaction(invalid_with_csv_tx), 0, | ||||
SigHashType().withForkId(true), spend_tx.vout[2].nValue); | SigHashType().withForkId(true), spend_tx.vout[2].nValue); | ||||
BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); | BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); | ||||
vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | ||||
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; | invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; | ||||
ValidateCheckInputsForAllFlags( | ValidateCheckInputsForAllFlags( | ||||
invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true); | invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true); | ||||
// Make it valid, and check again | // Make it valid, and check again | ||||
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; | invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; | ||||
CValidationState state; | CValidationState state; | ||||
PrecomputedTransactionData txdata(invalid_with_csv_tx); | |||||
BOOST_CHECK(CheckInputs(invalid_with_csv_tx, state, pcoinsTip, true, | CTransaction transaction(invalid_with_csv_tx); | ||||
PrecomputedTransactionData txdata(transaction); | |||||
BOOST_CHECK(CheckInputs(transaction, state, pcoinsTip, true, | |||||
MANDATORY_SCRIPT_VERIFY_FLAGS | | MANDATORY_SCRIPT_VERIFY_FLAGS | | ||||
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, | SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, | ||||
true, true, txdata, nullptr)); | true, true, txdata, nullptr)); | ||||
} | } | ||||
// TODO: add tests for remaining script flags | // TODO: add tests for remaining script flags | ||||
{ | { | ||||
Show All 27 Lines | // TODO: add tests for remaining script flags | ||||
ValidateCheckInputsForAllFlags(tx, 0, true, false); | ValidateCheckInputsForAllFlags(tx, 0, true, false); | ||||
// Check that if the second input is invalid, but the first input is | // Check that if the second input is invalid, but the first input is | ||||
// valid, the transaction is not cached. | // valid, the transaction is not cached. | ||||
// Invalidate vin[1] | // Invalidate vin[1] | ||||
tx.vin[1].scriptSig = CScript(); | tx.vin[1].scriptSig = CScript(); | ||||
CValidationState state; | CValidationState state; | ||||
PrecomputedTransactionData txdata(tx); | CTransaction transaction(tx); | ||||
PrecomputedTransactionData txdata(transaction); | |||||
// This transaction is now invalid because the second signature is | // This transaction is now invalid because the second signature is | ||||
// missing. | // missing. | ||||
BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip, true, | BOOST_CHECK(!CheckInputs(transaction, state, pcoinsTip, true, | ||||
MANDATORY_SCRIPT_VERIFY_FLAGS, true, true, | MANDATORY_SCRIPT_VERIFY_FLAGS, true, true, | ||||
txdata, nullptr)); | txdata, nullptr)); | ||||
// Make sure this transaction was not cached (ie becausethe first input | // Make sure this transaction was not cached (ie becausethe first input | ||||
// was valid) | // was valid) | ||||
std::vector<CScriptCheck> scriptchecks; | std::vector<CScriptCheck> scriptchecks; | ||||
BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, | BOOST_CHECK(CheckInputs(transaction, state, pcoinsTip, true, | ||||
MANDATORY_SCRIPT_VERIFY_FLAGS, true, true, | MANDATORY_SCRIPT_VERIFY_FLAGS, true, true, | ||||
txdata, &scriptchecks)); | txdata, &scriptchecks)); | ||||
// Should get 2 script checks back -- caching is on a whole-transaction | // Should get 2 script checks back -- caching is on a whole-transaction | ||||
// basis. | // basis. | ||||
BOOST_CHECK_EQUAL(scriptchecks.size(), 2); | BOOST_CHECK_EQUAL(scriptchecks.size(), 2); | ||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |