Commit e4c17d38 authored by Inphi's avatar Inphi Committed by GitHub

Reduce ChannelTimeout to 50 in Granite (#11343)

* Reduce ChannelTimeout to 50 in Granite

* Capture granite genesis files.

* Update snapshots.

* Update op-geth dependency and resolve TODOs.

* update op-geth dependency to rc.1

* fix TestGetRollupConfig

---------
Co-authored-by: default avatarAdrian Sutton <adrian@oplabs.co>
parent 5e317379
...@@ -249,22 +249,26 @@ jobs: ...@@ -249,22 +249,26 @@ jobs:
- ".devnet/allocs-l2-delta.json" - ".devnet/allocs-l2-delta.json"
- ".devnet/allocs-l2-ecotone.json" - ".devnet/allocs-l2-ecotone.json"
- ".devnet/allocs-l2-fjord.json" - ".devnet/allocs-l2-fjord.json"
- ".devnet/allocs-l2-granite.json"
- ".devnet/addresses.json" - ".devnet/addresses.json"
- ".devnet-l2oo/allocs-l1.json" - ".devnet-l2oo/allocs-l1.json"
- ".devnet-l2oo/addresses.json" - ".devnet-l2oo/addresses.json"
- ".devnet-l2oo/allocs-l2-delta.json" - ".devnet-l2oo/allocs-l2-delta.json"
- ".devnet-l2oo/allocs-l2-ecotone.json" - ".devnet-l2oo/allocs-l2-ecotone.json"
- ".devnet-l2oo/allocs-l2-fjord.json" - ".devnet-l2oo/allocs-l2-fjord.json"
- ".devnet-l2oo/allocs-l2-granite.json"
- ".devnet-plasma/allocs-l1.json" - ".devnet-plasma/allocs-l1.json"
- ".devnet-plasma/addresses.json" - ".devnet-plasma/addresses.json"
- ".devnet-plasma/allocs-l2-delta.json" - ".devnet-plasma/allocs-l2-delta.json"
- ".devnet-plasma/allocs-l2-ecotone.json" - ".devnet-plasma/allocs-l2-ecotone.json"
- ".devnet-plasma/allocs-l2-fjord.json" - ".devnet-plasma/allocs-l2-fjord.json"
- ".devnet-plasma/allocs-l2-granite.json"
- ".devnet-plasma-generic/allocs-l1.json" - ".devnet-plasma-generic/allocs-l1.json"
- ".devnet-plasma-generic/addresses.json" - ".devnet-plasma-generic/addresses.json"
- ".devnet-plasma-generic/allocs-l2-delta.json" - ".devnet-plasma-generic/allocs-l2-delta.json"
- ".devnet-plasma-generic/allocs-l2-ecotone.json" - ".devnet-plasma-generic/allocs-l2-ecotone.json"
- ".devnet-plasma-generic/allocs-l2-fjord.json" - ".devnet-plasma-generic/allocs-l2-fjord.json"
- ".devnet-plasma-generic/allocs-l2-granite.json"
- "packages/contracts-bedrock/deploy-config/devnetL1.json" - "packages/contracts-bedrock/deploy-config/devnetL1.json"
- "packages/contracts-bedrock/deployments/devnetL1" - "packages/contracts-bedrock/deployments/devnetL1"
- notify-failures-on-develop - notify-failures-on-develop
...@@ -891,6 +895,7 @@ jobs: ...@@ -891,6 +895,7 @@ jobs:
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-delta.json .devnet/allocs-l2-delta.json cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-delta.json .devnet/allocs-l2-delta.json
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-ecotone.json .devnet/allocs-l2-ecotone.json cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-ecotone.json .devnet/allocs-l2-ecotone.json
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-fjord.json .devnet/allocs-l2-fjord.json cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-fjord.json .devnet/allocs-l2-fjord.json
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l2-granite.json .devnet/allocs-l2-granite.json
cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l1.json .devnet/allocs-l1.json cp /tmp/workspace/.devnet<<parameters.variant>>/allocs-l1.json .devnet/allocs-l1.json
cp /tmp/workspace/.devnet<<parameters.variant>>/addresses.json .devnet/addresses.json cp /tmp/workspace/.devnet<<parameters.variant>>/addresses.json .devnet/addresses.json
cp /tmp/workspace/packages/contracts-bedrock/deploy-config/devnetL1.json packages/contracts-bedrock/deploy-config/devnetL1.json cp /tmp/workspace/packages/contracts-bedrock/deploy-config/devnetL1.json packages/contracts-bedrock/deploy-config/devnetL1.json
...@@ -1078,6 +1083,7 @@ jobs: ...@@ -1078,6 +1083,7 @@ jobs:
- ".devnet/allocs-l2-delta.json" - ".devnet/allocs-l2-delta.json"
- ".devnet/allocs-l2-ecotone.json" - ".devnet/allocs-l2-ecotone.json"
- ".devnet/allocs-l2-fjord.json" - ".devnet/allocs-l2-fjord.json"
- ".devnet/allocs-l2-granite.json"
- ".devnet/allocs-l1.json" - ".devnet/allocs-l1.json"
- ".devnet/addresses.json" - ".devnet/addresses.json"
- "packages/contracts-bedrock/deploy-config/devnetL1.json" - "packages/contracts-bedrock/deploy-config/devnetL1.json"
......
...@@ -22,7 +22,7 @@ parser.add_argument('--allocs', help='Only create the allocs and exit', type=boo ...@@ -22,7 +22,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"] FORKS = ["delta", "ecotone", "fjord", "granite"]
# Global environment variables # Global environment variables
DEVNET_NO_BUILD = os.getenv('DEVNET_NO_BUILD') == "true" DEVNET_NO_BUILD = os.getenv('DEVNET_NO_BUILD') == "true"
......
...@@ -11,7 +11,7 @@ require ( ...@@ -11,7 +11,7 @@ require (
github.com/crate-crypto/go-kzg-4844 v0.7.0 github.com/crate-crypto/go-kzg-4844 v0.7.0
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240801182704-4810f97b7ee9 github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240803025447-c92ef420eec2
github.com/ethereum/go-ethereum v1.13.15 github.com/ethereum/go-ethereum v1.13.15
github.com/fsnotify/fsnotify v1.7.0 github.com/fsnotify/fsnotify v1.7.0
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
...@@ -228,7 +228,7 @@ require ( ...@@ -228,7 +228,7 @@ require (
rsc.io/tmplfunc v0.0.3 // indirect rsc.io/tmplfunc v0.0.3 // indirect
) )
replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101315.3-rc.1 replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101316.0-rc.1
//replace github.com/ethereum/go-ethereum v1.13.9 => ../op-geth //replace github.com/ethereum/go-ethereum v1.13.9 => ../op-geth
...@@ -236,3 +236,7 @@ replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth ...@@ -236,3 +236,7 @@ replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth
// This release keeps breaking Go builds. Stop that. // This release keeps breaking Go builds. Stop that.
exclude github.com/kataras/iris/v12 v12.2.0-beta5 exclude github.com/kataras/iris/v12 v12.2.0-beta5
exclude github.com/kataras/iris/v12 v12.2.0
exclude github.com/kataras/iris/v12 v12.2.11
...@@ -171,10 +171,10 @@ github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/ ...@@ -171,10 +171,10 @@ github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/
github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.2/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.101315.3-rc.1 h1:Q/B0FBdtglzsFtqurvUsiNfH8isCOFFF/pf9ss0L4eY= github.com/ethereum-optimism/op-geth v1.101316.0-rc.1 h1:S6Nw/faA4g6AicK5oQR5p2VUjq8AyTEilLfNGgprbGU=
github.com/ethereum-optimism/op-geth v1.101315.3-rc.1/go.mod h1:h5C5tP+7gkMrlUGENuiV5ddlwJ4RxLdmdapRuTAGlnw= github.com/ethereum-optimism/op-geth v1.101316.0-rc.1/go.mod h1:nZ3TvP4mhOsfKkrgaT3GrDO4oCn5awPXFHKpVHuO63s=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240801182704-4810f97b7ee9 h1:Yqi7oOCWRN3SMl3rL5zGYSHIw2MyuTJ1nqokSi7ejfU= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240803025447-c92ef420eec2 h1:ySJykDUyb8RbcfLL3pz0Cs5Ji6NMVT7kmAY634DOCoE=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240801182704-4810f97b7ee9/go.mod h1:zy9f3TNPS7pwW4msMitF83fp0Wf452tZ6+Fg6d4JyXM= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240803025447-c92ef420eec2/go.mod h1:zy9f3TNPS7pwW4msMitF83fp0Wf452tZ6+Fg6d4JyXM=
github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY=
github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
......
...@@ -134,6 +134,9 @@ func (s *channel) updateInclusionBlocks() { ...@@ -134,6 +134,9 @@ func (s *channel) updateInclusionBlocks() {
func (s *channel) isTimedOut() bool { func (s *channel) isTimedOut() bool {
// Update min/max inclusion blocks for timeout check // Update min/max inclusion blocks for timeout check
s.updateInclusionBlocks() s.updateInclusionBlocks()
// Prior to the granite hard fork activating, the use of the shorter ChannelTimeout here may cause the batcher
// to believe the channel timed out when it was valid. It would then resubmit the blocks needlessly.
// This wastes batcher funds but doesn't cause any problems for the chain progressing safe head.
return s.maxInclusionBlock-s.minInclusionBlock >= s.cfg.ChannelTimeout return s.maxInclusionBlock-s.minInclusionBlock >= s.cfg.ChannelTimeout
} }
......
...@@ -185,9 +185,15 @@ func (bs *BatcherService) initRollupConfig(ctx context.Context) error { ...@@ -185,9 +185,15 @@ func (bs *BatcherService) initRollupConfig(ctx context.Context) error {
} }
func (bs *BatcherService) initChannelConfig(cfg *CLIConfig) error { func (bs *BatcherService) initChannelConfig(cfg *CLIConfig) error {
channelTimeout := bs.RollupConfig.ChannelTimeoutBedrock
// Use lower channel timeout if granite is scheduled.
// Ensures channels are restricted to the tighter timeout even if granite hasn't activated yet
if bs.RollupConfig.GraniteTime != nil {
channelTimeout = bs.RollupConfig.ChannelTimeoutGranite
}
cc := ChannelConfig{ cc := ChannelConfig{
SeqWindowSize: bs.RollupConfig.SeqWindowSize, SeqWindowSize: bs.RollupConfig.SeqWindowSize,
ChannelTimeout: bs.RollupConfig.ChannelTimeout, ChannelTimeout: channelTimeout,
MaxChannelDuration: cfg.MaxChannelDuration, MaxChannelDuration: cfg.MaxChannelDuration,
MaxFrameSize: cfg.MaxL1TxSize - 1, // account for version byte prefix; reset for blobs MaxFrameSize: cfg.MaxL1TxSize - 1, // account for version byte prefix; reset for blobs
TargetNumFrames: cfg.TargetNumFrames, TargetNumFrames: cfg.TargetNumFrames,
......
...@@ -338,6 +338,9 @@ type UpgradeScheduleDeployConfig struct { ...@@ -338,6 +338,9 @@ type UpgradeScheduleDeployConfig struct {
// L2GenesisFjordTimeOffset is the number of seconds after genesis block that Fjord hard fork activates. // L2GenesisFjordTimeOffset is the number of seconds after genesis block that Fjord hard fork activates.
// Set it to 0 to activate at genesis. Nil to disable Fjord. // Set it to 0 to activate at genesis. Nil to disable Fjord.
L2GenesisFjordTimeOffset *hexutil.Uint64 `json:"l2GenesisFjordTimeOffset,omitempty"` L2GenesisFjordTimeOffset *hexutil.Uint64 `json:"l2GenesisFjordTimeOffset,omitempty"`
// 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"`
// 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"`
...@@ -382,6 +385,10 @@ func (d *UpgradeScheduleDeployConfig) FjordTime(genesisTime uint64) *uint64 { ...@@ -382,6 +385,10 @@ func (d *UpgradeScheduleDeployConfig) FjordTime(genesisTime uint64) *uint64 {
return offsetToUpgradeTime(d.L2GenesisFjordTimeOffset, genesisTime) return offsetToUpgradeTime(d.L2GenesisFjordTimeOffset, genesisTime)
} }
func (d *UpgradeScheduleDeployConfig) GraniteTime(genesisTime uint64) *uint64 {
return offsetToUpgradeTime(d.L2GenesisGraniteTimeOffset, 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)
} }
...@@ -415,6 +422,9 @@ func (d *UpgradeScheduleDeployConfig) Check(log log.Logger) error { ...@@ -415,6 +422,9 @@ func (d *UpgradeScheduleDeployConfig) Check(log log.Logger) error {
if err := checkFork(d.L2GenesisEcotoneTimeOffset, d.L2GenesisFjordTimeOffset, "ecotone", "fjord"); err != nil { if err := checkFork(d.L2GenesisEcotoneTimeOffset, d.L2GenesisFjordTimeOffset, "ecotone", "fjord"); err != nil {
return err return err
} }
if err := checkFork(d.L2GenesisFjordTimeOffset, d.L2GenesisGraniteTimeOffset, "fjord", "granite"); err != nil {
return err
}
return nil return nil
} }
...@@ -438,8 +448,10 @@ type L2CoreDeployConfig struct { ...@@ -438,8 +448,10 @@ type L2CoreDeployConfig struct {
MaxSequencerDrift uint64 `json:"maxSequencerDrift"` MaxSequencerDrift uint64 `json:"maxSequencerDrift"`
// SequencerWindowSize is the number of L1 blocks per sequencing window. // SequencerWindowSize is the number of L1 blocks per sequencing window.
SequencerWindowSize uint64 `json:"sequencerWindowSize"` SequencerWindowSize uint64 `json:"sequencerWindowSize"`
// ChannelTimeout is the number of L1 blocks that a frame stays valid when included in L1. // ChannelTimeoutBedrock is the number of L1 blocks that a frame stays valid when included in L1.
ChannelTimeout uint64 `json:"channelTimeout"` ChannelTimeoutBedrock uint64 `json:"channelTimeout"`
// ChannelTimeoutGranite is the number of L1 blocks that a frame stays valid when included in L1 after granite.
ChannelTimeoutGranite uint64 `json:"channelTimeoutGranite,omitempty"`
// BatchInboxAddress is the L1 account that batches are sent to. // BatchInboxAddress is the L1 account that batches are sent to.
BatchInboxAddress common.Address `json:"batchInboxAddress"` BatchInboxAddress common.Address `json:"batchInboxAddress"`
...@@ -464,7 +476,7 @@ func (d *L2CoreDeployConfig) Check(log log.Logger) error { ...@@ -464,7 +476,7 @@ func (d *L2CoreDeployConfig) Check(log log.Logger) error {
if d.SequencerWindowSize == 0 { if d.SequencerWindowSize == 0 {
return fmt.Errorf("%w: SequencerWindowSize cannot be 0", ErrInvalidDeployConfig) return fmt.Errorf("%w: SequencerWindowSize cannot be 0", ErrInvalidDeployConfig)
} }
if d.ChannelTimeout == 0 { if d.ChannelTimeoutBedrock == 0 {
return fmt.Errorf("%w: ChannelTimeout cannot be 0", ErrInvalidDeployConfig) return fmt.Errorf("%w: ChannelTimeout cannot be 0", ErrInvalidDeployConfig)
} }
if d.BatchInboxAddress == (common.Address{}) { if d.BatchInboxAddress == (common.Address{}) {
...@@ -534,7 +546,13 @@ type L2InitializationConfig struct { ...@@ -534,7 +546,13 @@ type L2InitializationConfig struct {
} }
func (d *L2InitializationConfig) Check(log log.Logger) error { func (d *L2InitializationConfig) Check(log log.Logger) error {
return checkConfigBundle(d, log) if err := checkConfigBundle(d, log); err != nil {
return err
}
if d.ChannelTimeoutGranite == 0 && d.L2GenesisGraniteTimeOffset != nil {
return fmt.Errorf("%w: ChannelTimeoutGranite cannot be 0", ErrInvalidDeployConfig)
}
return nil
} }
// DevL1DeployConfig is used to configure a L1 chain for development/testing purposes. // DevL1DeployConfig is used to configure a L1 chain for development/testing purposes.
...@@ -804,7 +822,9 @@ func (d *DeployConfig) Check(log log.Logger) error { ...@@ -804,7 +822,9 @@ func (d *DeployConfig) Check(log log.Logger) error {
if d.L1BlockTime < d.L2BlockTime { if d.L1BlockTime < d.L2BlockTime {
return fmt.Errorf("L2 block time (%d) is larger than L1 block time (%d)", d.L2BlockTime, d.L1BlockTime) return fmt.Errorf("L2 block time (%d) is larger than L1 block time (%d)", d.L2BlockTime, d.L1BlockTime)
} }
if d.ChannelTimeoutGranite == 0 && d.L2GenesisGraniteTimeOffset != nil {
return fmt.Errorf("%w: ChannelTimeoutGranite cannot be 0", ErrInvalidDeployConfig)
}
return checkConfigBundle(d, log) return checkConfigBundle(d, log)
} }
...@@ -869,7 +889,8 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Block, l2GenesisBlockHas ...@@ -869,7 +889,8 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Block, l2GenesisBlockHas
BlockTime: d.L2BlockTime, BlockTime: d.L2BlockTime,
MaxSequencerDrift: d.MaxSequencerDrift, MaxSequencerDrift: d.MaxSequencerDrift,
SeqWindowSize: d.SequencerWindowSize, SeqWindowSize: d.SequencerWindowSize,
ChannelTimeout: d.ChannelTimeout, ChannelTimeoutBedrock: d.ChannelTimeoutBedrock,
ChannelTimeoutGranite: d.ChannelTimeoutGranite,
L1ChainID: new(big.Int).SetUint64(d.L1ChainID), L1ChainID: new(big.Int).SetUint64(d.L1ChainID),
L2ChainID: new(big.Int).SetUint64(d.L2ChainID), L2ChainID: new(big.Int).SetUint64(d.L2ChainID),
BatchInboxAddress: d.BatchInboxAddress, BatchInboxAddress: d.BatchInboxAddress,
...@@ -880,6 +901,7 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Block, l2GenesisBlockHas ...@@ -880,6 +901,7 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Block, l2GenesisBlockHas
DeltaTime: d.DeltaTime(l1StartBlock.Time()), DeltaTime: d.DeltaTime(l1StartBlock.Time()),
EcotoneTime: d.EcotoneTime(l1StartBlock.Time()), EcotoneTime: d.EcotoneTime(l1StartBlock.Time()),
FjordTime: d.FjordTime(l1StartBlock.Time()), FjordTime: d.FjordTime(l1StartBlock.Time()),
GraniteTime: d.GraniteTime(l1StartBlock.Time()),
InteropTime: d.InteropTime(l1StartBlock.Time()), InteropTime: d.InteropTime(l1StartBlock.Time()),
PlasmaConfig: plasma, PlasmaConfig: plasma,
}, nil }, nil
......
...@@ -67,11 +67,12 @@ func NewL2Genesis(config *DeployConfig, block *types.Block) (*core.Genesis, erro ...@@ -67,11 +67,12 @@ func NewL2Genesis(config *DeployConfig, block *types.Block) (*core.Genesis, erro
CancunTime: config.EcotoneTime(block.Time()), CancunTime: config.EcotoneTime(block.Time()),
EcotoneTime: config.EcotoneTime(block.Time()), EcotoneTime: config.EcotoneTime(block.Time()),
FjordTime: config.FjordTime(block.Time()), FjordTime: config.FjordTime(block.Time()),
GraniteTime: config.GraniteTime(block.Time()),
InteropTime: config.InteropTime(block.Time()), InteropTime: config.InteropTime(block.Time()),
Optimism: &params.OptimismConfig{ Optimism: &params.OptimismConfig{
EIP1559Denominator: eip1559Denom, EIP1559Denominator: eip1559Denom,
EIP1559Elasticity: eip1559Elasticity, EIP1559Elasticity: eip1559Elasticity,
EIP1559DenominatorCanyon: eip1559DenomCanyon, EIP1559DenominatorCanyon: &eip1559DenomCanyon,
}, },
} }
......
...@@ -23,6 +23,7 @@ const ( ...@@ -23,6 +23,7 @@ const (
L2AllocsDelta L2AllocsMode = "delta" L2AllocsDelta L2AllocsMode = "delta"
L2AllocsEcotone L2AllocsMode = "ecotone" L2AllocsEcotone L2AllocsMode = "ecotone"
L2AllocsFjord L2AllocsMode = "fjord" L2AllocsFjord L2AllocsMode = "fjord"
L2AllocsGranite L2AllocsMode = "granite"
) )
var ( var (
......
...@@ -64,7 +64,8 @@ func mockConfig(t *testing.T) Config { ...@@ -64,7 +64,8 @@ func mockConfig(t *testing.T) Config {
BlockTime: 2, BlockTime: 2,
MaxSequencerDrift: 600, MaxSequencerDrift: 600,
SeqWindowSize: 3600, SeqWindowSize: 3600,
ChannelTimeout: 300, ChannelTimeoutBedrock: 300,
ChannelTimeoutGranite: 50,
L1ChainID: big.NewInt(1), L1ChainID: big.NewInt(1),
L2ChainID: big.NewInt(2), L2ChainID: big.NewInt(2),
RegolithTime: &now, RegolithTime: &now,
......
...@@ -202,3 +202,10 @@ func (s *L2Sequencer) ActBuildL2ToFjord(t Testing) { ...@@ -202,3 +202,10 @@ func (s *L2Sequencer) ActBuildL2ToFjord(t Testing) {
s.ActL2EndBlock(t) s.ActL2EndBlock(t)
} }
} }
func (s *L2Sequencer) ActBuildL2ToGranite(t Testing) {
require.NotNil(t, s.rollupCfg.GraniteTime, "cannot activate GraniteTime when it is not scheduled")
for s.L2Unsafe().Time < *s.rollupCfg.GraniteTime {
s.ActL2StartBlock(t)
s.ActL2EndBlock(t)
}
}
...@@ -121,6 +121,7 @@ func init() { ...@@ -121,6 +121,7 @@ func init() {
} }
l2Allocs[mode] = allocs l2Allocs[mode] = allocs
} }
mustL2Allocs(genesis.L2AllocsGranite)
mustL2Allocs(genesis.L2AllocsFjord) mustL2Allocs(genesis.L2AllocsFjord)
mustL2Allocs(genesis.L2AllocsEcotone) mustL2Allocs(genesis.L2AllocsEcotone)
mustL2Allocs(genesis.L2AllocsDelta) mustL2Allocs(genesis.L2AllocsDelta)
......
...@@ -59,7 +59,8 @@ func MakeDeployParams(t require.TestingT, tp *TestParams) *DeployParams { ...@@ -59,7 +59,8 @@ func MakeDeployParams(t require.TestingT, tp *TestParams) *DeployParams {
deployConfig := config.DeployConfig.Copy() deployConfig := config.DeployConfig.Copy()
deployConfig.MaxSequencerDrift = tp.MaxSequencerDrift deployConfig.MaxSequencerDrift = tp.MaxSequencerDrift
deployConfig.SequencerWindowSize = tp.SequencerWindowSize deployConfig.SequencerWindowSize = tp.SequencerWindowSize
deployConfig.ChannelTimeout = tp.ChannelTimeout deployConfig.ChannelTimeoutBedrock = tp.ChannelTimeout
deployConfig.ChannelTimeoutGranite = tp.ChannelTimeout
deployConfig.L1BlockTime = tp.L1BlockTime deployConfig.L1BlockTime = tp.L1BlockTime
deployConfig.UsePlasma = tp.UsePlasma deployConfig.UsePlasma = tp.UsePlasma
ApplyDeployConfigForks(deployConfig) ApplyDeployConfigForks(deployConfig)
...@@ -173,7 +174,8 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) * ...@@ -173,7 +174,8 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
BlockTime: deployConf.L2BlockTime, BlockTime: deployConf.L2BlockTime,
MaxSequencerDrift: deployConf.MaxSequencerDrift, MaxSequencerDrift: deployConf.MaxSequencerDrift,
SeqWindowSize: deployConf.SequencerWindowSize, SeqWindowSize: deployConf.SequencerWindowSize,
ChannelTimeout: deployConf.ChannelTimeout, ChannelTimeoutBedrock: deployConf.ChannelTimeoutBedrock,
ChannelTimeoutGranite: deployConf.ChannelTimeoutGranite,
L1ChainID: new(big.Int).SetUint64(deployConf.L1ChainID), L1ChainID: new(big.Int).SetUint64(deployConf.L1ChainID),
L2ChainID: new(big.Int).SetUint64(deployConf.L2ChainID), L2ChainID: new(big.Int).SetUint64(deployConf.L2ChainID),
BatchInboxAddress: deployConf.BatchInboxAddress, BatchInboxAddress: deployConf.BatchInboxAddress,
...@@ -184,6 +186,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) * ...@@ -184,6 +186,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
DeltaTime: deployConf.DeltaTime(uint64(deployConf.L1GenesisBlockTimestamp)), DeltaTime: deployConf.DeltaTime(uint64(deployConf.L1GenesisBlockTimestamp)),
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)),
InteropTime: deployConf.InteropTime(uint64(deployConf.L1GenesisBlockTimestamp)), InteropTime: deployConf.InteropTime(uint64(deployConf.L1GenesisBlockTimestamp)),
PlasmaConfig: pcfg, PlasmaConfig: pcfg,
} }
...@@ -214,7 +217,8 @@ func SystemConfigFromDeployConfig(deployConfig *genesis.DeployConfig) eth.System ...@@ -214,7 +217,8 @@ func SystemConfigFromDeployConfig(deployConfig *genesis.DeployConfig) eth.System
} }
func ApplyDeployConfigForks(deployConfig *genesis.DeployConfig) { func ApplyDeployConfigForks(deployConfig *genesis.DeployConfig) {
isFjord := os.Getenv("OP_E2E_USE_FJORD") == "true" isGranite := 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" 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"
if isDelta { if isDelta {
...@@ -226,6 +230,9 @@ func ApplyDeployConfigForks(deployConfig *genesis.DeployConfig) { ...@@ -226,6 +230,9 @@ func ApplyDeployConfigForks(deployConfig *genesis.DeployConfig) {
if isFjord { if isFjord {
deployConfig.L2GenesisFjordTimeOffset = new(hexutil.Uint64) deployConfig.L2GenesisFjordTimeOffset = new(hexutil.Uint64)
} }
if isGranite {
deployConfig.L2GenesisGraniteTimeOffset = 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)
......
...@@ -60,7 +60,9 @@ func NewOpGeth(t testing.TB, ctx context.Context, cfg *SystemConfig) (*OpGeth, e ...@@ -60,7 +60,9 @@ func NewOpGeth(t testing.TB, ctx context.Context, cfg *SystemConfig) (*OpGeth, e
var allocsMode genesis.L2AllocsMode var allocsMode genesis.L2AllocsMode
allocsMode = genesis.L2AllocsDelta allocsMode = genesis.L2AllocsDelta
if fjordTime := cfg.DeployConfig.FjordTime(l1Block.Time()); fjordTime != nil && *fjordTime <= 0 { 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 allocsMode = genesis.L2AllocsFjord
} else if ecotoneTime := cfg.DeployConfig.EcotoneTime(l1Block.Time()); ecotoneTime != nil && *ecotoneTime <= 0 { } else if ecotoneTime := cfg.DeployConfig.EcotoneTime(l1Block.Time()); ecotoneTime != nil && *ecotoneTime <= 0 {
allocsMode = genesis.L2AllocsEcotone allocsMode = genesis.L2AllocsEcotone
......
...@@ -184,6 +184,7 @@ func RegolithSystemConfig(t *testing.T, regolithTimeOffset *hexutil.Uint64) Syst ...@@ -184,6 +184,7 @@ func RegolithSystemConfig(t *testing.T, regolithTimeOffset *hexutil.Uint64) Syst
cfg.DeployConfig.L2GenesisDeltaTimeOffset = nil cfg.DeployConfig.L2GenesisDeltaTimeOffset = nil
cfg.DeployConfig.L2GenesisEcotoneTimeOffset = nil cfg.DeployConfig.L2GenesisEcotoneTimeOffset = nil
cfg.DeployConfig.L2GenesisFjordTimeOffset = nil cfg.DeployConfig.L2GenesisFjordTimeOffset = nil
cfg.DeployConfig.L2GenesisGraniteTimeOffset = nil
// ADD NEW FORKS HERE! // ADD NEW FORKS HERE!
return cfg return cfg
} }
...@@ -214,6 +215,12 @@ func FjordSystemConfig(t *testing.T, fjordTimeOffset *hexutil.Uint64) SystemConf ...@@ -214,6 +215,12 @@ func FjordSystemConfig(t *testing.T, fjordTimeOffset *hexutil.Uint64) SystemConf
return cfg return cfg
} }
func GraniteSystemConfig(t *testing.T, graniteTimeOffset *hexutil.Uint64) SystemConfig {
cfg := EcotoneSystemConfig(t, &genesisTime)
cfg.DeployConfig.L2GenesisGraniteTimeOffset = graniteTimeOffset
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")
...@@ -540,7 +547,9 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste ...@@ -540,7 +547,9 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
l1Block := l1Genesis.ToBlock() l1Block := l1Genesis.ToBlock()
var allocsMode genesis.L2AllocsMode var allocsMode genesis.L2AllocsMode
allocsMode = genesis.L2AllocsDelta allocsMode = genesis.L2AllocsDelta
if fjordTime := cfg.DeployConfig.FjordTime(l1Block.Time()); fjordTime != nil && *fjordTime <= 0 { 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 allocsMode = genesis.L2AllocsFjord
} else if ecotoneTime := cfg.DeployConfig.EcotoneTime(l1Block.Time()); ecotoneTime != nil && *ecotoneTime <= 0 { } else if ecotoneTime := cfg.DeployConfig.EcotoneTime(l1Block.Time()); ecotoneTime != nil && *ecotoneTime <= 0 {
allocsMode = genesis.L2AllocsEcotone allocsMode = genesis.L2AllocsEcotone
...@@ -585,7 +594,8 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste ...@@ -585,7 +594,8 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
BlockTime: cfg.DeployConfig.L2BlockTime, BlockTime: cfg.DeployConfig.L2BlockTime,
MaxSequencerDrift: cfg.DeployConfig.MaxSequencerDrift, MaxSequencerDrift: cfg.DeployConfig.MaxSequencerDrift,
SeqWindowSize: cfg.DeployConfig.SequencerWindowSize, SeqWindowSize: cfg.DeployConfig.SequencerWindowSize,
ChannelTimeout: cfg.DeployConfig.ChannelTimeout, ChannelTimeoutBedrock: cfg.DeployConfig.ChannelTimeoutBedrock,
ChannelTimeoutGranite: cfg.DeployConfig.ChannelTimeoutGranite,
L1ChainID: cfg.L1ChainIDBig(), L1ChainID: cfg.L1ChainIDBig(),
L2ChainID: cfg.L2ChainIDBig(), L2ChainID: cfg.L2ChainIDBig(),
BatchInboxAddress: cfg.DeployConfig.BatchInboxAddress, BatchInboxAddress: cfg.DeployConfig.BatchInboxAddress,
...@@ -596,6 +606,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste ...@@ -596,6 +606,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
DeltaTime: cfg.DeployConfig.DeltaTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)), DeltaTime: cfg.DeployConfig.DeltaTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
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)),
InteropTime: cfg.DeployConfig.InteropTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)), InteropTime: cfg.DeployConfig.InteropTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
ProtocolVersionsAddress: cfg.L1Deployments.ProtocolVersionsProxy, ProtocolVersionsAddress: cfg.L1Deployments.ProtocolVersionsProxy,
} }
......
...@@ -55,7 +55,8 @@ var mainnetCfg = rollup.Config{ ...@@ -55,7 +55,8 @@ var mainnetCfg = rollup.Config{
BlockTime: 2, BlockTime: 2,
MaxSequencerDrift: 600, MaxSequencerDrift: 600,
SeqWindowSize: 3600, SeqWindowSize: 3600,
ChannelTimeout: 300, ChannelTimeoutBedrock: 300,
ChannelTimeoutGranite: 50,
L1ChainID: big.NewInt(1), L1ChainID: big.NewInt(1),
L2ChainID: big.NewInt(10), L2ChainID: big.NewInt(10),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"), BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"),
...@@ -90,7 +91,8 @@ var sepoliaCfg = rollup.Config{ ...@@ -90,7 +91,8 @@ var sepoliaCfg = rollup.Config{
BlockTime: 2, BlockTime: 2,
MaxSequencerDrift: 600, MaxSequencerDrift: 600,
SeqWindowSize: 3600, SeqWindowSize: 3600,
ChannelTimeout: 300, ChannelTimeoutBedrock: 300,
ChannelTimeoutGranite: 50,
L1ChainID: big.NewInt(11155111), L1ChainID: big.NewInt(11155111),
L2ChainID: big.NewInt(11155420), L2ChainID: big.NewInt(11155420),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155420"), BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155420"),
...@@ -101,6 +103,7 @@ var sepoliaCfg = rollup.Config{ ...@@ -101,6 +103,7 @@ var sepoliaCfg = rollup.Config{
DeltaTime: u64Ptr(1703203200), DeltaTime: u64Ptr(1703203200),
EcotoneTime: u64Ptr(1708534800), EcotoneTime: u64Ptr(1708534800),
FjordTime: u64Ptr(1716998400), FjordTime: u64Ptr(1716998400),
GraniteTime: u64Ptr(1723478400),
ProtocolVersionsAddress: common.HexToAddress("0x79ADD5713B383DAa0a138d3C4780C7A1804a8090"), ProtocolVersionsAddress: common.HexToAddress("0x79ADD5713B383DAa0a138d3C4780C7A1804a8090"),
} }
...@@ -125,7 +128,8 @@ var sepoliaDev0Cfg = rollup.Config{ ...@@ -125,7 +128,8 @@ var sepoliaDev0Cfg = rollup.Config{
BlockTime: 2, BlockTime: 2,
MaxSequencerDrift: 600, MaxSequencerDrift: 600,
SeqWindowSize: 3600, SeqWindowSize: 3600,
ChannelTimeout: 300, ChannelTimeoutBedrock: 300,
ChannelTimeoutGranite: 50,
L1ChainID: big.NewInt(11155111), L1ChainID: big.NewInt(11155111),
L2ChainID: big.NewInt(11155421), L2ChainID: big.NewInt(11155421),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155421"), BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155421"),
...@@ -136,6 +140,7 @@ var sepoliaDev0Cfg = rollup.Config{ ...@@ -136,6 +140,7 @@ var sepoliaDev0Cfg = rollup.Config{
DeltaTime: u64Ptr(0), DeltaTime: u64Ptr(0),
EcotoneTime: u64Ptr(1706634000), EcotoneTime: u64Ptr(1706634000),
FjordTime: u64Ptr(1715961600), FjordTime: u64Ptr(1715961600),
GraniteTime: u64Ptr(1723046400),
ProtocolVersionsAddress: common.HexToAddress("0x252CbE9517F731C618961D890D534183822dcC8d"), ProtocolVersionsAddress: common.HexToAddress("0x252CbE9517F731C618961D890D534183822dcC8d"),
} }
......
...@@ -77,8 +77,11 @@ func (s *ChainSpec) MaxChannelBankSize(t uint64) uint64 { ...@@ -77,8 +77,11 @@ func (s *ChainSpec) MaxChannelBankSize(t uint64) uint64 {
} }
// ChannelTimeout returns the channel timeout constant. // ChannelTimeout returns the channel timeout constant.
func (s *ChainSpec) ChannelTimeout() uint64 { func (s *ChainSpec) ChannelTimeout(t uint64) uint64 {
return s.config.ChannelTimeout if s.config.IsGranite(t) {
return s.config.ChannelTimeoutGranite
}
return s.config.ChannelTimeoutBedrock
} }
// MaxRLPBytesPerChannel returns the maximum amount of bytes that will be read from // MaxRLPBytesPerChannel returns the maximum amount of bytes that will be read from
...@@ -130,10 +133,10 @@ func (s *ChainSpec) CheckForkActivation(log log.Logger, block eth.L2BlockRef) { ...@@ -130,10 +133,10 @@ func (s *ChainSpec) CheckForkActivation(log log.Logger, block eth.L2BlockRef) {
s.currentFork = Fjord s.currentFork = Fjord
} }
if s.config.IsGranite(block.Time) { if s.config.IsGranite(block.Time) {
s.currentFork = Fjord s.currentFork = Granite
} }
if s.config.IsHolocene(block.Time) { if s.config.IsHolocene(block.Time) {
s.currentFork = Fjord s.currentFork = Holocene
} }
if s.config.IsInterop(block.Time) { if s.config.IsInterop(block.Time) {
s.currentFork = Interop s.currentFork = Interop
......
...@@ -36,7 +36,8 @@ var testConfig = Config{ ...@@ -36,7 +36,8 @@ var testConfig = Config{
BlockTime: 2, BlockTime: 2,
MaxSequencerDrift: 600, MaxSequencerDrift: 600,
SeqWindowSize: 3600, SeqWindowSize: 3600,
ChannelTimeout: 300, ChannelTimeoutBedrock: 300,
ChannelTimeoutGranite: 50,
L1ChainID: big.NewInt(1), L1ChainID: big.NewInt(1),
L2ChainID: big.NewInt(10), L2ChainID: big.NewInt(10),
RegolithTime: u64ptr(10), RegolithTime: u64ptr(10),
...@@ -44,6 +45,7 @@ var testConfig = Config{ ...@@ -44,6 +45,7 @@ var testConfig = Config{
DeltaTime: u64ptr(30), DeltaTime: u64ptr(30),
EcotoneTime: u64ptr(40), EcotoneTime: u64ptr(40),
FjordTime: u64ptr(50), FjordTime: u64ptr(50),
GraniteTime: u64ptr(60),
InteropTime: nil, InteropTime: nil,
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"), BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"),
DepositContractAddress: common.HexToAddress("0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"), DepositContractAddress: common.HexToAddress("0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"),
...@@ -170,10 +172,16 @@ func TestCheckForkActivation(t *testing.T) { ...@@ -170,10 +172,16 @@ func TestCheckForkActivation(t *testing.T) {
expectedCurrentFork: Canyon, expectedCurrentFork: Canyon,
expectedLog: "Detected hardfork activation block", expectedLog: "Detected hardfork activation block",
}, },
{
name: "Granite activation",
block: eth.L2BlockRef{Time: 60, Number: 8, Hash: common.Hash{0x7}},
expectedCurrentFork: Granite,
expectedLog: "Detected hardfork activation block",
},
{ {
name: "No more hardforks", name: "No more hardforks",
block: eth.L2BlockRef{Time: 700, Number: 8, Hash: common.Hash{0x8}}, block: eth.L2BlockRef{Time: 700, Number: 9, Hash: common.Hash{0x8}},
expectedCurrentFork: Fjord, expectedCurrentFork: Granite,
expectedLog: "", expectedLog: "",
}, },
} }
......
...@@ -98,7 +98,7 @@ func (cb *ChannelBank) IngestFrame(f Frame) { ...@@ -98,7 +98,7 @@ func (cb *ChannelBank) IngestFrame(f Frame) {
} }
// check if the channel is not timed out // check if the channel is not timed out
if currentCh.OpenBlockNumber()+cb.spec.ChannelTimeout() < origin.Number { if currentCh.OpenBlockNumber()+cb.spec.ChannelTimeout(origin.Time) < origin.Number {
log.Warn("channel is timed out, ignore frame") log.Warn("channel is timed out, ignore frame")
return return
} }
...@@ -125,7 +125,7 @@ func (cb *ChannelBank) Read() (data []byte, err error) { ...@@ -125,7 +125,7 @@ func (cb *ChannelBank) Read() (data []byte, err error) {
// channels at the head of the queue and we want to remove them all. // channels at the head of the queue and we want to remove them all.
first := cb.channelQueue[0] first := cb.channelQueue[0]
ch := cb.channels[first] ch := cb.channels[first]
timedOut := ch.OpenBlockNumber()+cb.spec.ChannelTimeout() < cb.Origin().Number timedOut := ch.OpenBlockNumber()+cb.spec.ChannelTimeout(cb.Origin().Time) < cb.Origin().Number
if timedOut { if timedOut {
cb.log.Info("channel timed out", "channel", first, "frames", len(ch.inputs)) cb.log.Info("channel timed out", "channel", first, "frames", len(ch.inputs))
cb.metrics.RecordChannelTimedOut() cb.metrics.RecordChannelTimedOut()
...@@ -157,7 +157,7 @@ func (cb *ChannelBank) Read() (data []byte, err error) { ...@@ -157,7 +157,7 @@ func (cb *ChannelBank) Read() (data []byte, err error) {
func (cb *ChannelBank) tryReadChannelAtIndex(i int) (data []byte, err error) { func (cb *ChannelBank) tryReadChannelAtIndex(i int) (data []byte, err error) {
chanID := cb.channelQueue[i] chanID := cb.channelQueue[i]
ch := cb.channels[chanID] ch := cb.channels[chanID]
timedOut := ch.OpenBlockNumber()+cb.spec.ChannelTimeout() < cb.Origin().Number timedOut := ch.OpenBlockNumber()+cb.spec.ChannelTimeout(cb.Origin().Time) < cb.Origin().Number
if timedOut || !ch.IsReady() { if timedOut || !ch.IsReady() {
return nil, io.EOF return nil, io.EOF
} }
......
...@@ -100,7 +100,7 @@ func TestChannelBankSimple(t *testing.T) { ...@@ -100,7 +100,7 @@ func TestChannelBankSimple(t *testing.T) {
input.AddFrames("a:1:second") input.AddFrames("a:1:second")
input.AddFrame(Frame{}, io.EOF) input.AddFrame(Frame{}, io.EOF)
cfg := &rollup.Config{ChannelTimeout: 10} cfg := &rollup.Config{ChannelTimeoutBedrock: 10, ChannelTimeoutGranite: 10}
cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, nil, metrics.NoopMetrics) cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, nil, metrics.NoopMetrics)
...@@ -144,7 +144,7 @@ func TestChannelBankInterleavedPreCanyon(t *testing.T) { ...@@ -144,7 +144,7 @@ func TestChannelBankInterleavedPreCanyon(t *testing.T) {
input.AddFrames("a:1:second") input.AddFrames("a:1:second")
input.AddFrame(Frame{}, io.EOF) input.AddFrame(Frame{}, io.EOF)
cfg := &rollup.Config{ChannelTimeout: 10, CanyonTime: nil} cfg := &rollup.Config{ChannelTimeoutBedrock: 10, ChannelTimeoutGranite: 10, CanyonTime: nil}
cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, nil, metrics.NoopMetrics) cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, nil, metrics.NoopMetrics)
...@@ -209,7 +209,7 @@ func TestChannelBankInterleaved(t *testing.T) { ...@@ -209,7 +209,7 @@ func TestChannelBankInterleaved(t *testing.T) {
input.AddFrame(Frame{}, io.EOF) input.AddFrame(Frame{}, io.EOF)
ct := uint64(0) ct := uint64(0)
cfg := &rollup.Config{ChannelTimeout: 10, CanyonTime: &ct} cfg := &rollup.Config{ChannelTimeoutBedrock: 10, ChannelTimeoutGranite: 10, CanyonTime: &ct}
cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, nil, metrics.NoopMetrics) cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, nil, metrics.NoopMetrics)
...@@ -269,7 +269,7 @@ func TestChannelBankDuplicates(t *testing.T) { ...@@ -269,7 +269,7 @@ func TestChannelBankDuplicates(t *testing.T) {
input.AddFrames("a:1:second") input.AddFrames("a:1:second")
input.AddFrame(Frame{}, io.EOF) input.AddFrame(Frame{}, io.EOF)
cfg := &rollup.Config{ChannelTimeout: 10} cfg := &rollup.Config{ChannelTimeoutBedrock: 10, ChannelTimeoutGranite: 10}
cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, nil, metrics.NoopMetrics) cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, nil, metrics.NoopMetrics)
......
...@@ -197,29 +197,36 @@ func (dp *DerivationPipeline) initialReset(ctx context.Context, resetL2Safe eth. ...@@ -197,29 +197,36 @@ func (dp *DerivationPipeline) initialReset(ctx context.Context, resetL2Safe eth.
dp.log.Info("Rewinding derivation-pipeline L1 traversal to handle reset") dp.log.Info("Rewinding derivation-pipeline L1 traversal to handle reset")
dp.metrics.RecordPipelineReset() dp.metrics.RecordPipelineReset()
spec := rollup.NewChainSpec(dp.rollupCfg)
// Walk back L2 chain to find the L1 origin that is old enough to start buffering channel data from. // Walk back L2 chain to find the L1 origin that is old enough to start buffering channel data from.
pipelineL2 := resetL2Safe pipelineL2 := resetL2Safe
l1Origin := resetL2Safe.L1Origin l1Origin := resetL2Safe.L1Origin
pipelineOrigin, err := dp.l1Fetcher.L1BlockRefByHash(ctx, l1Origin.Hash)
if err != nil {
return NewTemporaryError(fmt.Errorf("failed to fetch the new L1 progress: origin: %s; err: %w", pipelineL2.L1Origin, err))
}
for { for {
afterL2Genesis := pipelineL2.Number > dp.rollupCfg.Genesis.L2.Number afterL2Genesis := pipelineL2.Number > dp.rollupCfg.Genesis.L2.Number
afterL1Genesis := pipelineL2.L1Origin.Number > dp.rollupCfg.Genesis.L1.Number afterL1Genesis := pipelineL2.L1Origin.Number > dp.rollupCfg.Genesis.L1.Number
afterChannelTimeout := pipelineL2.L1Origin.Number+dp.rollupCfg.ChannelTimeout > l1Origin.Number afterChannelTimeout := pipelineL2.L1Origin.Number+spec.ChannelTimeout(pipelineOrigin.Time) > l1Origin.Number
if afterL2Genesis && afterL1Genesis && afterChannelTimeout { if afterL2Genesis && afterL1Genesis && afterChannelTimeout {
parent, err := dp.l2.L2BlockRefByHash(ctx, pipelineL2.ParentHash) parent, err := dp.l2.L2BlockRefByHash(ctx, pipelineL2.ParentHash)
if err != nil { if err != nil {
return NewResetError(fmt.Errorf("failed to fetch L2 parent block %s", pipelineL2.ParentID())) return NewResetError(fmt.Errorf("failed to fetch L2 parent block %s", pipelineL2.ParentID()))
} }
pipelineL2 = parent pipelineL2 = parent
pipelineOrigin, err = dp.l1Fetcher.L1BlockRefByHash(ctx, pipelineL2.L1Origin.Hash)
if err != nil {
return NewTemporaryError(fmt.Errorf("failed to fetch the new L1 progress: origin: %s; err: %w", pipelineL2.L1Origin, err))
}
} else { } else {
break break
} }
} }
pipelineOrigin, err := dp.l1Fetcher.L1BlockRefByHash(ctx, pipelineL2.L1Origin.Hash)
if err != nil {
return NewTemporaryError(fmt.Errorf("failed to fetch the new L1 progress: origin: %s; err: %w", pipelineL2.L1Origin, err))
}
sysCfg, err := dp.l2.SystemConfigByL2Hash(ctx, pipelineL2.Hash) sysCfg, err := dp.l2.SystemConfigByL2Hash(ctx, pipelineL2.Hash)
if err != nil { if err != nil {
return NewTemporaryError(fmt.Errorf("failed to fetch L1 config of L2 block %s: %w", pipelineL2.ID(), err)) return NewTemporaryError(fmt.Errorf("failed to fetch L1 config of L2 block %s: %w", pipelineL2.ID(), err))
......
...@@ -526,6 +526,11 @@ func (d *Sequencer) startBuildingBlock() { ...@@ -526,6 +526,11 @@ func (d *Sequencer) startBuildingBlock() {
d.log.Info("Sequencing Fjord upgrade block") d.log.Info("Sequencing Fjord upgrade block")
} }
// For the Fjord activation block we shouldn't include any sequencer transactions.
if d.rollupCfg.IsGraniteActivationBlock(uint64(attrs.Timestamp)) {
d.log.Info("Sequencing Granite upgrade block")
}
d.log.Debug("prepared attributes for new block", d.log.Debug("prepared attributes for new block",
"num", l2Head.Number+1, "time", uint64(attrs.Timestamp), "num", l2Head.Number+1, "time", uint64(attrs.Timestamp),
"origin", l1Origin, "origin_time", l1Origin.Time, "noTxPool", attrs.NoTxPool) "origin", l1Origin, "origin_time", l1Origin.Time, "noTxPool", attrs.NoTxPool)
......
...@@ -78,7 +78,8 @@ func LoadOPStackRollupConfig(chainID uint64) (*Config, error) { ...@@ -78,7 +78,8 @@ func LoadOPStackRollupConfig(chainID uint64) (*Config, error) {
BlockTime: chConfig.BlockTime, BlockTime: chConfig.BlockTime,
MaxSequencerDrift: 600, MaxSequencerDrift: 600,
SeqWindowSize: chConfig.SequencerWindowSize, SeqWindowSize: chConfig.SequencerWindowSize,
ChannelTimeout: 300, ChannelTimeoutBedrock: 300,
ChannelTimeoutGranite: 50,
L1ChainID: new(big.Int).SetUint64(superChain.Config.L1.ChainID), L1ChainID: new(big.Int).SetUint64(superChain.Config.L1.ChainID),
L2ChainID: new(big.Int).SetUint64(chConfig.ChainID), L2ChainID: new(big.Int).SetUint64(chConfig.ChainID),
RegolithTime: &regolithTime, RegolithTime: &regolithTime,
......
...@@ -19,6 +19,7 @@ import ( ...@@ -19,6 +19,7 @@ import (
var ( var (
ErrBlockTimeZero = errors.New("block time cannot be 0") ErrBlockTimeZero = errors.New("block time cannot be 0")
ErrMissingChannelTimeout = errors.New("channel timeout must be set, this should cover at least a L1 block time") ErrMissingChannelTimeout = errors.New("channel timeout must be set, this should cover at least a L1 block time")
ErrInvalidGraniteChannelTimeout = errors.New("channel timeout granite must be less than channel timeout")
ErrInvalidSeqWindowSize = errors.New("sequencing window size must at least be 2") ErrInvalidSeqWindowSize = errors.New("sequencing window size must at least be 2")
ErrMissingGenesisL1Hash = errors.New("genesis L1 hash cannot be empty") ErrMissingGenesisL1Hash = errors.New("genesis L1 hash cannot be empty")
ErrMissingGenesisL2Hash = errors.New("genesis L2 hash cannot be empty") ErrMissingGenesisL2Hash = errors.New("genesis L2 hash cannot be empty")
...@@ -81,7 +82,8 @@ type Config struct { ...@@ -81,7 +82,8 @@ type Config struct {
// Number of epochs (L1 blocks) per sequencing window, including the epoch L1 origin block itself // Number of epochs (L1 blocks) per sequencing window, including the epoch L1 origin block itself
SeqWindowSize uint64 `json:"seq_window_size"` SeqWindowSize uint64 `json:"seq_window_size"`
// Number of L1 blocks between when a channel can be opened and when it must be closed by. // Number of L1 blocks between when a channel can be opened and when it must be closed by.
ChannelTimeout uint64 `json:"channel_timeout"` ChannelTimeoutBedrock uint64 `json:"channel_timeout"`
ChannelTimeoutGranite uint64 `json:"channel_timeout_granite"`
// Required to verify L1 signatures // Required to verify L1 signatures
L1ChainID *big.Int `json:"l1_chain_id"` L1ChainID *big.Int `json:"l1_chain_id"`
// Required to identify the L2 network and create p2p signatures unique for this chain. // Required to identify the L2 network and create p2p signatures unique for this chain.
...@@ -266,9 +268,17 @@ func (cfg *Config) Check() error { ...@@ -266,9 +268,17 @@ func (cfg *Config) Check() error {
if cfg.BlockTime == 0 { if cfg.BlockTime == 0 {
return ErrBlockTimeZero return ErrBlockTimeZero
} }
if cfg.ChannelTimeout == 0 { if cfg.ChannelTimeoutBedrock == 0 {
return ErrMissingChannelTimeout return ErrMissingChannelTimeout
} }
if cfg.GraniteTime != nil {
if cfg.ChannelTimeoutGranite == 0 {
return ErrMissingChannelTimeout
}
if cfg.ChannelTimeoutGranite > cfg.ChannelTimeoutBedrock {
return ErrInvalidGraniteChannelTimeout
}
}
if cfg.SeqWindowSize < 2 { if cfg.SeqWindowSize < 2 {
return ErrInvalidSeqWindowSize return ErrInvalidSeqWindowSize
} }
......
...@@ -42,7 +42,8 @@ func randConfig() *Config { ...@@ -42,7 +42,8 @@ func randConfig() *Config {
BlockTime: 2, BlockTime: 2,
MaxSequencerDrift: 100, MaxSequencerDrift: 100,
SeqWindowSize: 2, SeqWindowSize: 2,
ChannelTimeout: 123, ChannelTimeoutBedrock: 123,
ChannelTimeoutGranite: 45,
L1ChainID: big.NewInt(900), L1ChainID: big.NewInt(900),
L2ChainID: big.NewInt(901), L2ChainID: big.NewInt(901),
BatchInboxAddress: randAddr(), BatchInboxAddress: randAddr(),
...@@ -232,6 +233,15 @@ func TestActivations(t *testing.T) { ...@@ -232,6 +233,15 @@ func TestActivations(t *testing.T) {
return c.IsFjord(t) return c.IsFjord(t)
}, },
}, },
{
name: "Granite",
setUpgradeTime: func(t *uint64, c *Config) {
c.GraniteTime = t
},
checkEnabled: func(t uint64, c *Config) bool {
return c.IsGranite(t)
},
},
{ {
name: "Interop", name: "Interop",
setUpgradeTime: func(t *uint64, c *Config) { setUpgradeTime: func(t *uint64, c *Config) {
...@@ -366,8 +376,27 @@ func TestConfig_Check(t *testing.T) { ...@@ -366,8 +376,27 @@ func TestConfig_Check(t *testing.T) {
expectedErr: ErrBlockTimeZero, expectedErr: ErrBlockTimeZero,
}, },
{ {
name: "ChannelTimeoutZero", name: "ChannelTimeoutBedrockZero",
modifier: func(cfg *Config) { cfg.ChannelTimeout = 0 }, modifier: func(cfg *Config) { cfg.ChannelTimeoutBedrock = 0 },
expectedErr: ErrMissingChannelTimeout,
},
{
name: "ChannelTimeoutGraniteZeroNotEnabled",
modifier: func(cfg *Config) { cfg.ChannelTimeoutGranite = 0 },
expectedErr: nil,
},
{
name: "ChannelTimeoutGraniteZeroEnabled",
modifier: func(cfg *Config) {
genesis := uint64(0)
cfg.ChannelTimeoutGranite = 0
cfg.RegolithTime = &genesis
cfg.CanyonTime = &genesis
cfg.DeltaTime = &genesis
cfg.EcotoneTime = &genesis
cfg.FjordTime = &genesis
cfg.GraniteTime = &genesis
},
expectedErr: ErrMissingChannelTimeout, expectedErr: ErrMissingChannelTimeout,
}, },
{ {
...@@ -466,7 +495,7 @@ func TestConfig_Check(t *testing.T) { ...@@ -466,7 +495,7 @@ func TestConfig_Check(t *testing.T) {
cfg := randConfig() cfg := randConfig()
test.modifier(cfg) test.modifier(cfg)
err := cfg.Check() err := cfg.Check()
assert.Same(t, err, test.expectedErr) assert.ErrorIs(t, err, test.expectedErr)
}) })
} }
......
...@@ -229,6 +229,7 @@ func rollupFromGethConfig(cfg *params.ChainConfig) *rollup.Config { ...@@ -229,6 +229,7 @@ func rollupFromGethConfig(cfg *params.ChainConfig) *rollup.Config {
RegolithTime: cfg.RegolithTime, RegolithTime: cfg.RegolithTime,
CanyonTime: cfg.CanyonTime, CanyonTime: cfg.CanyonTime,
EcotoneTime: cfg.EcotoneTime, EcotoneTime: cfg.EcotoneTime,
GraniteTime: cfg.GraniteTime,
InteropTime: cfg.InteropTime, InteropTime: cfg.InteropTime,
} }
} }
......
...@@ -321,8 +321,8 @@ Use the env var `DEPLOY_CONFIG_PATH` to use a particular deploy config file at r ...@@ -321,8 +321,8 @@ Use the env var `DEPLOY_CONFIG_PATH` to use a particular deploy config file at r
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` either to the lower-case fork name (currently `delta`, `ecotone`, or `fjord`) or to `latest`, which will select `FORK` either to the lower-case fork name (currently `delta`, `ecotone`, `fjord`, or `granite`) or to `latest`, which
the latest fork available (currently `fjord`). will select the latest fork available (currently `granite`).
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:
......
...@@ -32,10 +32,11 @@ enum Fork { ...@@ -32,10 +32,11 @@ enum Fork {
NONE, NONE,
DELTA, DELTA,
ECOTONE, ECOTONE,
FJORD FJORD,
GRANITE
} }
Fork constant LATEST_FORK = Fork.FJORD; Fork constant LATEST_FORK = Fork.GRANITE;
library ForkUtils { library ForkUtils {
function toString(Fork _fork) internal pure returns (string memory) { function toString(Fork _fork) internal pure returns (string memory) {
...@@ -47,6 +48,8 @@ library ForkUtils { ...@@ -47,6 +48,8 @@ library ForkUtils {
return "ecotone"; return "ecotone";
} else if (_fork == Fork.FJORD) { } else if (_fork == Fork.FJORD) {
return "fjord"; return "fjord";
} else if (_fork == Fork.GRANITE) {
return "granite";
} else { } else {
return "unknown"; return "unknown";
} }
...@@ -153,6 +156,8 @@ library Config { ...@@ -153,6 +156,8 @@ library Config {
return Fork.ECOTONE; return Fork.ECOTONE;
} else if (forkHash == keccak256(bytes("fjord"))) { } else if (forkHash == keccak256(bytes("fjord"))) {
return Fork.FJORD; return Fork.FJORD;
} else if (forkHash == keccak256(bytes("granite"))) {
return Fork.GRANITE;
} else { } else {
revert(string.concat("Config: unknown fork: ", forkStr)); revert(string.concat("Config: unknown fork: ", forkStr));
} }
......
...@@ -158,6 +158,10 @@ contract L2Genesis is Deployer { ...@@ -158,6 +158,10 @@ contract L2Genesis is Deployer {
if (writeForkGenesisAllocs(_fork, Fork.FJORD, _mode)) { if (writeForkGenesisAllocs(_fork, Fork.FJORD, _mode)) {
return; return;
} }
if (writeForkGenesisAllocs(_fork, Fork.GRANITE, _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_) {
......
...@@ -30,6 +30,7 @@ contract DeployConfig is Script { ...@@ -30,6 +30,7 @@ contract DeployConfig is Script {
uint256 public l2GenesisDeltaTimeOffset; uint256 public l2GenesisDeltaTimeOffset;
uint256 public l2GenesisEcotoneTimeOffset; uint256 public l2GenesisEcotoneTimeOffset;
uint256 public l2GenesisFjordTimeOffset; uint256 public l2GenesisFjordTimeOffset;
uint256 public l2GenesisGraniteTimeOffset;
uint256 public maxSequencerDrift; uint256 public maxSequencerDrift;
uint256 public sequencerWindowSize; uint256 public sequencerWindowSize;
uint256 public channelTimeout; uint256 public channelTimeout;
...@@ -108,6 +109,7 @@ contract DeployConfig is Script { ...@@ -108,6 +109,7 @@ contract DeployConfig is Script {
l2GenesisDeltaTimeOffset = _readOr(_json, "$.l2GenesisDeltaTimeOffset", NULL_OFFSET); l2GenesisDeltaTimeOffset = _readOr(_json, "$.l2GenesisDeltaTimeOffset", NULL_OFFSET);
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);
maxSequencerDrift = stdJson.readUint(_json, "$.maxSequencerDrift"); maxSequencerDrift = stdJson.readUint(_json, "$.maxSequencerDrift");
sequencerWindowSize = stdJson.readUint(_json, "$.sequencerWindowSize"); sequencerWindowSize = stdJson.readUint(_json, "$.sequencerWindowSize");
...@@ -243,7 +245,9 @@ contract DeployConfig is Script { ...@@ -243,7 +245,9 @@ contract DeployConfig is Script {
} }
function latestGenesisFork() internal view returns (Fork) { function latestGenesisFork() internal view returns (Fork) {
if (l2GenesisFjordTimeOffset == 0) { if (l2GenesisGraniteTimeOffset == 0) {
return Fork.GRANITE;
} else if (l2GenesisFjordTimeOffset == 0) {
return Fork.FJORD; return Fork.FJORD;
} else if (l2GenesisEcotoneTimeOffset == 0) { } else if (l2GenesisEcotoneTimeOffset == 0) {
return Fork.ECOTONE; return Fork.ECOTONE;
......
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