github.com/ethereum-optimism/optimism@v1.7.2/op-node/p2p/store/scorebook.go (about)

     1  package store
     2  
     3  import (
     4  	"context"
     5  	"sync/atomic"
     6  	"time"
     7  
     8  	"github.com/ethereum-optimism/optimism/op-service/clock"
     9  	"github.com/ethereum/go-ethereum/log"
    10  	ds "github.com/ipfs/go-datastore"
    11  	"github.com/libp2p/go-libp2p/core/peer"
    12  	"github.com/multiformats/go-base32"
    13  )
    14  
    15  const (
    16  	scoreCacheSize = 100
    17  )
    18  
    19  var scoresBase = ds.NewKey("/peers/scores")
    20  
    21  // LastUpdate requires atomic update operations. Use the helper functions SetLastUpdated and LastUpdated to modify and access this field.
    22  type scoreRecord struct {
    23  	LastUpdate int64      `json:"lastUpdate"` // unix timestamp in seconds
    24  	PeerScores PeerScores `json:"peerScores"`
    25  }
    26  
    27  func (s *scoreRecord) SetLastUpdated(t time.Time) {
    28  	atomic.StoreInt64(&s.LastUpdate, t.Unix())
    29  }
    30  
    31  func (s *scoreRecord) LastUpdated() time.Time {
    32  	return time.Unix(atomic.LoadInt64(&s.LastUpdate), 0)
    33  }
    34  
    35  func (s *scoreRecord) MarshalBinary() (data []byte, err error) {
    36  	return serializeScoresV0(*s)
    37  }
    38  
    39  func (s *scoreRecord) UnmarshalBinary(data []byte) error {
    40  	r, err := deserializeScoresV0(data)
    41  	if err != nil {
    42  		return err
    43  	}
    44  	*s = r
    45  	return nil
    46  }
    47  
    48  type scoreBook struct {
    49  	book *recordsBook[peer.ID, *scoreRecord]
    50  }
    51  
    52  func newScoreRecord() *scoreRecord {
    53  	return new(scoreRecord)
    54  }
    55  
    56  func peerIDKey(id peer.ID) ds.Key {
    57  	return ds.NewKey(base32.RawStdEncoding.EncodeToString([]byte(id)))
    58  }
    59  
    60  func newScoreBook(ctx context.Context, logger log.Logger, clock clock.Clock, store ds.Batching, retain time.Duration) (*scoreBook, error) {
    61  	book, err := newRecordsBook[peer.ID, *scoreRecord](ctx, logger, clock, store, scoreCacheSize, retain, scoresBase, newScoreRecord, peerIDKey)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	return &scoreBook{book: book}, nil
    66  }
    67  
    68  func (d *scoreBook) startGC() {
    69  	d.book.startGC()
    70  }
    71  
    72  func (d *scoreBook) GetPeerScores(id peer.ID) (PeerScores, error) {
    73  	record, err := d.book.getRecord(id)
    74  	if err == UnknownRecordErr {
    75  		return PeerScores{}, nil // return zeroed scores by default
    76  	}
    77  	if err != nil {
    78  		return PeerScores{}, err
    79  	}
    80  	return record.PeerScores, nil
    81  }
    82  
    83  func (d *scoreBook) GetPeerScore(id peer.ID) (float64, error) {
    84  	scores, err := d.GetPeerScores(id)
    85  	if err != nil {
    86  		return 0, err
    87  	}
    88  	return scores.Gossip.Total, nil
    89  }
    90  
    91  func (d *scoreBook) SetScore(id peer.ID, diff ScoreDiff) (PeerScores, error) {
    92  	v, err := d.book.SetRecord(id, diff)
    93  	return v.PeerScores, err
    94  }
    95  
    96  func (d *scoreBook) Close() {
    97  	d.book.Close()
    98  }