-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Use std::chrono for the time to rotate destination of addr messages + tests #18642
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
Use std::chrono for the time to rotate destination of addr messages + tests #18642
Conversation
@sipa btw, take a look at how hashAddr was fed to the hasher twice (with a shift, yeah). |
3c8319f
to
8690d40
Compare
@naumenkogs It was very inscrutable code, but the construction with double-hashing the address hash was by design. The idea is that the address both influences the hash directly, but also determines when the "reset time of the day" is (by including hashaddr in The shifting is pointless, we should get rid of it. It seems to be a silly evolution of this 2010 Satoshi code: 5cbf753 (where it made sense because everything was XORed together, and the address used the high bits, while the time used the low ones). |
8690d40
to
ea6a2fd
Compare
Updated the code with suggestion by @sipa, and simplified tests. |
ea6a2fd
to
cca35ff
Compare
40c7baf
to
ae5eaf5
Compare
ae5eaf5
to
72c4db3
Compare
72c4db3
to
8f0355e
Compare
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsNo conflicts as of last run. |
8f0355e
to
d1ede75
Compare
d1ede75
to
ab4107a
Compare
ab4107a
to
177df94
Compare
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.
(Tested) Concept ACK.
Some questions and style/PEP8 comments below, feel free to ignore.
src/net_processing.cpp
Outdated
|
||
std::chrono::seconds current_time = GetTime<std::chrono::seconds>(); | ||
// Adding address hash makes exact rotation time different per address, while preserving periodicity. | ||
uint64_t time_addr = static_cast<uint64_t>((current_time + std::chrono::seconds{static_cast<int64_t>(hashAddr)}) / ROTATE_ADDR_RELAY_DEST_INTERVAL); |
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.
nit: Can this be simpler? It's more code and (even with the removed bit shifting) a bit more complex to understand.
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.
We iterated over this line a couple times with @MarcoFalke, so I'm out of ideas here.
Open to suggestions!
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.
Annoyingly, I think this is UB, as hashAddr may exceed 2^63, and casting a larger number to a signed 64-bit integer would be outside its range (and overflowing signed integers is undefined behavior).
Suggestion: uint64_t time_addr = (current_time + std::chrono::seconds{hashAddr % ROTATE_ADDR_RELAY_DEST_INTERVAL.count()}) / ROTATE_ADDR_RELAY_DEST_INTERVAL;
, and make ROTATE_ADDR_RELAY_DEST_INTERVAL
to be of type std::chrono::seconds
.
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.
This isn't resolved actually; it's still casting hashAddr
from uint64_t
to int64_t
, which is implementation-defined behavior if it overflows (I was wrong claiming earlier that it was UB; arithmetic that overflows signed types is UB, but just the conversion to a signed type is at worst implementation-defined).
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.
We're constructing a std::chrono::seconds
from an int64_t
, but according to https://en.cppreference.com/w/cpp/chrono/duration, std::chrono::seconds
is only guaranteed to have 35 bits -- is this problematic?
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.
Uh, right. I think that could be a problem. This will need something like
uint64_t time_addr = (uint64_t{current_time / std::chrono::seconds{1}} + hashAddr) / (ROTATE_ADDR_RELAY_DEST_INTERVAL / std::chrono::seconds{1});
(I prefer using x / std::chrono::seconds{1}
over x.count()
to get the number of seconds of x
, as the former expression remains meaningful if the type of x
changes to something other than std::chrono::seconds
).
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.
My understanding was that std::chrono::seconds{int64_t{}}
wouldn't compile on platforms where seconds isn't backed by at least 64 bits. I don't expect any such platform to exist.
@ sipa there is also a count_seconds()
helper.
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.
Github is weird, I found this un-resolved issue totally accidentally...
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.
Okay the latest version should be safe?
177df94
to
72d7e24
Compare
@jonatack addressed all the things. |
It would be good to reply to the comments. Either addressing them or denying/closing them. |
Or alternatively submit the test in a separate pull request, since this is refactoring, so the test should already pass on master. |
7ba6b19
to
b3c71ea
Compare
Just to note |
b3c71ea
to
fca9977
Compare
…RelayAddress fa9f455 refactor: Remove pointless and confusing shift in RelayAddress (MarcoFalke) Pull request description: The second argument written to the siphash is already quantized to 24 hours, so it seems confusing to quantize the first argument to 32 bits (out of 64 bits). > The shifting is pointless, we should get rid of it. It seems to be a silly evolution of this 2010 Satoshi code: 5cbf753 (where it made sense because everything was XORed together, and the address used the high bits, while the time used the low ones). (Copied from bitcoin/bitcoin#18642 (comment)) (The original code was `uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));`) This also allows to remove a integer sanitizer suppression for the whole file. ACKs for top commit: laanwj: Code review ACK fa9f455 sipa: utACK fa9f455 promag: Code review ACK fa9f455. Tree-SHA512: f5fd107464ccd839d6749aed6914b4935e39ab42906546b3f3810a7339fc4633fef931a1783a287572af5ec64525626fa91d147d8ff52eb076740465bf5cf839
…ress fa9f455 refactor: Remove pointless and confusing shift in RelayAddress (MarcoFalke) Pull request description: The second argument written to the siphash is already quantized to 24 hours, so it seems confusing to quantize the first argument to 32 bits (out of 64 bits). > The shifting is pointless, we should get rid of it. It seems to be a silly evolution of this 2010 Satoshi code: 5cbf753 (where it made sense because everything was XORed together, and the address used the high bits, while the time used the low ones). (Copied from bitcoin#18642 (comment)) (The original code was `uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));`) This also allows to remove a integer sanitizer suppression for the whole file. ACKs for top commit: laanwj: Code review ACK fa9f455 sipa: utACK fa9f455 promag: Code review ACK fa9f455. Tree-SHA512: f5fd107464ccd839d6749aed6914b4935e39ab42906546b3f3810a7339fc4633fef931a1783a287572af5ec64525626fa91d147d8ff52eb076740465bf5cf839
c4a4eba
to
f6177ff
Compare
f6177ff
to
f2de1b2
Compare
Check that within 24h addr of a given node is forwarded to the same peer(s), and then the destination is rotated every 24h. Co-authored-by: Jon Atack <jon@atack.com>
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.
@naumenkogs if helpful, here is a rebase of this pull: https://github.com/jonatack/bitcoin/commits/pr18642-rebase-to-master-at-e04720e. If you don't have time to update this in a week or so, I'll open a PR for you with the same commits.
f2de1b2
to
2ff8f4d
Compare
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 2ff8f4d
We currently assign a destination peer for relaying particular addresses of nodes every 24 hours, and then rotate. This is done for rate-limiting (ultimately for privacy leak reduction I think?).
Before this change, 24 hours was defined as uint. I replaced it with std::chrono, which is mockable and type-safe.
Also added couple tests for this behavior.