/root/bitcoin/src/test/util/mining.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | using node::BlockAssembler; |
21 | | using node::NodeContext; |
22 | | |
23 | | COutPoint generatetoaddress(const NodeContext& node, const std::string& address) |
24 | 0 | { |
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 | | std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params) |
33 | 0 | { |
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 | 0 | } |
59 | 0 | } |
60 | 0 | return ret; |
61 | 0 | } |
62 | | |
63 | | COutPoint MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) |
64 | 0 | { |
65 | 0 | auto block = PrepareBlock(node, coinbase_scriptPubKey); |
66 | 0 | auto valid = MineBlock(node, block); |
67 | 0 | assert(!valid.IsNull()); |
68 | 0 | return valid; |
69 | 0 | } |
70 | | |
71 | | struct BlockValidationStateCatcher : public CValidationInterface { |
72 | | const uint256 m_hash; |
73 | | std::optional<BlockValidationState> m_state; |
74 | | |
75 | | BlockValidationStateCatcher(const uint256& hash) |
76 | 0 | : m_hash{hash}, |
77 | 0 | m_state{} {} |
78 | | |
79 | | protected: |
80 | | void BlockChecked(const CBlock& block, const BlockValidationState& state) override |
81 | 0 | { |
82 | 0 | if (block.GetHash() != m_hash) return; |
83 | 0 | m_state = state; |
84 | 0 | } |
85 | | }; |
86 | | |
87 | | COutPoint MineBlock(const NodeContext& node, std::shared_ptr<CBlock>& block) |
88 | 0 | { |
89 | 0 | while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) { |
90 | 0 | ++block->nNonce; |
91 | 0 | assert(block->nNonce); |
92 | 0 | } |
93 | | |
94 | 0 | auto& chainman{*Assert(node.chainman)}; |
95 | 0 | const auto old_height = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveHeight()); |
96 | 0 | bool new_block; |
97 | 0 | BlockValidationStateCatcher bvsc{block->GetHash()}; |
98 | 0 | node.validation_signals->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 | node.validation_signals->UnregisterValidationInterface(&bvsc); |
103 | 0 | node.validation_signals->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 | | std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey, |
112 | | const BlockAssembler::Options& assembler_options) |
113 | 0 | { |
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 | | std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) |
126 | 0 | { |
127 | 0 | BlockAssembler::Options assembler_options; |
128 | 0 | ApplyArgsManOptions(*node.args, assembler_options); |
129 | 0 | return PrepareBlock(node, coinbase_scriptPubKey, assembler_options); |
130 | 0 | } |