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
[p2p] Reduce addr blackholes #21528
[p2p] Reduce addr blackholes #21528
Conversation
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. |
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.
Concept ACK. Thanks for implementing this!
You've introduced a tiny thread safety issue by accessing m_addr_known
from multiple threads without a lock. Y'know, this'd be much tidier if the addr data was all contained in net_processing 😁
I think that an approach like this was first suggested by AJ in #15759 (comment):
I think it's a good idea, since it stops us relaying addrs to both inbound block-relay-only peers and other kinds of black holes. |
bcb89d9
to
8e2bcc0
Compare
fixed tests & added a test. patch is ready, but leaving as a draft until I gain more confidence that this would not break any other software on the network. compiling a list of other clients & compatibility with this patch:
|
8e2bcc0
to
0c194ff
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.
Concept ACK to making an effort not to send addrs to peers that will likely ignore them. By "disrupt other software on the network," is the concern that some nodes who aren't immediately active in addr-related dialogue might be skipped over and not hear about addrs?
At first I was confused because I figured a lot of nodes don't care about advertising their own addr (e.g. bootstrapping, in IBD, maybe not accepting inbounds). But it seems like a node making a full relay outbound will always send its own addr and a getaddr, and should thus immediately be a candidate for getting addrs forwarded to it (is this accurate?). Was there a version of Bitcoin Core that didn't send addr stuff after getting VERSION
from outbound?
src/net_processing.cpp
Outdated
@@ -3569,6 +3584,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, | |||
} | |||
pfrom.fSentAddr = true; | |||
|
|||
SetupAddressRelay(pfrom); | |||
|
|||
pfrom.vAddrToSend.clear(); |
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.
Side question: why do we clear this list here instead of appending to it, given that PushAddress
and SendMessages
filter for duplicates?
@glozow The concern would be other Bitcoin node implementations which don't send addr/getaddr, but do care about receiving them. I don't think that's particularly likely, but it's also hard to be sure there are none. |
Concept ACK |
Concept ACK Need to review surrounding code more, and run the tests. Looks good so far! |
a732ee3 [test] Add tests for addr relay in -blocksonly mode (Amiti Uttarwar) a6694ea [test] Add address relay tests involving outbound peers (Martin Zumsande) 8188b77 [test] Add tests for getaddr behavior (Martin Zumsande) d2dbfe6 [test] Extract sending an addr message into a helper (Amiti Uttarwar) c991943 [test] Refactor the addr relay test to prepare for new tests (Amiti Uttarwar) Pull request description: This extends the functional test `p2p_addr_relay.py`. It adds test coverage for address relay involving outbound peers, tests for both outgoing and incoming `GETADDR` requests and tests for `-blocksonly` mode. The initial refactors and some of the new tests were taken from Amiti Uttarwar's PR bitcoin#21528 - they are general test improvements not directly tied to the change proposed there. ACKs for top commit: amitiuttarwar: re-ACK a732ee3, small diff based on code review MarcoFalke: Concept ACK a732ee3 🌊 Tree-SHA512: e80d52683808ddd6b948a5134239f002f3fecf61b60e187877b07be6251721fde847104e495c75a1a5133a09c0b41a9255a0bec82932c0b304b516fa89bce33e
Reiterating my concept ACK on this. Reducing the number of addr black holes seems like a good win for addr gossipping across the network. This branch needs rebase now that the addr data has been moved up into net_processing. I'd be very happy to help with that if you need a hand. |
I think this was somewhat pending being sure it wouldn't break bitcore (see bitpay/bitcore#3140) which now looks like it's now resolved. |
Thanks!
Indeed. I'm now working to rebase & bring this PR out of draft. I've rebased locally but am working through some test failures, I hope to have this ready for review by early next week. PS: I also investigated bitcoinj & opened an issue on their repo, they also seem compatible 🎉. |
Use SetupAddressRelay to only initialize `m_addr_known` as needed. For outbound peers, we initialize the filter before sending our self announcement (not applicable for block-relay-only connections). For inbound peers, we initialize the filter when we get an addr related message (ADDR, ADDRV2, GETADDR). These changes intend to mitigate address blackholes. Since an inbound peer has to send us an addr related message to become eligible as a candidate for addr relay, this should reduce our likelihood of sending them self-announcements.
Now that we have a simple boolean stored on the field, the wrapper function is no longer necessary.
This test checks that we only relay addresses with inbound peers who have sent us an addr related message. Uses a combination of GETADDR and ADDR to verify when peers are eligible.
00a54cb
to
3f7250b
Compare
thanks @MarcoFalke, addressed your comments |
reACK 3f7250b Only changes are addressing review comments from Marco. |
ACK 3f7250b Compared the |
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.
@@ -167,6 +179,9 @@ def relay_tests(self): | |||
# of the outbound peer which is often sent before the GETADDR response. | |||
assert_equal(inbound_peer.num_ipv4_received, 0) | |||
|
|||
# Send an empty ADDR message to intialize address relay on this connection. |
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.
s/intialize/initialize
Maybe add a line to the release notes saying that inbound peers will never receive address messages unless they send ADDR, ADDRV2, or GETADDR themselves? |
@@ -11,14 +11,15 @@ | |||
NODE_NETWORK, | |||
NODE_WITNESS, | |||
msg_addr, | |||
msg_getaddr | |||
msg_getaddr, | |||
msg_verack |
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: Would be nice to always add a trailing comma to avoid ugly diffs and keeping the git blame
depth lower in the future.
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.
noted
Added in #22618, thanks :) |
And fix a typo in the test.
And fix a typo in the test.
9778b0f [net_processing] Provide debug error if code assumptions change. (Amiti Uttarwar) aa79c91 [docs] Add release notes for #21528 (Amiti Uttarwar) Pull request description: Adds a release note & addresses [this](bitcoin/bitcoin#21528 (comment)) review comment to make expectations more explicit. ACKs for top commit: Zero-1729: re-ACK 9778b0f jonatack: ACK 9778b0f Tree-SHA512: 9507df5f2746d05c6df8c86b7a19364610ebfafc81af7650be7e68d7536a0685cce9fd2e5f287ef92b6245c584f8875b24a958109ba5bd8acf3c8fc9fd19eef2
Summary: ``` This PR aims to reduce addr blackholes. When we receive an addr message that contains 10 or less addresses, we forward them to 1-2 peers. This is the main technique we use for self advertisements, so sending to peers that wouldn't relay would effectively "blackhole" the trickle. Although we cannot prevent this in a malicious case, we can improve it for the normal, honest cases, and reduce the overall likelihood of occurrence. Two known cases where peers would not participate in addr relay are if they have connected to you as a block-relay-only connection, or if they are a light client. This implementation defers initialization of m_addr_known until it is needed, then uses its presence to decide if the peer is participating in addr relay. For outbound (not block-relay-only) peers, we initialize the filter before sending the initial self announcement when processing their version message. For inbound peers, we initialize the filter if/when we get an addr related message (ADDR, ADDRV2, GETADDR). We do NOT initialize the filter based on a SENDADDRV2 message. ``` Backport of [[bitcoin/bitcoin#21528 | core#21528]]. Ref T1696. Test Plan: ninja all check-all Reviewers: #bitcoin_abc, tyler-smith Reviewed By: #bitcoin_abc, tyler-smith Subscribers: tyler-smith Maniphest Tasks: T1696 Differential Revision: https://reviews.bitcoinabc.org/D10933
This PR builds on the test refactors extracted into #22306 (first 5 commits).
This PR aims to reduce addr blackholes. When we receive an
addr
message that contains 10 or less addresses, we forward them to 1-2 peers. This is the main technique we use for self advertisements, so sending to peers that wouldn't relay would effectively "blackhole" the trickle. Although we cannot prevent this in a malicious case, we can improve it for the normal, honest cases, and reduce the overall likelihood of occurrence. Two known cases where peers would not participate in addr relay are if they have connected to you as a block-relay-only connection, or if they are a light client.This implementation defers initialization of
m_addr_known
until it is needed, then uses its presence to decide if the peer is participating in addr relay. For outbound (not block-relay-only) peers, we initialize the filter before sending the initial self announcement when processing theirversion
message. For inbound peers, we initialize the filter if/when we get an addr related message (ADDR
,ADDRV2
,GETADDR
). We do NOT initialize the filter based on aSENDADDRV2
message.To communicate about these changes beyond bitcoin core & to (try to) ensure that no other software would be disrupted, I have: