Skip to content

Commit f8866e8

Browse files
committed
Add roundtrip fuzz tests for CAddress serialization
1 parent e2f0548 commit f8866e8

File tree

2 files changed

+43
-8
lines changed

2 files changed

+43
-8
lines changed

src/protocol.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,13 @@ class CAddress : public CService
449449
uint32_t nTime{TIME_INIT};
450450
//! Serialized as uint64_t in V1, and as CompactSize in V2.
451451
ServiceFlags nServices{NODE_NONE};
452+
453+
friend bool operator==(const CAddress& a, const CAddress& b)
454+
{
455+
return a.nTime == b.nTime &&
456+
a.nServices == b.nServices &&
457+
static_cast<const CService&>(a) == static_cast<const CService&>(b);
458+
}
452459
};
453460

454461
/** getdata message type flags */

src/test/fuzz/deserialize.cpp

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ struct invalid_fuzzing_input_exception : public std::exception {
5353
};
5454

5555
template <typename T>
56-
CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION)
56+
CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION, const int ser_type = SER_NETWORK)
5757
{
58-
CDataStream ds(SER_NETWORK, version);
58+
CDataStream ds(ser_type, version);
5959
ds << obj;
6060
return ds;
6161
}
@@ -69,9 +69,9 @@ T Deserialize(CDataStream ds)
6969
}
7070

7171
template <typename T>
72-
void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optional<int> protocol_version = std::nullopt)
72+
void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optional<int> protocol_version = std::nullopt, const int ser_type = SER_NETWORK)
7373
{
74-
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
74+
CDataStream ds(buffer, ser_type, INIT_PROTO_VERSION);
7575
if (protocol_version) {
7676
ds.SetVersion(*protocol_version);
7777
} else {
@@ -92,9 +92,9 @@ void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optio
9292
}
9393

9494
template <typename T>
95-
void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION)
95+
void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION, const int ser_type = SER_NETWORK)
9696
{
97-
assert(Deserialize<T>(Serialize(obj, version)) == obj);
97+
assert(Deserialize<T>(Serialize(obj, version, ser_type)) == obj);
9898
}
9999

100100
} // namespace
@@ -251,9 +251,37 @@ FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, {
251251
DeserializeFromFuzzingInput(buffer, mh);
252252
(void)mh.IsCommandValid();
253253
})
254-
FUZZ_TARGET_DESERIALIZE(address_deserialize, {
254+
FUZZ_TARGET_DESERIALIZE(address_deserialize_v1_notime, {
255255
CAddress a;
256-
DeserializeFromFuzzingInput(buffer, a);
256+
DeserializeFromFuzzingInput(buffer, a, INIT_PROTO_VERSION);
257+
// A CAddress without nTime (as is expected under INIT_PROTO_VERSION) will roundtrip
258+
// in all 5 formats (with/without nTime, v1/v2, network/disk)
259+
AssertEqualAfterSerializeDeserialize(a, INIT_PROTO_VERSION);
260+
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION);
261+
AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK);
262+
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT);
263+
AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK);
264+
})
265+
FUZZ_TARGET_DESERIALIZE(address_deserialize_v1_withtime, {
266+
CAddress a;
267+
DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION);
268+
// A CAddress in V1 mode will roundtrip in all 4 formats that have nTime.
269+
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION);
270+
AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK);
271+
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT);
272+
AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK);
273+
})
274+
FUZZ_TARGET_DESERIALIZE(address_deserialize_v2, {
275+
CAddress a;
276+
DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION | ADDRV2_FORMAT);
277+
// A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats
278+
// with time if it's V1 compatible.
279+
if (a.IsAddrV1Compatible()) {
280+
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION);
281+
AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK);
282+
}
283+
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT);
284+
AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK);
257285
})
258286
FUZZ_TARGET_DESERIALIZE(inv_deserialize, {
259287
CInv i;

0 commit comments

Comments
 (0)