Skip to content

eth: stabilize tx relay peer selection #31714

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions eth/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ const (
// All transactions with a higher size will be announced and need to be fetched
// by the peer.
txMaxBroadcastSize = 4096

// Hysteresis to stabilize the number of direct peers to send transactions to.
directPeersHysteresis = 0.5
)

var syncChallengeTimeout = 15 * time.Second // Time allowance for a node to reply to the sync progress challenge
Expand Down Expand Up @@ -110,10 +113,11 @@ type handler struct {
snapSync atomic.Bool // Flag whether snap sync is enabled (gets disabled if we already have blocks)
synced atomic.Bool // Flag whether we're considered synchronised (enables transaction processing)

database ethdb.Database
txpool txPool
chain *core.BlockChain
maxPeers int
database ethdb.Database
txpool txPool
chain *core.BlockChain
maxPeers int
lastDirect atomic.Int64 // Last number of peers we sent transactions to, used to stabilize the randomness

downloader *downloader.Downloader
txFetcher *fetcher.TxFetcher
Expand Down Expand Up @@ -477,11 +481,21 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) {
annos = make(map[*ethPeer][]common.Hash) // Set peer->hash to announce
)
// Broadcast transactions to a batch of peers not knowing about it
direct := big.NewInt(int64(math.Sqrt(float64(h.peers.len())))) // Approximate number of peers to broadcast to
if direct.BitLen() == 0 {
direct = big.NewInt(1)
sqrtPeers := math.Sqrt(float64(h.peers.len())) // Approximate number of peers to broadcast to

// Use some hysteresis to avoid oscillating between two values, stabilising the modulus in the peer selection
// If the number of peers is small, use a minimum of 1 peer
var directInt int64
lastDirect := h.lastDirect.Load()
if int64(sqrtPeers) >= lastDirect {
directInt = max(int64(sqrtPeers), 1)
} else {
directInt = max(min(int64(sqrtPeers+directPeersHysteresis), lastDirect), 1)
}
total := new(big.Int).Exp(direct, big.NewInt(2), nil) // Stabilise total peer count a bit based on sqrt peers
h.lastDirect.Store(directInt)

direct := big.NewInt(directInt) // Number of peers to send directly to
total := big.NewInt(directInt * directInt) // Stabilise total peer count a bit based on sqrt peers

var (
signer = types.LatestSigner(h.chain.Config()) // Don't care about chain status, we just need *a* sender
Expand Down