From 13b08b8aeb21f70949c240d426795f85b7a8af55 Mon Sep 17 00:00:00 2001 From: Pangssu Date: Mon, 2 Dec 2024 16:44:15 +0900 Subject: [PATCH] feat: handle mpt transition time (#390) --- go.mod | 4 +- go.sum | 8 +- kroma-chain-ops/genesis/genesis.go | 15 +- kroma-devnet/devnet/__init__.py | 7 +- op-e2e/actions/user_test.go | 16 +- op-e2e/migration_test.go | 280 ++++++++++++++++++ op-node/rollup/derive/engine_controller.go | 7 +- op-node/rollup/driver/state.go | 6 + op-node/rollup/superchain.go | 22 +- op-service/flags/flags.go | 2 +- ops-devnet/docker-compose.yml | 54 +++- .../deploy-config/devnetL1-template.json | 1 + 12 files changed, 379 insertions(+), 43 deletions(-) create mode 100644 op-e2e/migration_test.go diff --git a/go.mod b/go.mod index 44477b478..a542b5891 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/kroma-network/kroma go 1.21 require ( - github.com/btcsuite/btcd v0.24.0 + github.com/btcsuite/btcd v0.24.2 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 github.com/cockroachdb/pebble v0.0.0-20231018212520-f6cde3fc2fa4 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 @@ -207,4 +207,4 @@ require ( replace github.com/ethereum-optimism/optimism v1.7.2 => ./ -replace github.com/ethereum/go-ethereum v1.13.8 => github.com/kroma-network/go-ethereum v0.5.0 +replace github.com/ethereum/go-ethereum v1.13.8 => github.com/kroma-network/go-ethereum v1.101308.3-0.20241129080356-056a5b4d3639 diff --git a/go.sum b/go.sum index d87843cde..192d0b931 100644 --- a/go.sum +++ b/go.sum @@ -48,8 +48,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= -github.com/btcsuite/btcd v0.24.0 h1:gL3uHE/IaFj6fcZSu03SvqPMSx7s/dPzfpG/atRwWdo= -github.com/btcsuite/btcd v0.24.0/go.mod h1:K4IDc1593s8jKXIF7yS7yCTSxrknB9z0STzc2j6XgE4= +github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= +github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= @@ -395,8 +395,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kroma-network/go-ethereum v0.5.0 h1:HqQ7khCuhQSWFCJu6/WnRQaBFlwDpPNNaLqDI3e+Br4= -github.com/kroma-network/go-ethereum v0.5.0/go.mod h1:SEk7AN/4FrDNJZg2pE1ja6xtPxLIJjfsbVVTweOafyk= +github.com/kroma-network/go-ethereum v1.101308.3-0.20241129080356-056a5b4d3639 h1:e4mSqeGxCFsRjxUf24HhdZwWAjM1Uu+Uw6A2cN3wYz0= +github.com/kroma-network/go-ethereum v1.101308.3-0.20241129080356-056a5b4d3639/go.mod h1:ZG4M8oph2j0C+R6CtUXuHeeUk5TuN5hVyl9gfwZawJg= github.com/kroma-network/zktrie v0.5.1-0.20230420142222-950ce7a8ce84 h1:VpLCQx+tFV6Nk0hbs3Noyxma/q9wIDdyacKpGQWUMI8= github.com/kroma-network/zktrie v0.5.1-0.20230420142222-950ce7a8ce84/go.mod h1:w54LrYo5rJEV503BgMPRNONsLTOEQv5V87q+uYaw9sM= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= diff --git a/kroma-chain-ops/genesis/genesis.go b/kroma-chain-ops/genesis/genesis.go index 6219df6d5..2af92db29 100644 --- a/kroma-chain-ops/genesis/genesis.go +++ b/kroma-chain-ops/genesis/genesis.go @@ -62,8 +62,7 @@ func NewL2Genesis(config *DeployConfig, block *types.Block) (*core.Genesis, erro ShanghaiTime: config.CanyonTime(block.Time()), CancunTime: config.EcotoneTime(block.Time()), EcotoneTime: config.EcotoneTime(block.Time()), - // TODO(seolaoh): uncomment this when geth updated - // KromaMPTTime: config.KromaMPTTime(block.Time()), + KromaMPTTime: config.KromaMPTTime(block.Time()), InteropTime: config.InteropTime(block.Time()), Kroma: ¶ms.KromaConfig{ EIP1559Denominator: eip1559Denom, @@ -73,10 +72,14 @@ func NewL2Genesis(config *DeployConfig, block *types.Block) (*core.Genesis, erro Zktrie: true, } - // TODO(seolaoh): turn off Zktrie when MPT time is past in genesis - //if kromaChainConfig.IsKromaMPT(block.Time()) { - // kromaChainConfig.Zktrie = false - //} + if kromaChainConfig.IsKromaMPT(block.Time()) { + kromaChainConfig.Optimism = ¶ms.OptimismConfig{ + EIP1559Denominator: eip1559Denom, + EIP1559Elasticity: eip1559Elasticity, + EIP1559DenominatorCanyon: eip1559DenomCanyon, + } + kromaChainConfig.Zktrie = false + } gasLimit := config.L2GenesisBlockGasLimit if gasLimit == 0 { diff --git a/kroma-devnet/devnet/__init__.py b/kroma-devnet/devnet/__init__.py index 2d9961a28..6347e1ba9 100644 --- a/kroma-devnet/devnet/__init__.py +++ b/kroma-devnet/devnet/__init__.py @@ -256,10 +256,15 @@ def devnet_deploy(paths): run_command(['docker', 'compose', 'up', '-d', 'l2'], cwd=paths.ops_bedrock_dir, env={ 'PWD': paths.ops_bedrock_dir }) + run_command(['docker', 'compose', 'up', '-d', 'l2-historical'], cwd=paths.ops_bedrock_dir, env={ + 'PWD': paths.ops_bedrock_dir + }) # Wait for the L2 to be available. wait_up(9545) wait_for_rpc_server('127.0.0.1:9545') + wait_up(9445) + wait_for_rpc_server('127.0.0.1:9445') # [Kroma: START] # Print out the addresses being used for easier debugging. @@ -275,7 +280,7 @@ def devnet_deploy(paths): log.info(f'Using AssetManager {asset_manager}') log.info('Bringing up `kroma-node`, `kroma-batcher` and `kroma-validator`.') - run_command(['docker', 'compose', 'up', '-d', 'kroma-node', 'kroma-batcher', 'kroma-validator', 'kroma-challenger'], cwd=paths.ops_bedrock_dir, env={ + run_command(['docker', 'compose', 'up', '-d', 'kroma-node', 'kroma-node-historical', 'kroma-batcher', 'kroma-validator', 'kroma-challenger'], cwd=paths.ops_bedrock_dir, env={ 'PWD': paths.ops_bedrock_dir, 'L2OO_ADDRESS': l2_output_oracle, 'COLOSSEUM_ADDRESS': colosseum, diff --git a/op-e2e/actions/user_test.go b/op-e2e/actions/user_test.go index 72ea00bf8..b87b3bcfc 100644 --- a/op-e2e/actions/user_test.go +++ b/op-e2e/actions/user_test.go @@ -5,12 +5,13 @@ import ( "math/rand" "testing" - "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + "github.com/ethereum-optimism/optimism/op-service/testlog" ) type hardforkScheduledTest struct { @@ -18,7 +19,6 @@ type hardforkScheduledTest struct { canyonTime *hexutil.Uint64 deltaTime *hexutil.Uint64 ecotoneTime *hexutil.Uint64 - kromaMPTTime *hexutil.Uint64 fjordTime *hexutil.Uint64 runToFork string } @@ -35,8 +35,6 @@ func (tc *hardforkScheduledTest) fork(fork string) **hexutil.Uint64 { switch fork { case "fjord": return &tc.fjordTime - case "mpt": - return &tc.kromaMPTTime case "ecotone": return &tc.ecotoneTime case "delta": @@ -67,10 +65,6 @@ func TestCrossLayerUser(t *testing.T) { "canyon", "delta", "ecotone", - // [Kroma: START] - // TODO(seolaoh): uncomment below forks when geth updated - //"mpt", - // [Kroma: END] //"fjord", } for i, fork := range forks { @@ -119,7 +113,6 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) { dp.DeployConfig.L2GenesisCanyonTimeOffset = test.canyonTime dp.DeployConfig.L2GenesisDeltaTimeOffset = test.deltaTime dp.DeployConfig.L2GenesisEcotoneTimeOffset = test.ecotoneTime - dp.DeployConfig.L2GenesisKromaMPTTimeOffset = test.kromaMPTTime dp.DeployConfig.L2GenesisFjordTimeOffset = test.fjordTime // [Kroma: START] @@ -133,9 +126,6 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) { if test.ecotoneTime != nil { require.Zero(t, uint64(*test.ecotoneTime)%uint64(dp.DeployConfig.L2BlockTime), "ecotone fork must be aligned") } - if test.kromaMPTTime != nil { - require.Zero(t, uint64(*test.kromaMPTTime)%uint64(dp.DeployConfig.L2BlockTime), "kroma mpt fork must be aligned") - } sd := e2eutils.Setup(t, dp, defaultAlloc) log := testlog.Logger(t, log.LevelDebug) diff --git a/op-e2e/migration_test.go b/op-e2e/migration_test.go new file mode 100644 index 000000000..cb827e9cb --- /dev/null +++ b/op-e2e/migration_test.go @@ -0,0 +1,280 @@ +package op_e2e + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/ethclient/gethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/rlp" + "github.com/kroma-network/zktrie/trie" + "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" + rollupNode "github.com/ethereum-optimism/optimism/op-node/node" + "github.com/ethereum-optimism/optimism/op-node/rollup/driver" + "github.com/ethereum-optimism/optimism/op-node/rollup/sync" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/kroma-network/kroma/kroma-bindings/predeploys" +) + +func TestMigration(t *testing.T) { + InitParallel(t) + + zero := hexutil.Uint64(0) + one := hexutil.Uint64(1) + mptTimeOffset := hexutil.Uint64(60) + + cfg := DefaultSystemConfig(t) + cfg.DeployConfig.L2GenesisDeltaTimeOffset = &zero + cfg.DeployConfig.L2GenesisEcotoneTimeOffset = &one + cfg.DeployConfig.L2GenesisKromaMPTTimeOffset = &mptTimeOffset + + // Setup historical rpc node. + historicalRpcPort := 8045 + cfg.Nodes["historical"] = &rollupNode.Config{ + Driver: driver.Config{ + VerifierConfDepth: 0, + SequencerConfDepth: 0, + SequencerEnabled: false, + }, + L1EpochPollInterval: time.Second * 4, + RuntimeConfigReloadInterval: time.Minute * 10, + ConfigPersistence: &rollupNode.DisabledConfigPersistence{}, + Sync: sync.Config{SyncMode: sync.CLSync}, + } + cfg.Loggers["historical"] = testlog.Logger(t, log.LevelInfo).New("role", "historical") + cfg.GethOptions["historical"] = append(cfg.GethOptions["historical"], []geth.GethOption{ + func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error { + nodeCfg.HTTPPort = historicalRpcPort + nodeCfg.HTTPModules = []string{"debug", "eth"} + nodeCfg.HTTPHost = "127.0.0.1" + return nil + }, + }...) + + // Set historical rpc endpoint. + for name := range cfg.Nodes { + name := name + cfg.GethOptions[name] = append(cfg.GethOptions[name], []geth.GethOption{ + func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error { + // Since the migration process requires preimages, enable storing preimage option. + ethCfg.Preimages = true + ethCfg.RollupHistoricalRPC = fmt.Sprintf("http://127.0.0.1:%d", historicalRpcPort) + if name == "historical" { + ethCfg.RollupHistoricalRPC = "" + ethCfg.DisableMPTMigration = true + } + // Deep copy the genesis + dst := &core.Genesis{} + b, _ := json.Marshal(ethCfg.Genesis) + err := json.Unmarshal(b, dst) + if err != nil { + return err + } + ethCfg.Genesis = dst + return nil + }, + }...) + } + + sys, err := cfg.Start(t) + defer sys.Close() + require.Nil(t, err, "Error starting up system") + l1Cl := sys.Clients["l1"] + l2Seq := sys.Clients["sequencer"] + l2Verif := sys.Clients["verifier"] + + // Send L2 TX + expectBalance := common.Big1 + _, err = wait.ForTransferTxOnL2(sys.Cfg.L2ChainIDBig(), l2Seq, l2Verif, cfg.Secrets.Alice, common.Address{0xff, 0xff}, expectBalance) + require.NoError(t, err) + + // Deploy contract on L2 + // object "Minimal" { + // code { + // datacopy(0x00, dataoffset("runtime"), datasize("runtime")) + // return(0x00, datasize("runtime")) + // } + // object "runtime" { + // code { + // if eq(calldatasize(), 0) { + // sstore(0x0, add(sload(0x0),1)) + // stop() + // } + // let slot := calldataload(0) + // sstore(slot, 0) + // } + // } + // } + minimalCode := common.Hex2Bytes("601680600c6000396000f3fe3615600b576000803555005b60016000540160005500") + chainId := cfg.L2ChainIDBig() + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + nonce, err := l2Seq.PendingNonceAt(ctx, cfg.Secrets.Addresses().Alice) + cancel() + require.NoError(t, err) + tx := types.MustSignNewTx(cfg.Secrets.Alice, types.LatestSignerForChainID(chainId), &types.DynamicFeeTx{ + ChainID: chainId, + Nonce: nonce, + To: nil, + GasTipCap: big.NewInt(10), + GasFeeCap: big.NewInt(200), + Gas: 100_000, + Data: minimalCode, + }) + ctx, cancel = context.WithTimeout(context.Background(), 2*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) + err = l2Seq.SendTransaction(ctx, tx) + cancel() + require.NoError(t, err) + deployReceipt, err := geth.WaitForTransaction(tx.Hash(), l2Verif, 4*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) + require.NoError(t, err) + // Set storage + tx = types.MustSignNewTx(cfg.Secrets.Alice, types.LatestSignerForChainID(chainId), &types.DynamicFeeTx{ + ChainID: chainId, + Nonce: tx.Nonce() + 1, + To: &deployReceipt.ContractAddress, + GasTipCap: big.NewInt(10), + GasFeeCap: big.NewInt(200), + Gas: 100_000, + }) + ctx, cancel = context.WithTimeout(context.Background(), 2*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) + err = l2Seq.SendTransaction(ctx, tx) + cancel() + require.NoError(t, err) + _, err = geth.WaitForTransaction(tx.Hash(), l2Verif, 4*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) + require.NoError(t, err) + // Check storage value + ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second) + slot := common.Hash{} + value, err := l2Verif.StorageAt(ctx, *tx.To(), slot, nil) + cancel() + require.NoError(t, err) + require.True(t, new(big.Int).SetBytes(value).Uint64() > 0) + // Delete storage + tx = types.MustSignNewTx(cfg.Secrets.Alice, types.LatestSignerForChainID(chainId), &types.DynamicFeeTx{ + ChainID: chainId, + Nonce: tx.Nonce() + 1, + To: &deployReceipt.ContractAddress, + GasTipCap: big.NewInt(10), + GasFeeCap: big.NewInt(200), + Gas: 100_000, + Data: slot.Bytes(), + }) + ctx, cancel = context.WithTimeout(context.Background(), 2*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) + err = l2Seq.SendTransaction(ctx, tx) + cancel() + require.NoError(t, err) + _, err = geth.WaitForTransaction(tx.Hash(), l2Verif, 4*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) + require.NoError(t, err) + // Check storage value + ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second) + value, err = l2Verif.StorageAt(ctx, *tx.To(), slot, nil) + cancel() + require.NoError(t, err) + require.True(t, new(big.Int).SetBytes(value).Uint64() == 0) + + transitionBlockNumber := new(big.Int).SetUint64(uint64(mptTimeOffset) / cfg.DeployConfig.L2BlockTime) + _, err = geth.WaitForBlock(transitionBlockNumber, l2Verif, time.Minute) + require.Nil(t, err) + + // Ensure that the transition block inserted into chain. + ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) + transitionBlock, err := l2Verif.BlockByNumber(ctx, transitionBlockNumber) + cancel() + require.Nil(t, err) + require.Equal(t, []byte("BEDROCK"), transitionBlock.Extra()) + + // Ensure that the transition block has been finalized. + l2Finalized, err := geth.WaitForBlockToBeFinalized(transitionBlockNumber, l2Verif, 1*time.Minute) + require.NoError(t, err, "must be able to fetch a finalized L2 block") + require.True(t, l2Finalized.NumberU64() >= transitionBlockNumber.Uint64(), "must have finalized L2 block") + + validateL1BlockTxProof(t, l1Cl, l2Verif, transitionBlockNumber) + + // Check states after migration + ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second) + balance, err := l2Verif.BalanceAt(ctx, common.Address{0xff, 0xff}, nil) + cancel() + require.Nil(t, err) + require.True(t, balance.Cmp(expectBalance) == 0) + + ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second) + code, err := l2Verif.CodeAt(ctx, deployReceipt.ContractAddress, nil) + cancel() + require.Nil(t, err) + require.True(t, len(code) > 0) +} + +func validateL1BlockTxProof(t *testing.T, l1Cl *ethclient.Client, l2Cl *ethclient.Client, number *big.Int) { + l1BlockHashSlot := "0x2" + l2GethCl := gethclient.New(l2Cl.Client()) + + validateZktProof := func(hex string) { + b := common.Hex2Bytes(strings.TrimPrefix(hex, "0x")) + _, err := trie.DecodeSMTProof(b) + require.Nil(t, err) + } + validateMptProof := func(hex string) { + b := common.Hex2Bytes(strings.TrimPrefix(hex, "0x")) + _, _, err := rlp.SplitList(b) + require.Nil(t, err) + } + validateL1BlockHash := func(v *big.Int) { + _, err := l1Cl.BlockByHash(context.Background(), common.BigToHash(v)) + require.Nil(t, err) + } + proof, err := l2GethCl.GetProof(context.Background(), predeploys.L1BlockAddr, []string{l1BlockHashSlot}, new(big.Int).Sub(number, common.Big1)) + require.Nil(t, err, "failed to validate state proof for pre-transition block") + for _, accProof := range proof.AccountProof { + validateZktProof(accProof) + } + for _, storageProof := range proof.StorageProof { + for _, p := range storageProof.Proof { + validateZktProof(p) + } + if storageProof.Key == l1BlockHashSlot { + validateL1BlockHash(storageProof.Value) + } + } + + proof, err = l2GethCl.GetProof(context.Background(), predeploys.L1BlockAddr, []string{l1BlockHashSlot}, number) + require.Nil(t, err, "failed to validate state proof for transition block") + for _, accProof := range proof.AccountProof { + validateMptProof(accProof) + } + for _, storageProof := range proof.StorageProof { + for _, p := range storageProof.Proof { + validateMptProof(p) + } + if storageProof.Key == l1BlockHashSlot { + validateL1BlockHash(storageProof.Value) + } + } + + proof, err = l2GethCl.GetProof(context.Background(), predeploys.L1BlockAddr, []string{l1BlockHashSlot}, new(big.Int).Add(number, common.Big1)) + require.Nil(t, err, "failed to validate state proof for post-transition block") + for _, accProof := range proof.AccountProof { + validateMptProof(accProof) + } + for _, storageProof := range proof.StorageProof { + for _, p := range storageProof.Proof { + validateMptProof(p) + } + if storageProof.Key == l1BlockHashSlot { + validateL1BlockHash(storageProof.Value) + } + } +} diff --git a/op-node/rollup/derive/engine_controller.go b/op-node/rollup/derive/engine_controller.go index d9103fcd5..7461aaaec 100644 --- a/op-node/rollup/derive/engine_controller.go +++ b/op-node/rollup/derive/engine_controller.go @@ -6,15 +6,16 @@ import ( "fmt" "time" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/async" "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" "github.com/ethereum-optimism/optimism/op-service/clock" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" ) type syncStatusEnum int diff --git a/op-node/rollup/driver/state.go b/op-node/rollup/driver/state.go index 33859ab8a..41bbee32e 100644 --- a/op-node/rollup/driver/state.go +++ b/op-node/rollup/driver/state.go @@ -7,10 +7,12 @@ import ( "errors" "fmt" "io" + "strings" gosync "sync" "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-node/rollup" @@ -389,6 +391,10 @@ func (s *Driver) eventLoop() { s.metrics.RecordPipelineReset() continue } else if err != nil && errors.Is(err, derive.ErrTemporary) { + if strings.Contains(err.Error(), core.ErrHaltOnStateTransition.Error()) { + s.log.Warn("Stopping derivation pipeline", "reason", err) + return + } s.log.Warn("Derivation process temporary error", "attempts", stepAttempts, "err", err) reqStep() continue diff --git a/op-node/rollup/superchain.go b/op-node/rollup/superchain.go index cc74b209a..a104f2899 100644 --- a/op-node/rollup/superchain.go +++ b/op-node/rollup/superchain.go @@ -91,18 +91,16 @@ func LoadOPStackRollupConfig(chainID uint64) (*Config, error) { // but since none of the superchain chains differ, it's not represented in the superchain-registry yet. // This restriction on superchain-chains may change in the future. // Test/Alt configurations can still load custom rollup-configs when necessary. - BlockTime: 2, - MaxSequencerDrift: 600, - SeqWindowSize: 3600, - ChannelTimeout: 300, - L1ChainID: new(big.Int).SetUint64(superChain.Config.L1.ChainID), - L2ChainID: new(big.Int).SetUint64(chConfig.ChainID), - RegolithTime: ®olithTime, - CanyonTime: chConfig.CanyonTime, - DeltaTime: chConfig.DeltaTime, - EcotoneTime: chConfig.EcotoneTime, - // TODO(seolaoh): uncomment this when geth updated - // KromaMPTTime: chConfig.KromaMPTTime, + BlockTime: 2, + MaxSequencerDrift: 600, + SeqWindowSize: 3600, + ChannelTimeout: 300, + L1ChainID: new(big.Int).SetUint64(superChain.Config.L1.ChainID), + L2ChainID: new(big.Int).SetUint64(chConfig.ChainID), + RegolithTime: ®olithTime, + CanyonTime: chConfig.CanyonTime, + DeltaTime: chConfig.DeltaTime, + EcotoneTime: chConfig.EcotoneTime, FjordTime: chConfig.FjordTime, BatchInboxAddress: common.Address(chConfig.BatchInboxAddr), DepositContractAddress: common.Address(addrs.OptimismPortalProxy), diff --git a/op-service/flags/flags.go b/op-service/flags/flags.go index eacc515d2..673b9a5a7 100644 --- a/op-service/flags/flags.go +++ b/op-service/flags/flags.go @@ -45,7 +45,7 @@ func CLIFlags(envPrefix string, category string) []cli.Flag { &cli.Uint64Flag{ Name: KromaMPTOverrideFlagName, Usage: "Manually specify the Kroma MPT fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_KROMA_MPT"), + EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_MPT"), Hidden: false, Category: category, }, diff --git a/ops-devnet/docker-compose.yml b/ops-devnet/docker-compose.yml index ed2e87201..728871a89 100644 --- a/ops-devnet/docker-compose.yml +++ b/ops-devnet/docker-compose.yml @@ -7,6 +7,7 @@ version: '3.4' volumes: l1_data: l2_data: + l2_historical_data: kroma_log: @@ -107,7 +108,7 @@ services: l2: pid: host # allow debugging - image: kromanetwork/geth:v0.5.0 + image: kromanetwork/geth:mpt-056a5b4d ports: - "9545:8545" - "9546:8546" @@ -123,6 +124,28 @@ services: - "/bin/sh" - "/entrypoint.sh" - "--authrpc.jwtsecret=/config/test-jwt-secret.txt" + - "--rollup.historicalrpc=http://l2-historical:8545" + + l2-historical: + pid: host # allow debugging + image: kromanetwork/geth:mpt-056a5b4d + ports: + - "9445:8545" + - "9446:8546" + environment: + CHAIN_ID: 901 + GETH_MINER_RECOMMIT: 100ms + volumes: + - "l2_historical_data:/db" + - "${PWD}/entrypoint-l2.sh:/entrypoint.sh" + - "${PWD}/../.devnet/genesis-l2.json:/genesis.json" + - "${PWD}/test-jwt-secret.txt:/config/test-jwt-secret.txt" + entrypoint: # pass the L2 specific flags by overriding the entry-point and adding extra arguments + - "/bin/sh" + - "/entrypoint.sh" + - "--authrpc.jwtsecret=/config/test-jwt-secret.txt" + - "--kroma.migration.disable=true" + kroma-node: pid: host # allow debugging @@ -169,6 +192,35 @@ services: - "${PWD}/../.devnet/rollup.json:/rollup.json" - kroma_log:/kroma_log + kroma-node-historical: + pid: host # allow debugging + depends_on: + - l1 + - l2-historical + image: "kromanetwork/node" + build: + context: .. + target: "op-node" + environment: + NODE_L1_ETH_RPC: ws://l1:8546 + NODE_L2_ENGINE_RPC: http://l2-historical:8551 + NODE_L2_ENGINE_AUTH: /config/test-jwt-secret.txt + NODE_ROLLUP_CONFIG: /rollup.json + NODE_L1_BEACON: http://beacon-chain:3500 + NODE_SEQUENCER_ENABLED: false + NODE_SEQUENCER_L1_CONFS: 0 + NODE_VERIFIER_L1_CONFS: 0 + NODE_P2P_LISTEN_IP: 0.0.0.0 + NODE_P2P_LISTEN_TCP_PORT: 9003 + NODE_P2P_LISTEN_UDP_PORT: 9003 + NODE_P2P_PEER_SCORING: light + NODE_P2P_PEER_BANNING: true + NODE_P2P_PRIV_PATH: /config/p2p-node-key.txt + volumes: + - "${PWD}/p2p-node-key.txt:/config/p2p-node-key.txt" + - "${PWD}/test-jwt-secret.txt:/config/test-jwt-secret.txt" + - "${PWD}/../.devnet/rollup.json:/rollup.json" + kroma-validator: pid: host # allow debugging depends_on: diff --git a/packages/contracts/deploy-config/devnetL1-template.json b/packages/contracts/deploy-config/devnetL1-template.json index 20ab26f95..bbfa954a4 100644 --- a/packages/contracts/deploy-config/devnetL1-template.json +++ b/packages/contracts/deploy-config/devnetL1-template.json @@ -33,6 +33,7 @@ "l2GenesisCanyonTimeOffset": "0x0", "l2GenesisDeltaTimeOffset": "0x0", "l2GenesisEcotoneTimeOffset": "0x2", + "l2GenesisKromaMPTTimeOffset": "0x4", "systemConfigStartBlock": 0, "validatorRewardScalar": 5000, "validatorPoolTrustedValidator": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",