mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 19:40:37 +00:00
122 lines
4.3 KiB
Go
122 lines
4.3 KiB
Go
//go:build !fuzz
|
|
|
|
package cache
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
|
forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types"
|
|
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
|
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
|
)
|
|
|
|
var (
|
|
// ProposerIndicesCacheMiss tracks the number of proposerIndices requests that aren't present in the cache.
|
|
ProposerIndicesCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
|
Name: "proposer_indices_cache_miss",
|
|
Help: "The number of proposer indices requests that aren't present in the cache.",
|
|
})
|
|
// ProposerIndicesCacheHit tracks the number of proposerIndices requests that are in the cache.
|
|
ProposerIndicesCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
|
Name: "proposer_indices_cache_hit",
|
|
Help: "The number of proposer indices requests that are present in the cache.",
|
|
})
|
|
)
|
|
|
|
// ProposerIndicesCache keeps track of the proposer indices in the next two
|
|
// epochs. It is keyed by the state root of the last epoch before. That is, for
|
|
// blocks during epoch 2, for example slot 65, it will be keyed by the state
|
|
// root of slot 63 (last slot in epoch 1).
|
|
// The cache keeps two sets of indices computed, the "safe" set is computed
|
|
// right before the epoch transition into the current epoch. For example for
|
|
// epoch 2 we will compute this list after importing block 63. The "unsafe"
|
|
// version is computed an epoch in advance, for example for epoch 3, it will be
|
|
// computed after importing block 63.
|
|
//
|
|
// The cache also keeps a map from checkpoints to state roots so that one is
|
|
// able to access the proposer indices list from a checkpoint instead. The
|
|
// checkpoint is the checkpoint for the epoch previous to the requested
|
|
// proposer indices. That is, for a slot in epoch 2 (eg. 65), the checkpoint
|
|
// root would be for slot 32 if present.
|
|
type ProposerIndicesCache struct {
|
|
sync.Mutex
|
|
indices map[primitives.Epoch]map[[32]byte][fieldparams.SlotsPerEpoch]primitives.ValidatorIndex
|
|
rootMap map[forkchoicetypes.Checkpoint][32]byte // A map from checkpoint root to state root
|
|
}
|
|
|
|
// NewProposerIndicesCache returns a newly created cache
|
|
func NewProposerIndicesCache() *ProposerIndicesCache {
|
|
return &ProposerIndicesCache{
|
|
indices: make(map[primitives.Epoch]map[[32]byte][fieldparams.SlotsPerEpoch]primitives.ValidatorIndex),
|
|
rootMap: make(map[forkchoicetypes.Checkpoint][32]byte),
|
|
}
|
|
}
|
|
|
|
// ProposerIndices returns the proposer indices (safe) for the given root
|
|
func (p *ProposerIndicesCache) ProposerIndices(epoch primitives.Epoch, root [32]byte) ([fieldparams.SlotsPerEpoch]primitives.ValidatorIndex, bool) {
|
|
p.Lock()
|
|
defer p.Unlock()
|
|
inner, ok := p.indices[epoch]
|
|
if !ok {
|
|
ProposerIndicesCacheMiss.Inc()
|
|
return [fieldparams.SlotsPerEpoch]primitives.ValidatorIndex{}, false
|
|
}
|
|
indices, exists := inner[root]
|
|
if exists {
|
|
ProposerIndicesCacheHit.Inc()
|
|
} else {
|
|
ProposerIndicesCacheMiss.Inc()
|
|
}
|
|
return indices, exists
|
|
}
|
|
|
|
// Prune resets the ProposerIndicesCache to its initial state
|
|
func (p *ProposerIndicesCache) Prune(epoch primitives.Epoch) {
|
|
p.Lock()
|
|
defer p.Unlock()
|
|
for key := range p.indices {
|
|
if key < epoch {
|
|
delete(p.indices, key)
|
|
}
|
|
}
|
|
for key := range p.rootMap {
|
|
if key.Epoch+1 < epoch {
|
|
delete(p.rootMap, key)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set sets the proposer indices for the given root as key
|
|
func (p *ProposerIndicesCache) Set(epoch primitives.Epoch, root [32]byte, indices [fieldparams.SlotsPerEpoch]primitives.ValidatorIndex) {
|
|
p.Lock()
|
|
defer p.Unlock()
|
|
|
|
inner, ok := p.indices[epoch]
|
|
if !ok {
|
|
inner = make(map[[32]byte][fieldparams.SlotsPerEpoch]primitives.ValidatorIndex)
|
|
p.indices[epoch] = inner
|
|
}
|
|
inner[root] = indices
|
|
}
|
|
|
|
// SetCheckpoint updates the map from checkpoints to state roots
|
|
func (p *ProposerIndicesCache) SetCheckpoint(c forkchoicetypes.Checkpoint, root [32]byte) {
|
|
p.Lock()
|
|
defer p.Unlock()
|
|
p.rootMap[c] = root
|
|
}
|
|
|
|
// IndicesFromCheckpoint returns the proposer indices from a checkpoint rather than the state root
|
|
func (p *ProposerIndicesCache) IndicesFromCheckpoint(c forkchoicetypes.Checkpoint) ([fieldparams.SlotsPerEpoch]primitives.ValidatorIndex, bool) {
|
|
p.Lock()
|
|
emptyIndices := [fieldparams.SlotsPerEpoch]primitives.ValidatorIndex{}
|
|
root, ok := p.rootMap[c]
|
|
p.Unlock()
|
|
if !ok {
|
|
return emptyIndices, ok
|
|
}
|
|
return p.ProposerIndices(c.Epoch+1, root)
|
|
}
|