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/vecdeque.h>10#include <cstdint>11#include <deque>13namespace {15/** The maximum number of simultaneous buffers kept by the test. */16static constexpr size_t MAX_BUFFERS{3};17/** How many elements are kept in a buffer at most. */18static constexpr size_t MAX_BUFFER_SIZE{48};19/** How many operations are performed at most on the buffers in one test. */20static constexpr size_t MAX_OPERATIONS{1024};22/** Perform a simulation fuzz test on VecDeque type T.23*24* T must be constructible from a uint64_t seed, comparable to other T, copyable, and movable.25*/26template<typename T, bool CheckNoneLeft>27void TestType(std::span<const uint8_t> buffer, uint64_t rng_tweak)28{29FuzzedDataProvider provider(buffer.data(), buffer.size());30// Local RNG, only used for the seeds to initialize T objects with.31InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>() ^ rng_tweak);33// Real circular buffers.34std::vector<VecDeque<T>> real;35real.reserve(MAX_BUFFERS);36// Simulated circular buffers.37std::vector<std::deque<T>> sim;38sim.reserve(MAX_BUFFERS);39// Temporary object of type T.40std::optional<T> tmp;42// Compare a real and a simulated buffer.43auto compare_fn = [](const VecDeque<T>& r, const std::deque<T>& s) {44assert(r.size() == s.size());45assert(r.empty() == s.empty());46assert(r.capacity() >= r.size());47if (s.size() == 0) return;48assert(r.front() == s.front());49assert(r.back() == s.back());50for (size_t i = 0; i < s.size(); ++i) {51assert(r[i] == s[i]);52}53};55LIMITED_WHILE (provider.remaining_bytes(), MAX_OPERATIONS) {56int command = provider.ConsumeIntegral<uint8_t>() % 64;57unsigned idx = real.empty() ? 0 : provider.ConsumeIntegralInRange<unsigned>(0, real.size() - 1);58const size_t num_buffers = sim.size();59// Pick one operation based on value of command. Not all operations are always applicable.60// Loop through the applicable ones until command reaches 0 (which avoids the need to61// compute the number of applicable commands ahead of time).62const bool non_empty{num_buffers != 0};63const bool non_full{num_buffers < MAX_BUFFERS};64const bool partially_full{non_empty && non_full};65const bool multiple_exist{num_buffers > 1};66const bool existing_buffer_non_full{non_empty && sim[idx].size() < MAX_BUFFER_SIZE};67const bool existing_buffer_non_empty{non_empty && !sim[idx].empty()};68assert(non_full || non_empty);69while (true) {70if (non_full && command-- == 0) {71/* Default construct. */72real.emplace_back();73sim.emplace_back();74break;75}76if (non_empty && command-- == 0) {77/* resize() */78compare_fn(real[idx], sim[idx]);79size_t new_size = provider.ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_SIZE);80real[idx].resize(new_size);81sim[idx].resize(new_size);82assert(real[idx].size() == new_size);83break;84}85if (non_empty && command-- == 0) {86/* clear() */87compare_fn(real[idx], sim[idx]);88real[idx].clear();89sim[idx].clear();90assert(real[idx].empty());91break;92}93if (non_empty && command-- == 0) {94/* Copy construct default. */95compare_fn(real[idx], sim[idx]);96real[idx] = VecDeque<T>();97sim[idx].clear();98assert(real[idx].size() == 0);99break;100}101if (non_empty && command-- == 0) {102/* Destruct. */103compare_fn(real.back(), sim.back());104real.pop_back();105sim.pop_back();106break;107}108if (partially_full && command-- == 0) {109/* Copy construct. */110real.emplace_back(real[idx]);111sim.emplace_back(sim[idx]);112break;113}114if (partially_full && command-- == 0) {115/* Move construct. */116VecDeque<T> copy(real[idx]);117real.emplace_back(std::move(copy));118sim.emplace_back(sim[idx]);119break;120}121if (multiple_exist && command-- == 0) {122/* swap() */123swap(real[idx], real[(idx + 1) % num_buffers]);124swap(sim[idx], sim[(idx + 1) % num_buffers]);125break;126}127if (multiple_exist && command-- == 0) {128/* Copy assign. */129compare_fn(real[idx], sim[idx]);130real[idx] = real[(idx + 1) % num_buffers];131sim[idx] = sim[(idx + 1) % num_buffers];132break;133}134if (multiple_exist && command-- == 0) {135/* Move assign. */136VecDeque<T> copy(real[(idx + 1) % num_buffers]);137compare_fn(real[idx], sim[idx]);138real[idx] = std::move(copy);139sim[idx] = sim[(idx + 1) % num_buffers];140break;141}142if (non_empty && command-- == 0) {143/* Self swap() */144swap(real[idx], real[idx]);145break;146}147if (non_empty && command-- == 0) {148/* Self-copy assign. */149real[idx] = real[idx];150break;151}152if (non_empty && command-- == 0) {153/* Self-move assign. */154// Do not use std::move(real[idx]) here: -Wself-move correctly warns about that.155real[idx] = static_cast<VecDeque<T>&&>(real[idx]);156break;157}158if (non_empty && command-- == 0) {159/* reserve() */160size_t res_size = provider.ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_SIZE);161size_t old_cap = real[idx].capacity();162size_t old_size = real[idx].size();163real[idx].reserve(res_size);164assert(real[idx].size() == old_size);165assert(real[idx].capacity() == std::max(old_cap, res_size));166break;167}168if (non_empty && command-- == 0) {169/* shrink_to_fit() */170size_t old_size = real[idx].size();171real[idx].shrink_to_fit();172assert(real[idx].size() == old_size);173assert(real[idx].capacity() == old_size);174break;175}176if (existing_buffer_non_full && command-- == 0) {177/* push_back() (copying) */178tmp = T(rng.rand64());179size_t old_size = real[idx].size();180size_t old_cap = real[idx].capacity();181real[idx].push_back(*tmp);182sim[idx].push_back(*tmp);183assert(real[idx].size() == old_size + 1);184if (old_cap > old_size) {185assert(real[idx].capacity() == old_cap);186} else {187assert(real[idx].capacity() > old_cap);188assert(real[idx].capacity() <= 2 * (old_cap + 1));189}190break;191}192if (existing_buffer_non_full && command-- == 0) {193/* push_back() (moving) */194tmp = T(rng.rand64());195size_t old_size = real[idx].size();196size_t old_cap = real[idx].capacity();197sim[idx].push_back(*tmp);198real[idx].push_back(std::move(*tmp));199assert(real[idx].size() == old_size + 1);200if (old_cap > old_size) {201assert(real[idx].capacity() == old_cap);202} else {203assert(real[idx].capacity() > old_cap);204assert(real[idx].capacity() <= 2 * (old_cap + 1));205}206break;207}208if (existing_buffer_non_full && command-- == 0) {209/* emplace_back() */210uint64_t seed{rng.rand64()};211size_t old_size = real[idx].size();212size_t old_cap = real[idx].capacity();213sim[idx].emplace_back(seed);214real[idx].emplace_back(seed);215assert(real[idx].size() == old_size + 1);216if (old_cap > old_size) {217assert(real[idx].capacity() == old_cap);218} else {219assert(real[idx].capacity() > old_cap);220assert(real[idx].capacity() <= 2 * (old_cap + 1));221}222break;223}224if (existing_buffer_non_full && command-- == 0) {225/* push_front() (copying) */226tmp = T(rng.rand64());227size_t old_size = real[idx].size();228size_t old_cap = real[idx].capacity();229real[idx].push_front(*tmp);230sim[idx].push_front(*tmp);231assert(real[idx].size() == old_size + 1);232if (old_cap > old_size) {233assert(real[idx].capacity() == old_cap);234} else {235assert(real[idx].capacity() > old_cap);236assert(real[idx].capacity() <= 2 * (old_cap + 1));237}238break;239}240if (existing_buffer_non_full && command-- == 0) {241/* push_front() (moving) */242tmp = T(rng.rand64());243size_t old_size = real[idx].size();244size_t old_cap = real[idx].capacity();245sim[idx].push_front(*tmp);246real[idx].push_front(std::move(*tmp));247assert(real[idx].size() == old_size + 1);248if (old_cap > old_size) {249assert(real[idx].capacity() == old_cap);250} else {
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.