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
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"
......
......@@ -251,9 +251,9 @@ require (
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
......
......@@ -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/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/op-geth v1.101411.1-rc.2 h1:nOeSTzcFWUCvJO1MJ5AyI26dqR1F7vYgz2jNNKuEtoE=
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/go.mod h1:XaVXL9jg8BcyOeugECgIUGa9Y3DjYJj71RHmb5qon6M=
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
......
......@@ -94,8 +94,8 @@ type L2GenesisBlockDeployConfig struct {
L2GenesisBlockGasUsed hexutil.Uint64 `json:"l2GenesisBlockGasUsed"`
L2GenesisBlockParentHash common.Hash `json:"l2GenesisBlockParentHash"`
L2GenesisBlockBaseFeePerGas *hexutil.Big `json:"l2GenesisBlockBaseFeePerGas"`
// L2GenesisBlockExtraData is configurable extradata. Will default to []byte("BEDROCK") if left unspecified.
L2GenesisBlockExtraData []byte `json:"l2GenesisBlockExtraData"`
// Note that there is no L2 genesis ExtraData, as it must default to a valid Holocene eip-1559
// configuration. See constant 'HoloceneExtraData' for the specific value used.
// Note that there is no L2 genesis timestamp:
// This is instead configured based on the timestamp of "l1StartingBlockTag".
}
......@@ -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,
......
......@@ -24,8 +24,6 @@ func TestConfigDataMarshalUnmarshal(t *testing.T) {
dec := json.NewDecoder(bytes.NewReader(b))
decoded := new(DeployConfig)
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)))
encoded, err := json.MarshalIndent(decoded, "", " ")
......
......@@ -2,13 +2,13 @@ package genesis
import (
"errors"
"fmt"
"math/big"
"time"
"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"
......@@ -18,8 +18,8 @@ import (
// defaultGasLimit represents the default gas limit for a genesis block.
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) {
......@@ -70,6 +70,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: &params.OptimismConfig{
EIP1559Denominator: eip1559Denom,
......@@ -91,21 +92,10 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene
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{
Config: &optimismChainConfig,
Nonce: uint64(config.L2GenesisBlockNonce),
Timestamp: l1StartTime,
ExtraData: extraData,
GasLimit: uint64(gasLimit),
Difficulty: difficulty.ToInt(),
Mixhash: config.L2GenesisBlockMixHash,
......@@ -121,6 +111,9 @@ func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Gene
genesis.BlobGasUsed = u64ptr(0)
genesis.ExcessBlobGas = u64ptr(0)
}
if optimismChainConfig.IsHolocene(genesis.Timestamp) {
genesis.ExtraData = HoloceneExtraData
}
return genesis, nil
}
......
......@@ -26,6 +26,7 @@ const (
L2AllocsEcotone L2AllocsMode = "ecotone"
L2AllocsFjord L2AllocsMode = "fjord"
L2AllocsGranite L2AllocsMode = "granite"
L2AllocsHolocene L2AllocsMode = "holocene"
)
var (
......
......@@ -39,7 +39,6 @@
"l2GenesisBlockGasUsed": "0x0",
"l2GenesisBlockParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"l2GenesisBlockBaseFeePerGas": "0x3b9aca00",
"l2GenesisBlockExtraData": "bm9uLWRlZmF1bHQgdmFsdWU=",
"baseFeeVaultRecipient": "0x42000000000000000000000000000000000000f5",
"l1FeeVaultRecipient": "0x42000000000000000000000000000000000000f6",
"sequencerFeeVaultRecipient": "0x42000000000000000000000000000000000000f7",
......
......@@ -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
}
......
......@@ -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,
......
......@@ -206,6 +206,7 @@ func NewHost(
EcotoneTime: nil,
FjordTime: nil,
GraniteTime: nil,
HoloceneTime: nil,
InteropTime: nil,
Optimism: nil,
}
......
......@@ -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{
......
......@@ -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)
......
......@@ -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)
}
}
......@@ -25,6 +25,8 @@ type hardforkScheduledTest struct {
deltaTime *hexutil.Uint64
ecotoneTime *hexutil.Uint64
fjordTime *hexutil.Uint64
graniteTime *hexutil.Uint64
holoceneTime *hexutil.Uint64
runToFork string
allocType config.AllocType
}
......@@ -39,6 +41,10 @@ func (tc *hardforkScheduledTest) GetFork(fork string) *uint64 {
func (tc *hardforkScheduledTest) fork(fork string) **hexutil.Uint64 {
switch fork {
case "holocene":
return &tc.holoceneTime
case "granite":
return &tc.graniteTime
case "fjord":
return &tc.fjordTime
case "ecotone":
......@@ -80,6 +86,8 @@ func testCrossLayerUser(t *testing.T, allocType config.AllocType) {
"delta",
"ecotone",
"fjord",
"granite",
"holocene",
}
for i, fork := range forks {
i := i
......@@ -136,6 +144,8 @@ 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 = test.graniteTime
dp.DeployConfig.L2GenesisHoloceneTimeOffset = test.holoceneTime
if test.canyonTime != nil {
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
dp.DeployConfig.L2GenesisFjordTimeOffset = &genesisBlock
case Granite:
dp.DeployConfig.L2GenesisGraniteTimeOffset = &genesisBlock
case Holocene:
dp.DeployConfig.L2GenesisHoloceneTimeOffset = &genesisBlock
}
})
sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc)
......
......@@ -84,11 +84,12 @@ var (
Regolith = &Hardfork{Name: "Regolith", Precedence: 1}
Canyon = &Hardfork{Name: "Canyon", Precedence: 2}
Delta = &Hardfork{Name: "Delta", Precedence: 3}
Fjord = &Hardfork{Name: "Fjord", Precedence: 4}
Ecotone = &Hardfork{Name: "Ecotone", Precedence: 5}
Ecotone = &Hardfork{Name: "Ecotone", Precedence: 4}
Fjord = &Hardfork{Name: "Fjord", 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, Ecotone, Fjord, Granite, Holocene}
var LatestForkOnly = ForkMatrix{Hardforks[len(Hardforks)-1]}
......
......@@ -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)
......
......@@ -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")
......
......@@ -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)
......
......@@ -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 {
......
......@@ -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)
......
......@@ -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)
......
......@@ -106,6 +106,22 @@ func Ether(v uint64) *big.Int {
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.
func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *SetupData {
deployConf := deployParams.DeployConfig.Copy()
......@@ -135,11 +151,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
l1Block := l1Genesis.ToBlock()
var allocsMode genesis.L2AllocsMode
allocsMode = genesis.L2AllocsDelta
if ecotoneTime := deployConf.EcotoneTime(l1Block.Time()); ecotoneTime != nil && *ecotoneTime == 0 {
allocsMode = genesis.L2AllocsEcotone
}
allocsMode := GetL2AllocsMode(deployConf, l1Block.Time())
l2Allocs := config.L2Allocs(deployParams.AllocType, allocsMode)
l2Genesis, err := genesis.BuildL2Genesis(deployConf, l2Allocs, l1Block.Header())
require.NoError(t, err, "failed to create l2 genesis")
......@@ -192,6 +204,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 +235,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 +252,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)
......
......@@ -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))
require.NoError(t, err)
l1Block := l1Genesis.ToBlock()
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
}
allocsMode := e2eutils.GetL2AllocsMode(cfg.DeployConfig, l1Block.Time())
l2Allocs := config.L2Allocs(config.AllocTypeStandard, allocsMode)
l2Genesis, err := genesis.BuildL2Genesis(cfg.DeployConfig, l2Allocs, l1Block.Header())
require.NoError(t, err)
......@@ -244,5 +235,9 @@ func (d *OpGeth) CreatePayloadAttributes(txs ...*types.Transaction) (*eth.Payloa
Withdrawals: withdrawals,
ParentBeaconBlockRoot: parentBeaconBlockRoot,
}
if d.L2ChainConfig.IsHolocene(uint64(timestamp)) {
attrs.EIP1559Params = new(eth.Bytes8)
*attrs.EIP1559Params = d.SystemConfig.EIP1559Params
}
return &attrs, nil
}
......@@ -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,
......
......@@ -77,6 +77,7 @@ func applySpanBatchActivation(active bool, dp *genesis.DeployConfig) {
dp.L2GenesisDeltaTimeOffset = nil
dp.L2GenesisEcotoneTimeOffset = nil
dp.L2GenesisFjordTimeOffset = nil
dp.L2GenesisGraniteTimeOffset = nil
}
}
......
......@@ -67,6 +67,7 @@ var mainnetCfg = rollup.Config{
EcotoneTime: u64Ptr(1710374401),
FjordTime: u64Ptr(1720627201),
GraniteTime: u64Ptr(1726070401),
// HoloceneTime: TBD
ProtocolVersionsAddress: common.HexToAddress("0x8062AbC286f5e7D9428a0Ccb9AbD71e50d93b935"),
}
......@@ -103,6 +104,7 @@ var sepoliaCfg = rollup.Config{
EcotoneTime: u64Ptr(1708534800),
FjordTime: u64Ptr(1716998400),
GraniteTime: u64Ptr(1723478400),
// HoloceneTime: TBD
ProtocolVersionsAddress: common.HexToAddress("0x79ADD5713B383DAa0a138d3C4780C7A1804a8090"),
}
......@@ -139,6 +141,7 @@ var sepoliaDev0Cfg = rollup.Config{
EcotoneTime: u64Ptr(1706634000),
FjordTime: u64Ptr(1715961600),
GraniteTime: u64Ptr(1723046400),
// HoloceneTime: TBD
ProtocolVersionsAddress: common.HexToAddress("0x252CbE9517F731C618961D890D534183822dcC8d"),
}
......
......@@ -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 &&
......
......@@ -149,7 +149,7 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex
}
}
return &eth.PayloadAttributes{
r := &eth.PayloadAttributes{
Timestamp: hexutil.Uint64(nextL2Time),
PrevRandao: eth.Bytes32(l1Info.MixDigest()),
SuggestedFeeRecipient: predeploys.SequencerFeeVaultAddr,
......@@ -158,5 +158,11 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex
GasLimit: (*eth.Uint64Quantity)(&sysConfig.GasLimit),
Withdrawals: withdrawals,
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) {
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{}
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
t.Run("regolith", func(t *testing.T) {
testCases := []struct {
......
......@@ -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,7 +60,8 @@ 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)
}
......@@ -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[28:32], info.BaseFeeScalar)
}
return eth.SystemConfig{
r := eth.SystemConfig{
BatcherAddr: info.BatcherAddr,
Overhead: info.L1FeeOverhead,
Scalar: info.L1FeeScalar,
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 (
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.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:
// Ignored in derivation. This configurable applies to runtime configuration outside of the derivation.
return nil
......
......@@ -32,6 +32,7 @@ var (
oneUint256 = abi.Arguments{
{Type: uint256T},
}
eip1559Params = []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}
)
// TestProcessSystemConfigUpdateLogEvent tests the parsing of an event and mutating the
......@@ -101,7 +102,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 +152,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 +186,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(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 {
......
......@@ -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,
......
......@@ -241,6 +241,15 @@ func TestActivations(t *testing.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",
setUpgradeTime: func(t *uint64, c *Config) {
......
......@@ -51,6 +51,14 @@ func NewBlockProcessorFromPayloadAttributes(provider BlockDataProvider, parent c
Nonce: types.EncodeNonce(0),
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)
}
......
......@@ -13,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"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/stateless"
"github.com/ethereum/go-ethereum/core/types"
......@@ -100,6 +101,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 +159,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
......@@ -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
func (ea *L2EngineAPI) verifyPayloadAttributes(attr *eth.PayloadAttributes) error {
c := ea.config()
t := uint64(attr.Timestamp)
// 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)
}
// 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)
}
// 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
}
......@@ -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"))
}
// 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)
}
......
......@@ -28,6 +28,7 @@ func TestCreatedBlocksAreCached(t *testing.T) {
require.NotNil(t, engineAPI)
genesis := backend.GetHeaderByNumber(0)
genesisHash := genesis.Hash()
eip1559Params := eth.Bytes8([]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8})
result, err := engineAPI.ForkchoiceUpdatedV3(context.Background(), &eth.ForkchoiceState{
HeadBlockHash: genesisHash,
SafeBlockHash: genesisHash,
......@@ -40,6 +41,7 @@ func TestCreatedBlocksAreCached(t *testing.T) {
ParentBeaconBlockRoot: &common.Hash{0x22},
NoTxPool: false,
GasLimit: (*eth.Uint64Quantity)(&genesis.GasLimit),
EIP1559Params: &eip1559Params,
})
require.NoError(t, err)
require.EqualValues(t, engine.VALID, result.PayloadStatus.Status)
......@@ -81,13 +83,25 @@ func newStubBackend(t *testing.T) *stubCachingBackend {
}
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{
Config: params.MergedTestChainConfig, // Arbitrary post-merge config
Config: &config,
Difficulty: common.Big0,
ParentHash: common.Hash{},
BaseFee: big.NewInt(7),
Alloc: map[common.Address]types.Account{},
ExtraData: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, // for Holocene eip-1559 params
}
return l2Genesis
}
......
......@@ -83,6 +83,30 @@ func (b Bytes32) TerminalString() string {
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
func (b *Bytes96) UnmarshalJSON(text []byte) error {
......@@ -329,6 +353,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 +416,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 Bytes8 `json:"eip1559Params"`
// More fields can be added for future SystemConfig versions.
}
......@@ -473,7 +503,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) {
......
......@@ -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.
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:
......
......@@ -48,6 +48,7 @@
"l2GenesisDeltaTimeOffset": "0x0",
"l2GenesisEcotoneTimeOffset": "0x0",
"l2GenesisFjordTimeOffset": "0x0",
"l2GenesisGraniteTimeOffset": "0x0",
"l1CancunTimeOffset": "0x0",
"systemConfigStartBlock": 0,
"requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000001",
......
......@@ -39,7 +39,6 @@
"l2GenesisRegolithTimeOffset": "0x0",
"l2GenesisCanyonTimeOffset": "0x0",
"l2GenesisDeltaTimeOffset": "0x0",
"l2GenesisBlockExtraData": null,
"proxyAdminOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2",
"finalSystemOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2",
"superchainConfigGuardian": "0x8c20c40180751d93e939dddee3517ae0d1ebead2",
......
......@@ -182,6 +182,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_) {
......
......@@ -443,6 +443,7 @@ contract Deploy is Deployer {
/// @notice Deploy all of the OP Chain specific contracts
function deployOpChain() public {
console.log("Deploying OP Chain");
// Ensure that the requisite contracts are deployed
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
OPContractsManager opcm = OPContractsManager(mustGetAddress("OPContractsManagerProxy"));
......
......@@ -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;
......
......@@ -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));
}
......
......@@ -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",
......
......@@ -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.
......
......@@ -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.
......
......@@ -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
}
......
......@@ -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
}
......
......@@ -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 });
......
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