diff --git a/op-e2e/op_geth.go b/op-e2e/op_geth.go index 2b2a9def12..744ffe7455 100644 --- a/op-e2e/op_geth.go +++ b/op-e2e/op_geth.go @@ -220,6 +220,20 @@ func (d *OpGeth) CreatePayloadAttributes(txs ...*types.Transaction) (*eth.Payloa txBytes = append(txBytes, bin) } + // [Kroma: START] Use KromaDepositTx instead of DepositTx + if d.L2ChainConfig.IsPreKromaMPT(uint64(timestamp)) { + for i := range txBytes { + if txBytes[i][0] == types.DepositTxType { + bin, err := derive.ToKromaDepositBytes(txBytes[i]) + if err != nil { + return nil, fmt.Errorf("failed to convert DepositTx to KromaDepositTx: %w", err) + } + txBytes[i] = bin + } + } + } + // [Kroma: END] + var withdrawals *types.Withdrawals if d.L2ChainConfig.IsCanyon(uint64(timestamp)) { withdrawals = &types.Withdrawals{} diff --git a/op-e2e/op_geth_test.go b/op-e2e/op_geth_test.go index 66cae566d8..e9ab4f2e4f 100644 --- a/op-e2e/op_geth_test.go +++ b/op-e2e/op_geth_test.go @@ -93,6 +93,10 @@ func TestInvalidDepositInFCU(t *testing.T) { Gas: 25000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + badDepositTx, err = badDepositTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] // We are inserting a block with an invalid deposit. // The invalid deposit should still remain in the block. @@ -263,6 +267,10 @@ func TestPreregolith(t *testing.T) { Gas: 25000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + depositTx, err = depositTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] envelope, err := opGeth.AddL2Block(ctx, depositTx) require.NoError(t, err) @@ -308,6 +316,10 @@ func TestPreregolith(t *testing.T) { Gas: 21_000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + incrementNonceTx, err = incrementNonceTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] // Contract creation deposit tx contractCreateTx := types.NewTx(&types.DepositTx{ @@ -317,6 +329,10 @@ func TestPreregolith(t *testing.T) { Data: []byte{}, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + contractCreateTx, err = contractCreateTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] _, err = opGeth.AddL2Block(ctx, incrementNonceTx, contractCreateTx) require.NoError(t, err) @@ -367,6 +383,10 @@ func TestPreregolith(t *testing.T) { Gas: uint64(cfg.DeployConfig.L2GenesisBlockGasLimit) - 1_000_000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + depositTx, err = depositTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] signer := types.LatestSigner(opGeth.L2ChainConfig) // Second tx with a gas limit that will fit in regolith but not bedrock @@ -452,6 +472,10 @@ func TestRegolith(t *testing.T) { Gas: 25000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + depositTx, err = depositTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] envelope, err := opGeth.AddL2Block(ctx, depositTx) require.NoError(t, err) @@ -504,6 +528,10 @@ func TestRegolith(t *testing.T) { Gas: 21_000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + incrementNonceTx, err = incrementNonceTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] // Contract creation deposit tx contractCreateTx := types.NewTx(&types.DepositTx{ @@ -513,6 +541,10 @@ func TestRegolith(t *testing.T) { Data: []byte{}, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + contractCreateTx, err = contractCreateTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] _, err = opGeth.AddL2Block(ctx, incrementNonceTx, contractCreateTx) require.NoError(t, err) @@ -570,6 +602,10 @@ func TestRegolith(t *testing.T) { Gas: uint64(cfg.DeployConfig.L2GenesisBlockGasLimit) - 1_000_000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + depositTx, err = depositTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] signer := types.LatestSigner(opGeth.L2ChainConfig) // Second tx with a gas limit that will fit in regolith but not bedrock @@ -674,6 +710,10 @@ func TestRegolith(t *testing.T) { Gas: 1_000_000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + deployTx, err = deployTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] // Store a non-zero value storeTx := types.NewTx(&types.DepositTx{ @@ -684,6 +724,10 @@ func TestRegolith(t *testing.T) { Gas: 1_000_000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + storeTx, err = storeTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] // Store a non-zero value zeroTx := types.NewTx(&types.DepositTx{ @@ -694,6 +738,10 @@ func TestRegolith(t *testing.T) { Gas: 1_000_000, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + zeroTx, err = zeroTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] // Store a non-zero value again // Has same gas cost as zeroTx, except the first tx gets a gas refund for clearing the storage slot @@ -705,6 +753,10 @@ func TestRegolith(t *testing.T) { Gas: 1_000_001, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + rezeroTx, err = rezeroTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] _, err = opGeth.AddL2Block(ctx, deployTx, storeTx, zeroTx, rezeroTx) require.NoError(t, err) @@ -791,6 +843,10 @@ func TestPreCanyon(t *testing.T) { }, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + pushZeroContractCreateTxn, err = pushZeroContractCreateTxn.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] _, err = opGeth.AddL2Block(ctx, pushZeroContractCreateTxn) require.NoError(t, err) @@ -865,6 +921,10 @@ func TestCanyon(t *testing.T) { }, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + pushZeroContractCreateTxn, err = pushZeroContractCreateTxn.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] _, err = opGeth.AddL2Block(ctx, pushZeroContractCreateTxn) require.NoError(t, err) @@ -933,6 +993,10 @@ func TestPreEcotone(t *testing.T) { }, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + tstoreTxn, err = tstoreTxn.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] _, err = opGeth.AddL2Block(ctx, tstoreTxn) require.NoError(t, err) @@ -1014,6 +1078,10 @@ func TestEcotone(t *testing.T) { }, IsSystemTransaction: false, }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + tstoreTxn, err = tstoreTxn.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] _, err = opGeth.AddL2Block(ctx, tstoreTxn) require.NoError(t, err) @@ -1027,3 +1095,117 @@ func TestEcotone(t *testing.T) { }) } } + +func TestPreKromaMPT(t *testing.T) { + futureTimestamp := hexutil.Uint64(4) + + tests := []struct { + name string + kromaMPTTime *hexutil.Uint64 + }{ + {name: "KromaMPTNotScheduled"}, + {name: "KromaMPTNotYetActive", kromaMPTTime: &futureTimestamp}, + } + for _, test := range tests { + test := test + t.Run(fmt.Sprintf("KromaDepositTx_%s", test.name), func(t *testing.T) { + InitParallel(t) + cfg := DefaultSystemConfig(t) + s := hexutil.Uint64(0) + cfg.DeployConfig.L2GenesisCanyonTimeOffset = &s + cfg.DeployConfig.L2GenesisDeltaTimeOffset = &s + cfg.DeployConfig.L2GenesisEcotoneTimeOffset = &s + cfg.DeployConfig.L2GenesisKromaMPTTimeOffset = test.kromaMPTTime + + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + opGeth, err := NewOpGeth(t, ctx, &cfg) + require.NoError(t, err) + defer opGeth.Close() + + fromAddr := cfg.Secrets.Addresses().Alice + // Contract creation deposit tx + contractCreateTx := types.NewTx(&types.DepositTx{ + From: fromAddr, + Value: big.NewInt(params.Ether), + Gas: 1000001, + Data: []byte{}, + IsSystemTransaction: false, + }) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + contractCreateTx, err = contractCreateTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] + + _, err = opGeth.AddL2Block(ctx, contractCreateTx) + require.NoError(t, err) + + // Check L1Info + l2Block, err := opGeth.L2Client.BlockByNumber(ctx, nil) + require.NoError(t, err) + depTxBytes, err := l2Block.Transactions()[0].MarshalBinary() + require.NoError(t, err) + isKromaDepTx, err := types.IsKromaDepositTx(depTxBytes[1:]) + require.NoError(t, err) + assert.Equal(t, true, isKromaDepTx) + + receipt, err := opGeth.L2Client.TransactionReceipt(ctx, contractCreateTx.Hash()) + require.NoError(t, err) + assert.Equal(t, types.ReceiptStatusSuccessful, receipt.Status) + }) + } +} + +func TestKromaMPT(t *testing.T) { + tests := []struct { + name string + kromaMPTTime hexutil.Uint64 + }{ + {name: "ActivateAtGenesis", kromaMPTTime: 0}, + } + for _, test := range tests { + test := test + t.Run(fmt.Sprintf("ReviveDepositTx_%s", test.name), func(t *testing.T) { + InitParallel(t) + cfg := DefaultSystemConfig(t) + s := hexutil.Uint64(0) + cfg.DeployConfig.L2GenesisCanyonTimeOffset = &s + cfg.DeployConfig.L2GenesisDeltaTimeOffset = &s + cfg.DeployConfig.L2GenesisEcotoneTimeOffset = &s + cfg.DeployConfig.L2GenesisKromaMPTTimeOffset = &test.kromaMPTTime + + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + opGeth, err := NewOpGeth(t, ctx, &cfg) + require.NoError(t, err) + defer opGeth.Close() + + fromAddr := cfg.Secrets.Addresses().Alice + // Contract creation deposit tx + contractCreateTx := types.NewTx(&types.DepositTx{ + From: fromAddr, + Value: big.NewInt(params.Ether), + Gas: 1000001, + Data: []byte{}, + IsSystemTransaction: false, + }) + + _, err = opGeth.AddL2Block(ctx, contractCreateTx) + require.NoError(t, err) + + l2Block, err := opGeth.L2Client.BlockByNumber(ctx, nil) + require.NoError(t, err) + depTxBytes, err := l2Block.Transactions()[0].MarshalBinary() + require.NoError(t, err) + isKromaDepTx, err := types.IsKromaDepositTx(depTxBytes[1:]) + require.NoError(t, err) + assert.Equal(t, false, isKromaDepTx) + + receipt, err := opGeth.L2Client.TransactionReceipt(ctx, contractCreateTx.Hash()) + require.NoError(t, err) + assert.Equal(t, types.ReceiptStatusSuccessful, receipt.Status) + }) + } +} diff --git a/op-node/p2p/sync.go b/op-node/p2p/sync.go index d1f2ea66b3..50ea1797e8 100644 --- a/op-node/p2p/sync.go +++ b/op-node/p2p/sync.go @@ -21,12 +21,10 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/kroma-network/kroma/op-node/rollup/derive" ) // StreamCtxFn provides a new context to use when handling stream requests @@ -670,20 +668,6 @@ func (s *SyncClient) readExecutionPayload(data []byte, expectedTime uint64) (*et return nil, fmt.Errorf("failed to decode response: %w", err) } - // [Kroma: START] Use KromaDepositTx instead of DepositTx before MPT time - if !s.cfg.IsKromaMPT(expectedTime) { - for i, otx := range res.Transactions { - if otx[0] == types.DepositTxType { - var err error - res.Transactions[i], err = derive.ToKromaDepositBytes(otx) - if err != nil { - return nil, fmt.Errorf("failed to convert deposit tx to KromaDepositTx: %w", err) - } - } - } - } - // [Kroma: END] - return ð.ExecutionPayloadEnvelope{ExecutionPayload: &res}, nil } diff --git a/op-node/rollup/derive/attributes.go b/op-node/rollup/derive/attributes.go index 0cac255ebb..0150ab0569 100644 --- a/op-node/rollup/derive/attributes.go +++ b/op-node/rollup/derive/attributes.go @@ -172,13 +172,6 @@ func ToKromaDepositBytes(input hexutil.Bytes) (hexutil.Bytes, error) { if input[0] != types.DepositTxType { return nil, fmt.Errorf("unexpected transaction type: %d", input[0]) } - isKromaDepTx, err := types.IsKromaDepositTx(input[1:]); - if err != nil { - return nil, err - } - if isKromaDepTx { - return input, nil - } var tx types.Transaction if err := tx.UnmarshalBinary(input); err != nil { return nil, fmt.Errorf("failed to decode deposit tx: %w", err) diff --git a/op-node/rollup/derive/attributes_queue_test.go b/op-node/rollup/derive/attributes_queue_test.go index f5f70c7584..c742d98358 100644 --- a/op-node/rollup/derive/attributes_queue_test.go +++ b/op-node/rollup/derive/attributes_queue_test.go @@ -90,9 +90,9 @@ func TestAttributesQueue(t *testing.T) { l1InfoTx, err := L1InfoDepositBytes(&rollupCfg, expectedL1Cfg, safeHead.SequenceNumber+1, l1Info, 0) require.NoError(st, err) - l1InfoTx, err = ToKromaDepositBytes(l1InfoTx) + kromaDepTx, err := ToKromaDepositBytes(l1InfoTx) require.NoError(st, err) - testAttributes(l1InfoTx, common.Address{}) + testAttributes(kromaDepTx, common.Address{}) }) t.Run("after kroma mpt time", func(st *testing.T) { diff --git a/op-node/rollup/derive/attributes_test.go b/op-node/rollup/derive/attributes_test.go index 898fd2fa39..8a97c93d08 100644 --- a/op-node/rollup/derive/attributes_test.go +++ b/op-node/rollup/derive/attributes_test.go @@ -113,6 +113,10 @@ func TestPreparePayloadAttributes(t *testing.T) { l1Info.InfoNum = l2Parent.L1Origin.Number + 1 epoch := l1Info.ID() l1InfoTx, err := L1InfoDepositBytes(cfg, testSysCfg, 0, l1Info, 0) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + l1InfoTx, err = ToKromaDepositBytes(l1InfoTx) + require.NoError(t, err) + // [Kroma: END] require.NoError(t, err) l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, nil, nil) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher) @@ -185,6 +189,10 @@ func TestPreparePayloadAttributes(t *testing.T) { epoch := l1Info.ID() l1InfoTx, err := L1InfoDepositBytes(cfg, testSysCfg, l2Parent.SequenceNumber+1, l1Info, 0) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + l1InfoTx, err = ToKromaDepositBytes(l1InfoTx) + require.NoError(t, err) + // [Kroma: END] require.NoError(t, err) l1Fetcher.ExpectInfoByHash(epoch.Hash, l1Info, nil) @@ -241,6 +249,68 @@ func TestPreparePayloadAttributes(t *testing.T) { time-- } l1InfoTx, err := L1InfoDepositBytes(cfg, testSysCfg, 0, l1Info, time) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + l1InfoTx, err = ToKromaDepositBytes(l1InfoTx) + require.NoError(t, err) + // [Kroma: END] + 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, l1InfoTx, []byte(attrs.Transactions[0])) + }) + } + }) + // Test that the payload attributes builder changes the deposit format based on L2-time-based KromaMPT activation + t.Run("kroma_mpt", func(t *testing.T) { + testCases := []struct { + name string + l1Time uint64 + l2ParentTime uint64 + kromaMPTTime uint64 + kromaMPT bool + }{ + {"exactly", 900, 1000 - cfg.BlockTime, 1000, true}, + {"almost", 900, 1000 - cfg.BlockTime - 1, 1000, false}, + {"inactive", 700, 700, 1000, false}, + {"l1 time before kroma_mpt", 1000, 1001, 1001, true}, + {"l1 time way before kroma_mpt", 1000, 2000, 2000, true}, + {"l1 time before kroma_mpt and l2 after", 1000, 3000, 2000, true}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cfgCopy := *cfg // copy, we are making KromaMPT config modifications + cfg := &cfgCopy + rng := rand.New(rand.NewSource(1234)) + l1Fetcher := &testutils.MockL1Source{} + defer l1Fetcher.AssertExpectations(t) + l2Parent := testutils.RandomL2BlockRef(rng) + cfg.KromaMPTTime = &tc.kromaMPTTime + l2Parent.Time = tc.l2ParentTime + + l1CfgFetcher := &testutils.MockL2Client{} + 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 + l1Info.InfoTime = tc.l1Time + + epoch := l1Info.ID() + time := tc.kromaMPTTime + if !tc.kromaMPT { + time-- + } + l1InfoTx, err := L1InfoDepositBytes(cfg, testSysCfg, 0, l1Info, time) + + // [Kroma: START] Use KromaDepositTx instead of DepositTx + if cfg.KromaMPTTime == nil || !cfg.IsKromaMPT(time) { + l1InfoTx, err = ToKromaDepositBytes(l1InfoTx) + require.NoError(t, err) + } + // [Kroma: END] require.NoError(t, err) l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, nil, nil) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher) diff --git a/op-node/rollup/derive/engine_queue_test.go b/op-node/rollup/derive/engine_queue_test.go index ba02c1db5b..ddc92de2ae 100644 --- a/op-node/rollup/derive/engine_queue_test.go +++ b/op-node/rollup/derive/engine_queue_test.go @@ -968,6 +968,12 @@ func TestBlockBuildingRace(t *testing.T) { InfoBloom: types.Bloom{}, InfoExtra: []byte{}, }, 0) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + if cfg.KromaMPTTime == nil || !cfg.IsKromaMPT(refA1.Time) { + a1InfoTx, err = ToKromaDepositBytes(a1InfoTx) + require.NoError(t, err) + } + // [Kroma: END] require.NoError(t, err) payloadA1 := ð.ExecutionPayload{ diff --git a/op-node/rollup/derive/l1_block_info.go b/op-node/rollup/derive/l1_block_info.go index 3105a5658e..3f098e9305 100644 --- a/op-node/rollup/derive/l1_block_info.go +++ b/op-node/rollup/derive/l1_block_info.go @@ -352,10 +352,5 @@ func L1InfoDepositBytes(rollupCfg *rollup.Config, sysCfg eth.SystemConfig, seqNu if err != nil { return nil, fmt.Errorf("failed to encode L1 info tx: %w", err) } - // [Kroma: START] Use KromaDepositTx instead of DepositTx before MPT time - if !rollupCfg.IsKromaMPT(l2BlockTime) { - opaqueL1Tx, err = ToKromaDepositBytes(opaqueL1Tx) - } - // [Kroma: END] return opaqueL1Tx, nil } diff --git a/op-node/rollup/driver/sequencer_test.go b/op-node/rollup/driver/sequencer_test.go index 3697e2b352..6f9e8b8ae9 100644 --- a/op-node/rollup/driver/sequencer_test.go +++ b/op-node/rollup/driver/sequencer_test.go @@ -258,6 +258,12 @@ func TestSequencerChaosMonkey(t *testing.T) { } infoDep, err := derive.L1InfoDepositBytes(cfg, cfg.Genesis.SystemConfig, seqNr, l1Info, 0) require.NoError(t, err) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + if cfg.KromaMPTTime == nil || !cfg.IsKromaMPT(l2Parent.Time + cfg.BlockTime) { + infoDep, err = derive.ToKromaDepositBytes(infoDep) + require.NoError(t, err) + } + // [Kroma: END] testGasLimit := eth.Uint64Quantity(10_000_000) return ð.PayloadAttributes{