Files
bitcoin/src/test/net_tests.cpp
Ryan Ofsky 94a98fbd1d assumeutxo cleanup: Move IsInitialBlockDownload & NotifyHeaderTip to ChainstateManager
This change makes IsInitialBlockDownload and NotifyHeaderTip functions no
longer tied to individual Chainstate objects. It makes them work with the
ChainstateManager object instead so code is simpler and it is no longer
possible to call them incorrectly with an inactive Chainstate.

This change also makes m_cached_finished_ibd caching easier to reason about,
because now there is only one cached value instead of two (for background and
snapshot chainstates) so the cached IBD state now no longer gets reset when a
snapshot is loaded.

There should be no change in behavior because these functions were always
called on the active ChainState objects.

These changes were discussed previously
https://github.com/bitcoin/bitcoin/pull/27746#discussion_r1246868905 and
https://github.com/bitcoin/bitcoin/pull/27746#discussion_r1237552792 as
possible followups for that PR.
2023-08-18 12:52:30 -04:00

1012 lines
41 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
addr = LookupHost("0.0.0.0", false).value();
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
addr = LookupHost("255.255.255.255", false).value();
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
addr = LookupHost("12.34.56.78", false).value();
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
addr = LookupHost("::", false).value();
BOOST_REQUIRE(!addr.IsValid());
BOOST_REQUIRE(addr.IsIPv6());
BOOST_CHECK(addr.IsBindAny());
BOOST_CHECK(addr.IsAddrV1Compatible());
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "::");
// IPv6, casual
addr = LookupHost("1122:3344:5566:7788:9900:aabb:ccdd:eeff", false).value();
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"};
addr = LookupHost(scoped_addr, false).value();
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.
addr = LookupHost(link_local + "%0", false).value();
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) {
const std::optional<CNetAddr> net_addr{LookupHost(input_address, false)};
BOOST_REQUIRE(net_addr.value().IsIPv6());
BOOST_CHECK_EQUAL(net_addr.value().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();
addr = LookupHost("1.2.3.4", false).value();
s << addr;
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000ffff01020304");
s.clear();
addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value();
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();
addr = LookupHost("1.2.3.4", false).value();
s << addr;
BOOST_CHECK_EQUAL(HexStr(s), "010401020304");
s.clear();
addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value();
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 ChainstateManager::IsInitialBlockDownload() to return false.
// Otherwise PushAddress() isn't called by PeerManager::ProcessMessage().
auto& chainman = static_cast<TestChainstateManager&>(*m_node.chainman);
chainman.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;
chainman.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_CASE(advertise_local_address)
{
auto CreatePeer = [](const CAddress& addr) {
return std::make_unique<CNode>(/*id=*/0,
/*sock=*/nullptr,
addr,
/*nKeyedNetGroupIn=*/0,
/*nLocalHostNonceIn=*/0,
CAddress{},
/*pszDest=*/std::string{},
ConnectionType::OUTBOUND_FULL_RELAY,
/*inbound_onion=*/false);
};
SetReachable(NET_CJDNS, true);
CAddress addr_ipv4{Lookup("1.2.3.4", 8333, false).value(), NODE_NONE};
BOOST_REQUIRE(addr_ipv4.IsValid());
BOOST_REQUIRE(addr_ipv4.IsIPv4());
CAddress addr_ipv6{Lookup("1122:3344:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
BOOST_REQUIRE(addr_ipv6.IsValid());
BOOST_REQUIRE(addr_ipv6.IsIPv6());
CAddress addr_ipv6_tunnel{Lookup("2002:3344:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
BOOST_REQUIRE(addr_ipv6_tunnel.IsValid());
BOOST_REQUIRE(addr_ipv6_tunnel.IsIPv6());
BOOST_REQUIRE(addr_ipv6_tunnel.IsRFC3964());
CAddress addr_teredo{Lookup("2001:0000:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
BOOST_REQUIRE(addr_teredo.IsValid());
BOOST_REQUIRE(addr_teredo.IsIPv6());
BOOST_REQUIRE(addr_teredo.IsRFC4380());
CAddress addr_onion;
BOOST_REQUIRE(addr_onion.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
BOOST_REQUIRE(addr_onion.IsValid());
BOOST_REQUIRE(addr_onion.IsTor());
CAddress addr_i2p;
BOOST_REQUIRE(addr_i2p.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p"));
BOOST_REQUIRE(addr_i2p.IsValid());
BOOST_REQUIRE(addr_i2p.IsI2P());
CService service_cjdns{Lookup("fc00:3344:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
CAddress addr_cjdns{MaybeFlipIPv6toCJDNS(service_cjdns), NODE_NONE};
BOOST_REQUIRE(addr_cjdns.IsValid());
BOOST_REQUIRE(addr_cjdns.IsCJDNS());
const auto peer_ipv4{CreatePeer(addr_ipv4)};
const auto peer_ipv6{CreatePeer(addr_ipv6)};
const auto peer_ipv6_tunnel{CreatePeer(addr_ipv6_tunnel)};
const auto peer_teredo{CreatePeer(addr_teredo)};
const auto peer_onion{CreatePeer(addr_onion)};
const auto peer_i2p{CreatePeer(addr_i2p)};
const auto peer_cjdns{CreatePeer(addr_cjdns)};
// one local clearnet address - advertise to all but privacy peers
AddLocal(addr_ipv4);
BOOST_CHECK(GetLocalAddress(*peer_ipv4) == addr_ipv4);
BOOST_CHECK(GetLocalAddress(*peer_ipv6) == addr_ipv4);
BOOST_CHECK(GetLocalAddress(*peer_ipv6_tunnel) == addr_ipv4);
BOOST_CHECK(GetLocalAddress(*peer_teredo) == addr_ipv4);
BOOST_CHECK(GetLocalAddress(*peer_cjdns) == addr_ipv4);
BOOST_CHECK(!GetLocalAddress(*peer_onion).IsValid());
BOOST_CHECK(!GetLocalAddress(*peer_i2p).IsValid());
RemoveLocal(addr_ipv4);
// local privacy addresses - don't advertise to clearnet peers
AddLocal(addr_onion);
AddLocal(addr_i2p);
BOOST_CHECK(!GetLocalAddress(*peer_ipv4).IsValid());
BOOST_CHECK(!GetLocalAddress(*peer_ipv6).IsValid());
BOOST_CHECK(!GetLocalAddress(*peer_ipv6_tunnel).IsValid());
BOOST_CHECK(!GetLocalAddress(*peer_teredo).IsValid());
BOOST_CHECK(!GetLocalAddress(*peer_cjdns).IsValid());
BOOST_CHECK(GetLocalAddress(*peer_onion) == addr_onion);
BOOST_CHECK(GetLocalAddress(*peer_i2p) == addr_i2p);
RemoveLocal(addr_onion);
RemoveLocal(addr_i2p);
// local addresses from all networks
AddLocal(addr_ipv4);
AddLocal(addr_ipv6);
AddLocal(addr_ipv6_tunnel);
AddLocal(addr_teredo);
AddLocal(addr_onion);
AddLocal(addr_i2p);
AddLocal(addr_cjdns);
BOOST_CHECK(GetLocalAddress(*peer_ipv4) == addr_ipv4);
BOOST_CHECK(GetLocalAddress(*peer_ipv6) == addr_ipv6);
BOOST_CHECK(GetLocalAddress(*peer_ipv6_tunnel) == addr_ipv6);
BOOST_CHECK(GetLocalAddress(*peer_teredo) == addr_ipv4);
BOOST_CHECK(GetLocalAddress(*peer_onion) == addr_onion);
BOOST_CHECK(GetLocalAddress(*peer_i2p) == addr_i2p);
BOOST_CHECK(GetLocalAddress(*peer_cjdns) == addr_cjdns);
RemoveLocal(addr_ipv4);
RemoveLocal(addr_ipv6);
RemoveLocal(addr_ipv6_tunnel);
RemoveLocal(addr_teredo);
RemoveLocal(addr_onion);
RemoveLocal(addr_i2p);
RemoveLocal(addr_cjdns);
}
BOOST_AUTO_TEST_SUITE_END()