LCOV - code coverage report
Current view: top level - src/test - net_tests.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 1026 1032 99.4 %
Date: 2026-06-25 07:23:51 Functions: 155 155 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2012-2021 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <test/util/setup_common.h>
       6             : 
       7             : #include <chainparams.h>
       8             : #include <clientversion.h>
       9             : #include <compat/compat.h>
      10             : #include <net.h>
      11             : #include <net_processing.h>
      12             : #include <netaddress.h>
      13             : #include <netbase.h>
      14             : #include <netmessagemaker.h>
      15             : #include <serialize.h>
      16             : #include <span.h>
      17             : #include <streams.h>
      18             : #include <test/util/random.h>
      19             : #include <test/util/validation.h>
      20             : #include <timedata.h>
      21             : #include <util/strencodings.h>
      22             : #include <util/string.h>
      23             : #include <util/system.h>
      24             : #include <validation.h>
      25             : #include <version.h>
      26             : 
      27             : #include <boost/test/unit_test.hpp>
      28             : 
      29             : #include <algorithm>
      30             : #include <cstdint>
      31             : #include <ios>
      32             : #include <memory>
      33             : #include <optional>
      34             : #include <string>
      35             : 
      36             : using namespace std::literals;
      37             : 
      38         146 : BOOST_FIXTURE_TEST_SUITE(net_tests, RegTestingSetup)
      39             : 
      40         149 : BOOST_AUTO_TEST_CASE(cnode_listen_port)
      41             : {
      42             :     // test default
      43           1 :     uint16_t port{GetListenPort()};
      44           1 :     BOOST_CHECK(port == Params().GetDefaultPort());
      45             :     // test set port
      46           1 :     uint16_t altPort = 12345;
      47           1 :     BOOST_CHECK(gArgs.SoftSetArg("-port", ToString(altPort)));
      48           1 :     port = GetListenPort();
      49           1 :     BOOST_CHECK(port == altPort);
      50           1 : }
      51             : 
      52         149 : BOOST_AUTO_TEST_CASE(cnode_simple_test)
      53             : {
      54           1 :     NodeId id = 0;
      55             : 
      56             :     in_addr ipv4Addr;
      57           1 :     ipv4Addr.s_addr = 0xa0b0c001;
      58             : 
      59           1 :     CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
      60           1 :     std::string pszDest;
      61             : 
      62           1 :     std::unique_ptr<CNode> pnode1 = std::make_unique<CNode>(id++,
      63           1 :                                                             /*sock=*/nullptr,
      64             :                                                             addr,
      65           1 :                                                             /*nKeyedNetGroupIn=*/0,
      66           1 :                                                             /*nLocalHostNonceIn=*/0,
      67           1 :                                                             CAddress(),
      68             :                                                             pszDest,
      69           1 :                                                             ConnectionType::OUTBOUND_FULL_RELAY,
      70           1 :                                                             /*inbound_onion=*/false);
      71           1 :     BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
      72           1 :     BOOST_CHECK(pnode1->IsManualConn() == false);
      73           1 :     BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
      74           1 :     BOOST_CHECK(pnode1->IsFeelerConn() == false);
      75           1 :     BOOST_CHECK(pnode1->IsAddrFetchConn() == false);
      76           1 :     BOOST_CHECK(pnode1->IsInboundConn() == false);
      77           1 :     BOOST_CHECK(pnode1->m_inbound_onion == false);
      78           1 :     BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4);
      79             : 
      80           1 :     std::unique_ptr<CNode> pnode2 = std::make_unique<CNode>(id++,
      81           1 :                                                             /*sock=*/nullptr,
      82             :                                                             addr,
      83           1 :                                                             /*nKeyedNetGroupIn=*/1,
      84           1 :                                                             /*nLocalHostNonceIn=*/1,
      85           1 :                                                             CAddress(),
      86             :                                                             pszDest,
      87           1 :                                                             ConnectionType::INBOUND,
      88           1 :                                                             /*inbound_onion=*/false);
      89           1 :     BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
      90           1 :     BOOST_CHECK(pnode2->IsManualConn() == false);
      91           1 :     BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
      92           1 :     BOOST_CHECK(pnode2->IsFeelerConn() == false);
      93           1 :     BOOST_CHECK(pnode2->IsAddrFetchConn() == false);
      94           1 :     BOOST_CHECK(pnode2->IsInboundConn() == true);
      95           1 :     BOOST_CHECK(pnode2->m_inbound_onion == false);
      96           1 :     BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4);
      97             : 
      98           1 :     std::unique_ptr<CNode> pnode3 = std::make_unique<CNode>(id++,
      99           1 :                                                             /*sock=*/nullptr,
     100             :                                                             addr,
     101           1 :                                                             /*nKeyedNetGroupIn=*/0,
     102           1 :                                                             /*nLocalHostNonceIn=*/0,
     103           1 :                                                             CAddress(),
     104             :                                                             pszDest,
     105           1 :                                                             ConnectionType::OUTBOUND_FULL_RELAY,
     106           1 :                                                             /*inbound_onion=*/false);
     107           1 :     BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
     108           1 :     BOOST_CHECK(pnode3->IsManualConn() == false);
     109           1 :     BOOST_CHECK(pnode3->IsBlockOnlyConn() == false);
     110           1 :     BOOST_CHECK(pnode3->IsFeelerConn() == false);
     111           1 :     BOOST_CHECK(pnode3->IsAddrFetchConn() == false);
     112           1 :     BOOST_CHECK(pnode3->IsInboundConn() == false);
     113           1 :     BOOST_CHECK(pnode3->m_inbound_onion == false);
     114           1 :     BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4);
     115             : 
     116           1 :     std::unique_ptr<CNode> pnode4 = std::make_unique<CNode>(id++,
     117           1 :                                                             /*sock=*/nullptr,
     118             :                                                             addr,
     119           1 :                                                             /*nKeyedNetGroupIn=*/1,
     120           1 :                                                             /*nLocalHostNonceIn=*/1,
     121           1 :                                                             CAddress(),
     122             :                                                             pszDest,
     123           1 :                                                             ConnectionType::INBOUND,
     124           1 :                                                             /*inbound_onion=*/true);
     125           1 :     BOOST_CHECK(pnode4->IsFullOutboundConn() == false);
     126           1 :     BOOST_CHECK(pnode4->IsManualConn() == false);
     127           1 :     BOOST_CHECK(pnode4->IsBlockOnlyConn() == false);
     128           1 :     BOOST_CHECK(pnode4->IsFeelerConn() == false);
     129           1 :     BOOST_CHECK(pnode4->IsAddrFetchConn() == false);
     130           1 :     BOOST_CHECK(pnode4->IsInboundConn() == true);
     131           1 :     BOOST_CHECK(pnode4->m_inbound_onion == true);
     132           1 :     BOOST_CHECK_EQUAL(pnode4->ConnectedThroughNetwork(), Network::NET_ONION);
     133           1 : }
     134             : 
     135         149 : BOOST_AUTO_TEST_CASE(cnetaddr_basic)
     136             : {
     137           1 :     CNetAddr addr;
     138             : 
     139             :     // IPv4, INADDR_ANY
     140           1 :     addr = LookupHost("0.0.0.0", false).value();
     141           1 :     BOOST_REQUIRE(!addr.IsValid());
     142           1 :     BOOST_REQUIRE(addr.IsIPv4());
     143             : 
     144           1 :     BOOST_CHECK(addr.IsBindAny());
     145           1 :     BOOST_CHECK(addr.IsAddrV1Compatible());
     146           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "0.0.0.0");
     147             : 
     148             :     // IPv4, INADDR_NONE
     149           1 :     addr = LookupHost("255.255.255.255", false).value();
     150           1 :     BOOST_REQUIRE(!addr.IsValid());
     151           1 :     BOOST_REQUIRE(addr.IsIPv4());
     152             : 
     153           1 :     BOOST_CHECK(!addr.IsBindAny());
     154           1 :     BOOST_CHECK(addr.IsAddrV1Compatible());
     155           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "255.255.255.255");
     156             : 
     157             :     // IPv4, casual
     158           1 :     addr = LookupHost("12.34.56.78", false).value();
     159           1 :     BOOST_REQUIRE(addr.IsValid());
     160           1 :     BOOST_REQUIRE(addr.IsIPv4());
     161             : 
     162           1 :     BOOST_CHECK(!addr.IsBindAny());
     163           1 :     BOOST_CHECK(addr.IsAddrV1Compatible());
     164           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "12.34.56.78");
     165             : 
     166             :     // IPv6, in6addr_any
     167           1 :     addr = LookupHost("::", false).value();
     168           1 :     BOOST_REQUIRE(!addr.IsValid());
     169           1 :     BOOST_REQUIRE(addr.IsIPv6());
     170             : 
     171           1 :     BOOST_CHECK(addr.IsBindAny());
     172           1 :     BOOST_CHECK(addr.IsAddrV1Compatible());
     173           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "::");
     174             : 
     175             :     // IPv6, casual
     176           1 :     addr = LookupHost("1122:3344:5566:7788:9900:aabb:ccdd:eeff", false).value();
     177           1 :     BOOST_REQUIRE(addr.IsValid());
     178           1 :     BOOST_REQUIRE(addr.IsIPv6());
     179             : 
     180           1 :     BOOST_CHECK(!addr.IsBindAny());
     181           1 :     BOOST_CHECK(addr.IsAddrV1Compatible());
     182           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff");
     183             : 
     184             :     // IPv6, scoped/link-local. See https://tools.ietf.org/html/rfc4007
     185             :     // We support non-negative decimal integers (uint32_t) as zone id indices.
     186             :     // Normal link-local scoped address functionality is to append "%" plus the
     187             :     // zone id, for example, given a link-local address of "fe80::1" and a zone
     188             :     // id of "32", return the address as "fe80::1%32".
     189           1 :     const std::string link_local{"fe80::1"};
     190           1 :     const std::string scoped_addr{link_local + "%32"};
     191           1 :     addr = LookupHost(scoped_addr, false).value();
     192           1 :     BOOST_REQUIRE(addr.IsValid());
     193           1 :     BOOST_REQUIRE(addr.IsIPv6());
     194           1 :     BOOST_CHECK(!addr.IsBindAny());
     195           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), scoped_addr);
     196             : 
     197             :     // Test that the delimiter "%" and default zone id of 0 can be omitted for the default scope.
     198           1 :     addr = LookupHost(link_local + "%0", false).value();
     199           1 :     BOOST_REQUIRE(addr.IsValid());
     200           1 :     BOOST_REQUIRE(addr.IsIPv6());
     201           1 :     BOOST_CHECK(!addr.IsBindAny());
     202           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), link_local);
     203             : 
     204             :     // TORv2, no longer supported
     205           1 :     BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
     206             : 
     207             :     // TORv3
     208           1 :     const char* torv3_addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion";
     209           1 :     BOOST_REQUIRE(addr.SetSpecial(torv3_addr));
     210           1 :     BOOST_REQUIRE(addr.IsValid());
     211           1 :     BOOST_REQUIRE(addr.IsTor());
     212             : 
     213           1 :     BOOST_CHECK(!addr.IsI2P());
     214           1 :     BOOST_CHECK(!addr.IsBindAny());
     215           1 :     BOOST_CHECK(!addr.IsAddrV1Compatible());
     216           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), torv3_addr);
     217             : 
     218             :     // TORv3, broken, with wrong checksum
     219           1 :     BOOST_CHECK(!addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscsad.onion"));
     220             : 
     221             :     // TORv3, broken, with wrong version
     222           1 :     BOOST_CHECK(!addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscrye.onion"));
     223             : 
     224             :     // TORv3, malicious
     225           1 :     BOOST_CHECK(!addr.SetSpecial(std::string{
     226             :         "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd\0wtf.onion", 66}));
     227             : 
     228             :     // TOR, bogus length
     229           1 :     BOOST_CHECK(!addr.SetSpecial(std::string{"mfrggzak.onion"}));
     230             : 
     231             :     // TOR, invalid base32
     232           1 :     BOOST_CHECK(!addr.SetSpecial(std::string{"mf*g zak.onion"}));
     233             : 
     234             :     // I2P
     235           1 :     const char* i2p_addr = "UDHDrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.I2P";
     236           1 :     BOOST_REQUIRE(addr.SetSpecial(i2p_addr));
     237           1 :     BOOST_REQUIRE(addr.IsValid());
     238           1 :     BOOST_REQUIRE(addr.IsI2P());
     239             : 
     240           1 :     BOOST_CHECK(!addr.IsTor());
     241           1 :     BOOST_CHECK(!addr.IsBindAny());
     242           1 :     BOOST_CHECK(!addr.IsAddrV1Compatible());
     243           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), ToLower(i2p_addr));
     244             : 
     245             :     // I2P, correct length, but decodes to less than the expected number of bytes.
     246           1 :     BOOST_CHECK(!addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jn=.b32.i2p"));
     247             : 
     248             :     // I2P, extra unnecessary padding
     249           1 :     BOOST_CHECK(!addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna=.b32.i2p"));
     250             : 
     251             :     // I2P, malicious
     252           1 :     BOOST_CHECK(!addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v\0wtf.b32.i2p"s));
     253             : 
     254             :     // I2P, valid but unsupported (56 Base32 characters)
     255             :     // See "Encrypted LS with Base 32 Addresses" in
     256             :     // https://geti2p.net/spec/encryptedleaseset.txt
     257           1 :     BOOST_CHECK(
     258             :         !addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscsad.b32.i2p"));
     259             : 
     260             :     // I2P, invalid base32
     261           1 :     BOOST_CHECK(!addr.SetSpecial(std::string{"tp*szydbh4dp.b32.i2p"}));
     262             : 
     263             :     // Internal
     264           1 :     addr.SetInternal("esffpp");
     265           1 :     BOOST_REQUIRE(!addr.IsValid()); // "internal" is considered invalid
     266           1 :     BOOST_REQUIRE(addr.IsInternal());
     267             : 
     268           1 :     BOOST_CHECK(!addr.IsBindAny());
     269           1 :     BOOST_CHECK(addr.IsAddrV1Compatible());
     270           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "esffpvrt3wpeaygy.internal");
     271             : 
     272             :     // Totally bogus
     273           1 :     BOOST_CHECK(!addr.SetSpecial("totally bogus"));
     274           1 : }
     275             : 
     276         149 : BOOST_AUTO_TEST_CASE(cnetaddr_tostring_canonical_ipv6)
     277             : {
     278             :     // Test that CNetAddr::ToString formats IPv6 addresses with zero compression as described in
     279             :     // RFC 5952 ("A Recommendation for IPv6 Address Text Representation").
     280           1 :     const std::map<std::string, std::string> canonical_representations_ipv6{
     281           1 :         {"0000:0000:0000:0000:0000:0000:0000:0000", "::"},
     282           1 :         {"000:0000:000:00:0:00:000:0000", "::"},
     283           1 :         {"000:000:000:000:000:000:000:000", "::"},
     284           1 :         {"00:00:00:00:00:00:00:00", "::"},
     285           1 :         {"0:0:0:0:0:0:0:0", "::"},
     286           1 :         {"0:0:0:0:0:0:0:1", "::1"},
     287           1 :         {"2001:0:0:1:0:0:0:1", "2001:0:0:1::1"},
     288           1 :         {"2001:0db8:0:0:1:0:0:1", "2001:db8::1:0:0:1"},
     289           1 :         {"2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:db8:85a3::8a2e:370:7334"},
     290           1 :         {"2001:0db8::0001", "2001:db8::1"},
     291           1 :         {"2001:0db8::0001:0000", "2001:db8::1:0"},
     292           1 :         {"2001:0db8::1:0:0:1", "2001:db8::1:0:0:1"},
     293           1 :         {"2001:db8:0000:0:1::1", "2001:db8::1:0:0:1"},
     294           1 :         {"2001:db8:0000:1:1:1:1:1", "2001:db8:0:1:1:1:1:1"},
     295           1 :         {"2001:db8:0:0:0:0:2:1", "2001:db8::2:1"},
     296           1 :         {"2001:db8:0:0:0::1", "2001:db8::1"},
     297           1 :         {"2001:db8:0:0:1:0:0:1", "2001:db8::1:0:0:1"},
     298           1 :         {"2001:db8:0:0:1::1", "2001:db8::1:0:0:1"},
     299           1 :         {"2001:DB8:0:0:1::1", "2001:db8::1:0:0:1"},
     300           1 :         {"2001:db8:0:0::1", "2001:db8::1"},
     301           1 :         {"2001:db8:0:0:aaaa::1", "2001:db8::aaaa:0:0:1"},
     302           1 :         {"2001:db8:0:1:1:1:1:1", "2001:db8:0:1:1:1:1:1"},
     303           1 :         {"2001:db8:0::1", "2001:db8::1"},
     304           1 :         {"2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3::8a2e:370:7334"},
     305           1 :         {"2001:db8::0:1", "2001:db8::1"},
     306           1 :         {"2001:db8::0:1:0:0:1", "2001:db8::1:0:0:1"},
     307           1 :         {"2001:DB8::1", "2001:db8::1"},
     308           1 :         {"2001:db8::1", "2001:db8::1"},
     309           1 :         {"2001:db8::1:0:0:1", "2001:db8::1:0:0:1"},
     310           1 :         {"2001:db8::1:1:1:1:1", "2001:db8:0:1:1:1:1:1"},
     311           1 :         {"2001:db8::aaaa:0:0:1", "2001:db8::aaaa:0:0:1"},
     312           1 :         {"2001:db8:aaaa:bbbb:cccc:dddd:0:1", "2001:db8:aaaa:bbbb:cccc:dddd:0:1"},
     313           1 :         {"2001:db8:aaaa:bbbb:cccc:dddd::1", "2001:db8:aaaa:bbbb:cccc:dddd:0:1"},
     314           1 :         {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
     315           1 :         {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:001", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
     316           1 :         {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:01", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
     317           1 :         {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
     318           1 :         {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
     319           1 :         {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
     320           1 :         {"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
     321             :     };
     322          81 :     for (const auto& [input_address, expected_canonical_representation_output] : canonical_representations_ipv6) {
     323          40 :         const std::optional<CNetAddr> net_addr{LookupHost(input_address, false)};
     324          40 :         BOOST_REQUIRE(net_addr.value().IsIPv6());
     325          40 :         BOOST_CHECK_EQUAL(net_addr.value().ToStringAddr(), expected_canonical_representation_output);
     326          40 :     }
     327           1 : }
     328             : 
     329         149 : BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1)
     330             : {
     331           1 :     CNetAddr addr;
     332           1 :     CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
     333             : 
     334           1 :     s << addr;
     335           1 :     BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000");
     336           1 :     s.clear();
     337             : 
     338           1 :     addr = LookupHost("1.2.3.4", false).value();
     339           1 :     s << addr;
     340           1 :     BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000ffff01020304");
     341           1 :     s.clear();
     342             : 
     343           1 :     addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value();
     344           1 :     s << addr;
     345           1 :     BOOST_CHECK_EQUAL(HexStr(s), "1a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
     346           1 :     s.clear();
     347             : 
     348             :     // TORv2, no longer supported
     349           1 :     BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
     350             : 
     351           1 :     BOOST_REQUIRE(addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
     352           1 :     s << addr;
     353           1 :     BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000");
     354           1 :     s.clear();
     355             : 
     356           1 :     addr.SetInternal("a");
     357           1 :     s << addr;
     358           1 :     BOOST_CHECK_EQUAL(HexStr(s), "fd6b88c08724ca978112ca1bbdcafac2");
     359           1 :     s.clear();
     360           1 : }
     361             : 
     362         149 : BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2)
     363             : {
     364           1 :     CNetAddr addr;
     365           1 :     CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
     366             :     // Add ADDRV2_FORMAT to the version so that the CNetAddr
     367             :     // serialize method produces an address in v2 format.
     368           1 :     s.SetVersion(s.GetVersion() | ADDRV2_FORMAT);
     369             : 
     370           1 :     s << addr;
     371           1 :     BOOST_CHECK_EQUAL(HexStr(s), "021000000000000000000000000000000000");
     372           1 :     s.clear();
     373             : 
     374           1 :     addr = LookupHost("1.2.3.4", false).value();
     375           1 :     s << addr;
     376           1 :     BOOST_CHECK_EQUAL(HexStr(s), "010401020304");
     377           1 :     s.clear();
     378             : 
     379           1 :     addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value();
     380           1 :     s << addr;
     381           1 :     BOOST_CHECK_EQUAL(HexStr(s), "02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
     382           1 :     s.clear();
     383             : 
     384             :     // TORv2, no longer supported
     385           1 :     BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
     386             : 
     387           1 :     BOOST_REQUIRE(addr.SetSpecial("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion"));
     388           1 :     s << addr;
     389           1 :     BOOST_CHECK_EQUAL(HexStr(s), "042053cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88");
     390           1 :     s.clear();
     391             : 
     392           1 :     BOOST_REQUIRE(addr.SetInternal("a"));
     393           1 :     s << addr;
     394           1 :     BOOST_CHECK_EQUAL(HexStr(s), "0210fd6b88c08724ca978112ca1bbdcafac2");
     395           1 :     s.clear();
     396           1 : }
     397             : 
     398         149 : BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
     399             : {
     400           1 :     CNetAddr addr;
     401           1 :     CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
     402             :     // Add ADDRV2_FORMAT to the version so that the CNetAddr
     403             :     // unserialize method expects an address in v2 format.
     404           1 :     s.SetVersion(s.GetVersion() | ADDRV2_FORMAT);
     405             : 
     406             :     // Valid IPv4.
     407           1 :     s << Span{ParseHex("01"          // network type (IPv4)
     408             :                        "04"          // address length
     409             :                        "01020304")}; // address
     410           1 :     s >> addr;
     411           1 :     BOOST_CHECK(addr.IsValid());
     412           1 :     BOOST_CHECK(addr.IsIPv4());
     413           1 :     BOOST_CHECK(addr.IsAddrV1Compatible());
     414           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "1.2.3.4");
     415           1 :     BOOST_REQUIRE(s.empty());
     416             : 
     417             :     // Invalid IPv4, valid length but address itself is shorter.
     418           1 :     s << Span{ParseHex("01"      // network type (IPv4)
     419             :                        "04"      // address length
     420             :                        "0102")}; // address
     421           2 :     BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, HasReason("end of data"));
     422           1 :     BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
     423           1 :     s.clear();
     424             : 
     425             :     // Invalid IPv4, with bogus length.
     426           1 :     s << Span{ParseHex("01"          // network type (IPv4)
     427             :                        "05"          // address length
     428             :                        "01020304")}; // address
     429           2 :     BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
     430             :                           HasReason("BIP155 IPv4 address with length 5 (should be 4)"));
     431           1 :     BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
     432           1 :     s.clear();
     433             : 
     434             :     // Invalid IPv4, with extreme length.
     435           1 :     s << Span{ParseHex("01"          // network type (IPv4)
     436             :                        "fd0102"      // address length (513 as CompactSize)
     437             :                        "01020304")}; // address
     438           2 :     BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
     439             :                           HasReason("Address too long: 513 > 512"));
     440           1 :     BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
     441           1 :     s.clear();
     442             : 
     443             :     // Valid IPv6.
     444           1 :     s << Span{ParseHex("02"                                  // network type (IPv6)
     445             :                        "10"                                  // address length
     446             :                        "0102030405060708090a0b0c0d0e0f10")}; // address
     447           1 :     s >> addr;
     448           1 :     BOOST_CHECK(addr.IsValid());
     449           1 :     BOOST_CHECK(addr.IsIPv6());
     450           1 :     BOOST_CHECK(addr.IsAddrV1Compatible());
     451           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "102:304:506:708:90a:b0c:d0e:f10");
     452           1 :     BOOST_REQUIRE(s.empty());
     453             : 
     454             :     // Valid IPv6, contains embedded "internal".
     455           1 :     s << Span{ParseHex(
     456           1 :         "02"                                  // network type (IPv6)
     457             :         "10"                                  // address length
     458             :         "fd6b88c08724ca978112ca1bbdcafac2")}; // address: 0xfd + sha256("bitcoin")[0:5] +
     459             :                                               // sha256(name)[0:10]
     460           1 :     s >> addr;
     461           1 :     BOOST_CHECK(addr.IsInternal());
     462           1 :     BOOST_CHECK(addr.IsAddrV1Compatible());
     463           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "zklycewkdo64v6wc.internal");
     464           1 :     BOOST_REQUIRE(s.empty());
     465             : 
     466             :     // Invalid IPv6, with bogus length.
     467           1 :     s << Span{ParseHex("02"    // network type (IPv6)
     468             :                        "04"    // address length
     469             :                        "00")}; // address
     470           2 :     BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
     471             :                           HasReason("BIP155 IPv6 address with length 4 (should be 16)"));
     472           1 :     BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
     473           1 :     s.clear();
     474             : 
     475             :     // Invalid IPv6, contains embedded IPv4.
     476           1 :     s << Span{ParseHex("02"                                  // network type (IPv6)
     477             :                        "10"                                  // address length
     478             :                        "00000000000000000000ffff01020304")}; // address
     479           1 :     s >> addr;
     480           1 :     BOOST_CHECK(!addr.IsValid());
     481           1 :     BOOST_REQUIRE(s.empty());
     482             : 
     483             :     // Invalid IPv6, contains embedded TORv2.
     484           1 :     s << Span{ParseHex("02"                                  // network type (IPv6)
     485             :                        "10"                                  // address length
     486             :                        "fd87d87eeb430102030405060708090a")}; // address
     487           1 :     s >> addr;
     488           1 :     BOOST_CHECK(!addr.IsValid());
     489           1 :     BOOST_REQUIRE(s.empty());
     490             : 
     491             :     // TORv2, no longer supported.
     492           1 :     s << Span{ParseHex("03"                      // network type (TORv2)
     493             :                        "0a"                      // address length
     494             :                        "f1f2f3f4f5f6f7f8f9fa")}; // address
     495           1 :     s >> addr;
     496           1 :     BOOST_CHECK(!addr.IsValid());
     497           1 :     BOOST_REQUIRE(s.empty());
     498             : 
     499             :     // Valid TORv3.
     500           1 :     s << Span{ParseHex("04"                               // network type (TORv3)
     501             :                        "20"                               // address length
     502             :                        "79bcc625184b05194975c28b66b66b04" // address
     503             :                        "69f7f6556fb1ac3189a79b40dda32f1f"
     504             :                        )};
     505           1 :     s >> addr;
     506           1 :     BOOST_CHECK(addr.IsValid());
     507           1 :     BOOST_CHECK(addr.IsTor());
     508           1 :     BOOST_CHECK(!addr.IsAddrV1Compatible());
     509           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(),
     510             :                       "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion");
     511           1 :     BOOST_REQUIRE(s.empty());
     512             : 
     513             :     // Invalid TORv3, with bogus length.
     514           1 :     s << Span{ParseHex("04" // network type (TORv3)
     515             :                        "00" // address length
     516             :                        "00" // address
     517             :                        )};
     518           2 :     BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
     519             :                           HasReason("BIP155 TORv3 address with length 0 (should be 32)"));
     520           1 :     BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
     521           1 :     s.clear();
     522             : 
     523             :     // Valid I2P.
     524           1 :     s << Span{ParseHex("05"                               // network type (I2P)
     525             :                        "20"                               // address length
     526             :                        "a2894dabaec08c0051a481a6dac88b64" // address
     527             :                        "f98232ae42d4b6fd2fa81952dfe36a87")};
     528           1 :     s >> addr;
     529           1 :     BOOST_CHECK(addr.IsValid());
     530           1 :     BOOST_CHECK(addr.IsI2P());
     531           1 :     BOOST_CHECK(!addr.IsAddrV1Compatible());
     532           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(),
     533             :                       "ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq.b32.i2p");
     534           1 :     BOOST_REQUIRE(s.empty());
     535             : 
     536             :     // Invalid I2P, with bogus length.
     537           1 :     s << Span{ParseHex("05" // network type (I2P)
     538             :                        "03" // address length
     539             :                        "00" // address
     540             :                        )};
     541           2 :     BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
     542             :                           HasReason("BIP155 I2P address with length 3 (should be 32)"));
     543           1 :     BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
     544           1 :     s.clear();
     545             : 
     546             :     // Valid CJDNS.
     547           1 :     s << Span{ParseHex("06"                               // network type (CJDNS)
     548             :                        "10"                               // address length
     549             :                        "fc000001000200030004000500060007" // address
     550             :                        )};
     551           1 :     s >> addr;
     552           1 :     BOOST_CHECK(addr.IsValid());
     553           1 :     BOOST_CHECK(addr.IsCJDNS());
     554           1 :     BOOST_CHECK(!addr.IsAddrV1Compatible());
     555           1 :     BOOST_CHECK_EQUAL(addr.ToStringAddr(), "fc00:1:2:3:4:5:6:7");
     556           1 :     BOOST_REQUIRE(s.empty());
     557             : 
     558             :     // Invalid CJDNS, wrong prefix.
     559           1 :     s << Span{ParseHex("06"                               // network type (CJDNS)
     560             :                        "10"                               // address length
     561             :                        "aa000001000200030004000500060007" // address
     562             :                        )};
     563           1 :     s >> addr;
     564           1 :     BOOST_CHECK(addr.IsCJDNS());
     565           1 :     BOOST_CHECK(!addr.IsValid());
     566           1 :     BOOST_REQUIRE(s.empty());
     567             : 
     568             :     // Invalid CJDNS, with bogus length.
     569           1 :     s << Span{ParseHex("06" // network type (CJDNS)
     570             :                        "01" // address length
     571             :                        "00" // address
     572             :                        )};
     573           2 :     BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
     574             :                           HasReason("BIP155 CJDNS address with length 1 (should be 16)"));
     575           1 :     BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
     576           1 :     s.clear();
     577             : 
     578             :     // Unknown, with extreme length.
     579           1 :     s << Span{ParseHex("aa"             // network type (unknown)
     580             :                        "fe00000002"     // address length (CompactSize's MAX_SIZE)
     581             :                        "01020304050607" // address
     582             :                        )};
     583           2 :     BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
     584             :                           HasReason("Address too long: 33554432 > 512"));
     585           1 :     BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
     586           1 :     s.clear();
     587             : 
     588             :     // Unknown, with reasonable length.
     589           1 :     s << Span{ParseHex("aa"       // network type (unknown)
     590             :                        "04"       // address length
     591             :                        "01020304" // address
     592             :                        )};
     593           1 :     s >> addr;
     594           1 :     BOOST_CHECK(!addr.IsValid());
     595           1 :     BOOST_REQUIRE(s.empty());
     596             : 
     597             :     // Unknown, with zero length.
     598           1 :     s << Span{ParseHex("aa" // network type (unknown)
     599             :                        "00" // address length
     600             :                        ""   // address
     601             :                        )};
     602           1 :     s >> addr;
     603           1 :     BOOST_CHECK(!addr.IsValid());
     604           1 :     BOOST_REQUIRE(s.empty());
     605           9 : }
     606             : 
     607             : // prior to PR #14728, this test triggers an undefined behavior
     608         149 : BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
     609             : {
     610             :     // set up local addresses; all that's necessary to reproduce the bug is
     611             :     // that a normal IPv4 address is among the entries, but if this address is
     612             :     // !IsRoutable the undefined behavior is easier to trigger deterministically
     613             :     in_addr raw_addr;
     614           1 :     raw_addr.s_addr = htonl(0x7f000001);
     615           1 :     const CNetAddr mapLocalHost_entry = CNetAddr(raw_addr);
     616             :     {
     617           1 :         LOCK(g_maplocalhost_mutex);
     618             :         LocalServiceInfo lsi;
     619           1 :         lsi.nScore = 23;
     620           1 :         lsi.nPort = 42;
     621           1 :         mapLocalHost[mapLocalHost_entry] = lsi;
     622           1 :     }
     623             : 
     624             :     // create a peer with an IPv4 address
     625             :     in_addr ipv4AddrPeer;
     626           1 :     ipv4AddrPeer.s_addr = 0xa0b0c001;
     627           1 :     CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
     628           1 :     std::unique_ptr<CNode> pnode = std::make_unique<CNode>(/*id=*/0,
     629           1 :                                                            /*sock=*/nullptr,
     630             :                                                            addr,
     631           1 :                                                            /*nKeyedNetGroupIn=*/0,
     632           1 :                                                            /*nLocalHostNonceIn=*/0,
     633           1 :                                                            CAddress{},
     634           1 :                                                            /*pszDest=*/std::string{},
     635           1 :                                                            ConnectionType::OUTBOUND_FULL_RELAY,
     636           1 :                                                            /*inbound_onion=*/false);
     637           1 :     pnode->fSuccessfullyConnected.store(true);
     638             : 
     639             :     // the peer claims to be reaching us via IPv6
     640             :     in6_addr ipv6AddrLocal;
     641           1 :     memset(ipv6AddrLocal.s6_addr, 0, 16);
     642           1 :     ipv6AddrLocal.s6_addr[0] = 0xcc;
     643           1 :     CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK);
     644           1 :     pnode->SetAddrLocal(addrLocal);
     645             : 
     646             :     // before patch, this causes undefined behavior detectable with clang's -fsanitize=memory
     647           1 :     GetLocalAddrForPeer(*pnode);
     648             : 
     649             :     // suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer
     650           1 :     BOOST_CHECK(1);
     651             : 
     652             :     // Cleanup, so that we don't confuse other tests.
     653             :     {
     654           1 :         LOCK(g_maplocalhost_mutex);
     655           1 :         mapLocalHost.erase(mapLocalHost_entry);
     656           1 :     }
     657           1 : }
     658             : 
     659         149 : BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
     660             : {
     661             :     // Test that GetLocalAddrForPeer() properly selects the address to self-advertise:
     662             :     //
     663             :     // 1. GetLocalAddrForPeer() calls GetLocalAddress() which returns an address that is
     664             :     //    not routable.
     665             :     // 2. GetLocalAddrForPeer() overrides the address with whatever the peer has told us
     666             :     //    he sees us as.
     667             :     // 2.1. For inbound connections we must override both the address and the port.
     668             :     // 2.2. For outbound connections we must override only the address.
     669             : 
     670             :     // Pretend that we bound to this port.
     671           1 :     const uint16_t bind_port = 20001;
     672           1 :     m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port));
     673             : 
     674             :     // Our address:port as seen from the peer, completely different from the above.
     675             :     in_addr peer_us_addr;
     676           1 :     peer_us_addr.s_addr = htonl(0x02030405);
     677           1 :     const CService peer_us{peer_us_addr, 20002};
     678             : 
     679             :     // Create a peer with a routable IPv4 address (outbound).
     680             :     in_addr peer_out_in_addr;
     681           1 :     peer_out_in_addr.s_addr = htonl(0x01020304);
     682           1 :     CNode peer_out{/*id=*/0,
     683           1 :                    /*sock=*/nullptr,
     684           1 :                    /*addrIn=*/CAddress{CService{peer_out_in_addr, 8333}, NODE_NETWORK},
     685             :                    /*nKeyedNetGroupIn=*/0,
     686             :                    /*nLocalHostNonceIn=*/0,
     687           1 :                    /*addrBindIn=*/CAddress{},
     688           1 :                    /*addrNameIn=*/std::string{},
     689             :                    /*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
     690             :                    /*inbound_onion=*/false};
     691           1 :     peer_out.fSuccessfullyConnected = true;
     692           1 :     peer_out.SetAddrLocal(peer_us);
     693             : 
     694             :     // Without the fix peer_us:8333 is chosen instead of the proper peer_us:bind_port.
     695           1 :     auto chosen_local_addr = GetLocalAddrForPeer(peer_out);
     696           1 :     BOOST_REQUIRE(chosen_local_addr);
     697           1 :     const CService expected{peer_us_addr, bind_port};
     698           1 :     BOOST_CHECK(*chosen_local_addr == expected);
     699             : 
     700             :     // Create a peer with a routable IPv4 address (inbound).
     701             :     in_addr peer_in_in_addr;
     702           1 :     peer_in_in_addr.s_addr = htonl(0x05060708);
     703           1 :     CNode peer_in{/*id=*/0,
     704           1 :                   /*sock=*/nullptr,
     705           1 :                   /*addrIn=*/CAddress{CService{peer_in_in_addr, 8333}, NODE_NETWORK},
     706             :                   /*nKeyedNetGroupIn=*/0,
     707             :                   /*nLocalHostNonceIn=*/0,
     708           1 :                   /*addrBindIn=*/CAddress{},
     709           1 :                   /*addrNameIn=*/std::string{},
     710             :                   /*conn_type_in=*/ConnectionType::INBOUND,
     711             :                   /*inbound_onion=*/false};
     712           1 :     peer_in.fSuccessfullyConnected = true;
     713           1 :     peer_in.SetAddrLocal(peer_us);
     714             : 
     715             :     // Without the fix peer_us:8333 is chosen instead of the proper peer_us:peer_us.GetPort().
     716           1 :     chosen_local_addr = GetLocalAddrForPeer(peer_in);
     717           1 :     BOOST_REQUIRE(chosen_local_addr);
     718           1 :     BOOST_CHECK(*chosen_local_addr == peer_us);
     719             : 
     720           1 :     m_node.args->ForceSetArg("-bind", "");
     721           1 : }
     722             : 
     723         149 : BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network)
     724             : {
     725           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_IPV4));
     726           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_IPV6));
     727           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_ONION));
     728           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_I2P));
     729           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_CJDNS));
     730             : 
     731           1 :     g_reachable_nets.Remove(NET_IPV4);
     732           1 :     g_reachable_nets.Remove(NET_IPV6);
     733           1 :     g_reachable_nets.Remove(NET_ONION);
     734           1 :     g_reachable_nets.Remove(NET_I2P);
     735           1 :     g_reachable_nets.Remove(NET_CJDNS);
     736             : 
     737           1 :     BOOST_CHECK(!g_reachable_nets.Contains(NET_IPV4));
     738           1 :     BOOST_CHECK(!g_reachable_nets.Contains(NET_IPV6));
     739           1 :     BOOST_CHECK(!g_reachable_nets.Contains(NET_ONION));
     740           1 :     BOOST_CHECK(!g_reachable_nets.Contains(NET_I2P));
     741           1 :     BOOST_CHECK(!g_reachable_nets.Contains(NET_CJDNS));
     742             : 
     743           1 :     g_reachable_nets.Add(NET_IPV4);
     744           1 :     g_reachable_nets.Add(NET_IPV6);
     745           1 :     g_reachable_nets.Add(NET_ONION);
     746           1 :     g_reachable_nets.Add(NET_I2P);
     747           1 :     g_reachable_nets.Add(NET_CJDNS);
     748             : 
     749           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_IPV4));
     750           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_IPV6));
     751           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_ONION));
     752           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_I2P));
     753           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_CJDNS));
     754           1 : }
     755             : 
     756         149 : BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal)
     757             : {
     758             :     // Should be reachable by default.
     759           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_UNROUTABLE));
     760           1 :     BOOST_CHECK(g_reachable_nets.Contains(NET_INTERNAL));
     761             : 
     762           1 :     g_reachable_nets.RemoveAll();
     763             : 
     764           1 :     BOOST_CHECK(!g_reachable_nets.Contains(NET_UNROUTABLE));
     765           1 :     BOOST_CHECK(!g_reachable_nets.Contains(NET_INTERNAL));
     766             : 
     767           1 :     g_reachable_nets.Add(NET_IPV4);
     768           1 :     g_reachable_nets.Add(NET_IPV6);
     769           1 :     g_reachable_nets.Add(NET_ONION);
     770           1 :     g_reachable_nets.Add(NET_I2P);
     771           1 :     g_reachable_nets.Add(NET_CJDNS);
     772           1 :     g_reachable_nets.Add(NET_UNROUTABLE);
     773           1 :     g_reachable_nets.Add(NET_INTERNAL);
     774           1 : }
     775             : 
     776           2 : CNetAddr UtilBuildAddress(unsigned char p1, unsigned char p2, unsigned char p3, unsigned char p4)
     777             : {
     778           2 :     unsigned char ip[] = {p1, p2, p3, p4};
     779             : 
     780             :     struct sockaddr_in sa;
     781           2 :     memset(&sa, 0, sizeof(sockaddr_in)); // initialize the memory block
     782           2 :     memcpy(&(sa.sin_addr), &ip, sizeof(ip));
     783           2 :     return CNetAddr(sa.sin_addr);
     784             : }
     785             : 
     786             : 
     787         149 : BOOST_AUTO_TEST_CASE(LimitedAndReachable_CNetAddr)
     788             : {
     789           1 :     CNetAddr addr = UtilBuildAddress(0x001, 0x001, 0x001, 0x001); // 1.1.1.1
     790             : 
     791           1 :     g_reachable_nets.Add(NET_IPV4);
     792           1 :     BOOST_CHECK(g_reachable_nets.Contains(addr));
     793             : 
     794           1 :     g_reachable_nets.Remove(NET_IPV4);
     795           1 :     BOOST_CHECK(!g_reachable_nets.Contains(addr));
     796             : 
     797           1 :     g_reachable_nets.Add(NET_IPV4); // have to reset this, because this is stateful.
     798           1 : }
     799             : 
     800             : 
     801         149 : BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle)
     802             : {
     803           1 :     CService addr = CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000); // 2.1.1.1:1000
     804             : 
     805           1 :     g_reachable_nets.Add(NET_IPV4);
     806             : 
     807           1 :     BOOST_CHECK(!IsLocal(addr));
     808           1 :     BOOST_CHECK(AddLocal(addr, 1000));
     809           1 :     BOOST_CHECK(IsLocal(addr));
     810             : 
     811           1 :     RemoveLocal(addr);
     812           1 :     BOOST_CHECK(!IsLocal(addr));
     813           1 : }
     814             : 
     815         149 : BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
     816             : {
     817           1 :     LOCK(NetEventsInterface::g_msgproc_mutex);
     818             : 
     819             :     // Tests the following scenario:
     820             :     // * -bind=3.4.5.6:20001 is specified
     821             :     // * we make an outbound connection to a peer
     822             :     // * the peer reports he sees us as 2.3.4.5:20002 in the version message
     823             :     //   (20002 is a random port assigned by our OS for the outgoing TCP connection,
     824             :     //   we cannot accept connections to it)
     825             :     // * we should self-advertise to that peer as 2.3.4.5:20001
     826             : 
     827             :     // Pretend that we bound to this port.
     828           1 :     const uint16_t bind_port = 20001;
     829           1 :     m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port));
     830           1 :     m_node.args->ForceSetArg("-capturemessages", "1");
     831             : 
     832             :     // Our address:port as seen from the peer - 2.3.4.5:20002 (different from the above).
     833             :     in_addr peer_us_addr;
     834           1 :     peer_us_addr.s_addr = htonl(0x02030405);
     835           1 :     const CService peer_us{peer_us_addr, 20002};
     836             : 
     837             :     // Create a peer with a routable IPv4 address.
     838             :     in_addr peer_in_addr;
     839           1 :     peer_in_addr.s_addr = htonl(0x01020304);
     840           1 :     CNode peer{/*id=*/0,
     841           1 :                /*sock=*/nullptr,
     842           1 :                /*addrIn=*/CAddress{CService{peer_in_addr, 8333}, NODE_NETWORK},
     843             :                /*nKeyedNetGroupIn=*/0,
     844             :                /*nLocalHostNonceIn=*/0,
     845           1 :                /*addrBindIn=*/CAddress{},
     846           1 :                /*addrNameIn=*/std::string{},
     847             :                /*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
     848             :                /*inbound_onion=*/false};
     849             : 
     850           1 :     const uint64_t services{NODE_NETWORK};
     851           1 :     const int64_t time{0};
     852           1 :     const CNetMsgMaker msg_maker{PROTOCOL_VERSION};
     853             : 
     854             :     // Force CChainState::IsInitialBlockDownload() to return false.
     855             :     // Otherwise PushAddress() isn't called by PeerManager::ProcessMessage().
     856           1 :     TestChainState& chainstate =
     857           1 :         *static_cast<TestChainState*>(&m_node.chainman->ActiveChainstate());
     858           1 :     chainstate.JumpOutOfIbd();
     859             : 
     860           1 :     m_node.peerman->InitializeNode(peer, NODE_NETWORK);
     861             : 
     862           1 :     std::atomic<bool> interrupt_dummy{false};
     863           1 :     std::chrono::microseconds time_received_dummy{0};
     864             : 
     865             :     const auto msg_version =
     866           1 :         msg_maker.Make(NetMsgType::VERSION, PROTOCOL_VERSION, services, time, services, peer_us);
     867           1 :     CDataStream msg_version_stream{msg_version.data, SER_NETWORK, PROTOCOL_VERSION};
     868             : 
     869           1 :     m_node.peerman->ProcessMessage(
     870           1 :         peer, NetMsgType::VERSION, msg_version_stream, time_received_dummy, interrupt_dummy);
     871             : 
     872           1 :     const auto msg_verack = msg_maker.Make(NetMsgType::VERACK);
     873           1 :     CDataStream msg_verack_stream{msg_verack.data, SER_NETWORK, PROTOCOL_VERSION};
     874             : 
     875             :     // Will set peer.fSuccessfullyConnected to true (necessary in SendMessages()).
     876           1 :     m_node.peerman->ProcessMessage(
     877           1 :         peer, NetMsgType::VERACK, msg_verack_stream, time_received_dummy, interrupt_dummy);
     878             : 
     879             :     // Ensure that peer_us_addr:bind_port is sent to the peer.
     880           1 :     const CService expected{peer_us_addr, bind_port};
     881           1 :     bool sent{false};
     882             : 
     883           1 :     const auto CaptureMessageOrig = CaptureMessage;
     884           4 :     CaptureMessage = [&sent, &expected](const CAddress& addr,
     885             :                                         const std::string& msg_type,
     886             :                                         Span<const unsigned char> data,
     887             :                                         bool is_incoming) -> void {
     888           3 :         if (!is_incoming && msg_type == "addr") {
     889           1 :             CDataStream s(data, SER_NETWORK, PROTOCOL_VERSION);
     890           1 :             std::vector<CAddress> addresses;
     891             : 
     892           1 :             s >> addresses;
     893             : 
     894           1 :             for (const auto& addr : addresses) {
     895           1 :                 if (addr == expected) {
     896           1 :                     sent = true;
     897           1 :                     return;
     898             :                 }
     899             :             }
     900           1 :         }
     901           3 :     };
     902             : 
     903           1 :     m_node.peerman->SendMessages(&peer);
     904             : 
     905           1 :     BOOST_CHECK(sent);
     906             : 
     907           1 :     CaptureMessage = CaptureMessageOrig;
     908           1 :     chainstate.ResetIbd();
     909           1 :     m_node.args->ForceSetArg("-capturemessages", "0");
     910           1 :     m_node.args->ForceSetArg("-bind", "");
     911             :     // PeerManager::ProcessMessage() calls AddTimeData() which changes the internal state
     912             :     // in timedata.cpp and later confuses the test "timedata_tests/addtimedata". Thus reset
     913             :     // that state as it was before our test was run.
     914           1 :     TestOnlyResetTimeData();
     915           1 : }
     916             : 
     917             : 
     918         149 : BOOST_AUTO_TEST_CASE(advertise_local_address)
     919             : {
     920           8 :     auto CreatePeer = [](const CAddress& addr) {
     921          14 :         return std::make_unique<CNode>(/*id=*/0,
     922           7 :                                        /*sock=*/nullptr,
     923           7 :                                        addr,
     924           7 :                                        /*nKeyedNetGroupIn=*/0,
     925           7 :                                        /*nLocalHostNonceIn=*/0,
     926           7 :                                        CAddress{},
     927           7 :                                        /*pszDest=*/std::string{},
     928           7 :                                        ConnectionType::OUTBOUND_FULL_RELAY,
     929           7 :                                        /*inbound_onion=*/false);
     930           0 :     };
     931           1 :     g_reachable_nets.Add(NET_CJDNS);
     932             : 
     933           1 :     CAddress addr_ipv4{Lookup("1.2.3.4", 8333, false).value(), NODE_NONE};
     934           1 :     BOOST_REQUIRE(addr_ipv4.IsValid());
     935           1 :     BOOST_REQUIRE(addr_ipv4.IsIPv4());
     936             : 
     937           1 :     CAddress addr_ipv6{Lookup("1122:3344:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
     938           1 :     BOOST_REQUIRE(addr_ipv6.IsValid());
     939           1 :     BOOST_REQUIRE(addr_ipv6.IsIPv6());
     940             : 
     941           1 :     CAddress addr_ipv6_tunnel{Lookup("2002:3344:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
     942           1 :     BOOST_REQUIRE(addr_ipv6_tunnel.IsValid());
     943           1 :     BOOST_REQUIRE(addr_ipv6_tunnel.IsIPv6());
     944           1 :     BOOST_REQUIRE(addr_ipv6_tunnel.IsRFC3964());
     945             : 
     946           1 :     CAddress addr_teredo{Lookup("2001:0000:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
     947           1 :     BOOST_REQUIRE(addr_teredo.IsValid());
     948           1 :     BOOST_REQUIRE(addr_teredo.IsIPv6());
     949           1 :     BOOST_REQUIRE(addr_teredo.IsRFC4380());
     950             : 
     951           1 :     CAddress addr_onion;
     952           1 :     BOOST_REQUIRE(addr_onion.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
     953           1 :     BOOST_REQUIRE(addr_onion.IsValid());
     954           1 :     BOOST_REQUIRE(addr_onion.IsTor());
     955             : 
     956           1 :     CAddress addr_i2p;
     957           1 :     BOOST_REQUIRE(addr_i2p.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p"));
     958           1 :     BOOST_REQUIRE(addr_i2p.IsValid());
     959           1 :     BOOST_REQUIRE(addr_i2p.IsI2P());
     960             : 
     961           1 :     CService service_cjdns{Lookup("fc00:3344:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
     962           1 :     CAddress addr_cjdns{MaybeFlipIPv6toCJDNS(service_cjdns), NODE_NONE};
     963           1 :     BOOST_REQUIRE(addr_cjdns.IsValid());
     964           1 :     BOOST_REQUIRE(addr_cjdns.IsCJDNS());
     965             : 
     966           1 :     const auto peer_ipv4{CreatePeer(addr_ipv4)};
     967           1 :     const auto peer_ipv6{CreatePeer(addr_ipv6)};
     968           1 :     const auto peer_ipv6_tunnel{CreatePeer(addr_ipv6_tunnel)};
     969           1 :     const auto peer_teredo{CreatePeer(addr_teredo)};
     970           1 :     const auto peer_onion{CreatePeer(addr_onion)};
     971           1 :     const auto peer_i2p{CreatePeer(addr_i2p)};
     972           1 :     const auto peer_cjdns{CreatePeer(addr_cjdns)};
     973             : 
     974             :     // one local clearnet address - advertise to all but privacy peers
     975           1 :     AddLocal(addr_ipv4);
     976           1 :     BOOST_CHECK(GetLocalAddress(*peer_ipv4) == addr_ipv4);
     977           1 :     BOOST_CHECK(GetLocalAddress(*peer_ipv6) == addr_ipv4);
     978           1 :     BOOST_CHECK(GetLocalAddress(*peer_ipv6_tunnel) == addr_ipv4);
     979           1 :     BOOST_CHECK(GetLocalAddress(*peer_teredo) == addr_ipv4);
     980           1 :     BOOST_CHECK(GetLocalAddress(*peer_cjdns) == addr_ipv4);
     981           1 :     BOOST_CHECK(!GetLocalAddress(*peer_onion).IsValid());
     982           1 :     BOOST_CHECK(!GetLocalAddress(*peer_i2p).IsValid());
     983           1 :     RemoveLocal(addr_ipv4);
     984             : 
     985             :     // local privacy addresses - don't advertise to clearnet peers
     986           1 :     AddLocal(addr_onion);
     987           1 :     AddLocal(addr_i2p);
     988           1 :     BOOST_CHECK(!GetLocalAddress(*peer_ipv4).IsValid());
     989           1 :     BOOST_CHECK(!GetLocalAddress(*peer_ipv6).IsValid());
     990           1 :     BOOST_CHECK(!GetLocalAddress(*peer_ipv6_tunnel).IsValid());
     991           1 :     BOOST_CHECK(!GetLocalAddress(*peer_teredo).IsValid());
     992           1 :     BOOST_CHECK(!GetLocalAddress(*peer_cjdns).IsValid());
     993           1 :     BOOST_CHECK(GetLocalAddress(*peer_onion) == addr_onion);
     994           1 :     BOOST_CHECK(GetLocalAddress(*peer_i2p) == addr_i2p);
     995           1 :     RemoveLocal(addr_onion);
     996           1 :     RemoveLocal(addr_i2p);
     997             : 
     998             :     // local addresses from all networks
     999           1 :     AddLocal(addr_ipv4);
    1000           1 :     AddLocal(addr_ipv6);
    1001           1 :     AddLocal(addr_ipv6_tunnel);
    1002           1 :     AddLocal(addr_teredo);
    1003           1 :     AddLocal(addr_onion);
    1004           1 :     AddLocal(addr_i2p);
    1005           1 :     AddLocal(addr_cjdns);
    1006           1 :     BOOST_CHECK(GetLocalAddress(*peer_ipv4) == addr_ipv4);
    1007           1 :     BOOST_CHECK(GetLocalAddress(*peer_ipv6) == addr_ipv6);
    1008           1 :     BOOST_CHECK(GetLocalAddress(*peer_ipv6_tunnel) == addr_ipv6);
    1009           1 :     BOOST_CHECK(GetLocalAddress(*peer_teredo) == addr_ipv4);
    1010           1 :     BOOST_CHECK(GetLocalAddress(*peer_onion) == addr_onion);
    1011           1 :     BOOST_CHECK(GetLocalAddress(*peer_i2p) == addr_i2p);
    1012           1 :     BOOST_CHECK(GetLocalAddress(*peer_cjdns) == addr_cjdns);
    1013           1 :     RemoveLocal(addr_ipv4);
    1014           1 :     RemoveLocal(addr_ipv6);
    1015           1 :     RemoveLocal(addr_ipv6_tunnel);
    1016           1 :     RemoveLocal(addr_teredo);
    1017           1 :     RemoveLocal(addr_onion);
    1018           1 :     RemoveLocal(addr_i2p);
    1019           1 :     RemoveLocal(addr_cjdns);
    1020           1 : }
    1021             : 
    1022             : namespace {
    1023             : 
    1024          78 : CKey GenerateRandomTestKey() noexcept
    1025             : {
    1026          78 :     CKey key;
    1027          78 :     uint256 key_data = InsecureRand256();
    1028          78 :     key.Set(key_data.begin(), key_data.end(), true);
    1029          78 :     return key;
    1030          78 : }
    1031             : 
    1032             : /** A class for scenario-based tests of V2Transport
    1033             :  *
    1034             :  * Each V2TransportTester encapsulates a V2Transport (the one being tested), and can be told to
    1035             :  * interact with it. To do so, it also encapsulates a BIP324Cipher to act as the other side. A
    1036             :  * second V2Transport is not used, as doing so would not permit scenarios that involve sending
    1037             :  * invalid data, or ones using BIP324 features that are not implemented on the sending
    1038             :  * side (like decoy packets).
    1039             :  */
    1040             : class V2TransportTester
    1041             : {
    1042             :     V2Transport m_transport; //!< V2Transport being tested
    1043             :     BIP324Cipher m_cipher; //!< Cipher to help with the other side
    1044             :     bool m_test_initiator; //!< Whether m_transport is the initiator (true) or responder (false)
    1045             : 
    1046             :     std::vector<uint8_t> m_sent_garbage; //!< The garbage we've sent to m_transport.
    1047             :     std::vector<uint8_t> m_recv_garbage; //!< The garbage we've received from m_transport.
    1048             :     std::vector<uint8_t> m_to_send; //!< Bytes we have queued up to send to m_transport.
    1049             :     std::vector<uint8_t> m_received; //!< Bytes we have received from m_transport.
    1050             :     std::deque<CSerializedNetMsg> m_msg_to_send; //!< Messages to be sent *by* m_transport to us.
    1051          78 :     bool m_sent_aad{false};
    1052             : 
    1053             : public:
    1054             :     /** Construct a tester object. test_initiator: whether the tested transport is initiator. */
    1055         156 :     V2TransportTester(bool test_initiator) :
    1056          78 :         m_transport(0, test_initiator, SER_NETWORK, INIT_PROTO_VERSION),
    1057          78 :         m_cipher{GenerateRandomTestKey(), MakeByteSpan(InsecureRand256())},
    1058          78 :         m_test_initiator(test_initiator)
    1059          78 :     {
    1060             :         // Set peer version for v2 short ID negotiation
    1061          78 :         m_transport.SetPeerVersion(PROTOCOL_VERSION);
    1062         156 :     }
    1063             : 
    1064             :     /** Data type returned by Interact:
    1065             :      *
    1066             :      * - std::nullopt: transport error occurred
    1067             :      * - otherwise: a vector of
    1068             :      *   - std::nullopt: invalid message received
    1069             :      *   - otherwise: a CNetMessage retrieved
    1070             :      */
    1071             :     using InteractResult = std::optional<std::vector<std::optional<CNetMessage>>>;
    1072             : 
    1073             :     /** Send/receive scheduled/available bytes and messages.
    1074             :      *
    1075             :      * This is the only function that interacts with the transport being tested; everything else is
    1076             :      * scheduling things done by Interact(), or processing things learned by it.
    1077             :      */
    1078         248 :     InteractResult Interact()
    1079             :     {
    1080         248 :         std::vector<std::optional<CNetMessage>> ret;
    1081        2964 :         while (true) {
    1082        2964 :             bool progress{false};
    1083             :             // Send bytes from m_to_send to the transport.
    1084        2964 :             if (!m_to_send.empty()) {
    1085        2168 :                 Span<const uint8_t> to_send = Span{m_to_send}.first(1 + InsecureRandRange(m_to_send.size()));
    1086        2168 :                 size_t old_len = to_send.size();
    1087        2168 :                 if (!m_transport.ReceivedBytes(to_send)) {
    1088          23 :                     return std::nullopt; // transport error occurred
    1089             :                 }
    1090        2145 :                 if (old_len != to_send.size()) {
    1091        2054 :                     progress = true;
    1092        2054 :                     m_to_send.erase(m_to_send.begin(), m_to_send.begin() + (old_len - to_send.size()));
    1093        2054 :                 }
    1094        2145 :             }
    1095             :             // Retrieve messages received by the transport.
    1096        2941 :             if (m_transport.ReceivedMessageComplete() && (!progress || InsecureRandBool())) {
    1097         252 :                 bool reject{false};
    1098         252 :                 auto msg = m_transport.GetReceivedMessage({}, reject);
    1099         252 :                 if (reject) {
    1100          61 :                     ret.emplace_back(std::nullopt);
    1101          61 :                 } else {
    1102         191 :                     ret.emplace_back(std::move(msg));
    1103             :                 }
    1104         252 :                 progress = true;
    1105         252 :             }
    1106             :             // Enqueue a message to be sent by the transport to us.
    1107        2941 :             if (!m_msg_to_send.empty() && (!progress || InsecureRandBool())) {
    1108          54 :                 if (m_transport.SetMessageToSend(m_msg_to_send.front())) {
    1109          54 :                     m_msg_to_send.pop_front();
    1110          54 :                     progress = true;
    1111          54 :                 }
    1112          54 :             }
    1113             :             // Receive bytes from the transport.
    1114        3959 :             const auto& [recv_bytes, _more, _msg_type] = m_transport.GetBytesToSend(!m_msg_to_send.empty());
    1115        2941 :             if (!recv_bytes.empty() && (!progress || InsecureRandBool())) {
    1116        1018 :                 size_t to_receive = 1 + InsecureRandRange(recv_bytes.size());
    1117        3054 :                 m_received.insert(m_received.end(), recv_bytes.begin(), recv_bytes.begin() + to_receive);
    1118        1018 :                 progress = true;
    1119        1018 :                 m_transport.MarkBytesSent(to_receive);
    1120        1018 :             }
    1121        2941 :             if (!progress) break;
    1122             :         }
    1123         225 :         return ret;
    1124         248 :     }
    1125             : 
    1126             :     /** Expose the cipher. */
    1127           1 :     BIP324Cipher& GetCipher() { return m_cipher; }
    1128             : 
    1129             :     /** Expose the transport. */
    1130           2 :     V2Transport& GetTransport() { return m_transport; }
    1131             : 
    1132             :     /** Schedule bytes to be sent to the transport. */
    1133       49362 :     void Send(Span<const uint8_t> data)
    1134             :     {
    1135       49362 :         m_to_send.insert(m_to_send.end(), data.begin(), data.end());
    1136       49362 :     }
    1137             : 
    1138             :     /** Send V1 version message header to the transport. */
    1139           2 :     void SendV1Version(const CMessageHeader::MessageStartChars& magic)
    1140             :     {
    1141           2 :         CMessageHeader hdr(magic, "version", 126 + InsecureRandRange(11));
    1142           2 :         CDataStream ser(SER_NETWORK, CLIENT_VERSION);
    1143           2 :         ser << hdr;
    1144           2 :         m_to_send.insert(m_to_send.end(), UCharCast(ser.data()), UCharCast(ser.data() + ser.size()));
    1145           2 :     }
    1146             : 
    1147             :     /** Schedule bytes to be sent to the transport. */
    1148       49286 :     void Send(Span<const std::byte> data) { Send(MakeUCharSpan(data)); }
    1149             : 
    1150             :     /** Schedule our ellswift key to be sent to the transport. */
    1151          76 :     void SendKey() { Send(m_cipher.GetOurPubKey()); }
    1152             : 
    1153             :     /** Schedule specified garbage to be sent to the transport. */
    1154          76 :     void SendGarbage(Span<const uint8_t> garbage)
    1155             :     {
    1156             :         // Remember the specified garbage (so we can use it as AAD).
    1157          76 :         m_sent_garbage.assign(garbage.begin(), garbage.end());
    1158             :         // Schedule it for sending.
    1159          76 :         Send(m_sent_garbage);
    1160          76 :     }
    1161             : 
    1162             :     /** Schedule garbage (of specified length) to be sent to the transport. */
    1163          75 :     void SendGarbage(size_t garbage_len)
    1164             :     {
    1165             :         // Generate random garbage and send it.
    1166          75 :         SendGarbage(g_insecure_rand_ctx.randbytes<uint8_t>(garbage_len));
    1167          75 :     }
    1168             : 
    1169             :     /** Schedule garbage (with valid random length) to be sent to the transport. */
    1170          23 :     void SendGarbage()
    1171             :     {
    1172          23 :          SendGarbage(InsecureRandRange(V2Transport::MAX_GARBAGE_LEN + 1));
    1173          23 :     }
    1174             : 
    1175             :     /** Schedule a message to be sent to us by the transport. */
    1176          54 :     void AddMessage(std::string m_type, std::vector<uint8_t> payload)
    1177             :     {
    1178          54 :         CSerializedNetMsg msg;
    1179          54 :         msg.m_type = std::move(m_type);
    1180          54 :         msg.data = std::move(payload);
    1181          54 :         m_msg_to_send.push_back(std::move(msg));
    1182          54 :     }
    1183             : 
    1184             :     /** Expect ellswift key to have been received from transport and process it.
    1185             :      *
    1186             :      * Many other V2TransportTester functions cannot be called until after ReceiveKey() has been
    1187             :      * called, as no encryption keys are set up before that point.
    1188             :      */
    1189          76 :     void ReceiveKey()
    1190             :     {
    1191             :         // When processing a key, enough bytes need to have been received already.
    1192          76 :         BOOST_REQUIRE(m_received.size() >= EllSwiftPubKey::size());
    1193             :         // Initialize the cipher using it (acting as the opposite side of the tested transport).
    1194          76 :         m_cipher.Initialize(MakeByteSpan(m_received).first(EllSwiftPubKey::size()), !m_test_initiator);
    1195             :         // Strip the processed bytes off the front of the receive buffer.
    1196          76 :         m_received.erase(m_received.begin(), m_received.begin() + EllSwiftPubKey::size());
    1197          76 :     }
    1198             : 
    1199             :     /** Schedule an encrypted packet with specified content/aad/ignore to be sent to transport
    1200             :      *  (only after ReceiveKey). */
    1201       49134 :     void SendPacket(Span<const uint8_t> content, Span<const uint8_t> aad = {}, bool ignore = false)
    1202             :     {
    1203             :         // Use cipher to construct ciphertext.
    1204       49134 :         std::vector<std::byte> ciphertext;
    1205       49134 :         ciphertext.resize(content.size() + BIP324Cipher::EXPANSION);
    1206       49134 :         m_cipher.Encrypt(
    1207       49134 :             /*contents=*/MakeByteSpan(content),
    1208       49134 :             /*aad=*/MakeByteSpan(aad),
    1209       49134 :             /*ignore=*/ignore,
    1210       49134 :             /*output=*/ciphertext);
    1211             :         // Schedule it for sending.
    1212       49134 :         Send(ciphertext);
    1213       49134 :     }
    1214             : 
    1215             :     /** Schedule garbage terminator to be sent to the transport (only after ReceiveKey). */
    1216          76 :     void SendGarbageTerm()
    1217             :     {
    1218             :         // Schedule the garbage terminator to be sent.
    1219          76 :         Send(m_cipher.GetSendGarbageTerminator());
    1220          76 :     }
    1221             : 
    1222             :     /** Schedule version packet to be sent to the transport (only after ReceiveKey). */
    1223         290 :     void SendVersion(Span<const uint8_t> version_data = {}, bool vers_ignore = false)
    1224             :     {
    1225         290 :         Span<const std::uint8_t> aad;
    1226             :         // Set AAD to garbage only for first packet.
    1227         290 :         if (!m_sent_aad) aad = m_sent_garbage;
    1228         290 :         SendPacket(/*content=*/version_data, /*aad=*/aad, /*ignore=*/vers_ignore);
    1229         290 :         m_sent_aad = true;
    1230         290 :     }
    1231             : 
    1232             :     /** Expect a packet to have been received from transport, process it, and return its contents
    1233             :      *  (only after ReceiveKey). Decoys are skipped. Optional associated authenticated data (AAD) is
    1234             :      *  expected in the first received packet, no matter if that is a decoy or not. */
    1235         128 :     std::vector<uint8_t> ReceivePacket(Span<const std::byte> aad = {})
    1236             :     {
    1237         128 :         std::vector<uint8_t> contents;
    1238             :         // Loop as long as there are ignored packets that are to be skipped.
    1239         128 :         while (true) {
    1240             :             // When processing a packet, at least enough bytes for its length descriptor must be received.
    1241         128 :             BOOST_REQUIRE(m_received.size() >= BIP324Cipher::LENGTH_LEN);
    1242             :             // Decrypt the content length.
    1243         128 :             size_t size = m_cipher.DecryptLength(MakeByteSpan(Span{m_received}.first(BIP324Cipher::LENGTH_LEN)));
    1244             :             // Check that the full packet is in the receive buffer.
    1245         128 :             BOOST_REQUIRE(m_received.size() >= size + BIP324Cipher::EXPANSION);
    1246             :             // Decrypt the packet contents.
    1247         128 :             contents.resize(size);
    1248         128 :             bool ignore{false};
    1249         128 :             bool ret = m_cipher.Decrypt(
    1250         128 :                 /*input=*/MakeByteSpan(
    1251         128 :                     Span{m_received}.first(size + BIP324Cipher::EXPANSION).subspan(BIP324Cipher::LENGTH_LEN)),
    1252         128 :                 /*aad=*/aad,
    1253             :                 /*ignore=*/ignore,
    1254         128 :                 /*contents=*/MakeWritableByteSpan(contents));
    1255         128 :             BOOST_CHECK(ret);
    1256             :             // Don't expect AAD in further packets.
    1257         128 :             aad = {};
    1258             :             // Strip the processed packet's bytes off the front of the receive buffer.
    1259         128 :             m_received.erase(m_received.begin(), m_received.begin() + size + BIP324Cipher::EXPANSION);
    1260             :             // Stop if the ignore bit is not set on this packet.
    1261         128 :             if (!ignore) break;
    1262             :         }
    1263         128 :         return contents;
    1264         128 :     }
    1265             : 
    1266             :     /** Expect garbage and garbage terminator to have been received, and process them (only after
    1267             :      *  ReceiveKey). */
    1268          74 :     void ReceiveGarbage()
    1269             :     {
    1270             :         // Figure out the garbage length.
    1271             :         size_t garblen;
    1272      151202 :         for (garblen = 0; garblen <= V2Transport::MAX_GARBAGE_LEN; ++garblen) {
    1273      151202 :             BOOST_REQUIRE(m_received.size() >= garblen + BIP324Cipher::GARBAGE_TERMINATOR_LEN);
    1274      151202 :             auto term_span = MakeByteSpan(Span{m_received}.subspan(garblen, BIP324Cipher::GARBAGE_TERMINATOR_LEN));
    1275      151202 :             if (term_span == m_cipher.GetReceiveGarbageTerminator()) break;
    1276      151128 :         }
    1277             :         // Copy the garbage to a buffer.
    1278          74 :         m_recv_garbage.assign(m_received.begin(), m_received.begin() + garblen);
    1279             :         // Strip garbage + garbage terminator off the front of the receive buffer.
    1280          74 :         m_received.erase(m_received.begin(), m_received.begin() + garblen + BIP324Cipher::GARBAGE_TERMINATOR_LEN);
    1281          74 :     }
    1282             : 
    1283             :     /** Expect version packet to have been received, and process it (only after ReceiveKey). */
    1284          74 :     void ReceiveVersion()
    1285             :     {
    1286          74 :         auto contents = ReceivePacket(/*aad=*/MakeByteSpan(m_recv_garbage));
    1287             :         // Version packets from real BIP324 peers are expected to be empty, despite the fact that
    1288             :         // this class supports *sending* non-empty version packets (to test that BIP324 peers
    1289             :         // correctly ignore version packet contents).
    1290          74 :         BOOST_CHECK(contents.empty());
    1291          74 :     }
    1292             : 
    1293             :     /** Expect application packet to have been received, with specified short id and payload.
    1294             :      *  (only after ReceiveKey). */
    1295           3 :     void ReceiveMessage(uint8_t short_id, Span<const uint8_t> payload)
    1296             :     {
    1297           3 :         auto ret = ReceivePacket();
    1298           3 :         BOOST_CHECK(ret.size() == payload.size() + 1);
    1299           3 :         BOOST_CHECK(ret[0] == short_id);
    1300           3 :         BOOST_CHECK(Span{ret}.subspan(1) == payload);
    1301           3 :     }
    1302             : 
    1303             :     /** Expect application packet to have been received, with specified 12-char message type and
    1304             :      *  payload (only after ReceiveKey). */
    1305          51 :     void ReceiveMessage(const std::string& m_type, Span<const uint8_t> payload)
    1306             :     {
    1307          51 :         auto ret = ReceivePacket();
    1308          51 :         BOOST_REQUIRE(ret.size() == payload.size() + 1 + CMessageHeader::COMMAND_SIZE);
    1309          51 :         BOOST_CHECK(ret[0] == 0);
    1310         663 :         for (unsigned i = 0; i < 12; ++i) {
    1311         612 :             if (i < m_type.size()) {
    1312         311 :                 BOOST_CHECK(ret[1 + i] == m_type[i]);
    1313         311 :             } else {
    1314         301 :                 BOOST_CHECK(ret[1 + i] == 0);
    1315             :             }
    1316         612 :         }
    1317          51 :         BOOST_CHECK(Span{ret}.subspan(1 + CMessageHeader::COMMAND_SIZE) == payload);
    1318          51 :     }
    1319             : 
    1320             :     /** Schedule an encrypted packet with specified message type and payload to be sent to
    1321             :      *  transport (only after ReceiveKey). */
    1322         120 :     void SendMessage(std::string mtype, Span<const uint8_t> payload)
    1323             :     {
    1324             :         // Construct contents consisting of 0x00 + 12-byte message type + payload.
    1325         120 :         std::vector<uint8_t> contents(1 + CMessageHeader::COMMAND_SIZE + payload.size());
    1326         120 :         std::copy(mtype.begin(), mtype.end(), reinterpret_cast<char*>(contents.data() + 1));
    1327         120 :         std::copy(payload.begin(), payload.end(), contents.begin() + 1 + CMessageHeader::COMMAND_SIZE);
    1328             :         // Send a packet with that as contents.
    1329         120 :         SendPacket(contents);
    1330         120 :     }
    1331             : 
    1332             :     /** Schedule an encrypted packet with specified short message id and payload to be sent to
    1333             :      *  transport (only after ReceiveKey). */
    1334         152 :     void SendMessage(uint8_t short_id, Span<const uint8_t> payload)
    1335             :     {
    1336             :         // Construct contents consisting of short_id + payload.
    1337         152 :         std::vector<uint8_t> contents(1 + payload.size());
    1338         152 :         contents[0] = short_id;
    1339         152 :         std::copy(payload.begin(), payload.end(), contents.begin() + 1);
    1340             :         // Send a packet with that as contents.
    1341         152 :         SendPacket(contents);
    1342         152 :     }
    1343             : 
    1344             :     /** Test whether the transport's session ID matches the session ID we expect. */
    1345          71 :     void CompareSessionIDs() const
    1346             :     {
    1347          71 :         auto info = m_transport.GetInfo();
    1348          71 :         BOOST_CHECK(info.session_id);
    1349          71 :         BOOST_CHECK(uint256(MakeUCharSpan(m_cipher.GetSessionID())) == *info.session_id);
    1350          71 :     }
    1351             : 
    1352             :     /** Introduce a bit error in the data scheduled to be sent. */
    1353          10 :     void Damage()
    1354             :     {
    1355          10 :         m_to_send[InsecureRandRange(m_to_send.size())] ^= (uint8_t{1} << InsecureRandRange(8));
    1356          10 :     }
    1357             : };
    1358             : 
    1359             : } // namespace
    1360             : 
    1361         149 : BOOST_AUTO_TEST_CASE(v2transport_test)
    1362             : {
    1363             :     // A mostly normal scenario, testing a transport in initiator mode.
    1364          11 :     for (int i = 0; i < 10; ++i) {
    1365          10 :         V2TransportTester tester(true);
    1366          10 :         auto ret = tester.Interact();
    1367          10 :         BOOST_REQUIRE(ret && ret->empty());
    1368          10 :         tester.SendKey();
    1369          10 :         tester.SendGarbage();
    1370          10 :         tester.ReceiveKey();
    1371          10 :         tester.SendGarbageTerm();
    1372          10 :         tester.SendVersion();
    1373          10 :         ret = tester.Interact();
    1374          10 :         BOOST_REQUIRE(ret && ret->empty());
    1375          10 :         tester.ReceiveGarbage();
    1376          10 :         tester.ReceiveVersion();
    1377          10 :         tester.CompareSessionIDs();
    1378          10 :         auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000));
    1379          10 :         auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000));
    1380          10 :         tester.SendMessage(uint8_t(4), msg_data_1); // cmpctblock short id
    1381          10 :         tester.SendMessage(0, {}); // Invalidly encoded message
    1382          10 :         tester.SendMessage("tx", msg_data_2); // 12-character encoded message type
    1383          10 :         ret = tester.Interact();
    1384          10 :         BOOST_REQUIRE(ret && ret->size() == 3);
    1385          10 :         BOOST_CHECK((*ret)[0] && (*ret)[0]->m_type == "cmpctblock" && Span{(*ret)[0]->m_recv} == MakeByteSpan(msg_data_1));
    1386          10 :         BOOST_CHECK(!(*ret)[1]);
    1387          10 :         BOOST_CHECK((*ret)[2] && (*ret)[2]->m_type == "tx" && Span{(*ret)[2]->m_recv} == MakeByteSpan(msg_data_2));
    1388             : 
    1389             :         // Then send a message with a bit error, expecting failure. It's possible this failure does
    1390             :         // not occur immediately (when the length descriptor was modified), but it should come
    1391             :         // eventually, and no messages can be delivered anymore.
    1392          10 :         tester.SendMessage("bad", msg_data_1);
    1393          10 :         tester.Damage();
    1394          10 :         while (true) {
    1395          10 :             ret = tester.Interact();
    1396          10 :             if (!ret) break; // failure
    1397           0 :             BOOST_CHECK(ret->size() == 0); // no message can be delivered
    1398             :             // Send another message.
    1399           0 :             auto msg_data_3 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(10000));
    1400           0 :             tester.SendMessage(uint8_t(12), msg_data_3); // getheaders short id
    1401           0 :         }
    1402          10 :     }
    1403             : 
    1404             :     // Normal scenario, with a transport in responder node.
    1405          11 :     for (int i = 0; i < 10; ++i) {
    1406          10 :         V2TransportTester tester(false);
    1407          10 :         tester.SendKey();
    1408          10 :         tester.SendGarbage();
    1409          10 :         auto ret = tester.Interact();
    1410          10 :         BOOST_REQUIRE(ret && ret->empty());
    1411          10 :         tester.ReceiveKey();
    1412          10 :         tester.SendGarbageTerm();
    1413          10 :         tester.SendVersion();
    1414          10 :         ret = tester.Interact();
    1415          10 :         BOOST_REQUIRE(ret && ret->empty());
    1416          10 :         tester.ReceiveGarbage();
    1417          10 :         tester.ReceiveVersion();
    1418          10 :         tester.CompareSessionIDs();
    1419          10 :         auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000));
    1420          10 :         auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000));
    1421          10 :         tester.SendMessage(uint8_t(14), msg_data_1); // inv short id
    1422          10 :         tester.SendMessage(uint8_t(19), msg_data_2); // pong short id
    1423          10 :         ret = tester.Interact();
    1424          10 :         BOOST_REQUIRE(ret && ret->size() == 2);
    1425          10 :         BOOST_CHECK((*ret)[0] && (*ret)[0]->m_type == "inv" && Span{(*ret)[0]->m_recv} == MakeByteSpan(msg_data_1));
    1426          10 :         BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "pong" && Span{(*ret)[1]->m_recv} == MakeByteSpan(msg_data_2));
    1427             : 
    1428             :         // Then send a too-large message.
    1429          10 :         auto msg_data_3 = g_insecure_rand_ctx.randbytes<uint8_t>(4005000);
    1430          10 :         tester.SendMessage(uint8_t(11), msg_data_3); // getdata short id
    1431          10 :         ret = tester.Interact();
    1432          10 :         BOOST_CHECK(!ret);
    1433          10 :     }
    1434             : 
    1435             :     // Various valid but unusual scenarios.
    1436          51 :     for (int i = 0; i < 50; ++i) {
    1437             :         /** Whether an initiator or responder is being tested. */
    1438          50 :         bool initiator = InsecureRandBool();
    1439             :         /** Use either 0 bytes or the maximum possible (4095 bytes) garbage length. */
    1440          50 :         size_t garb_len = InsecureRandBool() ? 0 : V2Transport::MAX_GARBAGE_LEN;
    1441             :         /** How many decoy packets to send before the version packet. */
    1442          50 :         unsigned num_ignore_version = InsecureRandRange(10);
    1443             :         /** What data to send in the version packet (ignored by BIP324 peers, but reserved for future extensions). */
    1444          50 :         auto ver_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandBool() ? 0 : InsecureRandRange(1000));
    1445             :         /** Whether to immediately send key and garbage out (required for responders, optional otherwise). */
    1446          50 :         bool send_immediately = !initiator || InsecureRandBool();
    1447             :         /** How many decoy packets to send before the first and second real message. */
    1448          50 :         unsigned num_decoys_1 = InsecureRandRange(1000), num_decoys_2 = InsecureRandRange(1000);
    1449          50 :         V2TransportTester tester(initiator);
    1450          50 :         if (send_immediately) {
    1451          34 :             tester.SendKey();
    1452          34 :             tester.SendGarbage(garb_len);
    1453          34 :         }
    1454          50 :         auto ret = tester.Interact();
    1455          50 :         BOOST_REQUIRE(ret && ret->empty());
    1456          50 :         if (!send_immediately) {
    1457          16 :             tester.SendKey();
    1458          16 :             tester.SendGarbage(garb_len);
    1459          16 :         }
    1460          50 :         tester.ReceiveKey();
    1461          50 :         tester.SendGarbageTerm();
    1462         266 :         for (unsigned v = 0; v < num_ignore_version; ++v) {
    1463         216 :             size_t ver_ign_data_len = InsecureRandBool() ? 0 : InsecureRandRange(1000);
    1464         216 :             auto ver_ign_data = g_insecure_rand_ctx.randbytes<uint8_t>(ver_ign_data_len);
    1465         216 :             tester.SendVersion(ver_ign_data, true);
    1466         216 :         }
    1467          50 :         tester.SendVersion(ver_data, false);
    1468          50 :         ret = tester.Interact();
    1469          50 :         BOOST_REQUIRE(ret && ret->empty());
    1470          50 :         tester.ReceiveGarbage();
    1471          50 :         tester.ReceiveVersion();
    1472          50 :         tester.CompareSessionIDs();
    1473       23650 :         for (unsigned d = 0; d < num_decoys_1; ++d) {
    1474       23600 :             auto decoy_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000));
    1475       23600 :             tester.SendPacket(/*content=*/decoy_data, /*aad=*/{}, /*ignore=*/true);
    1476       23600 :         }
    1477          50 :         auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(MAX_PROTOCOL_MESSAGE_LENGTH));
    1478          50 :         tester.SendMessage(uint8_t(28), msg_data_1);
    1479       25022 :         for (unsigned d = 0; d < num_decoys_2; ++d) {
    1480       24972 :             auto decoy_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000));
    1481       24972 :             tester.SendPacket(/*content=*/decoy_data, /*aad=*/{}, /*ignore=*/true);
    1482       24972 :         }
    1483          50 :         auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000));
    1484          50 :         tester.SendMessage(uint8_t(13), msg_data_2); // headers short id
    1485             :         // Send invalidly-encoded message
    1486          50 :         tester.SendMessage(std::string("blocktxn\x00\x00\x00a", CMessageHeader::COMMAND_SIZE), {});
    1487          50 :         tester.SendMessage("foobar", {}); // test receiving unknown message type
    1488          50 :         tester.AddMessage("barfoo", {}); // test sending unknown message type
    1489          50 :         ret = tester.Interact();
    1490          50 :         BOOST_REQUIRE(ret && ret->size() == 4);
    1491          50 :         BOOST_CHECK((*ret)[0] && (*ret)[0]->m_type == "addrv2" && Span{(*ret)[0]->m_recv} == MakeByteSpan(msg_data_1));
    1492          50 :         BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "headers" && Span{(*ret)[1]->m_recv} == MakeByteSpan(msg_data_2));
    1493          50 :         BOOST_CHECK(!(*ret)[2]);
    1494         100 :         BOOST_CHECK((*ret)[3] && (*ret)[3]->m_type == "foobar" && (*ret)[3]->m_recv.empty());
    1495          50 :         tester.ReceiveMessage("barfoo", {});
    1496          50 :     }
    1497             : 
    1498             :     // Too long garbage (initiator).
    1499             :     {
    1500           1 :         V2TransportTester tester(true);
    1501           1 :         auto ret = tester.Interact();
    1502           1 :         BOOST_REQUIRE(ret && ret->empty());
    1503           1 :         tester.SendKey();
    1504           1 :         tester.SendGarbage(V2Transport::MAX_GARBAGE_LEN + 1);
    1505           1 :         tester.ReceiveKey();
    1506           1 :         tester.SendGarbageTerm();
    1507           1 :         ret = tester.Interact();
    1508           1 :         BOOST_CHECK(!ret);
    1509           1 :     }
    1510             : 
    1511             :     // Too long garbage (responder).
    1512             :     {
    1513           1 :         V2TransportTester tester(false);
    1514           1 :         tester.SendKey();
    1515           1 :         tester.SendGarbage(V2Transport::MAX_GARBAGE_LEN + 1);
    1516           1 :         auto ret = tester.Interact();
    1517           1 :         BOOST_REQUIRE(ret && ret->empty());
    1518           1 :         tester.ReceiveKey();
    1519           1 :         tester.SendGarbageTerm();
    1520           1 :         ret = tester.Interact();
    1521           1 :         BOOST_CHECK(!ret);
    1522           1 :     }
    1523             : 
    1524             :     // Send garbage that includes the first 15 garbage terminator bytes somewhere.
    1525             :     {
    1526           1 :         V2TransportTester tester(true);
    1527           1 :         auto ret = tester.Interact();
    1528           1 :         BOOST_REQUIRE(ret && ret->empty());
    1529           1 :         tester.SendKey();
    1530           1 :         tester.ReceiveKey();
    1531             :         /** The number of random garbage bytes before the included first 15 bytes of terminator. */
    1532           1 :         size_t len_before = InsecureRandRange(V2Transport::MAX_GARBAGE_LEN - 16 + 1);
    1533             :         /** The number of random garbage bytes after it. */
    1534           1 :         size_t len_after = InsecureRandRange(V2Transport::MAX_GARBAGE_LEN - 16 - len_before + 1);
    1535             :         // Construct len_before + 16 + len_after random bytes.
    1536           1 :         auto garbage = g_insecure_rand_ctx.randbytes<uint8_t>(len_before + 16 + len_after);
    1537             :         // Replace the designed 16 bytes in the middle with the to-be-sent garbage terminator.
    1538           1 :         auto garb_term = MakeUCharSpan(tester.GetCipher().GetSendGarbageTerminator());
    1539           1 :         std::copy(garb_term.begin(), garb_term.begin() + 16, garbage.begin() + len_before);
    1540             :         // Introduce a bit error in the last byte of that copied garbage terminator, making only
    1541             :         // the first 15 of them match.
    1542           1 :         garbage[len_before + 15] ^= (uint8_t(1) << InsecureRandRange(8));
    1543           1 :         tester.SendGarbage(garbage);
    1544           1 :         tester.SendGarbageTerm();
    1545           1 :         tester.SendVersion();
    1546           1 :         ret = tester.Interact();
    1547           1 :         BOOST_REQUIRE(ret && ret->empty());
    1548           1 :         tester.ReceiveGarbage();
    1549           1 :         tester.ReceiveVersion();
    1550           1 :         tester.CompareSessionIDs();
    1551           1 :         auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(MAX_PROTOCOL_MESSAGE_LENGTH); // test that receiving max size payload works
    1552           1 :         auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(MAX_PROTOCOL_MESSAGE_LENGTH); // test that sending max size payload works
    1553             :         // Send an unknown/invalid short ID. Valid Bitcoin IDs are [0, V2_BITCOIN_IDS.size()-1],
    1554             :         // valid Dash IDs are [128, 128+V2_DASH_IDS.size()-1]. Generate IDs outside these ranges.
    1555           2 :         tester.SendMessage([]() {
    1556           1 :             if (g_insecure_rand_ctx.randbool()) {
    1557           1 :                 return static_cast<uint8_t>(InsecureRandRange(95) + 33); // Invalid Bitcoin range [33, 127]
    1558             :             } else {
    1559           0 :                 return static_cast<uint8_t>(InsecureRandRange(87) + 169); // Invalid Dash range [169, 255]
    1560             :             }
    1561           2 :         }(), {});
    1562           1 :         tester.SendMessage(uint8_t(2), msg_data_1); // "block" short id
    1563           1 :         tester.AddMessage("blocktxn", msg_data_2); // schedule blocktxn to be sent to us
    1564           1 :         ret = tester.Interact();
    1565           1 :         BOOST_REQUIRE(ret && ret->size() == 2);
    1566           1 :         BOOST_CHECK(!(*ret)[0]);
    1567           1 :         BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "block" && Span{(*ret)[1]->m_recv} == MakeByteSpan(msg_data_1));
    1568           1 :         tester.ReceiveMessage(uint8_t(3), msg_data_2); // "blocktxn" short id
    1569           1 :     }
    1570             : 
    1571             :     // Send correct network's V1 header
    1572             :     {
    1573           1 :         V2TransportTester tester(false);
    1574           1 :         tester.SendV1Version(Params().MessageStart());
    1575           1 :         auto ret = tester.Interact();
    1576           1 :         BOOST_CHECK(ret);
    1577           1 :     }
    1578             : 
    1579             :     // Send wrong network's V1 header
    1580             :     {
    1581           1 :         V2TransportTester tester(false);
    1582           1 :         tester.SendV1Version(CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->MessageStart());
    1583           1 :         auto ret = tester.Interact();
    1584           1 :         BOOST_CHECK(!ret);
    1585           1 :     }
    1586           1 : }
    1587             : 
    1588         149 : BOOST_AUTO_TEST_CASE(v2_short_id_version_negotiation)
    1589             : {
    1590             :     // Test that v2 short ID encoding respects peer protocol version.
    1591             :     // This ensures backwards compatibility when adding new short IDs.
    1592             : 
    1593             :     // Test 1: Baseline messages (short IDs 0-167) work with any v2-capable peer
    1594             :     {
    1595           1 :         V2TransportTester tester(true);
    1596           1 :         tester.GetTransport().SetPeerVersion(BIP324_DASH_BASELINE_VERSION); // v70235
    1597             : 
    1598           1 :         auto ret = tester.Interact();
    1599           1 :         BOOST_REQUIRE(ret && ret->empty());
    1600           1 :         tester.SendKey();
    1601           1 :         tester.SendGarbage();
    1602           1 :         tester.ReceiveKey();
    1603           1 :         tester.SendGarbageTerm();
    1604           1 :         tester.SendVersion();
    1605           1 :         ret = tester.Interact();
    1606           1 :         BOOST_REQUIRE(ret && ret->empty());
    1607           1 :         tester.ReceiveGarbage();
    1608           1 :         tester.ReceiveVersion();
    1609             : 
    1610             :         // SPORK (short ID 128) should use short encoding
    1611           1 :         auto msg_data = g_insecure_rand_ctx.randbytes<uint8_t>(100);
    1612           1 :         tester.AddMessage("spork", msg_data);
    1613           1 :         ret = tester.Interact();
    1614           1 :         BOOST_REQUIRE(ret && ret->empty());
    1615           1 :         tester.ReceiveMessage(uint8_t(128), msg_data);
    1616           1 :     }
    1617             : 
    1618             :     // Test 2: New short IDs (168+) require version negotiation
    1619             :     {
    1620             :         // Old peer (v70238) - doesn't know about PLATFORMBAN short ID 168
    1621           1 :         V2TransportTester tester_old(true);
    1622           1 :         tester_old.GetTransport().SetPeerVersion(70238);
    1623             : 
    1624           1 :         auto ret = tester_old.Interact();
    1625           1 :         BOOST_REQUIRE(ret && ret->empty());
    1626           1 :         tester_old.SendKey();
    1627           1 :         tester_old.SendGarbage();
    1628           1 :         tester_old.ReceiveKey();
    1629           1 :         tester_old.SendGarbageTerm();
    1630           1 :         tester_old.SendVersion();
    1631           1 :         ret = tester_old.Interact();
    1632           1 :         BOOST_REQUIRE(ret && ret->empty());
    1633           1 :         tester_old.ReceiveGarbage();
    1634           1 :         tester_old.ReceiveVersion();
    1635             : 
    1636             :         // Old peer gets long encoding for PLATFORMBAN
    1637           1 :         auto msg_data_old = g_insecure_rand_ctx.randbytes<uint8_t>(100);
    1638           1 :         tester_old.AddMessage("platformban", msg_data_old);
    1639           1 :         ret = tester_old.Interact();
    1640           1 :         BOOST_REQUIRE(ret && ret->empty());
    1641           1 :         tester_old.ReceiveMessage("platformban", msg_data_old); // long encoding
    1642             : 
    1643             :         // New peer (v70240) - knows about PLATFORMBAN short ID 168
    1644           1 :         V2TransportTester tester_new(true);
    1645             :         // Uses PROTOCOL_VERSION (70240) by default
    1646             : 
    1647           1 :         ret = tester_new.Interact();
    1648           1 :         BOOST_REQUIRE(ret && ret->empty());
    1649           1 :         tester_new.SendKey();
    1650           1 :         tester_new.SendGarbage();
    1651           1 :         tester_new.ReceiveKey();
    1652           1 :         tester_new.SendGarbageTerm();
    1653           1 :         tester_new.SendVersion();
    1654           1 :         ret = tester_new.Interact();
    1655           1 :         BOOST_REQUIRE(ret && ret->empty());
    1656           1 :         tester_new.ReceiveGarbage();
    1657           1 :         tester_new.ReceiveVersion();
    1658             : 
    1659             :         // New peer gets short encoding for PLATFORMBAN
    1660           1 :         auto msg_data_new = g_insecure_rand_ctx.randbytes<uint8_t>(100);
    1661           1 :         tester_new.AddMessage("platformban", msg_data_new);
    1662           1 :         ret = tester_new.Interact();
    1663           1 :         BOOST_REQUIRE(ret && ret->empty());
    1664           1 :         tester_new.ReceiveMessage(uint8_t(168), msg_data_new); // short encoding
    1665           1 :     }
    1666           1 : }
    1667             : 
    1668         146 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.16