mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-31 16:21:21 +00:00
133 lines
5.5 KiB
Go
133 lines
5.5 KiB
Go
package forkchoice
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/log/v3"
|
|
|
|
"github.com/ledgerwatch/erigon/cl/cltypes"
|
|
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
|
"github.com/ledgerwatch/erigon/cl/freezer"
|
|
"github.com/ledgerwatch/erigon/cl/phase1/core/state"
|
|
"github.com/ledgerwatch/erigon/cl/phase1/forkchoice/fork_graph"
|
|
"github.com/ledgerwatch/erigon/cl/transition/impl/eth2/statechange"
|
|
)
|
|
|
|
func (f *ForkChoiceStore) OnBlock(block *cltypes.SignedBeaconBlock, newPayload, fullValidation bool) error {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
f.headHash = libcommon.Hash{}
|
|
start := time.Now()
|
|
blockRoot, err := block.Block.HashSSZ()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if f.Slot() < block.Block.Slot {
|
|
return fmt.Errorf("block is too early compared to current_slot")
|
|
}
|
|
// Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
|
|
finalizedSlot := f.computeStartSlotAtEpoch(f.finalizedCheckpoint.Epoch())
|
|
if block.Block.Slot <= finalizedSlot {
|
|
return nil
|
|
}
|
|
|
|
var invalidBlock bool
|
|
if newPayload && f.engine != nil {
|
|
if invalidBlock, err = f.engine.NewPayload(block.Block.Body.ExecutionPayload, &block.Block.ParentRoot); err != nil {
|
|
if invalidBlock {
|
|
f.forkGraph.MarkHeaderAsInvalid(blockRoot)
|
|
}
|
|
log.Warn("newPayload failed", "err", err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
lastProcessedState, status, err := f.forkGraph.AddChainSegment(block, fullValidation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
switch status {
|
|
case fork_graph.PreValidated:
|
|
return nil
|
|
case fork_graph.Success:
|
|
f.updateChildren(block.Block.Slot-1, block.Block.ParentRoot, blockRoot) // parent slot can be innacurate
|
|
case fork_graph.BelowAnchor:
|
|
log.Debug("replay block", "code", status)
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("replay block, code: %+v", status)
|
|
}
|
|
if block.Block.Body.ExecutionPayload != nil {
|
|
f.eth2Roots.Add(blockRoot, block.Block.Body.ExecutionPayload.BlockHash)
|
|
}
|
|
|
|
if block.Block.Slot > f.highestSeen {
|
|
f.highestSeen = block.Block.Slot
|
|
}
|
|
// Remove the parent from the head set
|
|
delete(f.headSet, block.Block.ParentRoot)
|
|
f.headSet[blockRoot] = struct{}{}
|
|
// Add proposer score boost if the block is timely
|
|
timeIntoSlot := (f.time - f.genesisTime) % lastProcessedState.BeaconConfig().SecondsPerSlot
|
|
isBeforeAttestingInterval := timeIntoSlot < f.beaconCfg.SecondsPerSlot/f.beaconCfg.IntervalsPerSlot
|
|
if f.Slot() == block.Block.Slot && isBeforeAttestingInterval && f.proposerBoostRoot == (libcommon.Hash{}) {
|
|
f.proposerBoostRoot = blockRoot
|
|
}
|
|
if lastProcessedState.Slot()%f.beaconCfg.SlotsPerEpoch == 0 {
|
|
if err := freezer.PutObjectSSZIntoFreezer("beaconState", "caplin_core", lastProcessedState.Slot(), lastProcessedState, f.recorder); err != nil {
|
|
return err
|
|
}
|
|
// Update randao mixes
|
|
r := solid.NewHashVector(int(f.beaconCfg.EpochsPerHistoricalVector))
|
|
lastProcessedState.RandaoMixes().CopyTo(r)
|
|
f.randaoMixesLists.Add(blockRoot, r)
|
|
} else {
|
|
f.randaoDeltas.Add(blockRoot, randaoDelta{
|
|
epoch: state.Epoch(lastProcessedState),
|
|
delta: lastProcessedState.GetRandaoMixes(state.Epoch(lastProcessedState)),
|
|
})
|
|
}
|
|
f.participation.Add(state.Epoch(lastProcessedState), lastProcessedState.CurrentEpochParticipation().Copy())
|
|
f.preverifiedSizes.Add(blockRoot, preverifiedAppendListsSizes{
|
|
validatorLength: uint64(lastProcessedState.ValidatorLength()),
|
|
historicalRootsLength: lastProcessedState.HistoricalRootsLength(),
|
|
historicalSummariesLength: lastProcessedState.HistoricalSummariesLength(),
|
|
})
|
|
f.finalityCheckpoints.Add(blockRoot, finalityCheckpoints{
|
|
finalizedCheckpoint: lastProcessedState.FinalizedCheckpoint().Copy(),
|
|
currentJustifiedCheckpoint: lastProcessedState.CurrentJustifiedCheckpoint().Copy(),
|
|
previousJustifiedCheckpoint: lastProcessedState.PreviousJustifiedCheckpoint().Copy(),
|
|
})
|
|
f.totalActiveBalances.Add(blockRoot, lastProcessedState.GetTotalActiveBalance())
|
|
// Update checkpoints
|
|
f.updateCheckpoints(lastProcessedState.CurrentJustifiedCheckpoint().Copy(), lastProcessedState.FinalizedCheckpoint().Copy())
|
|
// First thing save previous values of the checkpoints (avoid memory copy of all states and ensure easy revert)
|
|
var (
|
|
previousJustifiedCheckpoint = lastProcessedState.PreviousJustifiedCheckpoint().Copy()
|
|
currentJustifiedCheckpoint = lastProcessedState.CurrentJustifiedCheckpoint().Copy()
|
|
finalizedCheckpoint = lastProcessedState.FinalizedCheckpoint().Copy()
|
|
justificationBits = lastProcessedState.JustificationBits().Copy()
|
|
)
|
|
// Eagerly compute unrealized justification and finality
|
|
if err := statechange.ProcessJustificationBitsAndFinality(lastProcessedState, nil); err != nil {
|
|
return err
|
|
}
|
|
f.operationsPool.NotifyBlock(block.Block)
|
|
f.updateUnrealizedCheckpoints(lastProcessedState.CurrentJustifiedCheckpoint().Copy(), lastProcessedState.FinalizedCheckpoint().Copy())
|
|
// Set the changed value pre-simulation
|
|
lastProcessedState.SetPreviousJustifiedCheckpoint(previousJustifiedCheckpoint)
|
|
lastProcessedState.SetCurrentJustifiedCheckpoint(currentJustifiedCheckpoint)
|
|
lastProcessedState.SetFinalizedCheckpoint(finalizedCheckpoint)
|
|
lastProcessedState.SetJustificationBits(justificationBits)
|
|
// If the block is from a prior epoch, apply the realized values
|
|
blockEpoch := f.computeEpochAtSlot(block.Block.Slot)
|
|
currentEpoch := f.computeEpochAtSlot(f.Slot())
|
|
if blockEpoch < currentEpoch {
|
|
f.updateCheckpoints(lastProcessedState.CurrentJustifiedCheckpoint().Copy(), lastProcessedState.FinalizedCheckpoint().Copy())
|
|
}
|
|
log.Debug("OnBlock", "elapsed", time.Since(start))
|
|
return nil
|
|
}
|