package peers import ( "crypto/ecdsa" "net" "sync" "time" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/discv5" ) // Discovery is an abstract interface for using different discovery providers. type Discovery interface { Running() bool Start() error Stop() error Register(topic string, stop chan struct{}) error Discover(topic string, period <-chan time.Duration, found chan<- *discv5.Node, lookup chan<- bool) error } // NewDiscV5 creates instances of discovery v5 facade. func NewDiscV5(prv *ecdsa.PrivateKey, laddr string, bootnodes []*discv5.Node) *DiscV5 { return &DiscV5{ prv: prv, laddr: laddr, bootnodes: bootnodes, } } // DiscV5 is a facade for ethereum discv5 implementation. type DiscV5 struct { mu sync.Mutex net *discv5.Network prv *ecdsa.PrivateKey laddr string bootnodes []*discv5.Node } // Running returns true if v5 server is started. func (d *DiscV5) Running() bool { d.mu.Lock() defer d.mu.Unlock() return d.net != nil } // Start creates v5 server and stores pointer to it. func (d *DiscV5) Start() error { d.mu.Lock() defer d.mu.Unlock() log.Debug("Starting discovery", "listen address", d.laddr) addr, err := net.ResolveUDPAddr("udp", d.laddr) if err != nil { return err } conn, err := net.ListenUDP("udp", addr) if err != nil { return err } realaddr := conn.LocalAddr().(*net.UDPAddr) ntab, err := discv5.ListenUDP(d.prv, conn, realaddr, "", nil) if err != nil { return err } if err := ntab.SetFallbackNodes(d.bootnodes); err != nil { return err } d.net = ntab return nil } // Stop closes v5 server listener and removes pointer. func (d *DiscV5) Stop() error { d.mu.Lock() defer d.mu.Unlock() if d.net == nil { return nil } d.net.Close() d.net = nil return nil } // Register creates a register request in v5 server. // It will block until stop is closed. func (d *DiscV5) Register(topic string, stop chan struct{}) error { d.net.RegisterTopic(discv5.Topic(topic), stop) return nil } // Discover creates search request in v5 server. Results will be published to found channel. // It will block until period is closed. func (d *DiscV5) Discover(topic string, period <-chan time.Duration, found chan<- *discv5.Node, lookup chan<- bool) error { d.net.SearchTopic(discv5.Topic(topic), period, found, lookup) return nil }