Commit e7fbaeca authored by Roberto Bayardo's avatar Roberto Bayardo Committed by GitHub

Holocene: initial op-node support for configurable eip-1559 params (#12497)

* extend op-node to support holocene 1559 params

* - add Holocene parameter validation to op-program engine

- updates for latest op-geth tag

---------
Co-authored-by: default avatarMatthew Slipper <me@matthewslipper.com>
parent c6c9c4b5
...@@ -24,7 +24,7 @@ parser.add_argument('--allocs', help='Only create the allocs and exit', type=boo ...@@ -24,7 +24,7 @@ parser.add_argument('--allocs', help='Only create the allocs and exit', type=boo
log = logging.getLogger() log = logging.getLogger()
# Global constants # Global constants
FORKS = ["delta", "ecotone", "fjord", "granite"] FORKS = ["delta", "ecotone", "fjord", "granite", "holocene"]
# Global environment variables # Global environment variables
DEVNET_NO_BUILD = os.getenv('DEVNET_NO_BUILD') == "true" DEVNET_NO_BUILD = os.getenv('DEVNET_NO_BUILD') == "true"
......
...@@ -251,9 +251,9 @@ require ( ...@@ -251,9 +251,9 @@ require (
rsc.io/tmplfunc v0.0.3 // indirect rsc.io/tmplfunc v0.0.3 // indirect
) )
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 v1.14.11 => github.com/ethereum-optimism/op-geth v1.101411.1-rc.2
// 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 // replace github.com/ethereum-optimism/superchain-registry/superchain => ../superchain-registry/superchain
......
...@@ -181,8 +181,8 @@ github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/u ...@@ -181,8 +181,8 @@ github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/u
github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= 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 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= 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.101411.1-rc.2 h1:nOeSTzcFWUCvJO1MJ5AyI26dqR1F7vYgz2jNNKuEtoE=
github.com/ethereum-optimism/op-geth v1.101408.1-0.20241002211323-d5a96613c22b/go.mod h1:7S4pp8KHBmEmKkRjL1BPOc6jY9hW+64YeMUjR3RVLw4= github.com/ethereum-optimism/op-geth v1.101411.1-rc.2/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 h1:hCIrLuOPV3FJfMDvXeOhCC3uQNvFoMIIlkT2mN2cfeg=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac/go.mod h1:XaVXL9jg8BcyOeugECgIUGa9Y3DjYJj71RHmb5qon6M= 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= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
......
...@@ -94,8 +94,8 @@ type L2GenesisBlockDeployConfig struct { ...@@ -94,8 +94,8 @@ type L2GenesisBlockDeployConfig struct {
L2GenesisBlockGasUsed hexutil.Uint64 `json:"l2GenesisBlockGasUsed"` L2GenesisBlockGasUsed hexutil.Uint64 `json:"l2GenesisBlockGasUsed"`
L2GenesisBlockParentHash common.Hash `json:"l2GenesisBlockParentHash"` L2GenesisBlockParentHash common.Hash `json:"l2GenesisBlockParentHash"`
L2GenesisBlockBaseFeePerGas *hexutil.Big `json:"l2GenesisBlockBaseFeePerGas"` L2GenesisBlockBaseFeePerGas *hexutil.Big `json:"l2GenesisBlockBaseFeePerGas"`
// L2GenesisBlockExtraData is configurable extradata. Will default to []byte("BEDROCK") if left unspecified. // Note that there is no L2 genesis ExtraData, as it must default to a valid Holocene eip-1559
L2GenesisBlockExtraData []byte `json:"l2GenesisBlockExtraData"` // configuration. See constant 'HoloceneExtraData' for the specific value used.
// Note that there is no L2 genesis timestamp: // Note that there is no L2 genesis timestamp:
// This is instead configured based on the timestamp of "l1StartingBlockTag". // This is instead configured based on the timestamp of "l1StartingBlockTag".
} }
...@@ -342,6 +342,9 @@ type UpgradeScheduleDeployConfig struct { ...@@ -342,6 +342,9 @@ type UpgradeScheduleDeployConfig struct {
// L2GenesisGraniteTimeOffset is the number of seconds after genesis block that Granite hard fork activates. // 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. // Set it to 0 to activate at genesis. Nil to disable Granite.
L2GenesisGraniteTimeOffset *hexutil.Uint64 `json:"l2GenesisGraniteTimeOffset,omitempty"` 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. // 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. // Set it to 0 to activate at genesis. Nil to disable Interop.
L2GenesisInteropTimeOffset *hexutil.Uint64 `json:"l2GenesisInteropTimeOffset,omitempty"` L2GenesisInteropTimeOffset *hexutil.Uint64 `json:"l2GenesisInteropTimeOffset,omitempty"`
...@@ -390,6 +393,10 @@ func (d *UpgradeScheduleDeployConfig) GraniteTime(genesisTime uint64) *uint64 { ...@@ -390,6 +393,10 @@ func (d *UpgradeScheduleDeployConfig) GraniteTime(genesisTime uint64) *uint64 {
return offsetToUpgradeTime(d.L2GenesisGraniteTimeOffset, genesisTime) return offsetToUpgradeTime(d.L2GenesisGraniteTimeOffset, genesisTime)
} }
func (d *UpgradeScheduleDeployConfig) HoloceneTime(genesisTime uint64) *uint64 {
return offsetToUpgradeTime(d.L2GenesisHoloceneTimeOffset, genesisTime)
}
func (d *UpgradeScheduleDeployConfig) InteropTime(genesisTime uint64) *uint64 { func (d *UpgradeScheduleDeployConfig) InteropTime(genesisTime uint64) *uint64 {
return offsetToUpgradeTime(d.L2GenesisInteropTimeOffset, genesisTime) return offsetToUpgradeTime(d.L2GenesisInteropTimeOffset, genesisTime)
} }
...@@ -422,6 +429,7 @@ func (d *UpgradeScheduleDeployConfig) forks() []Fork { ...@@ -422,6 +429,7 @@ func (d *UpgradeScheduleDeployConfig) forks() []Fork {
{L2GenesisTimeOffset: d.L2GenesisEcotoneTimeOffset, Name: string(L2AllocsEcotone)}, {L2GenesisTimeOffset: d.L2GenesisEcotoneTimeOffset, Name: string(L2AllocsEcotone)},
{L2GenesisTimeOffset: d.L2GenesisFjordTimeOffset, Name: string(L2AllocsFjord)}, {L2GenesisTimeOffset: d.L2GenesisFjordTimeOffset, Name: string(L2AllocsFjord)},
{L2GenesisTimeOffset: d.L2GenesisGraniteTimeOffset, Name: string(L2AllocsGranite)}, {L2GenesisTimeOffset: d.L2GenesisGraniteTimeOffset, Name: string(L2AllocsGranite)},
{L2GenesisTimeOffset: d.L2GenesisHoloceneTimeOffset, Name: string(L2AllocsHolocene)},
} }
} }
...@@ -931,6 +939,7 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Header, l2GenesisBlockHa ...@@ -931,6 +939,7 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Header, l2GenesisBlockHa
EcotoneTime: d.EcotoneTime(l1StartTime), EcotoneTime: d.EcotoneTime(l1StartTime),
FjordTime: d.FjordTime(l1StartTime), FjordTime: d.FjordTime(l1StartTime),
GraniteTime: d.GraniteTime(l1StartTime), GraniteTime: d.GraniteTime(l1StartTime),
HoloceneTime: d.HoloceneTime(l1StartTime),
InteropTime: d.InteropTime(l1StartTime), InteropTime: d.InteropTime(l1StartTime),
ProtocolVersionsAddress: d.ProtocolVersionsProxy, ProtocolVersionsAddress: d.ProtocolVersionsProxy,
AltDAConfig: altDA, AltDAConfig: altDA,
......
...@@ -24,8 +24,6 @@ func TestConfigDataMarshalUnmarshal(t *testing.T) { ...@@ -24,8 +24,6 @@ func TestConfigDataMarshalUnmarshal(t *testing.T) {
dec := json.NewDecoder(bytes.NewReader(b)) dec := json.NewDecoder(bytes.NewReader(b))
decoded := new(DeployConfig) decoded := new(DeployConfig)
require.NoError(t, dec.Decode(decoded)) require.NoError(t, dec.Decode(decoded))
require.EqualValues(t, "non-default value", string(decoded.L2GenesisBlockExtraData))
require.NoError(t, decoded.Check(testlog.Logger(t, log.LevelDebug))) require.NoError(t, decoded.Check(testlog.Logger(t, log.LevelDebug)))
encoded, err := json.MarshalIndent(decoded, "", " ") encoded, err := json.MarshalIndent(decoded, "", " ")
......
...@@ -2,13 +2,13 @@ package genesis ...@@ -2,13 +2,13 @@ package genesis
import ( import (
"errors" "errors"
"fmt"
"math/big" "math/big"
"time" "time"
"github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/predeploys"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "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"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
...@@ -18,8 +18,8 @@ import ( ...@@ -18,8 +18,8 @@ import (
// defaultGasLimit represents the default gas limit for a genesis block. // defaultGasLimit represents the default gas limit for a genesis block.
const defaultGasLimit = 30_000_000 const defaultGasLimit = 30_000_000
// BedrockTransitionBlockExtraData represents the default extra data for the bedrock transition block. // HoloceneExtraData represents the default extra data for Holocene-genesis chains.
var BedrockTransitionBlockExtraData = []byte("BEDROCK") var HoloceneExtraData = eip1559.EncodeHoloceneExtraData(250, 6)
// NewL2Genesis will create a new L2 genesis // NewL2Genesis will create a new L2 genesis
func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Genesis, error) { func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Genesis, error) {
...@@ -70,6 +70,7 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene ...@@ -70,6 +70,7 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene
EcotoneTime: config.EcotoneTime(l1StartTime), EcotoneTime: config.EcotoneTime(l1StartTime),
FjordTime: config.FjordTime(l1StartTime), FjordTime: config.FjordTime(l1StartTime),
GraniteTime: config.GraniteTime(l1StartTime), GraniteTime: config.GraniteTime(l1StartTime),
HoloceneTime: config.HoloceneTime(l1StartTime),
InteropTime: config.InteropTime(l1StartTime), InteropTime: config.InteropTime(l1StartTime),
Optimism: &params.OptimismConfig{ Optimism: &params.OptimismConfig{
EIP1559Denominator: eip1559Denom, EIP1559Denominator: eip1559Denom,
...@@ -91,21 +92,10 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene ...@@ -91,21 +92,10 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene
difficulty = newHexBig(0) difficulty = newHexBig(0)
} }
extraData := config.L2GenesisBlockExtraData
if extraData == nil {
// L2GenesisBlockExtraData is optional, so use a default value when nil
extraData = BedrockTransitionBlockExtraData
}
// Ensure that the extradata is valid
if size := len(extraData); size > 32 {
return nil, fmt.Errorf("transition block extradata too long: %d", size)
}
genesis := &core.Genesis{ genesis := &core.Genesis{
Config: &optimismChainConfig, Config: &optimismChainConfig,
Nonce: uint64(config.L2GenesisBlockNonce), Nonce: uint64(config.L2GenesisBlockNonce),
Timestamp: l1StartTime, Timestamp: l1StartTime,
ExtraData: extraData,
GasLimit: uint64(gasLimit), GasLimit: uint64(gasLimit),
Difficulty: difficulty.ToInt(), Difficulty: difficulty.ToInt(),
Mixhash: config.L2GenesisBlockMixHash, Mixhash: config.L2GenesisBlockMixHash,
...@@ -121,6 +111,9 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene ...@@ -121,6 +111,9 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene
genesis.BlobGasUsed = u64ptr(0) genesis.BlobGasUsed = u64ptr(0)
genesis.ExcessBlobGas = u64ptr(0) genesis.ExcessBlobGas = u64ptr(0)
} }
if optimismChainConfig.IsHolocene(genesis.Timestamp) {
genesis.ExtraData = HoloceneExtraData
}
return genesis, nil return genesis, nil
} }
......
...@@ -26,6 +26,7 @@ const ( ...@@ -26,6 +26,7 @@ const (
L2AllocsEcotone L2AllocsMode = "ecotone" L2AllocsEcotone L2AllocsMode = "ecotone"
L2AllocsFjord L2AllocsMode = "fjord" L2AllocsFjord L2AllocsMode = "fjord"
L2AllocsGranite L2AllocsMode = "granite" L2AllocsGranite L2AllocsMode = "granite"
L2AllocsHolocene L2AllocsMode = "holocene"
) )
var ( var (
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
"l2GenesisBlockGasUsed": "0x0", "l2GenesisBlockGasUsed": "0x0",
"l2GenesisBlockParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "l2GenesisBlockParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"l2GenesisBlockBaseFeePerGas": "0x3b9aca00", "l2GenesisBlockBaseFeePerGas": "0x3b9aca00",
"l2GenesisBlockExtraData": "bm9uLWRlZmF1bHQgdmFsdWU=",
"baseFeeVaultRecipient": "0x42000000000000000000000000000000000000f5", "baseFeeVaultRecipient": "0x42000000000000000000000000000000000000f5",
"l1FeeVaultRecipient": "0x42000000000000000000000000000000000000f6", "l1FeeVaultRecipient": "0x42000000000000000000000000000000000000f6",
"sequencerFeeVaultRecipient": "0x42000000000000000000000000000000000000f7", "sequencerFeeVaultRecipient": "0x42000000000000000000000000000000000000f7",
......
...@@ -130,7 +130,7 @@ func CreateL2(logger log.Logger, fa *foundry.ArtifactsFS, srcFS *foundry.SourceM ...@@ -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 := 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("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 return l2Host
} }
......
...@@ -232,6 +232,7 @@ func InteropL2DevConfig(l1ChainID, l2ChainID uint64, addrs devkeys.Addresses) (* ...@@ -232,6 +232,7 @@ func InteropL2DevConfig(l1ChainID, l2ChainID uint64, addrs devkeys.Addresses) (*
L2GenesisEcotoneTimeOffset: new(hexutil.Uint64), L2GenesisEcotoneTimeOffset: new(hexutil.Uint64),
L2GenesisFjordTimeOffset: new(hexutil.Uint64), L2GenesisFjordTimeOffset: new(hexutil.Uint64),
L2GenesisGraniteTimeOffset: new(hexutil.Uint64), L2GenesisGraniteTimeOffset: new(hexutil.Uint64),
L2GenesisHoloceneTimeOffset: new(hexutil.Uint64),
L2GenesisInteropTimeOffset: new(hexutil.Uint64), L2GenesisInteropTimeOffset: new(hexutil.Uint64),
L1CancunTimeOffset: new(hexutil.Uint64), L1CancunTimeOffset: new(hexutil.Uint64),
UseInterop: true, UseInterop: true,
......
...@@ -206,6 +206,7 @@ func NewHost( ...@@ -206,6 +206,7 @@ func NewHost(
EcotoneTime: nil, EcotoneTime: nil,
FjordTime: nil, FjordTime: nil,
GraniteTime: nil, GraniteTime: nil,
HoloceneTime: nil,
InteropTime: nil, InteropTime: nil,
Optimism: nil, Optimism: nil,
} }
......
...@@ -57,6 +57,7 @@ func DefaultDeployConfig(chainIntent *ChainIntent) genesis.DeployConfig { ...@@ -57,6 +57,7 @@ func DefaultDeployConfig(chainIntent *ChainIntent) genesis.DeployConfig {
L2GenesisEcotoneTimeOffset: u64UtilPtr(0), L2GenesisEcotoneTimeOffset: u64UtilPtr(0),
L2GenesisFjordTimeOffset: u64UtilPtr(0), L2GenesisFjordTimeOffset: u64UtilPtr(0),
L2GenesisGraniteTimeOffset: u64UtilPtr(0), L2GenesisGraniteTimeOffset: u64UtilPtr(0),
L2GenesisHoloceneTimeOffset: u64UtilPtr(0),
UseInterop: false, UseInterop: false,
}, },
L2CoreDeployConfig: genesis.L2CoreDeployConfig{ L2CoreDeployConfig: genesis.L2CoreDeployConfig{
......
...@@ -237,6 +237,7 @@ func GPOParamsChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { ...@@ -237,6 +237,7 @@ func GPOParamsChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
dp.DeployConfig.L2GenesisEcotoneTimeOffset = nil dp.DeployConfig.L2GenesisEcotoneTimeOffset = nil
dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisFjordTimeOffset = nil
dp.DeployConfig.L2GenesisGraniteTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil
dp.DeployConfig.L2GenesisHoloceneTimeOffset = nil
sd := e2eutils.Setup(t, dp, actionsHelpers.DefaultAlloc) sd := e2eutils.Setup(t, dp, actionsHelpers.DefaultAlloc)
log := testlog.Logger(t, log.LevelDebug) log := testlog.Logger(t, log.LevelDebug)
......
...@@ -213,3 +213,11 @@ func (s *L2Sequencer) ActBuildL2ToGranite(t Testing) { ...@@ -213,3 +213,11 @@ func (s *L2Sequencer) ActBuildL2ToGranite(t Testing) {
s.ActL2EndBlock(t) 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)
}
}
...@@ -25,6 +25,8 @@ type hardforkScheduledTest struct { ...@@ -25,6 +25,8 @@ type hardforkScheduledTest struct {
deltaTime *hexutil.Uint64 deltaTime *hexutil.Uint64
ecotoneTime *hexutil.Uint64 ecotoneTime *hexutil.Uint64
fjordTime *hexutil.Uint64 fjordTime *hexutil.Uint64
graniteTime *hexutil.Uint64
holoceneTime *hexutil.Uint64
runToFork string runToFork string
allocType config.AllocType allocType config.AllocType
} }
...@@ -39,6 +41,10 @@ func (tc *hardforkScheduledTest) GetFork(fork string) *uint64 { ...@@ -39,6 +41,10 @@ func (tc *hardforkScheduledTest) GetFork(fork string) *uint64 {
func (tc *hardforkScheduledTest) fork(fork string) **hexutil.Uint64 { func (tc *hardforkScheduledTest) fork(fork string) **hexutil.Uint64 {
switch fork { switch fork {
case "holocene":
return &tc.holoceneTime
case "granite":
return &tc.graniteTime
case "fjord": case "fjord":
return &tc.fjordTime return &tc.fjordTime
case "ecotone": case "ecotone":
...@@ -80,6 +86,8 @@ func testCrossLayerUser(t *testing.T, allocType config.AllocType) { ...@@ -80,6 +86,8 @@ func testCrossLayerUser(t *testing.T, allocType config.AllocType) {
"delta", "delta",
"ecotone", "ecotone",
"fjord", "fjord",
"granite",
"holocene",
} }
for i, fork := range forks { for i, fork := range forks {
i := i i := i
...@@ -136,6 +144,8 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) { ...@@ -136,6 +144,8 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) {
dp.DeployConfig.L2GenesisDeltaTimeOffset = test.deltaTime dp.DeployConfig.L2GenesisDeltaTimeOffset = test.deltaTime
dp.DeployConfig.L2GenesisEcotoneTimeOffset = test.ecotoneTime dp.DeployConfig.L2GenesisEcotoneTimeOffset = test.ecotoneTime
dp.DeployConfig.L2GenesisFjordTimeOffset = test.fjordTime dp.DeployConfig.L2GenesisFjordTimeOffset = test.fjordTime
dp.DeployConfig.L2GenesisGraniteTimeOffset = test.graniteTime
dp.DeployConfig.L2GenesisHoloceneTimeOffset = test.holoceneTime
if test.canyonTime != nil { if test.canyonTime != nil {
require.Zero(t, uint64(*test.canyonTime)%uint64(dp.DeployConfig.L2BlockTime), "canyon fork must be aligned") require.Zero(t, uint64(*test.canyonTime)%uint64(dp.DeployConfig.L2BlockTime), "canyon fork must be aligned")
......
...@@ -61,6 +61,8 @@ func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eut ...@@ -61,6 +61,8 @@ func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eut
dp.DeployConfig.L2GenesisFjordTimeOffset = &genesisBlock dp.DeployConfig.L2GenesisFjordTimeOffset = &genesisBlock
case Granite: case Granite:
dp.DeployConfig.L2GenesisGraniteTimeOffset = &genesisBlock dp.DeployConfig.L2GenesisGraniteTimeOffset = &genesisBlock
case Holocene:
dp.DeployConfig.L2GenesisHoloceneTimeOffset = &genesisBlock
} }
}) })
sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc)
......
...@@ -84,11 +84,12 @@ var ( ...@@ -84,11 +84,12 @@ var (
Regolith = &Hardfork{Name: "Regolith", Precedence: 1} Regolith = &Hardfork{Name: "Regolith", Precedence: 1}
Canyon = &Hardfork{Name: "Canyon", Precedence: 2} Canyon = &Hardfork{Name: "Canyon", Precedence: 2}
Delta = &Hardfork{Name: "Delta", Precedence: 3} Delta = &Hardfork{Name: "Delta", Precedence: 3}
Fjord = &Hardfork{Name: "Fjord", Precedence: 4} Ecotone = &Hardfork{Name: "Ecotone", Precedence: 4}
Ecotone = &Hardfork{Name: "Ecotone", Precedence: 5} Fjord = &Hardfork{Name: "Fjord", Precedence: 5}
Granite = &Hardfork{Name: "Granite", Precedence: 6} 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, Ecotone, Fjord, Granite, Holocene}
var LatestForkOnly = ForkMatrix{Hardforks[len(Hardforks)-1]} var LatestForkOnly = ForkMatrix{Hardforks[len(Hardforks)-1]}
......
...@@ -126,6 +126,7 @@ func TestDencunL2ForkAfterGenesis(gt *testing.T) { ...@@ -126,6 +126,7 @@ func TestDencunL2ForkAfterGenesis(gt *testing.T) {
dp.DeployConfig.L2GenesisEcotoneTimeOffset = &offset dp.DeployConfig.L2GenesisEcotoneTimeOffset = &offset
dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisFjordTimeOffset = nil
dp.DeployConfig.L2GenesisGraniteTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil
dp.DeployConfig.L2GenesisHoloceneTimeOffset = nil
// New forks have to be added here, after changing the default deploy config! // New forks have to be added here, after changing the default deploy config!
sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc)
......
...@@ -52,6 +52,7 @@ func TestEcotoneNetworkUpgradeTransactions(gt *testing.T) { ...@@ -52,6 +52,7 @@ func TestEcotoneNetworkUpgradeTransactions(gt *testing.T) {
dp.DeployConfig.L2GenesisEcotoneTimeOffset = &ecotoneOffset dp.DeployConfig.L2GenesisEcotoneTimeOffset = &ecotoneOffset
dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisFjordTimeOffset = nil
dp.DeployConfig.L2GenesisGraniteTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil
dp.DeployConfig.L2GenesisHoloceneTimeOffset = nil
// New forks have to be added here... // New forks have to be added here...
require.NoError(t, dp.DeployConfig.Check(log), "must have valid config") require.NoError(t, dp.DeployConfig.Check(log), "must have valid config")
......
...@@ -45,6 +45,7 @@ func TestFjordNetworkUpgradeTransactions(gt *testing.T) { ...@@ -45,6 +45,7 @@ func TestFjordNetworkUpgradeTransactions(gt *testing.T) {
dp.DeployConfig.L2GenesisDeltaTimeOffset = &genesisBlock dp.DeployConfig.L2GenesisDeltaTimeOffset = &genesisBlock
dp.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisBlock dp.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisBlock
dp.DeployConfig.L2GenesisFjordTimeOffset = &fjordOffset dp.DeployConfig.L2GenesisFjordTimeOffset = &fjordOffset
dp.DeployConfig.L2GenesisGraniteTimeOffset = nil
require.NoError(t, dp.DeployConfig.Check(log), "must have valid config") require.NoError(t, dp.DeployConfig.Check(log), "must have valid config")
sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc)
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
// ApplyDeltaTimeOffset adjusts fork configuration to not conflict with the delta overrides // ApplyDeltaTimeOffset adjusts fork configuration to not conflict with the delta overrides
func ApplyDeltaTimeOffset(dp *e2eutils.DeployParams, deltaTimeOffset *hexutil.Uint64) { func ApplyDeltaTimeOffset(dp *e2eutils.DeployParams, deltaTimeOffset *hexutil.Uint64) {
dp.DeployConfig.L2GenesisDeltaTimeOffset = deltaTimeOffset dp.DeployConfig.L2GenesisDeltaTimeOffset = deltaTimeOffset
dp.DeployConfig.L2GenesisGraniteTimeOffset = nil
// configure Ecotone to not be before Delta accidentally // configure Ecotone to not be before Delta accidentally
if dp.DeployConfig.L2GenesisEcotoneTimeOffset != nil { if dp.DeployConfig.L2GenesisEcotoneTimeOffset != nil {
if deltaTimeOffset == nil { if deltaTimeOffset == nil {
......
...@@ -142,6 +142,7 @@ func TestHardforkMiddleOfSpanBatch(gt *testing.T) { ...@@ -142,6 +142,7 @@ func TestHardforkMiddleOfSpanBatch(gt *testing.T) {
dp.DeployConfig.L2GenesisEcotoneTimeOffset = nil dp.DeployConfig.L2GenesisEcotoneTimeOffset = nil
dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisFjordTimeOffset = nil
dp.DeployConfig.L2GenesisGraniteTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil
dp.DeployConfig.L2GenesisHoloceneTimeOffset = nil
sd := e2eutils.Setup(t, dp, actionsHelpers.DefaultAlloc) sd := e2eutils.Setup(t, dp, actionsHelpers.DefaultAlloc)
log := testlog.Logger(t, log.LevelError) log := testlog.Logger(t, log.LevelError)
......
...@@ -185,6 +185,7 @@ func initAllocType(root string, allocType AllocType) { ...@@ -185,6 +185,7 @@ func initAllocType(root string, allocType AllocType) {
} }
l2Alloc[mode] = allocs l2Alloc[mode] = allocs
} }
mustL2Allocs(genesis.L2AllocsHolocene)
mustL2Allocs(genesis.L2AllocsGranite) mustL2Allocs(genesis.L2AllocsGranite)
mustL2Allocs(genesis.L2AllocsFjord) mustL2Allocs(genesis.L2AllocsFjord)
mustL2Allocs(genesis.L2AllocsEcotone) mustL2Allocs(genesis.L2AllocsEcotone)
......
...@@ -106,6 +106,22 @@ func Ether(v uint64) *big.Int { ...@@ -106,6 +106,22 @@ func Ether(v uint64) *big.Int {
return new(big.Int).Mul(new(big.Int).SetUint64(v), etherScalar) return new(big.Int).Mul(new(big.Int).SetUint64(v), etherScalar)
} }
func GetL2AllocsMode(dc *genesis.DeployConfig, t uint64) genesis.L2AllocsMode {
if fork := dc.HoloceneTime(t); fork != nil && *fork <= 0 {
return genesis.L2AllocsHolocene
}
if fork := dc.GraniteTime(t); fork != nil && *fork <= 0 {
return genesis.L2AllocsGranite
}
if fork := dc.FjordTime(t); fork != nil && *fork <= 0 {
return genesis.L2AllocsFjord
}
if fork := dc.EcotoneTime(t); fork != nil && *fork <= 0 {
return genesis.L2AllocsEcotone
}
return genesis.L2AllocsDelta
}
// Setup computes the testing setup configurations from deployment configuration and optional allocation parameters. // Setup computes the testing setup configurations from deployment configuration and optional allocation parameters.
func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *SetupData { func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *SetupData {
deployConf := deployParams.DeployConfig.Copy() deployConf := deployParams.DeployConfig.Copy()
...@@ -135,11 +151,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) * ...@@ -135,11 +151,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
l1Block := l1Genesis.ToBlock() l1Block := l1Genesis.ToBlock()
var allocsMode genesis.L2AllocsMode allocsMode := GetL2AllocsMode(deployConf, l1Block.Time())
allocsMode = genesis.L2AllocsDelta
if ecotoneTime := deployConf.EcotoneTime(l1Block.Time()); ecotoneTime != nil && *ecotoneTime == 0 {
allocsMode = genesis.L2AllocsEcotone
}
l2Allocs := config.L2Allocs(deployParams.AllocType, allocsMode) l2Allocs := config.L2Allocs(deployParams.AllocType, allocsMode)
l2Genesis, err := genesis.BuildL2Genesis(deployConf, l2Allocs, l1Block.Header()) l2Genesis, err := genesis.BuildL2Genesis(deployConf, l2Allocs, l1Block.Header())
require.NoError(t, err, "failed to create l2 genesis") require.NoError(t, err, "failed to create l2 genesis")
...@@ -192,6 +204,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) * ...@@ -192,6 +204,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
EcotoneTime: deployConf.EcotoneTime(uint64(deployConf.L1GenesisBlockTimestamp)), EcotoneTime: deployConf.EcotoneTime(uint64(deployConf.L1GenesisBlockTimestamp)),
FjordTime: deployConf.FjordTime(uint64(deployConf.L1GenesisBlockTimestamp)), FjordTime: deployConf.FjordTime(uint64(deployConf.L1GenesisBlockTimestamp)),
GraniteTime: deployConf.GraniteTime(uint64(deployConf.L1GenesisBlockTimestamp)), GraniteTime: deployConf.GraniteTime(uint64(deployConf.L1GenesisBlockTimestamp)),
HoloceneTime: deployConf.HoloceneTime(uint64(deployConf.L1GenesisBlockTimestamp)),
InteropTime: deployConf.InteropTime(uint64(deployConf.L1GenesisBlockTimestamp)), InteropTime: deployConf.InteropTime(uint64(deployConf.L1GenesisBlockTimestamp)),
AltDAConfig: pcfg, AltDAConfig: pcfg,
} }
...@@ -222,7 +235,8 @@ func SystemConfigFromDeployConfig(deployConfig *genesis.DeployConfig) eth.System ...@@ -222,7 +235,8 @@ func SystemConfigFromDeployConfig(deployConfig *genesis.DeployConfig) eth.System
} }
func ApplyDeployConfigForks(deployConfig *genesis.DeployConfig) { 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" isFjord := isGranite || os.Getenv("OP_E2E_USE_FJORD") == "true"
isEcotone := isFjord || os.Getenv("OP_E2E_USE_ECOTONE") == "true" isEcotone := isFjord || os.Getenv("OP_E2E_USE_ECOTONE") == "true"
isDelta := isEcotone || os.Getenv("OP_E2E_USE_DELTA") == "true" isDelta := isEcotone || os.Getenv("OP_E2E_USE_DELTA") == "true"
...@@ -238,6 +252,9 @@ func ApplyDeployConfigForks(deployConfig *genesis.DeployConfig) { ...@@ -238,6 +252,9 @@ func ApplyDeployConfigForks(deployConfig *genesis.DeployConfig) {
if isGranite { if isGranite {
deployConfig.L2GenesisGraniteTimeOffset = new(hexutil.Uint64) deployConfig.L2GenesisGraniteTimeOffset = new(hexutil.Uint64)
} }
if isHolocene {
deployConfig.L2GenesisHoloceneTimeOffset = new(hexutil.Uint64)
}
// Canyon and lower is activated by default // Canyon and lower is activated by default
deployConfig.L2GenesisCanyonTimeOffset = new(hexutil.Uint64) deployConfig.L2GenesisCanyonTimeOffset = new(hexutil.Uint64)
deployConfig.L2GenesisRegolithTimeOffset = new(hexutil.Uint64) deployConfig.L2GenesisRegolithTimeOffset = new(hexutil.Uint64)
......
...@@ -59,16 +59,7 @@ func NewOpGeth(t testing.TB, ctx context.Context, cfg *e2esys.SystemConfig) (*Op ...@@ -59,16 +59,7 @@ func NewOpGeth(t testing.TB, ctx context.Context, cfg *e2esys.SystemConfig) (*Op
l1Genesis, err := genesis.BuildL1DeveloperGenesis(cfg.DeployConfig, config.L1Allocs(config.AllocTypeStandard), config.L1Deployments(config.AllocTypeStandard)) l1Genesis, err := genesis.BuildL1DeveloperGenesis(cfg.DeployConfig, config.L1Allocs(config.AllocTypeStandard), config.L1Deployments(config.AllocTypeStandard))
require.NoError(t, err) require.NoError(t, err)
l1Block := l1Genesis.ToBlock() l1Block := l1Genesis.ToBlock()
allocsMode := e2eutils.GetL2AllocsMode(cfg.DeployConfig, l1Block.Time())
var allocsMode genesis.L2AllocsMode
allocsMode = genesis.L2AllocsDelta
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
} else if ecotoneTime := cfg.DeployConfig.EcotoneTime(l1Block.Time()); ecotoneTime != nil && *ecotoneTime <= 0 {
allocsMode = genesis.L2AllocsEcotone
}
l2Allocs := config.L2Allocs(config.AllocTypeStandard, allocsMode) l2Allocs := config.L2Allocs(config.AllocTypeStandard, allocsMode)
l2Genesis, err := genesis.BuildL2Genesis(cfg.DeployConfig, l2Allocs, l1Block.Header()) l2Genesis, err := genesis.BuildL2Genesis(cfg.DeployConfig, l2Allocs, l1Block.Header())
require.NoError(t, err) require.NoError(t, err)
...@@ -244,5 +235,9 @@ func (d *OpGeth) CreatePayloadAttributes(txs ...*types.Transaction) (*eth.Payloa ...@@ -244,5 +235,9 @@ func (d *OpGeth) CreatePayloadAttributes(txs ...*types.Transaction) (*eth.Payloa
Withdrawals: withdrawals, Withdrawals: withdrawals,
ParentBeaconBlockRoot: parentBeaconBlockRoot, ParentBeaconBlockRoot: parentBeaconBlockRoot,
} }
if d.L2ChainConfig.IsHolocene(uint64(timestamp)) {
attrs.EIP1559Params = new(eth.Bytes8)
*attrs.EIP1559Params = d.SystemConfig.EIP1559Params
}
return &attrs, nil return &attrs, nil
} }
...@@ -193,6 +193,7 @@ func RegolithSystemConfig(t *testing.T, regolithTimeOffset *hexutil.Uint64, opts ...@@ -193,6 +193,7 @@ func RegolithSystemConfig(t *testing.T, regolithTimeOffset *hexutil.Uint64, opts
cfg.DeployConfig.L2GenesisEcotoneTimeOffset = nil cfg.DeployConfig.L2GenesisEcotoneTimeOffset = nil
cfg.DeployConfig.L2GenesisFjordTimeOffset = nil cfg.DeployConfig.L2GenesisFjordTimeOffset = nil
cfg.DeployConfig.L2GenesisGraniteTimeOffset = nil cfg.DeployConfig.L2GenesisGraniteTimeOffset = nil
cfg.DeployConfig.L2GenesisHoloceneTimeOffset = nil
// ADD NEW FORKS HERE! // ADD NEW FORKS HERE!
return cfg return cfg
} }
...@@ -229,6 +230,12 @@ func GraniteSystemConfig(t *testing.T, graniteTimeOffset *hexutil.Uint64, opts . ...@@ -229,6 +230,12 @@ func GraniteSystemConfig(t *testing.T, graniteTimeOffset *hexutil.Uint64, opts .
return cfg 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 { func writeDefaultJWT(t testing.TB) string {
// Sadly the geth node config cannot load JWT secret from memory, it has to be a file // Sadly the geth node config cannot load JWT secret from memory, it has to be a file
jwtPath := path.Join(t.TempDir(), "jwt_secret") jwtPath := path.Join(t.TempDir(), "jwt_secret")
...@@ -606,6 +613,7 @@ func (cfg SystemConfig) Start(t *testing.T, startOpts ...StartOption) (*System, ...@@ -606,6 +613,7 @@ func (cfg SystemConfig) Start(t *testing.T, startOpts ...StartOption) (*System,
EcotoneTime: cfg.DeployConfig.EcotoneTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)), EcotoneTime: cfg.DeployConfig.EcotoneTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
FjordTime: cfg.DeployConfig.FjordTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)), FjordTime: cfg.DeployConfig.FjordTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
GraniteTime: cfg.DeployConfig.GraniteTime(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)), InteropTime: cfg.DeployConfig.InteropTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
ProtocolVersionsAddress: cfg.L1Deployments.ProtocolVersionsProxy, ProtocolVersionsAddress: cfg.L1Deployments.ProtocolVersionsProxy,
AltDAConfig: rollupAltDAConfig, AltDAConfig: rollupAltDAConfig,
......
...@@ -77,6 +77,7 @@ func applySpanBatchActivation(active bool, dp *genesis.DeployConfig) { ...@@ -77,6 +77,7 @@ func applySpanBatchActivation(active bool, dp *genesis.DeployConfig) {
dp.L2GenesisDeltaTimeOffset = nil dp.L2GenesisDeltaTimeOffset = nil
dp.L2GenesisEcotoneTimeOffset = nil dp.L2GenesisEcotoneTimeOffset = nil
dp.L2GenesisFjordTimeOffset = nil dp.L2GenesisFjordTimeOffset = nil
dp.L2GenesisGraniteTimeOffset = nil
} }
} }
......
...@@ -67,6 +67,7 @@ var mainnetCfg = rollup.Config{ ...@@ -67,6 +67,7 @@ var mainnetCfg = rollup.Config{
EcotoneTime: u64Ptr(1710374401), EcotoneTime: u64Ptr(1710374401),
FjordTime: u64Ptr(1720627201), FjordTime: u64Ptr(1720627201),
GraniteTime: u64Ptr(1726070401), GraniteTime: u64Ptr(1726070401),
// HoloceneTime: TBD
ProtocolVersionsAddress: common.HexToAddress("0x8062AbC286f5e7D9428a0Ccb9AbD71e50d93b935"), ProtocolVersionsAddress: common.HexToAddress("0x8062AbC286f5e7D9428a0Ccb9AbD71e50d93b935"),
} }
...@@ -103,6 +104,7 @@ var sepoliaCfg = rollup.Config{ ...@@ -103,6 +104,7 @@ var sepoliaCfg = rollup.Config{
EcotoneTime: u64Ptr(1708534800), EcotoneTime: u64Ptr(1708534800),
FjordTime: u64Ptr(1716998400), FjordTime: u64Ptr(1716998400),
GraniteTime: u64Ptr(1723478400), GraniteTime: u64Ptr(1723478400),
// HoloceneTime: TBD
ProtocolVersionsAddress: common.HexToAddress("0x79ADD5713B383DAa0a138d3C4780C7A1804a8090"), ProtocolVersionsAddress: common.HexToAddress("0x79ADD5713B383DAa0a138d3C4780C7A1804a8090"),
} }
...@@ -139,6 +141,7 @@ var sepoliaDev0Cfg = rollup.Config{ ...@@ -139,6 +141,7 @@ var sepoliaDev0Cfg = rollup.Config{
EcotoneTime: u64Ptr(1706634000), EcotoneTime: u64Ptr(1706634000),
FjordTime: u64Ptr(1715961600), FjordTime: u64Ptr(1715961600),
GraniteTime: u64Ptr(1723046400), GraniteTime: u64Ptr(1723046400),
// HoloceneTime: TBD
ProtocolVersionsAddress: common.HexToAddress("0x252CbE9517F731C618961D890D534183822dcC8d"), ProtocolVersionsAddress: common.HexToAddress("0x252CbE9517F731C618961D890D534183822dcC8d"),
} }
......
...@@ -88,7 +88,7 @@ func (eq *CLSync) OnEvent(ev event.Event) bool { ...@@ -88,7 +88,7 @@ func (eq *CLSync) OnEvent(ev event.Event) bool {
// onInvalidPayload checks if the first next-up payload matches the invalid payload. // 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. // If so, the payload is dropped, to give the next payloads a try.
func (eq *CLSync) onInvalidPayload(x engine.PayloadInvalidEvent) { 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 block := x.Envelope.ExecutionPayload
if peek := eq.unsafePayloads.Peek(); peek != nil && if peek := eq.unsafePayloads.Peek(); peek != nil &&
......
...@@ -149,7 +149,7 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex ...@@ -149,7 +149,7 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex
} }
} }
return &eth.PayloadAttributes{ r := &eth.PayloadAttributes{
Timestamp: hexutil.Uint64(nextL2Time), Timestamp: hexutil.Uint64(nextL2Time),
PrevRandao: eth.Bytes32(l1Info.MixDigest()), PrevRandao: eth.Bytes32(l1Info.MixDigest()),
SuggestedFeeRecipient: predeploys.SequencerFeeVaultAddr, SuggestedFeeRecipient: predeploys.SequencerFeeVaultAddr,
...@@ -158,5 +158,11 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex ...@@ -158,5 +158,11 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex
GasLimit: (*eth.Uint64Quantity)(&sysConfig.GasLimit), GasLimit: (*eth.Uint64Quantity)(&sysConfig.GasLimit),
Withdrawals: withdrawals, Withdrawals: withdrawals,
ParentBeaconBlockRoot: parentBeaconRoot, ParentBeaconBlockRoot: parentBeaconRoot,
}, nil }
if ba.rollupCfg.IsHolocene(nextL2Time) {
r.EIP1559Params = new(eth.Bytes8)
*r.EIP1559Params = sysConfig.EIP1559Params
}
return r, nil
} }
...@@ -120,6 +120,7 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -120,6 +120,7 @@ func TestPreparePayloadAttributes(t *testing.T) {
attrs, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch) attrs, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, attrs) 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, l2Parent.Time+cfg.BlockTime, uint64(attrs.Timestamp))
require.Equal(t, eth.Bytes32(l1Info.InfoMixDigest), attrs.PrevRandao) require.Equal(t, eth.Bytes32(l1Info.InfoMixDigest), attrs.PrevRandao)
require.Equal(t, predeploys.SequencerFeeVaultAddr, attrs.SuggestedFeeRecipient) require.Equal(t, predeploys.SequencerFeeVaultAddr, attrs.SuggestedFeeRecipient)
...@@ -287,6 +288,36 @@ func TestPreparePayloadAttributes(t *testing.T) { ...@@ -287,6 +288,36 @@ func TestPreparePayloadAttributes(t *testing.T) {
require.True(t, attrs.NoTxPool) 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{}
eip1559Params := eth.Bytes8([]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8})
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, 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 // Test that the payload attributes builder changes the deposit format based on L2-time-based regolith activation
t.Run("regolith", func(t *testing.T) { t.Run("regolith", func(t *testing.T) {
testCases := []struct { testCases := []struct {
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
...@@ -59,7 +60,8 @@ func PayloadToSystemConfig(rollupCfg *rollup.Config, payload *eth.ExecutionPaylo ...@@ -59,7 +60,8 @@ func PayloadToSystemConfig(rollupCfg *rollup.Config, payload *eth.ExecutionPaylo
rollupCfg.Genesis.L2.Number, payload.BlockHash, rollupCfg.Genesis.L2.Hash) rollupCfg.Genesis.L2.Number, payload.BlockHash, rollupCfg.Genesis.L2.Hash)
} }
return rollupCfg.Genesis.SystemConfig, nil return rollupCfg.Genesis.SystemConfig, nil
} else { }
if len(payload.Transactions) == 0 { if len(payload.Transactions) == 0 {
return eth.SystemConfig{}, fmt.Errorf("l2 block is missing L1 info deposit tx, block hash: %s", payload.BlockHash) return eth.SystemConfig{}, fmt.Errorf("l2 block is missing L1 info deposit tx, block hash: %s", payload.BlockHash)
} }
...@@ -82,11 +84,18 @@ func PayloadToSystemConfig(rollupCfg *rollup.Config, payload *eth.ExecutionPaylo ...@@ -82,11 +84,18 @@ func PayloadToSystemConfig(rollupCfg *rollup.Config, payload *eth.ExecutionPaylo
binary.BigEndian.PutUint32(info.L1FeeScalar[24:28], info.BlobBaseFeeScalar) binary.BigEndian.PutUint32(info.L1FeeScalar[24:28], info.BlobBaseFeeScalar)
binary.BigEndian.PutUint32(info.L1FeeScalar[28:32], info.BaseFeeScalar) binary.BigEndian.PutUint32(info.L1FeeScalar[28:32], info.BaseFeeScalar)
} }
return eth.SystemConfig{ r := eth.SystemConfig{
BatcherAddr: info.BatcherAddr, BatcherAddr: info.BatcherAddr,
Overhead: info.L1FeeOverhead, Overhead: info.L1FeeOverhead,
Scalar: info.L1FeeScalar, Scalar: info.L1FeeScalar,
GasLimit: uint64(payload.GasLimit), GasLimit: uint64(payload.GasLimit),
}, err
} }
if rollupCfg.IsHolocene(uint64(payload.Timestamp)) {
if err := eip1559.ValidateHoloceneExtraData(payload.ExtraData); err != nil {
return eth.SystemConfig{}, err
}
d, e := eip1559.DecodeHoloceneExtraData(payload.ExtraData)
copy(r.EIP1559Params[:], eip1559.EncodeHolocene1559Params(d, e))
}
return r, nil
} }
...@@ -18,9 +18,10 @@ import ( ...@@ -18,9 +18,10 @@ import (
var ( var (
SystemConfigUpdateBatcher = common.Hash{31: 0} SystemConfigUpdateBatcher = common.Hash{31: 0}
SystemConfigUpdateGasConfig = common.Hash{31: 1} SystemConfigUpdateFeeScalars = common.Hash{31: 1}
SystemConfigUpdateGasLimit = common.Hash{31: 2} SystemConfigUpdateGasLimit = common.Hash{31: 2}
SystemConfigUpdateUnsafeBlockSigner = common.Hash{31: 3} SystemConfigUpdateUnsafeBlockSigner = common.Hash{31: 3}
SystemConfigUpdateEIP1559Params = common.Hash{31: 4}
) )
var ( var (
...@@ -93,7 +94,7 @@ func ProcessSystemConfigUpdateLogEvent(destSysCfg *eth.SystemConfig, ev *types.L ...@@ -93,7 +94,7 @@ func ProcessSystemConfigUpdateLogEvent(destSysCfg *eth.SystemConfig, ev *types.L
} }
destSysCfg.BatcherAddr = address destSysCfg.BatcherAddr = address
return nil return nil
case SystemConfigUpdateGasConfig: case SystemConfigUpdateFeeScalars:
if pointer, err := solabi.ReadUint64(reader); err != nil || pointer != 32 { if pointer, err := solabi.ReadUint64(reader); err != nil || pointer != 32 {
return NewCriticalError(errors.New("invalid pointer field")) return NewCriticalError(errors.New("invalid pointer field"))
} }
...@@ -140,6 +141,22 @@ func ProcessSystemConfigUpdateLogEvent(destSysCfg *eth.SystemConfig, ev *types.L ...@@ -140,6 +141,22 @@ func ProcessSystemConfigUpdateLogEvent(destSysCfg *eth.SystemConfig, ev *types.L
} }
destSysCfg.GasLimit = gasLimit destSysCfg.GasLimit = gasLimit
return nil 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.ReadEthBytes32(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"))
}
copy(destSysCfg.EIP1559Params[:], params[24:32])
return nil
case SystemConfigUpdateUnsafeBlockSigner: case SystemConfigUpdateUnsafeBlockSigner:
// Ignored in derivation. This configurable applies to runtime configuration outside of the derivation. // Ignored in derivation. This configurable applies to runtime configuration outside of the derivation.
return nil return nil
......
...@@ -32,6 +32,7 @@ var ( ...@@ -32,6 +32,7 @@ var (
oneUint256 = abi.Arguments{ oneUint256 = abi.Arguments{
{Type: uint256T}, {Type: uint256T},
} }
eip1559Params = []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}
) )
// TestProcessSystemConfigUpdateLogEvent tests the parsing of an event and mutating the // TestProcessSystemConfigUpdateLogEvent tests the parsing of an event and mutating the
...@@ -101,7 +102,7 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) { ...@@ -101,7 +102,7 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) {
Topics: []common.Hash{ Topics: []common.Hash{
ConfigUpdateEventABIHash, ConfigUpdateEventABIHash,
ConfigUpdateEventVersion0, ConfigUpdateEventVersion0,
SystemConfigUpdateGasConfig, SystemConfigUpdateFeeScalars,
}, },
}, },
hook: func(t *testing.T, log *types.Log) *types.Log { hook: func(t *testing.T, log *types.Log) *types.Log {
...@@ -151,7 +152,7 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) { ...@@ -151,7 +152,7 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) {
Topics: []common.Hash{ Topics: []common.Hash{
ConfigUpdateEventABIHash, ConfigUpdateEventABIHash,
ConfigUpdateEventVersion0, ConfigUpdateEventVersion0,
SystemConfigUpdateGasConfig, SystemConfigUpdateFeeScalars,
}, },
}, },
hook: func(t *testing.T, log *types.Log) *types.Log { hook: func(t *testing.T, log *types.Log) *types.Log {
...@@ -185,6 +186,28 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) { ...@@ -185,6 +186,28 @@ func TestProcessSystemConfigUpdateLogEvent(t *testing.T) {
config: eth.SystemConfig{}, config: eth.SystemConfig{},
err: true, 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(new(big.Int).SetBytes(eip1559Params))
require.NoError(t, err)
data, err := bytesArgs.Pack(numberData)
require.NoError(t, err)
log.Data = data
return log
},
config: eth.SystemConfig{
EIP1559Params: eth.Bytes8(eip1559Params),
},
err: false,
},
} }
for _, test := range tests { for _, test := range tests {
......
...@@ -643,6 +643,8 @@ func createSequencer(log log.Logger) (*Sequencer, *sequencerTestDeps) { ...@@ -643,6 +643,8 @@ func createSequencer(log log.Logger) (*Sequencer, *sequencerTestDeps) {
DeltaTime: new(uint64), DeltaTime: new(uint64),
EcotoneTime: new(uint64), EcotoneTime: new(uint64),
FjordTime: new(uint64), FjordTime: new(uint64),
GraniteTime: new(uint64),
HoloceneTime: new(uint64),
} }
deps := &sequencerTestDeps{ deps := &sequencerTestDeps{
cfg: cfg, cfg: cfg,
......
...@@ -241,6 +241,15 @@ func TestActivations(t *testing.T) { ...@@ -241,6 +241,15 @@ func TestActivations(t *testing.T) {
return c.IsGranite(t) return c.IsGranite(t)
}, },
}, },
{
name: "Holocene",
setUpgradeTime: func(t *uint64, c *Config) {
c.HoloceneTime = t
},
checkEnabled: func(t uint64, c *Config) bool {
return c.IsHolocene(t)
},
},
{ {
name: "Interop", name: "Interop",
setUpgradeTime: func(t *uint64, c *Config) { setUpgradeTime: func(t *uint64, c *Config) {
......
...@@ -51,6 +51,14 @@ func NewBlockProcessorFromPayloadAttributes(provider BlockDataProvider, parent c ...@@ -51,6 +51,14 @@ func NewBlockProcessorFromPayloadAttributes(provider BlockDataProvider, parent c
Nonce: types.EncodeNonce(0), Nonce: types.EncodeNonce(0),
ParentBeaconRoot: attrs.ParentBeaconBlockRoot, ParentBeaconRoot: attrs.ParentBeaconBlockRoot,
} }
if attrs.EIP1559Params != nil {
d, e := eip1559.DecodeHolocene1559Params(attrs.EIP1559Params[:])
if d == 0 {
d = provider.Config().BaseFeeChangeDenominator(header.Time)
e = provider.Config().ElasticityMultiplier()
}
header.Extra = eip1559.EncodeHoloceneExtraData(d, e)
}
return NewBlockProcessorFromHeader(provider, header) return NewBlockProcessorFromHeader(provider, header)
} }
......
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
...@@ -100,6 +101,9 @@ func computePayloadId(headBlockHash common.Hash, attrs *eth.PayloadAttributes) e ...@@ -100,6 +101,9 @@ func computePayloadId(headBlockHash common.Hash, attrs *eth.PayloadAttributes) e
hasher.Write(tx) hasher.Write(tx)
} }
_ = binary.Write(hasher, binary.BigEndian, *attrs.GasLimit) _ = binary.Write(hasher, binary.BigEndian, *attrs.GasLimit)
if attrs.EIP1559Params != nil {
hasher.Write(attrs.EIP1559Params[:])
}
var out engine.PayloadID var out engine.PayloadID
copy(out[:], hasher.Sum(nil)[:8]) copy(out[:], hasher.Sum(nil)[:8])
return out return out
...@@ -155,6 +159,7 @@ func (ea *L2EngineAPI) startBlock(parent common.Hash, attrs *eth.PayloadAttribut ...@@ -155,6 +159,7 @@ func (ea *L2EngineAPI) startBlock(parent common.Hash, attrs *eth.PayloadAttribut
if err != nil { if err != nil {
return err return err
} }
ea.blockProcessor = processor ea.blockProcessor = processor
ea.pendingIndices = make(map[common.Address]uint64) ea.pendingIndices = make(map[common.Address]uint64)
ea.l2ForceEmpty = attrs.NoTxPool ea.l2ForceEmpty = attrs.NoTxPool
...@@ -256,15 +261,27 @@ func (ea *L2EngineAPI) ForkchoiceUpdatedV3(ctx context.Context, state *eth.Forkc ...@@ -256,15 +261,27 @@ func (ea *L2EngineAPI) ForkchoiceUpdatedV3(ctx context.Context, state *eth.Forkc
// Ported from: https://github.com/ethereum-optimism/op-geth/blob/c50337a60a1309a0f1dca3bf33ed1bb38c46cdd7/eth/catalyst/api.go#L206-L218 // Ported from: https://github.com/ethereum-optimism/op-geth/blob/c50337a60a1309a0f1dca3bf33ed1bb38c46cdd7/eth/catalyst/api.go#L206-L218
func (ea *L2EngineAPI) verifyPayloadAttributes(attr *eth.PayloadAttributes) error { func (ea *L2EngineAPI) verifyPayloadAttributes(attr *eth.PayloadAttributes) error {
c := ea.config() c := ea.config()
t := uint64(attr.Timestamp)
// Verify withdrawals attribute for Shanghai. // Verify withdrawals attribute for Shanghai.
if err := checkAttribute(c.IsShanghai, attr.Withdrawals != nil, c.LondonBlock, uint64(attr.Timestamp)); err != nil { if err := checkAttribute(c.IsShanghai, attr.Withdrawals != nil, c.LondonBlock, t); err != nil {
return fmt.Errorf("invalid withdrawals: %w", err) return fmt.Errorf("invalid withdrawals: %w", err)
} }
// Verify beacon root attribute for Cancun. // Verify beacon root attribute for Cancun.
if err := checkAttribute(c.IsCancun, attr.ParentBeaconBlockRoot != nil, c.LondonBlock, uint64(attr.Timestamp)); err != nil { if err := checkAttribute(c.IsCancun, attr.ParentBeaconBlockRoot != nil, c.LondonBlock, t); err != nil {
return fmt.Errorf("invalid parent beacon block root: %w", err) return fmt.Errorf("invalid parent beacon block root: %w", err)
} }
// Verify EIP-1559 params for Holocene.
if c.IsHolocene(t) {
if attr.EIP1559Params == nil {
return errors.New("got nil eip-1559 params while Holocene is active")
}
if err := eip1559.ValidateHolocene1559Params(attr.EIP1559Params[:]); err != nil {
return fmt.Errorf("invalid Holocene params: %w", err)
}
} else if attr.EIP1559Params != nil {
return errors.New("got Holocene params though fork not active")
}
return nil return nil
} }
...@@ -318,6 +335,13 @@ func (ea *L2EngineAPI) NewPayloadV3(ctx context.Context, params *eth.ExecutionPa ...@@ -318,6 +335,13 @@ func (ea *L2EngineAPI) NewPayloadV3(ctx context.Context, params *eth.ExecutionPa
return &eth.PayloadStatusV1{Status: eth.ExecutionInvalid}, engine.UnsupportedFork.With(errors.New("newPayloadV3 called pre-cancun")) return &eth.PayloadStatusV1{Status: eth.ExecutionInvalid}, engine.UnsupportedFork.With(errors.New("newPayloadV3 called pre-cancun"))
} }
// Payload must have eip-1559 params in ExtraData after Holocene
if ea.config().IsHolocene(uint64(params.Timestamp)) {
if err := eip1559.ValidateHoloceneExtraData(params.ExtraData); err != nil {
return &eth.PayloadStatusV1{Status: eth.ExecutionInvalid}, engine.UnsupportedFork.With(errors.New("invalid holocene extraData post-holoocene"))
}
}
return ea.newPayload(ctx, params, versionedHashes, beaconRoot) return ea.newPayload(ctx, params, versionedHashes, beaconRoot)
} }
......
...@@ -28,6 +28,7 @@ func TestCreatedBlocksAreCached(t *testing.T) { ...@@ -28,6 +28,7 @@ func TestCreatedBlocksAreCached(t *testing.T) {
require.NotNil(t, engineAPI) require.NotNil(t, engineAPI)
genesis := backend.GetHeaderByNumber(0) genesis := backend.GetHeaderByNumber(0)
genesisHash := genesis.Hash() genesisHash := genesis.Hash()
eip1559Params := eth.Bytes8([]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8})
result, err := engineAPI.ForkchoiceUpdatedV3(context.Background(), &eth.ForkchoiceState{ result, err := engineAPI.ForkchoiceUpdatedV3(context.Background(), &eth.ForkchoiceState{
HeadBlockHash: genesisHash, HeadBlockHash: genesisHash,
SafeBlockHash: genesisHash, SafeBlockHash: genesisHash,
...@@ -40,6 +41,7 @@ func TestCreatedBlocksAreCached(t *testing.T) { ...@@ -40,6 +41,7 @@ func TestCreatedBlocksAreCached(t *testing.T) {
ParentBeaconBlockRoot: &common.Hash{0x22}, ParentBeaconBlockRoot: &common.Hash{0x22},
NoTxPool: false, NoTxPool: false,
GasLimit: (*eth.Uint64Quantity)(&genesis.GasLimit), GasLimit: (*eth.Uint64Quantity)(&genesis.GasLimit),
EIP1559Params: &eip1559Params,
}) })
require.NoError(t, err) require.NoError(t, err)
require.EqualValues(t, engine.VALID, result.PayloadStatus.Status) require.EqualValues(t, engine.VALID, result.PayloadStatus.Status)
...@@ -81,13 +83,25 @@ func newStubBackend(t *testing.T) *stubCachingBackend { ...@@ -81,13 +83,25 @@ func newStubBackend(t *testing.T) *stubCachingBackend {
} }
func createGenesis() *core.Genesis { func createGenesis() *core.Genesis {
config := *params.MergedTestChainConfig
var zero uint64
// activate recent OP-stack forks
config.RegolithTime = &zero
config.CanyonTime = &zero
config.EcotoneTime = &zero
config.FjordTime = &zero
config.GraniteTime = &zero
config.HoloceneTime = &zero
l2Genesis := &core.Genesis{ l2Genesis := &core.Genesis{
Config: params.MergedTestChainConfig, // Arbitrary post-merge config Config: &config,
Difficulty: common.Big0, Difficulty: common.Big0,
ParentHash: common.Hash{}, ParentHash: common.Hash{},
BaseFee: big.NewInt(7), BaseFee: big.NewInt(7),
Alloc: map[common.Address]types.Account{}, Alloc: map[common.Address]types.Account{},
ExtraData: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, // for Holocene eip-1559 params
} }
return l2Genesis return l2Genesis
} }
......
...@@ -83,6 +83,30 @@ func (b Bytes32) TerminalString() string { ...@@ -83,6 +83,30 @@ func (b Bytes32) TerminalString() string {
return fmt.Sprintf("%x..%x", b[:3], b[29:]) return fmt.Sprintf("%x..%x", b[:3], b[29:])
} }
type Bytes8 [8]byte
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 type Bytes96 [96]byte
func (b *Bytes96) UnmarshalJSON(text []byte) error { func (b *Bytes96) UnmarshalJSON(text []byte) error {
...@@ -329,6 +353,8 @@ type PayloadAttributes struct { ...@@ -329,6 +353,8 @@ type PayloadAttributes struct {
NoTxPool bool `json:"noTxPool,omitempty"` NoTxPool bool `json:"noTxPool,omitempty"`
// GasLimit override // GasLimit override
GasLimit *Uint64Quantity `json:"gasLimit,omitempty"` GasLimit *Uint64Quantity `json:"gasLimit,omitempty"`
// EIP-1559 parameters, to be specified only post-Holocene
EIP1559Params *Bytes8 `json:"eip1559Params,omitempty"`
} }
type ExecutePayloadStatus string type ExecutePayloadStatus string
...@@ -390,6 +416,10 @@ type SystemConfig struct { ...@@ -390,6 +416,10 @@ type SystemConfig struct {
Scalar Bytes32 `json:"scalar"` Scalar Bytes32 `json:"scalar"`
// GasLimit identifies the L2 block gas limit // GasLimit identifies the L2 block gas limit
GasLimit uint64 `json:"gasLimit"` 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 Bytes8 `json:"eip1559Params"`
// More fields can be added for future SystemConfig versions. // More fields can be added for future SystemConfig versions.
} }
...@@ -473,7 +503,7 @@ func (b *Bytes48) UnmarshalJSON(text []byte) error { ...@@ -473,7 +503,7 @@ func (b *Bytes48) UnmarshalJSON(text []byte) error {
} }
func (b *Bytes48) UnmarshalText(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) { func (b Bytes48) MarshalText() ([]byte, error) {
......
...@@ -138,9 +138,9 @@ Create or modify a file `<network-name>.json` inside of the [`deploy-config`](./ ...@@ -138,9 +138,9 @@ Create or modify a file `<network-name>.json` inside of the [`deploy-config`](./
Use the env var `DEPLOY_CONFIG_PATH` to use a particular deploy config file at runtime. 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 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 compatible with this fork. The automatically detected fork can be overwritten by setting the environment variable `FORK`
`FORK` either to the lower-case fork name (currently `delta`, `ecotone`, `fjord`, or `granite`) or to `latest`, which either to the lower-case fork name (currently `delta`, `ecotone`, `fjord`, `granite`, or `holocene`) or to `latest`,
will select the latest fork available (currently `granite`). 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`. 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: The optional environment variable `OUTPUT_MODE` allows to modify this behavior by setting it to one of the following values:
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
"l2GenesisDeltaTimeOffset": "0x0", "l2GenesisDeltaTimeOffset": "0x0",
"l2GenesisEcotoneTimeOffset": "0x0", "l2GenesisEcotoneTimeOffset": "0x0",
"l2GenesisFjordTimeOffset": "0x0", "l2GenesisFjordTimeOffset": "0x0",
"l2GenesisGraniteTimeOffset": "0x0",
"l1CancunTimeOffset": "0x0", "l1CancunTimeOffset": "0x0",
"systemConfigStartBlock": 0, "systemConfigStartBlock": 0,
"requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000001", "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000001",
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
"l2GenesisRegolithTimeOffset": "0x0", "l2GenesisRegolithTimeOffset": "0x0",
"l2GenesisCanyonTimeOffset": "0x0", "l2GenesisCanyonTimeOffset": "0x0",
"l2GenesisDeltaTimeOffset": "0x0", "l2GenesisDeltaTimeOffset": "0x0",
"l2GenesisBlockExtraData": null,
"proxyAdminOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", "proxyAdminOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2",
"finalSystemOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", "finalSystemOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2",
"superchainConfigGuardian": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", "superchainConfigGuardian": "0x8c20c40180751d93e939dddee3517ae0d1ebead2",
......
...@@ -182,6 +182,10 @@ contract L2Genesis is Deployer { ...@@ -182,6 +182,10 @@ contract L2Genesis is Deployer {
if (writeForkGenesisAllocs(_fork, Fork.GRANITE, _mode)) { if (writeForkGenesisAllocs(_fork, Fork.GRANITE, _mode)) {
return; return;
} }
if (writeForkGenesisAllocs(_fork, Fork.HOLOCENE, _mode)) {
return;
}
} }
function writeForkGenesisAllocs(Fork _latest, Fork _current, OutputMode _mode) internal returns (bool isLatest_) { function writeForkGenesisAllocs(Fork _latest, Fork _current, OutputMode _mode) internal returns (bool isLatest_) {
......
...@@ -443,6 +443,7 @@ contract Deploy is Deployer { ...@@ -443,6 +443,7 @@ contract Deploy is Deployer {
/// @notice Deploy all of the OP Chain specific contracts /// @notice Deploy all of the OP Chain specific contracts
function deployOpChain() public { function deployOpChain() public {
console.log("Deploying OP Chain"); console.log("Deploying OP Chain");
// Ensure that the requisite contracts are deployed // Ensure that the requisite contracts are deployed
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy"); address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
OPContractsManager opcm = OPContractsManager(mustGetAddress("OPContractsManagerProxy")); OPContractsManager opcm = OPContractsManager(mustGetAddress("OPContractsManagerProxy"));
......
...@@ -30,6 +30,7 @@ contract DeployConfig is Script { ...@@ -30,6 +30,7 @@ contract DeployConfig is Script {
uint256 public l2GenesisEcotoneTimeOffset; uint256 public l2GenesisEcotoneTimeOffset;
uint256 public l2GenesisFjordTimeOffset; uint256 public l2GenesisFjordTimeOffset;
uint256 public l2GenesisGraniteTimeOffset; uint256 public l2GenesisGraniteTimeOffset;
uint256 public l2GenesisHoloceneTimeOffset;
uint256 public maxSequencerDrift; uint256 public maxSequencerDrift;
uint256 public sequencerWindowSize; uint256 public sequencerWindowSize;
uint256 public channelTimeout; uint256 public channelTimeout;
...@@ -109,6 +110,7 @@ contract DeployConfig is Script { ...@@ -109,6 +110,7 @@ contract DeployConfig is Script {
l2GenesisEcotoneTimeOffset = _readOr(_json, "$.l2GenesisEcotoneTimeOffset", NULL_OFFSET); l2GenesisEcotoneTimeOffset = _readOr(_json, "$.l2GenesisEcotoneTimeOffset", NULL_OFFSET);
l2GenesisFjordTimeOffset = _readOr(_json, "$.l2GenesisFjordTimeOffset", NULL_OFFSET); l2GenesisFjordTimeOffset = _readOr(_json, "$.l2GenesisFjordTimeOffset", NULL_OFFSET);
l2GenesisGraniteTimeOffset = _readOr(_json, "$.l2GenesisGraniteTimeOffset", NULL_OFFSET); l2GenesisGraniteTimeOffset = _readOr(_json, "$.l2GenesisGraniteTimeOffset", NULL_OFFSET);
l2GenesisHoloceneTimeOffset = _readOr(_json, "$.l2GenesisHoloceneTimeOffset", NULL_OFFSET);
maxSequencerDrift = stdJson.readUint(_json, "$.maxSequencerDrift"); maxSequencerDrift = stdJson.readUint(_json, "$.maxSequencerDrift");
sequencerWindowSize = stdJson.readUint(_json, "$.sequencerWindowSize"); sequencerWindowSize = stdJson.readUint(_json, "$.sequencerWindowSize");
...@@ -246,7 +248,9 @@ contract DeployConfig is Script { ...@@ -246,7 +248,9 @@ contract DeployConfig is Script {
} }
function latestGenesisFork() internal view returns (Fork) { function latestGenesisFork() internal view returns (Fork) {
if (l2GenesisGraniteTimeOffset == 0) { if (l2GenesisHoloceneTimeOffset == 0) {
return Fork.HOLOCENE;
} else if (l2GenesisGraniteTimeOffset == 0) {
return Fork.GRANITE; return Fork.GRANITE;
} else if (l2GenesisFjordTimeOffset == 0) { } else if (l2GenesisFjordTimeOffset == 0) {
return Fork.FJORD; return Fork.FJORD;
......
...@@ -33,10 +33,11 @@ enum Fork { ...@@ -33,10 +33,11 @@ enum Fork {
DELTA, DELTA,
ECOTONE, ECOTONE,
FJORD, FJORD,
GRANITE GRANITE,
HOLOCENE
} }
Fork constant LATEST_FORK = Fork.GRANITE; Fork constant LATEST_FORK = Fork.HOLOCENE;
library ForkUtils { library ForkUtils {
function toString(Fork _fork) internal pure returns (string memory) { function toString(Fork _fork) internal pure returns (string memory) {
...@@ -50,6 +51,8 @@ library ForkUtils { ...@@ -50,6 +51,8 @@ library ForkUtils {
return "fjord"; return "fjord";
} else if (_fork == Fork.GRANITE) { } else if (_fork == Fork.GRANITE) {
return "granite"; return "granite";
} else if (_fork == Fork.HOLOCENE) {
return "holocene";
} else { } else {
return "unknown"; return "unknown";
} }
...@@ -163,6 +166,8 @@ library Config { ...@@ -163,6 +166,8 @@ library Config {
return Fork.FJORD; return Fork.FJORD;
} else if (forkHash == keccak256(bytes("granite"))) { } else if (forkHash == keccak256(bytes("granite"))) {
return Fork.GRANITE; return Fork.GRANITE;
} else if (forkHash == keccak256(bytes("holocene"))) {
return Fork.HOLOCENE;
} else { } else {
revert(string.concat("Config: unknown fork: ", forkStr)); revert(string.concat("Config: unknown fork: ", forkStr));
} }
......
...@@ -48,12 +48,12 @@ ...@@ -48,12 +48,12 @@
"sourceCodeHash": "0x39489a85bc3a5c8560f82d41b31bf7fe22f5b648f4ed538f61695a73092ea9eb" "sourceCodeHash": "0x39489a85bc3a5c8560f82d41b31bf7fe22f5b648f4ed538f61695a73092ea9eb"
}, },
"src/L1/SystemConfig.sol": { "src/L1/SystemConfig.sol": {
"initCodeHash": "0x2fc36af5b3c493a423a19e0b597f6ff230b756b861b68099f3192d69b6088dc0", "initCodeHash": "0xbe40fde9ebea4cd0820dc7f1b1a5c8c1f5ace448baacdafb3068d16d55218180",
"sourceCodeHash": "0x06a50ac992175fdb434b13e8461893e83862c23ce399e697e6e8109728ad1a3d" "sourceCodeHash": "0x7c0366afeb116516d2de0d29456efea82ccdf643b1fcea215e3585d109c314a7"
}, },
"src/L1/SystemConfigInterop.sol": { "src/L1/SystemConfigInterop.sol": {
"initCodeHash": "0x7515e5ed1266412a8c2d27d99aba6266fda2fc9068c20f0b7e6b555ee5073c91", "initCodeHash": "0x9fe11f6086be055e9abfc6d38037ba2af5a9644b4a4b3fd66a6cbdb55f17c1e1",
"sourceCodeHash": "0x441d1e3e8e987f829f55996b5b6c850da8c59ad48f09cf7e0a69a1fa559d42a2" "sourceCodeHash": "0x53de72f7057d459da79207f560b3bf1d057e901ec38f515ea7d29d7e323063e1"
}, },
"src/L2/BaseFeeVault.sol": { "src/L2/BaseFeeVault.sol": {
"initCodeHash": "0xbf49824cf37e201181484a8a423fcad8f504dc925921a2b28e83398197858dec", "initCodeHash": "0xbf49824cf37e201181484a8a423fcad8f504dc925921a2b28e83398197858dec",
......
...@@ -23,13 +23,13 @@ import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; ...@@ -23,13 +23,13 @@ import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol";
contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken {
/// @notice Enum representing different types of updates. /// @notice Enum representing different types of updates.
/// @custom:value BATCHER Represents an update to the batcher hash. /// @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 GAS_LIMIT Represents an update to gas limit on L2.
/// @custom:value UNSAFE_BLOCK_SIGNER Represents an update to the signer key for unsafe /// @custom:value UNSAFE_BLOCK_SIGNER Represents an update to the signer key for unsafe
/// block distrubution. /// block distrubution.
enum UpdateType { enum UpdateType {
BATCHER, BATCHER,
GAS_CONFIG, FEE_SCALARS,
GAS_LIMIT, GAS_LIMIT,
UNSAFE_BLOCK_SIGNER UNSAFE_BLOCK_SIGNER
} }
...@@ -130,9 +130,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { ...@@ -130,9 +130,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken {
event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data); event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
/// @notice Semantic version. /// @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) { 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 /// @notice Constructs the SystemConfig contract. Cannot set
...@@ -380,7 +380,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { ...@@ -380,7 +380,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken {
scalar = _scalar; scalar = _scalar;
bytes memory data = abi.encode(_overhead, _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. /// @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 { ...@@ -400,7 +400,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken {
scalar = (uint256(0x01) << 248) | (uint256(_blobbasefeeScalar) << 32) | _basefeeScalar; scalar = (uint256(0x01) << 248) | (uint256(_blobbasefeeScalar) << 32) | _basefeeScalar;
bytes memory data = abi.encode(overhead, scalar); 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. /// @notice Updates the L2 gas limit. Can only be called by the owner.
......
...@@ -68,9 +68,9 @@ contract SystemConfigInterop is SystemConfig { ...@@ -68,9 +68,9 @@ contract SystemConfigInterop is SystemConfig {
Storage.setAddress(DEPENDENCY_MANAGER_SLOT, _dependencyManager); Storage.setAddress(DEPENDENCY_MANAGER_SLOT, _dependencyManager);
} }
/// @custom:semver +interop-beta.1 /// @custom:semver +interop-beta.2
function version() public pure override returns (string memory) { 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. /// @notice Internal setter for the gas paying token address, includes validation.
......
...@@ -7,7 +7,7 @@ import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; ...@@ -7,7 +7,7 @@ import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol";
interface ISystemConfig { interface ISystemConfig {
enum UpdateType { enum UpdateType {
BATCHER, BATCHER,
GAS_CONFIG, FEE_SCALARS,
GAS_LIMIT, GAS_LIMIT,
UNSAFE_BLOCK_SIGNER UNSAFE_BLOCK_SIGNER
} }
......
...@@ -9,7 +9,7 @@ import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; ...@@ -9,7 +9,7 @@ import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol";
interface ISystemConfigV160 { interface ISystemConfigV160 {
enum UpdateType { enum UpdateType {
BATCHER, BATCHER,
GAS_CONFIG, FEE_SCALARS,
GAS_LIMIT, GAS_LIMIT,
UNSAFE_BLOCK_SIGNER UNSAFE_BLOCK_SIGNER
} }
......
...@@ -544,7 +544,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -544,7 +544,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
// always zero out most significant byte // always zero out most significant byte
newScalar = (newScalar << 16) >> 16; newScalar = (newScalar << 16) >> 16;
vm.expectEmit(address(systemConfig)); 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()); vm.prank(systemConfig.owner());
systemConfig.setGasConfig(newOverhead, newScalar); systemConfig.setGasConfig(newOverhead, newScalar);
...@@ -557,7 +557,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -557,7 +557,7 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
ffi.encodeScalarEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar }); ffi.encodeScalarEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar });
vm.expectEmit(address(systemConfig)); 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()); vm.prank(systemConfig.owner());
systemConfig.setGasConfigEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar }); systemConfig.setGasConfigEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment