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