Changeset View
Changeset View
Standalone View
Standalone View
src/test/txvalidationcache_tests.cpp
Show First 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | CScript p2pkh_scriptPubKey = | ||||
GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); | GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); | ||||
CBasicKeyStore keystore; | CBasicKeyStore keystore; | ||||
keystore.AddKey(coinbaseKey); | keystore.AddKey(coinbaseKey); | ||||
keystore.AddCScript(p2pk_scriptPubKey); | keystore.AddCScript(p2pk_scriptPubKey); | ||||
CMutableTransaction funding_tx; | CMutableTransaction funding_tx; | ||||
// Needed when spending the output of this transaction | // Needed when spending the output of this transaction | ||||
CScript nulldummyPubKeyScript; | CScript noppyScriptPubKey; | ||||
// Create a funding transaction that can fail NULLDUMMY checks. This is for | // Create a transaction output that can fail DISCOURAGE_UPGRADABLE_NOPS | ||||
// testing consensus vs non-standard rules in `checkinputs_test`. | // checks when spent. This is for testing consensus vs non-standard rules in | ||||
// `checkinputs_test`. | |||||
{ | { | ||||
funding_tx.nVersion = 1; | funding_tx.nVersion = 1; | ||||
funding_tx.vin.resize(1); | funding_tx.vin.resize(1); | ||||
funding_tx.vin[0].prevout = COutPoint(m_coinbase_txns[0]->GetId(), 0); | funding_tx.vin[0].prevout = COutPoint(m_coinbase_txns[0]->GetId(), 0); | ||||
funding_tx.vout.resize(1); | funding_tx.vout.resize(1); | ||||
funding_tx.vout[0].nValue = 50 * COIN; | funding_tx.vout[0].nValue = 50 * COIN; | ||||
CKey dummyKey; | noppyScriptPubKey << OP_IF << OP_NOP10 << OP_ENDIF << OP_1; | ||||
dummyKey.MakeNewKey(true); | funding_tx.vout[0].scriptPubKey = noppyScriptPubKey; | ||||
nulldummyPubKeyScript << OP_1 << ToByteVector(coinbaseKey.GetPubKey()) | std::vector<uint8_t> fundingVchSig; | ||||
<< ToByteVector(dummyKey.GetPubKey()) << OP_2 | uint256 fundingSigHash = SignatureHash( | ||||
<< OP_CHECKMULTISIG; | |||||
funding_tx.vout[0].scriptPubKey = nulldummyPubKeyScript; | |||||
std::vector<uint8_t> nullDummyVchSig; | |||||
uint256 nulldummySigHash = SignatureHash( | |||||
p2pk_scriptPubKey, CTransaction(funding_tx), 0, | p2pk_scriptPubKey, CTransaction(funding_tx), 0, | ||||
SigHashType().withForkId(), m_coinbase_txns[0]->vout[0].nValue); | SigHashType().withForkId(), m_coinbase_txns[0]->vout[0].nValue); | ||||
BOOST_CHECK(coinbaseKey.SignECDSA(nulldummySigHash, nullDummyVchSig)); | BOOST_CHECK(coinbaseKey.SignECDSA(fundingSigHash, fundingVchSig)); | ||||
nullDummyVchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | fundingVchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | ||||
funding_tx.vin[0].scriptSig << nullDummyVchSig; | funding_tx.vin[0].scriptSig << fundingVchSig; | ||||
} | } | ||||
// Spend the funding transaction by mining it into a block | // Spend the funding transaction by mining it into a block | ||||
{ | { | ||||
CBlock block = CreateAndProcessBlock({funding_tx}, p2pk_scriptPubKey); | CBlock block = CreateAndProcessBlock({funding_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()); | ||||
} | } | ||||
// flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, | // flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, | ||||
// SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, SCRIPT_VERIFY_NULLDUMMY, uncompressed | // SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, | ||||
// pubkey thing | // SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS, uncompressed 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 spend_tx; | ||||
spend_tx.nVersion = 1; | spend_tx.nVersion = 1; | ||||
spend_tx.vin.resize(1); | spend_tx.vin.resize(1); | ||||
spend_tx.vin[0].prevout = COutPoint(funding_tx.GetId(), 0); | spend_tx.vin[0].prevout = COutPoint(funding_tx.GetId(), 0); | ||||
spend_tx.vout.resize(4); | spend_tx.vout.resize(4); | ||||
spend_tx.vout[0].nValue = 11 * CENT; | spend_tx.vout[0].nValue = 11 * CENT; | ||||
spend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey; | spend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey; | ||||
spend_tx.vout[1].nValue = 11 * CENT; | spend_tx.vout[1].nValue = 11 * CENT; | ||||
spend_tx.vout[1].scriptPubKey = | spend_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; | spend_tx.vout[2].nValue = 11 * CENT; | ||||
spend_tx.vout[2].scriptPubKey = | spend_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; | spend_tx.vout[3].nValue = 11 * CENT; | ||||
spend_tx.vout[3].scriptPubKey = p2sh_scriptPubKey; | spend_tx.vout[3].scriptPubKey = p2sh_scriptPubKey; | ||||
// Sign the main transaction that we spend from. | // "Sign" the main transaction that we spend from. | ||||
{ | { | ||||
std::vector<uint8_t> vchSig; | // This will cause OP_NOP10 to execute. | ||||
uint256 hash = SignatureHash( | spend_tx.vin[0].scriptSig << OP_1; | ||||
nulldummyPubKeyScript, CTransaction(spend_tx), 0, | |||||
SigHashType().withForkId(), funding_tx.vout[0].nValue); | |||||
coinbaseKey.SignECDSA(hash, vchSig); | |||||
vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); | |||||
// The last item on the stack will be dropped by CHECKMULTISIG This is | |||||
// to check nulldummy enforcement. It is OP_1 instead of OP_0. | |||||
spend_tx.vin[0].scriptSig << OP_1 << vchSig; | |||||
} | } | ||||
// 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 NULLDUMMY | // 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); | ||||
CValidationState state; | CValidationState state; | ||||
PrecomputedTransactionData ptd_spend_tx(tx); | PrecomputedTransactionData ptd_spend_tx(tx); | ||||
BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip.get(), true, | BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip.get(), true, | ||||
MANDATORY_SCRIPT_VERIFY_FLAGS | | MANDATORY_SCRIPT_VERIFY_FLAGS | | ||||
SCRIPT_VERIFY_NULLDUMMY, | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS, | ||||
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( | BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, | ||||
CheckInputs(tx, state, pcoinsTip.get(), true, | MANDATORY_SCRIPT_VERIFY_FLAGS | | ||||
MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_NULLDUMMY, | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS, | ||||
true, true, ptd_spend_tx, &scriptchecks)); | true, true, ptd_spend_tx, &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 CheckInputs returns true iff cleanstack-enforcing flags are | ||||
// not present. Don't add these checks to the cache, so that we can test | // not present. Don't add these checks to the cache, so that we can test | ||||
// later that block validation works fine in the absence of cached | // later that block validation works fine in the absence of cached | ||||
// successes. | // successes. | ||||
ValidateCheckInputsForAllFlags(tx, SCRIPT_VERIFY_NULLDUMMY, false, | ValidateCheckInputsForAllFlags( | ||||
false); | tx, SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS, false, false); | ||||
} | } | ||||
// 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, even though | ||||
// enabled yet), even though there's no cache entry. | // 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()); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
▲ Show 20 Lines • Show All 158 Lines • Show Last 20 Lines |