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) 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 <random.h>6#include <span.h>7#include <test/fuzz/util.h>8#include <util/bitset.h>10#include <bitset>11#include <vector>13namespace {15/** Pop the first byte from a byte-span, and return it. */16uint8_t ReadByte(FuzzBufferType& buffer)17{18if (buffer.empty()) return 0;19uint8_t ret = buffer.front();20buffer = buffer.subspan(1);21return ret;22}24/** Perform a simulation fuzz test on BitSet type S. */25template<typename S>26void TestType(FuzzBufferType buffer)27{28/** This fuzz test's design is based on the assumption that the actual bits stored in the29* bitsets and their simulations do not matter for the purpose of detecting edge cases, thus30* these are taken from a deterministically-seeded RNG instead. To provide some level of31* variation however, pick the seed based on the buffer size and size of the chosen bitset. */32InsecureRandomContext rng(buffer.size() + 0x10000 * S::Size());34using Sim = std::bitset<S::Size()>;35// Up to 4 real BitSets (initially 2).36std::vector<S> real(2);37// Up to 4 std::bitsets with the same corresponding contents.38std::vector<Sim> sim(2);40/* Compare sim[idx] with real[idx], using all inspector operations. */41auto compare_fn = [&](unsigned idx) {42/* iterators and operator[] */43auto it = real[idx].begin();44unsigned first = S::Size();45unsigned last = S::Size();46for (unsigned i = 0; i < S::Size(); ++i) {47bool match = (it != real[idx].end()) && *it == i;48assert(sim[idx][i] == real[idx][i]);49assert(match == real[idx][i]);50assert((it == real[idx].end()) != (it != real[idx].end()));51if (match) {52++it;53if (first == S::Size()) first = i;54last = i;55}56}57assert(it == real[idx].end());58assert(!(it != real[idx].end()));59/* Any / None */60assert(sim[idx].any() == real[idx].Any());61assert(sim[idx].none() == real[idx].None());62/* First / Last */63if (sim[idx].any()) {64assert(first == real[idx].First());65assert(last == real[idx].Last());66}67/* Count */68assert(sim[idx].count() == real[idx].Count());69};71LIMITED_WHILE (buffer.size() > 0, 1000) {72// Read one byte to determine which operation to execute on the BitSets.73int command = ReadByte(buffer) % 64;74// Read another byte that determines which bitsets will be involved.75unsigned args = ReadByte(buffer);76unsigned dest = ((args & 7) * sim.size()) >> 3;77unsigned src = (((args >> 3) & 7) * sim.size()) >> 3;78unsigned aux = (((args >> 6) & 3) * sim.size()) >> 2;79// Args are in range for non-empty sim, or sim is completely empty and will be grown80assert((sim.empty() && dest == 0 && src == 0 && aux == 0) ||81(!sim.empty() && dest < sim.size() && src < sim.size() && aux < sim.size()));83// Pick one operation based on value of command. Not all operations are always applicable.84// Loop through the applicable ones until command reaches 0 (which avoids the need to85// compute the number of applicable commands ahead of time).86while (true) {87if (dest < sim.size() && command-- == 0) {88/* Set() (true) */89unsigned val = ReadByte(buffer) % S::Size();90assert(sim[dest][val] == real[dest][val]);91sim[dest].set(val);92real[dest].Set(val);93break;94} else if (dest < sim.size() && command-- == 0) {95/* Reset() */96unsigned val = ReadByte(buffer) % S::Size();97assert(sim[dest][val] == real[dest][val]);98sim[dest].reset(val);99real[dest].Reset(val);100break;101} else if (dest < sim.size() && command-- == 0) {102/* Set() (conditional) */103unsigned val = ReadByte(buffer) % S::Size();104assert(sim[dest][val] == real[dest][val]);105sim[dest].set(val, args >> 7);106real[dest].Set(val, args >> 7);107break;108} else if (sim.size() < 4 && command-- == 0) {109/* Construct empty. */110sim.resize(sim.size() + 1);111real.resize(real.size() + 1);112break;113} else if (sim.size() < 4 && command-- == 0) {114/* Construct singleton. */115unsigned val = ReadByte(buffer) % S::Size();116std::bitset<S::Size()> newset;117newset[val] = true;118sim.push_back(newset);119real.push_back(S::Singleton(val));120break;121} else if (dest < sim.size() && command-- == 0) {122/* Make random. */123compare_fn(dest);124sim[dest].reset();125real[dest] = S{};126for (unsigned i = 0; i < S::Size(); ++i) {127if (rng.randbool()) {128sim[dest][i] = true;129real[dest].Set(i);130}131}132break;133} else if (dest < sim.size() && command-- == 0) {134/* Assign initializer list. */135unsigned r1 = rng.randrange(S::Size());136unsigned r2 = rng.randrange(S::Size());137unsigned r3 = rng.randrange(S::Size());138compare_fn(dest);139sim[dest].reset();140real[dest] = {r1, r2, r3};141sim[dest].set(r1);142sim[dest].set(r2);143sim[dest].set(r3);144break;145} else if (!sim.empty() && command-- == 0) {146/* Destruct. */147compare_fn(sim.size() - 1);148sim.pop_back();149real.pop_back();150break;151} else if (sim.size() < 4 && src < sim.size() && command-- == 0) {152/* Copy construct. */153sim.emplace_back(sim[src]);154real.emplace_back(real[src]);155break;156} else if (src < sim.size() && dest < sim.size() && command-- == 0) {157/* Copy assign. */158compare_fn(dest);159sim[dest] = sim[src];160real[dest] = real[src];161break;162} else if (src < sim.size() && dest < sim.size() && command-- == 0) {163/* swap() function. */164swap(sim[dest], sim[src]);165swap(real[dest], real[src]);166break;167} else if (sim.size() < 4 && command-- == 0) {168/* Construct with initializer list. */169unsigned r1 = rng.randrange(S::Size());170unsigned r2 = rng.randrange(S::Size());171sim.emplace_back();172sim.back().set(r1);173sim.back().set(r2);174real.push_back(S{r1, r2});175break;176} else if (dest < sim.size() && command-- == 0) {177/* Fill() + copy assign. */178unsigned len = ReadByte(buffer) % S::Size();179compare_fn(dest);180sim[dest].reset();181for (unsigned i = 0; i < len; ++i) sim[dest][i] = true;182real[dest] = S::Fill(len);183break;184} else if (src < sim.size() && command-- == 0) {185/* Iterator copy based compare. */186unsigned val = ReadByte(buffer) % S::Size();187/* In a first loop, compare begin..end, and copy to it_copy at some point. */188auto it = real[src].begin(), it_copy = it;189for (unsigned i = 0; i < S::Size(); ++i) {190if (i == val) it_copy = it;191bool match = (it != real[src].end()) && *it == i;192assert(match == sim[src][i]);193if (match) ++it;194}195assert(it == real[src].end());196/* Then compare from the copied point again to end. */197for (unsigned i = val; i < S::Size(); ++i) {198bool match = (it_copy != real[src].end()) && *it_copy == i;199assert(match == sim[src][i]);200if (match) ++it_copy;201}202assert(it_copy == real[src].end());203break;204} else if (src < sim.size() && dest < sim.size() && command-- == 0) {205/* operator|= */206compare_fn(dest);207sim[dest] |= sim[src];208real[dest] |= real[src];209break;210} else if (src < sim.size() && dest < sim.size() && command-- == 0) {211/* operator&= */212compare_fn(dest);213sim[dest] &= sim[src];214real[dest] &= real[src];215break;216} else if (src < sim.size() && dest < sim.size() && command-- == 0) {217/* operator-= */218compare_fn(dest);219sim[dest] &= ~sim[src];220real[dest] -= real[src];221break;222} else if (src < sim.size() && dest < sim.size() && command-- == 0) {223/* operator^= */224compare_fn(dest);225sim[dest] ^= sim[src];226real[dest] ^= real[src];227break;228} else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {229/* operator| */230compare_fn(dest);231sim[dest] = sim[src] | sim[aux];232real[dest] = real[src] | real[aux];233break;234} else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {235/* operator& */236compare_fn(dest);237sim[dest] = sim[src] & sim[aux];238real[dest] = real[src] & real[aux];239break;240} else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {241/* operator- */242compare_fn(dest);243sim[dest] = sim[src] & ~sim[aux];244real[dest] = real[src] - real[aux];245break;246} else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {247/* operator^ */248compare_fn(dest);249sim[dest] = sim[src] ^ sim[aux];250real[dest] = real[src] ^ real[aux];
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.