mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-03 01:33:20 +02:00
Merge bitcoin/bitcoin#20516: Well-defined CAddress disk serialization, and addrv2 anchors.dat
f8866e8c32Add roundtrip fuzz tests for CAddress serialization (Pieter Wuille)e2f0548b52Use addrv2 serialization in anchors.dat (Pieter Wuille)8cd8f37dfeIntroduce well-defined CAddress disk serialization (Pieter Wuille) Pull request description: Alternative to #20509. This makes the `CAddress` disk serialization format well defined, and uses it to enable addrv2 support in anchors.dat (in a way that's compatible with older software). The new format is: - The first 4 bytes store a format version number. Its low 19 bits are ignored (as those historically stored the `CLIENT_VERSION`), but its high 13 bits specify the actual serialization: - 0x00000000: LE64 encoding for `nServices`, V1 encoding for `CService` (like pre-BIP155 network serialization). - 0x20000000: CompactSize encoding for `nServices`, V2 encoding for `CService` (like BIP155 network serialization). - Any other value triggers an unsupported format error on deserialization, and can be used for future format changes. - The `ADDRV2_FORMAT` flag in the stream's version does not determine the actual serialization format; it only sets whether or not V2 encoding is permitted. ACKs for top commit: achow101: ACKf8866e8c32laanwj: Code review ACKf8866e8c32vasild: ACKf8866e8c32jonatack: ACKf8866e8c32tested rebased to master and built/run/restarted with DEBUG_ADDRMAN, peers.dat and anchors ser/deser seems fine hebasto: ACKf8866e8c32, tested on Linux Mint 20.1 (x86_64). Tree-SHA512: 3898f8a8c51783a46dd0aae03fa10060521f5dd6e79315fe95ba807689e78f202388ffa28c40bf156c6f7b1fc2ce806b155dcbe56027df73d039a55331723796
This commit is contained in:
@@ -53,9 +53,9 @@ struct invalid_fuzzing_input_exception : public std::exception {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION)
|
||||
CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION, const int ser_type = SER_NETWORK)
|
||||
{
|
||||
CDataStream ds(SER_NETWORK, version);
|
||||
CDataStream ds(ser_type, version);
|
||||
ds << obj;
|
||||
return ds;
|
||||
}
|
||||
@@ -69,9 +69,9 @@ T Deserialize(CDataStream ds)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optional<int> protocol_version = std::nullopt)
|
||||
void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optional<int> protocol_version = std::nullopt, const int ser_type = SER_NETWORK)
|
||||
{
|
||||
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
|
||||
CDataStream ds(buffer, ser_type, INIT_PROTO_VERSION);
|
||||
if (protocol_version) {
|
||||
ds.SetVersion(*protocol_version);
|
||||
} else {
|
||||
@@ -92,9 +92,9 @@ void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optio
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION)
|
||||
void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION, const int ser_type = SER_NETWORK)
|
||||
{
|
||||
assert(Deserialize<T>(Serialize(obj, version)) == obj);
|
||||
assert(Deserialize<T>(Serialize(obj, version, ser_type)) == obj);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -251,9 +251,37 @@ FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, {
|
||||
DeserializeFromFuzzingInput(buffer, mh);
|
||||
(void)mh.IsCommandValid();
|
||||
})
|
||||
FUZZ_TARGET_DESERIALIZE(address_deserialize, {
|
||||
FUZZ_TARGET_DESERIALIZE(address_deserialize_v1_notime, {
|
||||
CAddress a;
|
||||
DeserializeFromFuzzingInput(buffer, a);
|
||||
DeserializeFromFuzzingInput(buffer, a, INIT_PROTO_VERSION);
|
||||
// A CAddress without nTime (as is expected under INIT_PROTO_VERSION) will roundtrip
|
||||
// in all 5 formats (with/without nTime, v1/v2, network/disk)
|
||||
AssertEqualAfterSerializeDeserialize(a, INIT_PROTO_VERSION);
|
||||
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION);
|
||||
AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK);
|
||||
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT);
|
||||
AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK);
|
||||
})
|
||||
FUZZ_TARGET_DESERIALIZE(address_deserialize_v1_withtime, {
|
||||
CAddress a;
|
||||
DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION);
|
||||
// A CAddress in V1 mode will roundtrip in all 4 formats that have nTime.
|
||||
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION);
|
||||
AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK);
|
||||
AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT);
|
||||
AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK);
|
||||
})
|
||||
FUZZ_TARGET_DESERIALIZE(address_deserialize_v2, {
|
||||
CAddress a;
|
||||
DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION | ADDRV2_FORMAT);
|
||||
// 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, {
|
||||
CInv i;
|
||||
|
||||
Reference in New Issue
Block a user