From c1490e00eb9ec098dac5ae2aa9d82eae5847c06a Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Thu, 10 Oct 2024 13:27:25 -0700 Subject: [PATCH] extend op-node to support holocene 1559 params --- bedrock-devnet/devnet/__init__.py | 2 +- go.mod | 2 +- go.sum | 4 +- op-chain-ops/genesis/config.go | 9 ++ op-chain-ops/genesis/genesis.go | 9 +- op-chain-ops/genesis/layer_two.go | 9 +- op-chain-ops/interopgen/deploy.go | 2 +- op-chain-ops/interopgen/recipe.go | 1 + op-chain-ops/script/script.go | 1 + .../pkg/deployer/state/deploy_config.go | 1 + .../actions/derivation/system_config_test.go | 1 + op-e2e/actions/helpers/l2_sequencer.go | 8 ++ op-e2e/actions/helpers/user_test.go | 1 + op-e2e/actions/proofs/helpers/env.go | 2 + op-e2e/actions/proofs/helpers/matrix.go | 3 +- op-e2e/actions/upgrades/dencun_fork_test.go | 1 + op-e2e/actions/upgrades/ecotone_fork_test.go | 1 + op-e2e/actions/upgrades/fjord_fork_test.go | 1 + op-e2e/actions/upgrades/helpers/config.go | 1 + op-e2e/actions/upgrades/span_batch_test.go | 1 + op-e2e/config/init.go | 1 + op-e2e/e2eutils/setup.go | 7 +- op-e2e/opgeth/op_geth.go | 7 +- op-e2e/system/e2esys/setup.go | 8 ++ op-e2e/system/proofs/system_fpp_test.go | 1 + op-node/chaincfg/chains_test.go | 93 ++++++++++--------- op-node/rollup/clsync/clsync.go | 2 +- op-node/rollup/derive/attributes.go | 9 +- op-node/rollup/derive/attributes_test.go | 31 +++++++ op-node/rollup/derive/payload_util.go | 64 +++++++------ op-node/rollup/derive/system_config.go | 21 ++++- op-node/rollup/derive/system_config_test.go | 26 +++++- op-node/rollup/sequencing/sequencer_test.go | 2 + op-node/rollup/types_test.go | 7 +- .../client/l2/engineapi/block_processor.go | 9 ++ .../client/l2/engineapi/l2_engine_api.go | 4 + op-service/eth/types.go | 42 ++++++++- packages/contracts-bedrock/README.md | 6 +- .../deploy-config/devnetL1-template.json | 1 + .../contracts-bedrock/scripts/L2Genesis.s.sol | 4 + .../scripts/deploy/Deploy.s.sol | 7 ++ .../scripts/deploy/DeployConfig.s.sol | 6 +- .../scripts/libraries/Config.sol | 9 +- packages/contracts-bedrock/semver-lock.json | 8 +- .../contracts-bedrock/src/L1/SystemConfig.sol | 12 +-- .../src/L1/SystemConfigInterop.sol | 4 +- .../src/L1/interfaces/ISystemConfig.sol | 2 +- .../src/L1/interfaces/ISystemConfigV160.sol | 2 +- .../test/L1/SystemConfig.t.sol | 4 +- 49 files changed, 339 insertions(+), 120 deletions(-) diff --git a/bedrock-devnet/devnet/__init__.py b/bedrock-devnet/devnet/__init__.py index 8ff9c6b456912..7da2f6e82c3bc 100644 --- a/bedrock-devnet/devnet/__init__.py +++ b/bedrock-devnet/devnet/__init__.py @@ -24,7 +24,7 @@ log = logging.getLogger() # Global constants -FORKS = ["delta", "ecotone", "fjord", "granite"] +FORKS = ["delta", "ecotone", "fjord", "granite", "holocene"] # Global environment variables DEVNET_NO_BUILD = os.getenv('DEVNET_NO_BUILD') == "true" diff --git a/go.mod b/go.mod index 02fb7ad85610a..9933b37be9abf 100644 --- a/go.mod +++ b/go.mod @@ -253,7 +253,7 @@ require ( replace github.com/ethereum/go-ethereum v1.14.11 => github.com/ethereum-optimism/op-geth v1.101408.1-0.20241002211323-d5a96613c22b -// replace github.com/ethereum/go-ethereum => ../op-geth +//replace github.com/ethereum/go-ethereum => ../op-geth // replace github.com/ethereum-optimism/superchain-registry/superchain => ../superchain-registry/superchain diff --git a/go.sum b/go.sum index 90d22916553a0..610e9ae7731e8 100644 --- a/go.sum +++ b/go.sum @@ -181,8 +181,6 @@ github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/u github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= -github.com/ethereum-optimism/op-geth v1.101408.1-0.20241002211323-d5a96613c22b h1:9C6WytqAcqWKXQTMw2Da/S/aIJJmMvT+2MUpFnMdGrg= -github.com/ethereum-optimism/op-geth v1.101408.1-0.20241002211323-d5a96613c22b/go.mod h1:7S4pp8KHBmEmKkRjL1BPOc6jY9hW+64YeMUjR3RVLw4= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac h1:hCIrLuOPV3FJfMDvXeOhCC3uQNvFoMIIlkT2mN2cfeg= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac/go.mod h1:XaVXL9jg8BcyOeugECgIUGa9Y3DjYJj71RHmb5qon6M= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= @@ -695,6 +693,8 @@ github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtD github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/roberto-bayardo/op-geth v0.0.0-20241016220820-6c32375dda12 h1:2KAIkOPb2lnkxyHPzxrLOOquTSYn9XmNqEf+aTs5qAk= +github.com/roberto-bayardo/op-geth v0.0.0-20241016220820-6c32375dda12/go.mod h1:7S4pp8KHBmEmKkRjL1BPOc6jY9hW+64YeMUjR3RVLw4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= diff --git a/op-chain-ops/genesis/config.go b/op-chain-ops/genesis/config.go index 654a042ba445f..31cd7aceb8898 100644 --- a/op-chain-ops/genesis/config.go +++ b/op-chain-ops/genesis/config.go @@ -342,6 +342,9 @@ type UpgradeScheduleDeployConfig struct { // L2GenesisGraniteTimeOffset is the number of seconds after genesis block that Granite hard fork activates. // Set it to 0 to activate at genesis. Nil to disable Granite. L2GenesisGraniteTimeOffset *hexutil.Uint64 `json:"l2GenesisGraniteTimeOffset,omitempty"` + // L2GenesisHoloceneTimeOffset is the number of seconds after genesis block that the Holocene hard fork activates. + // Set it to 0 to activate at genesis. Nil to disable Holocene. + L2GenesisHoloceneTimeOffset *hexutil.Uint64 `json:"l2GenesisHoloceneTimeOffset,omitempty"` // L2GenesisInteropTimeOffset is the number of seconds after genesis block that the Interop hard fork activates. // Set it to 0 to activate at genesis. Nil to disable Interop. L2GenesisInteropTimeOffset *hexutil.Uint64 `json:"l2GenesisInteropTimeOffset,omitempty"` @@ -390,6 +393,10 @@ func (d *UpgradeScheduleDeployConfig) GraniteTime(genesisTime uint64) *uint64 { return offsetToUpgradeTime(d.L2GenesisGraniteTimeOffset, genesisTime) } +func (d *UpgradeScheduleDeployConfig) HoloceneTime(genesisTime uint64) *uint64 { + return offsetToUpgradeTime(d.L2GenesisHoloceneTimeOffset, genesisTime) +} + func (d *UpgradeScheduleDeployConfig) InteropTime(genesisTime uint64) *uint64 { return offsetToUpgradeTime(d.L2GenesisInteropTimeOffset, genesisTime) } @@ -422,6 +429,7 @@ func (d *UpgradeScheduleDeployConfig) forks() []Fork { {L2GenesisTimeOffset: d.L2GenesisEcotoneTimeOffset, Name: string(L2AllocsEcotone)}, {L2GenesisTimeOffset: d.L2GenesisFjordTimeOffset, Name: string(L2AllocsFjord)}, {L2GenesisTimeOffset: d.L2GenesisGraniteTimeOffset, Name: string(L2AllocsGranite)}, + {L2GenesisTimeOffset: d.L2GenesisHoloceneTimeOffset, Name: string(L2AllocsHolocene)}, } } @@ -931,6 +939,7 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Header, l2GenesisBlockHa EcotoneTime: d.EcotoneTime(l1StartTime), FjordTime: d.FjordTime(l1StartTime), GraniteTime: d.GraniteTime(l1StartTime), + HoloceneTime: d.HoloceneTime(l1StartTime), InteropTime: d.InteropTime(l1StartTime), ProtocolVersionsAddress: d.ProtocolVersionsProxy, AltDAConfig: altDA, diff --git a/op-chain-ops/genesis/genesis.go b/op-chain-ops/genesis/genesis.go index dc7a44ad7ddf5..5056497244ed4 100644 --- a/op-chain-ops/genesis/genesis.go +++ b/op-chain-ops/genesis/genesis.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -21,6 +22,9 @@ const defaultGasLimit = 30_000_000 // BedrockTransitionBlockExtraData represents the default extra data for the bedrock transition block. var BedrockTransitionBlockExtraData = []byte("BEDROCK") +// HoloceneExtraData represents the default extra data for Holocene-genesis chains. +var HoloceneExtraData = eip1559.EncodeHoloceneExtraData(250, 6) + // NewL2Genesis will create a new L2 genesis func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Genesis, error) { if config.L2ChainID == 0 { @@ -70,6 +74,7 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene EcotoneTime: config.EcotoneTime(l1StartTime), FjordTime: config.FjordTime(l1StartTime), GraniteTime: config.GraniteTime(l1StartTime), + HoloceneTime: config.HoloceneTime(l1StartTime), InteropTime: config.InteropTime(l1StartTime), Optimism: ¶ms.OptimismConfig{ EIP1559Denominator: eip1559Denom, @@ -93,8 +98,8 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene extraData := config.L2GenesisBlockExtraData if extraData == nil { - // L2GenesisBlockExtraData is optional, so use a default value when nil - extraData = BedrockTransitionBlockExtraData + // L2GenesisBlockExtraData is optional, so use a Holocene-compatible value when nil. + extraData = HoloceneExtraData } // Ensure that the extradata is valid if size := len(extraData); size > 32 { diff --git a/op-chain-ops/genesis/layer_two.go b/op-chain-ops/genesis/layer_two.go index c7c9765019e24..b1c0922de1eb4 100644 --- a/op-chain-ops/genesis/layer_two.go +++ b/op-chain-ops/genesis/layer_two.go @@ -22,10 +22,11 @@ type L2AllocsMode string type L2AllocsModeMap map[L2AllocsMode]*foundry.ForgeAllocs const ( - L2AllocsDelta L2AllocsMode = "delta" - L2AllocsEcotone L2AllocsMode = "ecotone" - L2AllocsFjord L2AllocsMode = "fjord" - L2AllocsGranite L2AllocsMode = "granite" + L2AllocsDelta L2AllocsMode = "delta" + L2AllocsEcotone L2AllocsMode = "ecotone" + L2AllocsFjord L2AllocsMode = "fjord" + L2AllocsGranite L2AllocsMode = "granite" + L2AllocsHolocene L2AllocsMode = "holocene" ) var ( diff --git a/op-chain-ops/interopgen/deploy.go b/op-chain-ops/interopgen/deploy.go index 3e93c00cb561e..83c241fdc0139 100644 --- a/op-chain-ops/interopgen/deploy.go +++ b/op-chain-ops/interopgen/deploy.go @@ -130,7 +130,7 @@ func CreateL2(logger log.Logger, fa *foundry.ArtifactsFS, srcFS *foundry.SourceM } l2Host := script.NewHost(logger.New("role", "l2", "chain", l2Cfg.L2ChainID), fa, srcFS, l2Context) l2Host.SetEnvVar("OUTPUT_MODE", "none") // we don't use the cheatcode, but capture the state outside of EVM execution - l2Host.SetEnvVar("FORK", "granite") // latest fork + l2Host.SetEnvVar("FORK", "holocene") // latest fork return l2Host } diff --git a/op-chain-ops/interopgen/recipe.go b/op-chain-ops/interopgen/recipe.go index b16a663bb6d14..4dbd0cefaed62 100644 --- a/op-chain-ops/interopgen/recipe.go +++ b/op-chain-ops/interopgen/recipe.go @@ -232,6 +232,7 @@ func InteropL2DevConfig(l1ChainID, l2ChainID uint64, addrs devkeys.Addresses) (* L2GenesisEcotoneTimeOffset: new(hexutil.Uint64), L2GenesisFjordTimeOffset: new(hexutil.Uint64), L2GenesisGraniteTimeOffset: new(hexutil.Uint64), + L2GenesisHoloceneTimeOffset: new(hexutil.Uint64), L2GenesisInteropTimeOffset: new(hexutil.Uint64), L1CancunTimeOffset: new(hexutil.Uint64), UseInterop: true, diff --git a/op-chain-ops/script/script.go b/op-chain-ops/script/script.go index 07839b93a6261..f91ba92aba4f9 100644 --- a/op-chain-ops/script/script.go +++ b/op-chain-ops/script/script.go @@ -206,6 +206,7 @@ func NewHost( EcotoneTime: nil, FjordTime: nil, GraniteTime: nil, + HoloceneTime: nil, InteropTime: nil, Optimism: nil, } diff --git a/op-deployer/pkg/deployer/state/deploy_config.go b/op-deployer/pkg/deployer/state/deploy_config.go index 4e6be6251b943..e7fd1cba4f00c 100644 --- a/op-deployer/pkg/deployer/state/deploy_config.go +++ b/op-deployer/pkg/deployer/state/deploy_config.go @@ -57,6 +57,7 @@ func DefaultDeployConfig(chainIntent *ChainIntent) genesis.DeployConfig { L2GenesisEcotoneTimeOffset: u64UtilPtr(0), L2GenesisFjordTimeOffset: u64UtilPtr(0), L2GenesisGraniteTimeOffset: u64UtilPtr(0), + L2GenesisHoloceneTimeOffset: u64UtilPtr(0), UseInterop: false, }, L2CoreDeployConfig: genesis.L2CoreDeployConfig{ diff --git a/op-e2e/actions/derivation/system_config_test.go b/op-e2e/actions/derivation/system_config_test.go index 362c9f2dc8547..ecfe466cadb0f 100644 --- a/op-e2e/actions/derivation/system_config_test.go +++ b/op-e2e/actions/derivation/system_config_test.go @@ -237,6 +237,7 @@ func GPOParamsChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { dp.DeployConfig.L2GenesisEcotoneTimeOffset = nil dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil + dp.DeployConfig.L2GenesisHoloceneTimeOffset = nil sd := e2eutils.Setup(t, dp, actionsHelpers.DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) diff --git a/op-e2e/actions/helpers/l2_sequencer.go b/op-e2e/actions/helpers/l2_sequencer.go index 424e12b23fda0..8afed4fd32ce2 100644 --- a/op-e2e/actions/helpers/l2_sequencer.go +++ b/op-e2e/actions/helpers/l2_sequencer.go @@ -213,3 +213,11 @@ func (s *L2Sequencer) ActBuildL2ToGranite(t Testing) { s.ActL2EndBlock(t) } } + +func (s *L2Sequencer) ActBuildL2ToHolocene(t Testing) { + require.NotNil(t, s.RollupCfg.HoloceneTime, "cannot activate HoloceneTime when it is not scheduled") + for s.L2Unsafe().Time < *s.RollupCfg.HoloceneTime { + s.ActL2StartBlock(t) + s.ActL2EndBlock(t) + } +} diff --git a/op-e2e/actions/helpers/user_test.go b/op-e2e/actions/helpers/user_test.go index 8990ed5fdd96d..ce43565714b9c 100644 --- a/op-e2e/actions/helpers/user_test.go +++ b/op-e2e/actions/helpers/user_test.go @@ -136,6 +136,7 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) { dp.DeployConfig.L2GenesisDeltaTimeOffset = test.deltaTime dp.DeployConfig.L2GenesisEcotoneTimeOffset = test.ecotoneTime dp.DeployConfig.L2GenesisFjordTimeOffset = test.fjordTime + dp.DeployConfig.L2GenesisGraniteTimeOffset = nil if test.canyonTime != nil { require.Zero(t, uint64(*test.canyonTime)%uint64(dp.DeployConfig.L2BlockTime), "canyon fork must be aligned") diff --git a/op-e2e/actions/proofs/helpers/env.go b/op-e2e/actions/proofs/helpers/env.go index de18c8cbce939..4283d0d1e1628 100644 --- a/op-e2e/actions/proofs/helpers/env.go +++ b/op-e2e/actions/proofs/helpers/env.go @@ -61,6 +61,8 @@ func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eut dp.DeployConfig.L2GenesisFjordTimeOffset = &genesisBlock case Granite: dp.DeployConfig.L2GenesisGraniteTimeOffset = &genesisBlock + case Holocene: + dp.DeployConfig.L2GenesisHoloceneTimeOffset = &genesisBlock } }) sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) diff --git a/op-e2e/actions/proofs/helpers/matrix.go b/op-e2e/actions/proofs/helpers/matrix.go index 7f3e810e86b6c..bbc06df2506c4 100644 --- a/op-e2e/actions/proofs/helpers/matrix.go +++ b/op-e2e/actions/proofs/helpers/matrix.go @@ -87,8 +87,9 @@ var ( Fjord = &Hardfork{Name: "Fjord", Precedence: 4} Ecotone = &Hardfork{Name: "Ecotone", Precedence: 5} Granite = &Hardfork{Name: "Granite", Precedence: 6} + Holocene = &Hardfork{Name: "Holocene", Precedence: 7} ) -var Hardforks = ForkMatrix{Regolith, Canyon, Delta, Fjord, Ecotone, Granite} +var Hardforks = ForkMatrix{Regolith, Canyon, Delta, Fjord, Ecotone, Granite, Holocene} var LatestForkOnly = ForkMatrix{Hardforks[len(Hardforks)-1]} diff --git a/op-e2e/actions/upgrades/dencun_fork_test.go b/op-e2e/actions/upgrades/dencun_fork_test.go index b15634c78adfe..adc995c0636d1 100644 --- a/op-e2e/actions/upgrades/dencun_fork_test.go +++ b/op-e2e/actions/upgrades/dencun_fork_test.go @@ -126,6 +126,7 @@ func TestDencunL2ForkAfterGenesis(gt *testing.T) { dp.DeployConfig.L2GenesisEcotoneTimeOffset = &offset dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil + dp.DeployConfig.L2GenesisHoloceneTimeOffset = nil // New forks have to be added here, after changing the default deploy config! sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) diff --git a/op-e2e/actions/upgrades/ecotone_fork_test.go b/op-e2e/actions/upgrades/ecotone_fork_test.go index 6b51b5b470a4d..9bbd5426b5d83 100644 --- a/op-e2e/actions/upgrades/ecotone_fork_test.go +++ b/op-e2e/actions/upgrades/ecotone_fork_test.go @@ -52,6 +52,7 @@ func TestEcotoneNetworkUpgradeTransactions(gt *testing.T) { dp.DeployConfig.L2GenesisEcotoneTimeOffset = &ecotoneOffset dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil + dp.DeployConfig.L2GenesisHoloceneTimeOffset = nil // New forks have to be added here... require.NoError(t, dp.DeployConfig.Check(log), "must have valid config") diff --git a/op-e2e/actions/upgrades/fjord_fork_test.go b/op-e2e/actions/upgrades/fjord_fork_test.go index 564ee49aa17d6..934aa411299fe 100644 --- a/op-e2e/actions/upgrades/fjord_fork_test.go +++ b/op-e2e/actions/upgrades/fjord_fork_test.go @@ -45,6 +45,7 @@ func TestFjordNetworkUpgradeTransactions(gt *testing.T) { dp.DeployConfig.L2GenesisDeltaTimeOffset = &genesisBlock dp.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisBlock dp.DeployConfig.L2GenesisFjordTimeOffset = &fjordOffset + dp.DeployConfig.L2GenesisGraniteTimeOffset = nil require.NoError(t, dp.DeployConfig.Check(log), "must have valid config") sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) diff --git a/op-e2e/actions/upgrades/helpers/config.go b/op-e2e/actions/upgrades/helpers/config.go index a936d86250a05..1c844afd32658 100644 --- a/op-e2e/actions/upgrades/helpers/config.go +++ b/op-e2e/actions/upgrades/helpers/config.go @@ -8,6 +8,7 @@ import ( // ApplyDeltaTimeOffset adjusts fork configuration to not conflict with the delta overrides func ApplyDeltaTimeOffset(dp *e2eutils.DeployParams, deltaTimeOffset *hexutil.Uint64) { dp.DeployConfig.L2GenesisDeltaTimeOffset = deltaTimeOffset + dp.DeployConfig.L2GenesisGraniteTimeOffset = nil // configure Ecotone to not be before Delta accidentally if dp.DeployConfig.L2GenesisEcotoneTimeOffset != nil { if deltaTimeOffset == nil { diff --git a/op-e2e/actions/upgrades/span_batch_test.go b/op-e2e/actions/upgrades/span_batch_test.go index 3888cae8a5e07..0588128b7dbb0 100644 --- a/op-e2e/actions/upgrades/span_batch_test.go +++ b/op-e2e/actions/upgrades/span_batch_test.go @@ -142,6 +142,7 @@ func TestHardforkMiddleOfSpanBatch(gt *testing.T) { dp.DeployConfig.L2GenesisEcotoneTimeOffset = nil dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil + dp.DeployConfig.L2GenesisHoloceneTimeOffset = nil sd := e2eutils.Setup(t, dp, actionsHelpers.DefaultAlloc) log := testlog.Logger(t, log.LevelError) diff --git a/op-e2e/config/init.go b/op-e2e/config/init.go index a635c9efd7e55..9419c1277060d 100644 --- a/op-e2e/config/init.go +++ b/op-e2e/config/init.go @@ -185,6 +185,7 @@ func initAllocType(root string, allocType AllocType) { } l2Alloc[mode] = allocs } + mustL2Allocs(genesis.L2AllocsHolocene) mustL2Allocs(genesis.L2AllocsGranite) mustL2Allocs(genesis.L2AllocsFjord) mustL2Allocs(genesis.L2AllocsEcotone) diff --git a/op-e2e/e2eutils/setup.go b/op-e2e/e2eutils/setup.go index 57c7c845672d4..1129a9744b7c3 100644 --- a/op-e2e/e2eutils/setup.go +++ b/op-e2e/e2eutils/setup.go @@ -192,6 +192,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) * EcotoneTime: deployConf.EcotoneTime(uint64(deployConf.L1GenesisBlockTimestamp)), FjordTime: deployConf.FjordTime(uint64(deployConf.L1GenesisBlockTimestamp)), GraniteTime: deployConf.GraniteTime(uint64(deployConf.L1GenesisBlockTimestamp)), + HoloceneTime: deployConf.HoloceneTime(uint64(deployConf.L1GenesisBlockTimestamp)), InteropTime: deployConf.InteropTime(uint64(deployConf.L1GenesisBlockTimestamp)), AltDAConfig: pcfg, } @@ -222,7 +223,8 @@ func SystemConfigFromDeployConfig(deployConfig *genesis.DeployConfig) eth.System } func ApplyDeployConfigForks(deployConfig *genesis.DeployConfig) { - isGranite := os.Getenv("OP_E2E_USE_GRANITE") == "true" + isHolocene := os.Getenv("OP_E2E_USE_HOLOCENE") == "true" + isGranite := isHolocene || os.Getenv("OP_E2E_USE_GRANITE") == "true" isFjord := isGranite || os.Getenv("OP_E2E_USE_FJORD") == "true" isEcotone := isFjord || os.Getenv("OP_E2E_USE_ECOTONE") == "true" isDelta := isEcotone || os.Getenv("OP_E2E_USE_DELTA") == "true" @@ -238,6 +240,9 @@ func ApplyDeployConfigForks(deployConfig *genesis.DeployConfig) { if isGranite { deployConfig.L2GenesisGraniteTimeOffset = new(hexutil.Uint64) } + if isHolocene { + deployConfig.L2GenesisHoloceneTimeOffset = new(hexutil.Uint64) + } // Canyon and lower is activated by default deployConfig.L2GenesisCanyonTimeOffset = new(hexutil.Uint64) deployConfig.L2GenesisRegolithTimeOffset = new(hexutil.Uint64) diff --git a/op-e2e/opgeth/op_geth.go b/op-e2e/opgeth/op_geth.go index 8785ea1a95519..a96386ee93500 100644 --- a/op-e2e/opgeth/op_geth.go +++ b/op-e2e/opgeth/op_geth.go @@ -62,7 +62,9 @@ func NewOpGeth(t testing.TB, ctx context.Context, cfg *e2esys.SystemConfig) (*Op var allocsMode genesis.L2AllocsMode allocsMode = genesis.L2AllocsDelta - if graniteTime := cfg.DeployConfig.GraniteTime(l1Block.Time()); graniteTime != nil && *graniteTime <= 0 { + if holoceneTime := cfg.DeployConfig.HoloceneTime(l1Block.Time()); holoceneTime != nil && *holoceneTime <= 0 { + allocsMode = genesis.L2AllocsHolocene + } else if graniteTime := cfg.DeployConfig.GraniteTime(l1Block.Time()); graniteTime != nil && *graniteTime <= 0 { allocsMode = genesis.L2AllocsGranite } else if fjordTime := cfg.DeployConfig.FjordTime(l1Block.Time()); fjordTime != nil && *fjordTime <= 0 { allocsMode = genesis.L2AllocsFjord @@ -244,5 +246,8 @@ func (d *OpGeth) CreatePayloadAttributes(txs ...*types.Transaction) (*eth.Payloa Withdrawals: withdrawals, ParentBeaconBlockRoot: parentBeaconBlockRoot, } + if d.L2ChainConfig.IsHolocene(uint64(timestamp)) { + attrs.EIP1559Params = eth.Bytes8FromUint64(d.SystemConfig.EIP1559Params) + } return &attrs, nil } diff --git a/op-e2e/system/e2esys/setup.go b/op-e2e/system/e2esys/setup.go index ad1969eeed8f9..17d973cb69b31 100644 --- a/op-e2e/system/e2esys/setup.go +++ b/op-e2e/system/e2esys/setup.go @@ -193,6 +193,7 @@ func RegolithSystemConfig(t *testing.T, regolithTimeOffset *hexutil.Uint64, opts cfg.DeployConfig.L2GenesisEcotoneTimeOffset = nil cfg.DeployConfig.L2GenesisFjordTimeOffset = nil cfg.DeployConfig.L2GenesisGraniteTimeOffset = nil + cfg.DeployConfig.L2GenesisHoloceneTimeOffset = nil // ADD NEW FORKS HERE! return cfg } @@ -229,6 +230,12 @@ func GraniteSystemConfig(t *testing.T, graniteTimeOffset *hexutil.Uint64, opts . return cfg } +func HoloceneSystemConfig(t *testing.T, holoceneTimeOffset *hexutil.Uint64, opts ...SystemConfigOpt) SystemConfig { + cfg := GraniteSystemConfig(t, &genesisTime, opts...) + cfg.DeployConfig.L2GenesisHoloceneTimeOffset = holoceneTimeOffset + return cfg +} + func writeDefaultJWT(t testing.TB) string { // Sadly the geth node config cannot load JWT secret from memory, it has to be a file jwtPath := path.Join(t.TempDir(), "jwt_secret") @@ -606,6 +613,7 @@ func (cfg SystemConfig) Start(t *testing.T, startOpts ...StartOption) (*System, EcotoneTime: cfg.DeployConfig.EcotoneTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)), FjordTime: cfg.DeployConfig.FjordTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)), GraniteTime: cfg.DeployConfig.GraniteTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)), + HoloceneTime: cfg.DeployConfig.HoloceneTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)), InteropTime: cfg.DeployConfig.InteropTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)), ProtocolVersionsAddress: cfg.L1Deployments.ProtocolVersionsProxy, AltDAConfig: rollupAltDAConfig, diff --git a/op-e2e/system/proofs/system_fpp_test.go b/op-e2e/system/proofs/system_fpp_test.go index 8729f2c7055c2..810e188bee645 100644 --- a/op-e2e/system/proofs/system_fpp_test.go +++ b/op-e2e/system/proofs/system_fpp_test.go @@ -77,6 +77,7 @@ func applySpanBatchActivation(active bool, dp *genesis.DeployConfig) { dp.L2GenesisDeltaTimeOffset = nil dp.L2GenesisEcotoneTimeOffset = nil dp.L2GenesisFjordTimeOffset = nil + dp.L2GenesisGraniteTimeOffset = nil } } diff --git a/op-node/chaincfg/chains_test.go b/op-node/chaincfg/chains_test.go index 15f062c926071..7499aa4ba3ee4 100644 --- a/op-node/chaincfg/chains_test.go +++ b/op-node/chaincfg/chains_test.go @@ -52,21 +52,22 @@ var mainnetCfg = rollup.Config{ GasLimit: 30_000_000, }, }, - BlockTime: 2, - MaxSequencerDrift: 600, - SeqWindowSize: 3600, - ChannelTimeoutBedrock: 300, - L1ChainID: big.NewInt(1), - L2ChainID: big.NewInt(10), - BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"), - DepositContractAddress: common.HexToAddress("0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"), - L1SystemConfigAddress: common.HexToAddress("0x229047fed2591dbec1eF1118d64F7aF3dB9EB290"), - RegolithTime: u64Ptr(0), - CanyonTime: u64Ptr(1704992401), - DeltaTime: u64Ptr(1708560000), - EcotoneTime: u64Ptr(1710374401), - FjordTime: u64Ptr(1720627201), - GraniteTime: u64Ptr(1726070401), + BlockTime: 2, + MaxSequencerDrift: 600, + SeqWindowSize: 3600, + ChannelTimeoutBedrock: 300, + L1ChainID: big.NewInt(1), + L2ChainID: big.NewInt(10), + BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"), + DepositContractAddress: common.HexToAddress("0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"), + L1SystemConfigAddress: common.HexToAddress("0x229047fed2591dbec1eF1118d64F7aF3dB9EB290"), + RegolithTime: u64Ptr(0), + CanyonTime: u64Ptr(1704992401), + DeltaTime: u64Ptr(1708560000), + EcotoneTime: u64Ptr(1710374401), + FjordTime: u64Ptr(1720627201), + GraniteTime: u64Ptr(1726070401), + // HoloceneTime: TBD ProtocolVersionsAddress: common.HexToAddress("0x8062AbC286f5e7D9428a0Ccb9AbD71e50d93b935"), } @@ -88,21 +89,22 @@ var sepoliaCfg = rollup.Config{ GasLimit: 30000000, }, }, - BlockTime: 2, - MaxSequencerDrift: 600, - SeqWindowSize: 3600, - ChannelTimeoutBedrock: 300, - L1ChainID: big.NewInt(11155111), - L2ChainID: big.NewInt(11155420), - BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155420"), - DepositContractAddress: common.HexToAddress("0x16fc5058f25648194471939df75cf27a2fdc48bc"), - L1SystemConfigAddress: common.HexToAddress("0x034edd2a225f7f429a63e0f1d2084b9e0a93b538"), - RegolithTime: u64Ptr(0), - CanyonTime: u64Ptr(1699981200), - DeltaTime: u64Ptr(1703203200), - EcotoneTime: u64Ptr(1708534800), - FjordTime: u64Ptr(1716998400), - GraniteTime: u64Ptr(1723478400), + BlockTime: 2, + MaxSequencerDrift: 600, + SeqWindowSize: 3600, + ChannelTimeoutBedrock: 300, + L1ChainID: big.NewInt(11155111), + L2ChainID: big.NewInt(11155420), + BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155420"), + DepositContractAddress: common.HexToAddress("0x16fc5058f25648194471939df75cf27a2fdc48bc"), + L1SystemConfigAddress: common.HexToAddress("0x034edd2a225f7f429a63e0f1d2084b9e0a93b538"), + RegolithTime: u64Ptr(0), + CanyonTime: u64Ptr(1699981200), + DeltaTime: u64Ptr(1703203200), + EcotoneTime: u64Ptr(1708534800), + FjordTime: u64Ptr(1716998400), + GraniteTime: u64Ptr(1723478400), + // HoloceneTime: TBD ProtocolVersionsAddress: common.HexToAddress("0x79ADD5713B383DAa0a138d3C4780C7A1804a8090"), } @@ -124,21 +126,22 @@ var sepoliaDev0Cfg = rollup.Config{ GasLimit: 30000000, }, }, - BlockTime: 2, - MaxSequencerDrift: 600, - SeqWindowSize: 3600, - ChannelTimeoutBedrock: 300, - L1ChainID: big.NewInt(11155111), - L2ChainID: big.NewInt(11155421), - BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155421"), - DepositContractAddress: common.HexToAddress("0x76114bd29dFcC7a9892240D317E6c7C2A281Ffc6"), - L1SystemConfigAddress: common.HexToAddress("0xa6b72407e2dc9EBF84b839B69A24C88929cf20F7"), - RegolithTime: u64Ptr(0), - CanyonTime: u64Ptr(0), - DeltaTime: u64Ptr(0), - EcotoneTime: u64Ptr(1706634000), - FjordTime: u64Ptr(1715961600), - GraniteTime: u64Ptr(1723046400), + BlockTime: 2, + MaxSequencerDrift: 600, + SeqWindowSize: 3600, + ChannelTimeoutBedrock: 300, + L1ChainID: big.NewInt(11155111), + L2ChainID: big.NewInt(11155421), + BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155421"), + DepositContractAddress: common.HexToAddress("0x76114bd29dFcC7a9892240D317E6c7C2A281Ffc6"), + L1SystemConfigAddress: common.HexToAddress("0xa6b72407e2dc9EBF84b839B69A24C88929cf20F7"), + RegolithTime: u64Ptr(0), + CanyonTime: u64Ptr(0), + DeltaTime: u64Ptr(0), + EcotoneTime: u64Ptr(1706634000), + FjordTime: u64Ptr(1715961600), + GraniteTime: u64Ptr(1723046400), + // HoloceneTime: TBD ProtocolVersionsAddress: common.HexToAddress("0x252CbE9517F731C618961D890D534183822dcC8d"), } diff --git a/op-node/rollup/clsync/clsync.go b/op-node/rollup/clsync/clsync.go index 64193b21b110d..abefd63a2297c 100644 --- a/op-node/rollup/clsync/clsync.go +++ b/op-node/rollup/clsync/clsync.go @@ -88,7 +88,7 @@ func (eq *CLSync) OnEvent(ev event.Event) bool { // onInvalidPayload checks if the first next-up payload matches the invalid payload. // If so, the payload is dropped, to give the next payloads a try. func (eq *CLSync) onInvalidPayload(x engine.PayloadInvalidEvent) { - eq.log.Debug("CL sync received invalid-payload report", x.Envelope.ExecutionPayload.ID()) + eq.log.Debug("CL sync received invalid-payload report", "id", x.Envelope.ExecutionPayload.ID()) block := x.Envelope.ExecutionPayload if peek := eq.unsafePayloads.Peek(); peek != nil && diff --git a/op-node/rollup/derive/attributes.go b/op-node/rollup/derive/attributes.go index cc38a31b9c54f..03396bd87e590 100644 --- a/op-node/rollup/derive/attributes.go +++ b/op-node/rollup/derive/attributes.go @@ -149,7 +149,7 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex } } - return ð.PayloadAttributes{ + r := ð.PayloadAttributes{ Timestamp: hexutil.Uint64(nextL2Time), PrevRandao: eth.Bytes32(l1Info.MixDigest()), SuggestedFeeRecipient: predeploys.SequencerFeeVaultAddr, @@ -158,5 +158,10 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex GasLimit: (*eth.Uint64Quantity)(&sysConfig.GasLimit), Withdrawals: withdrawals, ParentBeaconBlockRoot: parentBeaconRoot, - }, nil + } + if ba.rollupCfg.IsHolocene(nextL2Time) { + r.EIP1559Params = eth.Bytes8FromUint64(sysConfig.EIP1559Params) + } + + return r, nil } diff --git a/op-node/rollup/derive/attributes_test.go b/op-node/rollup/derive/attributes_test.go index 26b4b1f284370..5c988be3f4a63 100644 --- a/op-node/rollup/derive/attributes_test.go +++ b/op-node/rollup/derive/attributes_test.go @@ -120,6 +120,7 @@ func TestPreparePayloadAttributes(t *testing.T) { attrs, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch) require.NoError(t, err) require.NotNil(t, attrs) + require.Nil(t, attrs.EIP1559Params) // should be nil prior to Holocene require.Equal(t, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp)) require.Equal(t, eth.Bytes32(l1Info.InfoMixDigest), attrs.PrevRandao) require.Equal(t, predeploys.SequencerFeeVaultAddr, attrs.SuggestedFeeRecipient) @@ -287,6 +288,36 @@ func TestPreparePayloadAttributes(t *testing.T) { require.True(t, attrs.NoTxPool) }) + t.Run("holocene 1559 params", func(t *testing.T) { + cfg.ActivateAtGenesis(rollup.Holocene) + rng := rand.New(rand.NewSource(1234)) + l1Fetcher := &testutils.MockL1Source{} + defer l1Fetcher.AssertExpectations(t) + l2Parent := testutils.RandomL2BlockRef(rng) + l1CfgFetcher := &testutils.MockL2Client{} + var eip1559Params uint64 = 123456789 + testSysCfg := eth.SystemConfig{ + BatcherAddr: common.Address{42}, + Overhead: [32]byte{}, + Scalar: [32]byte{}, + EIP1559Params: eip1559Params, + } + l1CfgFetcher.ExpectSystemConfigByL2Hash(l2Parent.Hash, testSysCfg, nil) + defer l1CfgFetcher.AssertExpectations(t) + l1Info := testutils.RandomBlockInfo(rng) + l1Info.InfoParentHash = l2Parent.L1Origin.Hash + l1Info.InfoNum = l2Parent.L1Origin.Number + 1 + epoch := l1Info.ID() + l1InfoTx, err := L1InfoDepositBytes(cfg, testSysCfg, 0, l1Info, 0) + require.NoError(t, err) + l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, nil, nil) + attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher) + attrs, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch) + require.NoError(t, err) + require.Equal(t, eth.Bytes8FromUint64(eip1559Params), attrs.EIP1559Params) + require.Equal(t, l1InfoTx, []byte(attrs.Transactions[0])) + }) + // Test that the payload attributes builder changes the deposit format based on L2-time-based regolith activation t.Run("regolith", func(t *testing.T) { testCases := []struct { diff --git a/op-node/rollup/derive/payload_util.go b/op-node/rollup/derive/payload_util.go index 06a3a5a7f754b..bbfa4d48581bb 100644 --- a/op-node/rollup/derive/payload_util.go +++ b/op-node/rollup/derive/payload_util.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "fmt" + "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum-optimism/optimism/op-node/rollup" @@ -59,34 +60,41 @@ func PayloadToSystemConfig(rollupCfg *rollup.Config, payload *eth.ExecutionPaylo rollupCfg.Genesis.L2.Number, payload.BlockHash, rollupCfg.Genesis.L2.Hash) } return rollupCfg.Genesis.SystemConfig, nil - } else { - if len(payload.Transactions) == 0 { - return eth.SystemConfig{}, fmt.Errorf("l2 block is missing L1 info deposit tx, block hash: %s", payload.BlockHash) - } - var tx types.Transaction - if err := tx.UnmarshalBinary(payload.Transactions[0]); err != nil { - return eth.SystemConfig{}, fmt.Errorf("failed to decode first tx to read l1 info from: %w", err) - } - if tx.Type() != types.DepositTxType { - return eth.SystemConfig{}, fmt.Errorf("first payload tx has unexpected tx type: %d", tx.Type()) - } - info, err := L1BlockInfoFromBytes(rollupCfg, uint64(payload.Timestamp), tx.Data()) - if err != nil { - return eth.SystemConfig{}, fmt.Errorf("failed to parse L1 info deposit tx from L2 block: %w", err) - } - if isEcotoneButNotFirstBlock(rollupCfg, uint64(payload.Timestamp)) { - // Translate Ecotone values back into encoded scalar if needed. - // We do not know if it was derived from a v0 or v1 scalar, - // but v1 is fine, a 0 blob base fee has the same effect. - info.L1FeeScalar[0] = 1 - binary.BigEndian.PutUint32(info.L1FeeScalar[24:28], info.BlobBaseFeeScalar) - binary.BigEndian.PutUint32(info.L1FeeScalar[28:32], info.BaseFeeScalar) + } + + if len(payload.Transactions) == 0 { + return eth.SystemConfig{}, fmt.Errorf("l2 block is missing L1 info deposit tx, block hash: %s", payload.BlockHash) + } + var tx types.Transaction + if err := tx.UnmarshalBinary(payload.Transactions[0]); err != nil { + return eth.SystemConfig{}, fmt.Errorf("failed to decode first tx to read l1 info from: %w", err) + } + if tx.Type() != types.DepositTxType { + return eth.SystemConfig{}, fmt.Errorf("first payload tx has unexpected tx type: %d", tx.Type()) + } + info, err := L1BlockInfoFromBytes(rollupCfg, uint64(payload.Timestamp), tx.Data()) + if err != nil { + return eth.SystemConfig{}, fmt.Errorf("failed to parse L1 info deposit tx from L2 block: %w", err) + } + if isEcotoneButNotFirstBlock(rollupCfg, uint64(payload.Timestamp)) { + // Translate Ecotone values back into encoded scalar if needed. + // We do not know if it was derived from a v0 or v1 scalar, + // but v1 is fine, a 0 blob base fee has the same effect. + info.L1FeeScalar[0] = 1 + binary.BigEndian.PutUint32(info.L1FeeScalar[24:28], info.BlobBaseFeeScalar) + binary.BigEndian.PutUint32(info.L1FeeScalar[28:32], info.BaseFeeScalar) + } + r := eth.SystemConfig{ + BatcherAddr: info.BatcherAddr, + Overhead: info.L1FeeOverhead, + Scalar: info.L1FeeScalar, + GasLimit: uint64(payload.GasLimit), + } + if rollupCfg.IsHolocene(uint64(payload.Timestamp)) { + if err := eip1559.ValidateHoloceneExtraData(payload.ExtraData); err != nil { + return eth.SystemConfig{}, err } - return eth.SystemConfig{ - BatcherAddr: info.BatcherAddr, - Overhead: info.L1FeeOverhead, - Scalar: info.L1FeeScalar, - GasLimit: uint64(payload.GasLimit), - }, err + r.EIP1559Params = binary.BigEndian.Uint64(payload.ExtraData[1:]) } + return r, nil } diff --git a/op-node/rollup/derive/system_config.go b/op-node/rollup/derive/system_config.go index 6b0dbe50411db..0bf2cee12b425 100644 --- a/op-node/rollup/derive/system_config.go +++ b/op-node/rollup/derive/system_config.go @@ -18,9 +18,10 @@ import ( var ( SystemConfigUpdateBatcher = common.Hash{31: 0} - SystemConfigUpdateGasConfig = common.Hash{31: 1} + SystemConfigUpdateFeeScalars = common.Hash{31: 1} SystemConfigUpdateGasLimit = common.Hash{31: 2} SystemConfigUpdateUnsafeBlockSigner = common.Hash{31: 3} + SystemConfigUpdateEIP1559Params = common.Hash{31: 4} ) var ( @@ -93,7 +94,7 @@ func ProcessSystemConfigUpdateLogEvent(destSysCfg *eth.SystemConfig, ev *types.L } destSysCfg.BatcherAddr = address return nil - case SystemConfigUpdateGasConfig: + case SystemConfigUpdateFeeScalars: if pointer, err := solabi.ReadUint64(reader); err != nil || pointer != 32 { return NewCriticalError(errors.New("invalid pointer field")) } @@ -140,6 +141,22 @@ func ProcessSystemConfigUpdateLogEvent(destSysCfg *eth.SystemConfig, ev *types.L } destSysCfg.GasLimit = gasLimit return nil + case SystemConfigUpdateEIP1559Params: + if pointer, err := solabi.ReadUint64(reader); err != nil || pointer != 32 { + return NewCriticalError(errors.New("invalid pointer field")) + } + if length, err := solabi.ReadUint64(reader); err != nil || length != 32 { + return NewCriticalError(errors.New("invalid length field")) + } + params, err := solabi.ReadUint64(reader) + if err != nil { + return NewCriticalError(errors.New("could not read eip-1559 params")) + } + if !solabi.EmptyReader(reader) { + return NewCriticalError(errors.New("too many bytes")) + } + destSysCfg.EIP1559Params = params + return nil case SystemConfigUpdateUnsafeBlockSigner: // Ignored in derivation. This configurable applies to runtime configuration outside of the derivation. return nil diff --git a/op-node/rollup/derive/system_config_test.go b/op-node/rollup/derive/system_config_test.go index cab9e83be6bec..60f2e515d8324 100644 --- a/op-node/rollup/derive/system_config_test.go +++ b/op-node/rollup/derive/system_config_test.go @@ -101,7 +101,7 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) { Topics: []common.Hash{ ConfigUpdateEventABIHash, ConfigUpdateEventVersion0, - SystemConfigUpdateGasConfig, + SystemConfigUpdateFeeScalars, }, }, hook: func(t *testing.T, log *types.Log) *types.Log { @@ -151,7 +151,7 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) { Topics: []common.Hash{ ConfigUpdateEventABIHash, ConfigUpdateEventVersion0, - SystemConfigUpdateGasConfig, + SystemConfigUpdateFeeScalars, }, }, hook: func(t *testing.T, log *types.Log) *types.Log { @@ -185,6 +185,28 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) { config: eth.SystemConfig{}, err: true, }, + { + name: "SystemConfigUpdateEIP1559Params", + log: &types.Log{ + Topics: []common.Hash{ + ConfigUpdateEventABIHash, + ConfigUpdateEventVersion0, + SystemConfigUpdateEIP1559Params, + }, + }, + hook: func(t *testing.T, log *types.Log) *types.Log { + numberData, err := oneUint256.Pack(big.NewInt(123456789)) + require.NoError(t, err) + data, err := bytesArgs.Pack(numberData) + require.NoError(t, err) + log.Data = data + return log + }, + config: eth.SystemConfig{ + EIP1559Params: 123456789, + }, + err: false, + }, } for _, test := range tests { diff --git a/op-node/rollup/sequencing/sequencer_test.go b/op-node/rollup/sequencing/sequencer_test.go index 3265711a0c469..18fee8f5a186b 100644 --- a/op-node/rollup/sequencing/sequencer_test.go +++ b/op-node/rollup/sequencing/sequencer_test.go @@ -643,6 +643,8 @@ func createSequencer(log log.Logger) (*Sequencer, *sequencerTestDeps) { DeltaTime: new(uint64), EcotoneTime: new(uint64), FjordTime: new(uint64), + GraniteTime: new(uint64), + HoloceneTime: new(uint64), } deps := &sequencerTestDeps{ cfg: cfg, diff --git a/op-node/rollup/types_test.go b/op-node/rollup/types_test.go index 61c620be7f13c..e09df43a8f34f 100644 --- a/op-node/rollup/types_test.go +++ b/op-node/rollup/types_test.go @@ -233,14 +233,15 @@ func TestActivations(t *testing.T) { }, }, { - name: "Granite", + name: "Holocene", setUpgradeTime: func(t *uint64, c *Config) { - c.GraniteTime = t + c.HoloceneTime = t }, checkEnabled: func(t uint64, c *Config) bool { - return c.IsGranite(t) + return c.IsHolocene(t) }, }, + { name: "Interop", setUpgradeTime: func(t *uint64, c *Config) { diff --git a/op-program/client/l2/engineapi/block_processor.go b/op-program/client/l2/engineapi/block_processor.go index a2fee8eca7c1f..4f549eb7f6422 100644 --- a/op-program/client/l2/engineapi/block_processor.go +++ b/op-program/client/l2/engineapi/block_processor.go @@ -51,6 +51,15 @@ func NewBlockProcessorFromPayloadAttributes(provider BlockDataProvider, parent c Nonce: types.EncodeNonce(0), ParentBeaconRoot: attrs.ParentBeaconBlockRoot, } + if attrs.EIP1559Params != nil { + // Do we need to check if holocene is active? + d, e := eip1559.DecodeHolocene1559Params(attrs.EIP1559Params[:]) + if d == 0 { + d = provider.Config().BaseFeeChangeDenominator(header.Time) + e = provider.Config().ElasticityMultiplier() + } + header.Extra = eip1559.EncodeHoloceneExtraData(uint32(d), uint32(e)) + } return NewBlockProcessorFromHeader(provider, header) } diff --git a/op-program/client/l2/engineapi/l2_engine_api.go b/op-program/client/l2/engineapi/l2_engine_api.go index 2f47cebbe5d62..10414e2227311 100644 --- a/op-program/client/l2/engineapi/l2_engine_api.go +++ b/op-program/client/l2/engineapi/l2_engine_api.go @@ -100,6 +100,9 @@ func computePayloadId(headBlockHash common.Hash, attrs *eth.PayloadAttributes) e hasher.Write(tx) } _ = binary.Write(hasher, binary.BigEndian, *attrs.GasLimit) + if attrs.EIP1559Params != nil { + hasher.Write(attrs.EIP1559Params[:]) + } var out engine.PayloadID copy(out[:], hasher.Sum(nil)[:8]) return out @@ -155,6 +158,7 @@ func (ea *L2EngineAPI) startBlock(parent common.Hash, attrs *eth.PayloadAttribut if err != nil { return err } + ea.blockProcessor = processor ea.pendingIndices = make(map[common.Address]uint64) ea.l2ForceEmpty = attrs.NoTxPool diff --git a/op-service/eth/types.go b/op-service/eth/types.go index be5899455c213..b6bd940df145f 100644 --- a/op-service/eth/types.go +++ b/op-service/eth/types.go @@ -83,6 +83,40 @@ func (b Bytes32) TerminalString() string { return fmt.Sprintf("%x..%x", b[:3], b[29:]) } +type Bytes8 [8]byte + +func Bytes8FromUint64(i uint64) *Bytes8 { + var b Bytes8 + binary.BigEndian.PutUint64(b[:], i) + return &b +} + +func (b *Bytes8) Uint64() uint64 { + return binary.BigEndian.Uint64(b[:]) +} + +func (b *Bytes8) UnmarshalJSON(text []byte) error { + return hexutil.UnmarshalFixedJSON(reflect.TypeOf(b), text, b[:]) +} + +func (b *Bytes8) UnmarshalText(text []byte) error { + return hexutil.UnmarshalFixedText("Bytes8", text, b[:]) +} + +func (b Bytes8) MarshalText() ([]byte, error) { + return hexutil.Bytes(b[:]).MarshalText() +} + +func (b Bytes8) String() string { + return hexutil.Encode(b[:]) +} + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (b Bytes8) TerminalString() string { + return fmt.Sprintf("%x", b[:]) +} + type Bytes96 [96]byte func (b *Bytes96) UnmarshalJSON(text []byte) error { @@ -329,6 +363,8 @@ type PayloadAttributes struct { NoTxPool bool `json:"noTxPool,omitempty"` // GasLimit override GasLimit *Uint64Quantity `json:"gasLimit,omitempty"` + // EIP-1559 parameters, to be specified only post-Holocene + EIP1559Params *Bytes8 `json:"eip1559Params,omitempty"` } type ExecutePayloadStatus string @@ -390,6 +426,10 @@ type SystemConfig struct { Scalar Bytes32 `json:"scalar"` // GasLimit identifies the L2 block gas limit GasLimit uint64 `json:"gasLimit"` + // EIP1559Params contains the Holocene-encoded EIP-1559 parameters. This + // value will be 0 if Holocene is not active, or if derivation has yet to + // process any EIP_1559_PARAMS system config update events. + EIP1559Params uint64 `json:"eip1559Params"` // More fields can be added for future SystemConfig versions. } @@ -473,7 +513,7 @@ func (b *Bytes48) UnmarshalJSON(text []byte) error { } func (b *Bytes48) UnmarshalText(text []byte) error { - return hexutil.UnmarshalFixedText("Bytes32", text, b[:]) + return hexutil.UnmarshalFixedText("Bytes48", text, b[:]) } func (b Bytes48) MarshalText() ([]byte, error) { diff --git a/packages/contracts-bedrock/README.md b/packages/contracts-bedrock/README.md index a4a718eeac47e..f3c70baf0914d 100644 --- a/packages/contracts-bedrock/README.md +++ b/packages/contracts-bedrock/README.md @@ -138,9 +138,9 @@ Create or modify a file `.json` inside of the [`deploy-config`](./ Use the env var `DEPLOY_CONFIG_PATH` to use a particular deploy config file at runtime. The script will read the latest active fork from the deploy config and the L2 genesis allocs generated will be -compatible with this fork. The automatically detected fork can be overwritten by setting the environment variable -`FORK` either to the lower-case fork name (currently `delta`, `ecotone`, `fjord`, or `granite`) or to `latest`, which -will select the latest fork available (currently `granite`). +compatible with this fork. The automatically detected fork can be overwritten by setting the environment variable `FORK` +either to the lower-case fork name (currently `delta`, `ecotone`, `fjord`, `granite`, or `holocene`) or to `latest`, +which will select the latest fork available (currently `holocene`). By default, the script will dump the L2 genesis allocs of the detected or selected fork only, to the file at `STATE_DUMP_PATH`. The optional environment variable `OUTPUT_MODE` allows to modify this behavior by setting it to one of the following values: diff --git a/packages/contracts-bedrock/deploy-config/devnetL1-template.json b/packages/contracts-bedrock/deploy-config/devnetL1-template.json index 1844d7dbd9cef..2f275f46c4f69 100644 --- a/packages/contracts-bedrock/deploy-config/devnetL1-template.json +++ b/packages/contracts-bedrock/deploy-config/devnetL1-template.json @@ -48,6 +48,7 @@ "l2GenesisDeltaTimeOffset": "0x0", "l2GenesisEcotoneTimeOffset": "0x0", "l2GenesisFjordTimeOffset": "0x0", + "l2GenesisGraniteTimeOffset": "0x0", "l1CancunTimeOffset": "0x0", "systemConfigStartBlock": 0, "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000001", diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index 2dd0e906dbeb9..90dbaf0fe61c8 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -183,6 +183,10 @@ contract L2Genesis is Deployer { if (writeForkGenesisAllocs(_fork, Fork.GRANITE, _mode)) { return; } + + if (writeForkGenesisAllocs(_fork, Fork.HOLOCENE, _mode)) { + return; + } } function writeForkGenesisAllocs(Fork _latest, Fork _current, OutputMode _mode) internal returns (bool isLatest_) { diff --git a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol index 9f34aa3a391dd..c17e4a31670e0 100644 --- a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol @@ -17,6 +17,7 @@ import { Process } from "scripts/libraries/Process.sol"; import { ChainAssertions } from "scripts/deploy/ChainAssertions.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { DeploySuperchainInput, DeploySuperchain, DeploySuperchainOutput } from "scripts/DeploySuperchain.s.sol"; +import { DeployOPChain } from "scripts/DeployOPChain.s.sol"; // generates required artifacts for op-e2e/interop tests import { DeployImplementationsInput, DeployImplementations, @@ -443,6 +444,12 @@ contract Deploy is Deployer { /// @notice Deploy all of the OP Chain specific contracts function deployOpChain() public { console.log("Deploying OP Chain"); + + // The lines below are only to prevent unused import error for DeployOPChain.sol which forces generation + // of the DeployOPChain.sol artifact needed by op-e2e interop tests. + DeployOPChain dop = new DeployOPChain(); + dop.etchIOContracts(); + // Ensure that the requisite contracts are deployed address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy"); OPContractsManager opcm = OPContractsManager(mustGetAddress("OPContractsManagerProxy")); diff --git a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol index 3542f16bc4220..69341dd3e8742 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol @@ -30,6 +30,7 @@ contract DeployConfig is Script { uint256 public l2GenesisEcotoneTimeOffset; uint256 public l2GenesisFjordTimeOffset; uint256 public l2GenesisGraniteTimeOffset; + uint256 public l2GenesisHoloceneTimeOffset; uint256 public maxSequencerDrift; uint256 public sequencerWindowSize; uint256 public channelTimeout; @@ -109,6 +110,7 @@ contract DeployConfig is Script { l2GenesisEcotoneTimeOffset = _readOr(_json, "$.l2GenesisEcotoneTimeOffset", NULL_OFFSET); l2GenesisFjordTimeOffset = _readOr(_json, "$.l2GenesisFjordTimeOffset", NULL_OFFSET); l2GenesisGraniteTimeOffset = _readOr(_json, "$.l2GenesisGraniteTimeOffset", NULL_OFFSET); + l2GenesisHoloceneTimeOffset = _readOr(_json, "$.l2GenesisHoloceneTimeOffset", NULL_OFFSET); maxSequencerDrift = stdJson.readUint(_json, "$.maxSequencerDrift"); sequencerWindowSize = stdJson.readUint(_json, "$.sequencerWindowSize"); @@ -246,7 +248,9 @@ contract DeployConfig is Script { } function latestGenesisFork() internal view returns (Fork) { - if (l2GenesisGraniteTimeOffset == 0) { + if (l2GenesisHoloceneTimeOffset == 0) { + return Fork.HOLOCENE; + } else if (l2GenesisGraniteTimeOffset == 0) { return Fork.GRANITE; } else if (l2GenesisFjordTimeOffset == 0) { return Fork.FJORD; diff --git a/packages/contracts-bedrock/scripts/libraries/Config.sol b/packages/contracts-bedrock/scripts/libraries/Config.sol index 41d2380c46d09..18084761e8076 100644 --- a/packages/contracts-bedrock/scripts/libraries/Config.sol +++ b/packages/contracts-bedrock/scripts/libraries/Config.sol @@ -33,10 +33,11 @@ enum Fork { DELTA, ECOTONE, FJORD, - GRANITE + GRANITE, + HOLOCENE } -Fork constant LATEST_FORK = Fork.GRANITE; +Fork constant LATEST_FORK = Fork.HOLOCENE; library ForkUtils { function toString(Fork _fork) internal pure returns (string memory) { @@ -50,6 +51,8 @@ library ForkUtils { return "fjord"; } else if (_fork == Fork.GRANITE) { return "granite"; + } else if (_fork == Fork.HOLOCENE) { + return "holocene"; } else { return "unknown"; } @@ -163,6 +166,8 @@ library Config { return Fork.FJORD; } else if (forkHash == keccak256(bytes("granite"))) { return Fork.GRANITE; + } else if (forkHash == keccak256(bytes("holocene"))) { + return Fork.HOLOCENE; } else { revert(string.concat("Config: unknown fork: ", forkStr)); } diff --git a/packages/contracts-bedrock/semver-lock.json b/packages/contracts-bedrock/semver-lock.json index 9488435c1ca31..32430cc0deb92 100644 --- a/packages/contracts-bedrock/semver-lock.json +++ b/packages/contracts-bedrock/semver-lock.json @@ -48,12 +48,12 @@ "sourceCodeHash": "0x39489a85bc3a5c8560f82d41b31bf7fe22f5b648f4ed538f61695a73092ea9eb" }, "src/L1/SystemConfig.sol": { - "initCodeHash": "0x2fc36af5b3c493a423a19e0b597f6ff230b756b861b68099f3192d69b6088dc0", - "sourceCodeHash": "0x06a50ac992175fdb434b13e8461893e83862c23ce399e697e6e8109728ad1a3d" + "initCodeHash": "0xbe40fde9ebea4cd0820dc7f1b1a5c8c1f5ace448baacdafb3068d16d55218180", + "sourceCodeHash": "0x7c0366afeb116516d2de0d29456efea82ccdf643b1fcea215e3585d109c314a7" }, "src/L1/SystemConfigInterop.sol": { - "initCodeHash": "0x7515e5ed1266412a8c2d27d99aba6266fda2fc9068c20f0b7e6b555ee5073c91", - "sourceCodeHash": "0x441d1e3e8e987f829f55996b5b6c850da8c59ad48f09cf7e0a69a1fa559d42a2" + "initCodeHash": "0x9fe11f6086be055e9abfc6d38037ba2af5a9644b4a4b3fd66a6cbdb55f17c1e1", + "sourceCodeHash": "0x53de72f7057d459da79207f560b3bf1d057e901ec38f515ea7d29d7e323063e1" }, "src/L2/BaseFeeVault.sol": { "initCodeHash": "0xbf49824cf37e201181484a8a423fcad8f504dc925921a2b28e83398197858dec", diff --git a/packages/contracts-bedrock/src/L1/SystemConfig.sol b/packages/contracts-bedrock/src/L1/SystemConfig.sol index 032cb3227984f..43a5a4926e7dd 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfig.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfig.sol @@ -23,13 +23,13 @@ import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { /// @notice Enum representing different types of updates. /// @custom:value BATCHER Represents an update to the batcher hash. - /// @custom:value GAS_CONFIG Represents an update to txn fee config on L2. + /// @custom:value FEE_SCALARS Represents an update to l1 data fee scalars. /// @custom:value GAS_LIMIT Represents an update to gas limit on L2. /// @custom:value UNSAFE_BLOCK_SIGNER Represents an update to the signer key for unsafe /// block distrubution. enum UpdateType { BATCHER, - GAS_CONFIG, + FEE_SCALARS, GAS_LIMIT, UNSAFE_BLOCK_SIGNER } @@ -130,9 +130,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data); /// @notice Semantic version. - /// @custom:semver 2.3.0-beta.3 + /// @custom:semver 2.3.0-beta.4 function version() public pure virtual returns (string memory) { - return "2.3.0-beta.3"; + return "2.3.0-beta.4"; } /// @notice Constructs the SystemConfig contract. Cannot set @@ -380,7 +380,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { scalar = _scalar; bytes memory data = abi.encode(_overhead, _scalar); - emit ConfigUpdate(VERSION, UpdateType.GAS_CONFIG, data); + emit ConfigUpdate(VERSION, UpdateType.FEE_SCALARS, data); } /// @notice Updates gas config as of the Ecotone upgrade. Can only be called by the owner. @@ -400,7 +400,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { scalar = (uint256(0x01) << 248) | (uint256(_blobbasefeeScalar) << 32) | _basefeeScalar; bytes memory data = abi.encode(overhead, scalar); - emit ConfigUpdate(VERSION, UpdateType.GAS_CONFIG, data); + emit ConfigUpdate(VERSION, UpdateType.FEE_SCALARS, data); } /// @notice Updates the L2 gas limit. Can only be called by the owner. diff --git a/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol b/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol index f7b8921d10d2d..3eb016b2c5385 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol @@ -68,9 +68,9 @@ contract SystemConfigInterop is SystemConfig { Storage.setAddress(DEPENDENCY_MANAGER_SLOT, _dependencyManager); } - /// @custom:semver +interop-beta.1 + /// @custom:semver +interop-beta.2 function version() public pure override returns (string memory) { - return string.concat(super.version(), "+interop-beta.1"); + return string.concat(super.version(), "+interop-beta.2"); } /// @notice Internal setter for the gas paying token address, includes validation. diff --git a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfig.sol b/packages/contracts-bedrock/src/L1/interfaces/ISystemConfig.sol index a7c5434d048b0..33dc66befd1bb 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfig.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/ISystemConfig.sol @@ -7,7 +7,7 @@ import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; interface ISystemConfig { enum UpdateType { BATCHER, - GAS_CONFIG, + FEE_SCALARS, GAS_LIMIT, UNSAFE_BLOCK_SIGNER } diff --git a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigV160.sol b/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigV160.sol index deb0dd2c52ad6..210b0ddf8e5e6 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigV160.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigV160.sol @@ -9,7 +9,7 @@ import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; interface ISystemConfigV160 { enum UpdateType { BATCHER, - GAS_CONFIG, + FEE_SCALARS, GAS_LIMIT, UNSAFE_BLOCK_SIGNER } diff --git a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol index f2a0af0d0b999..bd851e3cdca87 100644 --- a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol +++ b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol @@ -544,7 +544,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { // always zero out most significant byte newScalar = (newScalar << 16) >> 16; vm.expectEmit(address(systemConfig)); - emit ConfigUpdate(0, ISystemConfig.UpdateType.GAS_CONFIG, abi.encode(newOverhead, newScalar)); + emit ConfigUpdate(0, ISystemConfig.UpdateType.FEE_SCALARS, abi.encode(newOverhead, newScalar)); vm.prank(systemConfig.owner()); systemConfig.setGasConfig(newOverhead, newScalar); @@ -557,7 +557,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ffi.encodeScalarEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar }); vm.expectEmit(address(systemConfig)); - emit ConfigUpdate(0, ISystemConfig.UpdateType.GAS_CONFIG, abi.encode(systemConfig.overhead(), encoded)); + emit ConfigUpdate(0, ISystemConfig.UpdateType.FEE_SCALARS, abi.encode(systemConfig.overhead(), encoded)); vm.prank(systemConfig.owner()); systemConfig.setGasConfigEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar });