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.
1001BOOST_CHECK(GetLocalAddress(*peer_ipv6_tunnel) == addr_ipv4);1002BOOST_CHECK(GetLocalAddress(*peer_teredo) == addr_ipv4);1003BOOST_CHECK(GetLocalAddress(*peer_cjdns) == addr_ipv4);1004BOOST_CHECK(!GetLocalAddress(*peer_onion).IsValid());1005BOOST_CHECK(!GetLocalAddress(*peer_i2p).IsValid());1006RemoveLocal(addr_ipv4);1008// local privacy addresses - don't advertise to clearnet peers1009AddLocal(addr_onion);1010AddLocal(addr_i2p);1011BOOST_CHECK(!GetLocalAddress(*peer_ipv4).IsValid());1012BOOST_CHECK(!GetLocalAddress(*peer_ipv6).IsValid());1013BOOST_CHECK(!GetLocalAddress(*peer_ipv6_tunnel).IsValid());1014BOOST_CHECK(!GetLocalAddress(*peer_teredo).IsValid());1015BOOST_CHECK(!GetLocalAddress(*peer_cjdns).IsValid());1016BOOST_CHECK(GetLocalAddress(*peer_onion) == addr_onion);1017BOOST_CHECK(GetLocalAddress(*peer_i2p) == addr_i2p);1018RemoveLocal(addr_onion);1019RemoveLocal(addr_i2p);1021// local addresses from all networks1022AddLocal(addr_ipv4);1023AddLocal(addr_ipv6);1024AddLocal(addr_ipv6_tunnel);1025AddLocal(addr_teredo);1026AddLocal(addr_onion);1027AddLocal(addr_i2p);1028AddLocal(addr_cjdns);1029BOOST_CHECK(GetLocalAddress(*peer_ipv4) == addr_ipv4);1030BOOST_CHECK(GetLocalAddress(*peer_ipv6) == addr_ipv6);1031BOOST_CHECK(GetLocalAddress(*peer_ipv6_tunnel) == addr_ipv6);1032BOOST_CHECK(GetLocalAddress(*peer_teredo) == addr_ipv4);1033BOOST_CHECK(GetLocalAddress(*peer_onion) == addr_onion);1034BOOST_CHECK(GetLocalAddress(*peer_i2p) == addr_i2p);1035BOOST_CHECK(GetLocalAddress(*peer_cjdns) == addr_cjdns);1036RemoveLocal(addr_ipv4);1037RemoveLocal(addr_ipv6);1038RemoveLocal(addr_ipv6_tunnel);1039RemoveLocal(addr_teredo);1040RemoveLocal(addr_onion);1041RemoveLocal(addr_i2p);1042RemoveLocal(addr_cjdns);1043}1045namespace {1047CKey GenerateRandomTestKey(FastRandomContext& rng) noexcept1048{1049CKey key;1050uint256 key_data = rng.rand256();1051key.Set(key_data.begin(), key_data.end(), true);1052return key;1053}1055/** A class for scenario-based tests of V2Transport1056*1057* Each V2TransportTester encapsulates a V2Transport (the one being tested), and can be told to1058* interact with it. To do so, it also encapsulates a BIP324Cipher to act as the other side. A1059* second V2Transport is not used, as doing so would not permit scenarios that involve sending1060* invalid data, or ones using BIP324 features that are not implemented on the sending1061* side (like decoy packets).1062*/1063class V2TransportTester1064{1065FastRandomContext& m_rng;1066V2Transport m_transport; //!< V2Transport being tested1067BIP324Cipher m_cipher; //!< Cipher to help with the other side1068bool m_test_initiator; //!< Whether m_transport is the initiator (true) or responder (false)1070std::vector<uint8_t> m_sent_garbage; //!< The garbage we've sent to m_transport.1071std::vector<uint8_t> m_recv_garbage; //!< The garbage we've received from m_transport.1072std::vector<uint8_t> m_to_send; //!< Bytes we have queued up to send to m_transport.1073std::vector<uint8_t> m_received; //!< Bytes we have received from m_transport.1074std::deque<CSerializedNetMsg> m_msg_to_send; //!< Messages to be sent *by* m_transport to us.1075bool m_sent_aad{false};1077public:1078/** Construct a tester object. test_initiator: whether the tested transport is initiator. */1079explicit V2TransportTester(FastRandomContext& rng, bool test_initiator)1080: m_rng{rng},1081m_transport{0, test_initiator},1082m_cipher{GenerateRandomTestKey(m_rng), MakeByteSpan(m_rng.rand256())},1083m_test_initiator(test_initiator) {}1085/** Data type returned by Interact:1086*1087* - std::nullopt: transport error occurred1088* - otherwise: a vector of1089* - std::nullopt: invalid message received1090* - otherwise: a CNetMessage retrieved1091*/1092using InteractResult = std::optional<std::vector<std::optional<CNetMessage>>>;1094/** Send/receive scheduled/available bytes and messages.1095*1096* This is the only function that interacts with the transport being tested; everything else is1097* scheduling things done by Interact(), or processing things learned by it.1098*/1099InteractResult Interact()1100{1101std::vector<std::optional<CNetMessage>> ret;1102while (true) {1103bool progress{false};1104// Send bytes from m_to_send to the transport.1105if (!m_to_send.empty()) {1106std::span<const uint8_t> to_send = std::span{m_to_send}.first(1 + m_rng.randrange(m_to_send.size()));1107size_t old_len = to_send.size();1108if (!m_transport.ReceivedBytes(to_send)) {1109return std::nullopt; // transport error occurred1110}1111if (old_len != to_send.size()) {1112progress = true;1113m_to_send.erase(m_to_send.begin(), m_to_send.begin() + (old_len - to_send.size()));1114}1115}1116// Retrieve messages received by the transport.1117if (m_transport.ReceivedMessageComplete() && (!progress || m_rng.randbool())) {1118bool reject{false};1119auto msg = m_transport.GetReceivedMessage({}, reject);1120if (reject) {1121ret.emplace_back(std::nullopt);1122} else {1123ret.emplace_back(std::move(msg));1124}1125progress = true;1126}1127// Enqueue a message to be sent by the transport to us.1128if (!m_msg_to_send.empty() && (!progress || m_rng.randbool())) {1129if (m_transport.SetMessageToSend(m_msg_to_send.front())) {1130m_msg_to_send.pop_front();1131progress = true;1132}1133}1134// Receive bytes from the transport.1135const auto& [recv_bytes, _more, _msg_type] = m_transport.GetBytesToSend(!m_msg_to_send.empty());1136if (!recv_bytes.empty() && (!progress || m_rng.randbool())) {1137size_t to_receive = 1 + m_rng.randrange(recv_bytes.size());1138m_received.insert(m_received.end(), recv_bytes.begin(), recv_bytes.begin() + to_receive);1139progress = true;1140m_transport.MarkBytesSent(to_receive);1141}1142if (!progress) break;1143}1144return ret;1145}1147/** Expose the cipher. */1148BIP324Cipher& GetCipher() { return m_cipher; }1150/** Schedule bytes to be sent to the transport. */1151void Send(std::span<const uint8_t> data)1152{1153m_to_send.insert(m_to_send.end(), data.begin(), data.end());1154}1156/** Send V1 version message header to the transport. */1157void SendV1Version(const MessageStartChars& magic)1158{1159CMessageHeader hdr(magic, "version", 126 + m_rng.randrange(11));1160DataStream ser{};1161ser << hdr;1162m_to_send.insert(m_to_send.end(), UCharCast(ser.data()), UCharCast(ser.data() + ser.size()));1163}1165/** Schedule bytes to be sent to the transport. */1166void Send(std::span<const std::byte> data) { Send(MakeUCharSpan(data)); }1168/** Schedule our ellswift key to be sent to the transport. */1169void SendKey() { Send(m_cipher.GetOurPubKey()); }1171/** Schedule specified garbage to be sent to the transport. */1172void SendGarbage(std::span<const uint8_t> garbage)1173{1174// Remember the specified garbage (so we can use it as AAD).1175m_sent_garbage.assign(garbage.begin(), garbage.end());1176// Schedule it for sending.1177Send(m_sent_garbage);1178}1180/** Schedule garbage (of specified length) to be sent to the transport. */1181void SendGarbage(size_t garbage_len)1182{1183// Generate random garbage and send it.1184SendGarbage(m_rng.randbytes<uint8_t>(garbage_len));1185}1187/** Schedule garbage (with valid random length) to be sent to the transport. */1188void SendGarbage()1189{1190SendGarbage(m_rng.randrange(V2Transport::MAX_GARBAGE_LEN + 1));1191}1193/** Schedule a message to be sent to us by the transport. */1194void AddMessage(std::string m_type, std::vector<uint8_t> payload)1195{1196CSerializedNetMsg msg;1197msg.m_type = std::move(m_type);1198msg.data = std::move(payload);1199m_msg_to_send.push_back(std::move(msg));1200}1202/** Expect ellswift key to have been received from transport and process it.1203*1204* Many other V2TransportTester functions cannot be called until after ReceiveKey() has been1205* called, as no encryption keys are set up before that point.1206*/1207void ReceiveKey()1208{1209// When processing a key, enough bytes need to have been received already.1210BOOST_REQUIRE(m_received.size() >= EllSwiftPubKey::size());1211// Initialize the cipher using it (acting as the opposite side of the tested transport).1212m_cipher.Initialize(MakeByteSpan(m_received).first(EllSwiftPubKey::size()), !m_test_initiator);1213// Strip the processed bytes off the front of the receive buffer.1214m_received.erase(m_received.begin(), m_received.begin() + EllSwiftPubKey::size());1215}1217/** Schedule an encrypted packet with specified content/aad/ignore to be sent to transport1218* (only after ReceiveKey). */1219void SendPacket(std::span<const uint8_t> content, std::span<const uint8_t> aad = {}, bool ignore = false)1220{1221// Use cipher to construct ciphertext.1222std::vector<std::byte> ciphertext;1223ciphertext.resize(content.size() + BIP324Cipher::EXPANSION);1224m_cipher.Encrypt(1225/*contents=*/MakeByteSpan(content),1226/*aad=*/MakeByteSpan(aad),1227/*ignore=*/ignore,1228/*output=*/ciphertext);1229// Schedule it for sending.1230Send(ciphertext);1231}1233/** Schedule garbage terminator to be sent to the transport (only after ReceiveKey). */1234void SendGarbageTerm()1235{1236// Schedule the garbage terminator to be sent.1237Send(m_cipher.GetSendGarbageTerminator());1238}1240/** Schedule version packet to be sent to the transport (only after ReceiveKey). */1241void SendVersion(std::span<const uint8_t> version_data = {}, bool vers_ignore = false)1242{1243std::span<const std::uint8_t> aad;1244// Set AAD to garbage only for first packet.1245if (!m_sent_aad) aad = m_sent_garbage;1246SendPacket(/*content=*/version_data, /*aad=*/aad, /*ignore=*/vers_ignore);1247m_sent_aad = true;1248}1250/** Expect a packet to have been received from transport, process it, and return its contents
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.