diff --git a/discovery/rendezvous.go b/discovery/rendezvous.go index 4b10ec85b..ad6dc5810 100644 --- a/discovery/rendezvous.go +++ b/discovery/rendezvous.go @@ -3,6 +3,7 @@ package discovery import ( "context" "crypto/ecdsa" + "errors" "math/rand" "net" "sync" @@ -22,20 +23,18 @@ const ( bucketSize = 10 ) +var ( + errNodeIsNil = errors.New("node cannot be nil") + errIdentityIsNil = errors.New("identity cannot be nil") +) + func NewRendezvous(servers []ma.Multiaddr, identity *ecdsa.PrivateKey, node *discover.Node) (*Rendezvous, error) { r := new(Rendezvous) + r.node = node + r.identity = identity r.servers = servers r.registrationPeriod = registrationPeriod r.bucketSize = bucketSize - - r.record = enr.Record{} - r.record.Set(enr.IP(node.IP)) - r.record.Set(enr.TCP(node.TCP)) - r.record.Set(enr.UDP(node.UDP)) - // public key is added to ENR when ENR is signed - if err := enr.SignV4(&r.record, identity); err != nil { - return nil, err - } return r, nil } @@ -44,7 +43,7 @@ func NewRendezvousWithENR(servers []ma.Multiaddr, record enr.Record) *Rendezvous r.servers = servers r.registrationPeriod = registrationPeriod r.bucketSize = bucketSize - r.record = record + r.record = &record return r } @@ -62,7 +61,11 @@ type Rendezvous struct { servers []ma.Multiaddr registrationPeriod time.Duration bucketSize int - record enr.Record + node *discover.Node + identity *ecdsa.PrivateKey + + recordMu sync.Mutex + record *enr.Record // record is set directly if rendezvous is used in proxy mode } func (r *Rendezvous) Running() bool { @@ -93,7 +96,30 @@ func (r *Rendezvous) Stop() error { return nil } -func (r *Rendezvous) register(topic string) error { +func (r *Rendezvous) MakeRecord() (record enr.Record, err error) { + r.recordMu.Lock() + defer r.recordMu.Unlock() + if r.record != nil { + return *r.record, nil + } + if r.node == nil { + return record, errNodeIsNil + } + if r.identity == nil { + return record, errIdentityIsNil + } + record.Set(enr.IP(r.node.IP)) + record.Set(enr.TCP(r.node.TCP)) + record.Set(enr.UDP(r.node.UDP)) + // public key is added to ENR when ENR is signed + if err := enr.SignV4(&record, r.identity); err != nil { + return record, err + } + r.record = &record + return record, nil +} + +func (r *Rendezvous) register(topic string, record enr.Record) error { srv := r.servers[rand.Intn(len(r.servers))] ctx, cancel := context.WithTimeout(r.rootCtx, requestTimeout) defer cancel() @@ -101,7 +127,7 @@ func (r *Rendezvous) register(topic string) error { r.mu.RLock() defer r.mu.RUnlock() - err := r.client.Register(ctx, srv, topic, r.record, r.registrationPeriod) + err := r.client.Register(ctx, srv, topic, record, r.registrationPeriod) if err != nil { log.Error("error registering", "topic", topic, "rendezvous server", srv, "err", err) } @@ -110,12 +136,16 @@ func (r *Rendezvous) register(topic string) error { // Register renews registration in the specified server. func (r *Rendezvous) Register(topic string, stop chan struct{}) error { + record, err := r.MakeRecord() + if err != nil { + return err + } // sending registration more often than the whole registraton period // will ensure that it won't be accidentally removed ticker := time.NewTicker(r.registrationPeriod / 2) defer ticker.Stop() - if err := r.register(topic); err == context.Canceled { + if err := r.register(topic, record); err == context.Canceled { return err } @@ -124,7 +154,7 @@ func (r *Rendezvous) Register(topic string, stop chan struct{}) error { case <-stop: return nil case <-ticker.C: - if err := r.register(topic); err == context.Canceled { + if err := r.register(topic, record); err == context.Canceled { return err } } diff --git a/discovery/rendezvous_test.go b/discovery/rendezvous_test.go index 77b5369e5..aeb913d41 100644 --- a/discovery/rendezvous_test.go +++ b/discovery/rendezvous_test.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discv5" + "github.com/ethereum/go-ethereum/p2p/enr" lcrypto "github.com/libp2p/go-libp2p-crypto" ma "github.com/multiformats/go-multiaddr" "github.com/status-im/rendezvous/server" @@ -60,6 +61,18 @@ func TestRendezvousDiscovery(t *testing.T) { close(period) } +func TestMakeRecordReturnsCachedRecord(t *testing.T) { + identity, err := crypto.GenerateKey() + require.NoError(t, err) + record := enr.Record{} + require.NoError(t, enr.SignV4(&record, identity)) + c := NewRendezvousWithENR(nil, record) + rst, err := c.MakeRecord() + require.NoError(t, err) + require.NotNil(t, rst.NodeAddr()) + require.Equal(t, record.NodeAddr(), rst.NodeAddr()) +} + func BenchmarkRendezvousStart(b *testing.B) { identity, err := crypto.GenerateKey() require.NoError(b, err)