prysm-pulse/beacon-chain/blockchain/state_balance_cache.go
Potuz 0d6e8718fd
Aditya's PR 18 (#11945)
* Aditya's PR 18

This PR implements PR18. There is still a missing piece which is
consistency of head with finalized checkpoint. I will think on ways to
enforce this.

* prune finalized incompatible

* don't check finalization on viable for head

* unit tests fixes

* gazelle

* remove finalized epoch from viableForHead

* remove finalized epoch from leadsToViableHead

* use non-slashed indices

* function rename

* lint fixes

* lint fixes

* lint fixes
2023-02-05 09:40:07 -03:00

63 lines
1.9 KiB
Go

package blockchain
import (
"context"
"sync"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
)
type stateBalanceCache struct {
sync.Mutex
balances []uint64
root [32]byte
stateGen balanceByRooter
}
type balanceByRooter interface {
ActiveNonSlashedBalancesByRoot(context.Context, [32]byte) ([]uint64, error)
}
// newStateBalanceCache exists to remind us that stateBalanceCache needs a state gen
// to avoid nil pointer bugs when updating the cache in the read path (get())
func newStateBalanceCache(sg *stategen.State) (*stateBalanceCache, error) {
if sg == nil {
return nil, errors.New("can't initialize state balance cache without stategen")
}
return &stateBalanceCache{stateGen: sg}, nil
}
// update is called by get() when the requested root doesn't match
// the previously read value. This cache assumes we only want to cache one
// set of balances for a single root (the current justified root).
//
// WARNING: this is not thread-safe on its own, relies on get() for locking
func (c *stateBalanceCache) update(ctx context.Context, justifiedRoot [32]byte) ([]uint64, error) {
stateBalanceCacheMiss.Inc()
justifiedBalances, err := c.stateGen.ActiveNonSlashedBalancesByRoot(ctx, justifiedRoot)
if err != nil {
return nil, errors.Wrap(err, "could not get balances")
}
c.balances = justifiedBalances
c.root = justifiedRoot
return c.balances, nil
}
// getBalances takes an explicit justifiedRoot so it can invalidate the singleton cache key
// when the justified root changes, and takes a context so that the long-running stategen
// read path can connect to the upstream cancellation/timeout chain.
func (c *stateBalanceCache) get(ctx context.Context, justifiedRoot [32]byte) ([]uint64, error) {
c.Lock()
defer c.Unlock()
if justifiedRoot != [32]byte{} && justifiedRoot == c.root {
stateBalanceCacheHit.Inc()
return c.balances, nil
}
return c.update(ctx, justifiedRoot)
}