// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #include #include #include using node::BlockAssembler; using node::NodeContext; COutPoint generatetoaddress(const NodeContext& node, const std::string& address) { const auto dest = DecodeDestination(address); assert(IsValidDestination(dest)); const auto coinbase_script = GetScriptForDestination(dest); return MineBlock(node, coinbase_script); } std::vector> CreateBlockChain(size_t total_height, const CChainParams& params) { std::vector> ret{total_height}; auto time{params.GenesisBlock().nTime}; for (size_t height{0}; height < total_height; ++height) { CBlock& block{*(ret.at(height) = std::make_shared())}; CMutableTransaction coinbase_tx; coinbase_tx.vin.resize(1); coinbase_tx.vin[0].prevout.SetNull(); coinbase_tx.vout.resize(1); coinbase_tx.vout[0].scriptPubKey = P2WSH_OP_TRUE; coinbase_tx.vout[0].nValue = GetBlockSubsidy(height + 1, params.GetConsensus()); coinbase_tx.vin[0].scriptSig = CScript() << (height + 1) << OP_0; block.vtx = {MakeTransactionRef(std::move(coinbase_tx))}; block.nVersion = VERSIONBITS_LAST_OLD_BLOCK_VERSION; block.hashPrevBlock = (height >= 1 ? *ret.at(height - 1) : params.GenesisBlock()).GetHash(); block.hashMerkleRoot = BlockMerkleRoot(block); block.nTime = ++time; block.nBits = params.GenesisBlock().nBits; block.nNonce = 0; while (!CheckProofOfWork(block.GetHash(), block.nBits, params.GetConsensus())) { ++block.nNonce; assert(block.nNonce); } } return ret; } COutPoint MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) { auto block = PrepareBlock(node, coinbase_scriptPubKey); auto valid = MineBlock(node, block); assert(!valid.IsNull()); return valid; } struct BlockValidationStateCatcher : public CValidationInterface { const uint256 m_hash; std::optional m_state; BlockValidationStateCatcher(const uint256& hash) : m_hash{hash}, m_state{} {} protected: void BlockChecked(const CBlock& block, const BlockValidationState& state) override { if (block.GetHash() != m_hash) return; m_state = state; } }; COutPoint MineBlock(const NodeContext& node, std::shared_ptr& block) { while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) { ++block->nNonce; assert(block->nNonce); } auto& chainman{*Assert(node.chainman)}; const auto old_height = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveHeight()); bool new_block; BlockValidationStateCatcher bvsc{block->GetHash()}; node.validation_signals->RegisterValidationInterface(&bvsc); const bool processed{chainman.ProcessNewBlock(block, true, true, &new_block)}; const bool duplicate{!new_block && processed}; assert(!duplicate); node.validation_signals->UnregisterValidationInterface(&bvsc); node.validation_signals->SyncWithValidationInterfaceQueue(); const bool was_valid{bvsc.m_state && bvsc.m_state->IsValid()}; assert(old_height + was_valid == WITH_LOCK(chainman.GetMutex(), return chainman.ActiveHeight())); if (was_valid) return {block->vtx[0]->GetHash(), 0}; return {}; } std::shared_ptr PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey, const BlockAssembler::Options& assembler_options) { auto block = std::make_shared( BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get()), assembler_options} .CreateNewBlock(coinbase_scriptPubKey) ->block); LOCK(cs_main); block->nTime = Assert(node.chainman)->ActiveChain().Tip()->GetMedianTimePast() + 1; block->hashMerkleRoot = BlockMerkleRoot(*block); return block; } std::shared_ptr PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) { BlockAssembler::Options assembler_options; ApplyArgsManOptions(*node.args, assembler_options); return PrepareBlock(node, coinbase_scriptPubKey, assembler_options); }