Skip to content

Commit

Permalink
eth/catalyst: reset to current header if chain is rewound (in dev mod…
Browse files Browse the repository at this point in the history
…e) (ethereum#27992)

Signed-off-by: jsvisa <delweng@gmail.com>
Co-authored-by: Jared Wasinger <j-wasinger@hotmail.com>
(cherry picked from commit cde462c)
  • Loading branch information
jsvisa authored and Tristan-Wilson committed Oct 11, 2023
1 parent c530059 commit ca2d9a7
Showing 1 changed file with 53 additions and 21 deletions.
74 changes: 53 additions & 21 deletions eth/catalyst/simulated_beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package catalyst

import (
"errors"
"fmt"
"sync"
"time"

Expand Down Expand Up @@ -144,40 +143,49 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal) error {
feeRecipient := c.feeRecipient
c.feeRecipientLock.Unlock()

// Reset to CurrentBlock in case of the chain was rewound
if header := c.eth.BlockChain().CurrentBlock(); c.curForkchoiceState.HeadBlockHash != header.Hash() {
finalizedHash := c.finalizedBlockHash(header.Number.Uint64())
c.setCurrentState(header.Hash(), *finalizedHash)
}

fcResponse, err := c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, &engine.PayloadAttributes{
Timestamp: tstamp,
SuggestedFeeRecipient: feeRecipient,
Withdrawals: withdrawals,
})
if err != nil {
return fmt.Errorf("error calling forkchoice update: %v", err)
return err
}
if fcResponse == engine.STATUS_SYNCING {
return errors.New("chain rewind prevented invocation of payload creation")
}

envelope, err := c.engineAPI.getPayload(*fcResponse.PayloadID)
if err != nil {
return fmt.Errorf("error retrieving payload: %v", err)
return err
}
payload := envelope.ExecutionPayload

var finalizedHash common.Hash
if payload.Number%devEpochLength == 0 {
finalizedHash = payload.BlockHash
} else {
finalizedHash = c.eth.BlockChain().GetBlockByNumber((payload.Number - 1) / devEpochLength * devEpochLength).Hash()
if fh := c.finalizedBlockHash(payload.Number); fh == nil {
return errors.New("chain rewind interrupted calculation of finalized block hash")
} else {
finalizedHash = *fh
}
}

// mark the payload as canon
// Mark the payload as canon
if _, err = c.engineAPI.NewPayloadV2(*payload); err != nil {
return fmt.Errorf("failed to mark payload as canonical: %v", err)
}
c.curForkchoiceState = engine.ForkchoiceStateV1{
HeadBlockHash: payload.BlockHash,
SafeBlockHash: payload.BlockHash,
FinalizedBlockHash: finalizedHash,
return err
}
// mark the block containing the payload as canonical
c.setCurrentState(payload.BlockHash, finalizedHash)
// Mark the block containing the payload as canonical
if _, err = c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, nil); err != nil {
return fmt.Errorf("failed to mark block as canonical: %v", err)
return err
}
c.lastBlockTime = payload.Timestamp
return nil
Expand All @@ -198,20 +206,18 @@ func (c *SimulatedBeacon) loopOnDemand() {
case w := <-c.withdrawals.pending:
withdrawals := append(c.withdrawals.gatherPending(9), w)
if err := c.sealBlock(withdrawals); err != nil {
log.Error("Error performing sealing-work", "err", err)
return
log.Warn("Error performing sealing work", "err", err)
}
case <-newTxs:
withdrawals := c.withdrawals.gatherPending(10)
if err := c.sealBlock(withdrawals); err != nil {
log.Error("Error performing sealing-work", "err", err)
return
log.Warn("Error performing sealing work", "err", err)
}
}
}
}

// loopOnDemand runs the block production loop for non-zero period configuration
// loop runs the block production loop for non-zero period configuration
func (c *SimulatedBeacon) loop() {
timer := time.NewTimer(0)
for {
Expand All @@ -221,14 +227,40 @@ func (c *SimulatedBeacon) loop() {
case <-timer.C:
withdrawals := c.withdrawals.gatherPending(10)
if err := c.sealBlock(withdrawals); err != nil {
log.Error("Error performing sealing-work", "err", err)
return
log.Warn("Error performing sealing work", "err", err)
} else {
timer.Reset(time.Second * time.Duration(c.period))
}
timer.Reset(time.Second * time.Duration(c.period))
}
}
}

// finalizedBlockHash returns the block hash of the finalized block corresponding to the given number
// or nil if doesn't exist in the chain.
func (c *SimulatedBeacon) finalizedBlockHash(number uint64) *common.Hash {
var finalizedNumber uint64
if number%devEpochLength == 0 {
finalizedNumber = number
} else {
finalizedNumber = (number - 1) / devEpochLength * devEpochLength
}

if finalizedBlock := c.eth.BlockChain().GetBlockByNumber(finalizedNumber); finalizedBlock != nil {
fh := finalizedBlock.Hash()
return &fh
}
return nil
}

// setCurrentState sets the current forkchoice state
func (c *SimulatedBeacon) setCurrentState(headHash, finalizedHash common.Hash) {
c.curForkchoiceState = engine.ForkchoiceStateV1{
HeadBlockHash: headHash,
SafeBlockHash: headHash,
FinalizedBlockHash: finalizedHash,
}
}

func RegisterSimulatedBeaconAPIs(stack *node.Node, sim *SimulatedBeacon) {
stack.RegisterAPIs([]rpc.API{
{
Expand Down

0 comments on commit ca2d9a7

Please sign in to comment.