eth: optimize and add benchmark

This commit is contained in:
Felix Lange 2025-08-27 15:16:46 +02:00
parent 4cef22cba6
commit d6098cc52e
2 changed files with 63 additions and 28 deletions

View file

@ -19,7 +19,6 @@ package eth
import (
"cmp"
"errors"
"hash"
"hash/fnv"
"maps"
"math"
@ -690,7 +689,6 @@ func (st *blockRangeState) currentRange() eth.BlockRangeUpdatePacket {
type broadcastChoice struct {
self enode.ID
hash hash.Hash64
buffer map[*ethPeer]struct{}
tmp []broadcastPeer
}
@ -703,7 +701,6 @@ type broadcastPeer struct {
func newBroadcastChoice(self enode.ID) *broadcastChoice {
return &broadcastChoice{
self: self,
hash: fnv.New64(),
buffer: make(map[*ethPeer]struct{}),
}
}
@ -713,12 +710,13 @@ func newBroadcastChoice(self enode.ID) *broadcastChoice {
func (bc *broadcastChoice) choosePeers(peers []*ethPeer, txSender common.Address) map[*ethPeer]struct{} {
// Compute scores.
bc.tmp = slices.Grow(bc.tmp[:0], len(peers))[:len(peers)]
hash := fnv.New64()
for i, peer := range peers {
bc.hash.Reset()
bc.hash.Write(bc.self[:])
bc.hash.Write(peer.Peer.Peer.ID().Bytes())
bc.hash.Write(txSender[:])
bc.tmp[i] = broadcastPeer{peer, bc.hash.Sum64()}
hash.Reset()
hash.Write(bc.self[:])
hash.Write(peer.Peer.Peer.ID().Bytes())
hash.Write(txSender[:])
bc.tmp[i] = broadcastPeer{peer, hash.Sum64()}
}
// Sort by score.

View file

@ -220,34 +220,18 @@ func (b *testHandler) close() {
}
func TestBroadcastChoice(t *testing.T) {
// Create choices.
self := enode.HexID("1111111111111111111111111111111111111111111111111111111111111111")
choice49 := newBroadcastChoice(self)
choice50 := newBroadcastChoice(self)
// Create test peers.
var (
rand = rand.New(rand.NewSource(33))
peers = make([]*ethPeer, 50)
)
for i := range peers {
var id enode.ID
rand.Read(id[:])
p2pPeer := p2p.NewPeer(id, "test", nil)
ep := eth.NewPeer(eth.ETH69, p2pPeer, nil, nil)
peers[i] = &ethPeer{Peer: ep}
}
defer func() {
for _, p := range peers {
p.Close()
}
}()
// Create random tx sender addresses.
// Create test peers and random tx sender addresses.
rand := rand.New(rand.NewSource(33))
txsenders := make([]common.Address, 400)
for i := range txsenders {
rand.Read(txsenders[i][:])
}
peers := createTestPeers(rand, 50)
defer closePeers(peers)
// Evaluate choice49 first.
expectedCount := 7 // sqrt(49)
@ -280,3 +264,56 @@ func TestBroadcastChoice(t *testing.T) {
}
}
}
func BenchmarkBroadcastChoice(b *testing.B) {
b.Run("50", func(b *testing.B) {
benchmarkBroadcastChoice(b, 50)
})
b.Run("200", func(b *testing.B) {
benchmarkBroadcastChoice(b, 200)
})
b.Run("500", func(b *testing.B) {
benchmarkBroadcastChoice(b, 500)
})
}
// This measures the overhead of sending one transaction to N peers.
func benchmarkBroadcastChoice(b *testing.B, npeers int) {
rand := rand.New(rand.NewSource(33))
peers := createTestPeers(rand, npeers)
defer closePeers(peers)
txsenders := make([]common.Address, b.N)
for i := range txsenders {
rand.Read(txsenders[i][:])
}
self := enode.HexID("1111111111111111111111111111111111111111111111111111111111111111")
choice := newBroadcastChoice(self)
b.ResetTimer()
for i := range b.N {
set := choice.choosePeers(peers, txsenders[i])
if len(set) == 0 {
b.Fatal("empty result")
}
}
}
func createTestPeers(rand *rand.Rand, n int) []*ethPeer {
peers := make([]*ethPeer, n)
for i := range peers {
var id enode.ID
rand.Read(id[:])
p2pPeer := p2p.NewPeer(id, "test", nil)
ep := eth.NewPeer(eth.ETH69, p2pPeer, nil, nil)
peers[i] = &ethPeer{Peer: ep}
}
return peers
}
func closePeers(peers []*ethPeer) {
for _, p := range peers {
p.Close()
}
}