github.com/ethereum-optimism/optimism@v1.7.2/op-node/p2p/store/mdbook.go (about) 1 package store 2 3 import ( 4 "context" 5 "encoding/json" 6 "sync/atomic" 7 "time" 8 9 "github.com/ethereum-optimism/optimism/op-service/clock" 10 "github.com/ethereum/go-ethereum/log" 11 ds "github.com/ipfs/go-datastore" 12 "github.com/libp2p/go-libp2p/core/peer" 13 ) 14 15 const ( 16 mdCacheSize = 100 17 mdRecordExpiration = time.Hour * 24 * 7 18 ) 19 20 var metadataBase = ds.NewKey("/peers/md") 21 22 // LastUpdate requires atomic update operations. Use the helper functions SetLastUpdated and LastUpdated to modify and access this field. 23 type metadataRecord struct { 24 LastUpdate int64 `json:"lastUpdate"` // unix timestamp in seconds 25 PeerMetadata PeerMetadata `json:"peerMetadata"` 26 } 27 28 type PeerMetadata struct { 29 ENR string `json:"enr"` 30 OPStackID uint64 `json:"opStackID"` 31 } 32 33 func (m *metadataRecord) SetLastUpdated(t time.Time) { 34 atomic.StoreInt64(&m.LastUpdate, t.Unix()) 35 } 36 37 func (m *metadataRecord) LastUpdated() time.Time { 38 return time.Unix(atomic.LoadInt64(&m.LastUpdate), 0) 39 } 40 41 func (m *metadataRecord) MarshalBinary() (data []byte, err error) { 42 return json.Marshal(m) 43 } 44 45 func (m *metadataRecord) UnmarshalBinary(data []byte) error { 46 return json.Unmarshal(data, m) 47 } 48 49 type metadataBook struct { 50 book *recordsBook[peer.ID, *metadataRecord] 51 } 52 53 func newMetadataRecord() *metadataRecord { 54 return new(metadataRecord) 55 } 56 57 func newMetadataBook(ctx context.Context, logger log.Logger, clock clock.Clock, store ds.Batching) (*metadataBook, error) { 58 book, err := newRecordsBook[peer.ID, *metadataRecord](ctx, logger, clock, store, mdCacheSize, mdRecordExpiration, metadataBase, newMetadataRecord, peerIDKey) 59 if err != nil { 60 return nil, err 61 } 62 return &metadataBook{book: book}, nil 63 } 64 65 func (m *metadataBook) startGC() { 66 m.book.startGC() 67 } 68 69 func (m *metadataBook) GetPeerMetadata(id peer.ID) (PeerMetadata, error) { 70 record, err := m.book.getRecord(id) 71 // If the record is not found, return an empty PeerMetadata 72 if err == UnknownRecordErr { 73 return PeerMetadata{}, nil 74 } 75 if err != nil { 76 return PeerMetadata{}, err 77 } 78 return record.PeerMetadata, nil 79 } 80 81 // Apply simply overwrites the record with the new one. 82 // presently, metadata is only collected during peering, so this is fine. 83 // if in the future this data can be updated or expanded, this function will need to be updated. 84 func (md *metadataRecord) Apply(rec *metadataRecord) { 85 *rec = *md 86 } 87 88 func (m *metadataBook) SetPeerMetadata(id peer.ID, md PeerMetadata) (PeerMetadata, error) { 89 rec := newMetadataRecord() 90 rec.PeerMetadata = md 91 rec.SetLastUpdated(m.book.clock.Now()) 92 v, err := m.book.SetRecord(id, rec) 93 return v.PeerMetadata, err 94 } 95 96 func (m *metadataBook) Close() { 97 m.book.Close() 98 }