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) 2021-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <consensus/amount.h>6#include <pubkey.h>7#include <test/fuzz/util.h>8#include <test/util/script.h>9#include <util/check.h>10#include <util/overflow.h>11#include <util/rbf.h>12#include <util/time.h>14#include <memory>16std::vector<uint8_t> ConstructPubKeyBytes(FuzzedDataProvider& fuzzed_data_provider, std::span<const uint8_t> byte_data, const bool compressed) noexcept17{18uint8_t pk_type;19if (compressed) {20pk_type = fuzzed_data_provider.PickValueInArray({0x02, 0x03});21} else {22pk_type = fuzzed_data_provider.PickValueInArray({0x04, 0x06, 0x07});23}24std::vector<uint8_t> pk_data{byte_data.begin(), byte_data.begin() + (compressed ? CPubKey::COMPRESSED_SIZE : CPubKey::SIZE)};25pk_data[0] = pk_type;26return pk_data;27}29CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max) noexcept30{31return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, max.value_or(MAX_MONEY));32}34NodeSeconds ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min, const std::optional<int64_t>& max) noexcept35{36// Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) disables mocktime.37static const int64_t time_min{ParseISO8601DateTime("2000-01-01T00:00:01Z").value()};38static const int64_t time_max{ParseISO8601DateTime("2100-12-31T23:59:59Z").value()};39return NodeSeconds{ConsumeDuration<std::chrono::seconds>(fuzzed_data_provider, min.value_or(time_min) * 1s, max.value_or(time_max) * 1s)};40}42CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<Txid>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept43{44CMutableTransaction tx_mut;45const auto p2wsh_op_true = fuzzed_data_provider.ConsumeBool();46tx_mut.version = fuzzed_data_provider.ConsumeBool() ?47CTransaction::CURRENT_VERSION :48fuzzed_data_provider.ConsumeIntegral<uint32_t>();49tx_mut.nLockTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>();50const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_in);51const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_out);52for (int i = 0; i < num_in; ++i) {53const auto& txid_prev = prevout_txids ?54PickValue(fuzzed_data_provider, *prevout_txids) :55Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider));56const auto index_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, max_num_out);57const auto sequence = ConsumeSequence(fuzzed_data_provider);58const auto script_sig = p2wsh_op_true ? CScript{} : ConsumeScript(fuzzed_data_provider);59CScriptWitness script_wit;60if (p2wsh_op_true) {61script_wit.stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};62} else {63script_wit = ConsumeScriptWitness(fuzzed_data_provider);64}65CTxIn in;66in.prevout = COutPoint{txid_prev, index_out};67in.nSequence = sequence;68in.scriptSig = script_sig;69in.scriptWitness = script_wit;71tx_mut.vin.push_back(in);72}73for (int i = 0; i < num_out; ++i) {74const auto amount = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);75const auto script_pk = p2wsh_op_true ?76P2WSH_OP_TRUE :77ConsumeScript(fuzzed_data_provider, /*maybe_p2wsh=*/true);78tx_mut.vout.emplace_back(amount, script_pk);79}80return tx_mut;81}83CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size) noexcept84{85CScriptWitness ret;86const auto n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_stack_elem_size);87for (size_t i = 0; i < n_elements; ++i) {88ret.stack.push_back(ConsumeRandomLengthByteVector(fuzzed_data_provider));89}90return ret;91}93CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const bool maybe_p2wsh) noexcept94{95CScript r_script{};96{97// Keep a buffer of bytes to allow the fuzz engine to produce smaller98// inputs to generate CScripts with repeated data.99static constexpr unsigned MAX_BUFFER_SZ{128};100std::vector<uint8_t> buffer(MAX_BUFFER_SZ, uint8_t{'a'});101while (fuzzed_data_provider.ConsumeBool()) {102CallOneOf(103fuzzed_data_provider,104[&] {105// Insert byte vector directly to allow malformed or unparsable scripts106r_script.insert(r_script.end(), buffer.begin(), buffer.begin() + fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BUFFER_SZ));107},108[&] {109// Push a byte vector from the buffer110r_script << std::vector<uint8_t>{buffer.begin(), buffer.begin() + fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BUFFER_SZ)};111},112[&] {113// Push multisig114// There is a special case for this to aid the fuzz engine115// navigate the highly structured multisig format.116r_script << fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 22);117int num_data{fuzzed_data_provider.ConsumeIntegralInRange(1, 22)};118while (num_data--) {119auto pubkey_bytes{ConstructPubKeyBytes(fuzzed_data_provider, buffer, fuzzed_data_provider.ConsumeBool())};120if (fuzzed_data_provider.ConsumeBool()) {121pubkey_bytes.back() = num_data; // Make each pubkey different122}123r_script << pubkey_bytes;124}125r_script << fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 22);126},127[&] {128// Mutate the buffer129const auto vec{ConsumeRandomLengthByteVector(fuzzed_data_provider, /*max_length=*/MAX_BUFFER_SZ)};130std::copy(vec.begin(), vec.end(), buffer.begin());131},132[&] {133// Push an integral134r_script << fuzzed_data_provider.ConsumeIntegral<int64_t>();135},136[&] {137// Push an opcode138r_script << ConsumeOpcodeType(fuzzed_data_provider);139},140[&] {141// Push a scriptnum142r_script << ConsumeScriptNum(fuzzed_data_provider);143});144}145}146if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool()) {147uint256 script_hash;148CSHA256().Write(r_script.data(), r_script.size()).Finalize(script_hash.begin());149r_script.clear();150r_script << OP_0 << ToByteVector(script_hash);151}152return r_script;153}155uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept156{157return fuzzed_data_provider.ConsumeBool() ?158fuzzed_data_provider.PickValueInArray({159CTxIn::SEQUENCE_FINAL,160CTxIn::MAX_SEQUENCE_NONFINAL,161MAX_BIP125_RBF_SEQUENCE,162}) :163fuzzed_data_provider.ConsumeIntegral<uint32_t>();164}166std::map<COutPoint, Coin> ConsumeCoins(FuzzedDataProvider& fuzzed_data_provider) noexcept167{168std::map<COutPoint, Coin> coins;169LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 10000) {170const std::optional<COutPoint> outpoint{ConsumeDeserializable<COutPoint>(fuzzed_data_provider)};171if (!outpoint) {172break;173}174const std::optional<Coin> coin{ConsumeDeserializable<Coin>(fuzzed_data_provider)};175if (!coin) {176break;177}178coins[*outpoint] = *coin;179}181return coins;182}184CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept185{186CTxDestination tx_destination;187const size_t call_size{CallOneOf(188fuzzed_data_provider,189[&] {190tx_destination = CNoDestination{};191},192[&] {193bool compressed = fuzzed_data_provider.ConsumeBool();194CPubKey pk{ConstructPubKeyBytes(195fuzzed_data_provider,196ConsumeFixedLengthByteVector(fuzzed_data_provider, (compressed ? CPubKey::COMPRESSED_SIZE : CPubKey::SIZE)),197compressed198)};199tx_destination = PubKeyDestination{pk};200},201[&] {202tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};203},204[&] {205tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)};206},207[&] {208tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)};209},210[&] {211tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)};212},213[&] {214tx_destination = WitnessV1Taproot{XOnlyPubKey{ConsumeUInt256(fuzzed_data_provider)}};215},216[&] {217tx_destination = PayToAnchor{};218},219[&] {220std::vector<unsigned char> program{ConsumeRandomLengthByteVector(fuzzed_data_provider, /*max_length=*/40)};221if (program.size() < 2) {222program = {0, 0};223}224tx_destination = WitnessUnknown{fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(2, 16), program};225})};226Assert(call_size == std::variant_size_v<CTxDestination>);227return tx_destination;228}230CKey ConsumePrivateKey(FuzzedDataProvider& fuzzed_data_provider, std::optional<bool> compressed) noexcept231{232auto key_data = fuzzed_data_provider.ConsumeBytes<uint8_t>(32);233key_data.resize(32);234CKey key;235bool compressed_value = compressed ? *compressed : fuzzed_data_provider.ConsumeBool();236key.Set(key_data.begin(), key_data.end(), compressed_value);237return key;238}240bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept241{242for (const CTxIn& tx_in : tx.vin) {243const Coin& coin = inputs.AccessCoin(tx_in.prevout);244if (coin.IsSpent()) {245return true;246}247}248return false;249}
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.