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) 2020-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 <test/util/net.h>7#include <net.h>8#include <net_processing.h>9#include <netaddress.h>10#include <netmessagemaker.h>11#include <node/connection_types.h>12#include <node/eviction.h>13#include <protocol.h>14#include <random.h>15#include <serialize.h>16#include <span.h>17#include <sync.h>19#include <chrono>20#include <optional>21#include <vector>23void ConnmanTestMsg::Handshake(CNode& node,24bool successfully_connected,25ServiceFlags remote_services,26ServiceFlags local_services,27int32_t version,28bool relay_txs)29{30auto& peerman{static_cast<PeerManager&>(*m_msgproc)};31auto& connman{*this};33peerman.InitializeNode(node, local_services);34peerman.SendMessages(node);35FlushSendBuffer(node); // Drop the version message added by SendMessages.37CSerializedNetMsg msg_version{38NetMsg::Make(NetMsgType::VERSION,39version, //40Using<CustomUintFormatter<8>>(remote_services), //41int64_t{}, // dummy time42int64_t{}, // ignored service bits43CNetAddr::V1(CService{}), // dummy44int64_t{}, // ignored service bits45CNetAddr::V1(CService{}), // ignored46uint64_t{1}, // dummy nonce47std::string{}, // dummy subver48int32_t{}, // dummy starting_height49relay_txs),50};52(void)connman.ReceiveMsgFrom(node, std::move(msg_version));53node.fPauseSend = false;54connman.ProcessMessagesOnce(node);55peerman.SendMessages(node);56FlushSendBuffer(node); // Drop the verack message added by SendMessages.57if (node.fDisconnect) return;58assert(node.nVersion == version);59assert(node.GetCommonVersion() == std::min(version, node.AdvertisedVersion()));60CNodeStateStats statestats;61assert(peerman.GetNodeStateStats(node.GetId(), statestats));62assert(statestats.m_relay_txs == (relay_txs && !node.IsBlockOnlyConn()));63assert(statestats.their_services == remote_services);64if (successfully_connected) {65CSerializedNetMsg msg_verack{NetMsg::Make(NetMsgType::VERACK)};66(void)connman.ReceiveMsgFrom(node, std::move(msg_verack));67node.fPauseSend = false;68connman.ProcessMessagesOnce(node);69peerman.SendMessages(node);70assert(node.fSuccessfullyConnected == true);71}72}74void ConnmanTestMsg::ResetAddrCache() { m_addr_response_caches = {}; }76void ConnmanTestMsg::ResetMaxOutboundCycle()77{78LOCK(m_total_bytes_sent_mutex);79nMaxOutboundCycleStartTime = 0s;80nMaxOutboundTotalBytesSentInCycle = 0;81}83void ConnmanTestMsg::Reset()84{85ResetAddrCache();86ResetMaxOutboundCycle();87m_private_broadcast.m_outbound_tor_ok_at_least_once.store(false);88m_private_broadcast.m_num_to_open.store(0);89}91void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, std::span<const uint8_t> msg_bytes, bool& complete) const92{93assert(node.ReceiveMsgBytes(msg_bytes, complete));94if (complete) {95node.MarkReceivedMsgsForProcessing();96}97}99void ConnmanTestMsg::FlushSendBuffer(CNode& node) const100{101LOCK(node.cs_vSend);102node.vSendMsg.clear();103node.m_send_memusage = 0;104while (true) {105const auto& [to_send, _more, _msg_type] = node.m_transport->GetBytesToSend(false);106if (to_send.empty()) break;107node.m_transport->MarkBytesSent(to_send.size());108}109}111bool ConnmanTestMsg::ReceiveMsgFrom(CNode& node, CSerializedNetMsg&& ser_msg) const112{113bool queued = node.m_transport->SetMessageToSend(ser_msg);114assert(queued);115bool complete{false};116while (true) {117const auto& [to_send, _more, _msg_type] = node.m_transport->GetBytesToSend(false);118if (to_send.empty()) break;119NodeReceiveMsgBytes(node, to_send, complete);120node.m_transport->MarkBytesSent(to_send.size());121}122return complete;123}125CNode* ConnmanTestMsg::ConnectNodePublic(PeerManager& peerman, const char* pszDest, ConnectionType conn_type)126{127CNode* node = ConnectNode(CAddress{}, pszDest, /*fCountFailure=*/false, conn_type, /*use_v2transport=*/true, /*proxy_override=*/std::nullopt);128if (!node) return nullptr;129node->SetCommonVersion(PROTOCOL_VERSION);130peerman.InitializeNode(*node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));131node->fSuccessfullyConnected = true;132AddTestNode(*node);133return node;134}136std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(int n_candidates, FastRandomContext& random_context)137{138std::vector<NodeEvictionCandidate> candidates;139candidates.reserve(n_candidates);140for (int id = 0; id < n_candidates; ++id) {141candidates.push_back({142.id=id,143.m_connected=NodeSeconds{std::chrono::seconds{random_context.randrange(100)}},144.m_min_ping_time=std::chrono::microseconds{random_context.randrange(100)},145.m_last_block_time=std::chrono::seconds{random_context.randrange(100)},146.m_last_tx_time=std::chrono::seconds{random_context.randrange(100)},147.fRelevantServices=random_context.randbool(),148.m_relay_txs=random_context.randbool(),149.fBloomFilter=random_context.randbool(),150.nKeyedNetGroup=random_context.randrange(100u),151.prefer_evict=random_context.randbool(),152.m_is_local=random_context.randbool(),153.m_network=ALL_NETWORKS[random_context.randrange(ALL_NETWORKS.size())],154.m_noban=false,155.m_conn_type=ConnectionType::INBOUND,156});157}158return candidates;159}161// Have different ZeroSock (or others that inherit from it) objects have different162// m_socket because EqualSharedPtrSock compares m_socket and we want to avoid two163// different objects comparing as equal.164static std::atomic<SOCKET> g_mocked_sock_fd{0};166ZeroSock::ZeroSock() : Sock{g_mocked_sock_fd++} {}168// Sock::~Sock() would try to close(2) m_socket if it is not INVALID_SOCKET, avoid that.169ZeroSock::~ZeroSock() { m_socket = INVALID_SOCKET; }171ssize_t ZeroSock::Send(const void*, size_t len, int) const { return len; }173ssize_t ZeroSock::Recv(void* buf, size_t len, int flags) const174{175memset(buf, 0x0, len);176return len;177}179int ZeroSock::Connect(const sockaddr*, socklen_t) const { return 0; }181int ZeroSock::Bind(const sockaddr*, socklen_t) const { return 0; }183int ZeroSock::Listen(int) const { return 0; }185std::unique_ptr<Sock> ZeroSock::Accept(sockaddr* addr, socklen_t* addr_len) const186{187if (addr != nullptr) {188// Pretend all connections come from 5.5.5.5:6789189memset(addr, 0x00, *addr_len);190const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in));191if (*addr_len >= write_len) {192*addr_len = write_len;193sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(addr);194addr_in->sin_family = AF_INET;195memset(&addr_in->sin_addr, 0x05, sizeof(addr_in->sin_addr));196addr_in->sin_port = htons(6789);197}198}199return std::make_unique<ZeroSock>();200}202int ZeroSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const203{204std::memset(opt_val, 0x0, *opt_len);205return 0;206}208int ZeroSock::SetSockOpt(int, int, const void*, socklen_t) const { return 0; }210int ZeroSock::GetSockName(sockaddr* name, socklen_t* name_len) const211{212std::memset(name, 0x0, *name_len);213return 0;214}216bool ZeroSock::SetNonBlocking() const { return true; }218bool ZeroSock::IsSelectable() const { return true; }220bool ZeroSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const221{222if (occurred != nullptr) {223*occurred = requested;224}225return true;226}228bool ZeroSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const229{230for (auto& [sock, events] : events_per_sock) {231(void)sock;232events.occurred = events.requested;233}234return true;235}237ZeroSock& ZeroSock::operator=(Sock&& other)238{239assert(false && "Move of Sock into ZeroSock not allowed.");240return *this;241}243StaticContentsSock::StaticContentsSock(const std::string& contents)244: m_contents{contents}245{246}248ssize_t StaticContentsSock::Recv(void* buf, size_t len, int flags) const249{250const size_t consume_bytes{std::min(len, m_contents.size() - m_consumed)};
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.