From c4fc45e9bbcabeb2ae25fa80a20f3c3e4ce96456 Mon Sep 17 00:00:00 2001 From: lightclient Date: Thu, 8 May 2025 13:54:57 -0600 Subject: [PATCH] eth/catalyst: add checkFork helper Co-authored-by: lightclient Co-authored-by: Marius van der Wijden --- eth/catalyst/api.go | 60 +++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 1e6981a76a..0eeaa7f5d5 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params/forks" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" @@ -199,7 +200,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa if payloadAttributes.Withdrawals != nil || payloadAttributes.BeaconRoot != nil { return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("withdrawals and beacon root not supported in V1")) } - if api.eth.BlockChain().Config().IsShanghai(api.eth.BlockChain().Config().LondonBlock, payloadAttributes.Timestamp) { + if api.config().IsShanghai(api.config().LondonBlock, payloadAttributes.Timestamp) { return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("forkChoiceUpdateV1 called post-shanghai")) } } @@ -213,7 +214,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa if params.BeaconRoot != nil { return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("unexpected beacon root")) } - switch api.eth.BlockChain().Config().LatestFork(params.Timestamp) { + switch api.config().LatestFork(params.Timestamp) { case forks.Paris: if params.Withdrawals != nil { return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai")) @@ -239,7 +240,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa if params.BeaconRoot == nil { return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun && api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { + if !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague) { return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads")) } } @@ -257,7 +258,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV1(update engine.Forkchoice if payloadAttributes.Withdrawals != nil || payloadAttributes.BeaconRoot != nil { return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("withdrawals and beacon root not supported in V1")) } - if api.eth.BlockChain().Config().IsShanghai(api.eth.BlockChain().Config().LondonBlock, payloadAttributes.Timestamp) { + if api.config().IsShanghai(api.config().LondonBlock, payloadAttributes.Timestamp) { return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("forkChoiceUpdateV1 called post-shanghai")) } } @@ -271,7 +272,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV2(update engine.Forkchoice if params.BeaconRoot != nil { return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("unexpected beacon root")) } - switch api.eth.BlockChain().Config().LatestFork(params.Timestamp) { + switch api.config().LatestFork(params.Timestamp) { case forks.Paris: if params.Withdrawals != nil { return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai")) @@ -297,7 +298,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.Forkchoice if params.BeaconRoot == nil { return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun && api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { + if !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague) { return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads")) } } @@ -468,7 +469,7 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config engine.Transit api.lastTransitionUpdate = time.Now() api.lastTransitionLock.Unlock() - ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty + ttd := api.config().TerminalTotalDifficulty if ttd == nil || ttd.Cmp(config.TerminalTotalDifficulty.ToInt()) != 0 { log.Warn("Invalid TTD configured", "geth", ttd, "beacon", config.TerminalTotalDifficulty) return nil, fmt.Errorf("invalid ttd: execution %v consensus %v", ttd, config.TerminalTotalDifficulty) @@ -560,10 +561,10 @@ func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.Payl // NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) { - if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().Config().LondonBlock, params.Timestamp) { + if api.config().IsCancun(api.config().LondonBlock, params.Timestamp) { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("can't use newPayloadV2 post-cancun")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) == forks.Shanghai { + if api.checkFork(params.Timestamp, forks.Shanghai) { if params.Withdrawals == nil { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) } @@ -600,7 +601,7 @@ func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHas return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { + if !api.checkFork(params.Timestamp, forks.Cancun) { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV3 must only be called for cancun payloads")) } return api.newPayload(params, versionedHashes, beaconRoot, nil, false) @@ -628,7 +629,7 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil executionRequests post-prague")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { + if !api.checkFork(params.Timestamp, forks.Prague) { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV4 must only be called for prague payloads")) } requests := convertRequests(executionRequests) @@ -650,10 +651,10 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV1(params engine.ExecutableData) ( // NewPayloadWithWitnessV2 is analogous to NewPayloadV2, only it also generates // and returns a stateless witness after running the payload. func (api *ConsensusAPI) NewPayloadWithWitnessV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) { - if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().Config().LondonBlock, params.Timestamp) { + if api.config().IsCancun(api.config().LondonBlock, params.Timestamp) { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("can't use newPayloadV2 post-cancun")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) == forks.Shanghai { + if api.checkFork(params.Timestamp, forks.Shanghai) { if params.Withdrawals == nil { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) } @@ -691,7 +692,7 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV3(params engine.ExecutableData, v return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { + if !api.checkFork(params.Timestamp, forks.Cancun) { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadWithWitnessV3 must only be called for cancun payloads")) } return api.newPayload(params, versionedHashes, beaconRoot, nil, true) @@ -720,7 +721,7 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV4(params engine.ExecutableData, v return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil executionRequests post-prague")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { + if !api.checkFork(params.Timestamp, forks.Prague) { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadWithWitnessV4 must only be called for prague payloads")) } requests := convertRequests(executionRequests) @@ -742,10 +743,10 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV1(params engine.ExecutableData, // ExecuteStatelessPayloadV2 is analogous to NewPayloadV2, only it operates in // a stateless mode on top of a provided witness instead of the local database. func (api *ConsensusAPI) ExecuteStatelessPayloadV2(params engine.ExecutableData, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) { - if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().Config().LondonBlock, params.Timestamp) { + if api.config().IsCancun(api.config().LondonBlock, params.Timestamp) { return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("can't use newPayloadV2 post-cancun")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) == forks.Shanghai { + if api.checkFork(params.Timestamp, forks.Shanghai) { if params.Withdrawals == nil { return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) } @@ -783,7 +784,7 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV3(params engine.ExecutableData, return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { + if !api.checkFork(params.Timestamp, forks.Cancun) { return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("executeStatelessPayloadV3 must only be called for cancun payloads")) } return api.executeStatelessPayload(params, versionedHashes, beaconRoot, nil, opaqueWitness) @@ -812,7 +813,7 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV4(params engine.ExecutableData, return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil executionRequests post-prague")) } - if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague { + if !api.checkFork(params.Timestamp, forks.Prague) { return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("executeStatelessPayloadV4 must only be called for prague payloads")) } requests := convertRequests(executionRequests) @@ -981,7 +982,7 @@ func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, v api.lastNewPayloadLock.Unlock() log.Trace("Executing block statelessly", "number", block.Number(), "hash", params.BlockHash) - stateRoot, receiptRoot, err := core.ExecuteStateless(api.eth.BlockChain().Config(), vm.Config{}, block, witness) + stateRoot, receiptRoot, err := core.ExecuteStateless(api.config(), vm.Config{}, block, witness) if err != nil { log.Warn("ExecuteStatelessPayload: execution failed", "err", err) errorMsg := err.Error() @@ -1119,7 +1120,7 @@ func (api *ConsensusAPI) heartbeat() { time.Sleep(beaconUpdateStartupTimeout) // If the network is not yet merged/merging, don't bother continuing. - if api.eth.BlockChain().Config().TerminalTotalDifficulty == nil { + if api.config().TerminalTotalDifficulty == nil { return } @@ -1163,6 +1164,23 @@ func (api *ConsensusAPI) heartbeat() { } } +// config retrieves the chain's fork configuration. +func (api *ConsensusAPI) config() *params.ChainConfig { + return api.eth.BlockChain().Config() +} + +// checkFork returns true if the latest fork at the given timestamp +// is one of the forks provided. +func (api *ConsensusAPI) checkFork(timestamp uint64, forks ...forks.Fork) bool { + latest := api.config().LatestFork(timestamp) + for _, fork := range forks { + if latest == fork { + return true + } + } + return false +} + // ExchangeCapabilities returns the current methods provided by this node. func (api *ConsensusAPI) ExchangeCapabilities([]string) []string { return caps