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 200 : COutPoint MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) 64 : { 65 200 : auto block = PrepareBlock(node, coinbase_scriptPubKey); 66 200 : auto valid = MineBlock(node, block); 67 200 : assert(!valid.IsNull()); 68 : return valid; 69 200 : } 70 : 71 : struct BlockValidationStateCatcher : public CValidationInterface { 72 : const uint256 m_hash; 73 : std::optional<BlockValidationState> m_state; 74 2 : 75 200 : BlockValidationStateCatcher(const uint256& hash) 76 200 : : m_hash{hash}, 77 400 : m_state{} {} 78 : 79 : protected: 80 200 : void BlockChecked(const CBlock& block, const BlockValidationState& state) override 81 : { 82 200 : if (block.GetHash() != m_hash) return; 83 200 : m_state = state; 84 200 : } 85 : }; 86 : 87 200 : COutPoint MineBlock(const NodeContext& node, std::shared_ptr<CBlock>& block) 88 : { 89 470 : while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) { 90 270 : ++block->nNonce; 91 270 : assert(block->nNonce); 92 : } 93 : 94 200 : auto& chainman{*Assert(node.chainman)}; 95 400 : const auto old_height = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveHeight()); 96 : bool new_block; 97 200 : BlockValidationStateCatcher bvsc{block->GetHash()}; 98 200 : RegisterValidationInterface(&bvsc); 99 200 : const bool processed{chainman.ProcessNewBlock(block, true, true, &new_block)}; 100 200 : const bool duplicate{!new_block && processed}; 101 200 : assert(!duplicate); 102 200 : UnregisterValidationInterface(&bvsc); 103 200 : SyncWithValidationInterfaceQueue(); 104 400 : const bool was_valid{bvsc.m_state && bvsc.m_state->IsValid()}; 105 400 : assert(old_height + was_valid == WITH_LOCK(chainman.GetMutex(), return chainman.ActiveHeight())); 106 : 107 200 : if (was_valid) return {block->vtx[0]->GetHash(), 0}; 108 0 : return {}; 109 200 : } 110 : 111 200 : std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey, 112 : const BlockAssembler::Options& assembler_options) 113 : { 114 200 : auto block = std::make_shared<CBlock>( 115 200 : BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get()), assembler_options} 116 200 : .CreateNewBlock(coinbase_scriptPubKey) 117 200 : ->block); 118 : 119 200 : LOCK(cs_main); 120 200 : block->nTime = Assert(node.chainman)->ActiveChain().Tip()->GetMedianTimePast() + 1; 121 200 : block->hashMerkleRoot = BlockMerkleRoot(*block); 122 : 123 200 : return block; 124 200 : } 125 200 : std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) 126 : { 127 200 : BlockAssembler::Options assembler_options; 128 200 : ApplyArgsManOptions(*node.args, assembler_options); 129 200 : return PrepareBlock(node, coinbase_scriptPubKey, assembler_options); 130 : }