Changeset View
Changeset View
Standalone View
Standalone View
src/test/txvalidationcache_tests.cpp
Show First 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | mutableSpend_tx.vout[1].scriptPubKey = | ||||
<< ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; | << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; | ||||
mutableSpend_tx.vout[2].nValue = 11 * CENT; | mutableSpend_tx.vout[2].nValue = 11 * CENT; | ||||
mutableSpend_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; | ||||
mutableSpend_tx.vout[3].nValue = 11 * CENT; | mutableSpend_tx.vout[3].nValue = 11 * CENT; | ||||
mutableSpend_tx.vout[3].scriptPubKey = p2sh_scriptPubKey; | mutableSpend_tx.vout[3].scriptPubKey = p2sh_scriptPubKey; | ||||
// Sign, and push an extra element on the stack. | LOCK(cs_main); | ||||
// Test that invalidity under a set of flags doesn't preclude validity under | |||||
// other (eg consensus) flags. | |||||
{ | |||||
// Create a transaction which will fail cleanstack | |||||
{ | { | ||||
std::vector<uint8_t> vchSig; | std::vector<uint8_t> vchSig; | ||||
uint256 hash = SignatureHash( | uint256 hash = SignatureHash( | ||||
p2pk_scriptPubKey, CTransaction(mutableSpend_tx), 0, | p2pk_scriptPubKey, CTransaction(mutableSpend_tx), 0, | ||||
SigHashType().withForkId(), coinbaseTxns[0].vout[0].nValue); | SigHashType().withForkId(), 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)); | ||||
mutableSpend_tx.vin[0].scriptSig << OP_TRUE << vchSig; | mutableSpend_tx.vin[0].scriptSig = CScript() << OP_1 << vchSig; | ||||
} | } | ||||
const CTransaction dirtystack_tx(mutableSpend_tx); | |||||
const CTransaction spend_tx(mutableSpend_tx); | |||||
LOCK(cs_main); | |||||
// Test that invalidity under a set of flags doesn't preclude validity under | |||||
// other (eg consensus) flags. | |||||
// spend_tx is invalid according to DERSIG | |||||
{ | |||||
CValidationState state; | CValidationState state; | ||||
PrecomputedTransactionData ptd_spend_tx(spend_tx); | PrecomputedTransactionData ptd_spend_tx(dirtystack_tx); | ||||
BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip.get(), true, | // Invalid under cleanstack | ||||
BOOST_CHECK(!CheckInputs(dirtystack_tx, state, pcoinsTip.get(), true, | |||||
MANDATORY_SCRIPT_VERIFY_FLAGS | | MANDATORY_SCRIPT_VERIFY_FLAGS | | ||||
SCRIPT_VERIFY_CLEANSTACK, | SCRIPT_VERIFY_CLEANSTACK, | ||||
true, true, ptd_spend_tx, nullptr)); | true, true, ptd_spend_tx, 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(spend_tx, state, pcoinsTip.get(), true, | BOOST_CHECK(CheckInputs(dirtystack_tx, state, pcoinsTip.get(), true, | ||||
MANDATORY_SCRIPT_VERIFY_FLAGS | | MANDATORY_SCRIPT_VERIFY_FLAGS | | ||||
SCRIPT_VERIFY_CLEANSTACK, | SCRIPT_VERIFY_CLEANSTACK, | ||||
true, true, ptd_spend_tx, &scriptchecks)); | true, true, ptd_spend_tx, &scriptchecks)); | ||||
BOOST_CHECK_EQUAL(scriptchecks.size(), 1); | BOOST_CHECK_EQUAL(scriptchecks.size(), 1); | ||||
// Test that CheckInputs returns true iff cleanstack-enforcing flags are | // Test that CheckInputs returns false if cleanstack is enforced for | ||||
// not present. Don't add these checks to the cache, so that we can test | // all combinations of flags | ||||
// later that block validation works fine in the absence of cached | ValidateCheckInputsForAllFlags(dirtystack_tx, SCRIPT_VERIFY_CLEANSTACK, | ||||
// successes. | |||||
ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_CLEANSTACK, | |||||
false, false); | false, false); | ||||
} | |||||
// Create a transaction we can spend | |||||
// 1. Sign | |||||
{ | |||||
std::vector<uint8_t> vchSig; | |||||
uint256 hash = SignatureHash( | |||||
p2pk_scriptPubKey, CTransaction(mutableSpend_tx), 0, | |||||
SigHashType().withForkId(), coinbaseTxns[0].vout[0].nValue); | |||||
BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); | |||||
vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | |||||
mutableSpend_tx.vin[0].scriptSig = CScript() << vchSig; | |||||
} | |||||
const CTransaction spend_tx(mutableSpend_tx); | |||||
// 2. Spend into UTXOs we can respend later | |||||
{ | |||||
CValidationState state; | |||||
PrecomputedTransactionData ptd_spend_tx(spend_tx); | |||||
// Valid under cleanstack, but don't cache or the next step | |||||
// check won't be able to be tested. | |||||
BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip.get(), true, | |||||
MANDATORY_SCRIPT_VERIFY_FLAGS | | |||||
SCRIPT_VERIFY_CLEANSTACK, | |||||
true, false, ptd_spend_tx, nullptr)); | |||||
// If we call again asking for scriptchecks (as happens in | |||||
// ConnectBlock), we should add a script check object for this. | |||||
std::vector<CScriptCheck> scriptchecks; | |||||
BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip.get(), true, | |||||
MANDATORY_SCRIPT_VERIFY_FLAGS | | |||||
SCRIPT_VERIFY_CLEANSTACK, | |||||
true, true, ptd_spend_tx, &scriptchecks)); | |||||
BOOST_CHECK_EQUAL(scriptchecks.size(), 1); | |||||
// And if we produce a block with this tx, it should be valid (LOW_S not | // And if we produce a block with this tx, it should be valid. | ||||
// enabled yet), even though there's no cache entry. | |||||
CBlock block; | CBlock block; | ||||
block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey); | block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey); | ||||
BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); | BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); | ||||
BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash()); | BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash()); | ||||
} | } | ||||
// Test P2SH: construct a transaction that is valid without P2SH, and then | // Test P2SH: construct a transaction that is valid without P2SH, and then | ||||
▲ Show 20 Lines • Show All 149 Lines • Show Last 20 Lines |