mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 19:50:36 +00:00
Avoid unnecessary unwind+rewind (#6712)
On [withdrawal-mainnet-shadowfork-1](https://withdrawal-mainnet-shadowfork-1.ethpandaops.io/) erigon was unnecessarily re-executing blocks after 16m (snapshot) multiple times. That was likely due to CL issuing `forkchoiceUpdated` pointing to an old block for some reason. This PR introduces a protection against such inefficiency.
This commit is contained in:
parent
1436060fd8
commit
004c5afdfa
@ -64,6 +64,13 @@ func (s *StageState) ExecutionAt(db kv.Getter) (uint64, error) {
|
||||
return execution, err
|
||||
}
|
||||
|
||||
// IntermediateHashesAt gets the current state of the "IntermediateHashes" stage.
|
||||
// A block is fully validated after the IntermediateHashes stage is passed successfully.
|
||||
func (s *StageState) IntermediateHashesAt(db kv.Getter) (uint64, error) {
|
||||
progress, err := stages.GetStageProgress(db, stages.IntermediateHashes)
|
||||
return progress, err
|
||||
}
|
||||
|
||||
// Unwinder allows the stage to cause an unwind.
|
||||
type Unwinder interface {
|
||||
// UnwindTo begins staged sync unwind to the specified block.
|
||||
|
@ -290,24 +290,41 @@ func startHandlingForkChoice(
|
||||
headerHash := forkChoice.HeadBlockHash
|
||||
log.Debug(fmt.Sprintf("[%s] Handling fork choice", s.LogPrefix()), "headerHash", headerHash)
|
||||
|
||||
currentHeadHash := rawdb.ReadHeadHeaderHash(tx)
|
||||
if currentHeadHash == headerHash { // no-op
|
||||
log.Debug(fmt.Sprintf("[%s] Fork choice no-op", s.LogPrefix()))
|
||||
canonical, err := rawdb.IsCanonicalHash(tx, headerHash)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[%s] Fork choice err (IsCanonicalHash)", s.LogPrefix()), "err", err)
|
||||
cfg.hd.BeaconRequestList.Remove(requestId)
|
||||
canonical, err := writeForkChoiceHashes(forkChoice, s, tx, cfg)
|
||||
return nil, err
|
||||
}
|
||||
if canonical {
|
||||
headerNumber := rawdb.ReadHeaderNumber(tx, headerHash)
|
||||
ihProgress, err := s.IntermediateHashesAt(tx)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[%s] Fork choice err", s.LogPrefix()), "err", err)
|
||||
log.Warn(fmt.Sprintf("[%s] Fork choice err (IntermediateHashesAt)", s.LogPrefix()), "err", err)
|
||||
cfg.hd.BeaconRequestList.Remove(requestId)
|
||||
return nil, err
|
||||
}
|
||||
if canonical {
|
||||
return &engineapi.PayloadStatus{
|
||||
Status: remote.EngineStatus_VALID,
|
||||
LatestValidHash: currentHeadHash,
|
||||
}, nil
|
||||
} else {
|
||||
return &engineapi.PayloadStatus{
|
||||
CriticalError: &privateapi.InvalidForkchoiceStateErr,
|
||||
}, nil
|
||||
if ihProgress >= *headerNumber {
|
||||
// FCU points to a canonical and fully validated block in the past.
|
||||
// Treat it as a no-op to avoid unnecessary unwind of block execution and other stages
|
||||
// with subsequent rewind on a newer FCU.
|
||||
log.Debug(fmt.Sprintf("[%s] Fork choice no-op", s.LogPrefix()))
|
||||
cfg.hd.BeaconRequestList.Remove(requestId)
|
||||
canonical, err = writeForkChoiceHashes(forkChoice, s, tx, cfg)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[%s] Fork choice err", s.LogPrefix()), "err", err)
|
||||
return nil, err
|
||||
}
|
||||
if canonical {
|
||||
return &engineapi.PayloadStatus{
|
||||
Status: remote.EngineStatus_VALID,
|
||||
LatestValidHash: headerHash,
|
||||
}, nil
|
||||
} else {
|
||||
return &engineapi.PayloadStatus{
|
||||
CriticalError: &privateapi.InvalidForkchoiceStateErr,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,7 +355,6 @@ func startHandlingForkChoice(
|
||||
if err := cfg.forkValidator.FlushExtendingFork(tx, cfg.notifications.Accumulator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.hd.BeaconRequestList.Remove(requestId)
|
||||
canonical, err := writeForkChoiceHashes(forkChoice, s, tx, cfg)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[%s] Fork choice err", s.LogPrefix()), "err", err)
|
||||
@ -382,7 +398,7 @@ func startHandlingForkChoice(
|
||||
if err = fixCanonicalChain(s.LogPrefix(), logEvery, headerNumber, headerHash, tx, cfg.blockReader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = rawdb.WriteHeadHeaderHash(tx, forkChoice.HeadBlockHash); err != nil {
|
||||
if err = rawdb.WriteHeadHeaderHash(tx, headerHash); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -394,13 +410,11 @@ func startHandlingForkChoice(
|
||||
if err := s.Update(tx, headerNumber); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Referesh currentHeadHash
|
||||
currentHeadHash = rawdb.ReadHeadHeaderHash(tx)
|
||||
|
||||
if canonical {
|
||||
return &engineapi.PayloadStatus{
|
||||
Status: remote.EngineStatus_VALID,
|
||||
LatestValidHash: currentHeadHash,
|
||||
LatestValidHash: headerHash,
|
||||
}, nil
|
||||
} else {
|
||||
return &engineapi.PayloadStatus{
|
||||
|
Loading…
Reference in New Issue
Block a user