0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-03-04 13:55:23 -05:00

Use serialization parameters for CAddress serialization

This also cleans up the addrman (de)serialization code paths to only
allow `Disk` serialization. Some unit tests previously forced a
`Network` serialization, which does not make sense, because Bitcoin Core
in production will always `Disk` serialize.
This cleanup idea was suggested by Pieter Wuille and implemented by Anthony
Towns.

Co-authored-by: Pieter Wuille <pieter@wuille.net>
Co-authored-by: Anthony Towns <aj@erisian.com.au>
This commit is contained in:
MarcoFalke 2023-01-31 18:04:44 +01:00
parent faec591d64
commit fac81affb5
No known key found for this signature in database
19 changed files with 276 additions and 215 deletions

View file

@ -47,16 +47,16 @@ bool SerializeDB(Stream& stream, const Data& data)
} }
template <typename Data> template <typename Data>
bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data, int version) bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data)
{ {
// Generate random temporary filename // Generate random temporary filename
const uint16_t randv{GetRand<uint16_t>()}; const uint16_t randv{GetRand<uint16_t>()};
std::string tmpfn = strprintf("%s.%04x", prefix, randv); std::string tmpfn = strprintf("%s.%04x", prefix, randv);
// open temp output file, and associate with CAutoFile // open temp output file
fs::path pathTmp = gArgs.GetDataDirNet() / fs::u8path(tmpfn); fs::path pathTmp = gArgs.GetDataDirNet() / fs::u8path(tmpfn);
FILE *file = fsbridge::fopen(pathTmp, "wb"); FILE *file = fsbridge::fopen(pathTmp, "wb");
CAutoFile fileout(file, SER_DISK, version); AutoFile fileout{file};
if (fileout.IsNull()) { if (fileout.IsNull()) {
fileout.fclose(); fileout.fclose();
remove(pathTmp); remove(pathTmp);
@ -86,9 +86,9 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
} }
template <typename Stream, typename Data> template <typename Stream, typename Data>
void DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true) void DeserializeDB(Stream& stream, Data&& data, bool fCheckSum = true)
{ {
CHashVerifier<Stream> verifier(&stream); HashVerifier verifier{stream};
// de-serialize file header (network specific magic number) and .. // de-serialize file header (network specific magic number) and ..
unsigned char pchMsgTmp[4]; unsigned char pchMsgTmp[4];
verifier >> pchMsgTmp; verifier >> pchMsgTmp;
@ -111,11 +111,10 @@ void DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
} }
template <typename Data> template <typename Data>
void DeserializeFileDB(const fs::path& path, Data& data, int version) void DeserializeFileDB(const fs::path& path, Data&& data)
{ {
// open input file, and associate with CAutoFile
FILE* file = fsbridge::fopen(path, "rb"); FILE* file = fsbridge::fopen(path, "rb");
CAutoFile filein(file, SER_DISK, version); AutoFile filein{file};
if (filein.IsNull()) { if (filein.IsNull()) {
throw DbNotFoundError{}; throw DbNotFoundError{};
} }
@ -175,10 +174,10 @@ bool CBanDB::Read(banmap_t& banSet)
bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr) bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr)
{ {
const auto pathAddr = args.GetDataDirNet() / "peers.dat"; const auto pathAddr = args.GetDataDirNet() / "peers.dat";
return SerializeFileDB("peers", pathAddr, addr, CLIENT_VERSION); return SerializeFileDB("peers", pathAddr, addr);
} }
void ReadFromStream(AddrMan& addr, CDataStream& ssPeers) void ReadFromStream(AddrMan& addr, DataStream& ssPeers)
{ {
DeserializeDB(ssPeers, addr, false); DeserializeDB(ssPeers, addr, false);
} }
@ -191,7 +190,7 @@ util::Result<std::unique_ptr<AddrMan>> LoadAddrman(const NetGroupManager& netgro
const auto start{SteadyClock::now()}; const auto start{SteadyClock::now()};
const auto path_addr{args.GetDataDirNet() / "peers.dat"}; const auto path_addr{args.GetDataDirNet() / "peers.dat"};
try { try {
DeserializeFileDB(path_addr, *addrman, CLIENT_VERSION); DeserializeFileDB(path_addr, *addrman);
LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} catch (const DbNotFoundError&) { } catch (const DbNotFoundError&) {
// Addrman can be in an inconsistent state after failure, reset it // Addrman can be in an inconsistent state after failure, reset it
@ -217,14 +216,14 @@ util::Result<std::unique_ptr<AddrMan>> LoadAddrman(const NetGroupManager& netgro
void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors) void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors)
{ {
LOG_TIME_SECONDS(strprintf("Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size())); LOG_TIME_SECONDS(strprintf("Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size()));
SerializeFileDB("anchors", anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT); SerializeFileDB("anchors", anchors_db_path, WithParams(CAddress::V2_DISK, anchors));
} }
std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path) std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
{ {
std::vector<CAddress> anchors; std::vector<CAddress> anchors;
try { try {
DeserializeFileDB(anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT); DeserializeFileDB(anchors_db_path, WithParams(CAddress::V2_DISK, anchors));
LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename()))); LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename())));
} catch (const std::exception&) { } catch (const std::exception&) {
anchors.clear(); anchors.clear();

View file

@ -16,12 +16,13 @@
class ArgsManager; class ArgsManager;
class AddrMan; class AddrMan;
class CAddress; class CAddress;
class CDataStream; class DataStream;
class NetGroupManager; class NetGroupManager;
bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr);
/** Only used by tests. */ /** Only used by tests. */
void ReadFromStream(AddrMan& addr, CDataStream& ssPeers); void ReadFromStream(AddrMan& addr, DataStream& ssPeers);
bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr);
/** Access to the banlist database (banlist.json) */ /** Access to the banlist database (banlist.json) */
class CBanDB class CBanDB

View file

@ -171,8 +171,7 @@ void AddrManImpl::Serialize(Stream& s_) const
*/ */
// Always serialize in the latest version (FILE_FORMAT). // Always serialize in the latest version (FILE_FORMAT).
ParamsStream s{CAddress::V2_DISK, s_};
OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
s << static_cast<uint8_t>(FILE_FORMAT); s << static_cast<uint8_t>(FILE_FORMAT);
@ -236,14 +235,8 @@ void AddrManImpl::Unserialize(Stream& s_)
Format format; Format format;
s_ >> Using<CustomUintFormatter<1>>(format); s_ >> Using<CustomUintFormatter<1>>(format);
int stream_version = s_.GetVersion(); const auto ser_params = (format >= Format::V3_BIP155 ? CAddress::V2_DISK : CAddress::V1_DISK);
if (format >= Format::V3_BIP155) { ParamsStream s{ser_params, s_};
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
// unserialize methods know that an address in addrv2 format is coming.
stream_version |= ADDRV2_FORMAT;
}
OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
uint8_t compat; uint8_t compat;
s >> compat; s >> compat;
@ -1249,12 +1242,12 @@ void AddrMan::Unserialize(Stream& s_)
} }
// explicit instantiation // explicit instantiation
template void AddrMan::Serialize(HashedSourceWriter<CAutoFile>& s) const; template void AddrMan::Serialize(HashedSourceWriter<AutoFile>&) const;
template void AddrMan::Serialize(CDataStream& s) const; template void AddrMan::Serialize(DataStream&) const;
template void AddrMan::Unserialize(CAutoFile& s); template void AddrMan::Unserialize(AutoFile&);
template void AddrMan::Unserialize(CHashVerifier<CAutoFile>& s); template void AddrMan::Unserialize(HashVerifier<AutoFile>&);
template void AddrMan::Unserialize(CDataStream& s); template void AddrMan::Unserialize(DataStream&);
template void AddrMan::Unserialize(CHashVerifier<CDataStream>& s); template void AddrMan::Unserialize(HashVerifier<DataStream>&);
size_t AddrMan::Size(std::optional<Network> net, std::optional<bool> in_new) const size_t AddrMan::Size(std::optional<Network> net, std::optional<bool> in_new) const
{ {

View file

@ -234,18 +234,18 @@ public:
/** Writes data to an underlying source stream, while hashing the written data. */ /** Writes data to an underlying source stream, while hashing the written data. */
template <typename Source> template <typename Source>
class HashedSourceWriter : public CHashWriter class HashedSourceWriter : public HashWriter
{ {
private: private:
Source& m_source; Source& m_source;
public: public:
explicit HashedSourceWriter(Source& source LIFETIMEBOUND) : CHashWriter{source.GetType(), source.GetVersion()}, m_source{source} {} explicit HashedSourceWriter(Source& source LIFETIMEBOUND) : HashWriter{}, m_source{source} {}
void write(Span<const std::byte> src) void write(Span<const std::byte> src)
{ {
m_source.write(src); m_source.write(src);
CHashWriter::write(src); HashWriter::write(src);
} }
template <typename T> template <typename T>

View file

@ -202,7 +202,8 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
const auto one_week{7 * 24h}; const auto one_week{7 * 24h};
std::vector<CAddress> vSeedsOut; std::vector<CAddress> vSeedsOut;
FastRandomContext rng; FastRandomContext rng;
CDataStream s(vSeedsIn, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); DataStream underlying_stream{vSeedsIn};
ParamsStream s{CAddress::V2_NETWORK, underlying_stream};
while (!s.eof()) { while (!s.eof()) {
CService endpoint; CService endpoint;
s >> endpoint; s >> endpoint;

View file

@ -1415,8 +1415,8 @@ void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer)
const bool tx_relay{!RejectIncomingTxs(pnode)}; const bool tx_relay{!RejectIncomingTxs(pnode)};
m_connman.PushMessage(&pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, my_services, nTime, m_connman.PushMessage(&pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, my_services, nTime,
your_services, addr_you, // Together the pre-version-31402 serialization of CAddress "addrYou" (without nTime) your_services, WithParams(CNetAddr::V1, addr_you), // Together the pre-version-31402 serialization of CAddress "addrYou" (without nTime)
my_services, CService(), // Together the pre-version-31402 serialization of CAddress "addrMe" (without nTime) my_services, WithParams(CNetAddr::V1, CService{}), // Together the pre-version-31402 serialization of CAddress "addrMe" (without nTime)
nonce, strSubVersion, nNodeStartingHeight, tx_relay)); nonce, strSubVersion, nNodeStartingHeight, tx_relay));
if (fLogIPs) { if (fLogIPs) {
@ -3281,7 +3281,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
nTime = 0; nTime = 0;
} }
vRecv.ignore(8); // Ignore the addrMe service bits sent by the peer vRecv.ignore(8); // Ignore the addrMe service bits sent by the peer
vRecv >> addrMe; vRecv >> WithParams(CNetAddr::V1, addrMe);
if (!pfrom.IsInboundConn()) if (!pfrom.IsInboundConn())
{ {
m_addrman.SetServices(pfrom.addr, nServices); m_addrman.SetServices(pfrom.addr, nServices);
@ -3660,17 +3660,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
} }
if (msg_type == NetMsgType::ADDR || msg_type == NetMsgType::ADDRV2) { if (msg_type == NetMsgType::ADDR || msg_type == NetMsgType::ADDRV2) {
int stream_version = vRecv.GetVersion(); const auto ser_params{
if (msg_type == NetMsgType::ADDRV2) { msg_type == NetMsgType::ADDRV2 ?
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress // Set V2 param so that the CNetAddr and CAddress
// unserialize methods know that an address in v2 format is coming. // unserialize methods know that an address in v2 format is coming.
stream_version |= ADDRV2_FORMAT; CAddress::V2_NETWORK :
} CAddress::V1_NETWORK,
};
OverrideStream<CDataStream> s(&vRecv, vRecv.GetType(), stream_version);
std::vector<CAddress> vAddr; std::vector<CAddress> vAddr;
s >> vAddr; vRecv >> WithParams(ser_params, vAddr);
if (!SetupAddressRelay(pfrom, *peer)) { if (!SetupAddressRelay(pfrom, *peer)) {
LogPrint(BCLog::NET, "ignoring %s message from %s peer=%d\n", msg_type, pfrom.ConnectionTypeAsString(), pfrom.GetId()); LogPrint(BCLog::NET, "ignoring %s message from %s peer=%d\n", msg_type, pfrom.ConnectionTypeAsString(), pfrom.GetId());
@ -5272,15 +5272,15 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
if (peer.m_addrs_to_send.empty()) return; if (peer.m_addrs_to_send.empty()) return;
const char* msg_type; const char* msg_type;
int make_flags; CNetAddr::Encoding ser_enc;
if (peer.m_wants_addrv2) { if (peer.m_wants_addrv2) {
msg_type = NetMsgType::ADDRV2; msg_type = NetMsgType::ADDRV2;
make_flags = ADDRV2_FORMAT; ser_enc = CNetAddr::Encoding::V2;
} else { } else {
msg_type = NetMsgType::ADDR; msg_type = NetMsgType::ADDR;
make_flags = 0; ser_enc = CNetAddr::Encoding::V1;
} }
m_connman.PushMessage(&node, CNetMsgMaker(node.GetCommonVersion()).Make(make_flags, msg_type, peer.m_addrs_to_send)); m_connman.PushMessage(&node, CNetMsgMaker(node.GetCommonVersion()).Make(msg_type, WithParams(CAddress::SerParams{{ser_enc}, CAddress::Format::Network}, peer.m_addrs_to_send)));
peer.m_addrs_to_send.clear(); peer.m_addrs_to_send.clear();
// we only send the big addr message once // we only send the big addr message once

View file

@ -24,14 +24,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
/**
* A flag that is ORed into the protocol version to designate that addresses
* should be serialized in (unserialized from) v2 format (BIP155).
* Make sure that this does not collide with any of the values in `version.h`
* or with `SERIALIZE_TRANSACTION_NO_WITNESS`.
*/
static constexpr int ADDRV2_FORMAT = 0x20000000;
/** /**
* A network type. * A network type.
* @note An address may belong to more than one network, for example `10.0.0.1` * @note An address may belong to more than one network, for example `10.0.0.1`
@ -220,13 +212,23 @@ public:
return IsIPv4() || IsIPv6() || IsTor() || IsI2P() || IsCJDNS(); return IsIPv4() || IsIPv6() || IsTor() || IsI2P() || IsCJDNS();
} }
enum class Encoding {
V1,
V2, //!< BIP155 encoding
};
struct SerParams {
const Encoding enc;
};
static constexpr SerParams V1{Encoding::V1};
static constexpr SerParams V2{Encoding::V2};
/** /**
* Serialize to a stream. * Serialize to a stream.
*/ */
template <typename Stream> template <typename Stream>
void Serialize(Stream& s) const void Serialize(Stream& s) const
{ {
if (s.GetVersion() & ADDRV2_FORMAT) { if (s.GetParams().enc == Encoding::V2) {
SerializeV2Stream(s); SerializeV2Stream(s);
} else { } else {
SerializeV1Stream(s); SerializeV1Stream(s);
@ -239,7 +241,7 @@ public:
template <typename Stream> template <typename Stream>
void Unserialize(Stream& s) void Unserialize(Stream& s)
{ {
if (s.GetVersion() & ADDRV2_FORMAT) { if (s.GetParams().enc == Encoding::V2) {
UnserializeV2Stream(s); UnserializeV2Stream(s);
} else { } else {
UnserializeV1Stream(s); UnserializeV1Stream(s);

View file

@ -390,35 +390,43 @@ public:
CAddress(CService ipIn, ServiceFlags nServicesIn) : CService{ipIn}, nServices{nServicesIn} {}; CAddress(CService ipIn, ServiceFlags nServicesIn) : CService{ipIn}, nServices{nServicesIn} {};
CAddress(CService ipIn, ServiceFlags nServicesIn, NodeSeconds time) : CService{ipIn}, nTime{time}, nServices{nServicesIn} {}; CAddress(CService ipIn, ServiceFlags nServicesIn, NodeSeconds time) : CService{ipIn}, nTime{time}, nServices{nServicesIn} {};
SERIALIZE_METHODS(CAddress, obj) enum class Format {
Disk,
Network,
};
struct SerParams : CNetAddr::SerParams {
const Format fmt;
};
static constexpr SerParams V1_NETWORK{{CNetAddr::Encoding::V1}, Format::Network};
static constexpr SerParams V2_NETWORK{{CNetAddr::Encoding::V2}, Format::Network};
static constexpr SerParams V1_DISK{{CNetAddr::Encoding::V1}, Format::Disk};
static constexpr SerParams V2_DISK{{CNetAddr::Encoding::V2}, Format::Disk};
SERIALIZE_METHODS_PARAMS(CAddress, obj, SerParams, params)
{ {
// CAddress has a distinct network serialization and a disk serialization, but it should never
// be hashed (except through CHashWriter in addrdb.cpp, which sets SER_DISK), and it's
// ambiguous what that would mean. Make sure no code relying on that is introduced:
assert(!(s.GetType() & SER_GETHASH));
bool use_v2; bool use_v2;
if (s.GetType() & SER_DISK) { if (params.fmt == Format::Disk) {
// In the disk serialization format, the encoding (v1 or v2) is determined by a flag version // In the disk serialization format, the encoding (v1 or v2) is determined by a flag version
// that's part of the serialization itself. ADDRV2_FORMAT in the stream version only determines // that's part of the serialization itself. ADDRV2_FORMAT in the stream version only determines
// whether V2 is chosen/permitted at all. // whether V2 is chosen/permitted at all.
uint32_t stored_format_version = DISK_VERSION_INIT; uint32_t stored_format_version = DISK_VERSION_INIT;
if (s.GetVersion() & ADDRV2_FORMAT) stored_format_version |= DISK_VERSION_ADDRV2; if (params.enc == Encoding::V2) stored_format_version |= DISK_VERSION_ADDRV2;
READWRITE(stored_format_version); READWRITE(stored_format_version);
stored_format_version &= ~DISK_VERSION_IGNORE_MASK; // ignore low bits stored_format_version &= ~DISK_VERSION_IGNORE_MASK; // ignore low bits
if (stored_format_version == 0) { if (stored_format_version == 0) {
use_v2 = false; use_v2 = false;
} else if (stored_format_version == DISK_VERSION_ADDRV2 && (s.GetVersion() & ADDRV2_FORMAT)) { } else if (stored_format_version == DISK_VERSION_ADDRV2 && params.enc == Encoding::V2) {
// Only support v2 deserialization if ADDRV2_FORMAT is set. // Only support v2 deserialization if V2 is set.
use_v2 = true; use_v2 = true;
} else { } else {
throw std::ios_base::failure("Unsupported CAddress disk format version"); throw std::ios_base::failure("Unsupported CAddress disk format version");
} }
} else { } else {
assert(params.fmt == Format::Network);
// In the network serialization format, the encoding (v1 or v2) is determined directly by // In the network serialization format, the encoding (v1 or v2) is determined directly by
// the value of ADDRV2_FORMAT in the stream version, as no explicitly encoded version // the value of enc in the stream params, as no explicitly encoded version
// exists in the stream. // exists in the stream.
assert(s.GetType() & SER_NETWORK); use_v2 = params.enc == Encoding::V2;
use_v2 = s.GetVersion() & ADDRV2_FORMAT;
} }
READWRITE(Using<LossyChronoFormatter<uint32_t>>(obj.nTime)); READWRITE(Using<LossyChronoFormatter<uint32_t>>(obj.nTime));
@ -432,8 +440,8 @@ public:
READWRITE(Using<CustomUintFormatter<8>>(obj.nServices)); READWRITE(Using<CustomUintFormatter<8>>(obj.nServices));
} }
// Invoke V1/V2 serializer for CService parent object. // Invoke V1/V2 serializer for CService parent object.
OverrideStream<Stream> os(&s, s.GetType(), use_v2 ? ADDRV2_FORMAT : 0); const auto ser_params{use_v2 ? CNetAddr::V2 : CNetAddr::V1};
SerReadWriteMany(os, ser_action, AsBase<CService>(obj)); READWRITE(WithParams(ser_params, AsBase<CService>(obj)));
} }
//! Always included in serialization. The behavior is unspecified if the value is not representable as uint32_t. //! Always included in serialization. The behavior is unspecified if the value is not representable as uint32_t.

View file

@ -697,7 +697,7 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
auto addrman_asmap1_dup = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio); auto addrman_asmap1_dup = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio); auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); DataStream stream{};
CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE); CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
CNetAddr default_source; CNetAddr default_source;
@ -757,7 +757,7 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
// Confirm that invalid addresses are ignored in unserialization. // Confirm that invalid addresses are ignored in unserialization.
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node)); auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); DataStream stream{};
const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE}; const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
const CAddress new2{ResolveService("6.6.6.6"), NODE_NONE}; const CAddress new2{ResolveService("6.6.6.6"), NODE_NONE};
@ -940,9 +940,9 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
BOOST_CHECK(!addr_pos36.tried); BOOST_CHECK(!addr_pos36.tried);
} }
static CDataStream AddrmanToStream(const AddrMan& addrman) static auto AddrmanToStream(const AddrMan& addrman)
{ {
CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION); DataStream ssPeersIn{};
ssPeersIn << Params().MessageStart(); ssPeersIn << Params().MessageStart();
ssPeersIn << addrman; ssPeersIn << addrman;
return ssPeersIn; return ssPeersIn;
@ -972,7 +972,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
BOOST_CHECK(addrman.Size() == 3); BOOST_CHECK(addrman.Size() == 3);
// Test that the de-serialization does not throw an exception. // Test that the de-serialization does not throw an exception.
CDataStream ssPeers1 = AddrmanToStream(addrman); auto ssPeers1{AddrmanToStream(addrman)};
bool exceptionThrown = false; bool exceptionThrown = false;
AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)}; AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
@ -989,7 +989,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
BOOST_CHECK(exceptionThrown == false); BOOST_CHECK(exceptionThrown == false);
// Test that ReadFromStream creates an addrman with the correct number of addrs. // Test that ReadFromStream creates an addrman with the correct number of addrs.
CDataStream ssPeers2 = AddrmanToStream(addrman); DataStream ssPeers2 = AddrmanToStream(addrman);
AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)}; AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.Size() == 0); BOOST_CHECK(addrman2.Size() == 0);
@ -998,9 +998,9 @@ BOOST_AUTO_TEST_CASE(load_addrman)
} }
// Produce a corrupt peers.dat that claims 20 addrs when it only has one addr. // Produce a corrupt peers.dat that claims 20 addrs when it only has one addr.
static CDataStream MakeCorruptPeersDat() static auto MakeCorruptPeersDat()
{ {
CDataStream s(SER_DISK, CLIENT_VERSION); DataStream s{};
s << ::Params().MessageStart(); s << ::Params().MessageStart();
unsigned char nVersion = 1; unsigned char nVersion = 1;
@ -1019,7 +1019,7 @@ static CDataStream MakeCorruptPeersDat()
std::optional<CNetAddr> resolved{LookupHost("252.2.2.2", false)}; std::optional<CNetAddr> resolved{LookupHost("252.2.2.2", false)};
BOOST_REQUIRE(resolved.has_value()); BOOST_REQUIRE(resolved.has_value());
AddrInfo info = AddrInfo(addr, resolved.value()); AddrInfo info = AddrInfo(addr, resolved.value());
s << info; s << WithParams(CAddress::V1_DISK, info);
return s; return s;
} }
@ -1027,7 +1027,7 @@ static CDataStream MakeCorruptPeersDat()
BOOST_AUTO_TEST_CASE(load_addrman_corrupted) BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
{ {
// Test that the de-serialization of corrupted peers.dat throws an exception. // Test that the de-serialization of corrupted peers.dat throws an exception.
CDataStream ssPeers1 = MakeCorruptPeersDat(); auto ssPeers1{MakeCorruptPeersDat()};
bool exceptionThrown = false; bool exceptionThrown = false;
AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)}; AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman1.Size() == 0); BOOST_CHECK(addrman1.Size() == 0);
@ -1041,7 +1041,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
BOOST_CHECK(exceptionThrown); BOOST_CHECK(exceptionThrown);
// Test that ReadFromStream fails if peers.dat is corrupt // Test that ReadFromStream fails if peers.dat is corrupt
CDataStream ssPeers2 = MakeCorruptPeersDat(); auto ssPeers2{MakeCorruptPeersDat()};
AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)}; AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.Size() == 0); BOOST_CHECK(addrman2.Size() == 0);

View file

@ -49,7 +49,7 @@ void initialize_addrman()
FUZZ_TARGET(data_stream_addr_man, .init = initialize_addrman) FUZZ_TARGET(data_stream_addr_man, .init = initialize_addrman)
{ {
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); DataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)}; NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
AddrMan addr_man(netgroupman, /*deterministic=*/false, GetCheckRatio()); AddrMan addr_man(netgroupman, /*deterministic=*/false, GetCheckRatio());
try { try {
@ -78,12 +78,12 @@ CNetAddr RandAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext& f
net = 6; net = 6;
} }
CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); DataStream s{};
s << net; s << net;
s << fast_random_context.randbytes(net_len_map.at(net)); s << fast_random_context.randbytes(net_len_map.at(net));
s >> addr; s >> WithParams(CAddress::V2_NETWORK, addr);
} }
// Return a dummy IPv4 5.5.5.5 if we generated an invalid address. // Return a dummy IPv4 5.5.5.5 if we generated an invalid address.
@ -241,9 +241,7 @@ FUZZ_TARGET(addrman, .init = initialize_addrman)
auto addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider); auto addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider);
if (fuzzed_data_provider.ConsumeBool()) { if (fuzzed_data_provider.ConsumeBool()) {
const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
CDataStream ds(serialized_data, SER_DISK, INIT_PROTO_VERSION); DataStream ds{serialized_data};
const auto ser_version{fuzzed_data_provider.ConsumeIntegral<int32_t>()};
ds.SetVersion(ser_version);
try { try {
ds >> *addr_man_ptr; ds >> *addr_man_ptr;
} catch (const std::ios_base::failure&) { } catch (const std::ios_base::failure&) {
@ -295,7 +293,7 @@ FUZZ_TARGET(addrman, .init = initialize_addrman)
in_new = fuzzed_data_provider.ConsumeBool(); in_new = fuzzed_data_provider.ConsumeBool();
} }
(void)const_addr_man.Size(network, in_new); (void)const_addr_man.Size(network, in_new);
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); DataStream data_stream{};
data_stream << const_addr_man; data_stream << const_addr_man;
} }
@ -309,10 +307,10 @@ FUZZ_TARGET(addrman_serdeser, .init = initialize_addrman)
AddrManDeterministic addr_man1{netgroupman, fuzzed_data_provider}; AddrManDeterministic addr_man1{netgroupman, fuzzed_data_provider};
AddrManDeterministic addr_man2{netgroupman, fuzzed_data_provider}; AddrManDeterministic addr_man2{netgroupman, fuzzed_data_provider};
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); DataStream data_stream{};
FillAddrman(addr_man1, fuzzed_data_provider); FillAddrman(addr_man1, fuzzed_data_provider);
data_stream << addr_man1; data_stream << addr_man1;
data_stream >> addr_man2; data_stream >> addr_man2;
assert(addr_man1 == addr_man2); assert(addr_man1 == addr_man2);
} }

View file

@ -24,6 +24,8 @@
#include <pubkey.h> #include <pubkey.h>
#include <script/keyorigin.h> #include <script/keyorigin.h>
#include <streams.h> #include <streams.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/util/setup_common.h> #include <test/util/setup_common.h>
#include <undo.h> #include <undo.h>
#include <version.h> #include <version.h>
@ -34,8 +36,6 @@
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <test/fuzz/fuzz.h>
using node::SnapshotMetadata; using node::SnapshotMetadata;
namespace { namespace {
@ -62,6 +62,34 @@ namespace {
struct invalid_fuzzing_input_exception : public std::exception { struct invalid_fuzzing_input_exception : public std::exception {
}; };
template <typename T, typename P>
DataStream Serialize(const T& obj, const P& params)
{
DataStream ds{};
ds << WithParams(params, obj);
return ds;
}
template <typename T, typename P>
T Deserialize(DataStream&& ds, const P& params)
{
T obj;
ds >> WithParams(params, obj);
return obj;
}
template <typename T, typename P>
void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj, const P& params)
{
DataStream ds{buffer};
try {
ds >> WithParams(params, obj);
} catch (const std::ios_base::failure&) {
throw invalid_fuzzing_input_exception();
}
assert(buffer.empty() || !Serialize(obj, params).empty());
}
template <typename T> template <typename T>
CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION, const int ser_type = SER_NETWORK) CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION, const int ser_type = SER_NETWORK)
{ {
@ -79,7 +107,7 @@ T Deserialize(CDataStream ds)
} }
template <typename T> template <typename T>
void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optional<int> protocol_version = std::nullopt, const int ser_type = SER_NETWORK) void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj, const std::optional<int> protocol_version = std::nullopt, const int ser_type = SER_NETWORK)
{ {
CDataStream ds(buffer, ser_type, INIT_PROTO_VERSION); CDataStream ds(buffer, ser_type, INIT_PROTO_VERSION);
if (protocol_version) { if (protocol_version) {
@ -101,6 +129,11 @@ void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optio
assert(buffer.empty() || !Serialize(obj).empty()); assert(buffer.empty() || !Serialize(obj).empty());
} }
template <typename T, typename P>
void AssertEqualAfterSerializeDeserialize(const T& obj, const P& params)
{
assert(Deserialize<T>(Serialize(obj, params), params) == obj);
}
template <typename T> template <typename T>
void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION, const int ser_type = SER_NETWORK) void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION, const int ser_type = SER_NETWORK)
{ {
@ -113,10 +146,11 @@ FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, {
BlockFilter block_filter; BlockFilter block_filter;
DeserializeFromFuzzingInput(buffer, block_filter); DeserializeFromFuzzingInput(buffer, block_filter);
}) })
FUZZ_TARGET_DESERIALIZE(addr_info_deserialize, { FUZZ_TARGET(addr_info_deserialize, .init = initialize_deserialize)
AddrInfo addr_info; {
DeserializeFromFuzzingInput(buffer, addr_info); FuzzedDataProvider fdp{buffer.data(), buffer.size()};
}) (void)ConsumeDeserializable<AddrInfo>(fdp, ConsumeDeserializationParams<CAddress::SerParams>(fdp));
}
FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, { FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, {
CBlockFileInfo block_file_info; CBlockFileInfo block_file_info;
DeserializeFromFuzzingInput(buffer, block_file_info); DeserializeFromFuzzingInput(buffer, block_file_info);
@ -197,13 +231,6 @@ FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
bool mutated; bool mutated;
BlockMerkleRoot(block, &mutated); BlockMerkleRoot(block, &mutated);
}) })
FUZZ_TARGET_DESERIALIZE(addrman_deserialize, {
NetGroupManager netgroupman{std::vector<bool>()};
AddrMan am(netgroupman,
/*deterministic=*/false,
g_setup->m_node.args->GetIntArg("-checkaddrman", 0));
DeserializeFromFuzzingInput(buffer, am);
})
FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, { FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {
CBlockHeader bh; CBlockHeader bh;
DeserializeFromFuzzingInput(buffer, bh); DeserializeFromFuzzingInput(buffer, bh);
@ -220,66 +247,62 @@ FUZZ_TARGET_DESERIALIZE(coins_deserialize, {
Coin coin; Coin coin;
DeserializeFromFuzzingInput(buffer, coin); DeserializeFromFuzzingInput(buffer, coin);
}) })
FUZZ_TARGET_DESERIALIZE(netaddr_deserialize, { FUZZ_TARGET(netaddr_deserialize, .init = initialize_deserialize)
CNetAddr na; {
DeserializeFromFuzzingInput(buffer, na); FuzzedDataProvider fdp{buffer.data(), buffer.size()};
const auto maybe_na{ConsumeDeserializable<CNetAddr>(fdp, ConsumeDeserializationParams<CNetAddr::SerParams>(fdp))};
if (!maybe_na) return;
const CNetAddr& na{*maybe_na};
if (na.IsAddrV1Compatible()) { if (na.IsAddrV1Compatible()) {
AssertEqualAfterSerializeDeserialize(na); AssertEqualAfterSerializeDeserialize(na, ConsumeDeserializationParams<CNetAddr::SerParams>(fdp));
} }
AssertEqualAfterSerializeDeserialize(na, INIT_PROTO_VERSION | ADDRV2_FORMAT); AssertEqualAfterSerializeDeserialize(na, CNetAddr::V2);
}) }
FUZZ_TARGET_DESERIALIZE(service_deserialize, { FUZZ_TARGET(service_deserialize, .init = initialize_deserialize)
CService s; {
DeserializeFromFuzzingInput(buffer, s); FuzzedDataProvider fdp{buffer.data(), buffer.size()};
const auto ser_params{ConsumeDeserializationParams<CNetAddr::SerParams>(fdp)};
const auto maybe_s{ConsumeDeserializable<CService>(fdp, ser_params)};
if (!maybe_s) return;
const CService& s{*maybe_s};
if (s.IsAddrV1Compatible()) { if (s.IsAddrV1Compatible()) {
AssertEqualAfterSerializeDeserialize(s); AssertEqualAfterSerializeDeserialize(s, ConsumeDeserializationParams<CNetAddr::SerParams>(fdp));
} }
AssertEqualAfterSerializeDeserialize(s, INIT_PROTO_VERSION | ADDRV2_FORMAT); AssertEqualAfterSerializeDeserialize(s, CNetAddr::V2);
CService s1; if (ser_params.enc == CNetAddr::Encoding::V1) {
DeserializeFromFuzzingInput(buffer, s1, INIT_PROTO_VERSION); assert(s.IsAddrV1Compatible());
AssertEqualAfterSerializeDeserialize(s1, INIT_PROTO_VERSION); }
assert(s1.IsAddrV1Compatible()); }
CService s2;
DeserializeFromFuzzingInput(buffer, s2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
AssertEqualAfterSerializeDeserialize(s2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
})
FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, { FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, {
CMessageHeader mh; CMessageHeader mh;
DeserializeFromFuzzingInput(buffer, mh); DeserializeFromFuzzingInput(buffer, mh);
(void)mh.IsCommandValid(); (void)mh.IsCommandValid();
}) })
FUZZ_TARGET_DESERIALIZE(address_deserialize_v1_notime, { FUZZ_TARGET(address_deserialize, .init = initialize_deserialize)
CAddress a; {
DeserializeFromFuzzingInput(buffer, a, INIT_PROTO_VERSION); FuzzedDataProvider fdp{buffer.data(), buffer.size()};
// A CAddress without nTime (as is expected under INIT_PROTO_VERSION) will roundtrip const auto ser_enc{ConsumeDeserializationParams<CNetAddr::SerParams>(fdp)};
// in all 5 formats (with/without nTime, v1/v2, network/disk) const auto maybe_a{ConsumeDeserializable<CAddress>(fdp, CAddress::SerParams{{ser_enc}, CAddress::Format::Network})};
AssertEqualAfterSerializeDeserialize(a, INIT_PROTO_VERSION); if (!maybe_a) return;
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION); const CAddress& a{*maybe_a};
AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK); // A CAddress in V1 mode will roundtrip
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT); // in all 4 formats (v1/v2, network/disk)
AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK); if (ser_enc.enc == CNetAddr::Encoding::V1) {
}) AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
FUZZ_TARGET_DESERIALIZE(address_deserialize_v1_withtime, { AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
CAddress a; AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION); AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
// A CAddress in V1 mode will roundtrip in all 4 formats that have nTime. } else {
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION); // A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats
AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK); // if it's V1 compatible.
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT); if (a.IsAddrV1Compatible()) {
AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK); AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
}) AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
FUZZ_TARGET_DESERIALIZE(address_deserialize_v2, { }
CAddress a; AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION | ADDRV2_FORMAT); AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
// A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats
// with time if it's V1 compatible.
if (a.IsAddrV1Compatible()) {
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION);
AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK);
} }
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT); }
AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK);
})
FUZZ_TARGET_DESERIALIZE(inv_deserialize, { FUZZ_TARGET_DESERIALIZE(inv_deserialize, {
CInv i; CInv i;
DeserializeFromFuzzingInput(buffer, i); DeserializeFromFuzzingInput(buffer, i);

View file

@ -53,7 +53,7 @@ FUZZ_TARGET(net, .init = initialize_net)
} }
}, },
[&] { [&] {
const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider); const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider, ConsumeDeserializationParams<CNetAddr::SerParams>(fuzzed_data_provider));
if (!service_opt) { if (!service_opt) {
return; return;
} }

View file

@ -36,7 +36,8 @@ FUZZ_TARGET(script_sign, .init = initialize_script_sign)
const std::vector<uint8_t> key = ConsumeRandomLengthByteVector(fuzzed_data_provider, 128); const std::vector<uint8_t> key = ConsumeRandomLengthByteVector(fuzzed_data_provider, 128);
{ {
CDataStream random_data_stream = ConsumeDataStream(fuzzed_data_provider); DataStream stream{ConsumeDataStream(fuzzed_data_provider)};
CDataStream random_data_stream{stream, SER_NETWORK, INIT_PROTO_VERSION}; // temporary copy, to be removed along with the version flag SERIALIZE_TRANSACTION_NO_WITNESS
std::map<CPubKey, KeyOriginInfo> hd_keypaths; std::map<CPubKey, KeyOriginInfo> hd_keypaths;
try { try {
DeserializeHDKeypaths(random_data_stream, key, hd_keypaths); DeserializeHDKeypaths(random_data_stream, key, hd_keypaths);

View file

@ -70,9 +70,9 @@ template<typename B = uint8_t>
return BytesToBits(ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)); return BytesToBits(ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length));
} }
[[nodiscard]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept [[nodiscard]] inline DataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
{ {
return CDataStream{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION}; return DataStream{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)};
} }
[[nodiscard]] inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept [[nodiscard]] inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept
@ -96,6 +96,23 @@ template <typename T>
return r; return r;
} }
template <typename P>
[[nodiscard]] P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcept;
template <typename T, typename P>
[[nodiscard]] std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const P& params, const std::optional<size_t>& max_length = std::nullopt) noexcept
{
const std::vector<uint8_t> buffer{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)};
DataStream ds{buffer};
T obj;
try {
ds >> WithParams(params, obj);
} catch (const std::ios_base::failure&) {
return std::nullopt;
}
return obj;
}
template <typename T> template <typename T>
[[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept [[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
{ {

View file

@ -55,6 +55,27 @@ CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}}; return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};
} }
template <typename P>
P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
constexpr std::array ADDR_ENCODINGS{
CNetAddr::Encoding::V1,
CNetAddr::Encoding::V2,
};
constexpr std::array ADDR_FORMATS{
CAddress::Format::Disk,
CAddress::Format::Network,
};
if constexpr (std::is_same_v<P, CNetAddr::SerParams>) {
return P{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)};
}
if constexpr (std::is_same_v<P, CAddress::SerParams>) {
return P{{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)}, PickValue(fuzzed_data_provider, ADDR_FORMATS)};
}
}
template CNetAddr::SerParams ConsumeDeserializationParams(FuzzedDataProvider&) noexcept;
template CAddress::SerParams ConsumeDeserializationParams(FuzzedDataProvider&) noexcept;
FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider)
: m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()} : m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()}
{ {

View file

@ -327,19 +327,20 @@ BOOST_AUTO_TEST_CASE(cnetaddr_tostring_canonical_ipv6)
BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1) BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1)
{ {
CNetAddr addr; CNetAddr addr;
CDataStream s(SER_NETWORK, PROTOCOL_VERSION); DataStream s{};
const auto ser_params{CAddress::V1_NETWORK};
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000"); BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000");
s.clear(); s.clear();
addr = LookupHost("1.2.3.4", false).value(); addr = LookupHost("1.2.3.4", false).value();
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000ffff01020304"); BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000ffff01020304");
s.clear(); s.clear();
addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value(); addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value();
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "1a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b"); BOOST_CHECK_EQUAL(HexStr(s), "1a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
s.clear(); s.clear();
@ -347,12 +348,12 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1)
BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion")); BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
BOOST_REQUIRE(addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion")); BOOST_REQUIRE(addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000"); BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000");
s.clear(); s.clear();
addr.SetInternal("a"); addr.SetInternal("a");
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "fd6b88c08724ca978112ca1bbdcafac2"); BOOST_CHECK_EQUAL(HexStr(s), "fd6b88c08724ca978112ca1bbdcafac2");
s.clear(); s.clear();
} }
@ -360,22 +361,20 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1)
BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2) BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2)
{ {
CNetAddr addr; CNetAddr addr;
CDataStream s(SER_NETWORK, PROTOCOL_VERSION); DataStream s{};
// Add ADDRV2_FORMAT to the version so that the CNetAddr const auto ser_params{CAddress::V2_NETWORK};
// serialize method produces an address in v2 format.
s.SetVersion(s.GetVersion() | ADDRV2_FORMAT);
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "021000000000000000000000000000000000"); BOOST_CHECK_EQUAL(HexStr(s), "021000000000000000000000000000000000");
s.clear(); s.clear();
addr = LookupHost("1.2.3.4", false).value(); addr = LookupHost("1.2.3.4", false).value();
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "010401020304"); BOOST_CHECK_EQUAL(HexStr(s), "010401020304");
s.clear(); s.clear();
addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value(); addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value();
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b"); BOOST_CHECK_EQUAL(HexStr(s), "02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
s.clear(); s.clear();
@ -383,12 +382,12 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2)
BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion")); BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
BOOST_REQUIRE(addr.SetSpecial("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion")); BOOST_REQUIRE(addr.SetSpecial("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion"));
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "042053cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88"); BOOST_CHECK_EQUAL(HexStr(s), "042053cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88");
s.clear(); s.clear();
BOOST_REQUIRE(addr.SetInternal("a")); BOOST_REQUIRE(addr.SetInternal("a"));
s << addr; s << WithParams(ser_params, addr);
BOOST_CHECK_EQUAL(HexStr(s), "0210fd6b88c08724ca978112ca1bbdcafac2"); BOOST_CHECK_EQUAL(HexStr(s), "0210fd6b88c08724ca978112ca1bbdcafac2");
s.clear(); s.clear();
} }
@ -396,16 +395,14 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2)
BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
{ {
CNetAddr addr; CNetAddr addr;
CDataStream s(SER_NETWORK, PROTOCOL_VERSION); DataStream s{};
// Add ADDRV2_FORMAT to the version so that the CNetAddr const auto ser_params{CAddress::V2_NETWORK};
// unserialize method expects an address in v2 format.
s.SetVersion(s.GetVersion() | ADDRV2_FORMAT);
// Valid IPv4. // Valid IPv4.
s << Span{ParseHex("01" // network type (IPv4) s << Span{ParseHex("01" // network type (IPv4)
"04" // address length "04" // address length
"01020304")}; // address "01020304")}; // address
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsIPv4()); BOOST_CHECK(addr.IsIPv4());
BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK(addr.IsAddrV1Compatible());
@ -416,7 +413,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s << Span{ParseHex("01" // network type (IPv4) s << Span{ParseHex("01" // network type (IPv4)
"04" // address length "04" // address length
"0102")}; // address "0102")}; // address
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, HasReason("end of data")); BOOST_CHECK_EXCEPTION(s >> WithParams(ser_params, addr), std::ios_base::failure, HasReason("end of data"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear(); s.clear();
@ -424,7 +421,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s << Span{ParseHex("01" // network type (IPv4) s << Span{ParseHex("01" // network type (IPv4)
"05" // address length "05" // address length
"01020304")}; // address "01020304")}; // address
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, BOOST_CHECK_EXCEPTION(s >> WithParams(ser_params, addr), std::ios_base::failure,
HasReason("BIP155 IPv4 address with length 5 (should be 4)")); HasReason("BIP155 IPv4 address with length 5 (should be 4)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear(); s.clear();
@ -433,7 +430,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s << Span{ParseHex("01" // network type (IPv4) s << Span{ParseHex("01" // network type (IPv4)
"fd0102" // address length (513 as CompactSize) "fd0102" // address length (513 as CompactSize)
"01020304")}; // address "01020304")}; // address
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, BOOST_CHECK_EXCEPTION(s >> WithParams(ser_params, addr), std::ios_base::failure,
HasReason("Address too long: 513 > 512")); HasReason("Address too long: 513 > 512"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear(); s.clear();
@ -442,7 +439,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s << Span{ParseHex("02" // network type (IPv6) s << Span{ParseHex("02" // network type (IPv6)
"10" // address length "10" // address length
"0102030405060708090a0b0c0d0e0f10")}; // address "0102030405060708090a0b0c0d0e0f10")}; // address
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsIPv6()); BOOST_CHECK(addr.IsIPv6());
BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK(addr.IsAddrV1Compatible());
@ -455,7 +452,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"10" // address length "10" // address length
"fd6b88c08724ca978112ca1bbdcafac2")}; // address: 0xfd + sha256("bitcoin")[0:5] + "fd6b88c08724ca978112ca1bbdcafac2")}; // address: 0xfd + sha256("bitcoin")[0:5] +
// sha256(name)[0:10] // sha256(name)[0:10]
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(addr.IsInternal()); BOOST_CHECK(addr.IsInternal());
BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK(addr.IsAddrV1Compatible());
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "zklycewkdo64v6wc.internal"); BOOST_CHECK_EQUAL(addr.ToStringAddr(), "zklycewkdo64v6wc.internal");
@ -465,7 +462,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s << Span{ParseHex("02" // network type (IPv6) s << Span{ParseHex("02" // network type (IPv6)
"04" // address length "04" // address length
"00")}; // address "00")}; // address
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, BOOST_CHECK_EXCEPTION(s >> WithParams(ser_params, addr), std::ios_base::failure,
HasReason("BIP155 IPv6 address with length 4 (should be 16)")); HasReason("BIP155 IPv6 address with length 4 (should be 16)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear(); s.clear();
@ -474,7 +471,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s << Span{ParseHex("02" // network type (IPv6) s << Span{ParseHex("02" // network type (IPv6)
"10" // address length "10" // address length
"00000000000000000000ffff01020304")}; // address "00000000000000000000ffff01020304")}; // address
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(!addr.IsValid()); BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty()); BOOST_REQUIRE(s.empty());
@ -482,7 +479,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s << Span{ParseHex("02" // network type (IPv6) s << Span{ParseHex("02" // network type (IPv6)
"10" // address length "10" // address length
"fd87d87eeb430102030405060708090a")}; // address "fd87d87eeb430102030405060708090a")}; // address
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(!addr.IsValid()); BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty()); BOOST_REQUIRE(s.empty());
@ -490,7 +487,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
s << Span{ParseHex("03" // network type (TORv2) s << Span{ParseHex("03" // network type (TORv2)
"0a" // address length "0a" // address length
"f1f2f3f4f5f6f7f8f9fa")}; // address "f1f2f3f4f5f6f7f8f9fa")}; // address
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(!addr.IsValid()); BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty()); BOOST_REQUIRE(s.empty());
@ -500,7 +497,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"79bcc625184b05194975c28b66b66b04" // address "79bcc625184b05194975c28b66b66b04" // address
"69f7f6556fb1ac3189a79b40dda32f1f" "69f7f6556fb1ac3189a79b40dda32f1f"
)}; )};
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsTor()); BOOST_CHECK(addr.IsTor());
BOOST_CHECK(!addr.IsAddrV1Compatible()); BOOST_CHECK(!addr.IsAddrV1Compatible());
@ -513,7 +510,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"00" // address length "00" // address length
"00" // address "00" // address
)}; )};
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, BOOST_CHECK_EXCEPTION(s >> WithParams(ser_params, addr), std::ios_base::failure,
HasReason("BIP155 TORv3 address with length 0 (should be 32)")); HasReason("BIP155 TORv3 address with length 0 (should be 32)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear(); s.clear();
@ -523,7 +520,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"20" // address length "20" // address length
"a2894dabaec08c0051a481a6dac88b64" // address "a2894dabaec08c0051a481a6dac88b64" // address
"f98232ae42d4b6fd2fa81952dfe36a87")}; "f98232ae42d4b6fd2fa81952dfe36a87")};
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsI2P()); BOOST_CHECK(addr.IsI2P());
BOOST_CHECK(!addr.IsAddrV1Compatible()); BOOST_CHECK(!addr.IsAddrV1Compatible());
@ -536,7 +533,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"03" // address length "03" // address length
"00" // address "00" // address
)}; )};
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, BOOST_CHECK_EXCEPTION(s >> WithParams(ser_params, addr), std::ios_base::failure,
HasReason("BIP155 I2P address with length 3 (should be 32)")); HasReason("BIP155 I2P address with length 3 (should be 32)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear(); s.clear();
@ -546,7 +543,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"10" // address length "10" // address length
"fc000001000200030004000500060007" // address "fc000001000200030004000500060007" // address
)}; )};
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsCJDNS()); BOOST_CHECK(addr.IsCJDNS());
BOOST_CHECK(!addr.IsAddrV1Compatible()); BOOST_CHECK(!addr.IsAddrV1Compatible());
@ -558,7 +555,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"10" // address length "10" // address length
"aa000001000200030004000500060007" // address "aa000001000200030004000500060007" // address
)}; )};
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(addr.IsCJDNS()); BOOST_CHECK(addr.IsCJDNS());
BOOST_CHECK(!addr.IsValid()); BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty()); BOOST_REQUIRE(s.empty());
@ -568,7 +565,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"01" // address length "01" // address length
"00" // address "00" // address
)}; )};
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, BOOST_CHECK_EXCEPTION(s >> WithParams(ser_params, addr), std::ios_base::failure,
HasReason("BIP155 CJDNS address with length 1 (should be 16)")); HasReason("BIP155 CJDNS address with length 1 (should be 16)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear(); s.clear();
@ -578,7 +575,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"fe00000002" // address length (CompactSize's MAX_SIZE) "fe00000002" // address length (CompactSize's MAX_SIZE)
"01020304050607" // address "01020304050607" // address
)}; )};
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, BOOST_CHECK_EXCEPTION(s >> WithParams(ser_params, addr), std::ios_base::failure,
HasReason("Address too long: 33554432 > 512")); HasReason("Address too long: 33554432 > 512"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input. BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear(); s.clear();
@ -588,7 +585,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"04" // address length "04" // address length
"01020304" // address "01020304" // address
)}; )};
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(!addr.IsValid()); BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty()); BOOST_REQUIRE(s.empty());
@ -597,7 +594,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
"00" // address length "00" // address length
"" // address "" // address
)}; )};
s >> addr; s >> WithParams(ser_params, addr);
BOOST_CHECK(!addr.IsValid()); BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty()); BOOST_REQUIRE(s.empty());
} }
@ -852,7 +849,7 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
std::chrono::microseconds time_received_dummy{0}; std::chrono::microseconds time_received_dummy{0};
const auto msg_version = const auto msg_version =
msg_maker.Make(NetMsgType::VERSION, PROTOCOL_VERSION, services, time, services, peer_us); msg_maker.Make(NetMsgType::VERSION, PROTOCOL_VERSION, services, time, services, WithParams(CAddress::V1_NETWORK, peer_us));
CDataStream msg_version_stream{msg_version.data, SER_NETWORK, PROTOCOL_VERSION}; CDataStream msg_version_stream{msg_version.data, SER_NETWORK, PROTOCOL_VERSION};
m_node.peerman->ProcessMessage( m_node.peerman->ProcessMessage(
@ -875,10 +872,10 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
Span<const unsigned char> data, Span<const unsigned char> data,
bool is_incoming) -> void { bool is_incoming) -> void {
if (!is_incoming && msg_type == "addr") { if (!is_incoming && msg_type == "addr") {
CDataStream s(data, SER_NETWORK, PROTOCOL_VERSION); DataStream s{data};
std::vector<CAddress> addresses; std::vector<CAddress> addresses;
s >> addresses; s >> WithParams(CAddress::V1_NETWORK, addresses);
for (const auto& addr : addresses) { for (const auto& addr : addresses) {
if (addr == expected) { if (addr == expected) {

View file

@ -559,35 +559,35 @@ static constexpr const char* stream_addrv2_hex =
BOOST_AUTO_TEST_CASE(caddress_serialize_v1) BOOST_AUTO_TEST_CASE(caddress_serialize_v1)
{ {
CDataStream s(SER_NETWORK, PROTOCOL_VERSION); DataStream s{};
s << fixture_addresses; s << WithParams(CAddress::V1_NETWORK, fixture_addresses);
BOOST_CHECK_EQUAL(HexStr(s), stream_addrv1_hex); BOOST_CHECK_EQUAL(HexStr(s), stream_addrv1_hex);
} }
BOOST_AUTO_TEST_CASE(caddress_unserialize_v1) BOOST_AUTO_TEST_CASE(caddress_unserialize_v1)
{ {
CDataStream s(ParseHex(stream_addrv1_hex), SER_NETWORK, PROTOCOL_VERSION); DataStream s{ParseHex(stream_addrv1_hex)};
std::vector<CAddress> addresses_unserialized; std::vector<CAddress> addresses_unserialized;
s >> addresses_unserialized; s >> WithParams(CAddress::V1_NETWORK, addresses_unserialized);
BOOST_CHECK(fixture_addresses == addresses_unserialized); BOOST_CHECK(fixture_addresses == addresses_unserialized);
} }
BOOST_AUTO_TEST_CASE(caddress_serialize_v2) BOOST_AUTO_TEST_CASE(caddress_serialize_v2)
{ {
CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); DataStream s{};
s << fixture_addresses; s << WithParams(CAddress::V2_NETWORK, fixture_addresses);
BOOST_CHECK_EQUAL(HexStr(s), stream_addrv2_hex); BOOST_CHECK_EQUAL(HexStr(s), stream_addrv2_hex);
} }
BOOST_AUTO_TEST_CASE(caddress_unserialize_v2) BOOST_AUTO_TEST_CASE(caddress_unserialize_v2)
{ {
CDataStream s(ParseHex(stream_addrv2_hex), SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); DataStream s{ParseHex(stream_addrv2_hex)};
std::vector<CAddress> addresses_unserialized; std::vector<CAddress> addresses_unserialized;
s >> addresses_unserialized; s >> WithParams(CAddress::V2_NETWORK, addresses_unserialized);
BOOST_CHECK(fixture_addresses == addresses_unserialized); BOOST_CHECK(fixture_addresses == addresses_unserialized);
} }

View file

@ -33,9 +33,9 @@ void ConnmanTestMsg::Handshake(CNode& node,
Using<CustomUintFormatter<8>>(remote_services), // Using<CustomUintFormatter<8>>(remote_services), //
int64_t{}, // dummy time int64_t{}, // dummy time
int64_t{}, // ignored service bits int64_t{}, // ignored service bits
CService{}, // dummy WithParams(CNetAddr::V1, CService{}), // dummy
int64_t{}, // ignored service bits int64_t{}, // ignored service bits
CService{}, // ignored WithParams(CNetAddr::V1, CService{}), // ignored
uint64_t{1}, // dummy nonce uint64_t{1}, // dummy nonce
std::string{}, // dummy subver std::string{}, // dummy subver
int32_t{}, // dummy starting_height int32_t{}, // dummy starting_height

View file

@ -36,6 +36,6 @@ static const int INVALID_CB_NO_BAN_VERSION = 70015;
static const int WTXID_RELAY_VERSION = 70016; static const int WTXID_RELAY_VERSION = 70016;
// Make sure that none of the values above collide with // Make sure that none of the values above collide with
// `SERIALIZE_TRANSACTION_NO_WITNESS` or `ADDRV2_FORMAT`. // `SERIALIZE_TRANSACTION_NO_WITNESS`.
#endif // BITCOIN_VERSION_H #endif // BITCOIN_VERSION_H