erigon-pulse/cl/phase1/core/state/cache.go
2023-10-21 23:10:58 +02:00

233 lines
6.8 KiB
Go

package state
import (
"crypto/sha256"
"encoding/binary"
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
"github.com/ledgerwatch/erigon/cl/phase1/core/state/lru"
"github.com/ledgerwatch/erigon/cl/phase1/core/state/raw"
shuffling2 "github.com/ledgerwatch/erigon/cl/phase1/core/state/shuffling"
"github.com/ledgerwatch/erigon-lib/common"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/utils"
)
type HashFunc func([]byte) ([32]byte, error)
// CachingBeaconState is a cached wrapper around a raw CachingBeaconState provider
type CachingBeaconState struct {
// embedded BeaconState
*raw.BeaconState
// Internals
publicKeyIndicies map[[48]byte]uint64
// Caches
activeValidatorsCache *lru.Cache[uint64, []uint64]
shuffledSetsCache *lru.Cache[common.Hash, []uint64]
totalActiveBalanceCache *uint64
totalActiveBalanceRootCache uint64
proposerIndex *uint64
previousStateRoot common.Hash
}
func New(cfg *clparams.BeaconChainConfig) *CachingBeaconState {
state := &CachingBeaconState{
BeaconState: raw.New(cfg),
}
state.initBeaconState()
return state
}
func NewFromRaw(r *raw.BeaconState) *CachingBeaconState {
state := &CachingBeaconState{
BeaconState: r,
}
state.initBeaconState()
return state
}
func (b *CachingBeaconState) SetPreviousStateRoot(root libcommon.Hash) {
b.previousStateRoot = root
}
func (b *CachingBeaconState) _updateProposerIndex() (err error) {
epoch := Epoch(b)
hash := sha256.New()
beaconConfig := b.BeaconConfig()
mixPosition := (epoch + beaconConfig.EpochsPerHistoricalVector - beaconConfig.MinSeedLookahead - 1) %
beaconConfig.EpochsPerHistoricalVector
// Input for the seed hash.
mix := b.GetRandaoMix(int(mixPosition))
input := shuffling2.GetSeed(b.BeaconConfig(), mix, epoch, b.BeaconConfig().DomainBeaconProposer)
slotByteArray := make([]byte, 8)
binary.LittleEndian.PutUint64(slotByteArray, b.Slot())
// Add slot to the end of the input.
inputWithSlot := append(input[:], slotByteArray...)
// Calculate the hash.
hash.Write(inputWithSlot)
seed := hash.Sum(nil)
indices := b.GetActiveValidatorsIndices(epoch)
// Write the seed to an array.
seedArray := [32]byte{}
copy(seedArray[:], seed)
b.proposerIndex = new(uint64)
*b.proposerIndex, err = shuffling2.ComputeProposerIndex(b.BeaconState, indices, seedArray)
return
}
// _initializeValidatorsPhase0 initializes the validators matching flags based on previous/current attestations
func (b *CachingBeaconState) _initializeValidatorsPhase0() error {
// Previous Pending attestations
if b.Slot() == 0 {
return nil
}
previousEpochRoot, err := GetBlockRoot(b, PreviousEpoch(b))
if err != nil {
return err
}
if err := solid.RangeErr[*solid.PendingAttestation](b.PreviousEpochAttestations(), func(i1 int, pa *solid.PendingAttestation, _ int) error {
attestationData := pa.AttestantionData()
slotRoot, err := b.GetBlockRootAtSlot(attestationData.Slot())
if err != nil {
return err
}
indicies, err := b.GetAttestingIndicies(attestationData, pa.AggregationBits(), false)
if err != nil {
return err
}
for _, index := range indicies {
previousMinAttestationDelay, err := b.ValidatorMinPreviousInclusionDelayAttestation(int(index))
if err != nil {
return err
}
if previousMinAttestationDelay == nil || previousMinAttestationDelay.InclusionDelay() > pa.InclusionDelay() {
if err := b.SetValidatorMinPreviousInclusionDelayAttestation(int(index), pa); err != nil {
return err
}
}
if err := b.SetValidatorIsPreviousMatchingSourceAttester(int(index), true); err != nil {
return err
}
if attestationData.Target().BlockRoot() != previousEpochRoot {
continue
}
if err := b.SetValidatorIsPreviousMatchingTargetAttester(int(index), true); err != nil {
return err
}
if attestationData.BeaconBlockRoot() == slotRoot {
if err := b.SetValidatorIsPreviousMatchingHeadAttester(int(index), true); err != nil {
return err
}
}
}
return nil
}); err != nil {
return err
}
// Current Pending attestations
if b.CurrentEpochAttestationsLength() == 0 {
return nil
}
currentEpochRoot, err := GetBlockRoot(b, Epoch(b))
if err != nil {
return err
}
return solid.RangeErr[*solid.PendingAttestation](b.CurrentEpochAttestations(), func(i1 int, pa *solid.PendingAttestation, _ int) error {
attestationData := pa.AttestantionData()
slotRoot, err := b.GetBlockRootAtSlot(attestationData.Slot())
if err != nil {
return err
}
if err != nil {
return err
}
indicies, err := b.GetAttestingIndicies(attestationData, pa.AggregationBits(), false)
if err != nil {
return err
}
for _, index := range indicies {
currentMinAttestationDelay, err := b.ValidatorMinCurrentInclusionDelayAttestation(int(index))
if err != nil {
return err
}
if currentMinAttestationDelay == nil || currentMinAttestationDelay.InclusionDelay() > pa.InclusionDelay() {
if err := b.SetValidatorMinCurrentInclusionDelayAttestation(int(index), pa); err != nil {
return err
}
}
if err := b.SetValidatorIsCurrentMatchingSourceAttester(int(index), true); err != nil {
return err
}
if attestationData.Target().BlockRoot() == currentEpochRoot {
if err := b.SetValidatorIsCurrentMatchingTargetAttester(int(index), true); err != nil {
return err
}
}
if attestationData.BeaconBlockRoot() == slotRoot {
if err := b.SetValidatorIsCurrentMatchingHeadAttester(int(index), true); err != nil {
return err
}
}
}
return nil
})
}
func (b *CachingBeaconState) _refreshActiveBalances() {
epoch := Epoch(b)
b.totalActiveBalanceCache = new(uint64)
*b.totalActiveBalanceCache = 0
b.ForEachValidator(func(validator solid.Validator, idx, total int) bool {
if validator.Active(epoch) {
*b.totalActiveBalanceCache += validator.EffectiveBalance()
}
return true
})
*b.totalActiveBalanceCache = utils.Max64(b.BeaconConfig().EffectiveBalanceIncrement, *b.totalActiveBalanceCache)
b.totalActiveBalanceRootCache = utils.IntegerSquareRoot(*b.totalActiveBalanceCache)
}
func (b *CachingBeaconState) initCaches() error {
var err error
if b.activeValidatorsCache, err = lru.New[uint64, []uint64]("beacon_active_validators_cache", 3); err != nil {
return err
}
if b.shuffledSetsCache, err = lru.New[common.Hash, []uint64]("beacon_shuffled_sets_cache", 3); err != nil {
return err
}
return nil
}
func (b *CachingBeaconState) initBeaconState() error {
b._refreshActiveBalances()
b.publicKeyIndicies = make(map[[48]byte]uint64)
b.ForEachValidator(func(validator solid.Validator, i, total int) bool {
b.publicKeyIndicies[validator.PublicKey()] = uint64(i)
return true
})
b.initCaches()
if err := b._updateProposerIndex(); err != nil {
return err
}
if b.Version() >= clparams.Phase0Version {
return b._initializeValidatorsPhase0()
}
return nil
}