mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 14:53:43 +01:00
This is an extraction of ArgsManager related functions from util/system into their own common file. Config file related functions are moved to common/config.cpp. The background of this commit is an ongoing effort to decouple the libbitcoinkernel library from the ArgsManager. The ArgsManager belongs into the common library, since the kernel library should not depend on it. See doc/design/libraries.md for more information on this rationale.
909 lines
36 KiB
C++
909 lines
36 KiB
C++
// Copyright (c) 2012-2022 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <chainparams.h>
|
|
#include <clientversion.h>
|
|
#include <common/args.h>
|
|
#include <compat/compat.h>
|
|
#include <cstdint>
|
|
#include <net.h>
|
|
#include <net_processing.h>
|
|
#include <netaddress.h>
|
|
#include <netbase.h>
|
|
#include <netmessagemaker.h>
|
|
#include <serialize.h>
|
|
#include <span.h>
|
|
#include <streams.h>
|
|
#include <test/util/setup_common.h>
|
|
#include <test/util/validation.h>
|
|
#include <timedata.h>
|
|
#include <util/strencodings.h>
|
|
#include <util/string.h>
|
|
#include <validation.h>
|
|
#include <version.h>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <ios>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
|
|
using namespace std::literals;
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(net_tests, RegTestingSetup)
|
|
|
|
BOOST_AUTO_TEST_CASE(cnode_listen_port)
|
|
{
|
|
// test default
|
|
uint16_t port{GetListenPort()};
|
|
BOOST_CHECK(port == Params().GetDefaultPort());
|
|
// test set port
|
|
uint16_t altPort = 12345;
|
|
BOOST_CHECK(gArgs.SoftSetArg("-port", ToString(altPort)));
|
|
port = GetListenPort();
|
|
BOOST_CHECK(port == altPort);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|
{
|
|
NodeId id = 0;
|
|
|
|
in_addr ipv4Addr;
|
|
ipv4Addr.s_addr = 0xa0b0c001;
|
|
|
|
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
|
|
std::string pszDest;
|
|
|
|
std::unique_ptr<CNode> pnode1 = std::make_unique<CNode>(id++,
|
|
/*sock=*/nullptr,
|
|
addr,
|
|
/*nKeyedNetGroupIn=*/0,
|
|
/*nLocalHostNonceIn=*/0,
|
|
CAddress(),
|
|
pszDest,
|
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
|
/*inbound_onion=*/false);
|
|
BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
|
|
BOOST_CHECK(pnode1->IsManualConn() == false);
|
|
BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
|
|
BOOST_CHECK(pnode1->IsFeelerConn() == false);
|
|
BOOST_CHECK(pnode1->IsAddrFetchConn() == false);
|
|
BOOST_CHECK(pnode1->IsInboundConn() == false);
|
|
BOOST_CHECK(pnode1->m_inbound_onion == false);
|
|
BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4);
|
|
|
|
std::unique_ptr<CNode> pnode2 = std::make_unique<CNode>(id++,
|
|
/*sock=*/nullptr,
|
|
addr,
|
|
/*nKeyedNetGroupIn=*/1,
|
|
/*nLocalHostNonceIn=*/1,
|
|
CAddress(),
|
|
pszDest,
|
|
ConnectionType::INBOUND,
|
|
/*inbound_onion=*/false);
|
|
BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
|
|
BOOST_CHECK(pnode2->IsManualConn() == false);
|
|
BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
|
|
BOOST_CHECK(pnode2->IsFeelerConn() == false);
|
|
BOOST_CHECK(pnode2->IsAddrFetchConn() == false);
|
|
BOOST_CHECK(pnode2->IsInboundConn() == true);
|
|
BOOST_CHECK(pnode2->m_inbound_onion == false);
|
|
BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4);
|
|
|
|
std::unique_ptr<CNode> pnode3 = std::make_unique<CNode>(id++,
|
|
/*sock=*/nullptr,
|
|
addr,
|
|
/*nKeyedNetGroupIn=*/0,
|
|
/*nLocalHostNonceIn=*/0,
|
|
CAddress(),
|
|
pszDest,
|
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
|
/*inbound_onion=*/false);
|
|
BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
|
|
BOOST_CHECK(pnode3->IsManualConn() == false);
|
|
BOOST_CHECK(pnode3->IsBlockOnlyConn() == false);
|
|
BOOST_CHECK(pnode3->IsFeelerConn() == false);
|
|
BOOST_CHECK(pnode3->IsAddrFetchConn() == false);
|
|
BOOST_CHECK(pnode3->IsInboundConn() == false);
|
|
BOOST_CHECK(pnode3->m_inbound_onion == false);
|
|
BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4);
|
|
|
|
std::unique_ptr<CNode> pnode4 = std::make_unique<CNode>(id++,
|
|
/*sock=*/nullptr,
|
|
addr,
|
|
/*nKeyedNetGroupIn=*/1,
|
|
/*nLocalHostNonceIn=*/1,
|
|
CAddress(),
|
|
pszDest,
|
|
ConnectionType::INBOUND,
|
|
/*inbound_onion=*/true);
|
|
BOOST_CHECK(pnode4->IsFullOutboundConn() == false);
|
|
BOOST_CHECK(pnode4->IsManualConn() == false);
|
|
BOOST_CHECK(pnode4->IsBlockOnlyConn() == false);
|
|
BOOST_CHECK(pnode4->IsFeelerConn() == false);
|
|
BOOST_CHECK(pnode4->IsAddrFetchConn() == false);
|
|
BOOST_CHECK(pnode4->IsInboundConn() == true);
|
|
BOOST_CHECK(pnode4->m_inbound_onion == true);
|
|
BOOST_CHECK_EQUAL(pnode4->ConnectedThroughNetwork(), Network::NET_ONION);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
|
{
|
|
CNetAddr addr;
|
|
|
|
// IPv4, INADDR_ANY
|
|
BOOST_REQUIRE(LookupHost("0.0.0.0", addr, false));
|
|
BOOST_REQUIRE(!addr.IsValid());
|
|
BOOST_REQUIRE(addr.IsIPv4());
|
|
|
|
BOOST_CHECK(addr.IsBindAny());
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "0.0.0.0");
|
|
|
|
// IPv4, INADDR_NONE
|
|
BOOST_REQUIRE(LookupHost("255.255.255.255", addr, false));
|
|
BOOST_REQUIRE(!addr.IsValid());
|
|
BOOST_REQUIRE(addr.IsIPv4());
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "255.255.255.255");
|
|
|
|
// IPv4, casual
|
|
BOOST_REQUIRE(LookupHost("12.34.56.78", addr, false));
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
BOOST_REQUIRE(addr.IsIPv4());
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "12.34.56.78");
|
|
|
|
// IPv6, in6addr_any
|
|
BOOST_REQUIRE(LookupHost("::", addr, false));
|
|
BOOST_REQUIRE(!addr.IsValid());
|
|
BOOST_REQUIRE(addr.IsIPv6());
|
|
|
|
BOOST_CHECK(addr.IsBindAny());
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "::");
|
|
|
|
// IPv6, casual
|
|
BOOST_REQUIRE(LookupHost("1122:3344:5566:7788:9900:aabb:ccdd:eeff", addr, false));
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
BOOST_REQUIRE(addr.IsIPv6());
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff");
|
|
|
|
// IPv6, scoped/link-local. See https://tools.ietf.org/html/rfc4007
|
|
// We support non-negative decimal integers (uint32_t) as zone id indices.
|
|
// Normal link-local scoped address functionality is to append "%" plus the
|
|
// zone id, for example, given a link-local address of "fe80::1" and a zone
|
|
// id of "32", return the address as "fe80::1%32".
|
|
const std::string link_local{"fe80::1"};
|
|
const std::string scoped_addr{link_local + "%32"};
|
|
BOOST_REQUIRE(LookupHost(scoped_addr, addr, false));
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
BOOST_REQUIRE(addr.IsIPv6());
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), scoped_addr);
|
|
|
|
// Test that the delimiter "%" and default zone id of 0 can be omitted for the default scope.
|
|
BOOST_REQUIRE(LookupHost(link_local + "%0", addr, false));
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
BOOST_REQUIRE(addr.IsIPv6());
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), link_local);
|
|
|
|
// TORv2, no longer supported
|
|
BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
|
|
|
|
// TORv3
|
|
const char* torv3_addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion";
|
|
BOOST_REQUIRE(addr.SetSpecial(torv3_addr));
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
BOOST_REQUIRE(addr.IsTor());
|
|
|
|
BOOST_CHECK(!addr.IsI2P());
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), torv3_addr);
|
|
|
|
// TORv3, broken, with wrong checksum
|
|
BOOST_CHECK(!addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscsad.onion"));
|
|
|
|
// TORv3, broken, with wrong version
|
|
BOOST_CHECK(!addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscrye.onion"));
|
|
|
|
// TORv3, malicious
|
|
BOOST_CHECK(!addr.SetSpecial(std::string{
|
|
"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd\0wtf.onion", 66}));
|
|
|
|
// TOR, bogus length
|
|
BOOST_CHECK(!addr.SetSpecial(std::string{"mfrggzak.onion"}));
|
|
|
|
// TOR, invalid base32
|
|
BOOST_CHECK(!addr.SetSpecial(std::string{"mf*g zak.onion"}));
|
|
|
|
// I2P
|
|
const char* i2p_addr = "UDHDrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.I2P";
|
|
BOOST_REQUIRE(addr.SetSpecial(i2p_addr));
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
BOOST_REQUIRE(addr.IsI2P());
|
|
|
|
BOOST_CHECK(!addr.IsTor());
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), ToLower(i2p_addr));
|
|
|
|
// I2P, correct length, but decodes to less than the expected number of bytes.
|
|
BOOST_CHECK(!addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jn=.b32.i2p"));
|
|
|
|
// I2P, extra unnecessary padding
|
|
BOOST_CHECK(!addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna=.b32.i2p"));
|
|
|
|
// I2P, malicious
|
|
BOOST_CHECK(!addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v\0wtf.b32.i2p"s));
|
|
|
|
// I2P, valid but unsupported (56 Base32 characters)
|
|
// See "Encrypted LS with Base 32 Addresses" in
|
|
// https://geti2p.net/spec/encryptedleaseset.txt
|
|
BOOST_CHECK(
|
|
!addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscsad.b32.i2p"));
|
|
|
|
// I2P, invalid base32
|
|
BOOST_CHECK(!addr.SetSpecial(std::string{"tp*szydbh4dp.b32.i2p"}));
|
|
|
|
// Internal
|
|
addr.SetInternal("esffpp");
|
|
BOOST_REQUIRE(!addr.IsValid()); // "internal" is considered invalid
|
|
BOOST_REQUIRE(addr.IsInternal());
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "esffpvrt3wpeaygy.internal");
|
|
|
|
// Totally bogus
|
|
BOOST_CHECK(!addr.SetSpecial("totally bogus"));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(cnetaddr_tostring_canonical_ipv6)
|
|
{
|
|
// Test that CNetAddr::ToString formats IPv6 addresses with zero compression as described in
|
|
// RFC 5952 ("A Recommendation for IPv6 Address Text Representation").
|
|
const std::map<std::string, std::string> canonical_representations_ipv6{
|
|
{"0000:0000:0000:0000:0000:0000:0000:0000", "::"},
|
|
{"000:0000:000:00:0:00:000:0000", "::"},
|
|
{"000:000:000:000:000:000:000:000", "::"},
|
|
{"00:00:00:00:00:00:00:00", "::"},
|
|
{"0:0:0:0:0:0:0:0", "::"},
|
|
{"0:0:0:0:0:0:0:1", "::1"},
|
|
{"2001:0:0:1:0:0:0:1", "2001:0:0:1::1"},
|
|
{"2001:0db8:0:0:1:0:0:1", "2001:db8::1:0:0:1"},
|
|
{"2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:db8:85a3::8a2e:370:7334"},
|
|
{"2001:0db8::0001", "2001:db8::1"},
|
|
{"2001:0db8::0001:0000", "2001:db8::1:0"},
|
|
{"2001:0db8::1:0:0:1", "2001:db8::1:0:0:1"},
|
|
{"2001:db8:0000:0:1::1", "2001:db8::1:0:0:1"},
|
|
{"2001:db8:0000:1:1:1:1:1", "2001:db8:0:1:1:1:1:1"},
|
|
{"2001:db8:0:0:0:0:2:1", "2001:db8::2:1"},
|
|
{"2001:db8:0:0:0::1", "2001:db8::1"},
|
|
{"2001:db8:0:0:1:0:0:1", "2001:db8::1:0:0:1"},
|
|
{"2001:db8:0:0:1::1", "2001:db8::1:0:0:1"},
|
|
{"2001:DB8:0:0:1::1", "2001:db8::1:0:0:1"},
|
|
{"2001:db8:0:0::1", "2001:db8::1"},
|
|
{"2001:db8:0:0:aaaa::1", "2001:db8::aaaa:0:0:1"},
|
|
{"2001:db8:0:1:1:1:1:1", "2001:db8:0:1:1:1:1:1"},
|
|
{"2001:db8:0::1", "2001:db8::1"},
|
|
{"2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3::8a2e:370:7334"},
|
|
{"2001:db8::0:1", "2001:db8::1"},
|
|
{"2001:db8::0:1:0:0:1", "2001:db8::1:0:0:1"},
|
|
{"2001:DB8::1", "2001:db8::1"},
|
|
{"2001:db8::1", "2001:db8::1"},
|
|
{"2001:db8::1:0:0:1", "2001:db8::1:0:0:1"},
|
|
{"2001:db8::1:1:1:1:1", "2001:db8:0:1:1:1:1:1"},
|
|
{"2001:db8::aaaa:0:0:1", "2001:db8::aaaa:0:0:1"},
|
|
{"2001:db8:aaaa:bbbb:cccc:dddd:0:1", "2001:db8:aaaa:bbbb:cccc:dddd:0:1"},
|
|
{"2001:db8:aaaa:bbbb:cccc:dddd::1", "2001:db8:aaaa:bbbb:cccc:dddd:0:1"},
|
|
{"2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
|
|
{"2001:db8:aaaa:bbbb:cccc:dddd:eeee:001", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
|
|
{"2001:db8:aaaa:bbbb:cccc:dddd:eeee:01", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
|
|
{"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"},
|
|
{"2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
|
|
{"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
|
|
{"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
|
|
};
|
|
for (const auto& [input_address, expected_canonical_representation_output] : canonical_representations_ipv6) {
|
|
CNetAddr net_addr;
|
|
BOOST_REQUIRE(LookupHost(input_address, net_addr, false));
|
|
BOOST_REQUIRE(net_addr.IsIPv6());
|
|
BOOST_CHECK_EQUAL(net_addr.ToStringAddr(), expected_canonical_representation_output);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1)
|
|
{
|
|
CNetAddr addr;
|
|
CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
|
|
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000");
|
|
s.clear();
|
|
|
|
BOOST_REQUIRE(LookupHost("1.2.3.4", addr, false));
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000ffff01020304");
|
|
s.clear();
|
|
|
|
BOOST_REQUIRE(LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", addr, false));
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "1a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
|
|
s.clear();
|
|
|
|
// TORv2, no longer supported
|
|
BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
|
|
|
|
BOOST_REQUIRE(addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000");
|
|
s.clear();
|
|
|
|
addr.SetInternal("a");
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "fd6b88c08724ca978112ca1bbdcafac2");
|
|
s.clear();
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2)
|
|
{
|
|
CNetAddr addr;
|
|
CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
|
|
// Add ADDRV2_FORMAT to the version so that the CNetAddr
|
|
// serialize method produces an address in v2 format.
|
|
s.SetVersion(s.GetVersion() | ADDRV2_FORMAT);
|
|
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "021000000000000000000000000000000000");
|
|
s.clear();
|
|
|
|
BOOST_REQUIRE(LookupHost("1.2.3.4", addr, false));
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "010401020304");
|
|
s.clear();
|
|
|
|
BOOST_REQUIRE(LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", addr, false));
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
|
|
s.clear();
|
|
|
|
// TORv2, no longer supported
|
|
BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
|
|
|
|
BOOST_REQUIRE(addr.SetSpecial("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion"));
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "042053cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88");
|
|
s.clear();
|
|
|
|
BOOST_REQUIRE(addr.SetInternal("a"));
|
|
s << addr;
|
|
BOOST_CHECK_EQUAL(HexStr(s), "0210fd6b88c08724ca978112ca1bbdcafac2");
|
|
s.clear();
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
|
|
{
|
|
CNetAddr addr;
|
|
CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
|
|
// Add ADDRV2_FORMAT to the version so that the CNetAddr
|
|
// unserialize method expects an address in v2 format.
|
|
s.SetVersion(s.GetVersion() | ADDRV2_FORMAT);
|
|
|
|
// Valid IPv4.
|
|
s << Span{ParseHex("01" // network type (IPv4)
|
|
"04" // address length
|
|
"01020304")}; // address
|
|
s >> addr;
|
|
BOOST_CHECK(addr.IsValid());
|
|
BOOST_CHECK(addr.IsIPv4());
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "1.2.3.4");
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Invalid IPv4, valid length but address itself is shorter.
|
|
s << Span{ParseHex("01" // network type (IPv4)
|
|
"04" // address length
|
|
"0102")}; // address
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, HasReason("end of data"));
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
s.clear();
|
|
|
|
// Invalid IPv4, with bogus length.
|
|
s << Span{ParseHex("01" // network type (IPv4)
|
|
"05" // address length
|
|
"01020304")}; // address
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
HasReason("BIP155 IPv4 address with length 5 (should be 4)"));
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
s.clear();
|
|
|
|
// Invalid IPv4, with extreme length.
|
|
s << Span{ParseHex("01" // network type (IPv4)
|
|
"fd0102" // address length (513 as CompactSize)
|
|
"01020304")}; // address
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
HasReason("Address too long: 513 > 512"));
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
s.clear();
|
|
|
|
// Valid IPv6.
|
|
s << Span{ParseHex("02" // network type (IPv6)
|
|
"10" // address length
|
|
"0102030405060708090a0b0c0d0e0f10")}; // address
|
|
s >> addr;
|
|
BOOST_CHECK(addr.IsValid());
|
|
BOOST_CHECK(addr.IsIPv6());
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "102:304:506:708:90a:b0c:d0e:f10");
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Valid IPv6, contains embedded "internal".
|
|
s << Span{ParseHex(
|
|
"02" // network type (IPv6)
|
|
"10" // address length
|
|
"fd6b88c08724ca978112ca1bbdcafac2")}; // address: 0xfd + sha256("bitcoin")[0:5] +
|
|
// sha256(name)[0:10]
|
|
s >> addr;
|
|
BOOST_CHECK(addr.IsInternal());
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "zklycewkdo64v6wc.internal");
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Invalid IPv6, with bogus length.
|
|
s << Span{ParseHex("02" // network type (IPv6)
|
|
"04" // address length
|
|
"00")}; // address
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
HasReason("BIP155 IPv6 address with length 4 (should be 16)"));
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
s.clear();
|
|
|
|
// Invalid IPv6, contains embedded IPv4.
|
|
s << Span{ParseHex("02" // network type (IPv6)
|
|
"10" // address length
|
|
"00000000000000000000ffff01020304")}; // address
|
|
s >> addr;
|
|
BOOST_CHECK(!addr.IsValid());
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Invalid IPv6, contains embedded TORv2.
|
|
s << Span{ParseHex("02" // network type (IPv6)
|
|
"10" // address length
|
|
"fd87d87eeb430102030405060708090a")}; // address
|
|
s >> addr;
|
|
BOOST_CHECK(!addr.IsValid());
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// TORv2, no longer supported.
|
|
s << Span{ParseHex("03" // network type (TORv2)
|
|
"0a" // address length
|
|
"f1f2f3f4f5f6f7f8f9fa")}; // address
|
|
s >> addr;
|
|
BOOST_CHECK(!addr.IsValid());
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Valid TORv3.
|
|
s << Span{ParseHex("04" // network type (TORv3)
|
|
"20" // address length
|
|
"79bcc625184b05194975c28b66b66b04" // address
|
|
"69f7f6556fb1ac3189a79b40dda32f1f"
|
|
)};
|
|
s >> addr;
|
|
BOOST_CHECK(addr.IsValid());
|
|
BOOST_CHECK(addr.IsTor());
|
|
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(),
|
|
"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion");
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Invalid TORv3, with bogus length.
|
|
s << Span{ParseHex("04" // network type (TORv3)
|
|
"00" // address length
|
|
"00" // address
|
|
)};
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
HasReason("BIP155 TORv3 address with length 0 (should be 32)"));
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
s.clear();
|
|
|
|
// Valid I2P.
|
|
s << Span{ParseHex("05" // network type (I2P)
|
|
"20" // address length
|
|
"a2894dabaec08c0051a481a6dac88b64" // address
|
|
"f98232ae42d4b6fd2fa81952dfe36a87")};
|
|
s >> addr;
|
|
BOOST_CHECK(addr.IsValid());
|
|
BOOST_CHECK(addr.IsI2P());
|
|
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(),
|
|
"ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq.b32.i2p");
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Invalid I2P, with bogus length.
|
|
s << Span{ParseHex("05" // network type (I2P)
|
|
"03" // address length
|
|
"00" // address
|
|
)};
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
HasReason("BIP155 I2P address with length 3 (should be 32)"));
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
s.clear();
|
|
|
|
// Valid CJDNS.
|
|
s << Span{ParseHex("06" // network type (CJDNS)
|
|
"10" // address length
|
|
"fc000001000200030004000500060007" // address
|
|
)};
|
|
s >> addr;
|
|
BOOST_CHECK(addr.IsValid());
|
|
BOOST_CHECK(addr.IsCJDNS());
|
|
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
|
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "fc00:1:2:3:4:5:6:7");
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Invalid CJDNS, wrong prefix.
|
|
s << Span{ParseHex("06" // network type (CJDNS)
|
|
"10" // address length
|
|
"aa000001000200030004000500060007" // address
|
|
)};
|
|
s >> addr;
|
|
BOOST_CHECK(addr.IsCJDNS());
|
|
BOOST_CHECK(!addr.IsValid());
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Invalid CJDNS, with bogus length.
|
|
s << Span{ParseHex("06" // network type (CJDNS)
|
|
"01" // address length
|
|
"00" // address
|
|
)};
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
HasReason("BIP155 CJDNS address with length 1 (should be 16)"));
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
s.clear();
|
|
|
|
// Unknown, with extreme length.
|
|
s << Span{ParseHex("aa" // network type (unknown)
|
|
"fe00000002" // address length (CompactSize's MAX_SIZE)
|
|
"01020304050607" // address
|
|
)};
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
HasReason("Address too long: 33554432 > 512"));
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
s.clear();
|
|
|
|
// Unknown, with reasonable length.
|
|
s << Span{ParseHex("aa" // network type (unknown)
|
|
"04" // address length
|
|
"01020304" // address
|
|
)};
|
|
s >> addr;
|
|
BOOST_CHECK(!addr.IsValid());
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
// Unknown, with zero length.
|
|
s << Span{ParseHex("aa" // network type (unknown)
|
|
"00" // address length
|
|
"" // address
|
|
)};
|
|
s >> addr;
|
|
BOOST_CHECK(!addr.IsValid());
|
|
BOOST_REQUIRE(s.empty());
|
|
}
|
|
|
|
// prior to PR #14728, this test triggers an undefined behavior
|
|
BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
|
{
|
|
// set up local addresses; all that's necessary to reproduce the bug is
|
|
// that a normal IPv4 address is among the entries, but if this address is
|
|
// !IsRoutable the undefined behavior is easier to trigger deterministically
|
|
in_addr raw_addr;
|
|
raw_addr.s_addr = htonl(0x7f000001);
|
|
const CNetAddr mapLocalHost_entry = CNetAddr(raw_addr);
|
|
{
|
|
LOCK(g_maplocalhost_mutex);
|
|
LocalServiceInfo lsi;
|
|
lsi.nScore = 23;
|
|
lsi.nPort = 42;
|
|
mapLocalHost[mapLocalHost_entry] = lsi;
|
|
}
|
|
|
|
// create a peer with an IPv4 address
|
|
in_addr ipv4AddrPeer;
|
|
ipv4AddrPeer.s_addr = 0xa0b0c001;
|
|
CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
|
|
std::unique_ptr<CNode> pnode = std::make_unique<CNode>(/*id=*/0,
|
|
/*sock=*/nullptr,
|
|
addr,
|
|
/*nKeyedNetGroupIn=*/0,
|
|
/*nLocalHostNonceIn=*/0,
|
|
CAddress{},
|
|
/*pszDest=*/std::string{},
|
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
|
/*inbound_onion=*/false);
|
|
pnode->fSuccessfullyConnected.store(true);
|
|
|
|
// the peer claims to be reaching us via IPv6
|
|
in6_addr ipv6AddrLocal;
|
|
memset(ipv6AddrLocal.s6_addr, 0, 16);
|
|
ipv6AddrLocal.s6_addr[0] = 0xcc;
|
|
CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK);
|
|
pnode->SetAddrLocal(addrLocal);
|
|
|
|
// before patch, this causes undefined behavior detectable with clang's -fsanitize=memory
|
|
GetLocalAddrForPeer(*pnode);
|
|
|
|
// suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer
|
|
BOOST_CHECK(1);
|
|
|
|
// Cleanup, so that we don't confuse other tests.
|
|
{
|
|
LOCK(g_maplocalhost_mutex);
|
|
mapLocalHost.erase(mapLocalHost_entry);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
|
{
|
|
// Test that GetLocalAddrForPeer() properly selects the address to self-advertise:
|
|
//
|
|
// 1. GetLocalAddrForPeer() calls GetLocalAddress() which returns an address that is
|
|
// not routable.
|
|
// 2. GetLocalAddrForPeer() overrides the address with whatever the peer has told us
|
|
// he sees us as.
|
|
// 2.1. For inbound connections we must override both the address and the port.
|
|
// 2.2. For outbound connections we must override only the address.
|
|
|
|
// Pretend that we bound to this port.
|
|
const uint16_t bind_port = 20001;
|
|
m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port));
|
|
|
|
// Our address:port as seen from the peer, completely different from the above.
|
|
in_addr peer_us_addr;
|
|
peer_us_addr.s_addr = htonl(0x02030405);
|
|
const CService peer_us{peer_us_addr, 20002};
|
|
|
|
// Create a peer with a routable IPv4 address (outbound).
|
|
in_addr peer_out_in_addr;
|
|
peer_out_in_addr.s_addr = htonl(0x01020304);
|
|
CNode peer_out{/*id=*/0,
|
|
/*sock=*/nullptr,
|
|
/*addrIn=*/CAddress{CService{peer_out_in_addr, 8333}, NODE_NETWORK},
|
|
/*nKeyedNetGroupIn=*/0,
|
|
/*nLocalHostNonceIn=*/0,
|
|
/*addrBindIn=*/CAddress{},
|
|
/*addrNameIn=*/std::string{},
|
|
/*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
|
|
/*inbound_onion=*/false};
|
|
peer_out.fSuccessfullyConnected = true;
|
|
peer_out.SetAddrLocal(peer_us);
|
|
|
|
// Without the fix peer_us:8333 is chosen instead of the proper peer_us:bind_port.
|
|
auto chosen_local_addr = GetLocalAddrForPeer(peer_out);
|
|
BOOST_REQUIRE(chosen_local_addr);
|
|
const CService expected{peer_us_addr, bind_port};
|
|
BOOST_CHECK(*chosen_local_addr == expected);
|
|
|
|
// Create a peer with a routable IPv4 address (inbound).
|
|
in_addr peer_in_in_addr;
|
|
peer_in_in_addr.s_addr = htonl(0x05060708);
|
|
CNode peer_in{/*id=*/0,
|
|
/*sock=*/nullptr,
|
|
/*addrIn=*/CAddress{CService{peer_in_in_addr, 8333}, NODE_NETWORK},
|
|
/*nKeyedNetGroupIn=*/0,
|
|
/*nLocalHostNonceIn=*/0,
|
|
/*addrBindIn=*/CAddress{},
|
|
/*addrNameIn=*/std::string{},
|
|
/*conn_type_in=*/ConnectionType::INBOUND,
|
|
/*inbound_onion=*/false};
|
|
peer_in.fSuccessfullyConnected = true;
|
|
peer_in.SetAddrLocal(peer_us);
|
|
|
|
// Without the fix peer_us:8333 is chosen instead of the proper peer_us:peer_us.GetPort().
|
|
chosen_local_addr = GetLocalAddrForPeer(peer_in);
|
|
BOOST_REQUIRE(chosen_local_addr);
|
|
BOOST_CHECK(*chosen_local_addr == peer_us);
|
|
|
|
m_node.args->ForceSetArg("-bind", "");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network)
|
|
{
|
|
BOOST_CHECK(IsReachable(NET_IPV4));
|
|
BOOST_CHECK(IsReachable(NET_IPV6));
|
|
BOOST_CHECK(IsReachable(NET_ONION));
|
|
BOOST_CHECK(IsReachable(NET_I2P));
|
|
BOOST_CHECK(IsReachable(NET_CJDNS));
|
|
|
|
SetReachable(NET_IPV4, false);
|
|
SetReachable(NET_IPV6, false);
|
|
SetReachable(NET_ONION, false);
|
|
SetReachable(NET_I2P, false);
|
|
SetReachable(NET_CJDNS, false);
|
|
|
|
BOOST_CHECK(!IsReachable(NET_IPV4));
|
|
BOOST_CHECK(!IsReachable(NET_IPV6));
|
|
BOOST_CHECK(!IsReachable(NET_ONION));
|
|
BOOST_CHECK(!IsReachable(NET_I2P));
|
|
BOOST_CHECK(!IsReachable(NET_CJDNS));
|
|
|
|
SetReachable(NET_IPV4, true);
|
|
SetReachable(NET_IPV6, true);
|
|
SetReachable(NET_ONION, true);
|
|
SetReachable(NET_I2P, true);
|
|
SetReachable(NET_CJDNS, true);
|
|
|
|
BOOST_CHECK(IsReachable(NET_IPV4));
|
|
BOOST_CHECK(IsReachable(NET_IPV6));
|
|
BOOST_CHECK(IsReachable(NET_ONION));
|
|
BOOST_CHECK(IsReachable(NET_I2P));
|
|
BOOST_CHECK(IsReachable(NET_CJDNS));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal)
|
|
{
|
|
BOOST_CHECK(IsReachable(NET_UNROUTABLE));
|
|
BOOST_CHECK(IsReachable(NET_INTERNAL));
|
|
|
|
SetReachable(NET_UNROUTABLE, false);
|
|
SetReachable(NET_INTERNAL, false);
|
|
|
|
BOOST_CHECK(IsReachable(NET_UNROUTABLE)); // Ignored for both networks
|
|
BOOST_CHECK(IsReachable(NET_INTERNAL));
|
|
}
|
|
|
|
CNetAddr UtilBuildAddress(unsigned char p1, unsigned char p2, unsigned char p3, unsigned char p4)
|
|
{
|
|
unsigned char ip[] = {p1, p2, p3, p4};
|
|
|
|
struct sockaddr_in sa;
|
|
memset(&sa, 0, sizeof(sockaddr_in)); // initialize the memory block
|
|
memcpy(&(sa.sin_addr), &ip, sizeof(ip));
|
|
return CNetAddr(sa.sin_addr);
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(LimitedAndReachable_CNetAddr)
|
|
{
|
|
CNetAddr addr = UtilBuildAddress(0x001, 0x001, 0x001, 0x001); // 1.1.1.1
|
|
|
|
SetReachable(NET_IPV4, true);
|
|
BOOST_CHECK(IsReachable(addr));
|
|
|
|
SetReachable(NET_IPV4, false);
|
|
BOOST_CHECK(!IsReachable(addr));
|
|
|
|
SetReachable(NET_IPV4, true); // have to reset this, because this is stateful.
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle)
|
|
{
|
|
CService addr = CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000); // 2.1.1.1:1000
|
|
|
|
SetReachable(NET_IPV4, true);
|
|
|
|
BOOST_CHECK(!IsLocal(addr));
|
|
BOOST_CHECK(AddLocal(addr, 1000));
|
|
BOOST_CHECK(IsLocal(addr));
|
|
|
|
RemoveLocal(addr);
|
|
BOOST_CHECK(!IsLocal(addr));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
|
|
{
|
|
LOCK(NetEventsInterface::g_msgproc_mutex);
|
|
|
|
// Tests the following scenario:
|
|
// * -bind=3.4.5.6:20001 is specified
|
|
// * we make an outbound connection to a peer
|
|
// * the peer reports he sees us as 2.3.4.5:20002 in the version message
|
|
// (20002 is a random port assigned by our OS for the outgoing TCP connection,
|
|
// we cannot accept connections to it)
|
|
// * we should self-advertise to that peer as 2.3.4.5:20001
|
|
|
|
// Pretend that we bound to this port.
|
|
const uint16_t bind_port = 20001;
|
|
m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port));
|
|
m_node.args->ForceSetArg("-capturemessages", "1");
|
|
|
|
// Our address:port as seen from the peer - 2.3.4.5:20002 (different from the above).
|
|
in_addr peer_us_addr;
|
|
peer_us_addr.s_addr = htonl(0x02030405);
|
|
const CService peer_us{peer_us_addr, 20002};
|
|
|
|
// Create a peer with a routable IPv4 address.
|
|
in_addr peer_in_addr;
|
|
peer_in_addr.s_addr = htonl(0x01020304);
|
|
CNode peer{/*id=*/0,
|
|
/*sock=*/nullptr,
|
|
/*addrIn=*/CAddress{CService{peer_in_addr, 8333}, NODE_NETWORK},
|
|
/*nKeyedNetGroupIn=*/0,
|
|
/*nLocalHostNonceIn=*/0,
|
|
/*addrBindIn=*/CAddress{},
|
|
/*addrNameIn=*/std::string{},
|
|
/*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
|
|
/*inbound_onion=*/false};
|
|
|
|
const uint64_t services{NODE_NETWORK | NODE_WITNESS};
|
|
const int64_t time{0};
|
|
const CNetMsgMaker msg_maker{PROTOCOL_VERSION};
|
|
|
|
// Force Chainstate::IsInitialBlockDownload() to return false.
|
|
// Otherwise PushAddress() isn't called by PeerManager::ProcessMessage().
|
|
TestChainState& chainstate =
|
|
*static_cast<TestChainState*>(&m_node.chainman->ActiveChainstate());
|
|
chainstate.JumpOutOfIbd();
|
|
|
|
m_node.peerman->InitializeNode(peer, NODE_NETWORK);
|
|
|
|
std::atomic<bool> interrupt_dummy{false};
|
|
std::chrono::microseconds time_received_dummy{0};
|
|
|
|
const auto msg_version =
|
|
msg_maker.Make(NetMsgType::VERSION, PROTOCOL_VERSION, services, time, services, peer_us);
|
|
CDataStream msg_version_stream{msg_version.data, SER_NETWORK, PROTOCOL_VERSION};
|
|
|
|
m_node.peerman->ProcessMessage(
|
|
peer, NetMsgType::VERSION, msg_version_stream, time_received_dummy, interrupt_dummy);
|
|
|
|
const auto msg_verack = msg_maker.Make(NetMsgType::VERACK);
|
|
CDataStream msg_verack_stream{msg_verack.data, SER_NETWORK, PROTOCOL_VERSION};
|
|
|
|
// Will set peer.fSuccessfullyConnected to true (necessary in SendMessages()).
|
|
m_node.peerman->ProcessMessage(
|
|
peer, NetMsgType::VERACK, msg_verack_stream, time_received_dummy, interrupt_dummy);
|
|
|
|
// Ensure that peer_us_addr:bind_port is sent to the peer.
|
|
const CService expected{peer_us_addr, bind_port};
|
|
bool sent{false};
|
|
|
|
const auto CaptureMessageOrig = CaptureMessage;
|
|
CaptureMessage = [&sent, &expected](const CAddress& addr,
|
|
const std::string& msg_type,
|
|
Span<const unsigned char> data,
|
|
bool is_incoming) -> void {
|
|
if (!is_incoming && msg_type == "addr") {
|
|
CDataStream s(data, SER_NETWORK, PROTOCOL_VERSION);
|
|
std::vector<CAddress> addresses;
|
|
|
|
s >> addresses;
|
|
|
|
for (const auto& addr : addresses) {
|
|
if (addr == expected) {
|
|
sent = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
m_node.peerman->SendMessages(&peer);
|
|
|
|
BOOST_CHECK(sent);
|
|
|
|
CaptureMessage = CaptureMessageOrig;
|
|
chainstate.ResetIbd();
|
|
m_node.args->ForceSetArg("-capturemessages", "0");
|
|
m_node.args->ForceSetArg("-bind", "");
|
|
// PeerManager::ProcessMessage() calls AddTimeData() which changes the internal state
|
|
// in timedata.cpp and later confuses the test "timedata_tests/addtimedata". Thus reset
|
|
// that state as it was before our test was run.
|
|
TestOnlyResetTimeData();
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|