1 // Copyright (c) 2011-2018 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <bench/bench.h>
6 #include <chainparams.h>
7 #include <coins.h>
8 #include <consensus/merkle.h>
9 #include <consensus/validation.h>
10 #include <miner.h>
11 #include <policy/policy.h>
12 #include <pow.h>
13 #include <scheduler.h>
14 #include <txdb.h>
15 #include <txmempool.h>
16 #include <util/time.h>
17 #include <validation.h>
18 #include <validationinterface.h>
19 
20 #include <boost/thread.hpp>
21 
22 #include <list>
23 #include <vector>
24 
25 
DuplicateInputs(benchmark::State & state)26 static void DuplicateInputs(benchmark::State& state)
27 {
28     const CScript SCRIPT_PUB{CScript(OP_TRUE)};
29 
30     // Switch to regtest so we can mine faster
31     // Also segwit is active, so we can include witness transactions
32     SelectParams(CBaseChainParams::REGTEST);
33 
34     InitScriptExecutionCache();
35 
36     boost::thread_group thread_group;
37     CScheduler scheduler;
38     const CChainParams& chainparams = Params();
39     {
40         LOCK(cs_main);
41         ::pblocktree.reset(new CBlockTreeDB(1 << 20, true));
42         ::pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
43         ::pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
44     }
45     {
46         thread_group.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
47         GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
48         LoadGenesisBlock(chainparams);
49         CValidationState cvstate;
50         ActivateBestChain(cvstate, chainparams);
51         assert(::chainActive.Tip() != nullptr);
52         const bool witness_enabled{IsWitnessEnabled(::chainActive.Tip(), chainparams.GetConsensus())};
53         assert(witness_enabled);
54     }
55 
56     CBlock block{};
57     CMutableTransaction coinbaseTx{};
58     CMutableTransaction naughtyTx{};
59 
60     CBlockIndex* pindexPrev = ::chainActive.Tip();
61     assert(pindexPrev != nullptr);
62     block.nBits = GetNextWorkRequired(pindexPrev, &block, chainparams.GetConsensus());
63     block.nNonce = 0;
64     auto nHeight = pindexPrev->nHeight + 1;
65 
66     // Make a coinbase TX
67     coinbaseTx.vin.resize(1);
68     coinbaseTx.vin[0].prevout.SetNull();
69     coinbaseTx.vout.resize(1);
70     coinbaseTx.vout[0].scriptPubKey = SCRIPT_PUB;
71     coinbaseTx.vout[0].nValue = GetBlockSubsidy(nHeight, chainparams.GetConsensus());
72     coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
73 
74 
75     naughtyTx.vout.resize(1);
76     naughtyTx.vout[0].nValue = 0;
77     naughtyTx.vout[0].scriptPubKey = SCRIPT_PUB;
78 
79     uint64_t n_inputs = (((MAX_BLOCK_SERIALIZED_SIZE / WITNESS_SCALE_FACTOR) - (CTransaction(coinbaseTx).GetTotalSize() + CTransaction(naughtyTx).GetTotalSize())) / 41) - 100;
80     for (uint64_t x = 0; x < (n_inputs - 1); ++x) {
81         naughtyTx.vin.emplace_back(GetRandHash(), 0, CScript(), 0);
82     }
83     naughtyTx.vin.emplace_back(naughtyTx.vin.back());
84 
85     block.vtx.push_back(MakeTransactionRef(std::move(coinbaseTx)));
86     block.vtx.push_back(MakeTransactionRef(std::move(naughtyTx)));
87 
88     block.hashMerkleRoot = BlockMerkleRoot(block);
89 
90     while (state.KeepRunning()) {
91         CValidationState cvstate{};
92         assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
93         assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
94     }
95 
96     thread_group.interrupt_all();
97     thread_group.join_all();
98     GetMainSignals().FlushBackgroundCallbacks();
99     GetMainSignals().UnregisterBackgroundSignalScheduler();
100 }
101 
102 BENCHMARK(DuplicateInputs, 10);
103