Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2022-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or https://www.opensource.org/licenses/mit-license.php.5#include <addresstype.h>6#include <bench/bench.h>7#include <chain.h>8#include <chainparams.h>9#include <consensus/amount.h>10#include <consensus/consensus.h>11#include <consensus/merkle.h>12#include <kernel/chain.h>13#include <kernel/types.h>14#include <node/blockstorage.h>15#include <outputtype.h>16#include <primitives/block.h>17#include <primitives/transaction.h>18#include <script/script.h>19#include <sync.h>20#include <test/util/setup_common.h>21#include <test/util/time.h>22#include <uint256.h>23#include <util/check.h>24#include <util/result.h>25#include <validation.h>26#include <versionbits.h>27#include <wallet/coincontrol.h>28#include <wallet/coinselection.h>29#include <wallet/spend.h>30#include <wallet/sqlite.h>31#include <wallet/test/util.h>32#include <wallet/wallet.h>33#include <wallet/walletutil.h>35#include <cstdint>36#include <map>37#include <memory>38#include <optional>39#include <string>40#include <utility>41#include <vector>43using kernel::ChainstateRole;44using wallet::CWallet;45using wallet::MakeInMemoryWalletDatabase;46using wallet::WALLET_FLAG_DESCRIPTORS;48struct TipBlock49{50uint256 prev_block_hash;51int64_t prev_block_time;52int tip_height;53};55TipBlock getTip(const CChainParams& params, const node::NodeContext& context)56{57auto tip = WITH_LOCK(::cs_main, return context.chainman->ActiveTip());58return (tip) ? TipBlock{tip->GetBlockHash(), tip->GetBlockTime(), tip->nHeight} :59TipBlock{params.GenesisBlock().GetHash(), params.GenesisBlock().GetBlockTime(), 0};60}62void generateFakeBlock(const CChainParams& params,63const node::NodeContext& context,64CWallet& wallet,65const CScript& coinbase_out_script)66{67TipBlock tip{getTip(params, context)};69// Create block70CBlock block;71CMutableTransaction coinbase_tx;72coinbase_tx.vin.resize(1);73coinbase_tx.vin[0].prevout.SetNull();74coinbase_tx.vout.resize(2);75coinbase_tx.vout[0].scriptPubKey = coinbase_out_script;76coinbase_tx.vout[0].nValue = 48 * COIN;77coinbase_tx.vin[0].scriptSig = CScript() << ++tip.tip_height << OP_0;78coinbase_tx.vout[1].scriptPubKey = coinbase_out_script; // extra output79coinbase_tx.vout[1].nValue = 1 * COIN;81// Fill the coinbase with outputs that don't belong to the wallet in order to benchmark82// AvailableCoins' behavior with unnecessary TXOs83for (int i = 0; i < 50; ++i) {84coinbase_tx.vout.emplace_back(1 * COIN / 50, CScript(OP_TRUE));85}87block.vtx = {MakeTransactionRef(std::move(coinbase_tx))};89block.nVersion = VERSIONBITS_LAST_OLD_BLOCK_VERSION;90block.hashPrevBlock = tip.prev_block_hash;91block.hashMerkleRoot = BlockMerkleRoot(block);92block.nTime = ++tip.prev_block_time;93block.nBits = params.GenesisBlock().nBits;94block.nNonce = 0;96{97LOCK(::cs_main);98// Add it to the index99CBlockIndex* pindex{context.chainman->m_blockman.AddToBlockIndex(block, context.chainman->m_best_header)};100// add it to the chain101context.chainman->ActiveChain().SetTip(*pindex);102}104// notify wallet105const auto& pindex = WITH_LOCK(::cs_main, return context.chainman->ActiveChain().Tip());106wallet.blockConnected(ChainstateRole{}, kernel::MakeBlockInfo(pindex, &block));107}109struct PreSelectInputs {110// How many coins from the wallet the process should select111int num_of_internal_inputs;112// future: this could have external inputs as well.113};115static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type, bool allow_other_inputs, std::optional<PreSelectInputs> preset_inputs)116{117const auto test_setup = MakeNoLogFileContext<const TestingSetup>();119// Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.120FakeNodeClock clock{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()};121CWallet wallet{test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()};122{123LOCK(wallet.cs_wallet);124wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);125wallet.SetupDescriptorScriptPubKeyMans();126}128// Generate destinations129const auto dest{getNewDestination(wallet, output_type)};131// Generate chain; each coinbase will have two outputs to fill-up the wallet132const auto& params = Params();133const CScript coinbase_out{GetScriptForDestination(dest)};134unsigned int chain_size = 5000; // 5k blocks means 10k UTXO for the wallet (minus 200 due COINBASE_MATURITY)135for (unsigned int i = 0; i < chain_size; ++i) {136generateFakeBlock(params, test_setup->m_node, wallet, coinbase_out);137}139// Check available balance140auto bal = WITH_LOCK(wallet.cs_wallet, return wallet::AvailableCoins(wallet).GetTotalAmount()); // Cache141assert(bal == 49 * COIN * (chain_size - COINBASE_MATURITY));143wallet::CCoinControl coin_control;144coin_control.m_allow_other_inputs = allow_other_inputs;146CAmount target = 0;147if (preset_inputs) {148// Select inputs, each has 48 BTC149wallet::CoinFilterParams filter_coins;150filter_coins.max_count = preset_inputs->num_of_internal_inputs;151const auto& res = WITH_LOCK(wallet.cs_wallet,152return wallet::AvailableCoins(wallet, /*coinControl=*/nullptr, /*feerate=*/std::nullopt, filter_coins));153for (int i=0; i < preset_inputs->num_of_internal_inputs; i++) {154const auto& coin{res.coins.at(output_type)[i]};155target += coin.txout.nValue;156coin_control.Select(coin.outpoint);157}158}160// If automatic coin selection is enabled, add the value of another UTXO to the target161if (coin_control.m_allow_other_inputs) target += 50 * COIN;162std::vector<wallet::CRecipient> recipients = {{dest, target, true}};164bench.run([&] {165LOCK(wallet.cs_wallet);166const auto& tx_res = CreateTransaction(wallet, recipients, /*change_pos=*/std::nullopt, coin_control);167assert(tx_res);168});169}171static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType>& output_type)172{173const auto test_setup = MakeNoLogFileContext<const TestingSetup>();174// Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.175FakeNodeClock clock{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()};176CWallet wallet{test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()};177{178LOCK(wallet.cs_wallet);179wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);180wallet.SetupDescriptorScriptPubKeyMans();181}183// Generate destinations184std::vector<CScript> dest_wallet;185dest_wallet.reserve(output_type.size());186for (auto type : output_type) {187dest_wallet.emplace_back(GetScriptForDestination(getNewDestination(wallet, type)));188}190// Generate chain; each coinbase will have two outputs to fill-up the wallet191const auto& params = Params();192unsigned int chain_size = 1000;193for (unsigned int i = 0; i < chain_size / dest_wallet.size(); ++i) {194for (const auto& dest : dest_wallet) {195generateFakeBlock(params, test_setup->m_node, wallet, dest);196}197}199// Check available balance200auto bal = WITH_LOCK(wallet.cs_wallet, return wallet::AvailableCoins(wallet).GetTotalAmount()); // Cache201assert(bal == 49 * COIN * (chain_size - COINBASE_MATURITY));203bench.run([&] {204LOCK(wallet.cs_wallet);205const auto& res = wallet::AvailableCoins(wallet);206assert(res.All().size() == (chain_size - COINBASE_MATURITY) * 2);207});208}210static void WalletCreateTxUseOnlyPresetInputs(benchmark::Bench& bench) { WalletCreateTx(bench, OutputType::BECH32, /*allow_other_inputs=*/false,211{{/*num_of_internal_inputs=*/4}}); }213static void WalletCreateTxUsePresetInputsAndCoinSelection(benchmark::Bench& bench) { WalletCreateTx(bench, OutputType::BECH32, /*allow_other_inputs=*/true,214{{/*num_of_internal_inputs=*/4}}); }216static void WalletAvailableCoins(benchmark::Bench& bench) { AvailableCoins(bench, {OutputType::BECH32M}); }218BENCHMARK(WalletCreateTxUseOnlyPresetInputs);219BENCHMARK(WalletCreateTxUsePresetInputsAndCoinSelection);220BENCHMARK(WalletAvailableCoins);
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.