Changeset View
Changeset View
Standalone View
Standalone View
src/test/txvalidationcache_tests.cpp
Show First 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | block = CreateAndProcessBlock(oneSpend, scriptPubKey); | ||||
BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); | BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); | ||||
} | } | ||||
// spends[1] should have been removed from the mempool when the block with | // spends[1] should have been removed from the mempool when the block with | ||||
// spends[0] is accepted: | // spends[0] is accepted: | ||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U); | BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U); | ||||
} | } | ||||
static inline bool | static inline bool | ||||
CheckInputs(const CTransaction &tx, TxValidationState &state, | CheckInputScripts(const CTransaction &tx, TxValidationState &state, | ||||
const CCoinsViewCache &view, const uint32_t flags, | const CCoinsViewCache &view, const uint32_t flags, | ||||
bool sigCacheStore, bool scriptCacheStore, | bool sigCacheStore, bool scriptCacheStore, | ||||
const PrecomputedTransactionData &txdata, int &nSigChecksOut, | const PrecomputedTransactionData &txdata, int &nSigChecksOut, | ||||
std::vector<CScriptCheck> *pvChecks, | std::vector<CScriptCheck> *pvChecks, | ||||
CheckInputsLimiter *pBlockLimitSigChecks = nullptr) | CheckInputsLimiter *pBlockLimitSigChecks = nullptr) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
// nSigChecksTxLimiter need to outlive this function call, because test | // nSigChecksTxLimiter need to outlive this function call, because test | ||||
// cases are using pvChecks, so the verification is done asynchronously. | // cases are using pvChecks, so the verification is done asynchronously. | ||||
static TxSigCheckLimiter nSigChecksTxLimiter; | static TxSigCheckLimiter nSigChecksTxLimiter; | ||||
nSigChecksTxLimiter = TxSigCheckLimiter(); | nSigChecksTxLimiter = TxSigCheckLimiter(); | ||||
return CheckInputs(tx, state, view, flags, sigCacheStore, scriptCacheStore, | return CheckInputScripts( | ||||
txdata, nSigChecksOut, nSigChecksTxLimiter, | tx, state, view, flags, sigCacheStore, scriptCacheStore, txdata, | ||||
pBlockLimitSigChecks, pvChecks); | nSigChecksOut, nSigChecksTxLimiter, pBlockLimitSigChecks, pvChecks); | ||||
} | } | ||||
// Run CheckInputs (using CoinsTip()) on the given transaction, for all script | // Run CheckInputScripts (using CoinsTip()) on the given transaction, for all | ||||
// flags. Test that CheckInputs passes for all flags that don't overlap with the | // script flags. Test that CheckInputScripts passes for all flags that don't | ||||
// failing_flags argument, but otherwise fails. | // overlap with the failing_flags argument, but otherwise fails. | ||||
// 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. | ||||
Show All 12 Lines | for (int i = 0; i < 4096; i++) { | ||||
// Filter out incompatible flag choices | // Filter out incompatible flag choices | ||||
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) { | if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) { | ||||
// CLEANSTACK requires P2SH, see VerifyScript() in | // CLEANSTACK requires P2SH, see VerifyScript() in | ||||
// script/interpreter.cpp | // script/interpreter.cpp | ||||
test_flags |= SCRIPT_VERIFY_P2SH; | test_flags |= SCRIPT_VERIFY_P2SH; | ||||
} | } | ||||
int nSigChecksDirect = 0xf00d; | int nSigChecksDirect = 0xf00d; | ||||
bool ret = | bool ret = CheckInputScripts( | ||||
CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, | tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, | ||||
true, add_to_cache, txdata, nSigChecksDirect); | add_to_cache, txdata, nSigChecksDirect); | ||||
// CheckInputs should succeed iff test_flags doesn't intersect with | // CheckInputScripts should succeed iff test_flags doesn't intersect | ||||
// failing_flags | // with failing_flags | ||||
bool expected_return_value = !(test_flags & failing_flags); | bool expected_return_value = !(test_flags & failing_flags); | ||||
BOOST_CHECK_EQUAL(ret, expected_return_value); | BOOST_CHECK_EQUAL(ret, expected_return_value); | ||||
if (ret) { | if (ret) { | ||||
BOOST_CHECK(nSigChecksDirect == expected_sigchecks); | BOOST_CHECK(nSigChecksDirect == expected_sigchecks); | ||||
} | } | ||||
// Test the caching | // Test the caching | ||||
if (ret && add_to_cache) { | if (ret && add_to_cache) { | ||||
// Check that we get a cache hit if the tx was valid | // Check that we get a cache hit if the tx was valid | ||||
std::vector<CScriptCheck> scriptchecks; | std::vector<CScriptCheck> scriptchecks; | ||||
int nSigChecksCached = 0xbeef; | int nSigChecksCached = 0xbeef; | ||||
BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), | BOOST_CHECK(CheckInputScripts( | ||||
test_flags, true, add_to_cache, txdata, | tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, | ||||
nSigChecksCached, &scriptchecks)); | add_to_cache, txdata, nSigChecksCached, &scriptchecks)); | ||||
BOOST_CHECK(nSigChecksCached == nSigChecksDirect); | BOOST_CHECK(nSigChecksCached == nSigChecksDirect); | ||||
BOOST_CHECK(scriptchecks.empty()); | BOOST_CHECK(scriptchecks.empty()); | ||||
} else { | } else { | ||||
// Check that we get script executions to check, if the transaction | // Check that we get script executions to check, if the transaction | ||||
// was invalid, or we didn't add to cache. | // was invalid, or we didn't add to cache. | ||||
std::vector<CScriptCheck> scriptchecks; | std::vector<CScriptCheck> scriptchecks; | ||||
int nSigChecksUncached = 0xbabe; | int nSigChecksUncached = 0xbabe; | ||||
BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), | BOOST_CHECK(CheckInputScripts( | ||||
test_flags, true, add_to_cache, txdata, | tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, | ||||
nSigChecksUncached, &scriptchecks)); | add_to_cache, txdata, nSigChecksUncached, &scriptchecks)); | ||||
BOOST_CHECK(!ret || nSigChecksUncached == 0); | BOOST_CHECK(!ret || nSigChecksUncached == 0); | ||||
BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size()); | BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) { | BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) { | ||||
// Test that passing CheckInputs with one set of script flags doesn't imply | // Test that passing CheckInputScripts with one set of script flags doesn't | ||||
// that we would pass again with a different set of flags. | // imply that we would pass again with a different set of flags. | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
InitScriptExecutionCache(); | InitScriptExecutionCache(); | ||||
} | } | ||||
CScript p2pk_scriptPubKey = | CScript p2pk_scriptPubKey = | ||||
CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; | CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; | ||||
CScript p2sh_scriptPubKey = | CScript p2sh_scriptPubKey = | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | // spend_tx is invalid according to DISCOURAGE_UPGRADABLE_NOPS | ||||
const CTransaction tx(spend_tx); | const CTransaction tx(spend_tx); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
TxValidationState state; | TxValidationState state; | ||||
PrecomputedTransactionData ptd_spend_tx(tx); | PrecomputedTransactionData ptd_spend_tx(tx); | ||||
int nSigChecksDummy; | int nSigChecksDummy; | ||||
BOOST_CHECK(!CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), | BOOST_CHECK(!CheckInputScripts(tx, state, | ||||
&::ChainstateActive().CoinsTip(), | |||||
STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | ||||
ptd_spend_tx, nSigChecksDummy, nullptr)); | ptd_spend_tx, nSigChecksDummy, nullptr)); | ||||
// If we call again asking for scriptchecks (as happens in | // If we call again asking for scriptchecks (as happens in | ||||
// ConnectBlock), we should add a script check object for this -- we're | // ConnectBlock), we should add a script check object for this -- we're | ||||
// not caching invalidity (if that changes, delete this test case). | // not caching invalidity (if that changes, delete this test case). | ||||
std::vector<CScriptCheck> scriptchecks; | std::vector<CScriptCheck> scriptchecks; | ||||
BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), | BOOST_CHECK( | ||||
CheckInputScripts(tx, state, &::ChainstateActive().CoinsTip(), | |||||
STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | ||||
ptd_spend_tx, nSigChecksDummy, &scriptchecks)); | ptd_spend_tx, nSigChecksDummy, &scriptchecks)); | ||||
BOOST_CHECK_EQUAL(scriptchecks.size(), 1U); | BOOST_CHECK_EQUAL(scriptchecks.size(), 1U); | ||||
// Test that CheckInputs returns true iff cleanstack-enforcing flags are | // Test that CheckInputScripts returns true iff cleanstack-enforcing | ||||
// not present. Don't add these checks to the cache, so that we can test | // flags are not present. Don't add these checks to the cache, so that | ||||
// later that block validation works fine in the absence of cached | // we can test later that block validation works fine in the absence of | ||||
// successes. | // cached successes. | ||||
ValidateCheckInputsForAllFlags( | ValidateCheckInputsForAllFlags( | ||||
tx, SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 0, false, 0); | tx, SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 0, false, 0); | ||||
} | } | ||||
// And if we produce a block with this tx, it should be valid, even though | // And if we produce a block with this tx, it should be valid, even though | ||||
// there's no cache entry. | // there's no cache entry. | ||||
CBlock block; | CBlock block; | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | // Test CHECKLOCKTIMEVERIFY | ||||
// 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; | ||||
TxValidationState state; | TxValidationState state; | ||||
CTransaction transaction(invalid_with_cltv_tx); | CTransaction transaction(invalid_with_cltv_tx); | ||||
PrecomputedTransactionData txdata(transaction); | PrecomputedTransactionData txdata(transaction); | ||||
int nSigChecksRet; | int nSigChecksRet; | ||||
BOOST_CHECK(CheckInputs(transaction, state, | BOOST_CHECK(CheckInputScripts(transaction, state, | ||||
::ChainstateActive().CoinsTip(), | ::ChainstateActive().CoinsTip(), | ||||
STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | ||||
txdata, nSigChecksRet, nullptr)); | txdata, nSigChecksRet, nullptr)); | ||||
BOOST_CHECK(nSigChecksRet == 1); | BOOST_CHECK(nSigChecksRet == 1); | ||||
} | } | ||||
// 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); | ||||
Show All 20 Lines | // TEST CHECKSEQUENCEVERIFY | ||||
// 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; | ||||
TxValidationState state; | TxValidationState state; | ||||
CTransaction transaction(invalid_with_csv_tx); | CTransaction transaction(invalid_with_csv_tx); | ||||
PrecomputedTransactionData txdata(transaction); | PrecomputedTransactionData txdata(transaction); | ||||
int nSigChecksRet; | int nSigChecksRet; | ||||
BOOST_CHECK(CheckInputs(transaction, state, | BOOST_CHECK(CheckInputScripts(transaction, state, | ||||
&::ChainstateActive().CoinsTip(), | &::ChainstateActive().CoinsTip(), | ||||
STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | ||||
txdata, nSigChecksRet, nullptr)); | txdata, nSigChecksRet, nullptr)); | ||||
BOOST_CHECK(nSigChecksRet == 1); | BOOST_CHECK(nSigChecksRet == 1); | ||||
} | } | ||||
// TODO: add tests for remaining script flags | // TODO: add tests for remaining script flags | ||||
{ | { | ||||
// Test a transaction with multiple inputs. | // Test a transaction with multiple inputs. | ||||
CMutableTransaction tx; | CMutableTransaction tx; | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | // TODO: add tests for remaining script flags | ||||
int nSigChecksDummy; | int nSigChecksDummy; | ||||
/** | /** | ||||
* Parallel validation initially works (no cached value), but | * Parallel validation initially works (no cached value), but | ||||
* evaluation of the script checks produces a failure. | * evaluation of the script checks produces a failure. | ||||
*/ | */ | ||||
std::vector<CScriptCheck> scriptchecks1; | std::vector<CScriptCheck> scriptchecks1; | ||||
CheckInputsLimiter sigchecklimiter1(1); | CheckInputsLimiter sigchecklimiter1(1); | ||||
BOOST_CHECK(CheckInputs(transaction, state, | BOOST_CHECK(CheckInputScripts( | ||||
&::ChainstateActive().CoinsTip(), flags, | transaction, state, &::ChainstateActive().CoinsTip(), flags, | ||||
true, true, txdata, nSigChecksDummy, | true, true, txdata, nSigChecksDummy, &scriptchecks1, | ||||
&scriptchecks1, &sigchecklimiter1)); | &sigchecklimiter1)); | ||||
// the first check passes but it did consume the limit. | // the first check passes but it did consume the limit. | ||||
BOOST_CHECK(scriptchecks1[1]()); | BOOST_CHECK(scriptchecks1[1]()); | ||||
BOOST_CHECK(sigchecklimiter1.check()); | BOOST_CHECK(sigchecklimiter1.check()); | ||||
// the second check (the first input) fails due to the limiter. | // the second check (the first input) fails due to the limiter. | ||||
BOOST_CHECK(!scriptchecks1[0]()); | BOOST_CHECK(!scriptchecks1[0]()); | ||||
BOOST_CHECK_EQUAL(scriptchecks1[0].GetScriptError(), | BOOST_CHECK_EQUAL(scriptchecks1[0].GetScriptError(), | ||||
ScriptError::SIGCHECKS_LIMIT_EXCEEDED); | ScriptError::SIGCHECKS_LIMIT_EXCEEDED); | ||||
BOOST_CHECK(!sigchecklimiter1.check()); | BOOST_CHECK(!sigchecklimiter1.check()); | ||||
// Serial validation fails with the limiter. | // Serial validation fails with the limiter. | ||||
CheckInputsLimiter sigchecklimiter2(1); | CheckInputsLimiter sigchecklimiter2(1); | ||||
TxValidationState state2; | TxValidationState state2; | ||||
BOOST_CHECK(!CheckInputs(transaction, state2, | BOOST_CHECK(!CheckInputScripts( | ||||
&::ChainstateActive().CoinsTip(), flags, | transaction, state2, &::ChainstateActive().CoinsTip(), flags, | ||||
true, true, txdata, nSigChecksDummy, | true, true, txdata, nSigChecksDummy, nullptr, | ||||
nullptr, &sigchecklimiter2)); | &sigchecklimiter2)); | ||||
BOOST_CHECK(!sigchecklimiter2.check()); | BOOST_CHECK(!sigchecklimiter2.check()); | ||||
BOOST_CHECK_EQUAL(state2.GetRejectReason(), | BOOST_CHECK_EQUAL(state2.GetRejectReason(), | ||||
"non-mandatory-script-verify-flag (Validation " | "non-mandatory-script-verify-flag (Validation " | ||||
"resources exceeded (SigChecks))"); | "resources exceeded (SigChecks))"); | ||||
/** | /** | ||||
* A slightly more permissive limiter (just enough) passes, and | * A slightly more permissive limiter (just enough) passes, and | ||||
* allows caching the result. | * allows caching the result. | ||||
*/ | */ | ||||
std::vector<CScriptCheck> scriptchecks3; | std::vector<CScriptCheck> scriptchecks3; | ||||
CheckInputsLimiter sigchecklimiter3(2); | CheckInputsLimiter sigchecklimiter3(2); | ||||
// first in parallel | // first in parallel | ||||
BOOST_CHECK(CheckInputs(transaction, state, | BOOST_CHECK(CheckInputScripts( | ||||
&::ChainstateActive().CoinsTip(), flags, | transaction, state, &::ChainstateActive().CoinsTip(), flags, | ||||
true, true, txdata, nSigChecksDummy, | true, true, txdata, nSigChecksDummy, &scriptchecks3, | ||||
&scriptchecks3, &sigchecklimiter3)); | &sigchecklimiter3)); | ||||
BOOST_CHECK(scriptchecks3[1]()); | BOOST_CHECK(scriptchecks3[1]()); | ||||
BOOST_CHECK(scriptchecks3[0]()); | BOOST_CHECK(scriptchecks3[0]()); | ||||
BOOST_CHECK(sigchecklimiter3.check()); | BOOST_CHECK(sigchecklimiter3.check()); | ||||
// then in serial, caching the result. | // then in serial, caching the result. | ||||
CheckInputsLimiter sigchecklimiter4(2); | CheckInputsLimiter sigchecklimiter4(2); | ||||
BOOST_CHECK(CheckInputs(transaction, state, | BOOST_CHECK(CheckInputScripts( | ||||
&::ChainstateActive().CoinsTip(), flags, | transaction, state, &::ChainstateActive().CoinsTip(), flags, | ||||
true, true, txdata, nSigChecksDummy, | true, true, txdata, nSigChecksDummy, nullptr, | ||||
nullptr, &sigchecklimiter4)); | &sigchecklimiter4)); | ||||
BOOST_CHECK(sigchecklimiter4.check()); | BOOST_CHECK(sigchecklimiter4.check()); | ||||
// now in parallel again, grabbing the cached result. | // now in parallel again, grabbing the cached result. | ||||
std::vector<CScriptCheck> scriptchecks5; | std::vector<CScriptCheck> scriptchecks5; | ||||
CheckInputsLimiter sigchecklimiter5(2); | CheckInputsLimiter sigchecklimiter5(2); | ||||
BOOST_CHECK(CheckInputs(transaction, state, | BOOST_CHECK(CheckInputScripts( | ||||
&::ChainstateActive().CoinsTip(), flags, | transaction, state, &::ChainstateActive().CoinsTip(), flags, | ||||
true, true, txdata, nSigChecksDummy, | true, true, txdata, nSigChecksDummy, &scriptchecks5, | ||||
&scriptchecks5, &sigchecklimiter5)); | &sigchecklimiter5)); | ||||
BOOST_CHECK(scriptchecks5.empty()); | BOOST_CHECK(scriptchecks5.empty()); | ||||
BOOST_CHECK(sigchecklimiter5.check()); | BOOST_CHECK(sigchecklimiter5.check()); | ||||
/** | /** | ||||
* Going back to the lower limit, we now fail immediately due to the | * Going back to the lower limit, we now fail immediately due to the | ||||
* caching. | * caching. | ||||
*/ | */ | ||||
CheckInputsLimiter sigchecklimiter6(1); | CheckInputsLimiter sigchecklimiter6(1); | ||||
TxValidationState state6; | TxValidationState state6; | ||||
BOOST_CHECK(!CheckInputs(transaction, state6, | BOOST_CHECK(!CheckInputScripts( | ||||
&::ChainstateActive().CoinsTip(), flags, | transaction, state6, &::ChainstateActive().CoinsTip(), flags, | ||||
true, true, txdata, nSigChecksDummy, | true, true, txdata, nSigChecksDummy, nullptr, | ||||
nullptr, &sigchecklimiter6)); | &sigchecklimiter6)); | ||||
BOOST_CHECK_EQUAL(state6.GetRejectReason(), "too-many-sigchecks"); | BOOST_CHECK_EQUAL(state6.GetRejectReason(), "too-many-sigchecks"); | ||||
BOOST_CHECK_EQUAL(state6.GetResult(), | BOOST_CHECK_EQUAL(state6.GetResult(), | ||||
TxValidationResult::TX_CONSENSUS); | TxValidationResult::TX_CONSENSUS); | ||||
BOOST_CHECK(!sigchecklimiter6.check()); | BOOST_CHECK(!sigchecklimiter6.check()); | ||||
// even in parallel validation, immediate fail from the cache. | // even in parallel validation, immediate fail from the cache. | ||||
std::vector<CScriptCheck> scriptchecks7; | std::vector<CScriptCheck> scriptchecks7; | ||||
CheckInputsLimiter sigchecklimiter7(1); | CheckInputsLimiter sigchecklimiter7(1); | ||||
TxValidationState state7; | TxValidationState state7; | ||||
BOOST_CHECK(!CheckInputs(transaction, state7, | BOOST_CHECK(!CheckInputScripts( | ||||
&::ChainstateActive().CoinsTip(), flags, | transaction, state7, &::ChainstateActive().CoinsTip(), flags, | ||||
true, true, txdata, nSigChecksDummy, | true, true, txdata, nSigChecksDummy, &scriptchecks7, | ||||
&scriptchecks7, &sigchecklimiter7)); | &sigchecklimiter7)); | ||||
BOOST_CHECK_EQUAL(state7.GetRejectReason(), "too-many-sigchecks"); | BOOST_CHECK_EQUAL(state7.GetRejectReason(), "too-many-sigchecks"); | ||||
BOOST_CHECK_EQUAL(state6.GetResult(), | BOOST_CHECK_EQUAL(state6.GetResult(), | ||||
TxValidationResult::TX_CONSENSUS); | TxValidationResult::TX_CONSENSUS); | ||||
BOOST_CHECK(!sigchecklimiter7.check()); | BOOST_CHECK(!sigchecklimiter7.check()); | ||||
BOOST_CHECK(scriptchecks7.empty()); | BOOST_CHECK(scriptchecks7.empty()); | ||||
} | } | ||||
// 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(); | ||||
TxValidationState state; | TxValidationState state; | ||||
CTransaction transaction(tx); | CTransaction transaction(tx); | ||||
PrecomputedTransactionData txdata(transaction); | 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. | ||||
int nSigChecksDummy; | int nSigChecksDummy; | ||||
BOOST_CHECK(!CheckInputs(transaction, state, | BOOST_CHECK(!CheckInputScripts(transaction, state, | ||||
&::ChainstateActive().CoinsTip(), | &::ChainstateActive().CoinsTip(), | ||||
STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | STANDARD_SCRIPT_VERIFY_FLAGS, true, true, | ||||
txdata, nSigChecksDummy, nullptr)); | txdata, nSigChecksDummy, 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( | BOOST_CHECK(CheckInputScripts( | ||||
CheckInputs(transaction, state, &::ChainstateActive().CoinsTip(), | transaction, state, &::ChainstateActive().CoinsTip(), | ||||
STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENFORCE_SIGCHECKS, | STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENFORCE_SIGCHECKS, true, true, | ||||
true, true, txdata, nSigChecksDummy, &scriptchecks)); | txdata, nSigChecksDummy, &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(), 2U); | BOOST_CHECK_EQUAL(scriptchecks.size(), 2U); | ||||
// Execute the first check, and check its result | // Execute the first check, and check its result | ||||
BOOST_CHECK(scriptchecks[0]()); | BOOST_CHECK(scriptchecks[0]()); | ||||
BOOST_CHECK_EQUAL(scriptchecks[0].GetScriptError(), ScriptError::OK); | BOOST_CHECK_EQUAL(scriptchecks[0].GetScriptError(), ScriptError::OK); | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines |