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