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
Syncing headers with feeler-peers #16859
Comments
Tentative Concept ACK: this seems like a low cost way to make eclipse attacks significantly harder to carry out. Nice idea! Can we think of any drawbacks beyond the small amount of additional bandwidth? What would be the pros/cons of keeping the connect-if-tip-is-stale logic unchanged and only adjust the feeler logic so that feelers sync headers? |
I would break this into two features: Feature one: syncing block headers from feelers: Feature two: evicting stale connections and replacing them with feeler connections: Maybe instead of evicting connections if you get a block header that none of your other peers know about download it from that feeler connection? |
Concept ACK. This is a trivial way to make eclipsing more expensive, and bandwidth overhead is small. Perhaps instead of evicting we should try to tell our peers about this new block? What if they are not attacking us but are just eclipsed too. |
I'm a little confused how this increases eclipse cost -- can't an attacker just fill up the |
So long as the implementation is such that it accepts the block before disconnecting anyone all it would do is let the attacker disconnect essentially one honest peer each of a few nodes per new block they make at the tip, at a considerable cost of their block getting orphaned (unless they can prevent the orphaning with >50% hashpower). This is because as soon as they relay their new block to you, it'll floodfill the honest network (assuming you're connected to it) and that same block won't be usable to cause any other eviction. This depends, however, on actually accepting the block before disconnecting anyone. One simple way to implement that is that eviction could just eliminate outbound peer which least recently sent us a block we accepted (and if none have, the most recently connected). The block-denying-header-making attack would then do nothing interesting, as the new connection would be the one that got evicted even if we learned a header from it. Suhas may have been assuming this because the existing stale tip eviction works that way... if the new stale tip peer didn't help us after all, it'll be the one that gets evicted.
|
I'm kinda thinking out loud here so I apologize for any important details I might have missed. Thanks for that link, if I understand the code correctly after 30 minutes if no block has been announced to us our tip becomes stale. static bool TipMayBeStale(const Consensus::Params &consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
if (g_last_tip_update == 0) {
g_last_tip_update = GetTime();
}
return g_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty();
} https://github.com/bitcoin/bitcoin/blob/master/src/net_processing.cpp#L570-L577 My understanding of the proposed behavior in this issue:When we make a feeler connection to a node A and it has a new block AND our tip is stale, we evict one of our outgoing connections and replace the connection with node A. Assuming I didn't bork up the math the probability that no miner finds a block within 30 minutes is: An attack to exploit this proposed behavior without mining power:Assume an attacker that can get blocks faster than the rest of the p2p network, say by connecting directly to miners and relaying blocks without verifying all the transactions:
Let's say a node makes a feeler connection and waits 90 seconds for a header reply (not sure what the actual time limit is). The probability that a block is announced in that 90 second period is: This attack doesn't require restarts. A well connected attacker could just perform this attack against the entire network slowly getting more outgoing connections until it manages to fully eclipse a node. Attacker nodes would never be replaced as outgoing connections by non-attacker nodes because attacker nodes would always get the blocks first. One positive factor is that while this many make eclipsing easier, it makes an eclipse position harder to exploit because once an attacker begins using their eclipse position to filter the view of a victim node, then the attacker is in danger of being replaced as an outgoing connection due to stale tips. Unfortunately this doesn't help much with eclipse attacks on lightning network participants because the attacker could give the victim node an unfiltered view of the Bitcoin's blockchain but just not rebroadcast breach remedy transactions. |
It occurred to me that we should eliminate the distinction between feelers -- peers we connect to on average every couple minutes to test entries in addrman -- and the extra outbound peers we connect to if our tip is stale (#11560). Instead, why not just sync headers with feeler connections, and if we happen to learn of a new block from that feeler when our tip had been stale, consider evicting an older connection (just as we do with our extra outbounds)?
It seems to me that this should increase the cost to an adversary trying to eclipse a node, because they'd need to control a large fraction of the addrman in order to withhold the most-work chain for any sizeable amount of time.
Moreover since we're already making these feeler connections already, it should be a small amount of additional bandwidth to sync headers with such a peer. (Perhaps we should avoid doing this in IBD...?)
@EthanHeilman Any thoughts?
The text was updated successfully, but these errors were encountered: