mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-10 13:01:21 +00:00
30430d585a
this first major move separates the transient beacon state cache from the underlying tree. leaf updates are enforced in the setters, which should make programming easier. all exported methods of the raw.BeaconState should be safe to call (without disrupting internal state) changes many functions to consume *raw.BeaconState in perparation for interface beyond refactor it also: adds a pool for the leaves of the validator ssz hash adds a pool for the snappy writers removed the parallel hash experiment (high memory use)
135 lines
4.2 KiB
Go
135 lines
4.2 KiB
Go
package forkchoice
|
|
|
|
import (
|
|
"sync"
|
|
|
|
lru "github.com/hashicorp/golang-lru/v2"
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon/cl/cltypes"
|
|
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state"
|
|
"github.com/ledgerwatch/erigon/cmd/erigon-cl/execution_client"
|
|
"github.com/ledgerwatch/erigon/cmd/erigon-cl/forkchoice/fork_graph"
|
|
)
|
|
|
|
const (
|
|
checkpointsPerCache = 1024
|
|
allowedCachedStates = 4
|
|
)
|
|
|
|
type ForkChoiceStore struct {
|
|
time uint64
|
|
highestSeen uint64
|
|
justifiedCheckpoint *cltypes.Checkpoint
|
|
finalizedCheckpoint *cltypes.Checkpoint
|
|
unrealizedJustifiedCheckpoint *cltypes.Checkpoint
|
|
unrealizedFinalizedCheckpoint *cltypes.Checkpoint
|
|
proposerBoostRoot libcommon.Hash
|
|
// Use go map because this is actually an unordered set
|
|
equivocatingIndicies map[uint64]struct{}
|
|
forkGraph *fork_graph.ForkGraph
|
|
// I use the cache due to the convenient auto-cleanup feauture.
|
|
checkpointStates *lru.Cache[cltypes.Checkpoint, *checkpointState] // We keep ssz snappy of it as the full beacon state is full of rendundant data.
|
|
latestMessages map[uint64]*LatestMessage
|
|
// We keep track of them so that we can forkchoice with EL.
|
|
eth2Roots *lru.Cache[libcommon.Hash, libcommon.Hash] // ETH2 root -> ETH1 hash
|
|
mu sync.Mutex
|
|
// EL
|
|
engine execution_client.ExecutionEngine
|
|
}
|
|
|
|
type LatestMessage struct {
|
|
Epoch uint64
|
|
Root libcommon.Hash
|
|
}
|
|
|
|
// NewForkChoiceStore initialize a new store from the given anchor state, either genesis or checkpoint sync state.
|
|
func NewForkChoiceStore(anchorState *state.BeaconState, engine execution_client.ExecutionEngine, enabledPruning bool) (*ForkChoiceStore, error) {
|
|
anchorRoot, err := anchorState.BlockRoot()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
anchorCheckpoint := &cltypes.Checkpoint{
|
|
Epoch: state.Epoch(anchorState.BeaconState),
|
|
Root: anchorRoot,
|
|
}
|
|
checkpointStates, err := lru.New[cltypes.Checkpoint, *checkpointState](allowedCachedStates)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
eth2Roots, err := lru.New[libcommon.Hash, libcommon.Hash](checkpointsPerCache)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ForkChoiceStore{
|
|
highestSeen: anchorState.Slot(),
|
|
time: anchorState.GenesisTime() + anchorState.BeaconConfig().SecondsPerSlot*anchorState.Slot(),
|
|
justifiedCheckpoint: anchorCheckpoint.Copy(),
|
|
finalizedCheckpoint: anchorCheckpoint.Copy(),
|
|
unrealizedJustifiedCheckpoint: anchorCheckpoint.Copy(),
|
|
unrealizedFinalizedCheckpoint: anchorCheckpoint.Copy(),
|
|
forkGraph: fork_graph.New(anchorState, enabledPruning),
|
|
equivocatingIndicies: map[uint64]struct{}{},
|
|
latestMessages: map[uint64]*LatestMessage{},
|
|
checkpointStates: checkpointStates,
|
|
eth2Roots: eth2Roots,
|
|
engine: engine,
|
|
}, nil
|
|
}
|
|
|
|
// Highest seen returns highest seen slot
|
|
func (f *ForkChoiceStore) HighestSeen() uint64 {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
return f.highestSeen
|
|
}
|
|
|
|
// Time returns current time
|
|
func (f *ForkChoiceStore) Time() uint64 {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
return f.time
|
|
}
|
|
|
|
// ProposerBoostRoot returns proposer boost root
|
|
func (f *ForkChoiceStore) ProposerBoostRoot() libcommon.Hash {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
return f.proposerBoostRoot
|
|
}
|
|
|
|
// JustifiedCheckpoint returns justified checkpoint
|
|
func (f *ForkChoiceStore) JustifiedCheckpoint() *cltypes.Checkpoint {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
return f.justifiedCheckpoint
|
|
}
|
|
|
|
// FinalizedCheckpoint returns justified checkpoint
|
|
func (f *ForkChoiceStore) FinalizedCheckpoint() *cltypes.Checkpoint {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
return f.finalizedCheckpoint
|
|
}
|
|
|
|
// FinalizedCheckpoint returns justified checkpoint
|
|
func (f *ForkChoiceStore) Engine() execution_client.ExecutionEngine {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
return f.engine
|
|
}
|
|
|
|
// FinalizedCheckpoint returns justified checkpoint
|
|
func (f *ForkChoiceStore) GetEth1Hash(eth2Root libcommon.Hash) libcommon.Hash {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
ret, _ := f.eth2Roots.Get(eth2Root)
|
|
return ret
|
|
}
|
|
|
|
// FinalizedCheckpoint returns justified checkpoint
|
|
func (f *ForkChoiceStore) AnchorSlot() uint64 {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
return f.forkGraph.AnchorSlot()
|
|
}
|