diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -20,6 +20,7 @@ #include "rpc/server.h" #include "script/scriptcache.h" #include "script/sigcache.h" +#include "script/standard.h" #include "txdb.h" #include "txmempool.h" #include "ui_interface.h" @@ -141,8 +142,28 @@ coinbaseKey.MakeNewKey(true); CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + + // Create a p2pkh coinbase + std::vector noTxns; + CBlock b1 = CreateAndProcessBlock(noTxns, scriptPubKey); + coinbaseTxns.push_back(*b1.vtx[0]); + + // Create a p2sh coinbase that can fail NULLDUMMY (Don't put the null in + // the txn). This is for testing consensus vs non-standard rules. + CKey dummyKey; + dummyKey.MakeNewKey(true); + CScript scriptPubKeyNullDummy = + CScript() << OP_1 << ToByteVector(coinbaseKey.GetPubKey()) + << ToByteVector(dummyKey.GetPubKey()) << OP_2 + << OP_CHECKMULTISIG; + CScript p2sh_scriptPubKeyNullDummy = + GetScriptForDestination(CScriptID(scriptPubKeyNullDummy)); + + CBlock b2 = CreateAndProcessBlock(noTxns, p2sh_scriptPubKeyNullDummy); + coinbaseTxns.push_back(*b2.vtx[0]); + + // Mature the coinbases for (int i = 0; i < COINBASE_MATURITY; i++) { - std::vector noTxns; CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey); coinbaseTxns.push_back(*b.vtx[0]); } @@ -164,6 +185,14 @@ for (const CMutableTransaction &tx : txns) { block.vtx.push_back(MakeTransactionRef(tx)); } + + // Order transactions by canonical order + std::sort(std::begin(block.vtx) + 1, std::end(block.vtx), + [](const std::shared_ptr &txa, + const std::shared_ptr &txb) -> bool { + return txa->GetId() < txb->GetId(); + }); + // IncrementExtraNonce creates a valid coinbase and merkleRoot unsigned int extraNonce = 0; IncrementExtraNonce(config, &block, chainActive.Tip(), extraNonce); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -114,6 +114,8 @@ bool ret = CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, nullptr); + std::cout << "CheckInputs: " << ret + << " Failure: " << state.GetRejectReason(); // CheckInputs should succeed iff test_flags doesn't intersect with // failing_flags @@ -174,7 +176,7 @@ mutableSpend_tx.nVersion = 1; mutableSpend_tx.vin.resize(1); - mutableSpend_tx.vin[0].prevout = COutPoint(coinbaseTxns[0].GetId(), 0); + mutableSpend_tx.vin[0].prevout = COutPoint(coinbaseTxns[1].GetId(), 0); mutableSpend_tx.vout.resize(4); mutableSpend_tx.vout[0].nValue = 11 * CENT; mutableSpend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey; @@ -194,10 +196,12 @@ std::vector vchSig; uint256 hash = SignatureHash( p2pk_scriptPubKey, CTransaction(mutableSpend_tx), 0, - SigHashType().withForkId(), coinbaseTxns[0].vout[0].nValue); + SigHashType().withForkId(), coinbaseTxns[1].vout[0].nValue); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); - mutableSpend_tx.vin[0].scriptSig << OP_TRUE << vchSig; + // First item will be dropped by CHECKMULTISIG + // This is to check nulldummy enforcement. It is OP_1 instead of OP_0 + mutableSpend_tx.vin[0].scriptSig << OP_1 << vchSig; } const CTransaction spend_tx(mutableSpend_tx); @@ -213,25 +217,25 @@ BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip.get(), true, MANDATORY_SCRIPT_VERIFY_FLAGS | - SCRIPT_VERIFY_CLEANSTACK, + SCRIPT_VERIFY_NULLDUMMY, true, true, ptd_spend_tx, nullptr)); // If we call again asking for scriptchecks (as happens in // ConnectBlock), we should add a script check object for this -- we're // not caching invalidity (if that changes, delete this test case). std::vector 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( + CheckInputs(spend_tx, state, pcoinsTip.get(), true, + MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_NULLDUMMY, + true, true, ptd_spend_tx, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), 1); // 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 // later that block validation works fine in the absence of cached // successes. - ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_CLEANSTACK, - false, false); + ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_NULLDUMMY, false, + false); // And if we produce a block with this tx, it should be valid (LOW_S not // enabled yet), even though there's no cache entry.