-
Notifications
You must be signed in to change notification settings - Fork 37.7k
net: CAddress deser: use stream's version, not what's coming from disk #20509
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
During `CAddress` deserialization we use `nVersion` to decide whether to use CompactSize format for `nServices`. However, that variable `nVersion` is first assigned `s.GetVersion()` and is later overwritten with whatever is coming from disk by `READWRITE(nVersion)`. We should use `s.GetVersion()` instead, which is also used by `READWRITEAS(CService, obj);`, called at the end of `CAddress` deserialization.
This has low impact because, while in theory some disk contents could cause us to deserialize inconsistently, we never create such disk contents.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK a55a338
while here, maybe hoist and make the implicit narrowing conversion explicit (or just hoist to an int)
@@ -370,11 +370,11 @@ public:
{
SER_READ(obj, obj.nTime = TIME_INIT);
int nVersion = s.GetVersion();
- if (s.GetType() & SER_DISK) {
+ bool is_disk_ser{static_cast<bool>(s.GetType() & SER_DISK)};
+ if (is_disk_ser) {
READWRITE(nVersion);
}
- if ((s.GetType() & SER_DISK) ||
- (nVersion != INIT_PROTO_VERSION && !(s.GetType() & SER_GETHASH))) {
+ if (is_disk_ser || (nVersion != INIT_PROTO_VERSION && !(s.GetType() & SER_GETHASH))) {
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
This looks wrong? If the disk has a non-addrv2 format, we shouldn't try to deserialise it as such... |
@luke-jr well, the assumption is that the version is set properly in the stream by the caller (this is the case in the current SERIALIZE_METHODS(CAddress, obj)
{
...
int nVersion = s.GetVersion();
if (s.GetType() & SER_DISK) {
READWRITE(nVersion); // Saves the disk contents into nVersion
}
...
if (nVersion & ADDRV2_FORMAT) { // Uses nVersion (== disk contents) [1]
...
}
READWRITEAS(CService, obj); // Uses s.GetVersion() [2]
} [1] and [2] should use the same variable. This PR changes [1] to use It would also be possible to change [2] to use the "disk contents": + const int stream_version_orig = s.GetVersion();
+ SER_READ(obj, if (s.GetType() & SER_DISK) { s.SetVersion(nVersion); });
READWRITEAS(CService, obj);
+ SER_READ(obj, if (s.GetType() & SER_DISK) { s.SetVersion(stream_version_orig); });
} But then one could ask a counter question to yours: "If the stream has a non-addrv2 format, we shouldn't try to deserialise it as such... (in [2])". Maybe compare the stream format with disk contents and if they don't both have ADDRV2_FORMAT set (or not set), then throw? If #20516 gets merged, then this PR would be obsolete and can be closed. |
…chors.dat f8866e8 Add roundtrip fuzz tests for CAddress serialization (Pieter Wuille) e2f0548 Use addrv2 serialization in anchors.dat (Pieter Wuille) 8cd8f37 Introduce 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: ACK f8866e8 laanwj: Code review ACK f8866e8 vasild: ACK f8866e8 jonatack: ACK f8866e8 tested rebased to master and built/run/restarted with DEBUG_ADDRMAN, peers.dat and anchors ser/deser seems fine hebasto: ACK f8866e8, tested on Linux Mint 20.1 (x86_64). Tree-SHA512: 3898f8a8c51783a46dd0aae03fa10060521f5dd6e79315fe95ba807689e78f202388ffa28c40bf156c6f7b1fc2ce806b155dcbe56027df73d039a55331723796
🐙 This pull request conflicts with the target branch and needs rebase. Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a "draft". |
Following the merge of #20516, maybe this PR can be closed IIUC. |
…drv2 anchors.dat f8866e8 Add roundtrip fuzz tests for CAddress serialization (Pieter Wuille) e2f0548 Use addrv2 serialization in anchors.dat (Pieter Wuille) 8cd8f37 Introduce well-defined CAddress disk serialization (Pieter Wuille) Pull request description: Alternative to bitcoin#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: ACK f8866e8 laanwj: Code review ACK f8866e8 vasild: ACK f8866e8 jonatack: ACK f8866e8 tested rebased to master and built/run/restarted with DEBUG_ADDRMAN, peers.dat and anchors ser/deser seems fine hebasto: ACK f8866e8, tested on Linux Mint 20.1 (x86_64). Tree-SHA512: 3898f8a8c51783a46dd0aae03fa10060521f5dd6e79315fe95ba807689e78f202388ffa28c40bf156c6f7b1fc2ce806b155dcbe56027df73d039a55331723796
@vasild Closing for now |
During
CAddress
deserialization we usenVersion
to decide whether touse CompactSize format for
nServices
. However, that variablenVersion
is first assigned
s.GetVersion()
and is later overwritten withwhatever is coming from disk by
READWRITE(nVersion)
.We should use
s.GetVersion()
instead, which is also used byREADWRITEAS(CService, obj);
, called at the end ofCAddress
deserialization.