Skip to content
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

eth: dial nodes from discv5 #30302

Merged
merged 6 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
65 changes: 41 additions & 24 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"math/big"
"runtime"
"sync"
"time"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -64,15 +65,13 @@ type Config = ethconfig.Config

// Ethereum implements the Ethereum full node service.
type Ethereum struct {
config *ethconfig.Config
// core protocol objects
config *ethconfig.Config
txPool *txpool.TxPool
blockchain *core.BlockChain

// Handlers
txPool *txpool.TxPool

blockchain *core.BlockChain
handler *handler
ethDialCandidates enode.Iterator
snapDialCandidates enode.Iterator
handler *handler
discmix *enode.FairMix

// DB interfaces
chainDb ethdb.Database // Block chain database
Expand Down Expand Up @@ -162,6 +161,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
p2pServer: stack.Server(),
discmix: enode.NewFairMix(2 * time.Second),
lightclient marked this conversation as resolved.
Show resolved Hide resolved
shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb),
}
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
Expand Down Expand Up @@ -266,17 +266,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
}
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice)

// Setup DNS discovery iterators.
dnsclient := dnsdisc.NewClient(dnsdisc.Config{})
eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...)
if err != nil {
return nil, err
}
eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...)
if err != nil {
return nil, err
}

// Start the RPC service
eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID)

Expand Down Expand Up @@ -359,17 +348,17 @@ func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer }
// Protocols returns all the currently configured
// network protocols to start.
func (s *Ethereum) Protocols() []p2p.Protocol {
protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates)
protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.discmix)
if s.config.SnapshotCache > 0 {
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...)
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler))...)
}
return protos
}

// Start implements node.Lifecycle, starting all internal goroutines needed by the
// Ethereum protocol implementation.
func (s *Ethereum) Start() error {
eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode())
s.setupDiscovery()

// Start the bloom bits servicing goroutines
s.startBloomHandlers(params.BloomBitsBlocks)
Expand All @@ -382,12 +371,40 @@ func (s *Ethereum) Start() error {
return nil
}

func (s *Ethereum) setupDiscovery() error {
eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode())

dnsclient := dnsdisc.NewClient(dnsdisc.Config{})
if len(s.config.EthDiscoveryURLs) > 0 {
iter, err := dnsclient.NewIterator(s.config.EthDiscoveryURLs...)
if err != nil {
return err
}
s.discmix.AddSource(iter)
}

if len(s.config.SnapDiscoveryURLs) > 0 {
iter, err := dnsclient.NewIterator(s.config.SnapDiscoveryURLs...)
if err != nil {
return err
}
s.discmix.AddSource(iter)
}

if s.p2pServer.DiscoveryV5() != nil {
filter := eth.NewNodeFilter(s.blockchain)
iter := enode.Filter(s.p2pServer.DiscoveryV5().RandomNodes(), filter)
s.discmix.AddSource(iter)
}

return nil
}

// Stop implements node.Lifecycle, terminating all internal goroutines used by the
// Ethereum protocol.
func (s *Ethereum) Stop() error {
// Stop all the peer-related stuff first.
s.ethDialCandidates.Close()
s.snapDialCandidates.Close()
s.discmix.Close()
s.handler.Stop()

// Then stop everything else.
Expand Down
14 changes: 14 additions & 0 deletions eth/protocols/eth/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,17 @@ func currentENREntry(chain *core.BlockChain) *enrEntry {
ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time),
}
}

// NewNodeFilter returns a filtering function that returns whether the provided
// enode advertises a forkid compatible with the current chain.
func NewNodeFilter(chain *core.BlockChain) func(*enode.Node) bool {
filter := forkid.NewFilter(chain)
return func(n *enode.Node) bool {
var entry enrEntry
if err := n.Load(entry); err != nil {
return false
}
err := filter(entry.ForkID)
return err == nil
}
}
3 changes: 1 addition & 2 deletions eth/protocols/eth/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2
PeerInfo: func(id enode.ID) interface{} {
return backend.PeerInfo(id)
},
Attributes: []enr.Entry{currentENREntry(backend.Chain())},
DialCandidates: dnsdisc,
Attributes: []enr.Entry{currentENREntry(backend.Chain())},
})
}
return protocols
Expand Down
11 changes: 2 additions & 9 deletions eth/protocols/snap/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,7 @@ type Backend interface {
}

// MakeProtocols constructs the P2P protocol definitions for `snap`.
func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol {
// Filter the discovery iterator for nodes advertising snap support.
dnsdisc = enode.Filter(dnsdisc, func(n *enode.Node) bool {
var snap enrEntry
return n.Load(&snap) == nil
})

func MakeProtocols(backend Backend) []p2p.Protocol {
protocols := make([]p2p.Protocol, len(ProtocolVersions))
for i, version := range ProtocolVersions {
version := version // Closure
Expand All @@ -108,8 +102,7 @@ func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol {
PeerInfo: func(id enode.ID) interface{} {
return backend.PeerInfo(id)
},
Attributes: []enr.Entry{&enrEntry{}},
DialCandidates: dnsdisc,
Attributes: []enr.Entry{&enrEntry{}},
}
}
return protocols
Expand Down