From 5bb52e2be31d066dc3a2f6a248bac49adabd4079 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 30 Aug 2024 09:00:15 +0200 Subject: [PATCH] internal/ethapi: add geth_fork method --- eth/catalyst/api.go | 9 ++++--- internal/ethapi/api.go | 19 ++++++++++++++ internal/web3ext/web3ext.go | 14 ++++++++++ params/config.go | 52 +++++++++++++++++++++++++++++++++++-- params/forks/forks.go | 45 ++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 6 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 4779f9756b..e3e9332a5b 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -212,7 +212,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.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) { case forks.Paris: if params.Withdrawals != nil { return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai")) @@ -238,7 +238,8 @@ 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.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Cancun && + api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Prague { return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads")) } } @@ -568,7 +569,7 @@ func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.Payl if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().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.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) == forks.Shanghai { if params.Withdrawals == nil { return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai")) } @@ -605,7 +606,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.eth.BlockChain().Config().LatestPostLondonFork(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) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a508b0ca5b..17b2bba1c7 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1958,6 +1958,25 @@ func (api *NetAPI) Version() string { return fmt.Sprintf("%d", api.networkVersion) } +// GethAPI offers geth-specific API methods. +type GethAPI struct { + b Backend +} + +// NewGethAPI creates a new net API instance. +func NewGethAPI(b Backend) *GethAPI { + return &GethAPI{b: b} +} + +// Fork returns the latest enabled fork as of the given block. +func (api *GethAPI) Fork(ctx context.Context, num rpc.BlockNumber) (string, error) { + b, err := api.b.BlockByNumber(ctx, num) + if err != nil { + return "", fmt.Errorf("block #%d not found", num) + } + return api.b.ChainConfig().LatestFork(b.Number(), b.Time()).String(), nil +} + // checkTxFee is an internal function used to check whether the fee of // the given transaction is _reasonable_(under the cap). func checkTxFee(gasPrice *big.Int, gas uint64, cap float64) error { diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 0c346bbf79..666b3e5ac9 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -720,3 +720,17 @@ web3._extend({ ], }); ` + +const GethJs = ` +web3._extend({ + property: 'geth', + methods: + [ + new web3._extend.Method({ + name: 'fork', + call: 'geth_fork', + params: 1 + }), + ], +}); +` diff --git a/params/config.go b/params/config.go index 9b3b92484a..045d9c08a8 100644 --- a/params/config.go +++ b/params/config.go @@ -505,6 +505,13 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi return parentTotalDiff.Cmp(c.TerminalTotalDifficulty) < 0 && totalDiff.Cmp(c.TerminalTotalDifficulty) >= 0 } +// IsParis returns whether the given block is either equal to the Paris (merge) +// fork or greater. +// Note: Only usable for post-merge networks where MergeNetsplitBlock has been configured. +func (c *ChainConfig) IsParis(num *big.Int) bool { + return c.IsLondon(num) && isBlockForked(c.MergeNetsplitBlock, num) +} + // IsShanghai returns whether time is either equal to the Shanghai fork time or greater. func (c *ChainConfig) IsShanghai(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.ShanghaiTime, time) @@ -704,8 +711,8 @@ func (c *ChainConfig) ElasticityMultiplier() uint64 { return DefaultElasticityMultiplier } -// LatestFork returns the latest time-based fork that would be active for the given time. -func (c *ChainConfig) LatestFork(time uint64) forks.Fork { +// LatestPostLondonFork returns the latest time-based fork that would be active for the given time. +func (c *ChainConfig) LatestPostLondonFork(time uint64) forks.Fork { // Assume last non-time-based fork has passed. london := c.LondonBlock @@ -721,6 +728,47 @@ func (c *ChainConfig) LatestFork(time uint64) forks.Fork { } } +func (c *ChainConfig) LatestFork(num *big.Int, time uint64) forks.Fork { + switch { + case c.IsPrague(num, time): + return forks.Prague + case c.IsCancun(num, time): + return forks.Cancun + case c.IsShanghai(num, time): + return forks.Shanghai + case c.IsParis(num): + return forks.Paris + case c.IsGrayGlacier(num): + return forks.GrayGlacier + case c.IsArrowGlacier(num): + return forks.ArrowGlacier + case c.IsLondon(num): + return forks.London + case c.IsBerlin(num): + return forks.Berlin + case c.IsMuirGlacier(num): + return forks.MuirGlacier + case c.IsIstanbul(num): + return forks.Istanbul + case c.IsPetersburg(num): + return forks.Petersburg + case c.IsConstantinople(num): + return forks.Constantinople + case c.IsByzantium(num): + return forks.Byzantium + case c.IsEIP158(num): + return forks.SpuriousDragon + case c.IsEIP155(num): + return forks.TangerineWhistle + case c.IsEIP150(num): + return forks.DAO + case c.IsHomestead(num): + return forks.Homestead + default: + return forks.Frontier + } +} + // isForkBlockIncompatible returns true if a fork scheduled at block s1 cannot be // rescheduled to block s2 because head is already past the fork. func isForkBlockIncompatible(s1, s2, head *big.Int) bool { diff --git a/params/forks/forks.go b/params/forks/forks.go index 4f50ff5aed..659f144a41 100644 --- a/params/forks/forks.go +++ b/params/forks/forks.go @@ -40,3 +40,48 @@ const ( Cancun Prague ) + +func (f Fork) String() string { + switch f { + case Prague: + return "prague" + case Cancun: + return "cancun" + case Shanghai: + return "shanghai" + case Paris: + return "paris" + case GrayGlacier: + return "grayGlacier" + case ArrowGlacier: + return "arrowGlacier" + case London: + return "london" + case Berlin: + return "berlin" + case MuirGlacier: + return "muirGlacier" + case Istanbul: + return "istanbul" + case Petersburg: + return "petersburg" + case Constantinople: + return "constantinople" + case Byzantium: + return "byzantium" + case SpuriousDragon: + return "spuriousDragon" + case TangerineWhistle: + return "tangerineWhistle" + case DAO: + return "dao" + case Homestead: + return "homestead" + case FrontierThawing: + return "frontierThawing" + case Frontier: + return "frontier" + default: + panic("unknown fork") + } +}