github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/p2p/scoring/internal/appSpecificScoreCache.go (about)

     1  package internal
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/libp2p/go-libp2p/core/peer"
     8  	"github.com/rs/zerolog"
     9  
    10  	"github.com/onflow/flow-go/model/flow"
    11  	"github.com/onflow/flow-go/module"
    12  	herocache "github.com/onflow/flow-go/module/mempool/herocache/backdata"
    13  	"github.com/onflow/flow-go/module/mempool/herocache/backdata/heropool"
    14  	"github.com/onflow/flow-go/module/mempool/stdmap"
    15  	"github.com/onflow/flow-go/network/p2p"
    16  )
    17  
    18  // AppSpecificScoreCache is a cache that stores the application specific score of peers.
    19  // The application specific score of a peer is used to calculate the GossipSub score of the peer.
    20  // Note that the application specific score and the GossipSub score are solely used by the current peer to select the peers
    21  // to which it will connect on a topic mesh.
    22  type AppSpecificScoreCache struct {
    23  	c *stdmap.Backend
    24  }
    25  
    26  var _ p2p.GossipSubApplicationSpecificScoreCache = (*AppSpecificScoreCache)(nil)
    27  
    28  // NewAppSpecificScoreCache creates a new application specific score cache with the given size limit.
    29  // The cache has an LRU eviction policy.
    30  // Args:
    31  // - sizeLimit: the size limit of the cache.
    32  // - logger: the logger to use for logging.
    33  // - collector: the metrics collector to use for collecting metrics.
    34  // Returns:
    35  // - *AppSpecificScoreCache: the created cache.
    36  func NewAppSpecificScoreCache(sizeLimit uint32, logger zerolog.Logger, collector module.HeroCacheMetrics) *AppSpecificScoreCache {
    37  	backData := herocache.NewCache(sizeLimit,
    38  		herocache.DefaultOversizeFactor,
    39  		heropool.LRUEjection,
    40  		logger.With().Str("mempool", "gossipsub-app-specific-score-cache").Logger(),
    41  		collector)
    42  
    43  	return &AppSpecificScoreCache{
    44  		c: stdmap.NewBackend(stdmap.WithBackData(backData)),
    45  	}
    46  }
    47  
    48  // Get returns the application specific score of a peer from the cache.
    49  // Args:
    50  // - peerID: the peer ID of the peer in the GossipSub protocol.
    51  // Returns:
    52  // - float64: the application specific score of the peer.
    53  // - time.Time: the time at which the score was last updated.
    54  // - bool: true if the score was retrieved successfully, false otherwise.
    55  func (a *AppSpecificScoreCache) Get(peerID peer.ID) (float64, time.Time, bool) {
    56  	e, ok := a.c.ByID(entityIdOf(peerID))
    57  	if !ok {
    58  		return 0, time.Time{}, false
    59  	}
    60  	return e.(appSpecificScoreRecordEntity).Score, e.(appSpecificScoreRecordEntity).LastUpdated, true
    61  }
    62  
    63  // AdjustWithInit adds the application specific score of a peer to the cache.
    64  // If the peer already has a score in the cache, the score is updated.
    65  // Args:
    66  // - peerID: the peer ID of the peer in the GossipSub protocol.
    67  // - score: the application specific score of the peer.
    68  // - time: the time at which the score was last updated.
    69  // Returns:
    70  // - error on failure to add the score. The returned error is irrecoverable and indicates an exception.
    71  func (a *AppSpecificScoreCache) AdjustWithInit(peerID peer.ID, score float64, time time.Time) error {
    72  	entityId := entityIdOf(peerID)
    73  
    74  	initLogic := func() flow.Entity {
    75  		return appSpecificScoreRecordEntity{
    76  			entityId:    entityId,
    77  			PeerID:      peerID,
    78  			Score:       score,
    79  			LastUpdated: time,
    80  		}
    81  	}
    82  	adjustLogic := func(entity flow.Entity) flow.Entity {
    83  		r := entity.(appSpecificScoreRecordEntity)
    84  		r.Score = score
    85  		r.LastUpdated = time
    86  		return r
    87  	}
    88  	_, adjusted := a.c.AdjustWithInit(entityId, adjustLogic, initLogic)
    89  	if !adjusted {
    90  		return fmt.Errorf("failed to adjust app specific score for peer %s", peerID)
    91  	}
    92  
    93  	return nil
    94  }