Branch data Line data Source code
1 : : // Copyright (c) 2019-2022 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 <test/util/mining.h> 6 : : 7 : : #include <chainparams.h> 8 : : #include <consensus/merkle.h> 9 : : #include <consensus/validation.h> 10 : : #include <key_io.h> 11 [ + - ]: 2 : #include <node/context.h> 12 [ + - ]: 2 : #include <pow.h> 13 : 2 : #include <primitives/transaction.h> 14 [ + - ]: 2 : #include <test/util/script.h> 15 [ + - + - : 2 : #include <util/check.h> + - ] 16 : : #include <validation.h> 17 [ + - ]: 2 : #include <validationinterface.h> 18 [ + - ]: 2 : #include <versionbits.h> 19 : : 20 : : using node::BlockAssembler; 21 : : using node::NodeContext; 22 : : 23 : 0 : COutPoint generatetoaddress(const NodeContext& node, const std::string& address) 24 : : { 25 : 0 : const auto dest = DecodeDestination(address); 26 [ # # # # ]: 0 : assert(IsValidDestination(dest)); 27 [ # # ]: 0 : const auto coinbase_script = GetScriptForDestination(dest); 28 : : 29 [ # # ]: 0 : return MineBlock(node, coinbase_script); 30 : 0 : } 31 : : 32 : 0 : std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params) 33 : : { 34 [ # # ]: 0 : std::vector<std::shared_ptr<CBlock>> ret{total_height}; 35 [ # # ]: 0 : auto time{params.GenesisBlock().nTime}; 36 [ # # ]: 0 : for (size_t height{0}; height < total_height; ++height) { 37 [ # # # # ]: 0 : CBlock& block{*(ret.at(height) = std::make_shared<CBlock>())}; 38 : : 39 [ # # ]: 0 : CMutableTransaction coinbase_tx; 40 [ # # ]: 0 : coinbase_tx.vin.resize(1); 41 [ # # ]: 0 : coinbase_tx.vin[0].prevout.SetNull(); 42 [ # # ]: 0 : coinbase_tx.vout.resize(1); 43 [ # # ]: 0 : coinbase_tx.vout[0].scriptPubKey = P2WSH_OP_TRUE; 44 [ # # # # ]: 0 : coinbase_tx.vout[0].nValue = GetBlockSubsidy(height + 1, params.GetConsensus()); 45 [ # # # # : 0 : coinbase_tx.vin[0].scriptSig = CScript() << (height + 1) << OP_0; # # # # ] 46 [ # # # # ]: 0 : block.vtx = {MakeTransactionRef(std::move(coinbase_tx))}; 47 : : 48 : 0 : block.nVersion = VERSIONBITS_LAST_OLD_BLOCK_VERSION; 49 [ # # # # : 0 : block.hashPrevBlock = (height >= 1 ? *ret.at(height - 1) : params.GenesisBlock()).GetHash(); # # # # ] 50 [ # # ]: 0 : block.hashMerkleRoot = BlockMerkleRoot(block); 51 : 0 : block.nTime = ++time; 52 [ # # ]: 0 : block.nBits = params.GenesisBlock().nBits; 53 : 0 : block.nNonce = 0; 54 : : 55 [ # # # # : 0 : while (!CheckProofOfWork(block.GetHash(), block.nBits, params.GetConsensus())) { # # # # ] 56 : 0 : ++block.nNonce; 57 [ # # ]: 0 : assert(block.nNonce); 58 : : } 59 : 0 : } 60 : 0 : return ret; 61 [ # # ]: 0 : } 62 : : 63 : 0 : COutPoint MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) 64 : : { 65 : 0 : auto block = PrepareBlock(node, coinbase_scriptPubKey); 66 [ # # ]: 0 : auto valid = MineBlock(node, block); 67 [ # # # # ]: 0 : assert(!valid.IsNull()); 68 : : return valid; 69 : 0 : } 70 : : 71 : : struct BlockValidationStateCatcher : public CValidationInterface { 72 : : const uint256 m_hash; 73 : : std::optional<BlockValidationState> m_state; 74 : 2 : 75 : 0 : BlockValidationStateCatcher(const uint256& hash) 76 : 0 : : m_hash{hash}, 77 : 0 : m_state{} {} 78 : : 79 : : protected: 80 : 0 : void BlockChecked(const CBlock& block, const BlockValidationState& state) override 81 : : { 82 [ # # ]: 0 : if (block.GetHash() != m_hash) return; 83 : 0 : m_state = state; 84 : 0 : } 85 : : }; 86 : : 87 : 0 : COutPoint MineBlock(const NodeContext& node, std::shared_ptr<CBlock>& block) 88 : : { 89 [ # # ]: 0 : while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) { 90 : 0 : ++block->nNonce; 91 [ # # ]: 0 : assert(block->nNonce); 92 : : } 93 : : 94 : 0 : auto& chainman{*Assert(node.chainman)}; 95 [ # # ]: 0 : const auto old_height = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveHeight()); 96 : : bool new_block; 97 : 0 : BlockValidationStateCatcher bvsc{block->GetHash()}; 98 [ # # ]: 0 : RegisterValidationInterface(&bvsc); 99 [ # # ]: 0 : const bool processed{chainman.ProcessNewBlock(block, true, true, &new_block)}; 100 [ # # ]: 0 : const bool duplicate{!new_block && processed}; 101 [ # # ]: 0 : assert(!duplicate); 102 [ # # ]: 0 : UnregisterValidationInterface(&bvsc); 103 [ # # ]: 0 : SyncWithValidationInterfaceQueue(); 104 [ # # # # : 0 : const bool was_valid{bvsc.m_state && bvsc.m_state->IsValid()}; # # ] 105 [ # # # # : 0 : assert(old_height + was_valid == WITH_LOCK(chainman.GetMutex(), return chainman.ActiveHeight())); # # # # # # ] 106 : : 107 [ # # # # : 0 : if (was_valid) return {block->vtx[0]->GetHash(), 0}; # # ] 108 [ # # ]: 0 : return {}; 109 : 0 : } 110 : : 111 : 0 : std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey, 112 : : const BlockAssembler::Options& assembler_options) 113 : : { 114 [ # # ]: 0 : auto block = std::make_shared<CBlock>( 115 : 0 : BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get()), assembler_options} 116 [ # # ]: 0 : .CreateNewBlock(coinbase_scriptPubKey) 117 : 0 : ->block); 118 : : 119 [ # # # # ]: 0 : LOCK(cs_main); 120 [ # # # # : 0 : block->nTime = Assert(node.chainman)->ActiveChain().Tip()->GetMedianTimePast() + 1; # # # # ] 121 [ # # ]: 0 : block->hashMerkleRoot = BlockMerkleRoot(*block); 122 : : 123 : 0 : return block; 124 [ # # ]: 0 : } 125 : 0 : std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) 126 : : { 127 : 0 : BlockAssembler::Options assembler_options; 128 : 0 : ApplyArgsManOptions(*node.args, assembler_options); 129 : 0 : return PrepareBlock(node, coinbase_scriptPubKey, assembler_options); 130 : : }