diff --git a/go.mod b/go.mod index a542b58915..d2a7cfc008 100644 --- a/go.mod +++ b/go.mod @@ -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 v1.101308.3-0.20241129080356-056a5b4d3639 +replace github.com/ethereum/go-ethereum v1.13.8 => github.com/kroma-network/go-ethereum v1.101308.3-0.20241205054106-fd7e291968d6 diff --git a/go.sum b/go.sum index 192d0b9318..df4c25cfb7 100644 --- a/go.sum +++ b/go.sum @@ -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 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/go-ethereum v1.101308.3-0.20241205054106-fd7e291968d6 h1:psD31rxeK1/94Uu3G1BpUlOYCOFzCtC4qGxqytfMWWo= +github.com/kroma-network/go-ethereum v1.101308.3-0.20241205054106-fd7e291968d6/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/op-e2e/actions/ecotone_fork_test.go b/op-e2e/actions/ecotone_fork_test.go index 58ff227e4c..8ae1bd4053 100644 --- a/op-e2e/actions/ecotone_fork_test.go +++ b/op-e2e/actions/ecotone_fork_test.go @@ -91,6 +91,15 @@ func TestEcotoneNetworkUpgradeTransactions(gt *testing.T) { // See [derive.EcotoneNetworkUpgradeTransactions] require.Equal(t, 7, len(transactions)) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + for i, otx := range transactions { + if otx.Type() == types.DepositTxType { + transactions[i], err = otx.ToKromaDepositTx() + require.NoError(t, err) + } + } + // [Kroma: END] + l1Info, err := derive.L1BlockInfoFromBytes(sd.RollupCfg, latestBlock.Time(), transactions[0].Data()) require.NoError(t, err) require.Equal(t, derive.L1InfoBedrockLen, len(transactions[0].Data())) diff --git a/op-e2e/actions/l2_engine_test.go b/op-e2e/actions/l2_engine_test.go index 62b9c7464f..3bc47f9610 100644 --- a/op-e2e/actions/l2_engine_test.go +++ b/op-e2e/actions/l2_engine_test.go @@ -5,8 +5,6 @@ import ( "math/big" "testing" - "github.com/ethereum-optimism/optimism/op-service/client/l2/engineapi" - "github.com/ethereum-optimism/optimism/op-service/client/l2/engineapi/test" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" @@ -20,6 +18,8 @@ import ( "github.com/stretchr/testify/require" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + "github.com/ethereum-optimism/optimism/op-service/client/l2/engineapi" + "github.com/ethereum-optimism/optimism/op-service/client/l2/engineapi/test" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/testlog" @@ -46,7 +46,7 @@ func TestL2EngineAPI(gt *testing.T) { chainA, _ := core.GenerateChain(sd.L2Cfg.Config, genesisBlock, consensus, db, 1, func(i int, gen *core.BlockGen) { gen.SetCoinbase(common.Address{'A'}) }) - payloadA, err := eth.BlockAsPayload(chainA[0], sd.RollupCfg.CanyonTime) + payloadA, err := eth.BlockAsPayload(chainA[0], sd.RollupCfg.CanyonTime, sd.RollupCfg.KromaMPTTime) require.NoError(t, err) // apply the payload @@ -69,7 +69,7 @@ func TestL2EngineAPI(gt *testing.T) { chainB, _ := core.GenerateChain(sd.L2Cfg.Config, genesisBlock, consensus, db, 1, func(i int, gen *core.BlockGen) { gen.SetCoinbase(common.Address{'B'}) }) - payloadB, err := eth.BlockAsPayload(chainB[0], sd.RollupCfg.CanyonTime) + payloadB, err := eth.BlockAsPayload(chainB[0], sd.RollupCfg.CanyonTime, sd.RollupCfg.KromaMPTTime) require.NoError(t, err) // apply the payload diff --git a/op-e2e/actions/l2_verifier.go b/op-e2e/actions/l2_verifier.go index e920add79d..31e92d3e15 100644 --- a/op-e2e/actions/l2_verifier.go +++ b/op-e2e/actions/l2_verifier.go @@ -280,6 +280,17 @@ func (s *L2Verifier) ActL2PipelineFull(t Testing) { // ActL2UnsafeGossipReceive creates an action that can receive an unsafe execution payload, like gossipsub func (s *L2Verifier) ActL2UnsafeGossipReceive(payload *eth.ExecutionPayloadEnvelope) Action { return func(t Testing) { + // [Kroma: START] Use KromaDepositTx instead of DepositTx + for i, otx := range payload.ExecutionPayload.Transactions { + if otx[0] != types.DepositTxType { + continue + } + var err error + txBytes, err := derive.ToKromaDepositBytes(otx) + require.NoError(t, err) + payload.ExecutionPayload.Transactions[i] = txBytes + } + // [Kroma: END] s.derivation.AddUnsafePayload(payload) } } @@ -287,6 +298,16 @@ func (s *L2Verifier) ActL2UnsafeGossipReceive(payload *eth.ExecutionPayloadEnvel // ActL2InsertUnsafePayload creates an action that can insert an unsafe execution payload func (s *L2Verifier) ActL2InsertUnsafePayload(payload *eth.ExecutionPayloadEnvelope) Action { return func(t Testing) { + // [Kroma: START] Use KromaDepositTx instead of DepositTx + for i, otx := range payload.ExecutionPayload.Transactions { + if otx[0] != types.DepositTxType { + continue + } + var err error + payload.ExecutionPayload.Transactions[i], err = derive.ToKromaDepositBytes(otx) + require.NoError(t, err) + } + // [Kroma: END] ref, err := derive.PayloadToBlockRef(s.rollupCfg, payload.ExecutionPayload) require.NoError(t, err) err = s.engine.InsertUnsafePayload(t.Ctx(), payload, ref) diff --git a/op-e2e/actions/user.go b/op-e2e/actions/user.go index 83c1e3c412..1444582bf0 100644 --- a/op-e2e/actions/user.go +++ b/op-e2e/actions/user.go @@ -381,6 +381,18 @@ func (s *CrossLayerUser) CheckDepositTx(t Testing, l1TxHash common.Hash, index i reconstructedDep, err := derive.UnmarshalDepositLogEvent(depositReceipt.Logs[index]) require.NoError(t, err, "Could not reconstruct L2 Deposit") l2Tx := types.NewTx(reconstructedDep) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + // If a receipt cannot be found using the DepositTx hash, it is converted to a KromaDepositTx. + _, err = s.L2.env.EthCl.TransactionReceipt(t.Ctx(), l2Tx.Hash()) + if err != nil { + if errors.Is(err, ethereum.NotFound) { + l2Tx, err = l2Tx.ToKromaDepositTx() + require.NoError(t, err, "failed to convert DepositTx to KromaDepositTx") + } else { + require.Fail(t, "failed to get deposit tx with reconstructed tx hash", err) + } + } + // [Kroma: END] s.L2.CheckReceipt(t, l2Success, l2Tx.Hash()) } } diff --git a/op-e2e/bridge_test.go b/op-e2e/bridge_test.go index e73915ba05..f582f1996c 100644 --- a/op-e2e/bridge_test.go +++ b/op-e2e/bridge_test.go @@ -98,7 +98,11 @@ func TestERC20BridgeDeposits(t *testing.T) { depositTx, err := derive.UnmarshalDepositLogEvent(&depositEvent.Raw) require.NoError(t, err) - _, err = wait.ForReceiptOK(context.Background(), l2Client, types.NewTx(depositTx).Hash()) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + kromaDepTx, err := types.NewTx(depositTx).ToKromaDepositTx() + require.NoError(t, err) + _, err = wait.ForReceiptOK(context.Background(), l2Client, kromaDepTx.Hash()) + // [Kroma: END] require.NoError(t, err) // Ensure that the deposit went through diff --git a/op-e2e/op_geth.go b/op-e2e/op_geth.go index c9db7a4682..744ffe7455 100644 --- a/op-e2e/op_geth.go +++ b/op-e2e/op_geth.go @@ -111,7 +111,7 @@ func NewOpGeth(t *testing.T, ctx context.Context, cfg *SystemConfig) (*OpGeth, e l2Client, err := ethclient.Dial(selectEndpoint(node)) require.Nil(t, err) - genesisPayload, err := eth.BlockAsPayload(l2GenesisBlock, cfg.DeployConfig.CanyonTime(l2GenesisBlock.Time())) + genesisPayload, err := eth.BlockAsPayload(l2GenesisBlock, cfg.DeployConfig.CanyonTime(l2GenesisBlock.Time()), cfg.DeployConfig.KromaMPTTime(l2GenesisBlock.Time())) require.Nil(t, err) return &OpGeth{ @@ -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 188c1bb7f8..e9ab4f2e4f 100644 --- a/op-e2e/op_geth_test.go +++ b/op-e2e/op_geth_test.go @@ -87,14 +87,16 @@ func TestInvalidDepositInFCU(t *testing.T) { require.Equal(t, 0, balance.Cmp(common.Big0)) badDepositTx := types.NewTx(&types.DepositTx{ - From: fromAddr, - To: &fromAddr, // send it to ourselves - Value: big.NewInt(params.Ether), - Gas: 25000, - /* [Kroma: START] + From: fromAddr, + To: &fromAddr, // send it to ourselves + Value: big.NewInt(params.Ether), + Gas: 25000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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. @@ -259,14 +261,16 @@ func TestPreregolith(t *testing.T) { // Simple transfer deposit tx depositTx := types.NewTx(&types.DepositTx{ - From: fromAddr, - To: &fromAddr, // send it to ourselves - Value: big.NewInt(params.Ether), - Gas: 25000, - /* [Kroma: START] + From: fromAddr, + To: &fromAddr, // send it to ourselves + Value: big.NewInt(params.Ether), + Gas: 25000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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) @@ -306,25 +310,29 @@ func TestPreregolith(t *testing.T) { fromAddr := cfg.Secrets.Addresses().Alice // Include a tx just to ensure Alice's nonce isn't 0 incrementNonceTx := types.NewTx(&types.DepositTx{ - From: fromAddr, - To: &fromAddr, - Value: big.NewInt(0), - Gas: 21_000, - /* [Kroma: START] + From: fromAddr, + To: &fromAddr, + Value: big.NewInt(0), + Gas: 21_000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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{ - From: fromAddr, - Value: big.NewInt(params.Ether), - Gas: 1000001, - Data: []byte{}, - /* [Kroma: START] + From: fromAddr, + Value: big.NewInt(params.Ether), + Gas: 1000001, + Data: []byte{}, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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) @@ -372,11 +380,13 @@ func TestPreregolith(t *testing.T) { To: &fromAddr, // send it to ourselves Value: big.NewInt(params.Ether), // SystemTx is assigned 1M gas limit - Gas: uint64(cfg.DeployConfig.L2GenesisBlockGasLimit) - 1_000_000, - /* [Kroma: START] + Gas: uint64(cfg.DeployConfig.L2GenesisBlockGasLimit) - 1_000_000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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 @@ -410,9 +420,7 @@ func TestPreregolith(t *testing.T) { rollupCfg := rollup.Config{} systemTx, err := derive.L1InfoDeposit(&rollupCfg, opGeth.SystemConfig, 1, opGeth.L1Head, 0) - /* [Kroma: START] systemTx.IsSystemTransaction = true - [Kroma: END] */ require.NoError(t, err) _, err = opGeth.AddL2Block(ctx, types.NewTx(systemTx)) @@ -458,14 +466,16 @@ func TestRegolith(t *testing.T) { // Simple transfer deposit tx depositTx := types.NewTx(&types.DepositTx{ - From: fromAddr, - To: &fromAddr, // send it to ourselves - Value: big.NewInt(params.Ether), - Gas: 25000, - /* [Kroma: START] + From: fromAddr, + To: &fromAddr, // send it to ourselves + Value: big.NewInt(params.Ether), + Gas: 25000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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) @@ -473,6 +483,10 @@ func TestRegolith(t *testing.T) { // L1Info tx should report actual gas used, not 0 or the tx gas limit infoTx, err := opGeth.L2Client.TransactionInBlock(ctx, envelope.ExecutionPayload.BlockHash, 0) require.NoError(t, err) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + infoTx, err = infoTx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] infoRcpt, err := opGeth.L2Client.TransactionReceipt(ctx, infoTx.Hash()) require.NoError(t, err) require.NotZero(t, infoRcpt.GasUsed) @@ -508,25 +522,29 @@ func TestRegolith(t *testing.T) { fromAddr := cfg.Secrets.Addresses().Alice // Include a tx just to ensure Alice's nonce isn't 0 incrementNonceTx := types.NewTx(&types.DepositTx{ - From: fromAddr, - To: &fromAddr, - Value: big.NewInt(0), - Gas: 21_000, - /* [Kroma: START] + From: fromAddr, + To: &fromAddr, + Value: big.NewInt(0), + Gas: 21_000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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{ - From: fromAddr, - Value: big.NewInt(params.Ether), - Gas: 1000001, - Data: []byte{}, - /* [Kroma: START] + From: fromAddr, + Value: big.NewInt(params.Ether), + Gas: 1000001, + Data: []byte{}, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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) @@ -581,11 +599,13 @@ func TestRegolith(t *testing.T) { To: &fromAddr, // send it to ourselves Value: big.NewInt(params.Ether), // SystemTx is assigned 1M gas limit - Gas: uint64(cfg.DeployConfig.L2GenesisBlockGasLimit) - 1_000_000, - /* [Kroma: START] + Gas: uint64(cfg.DeployConfig.L2GenesisBlockGasLimit) - 1_000_000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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 @@ -622,9 +642,7 @@ func TestRegolith(t *testing.T) { rollupCfg := rollup.Config{} systemTx, err := derive.L1InfoDeposit(&rollupCfg, opGeth.SystemConfig, 1, opGeth.L1Head, 0) - /* [Kroma: START] systemTx.IsSystemTransaction = true - [Kroma: END] */ require.NoError(t, err) _, err = opGeth.AddL2Block(ctx, types.NewTx(systemTx)) @@ -686,51 +704,59 @@ func TestRegolith(t *testing.T) { // Deposit TX to deploy a contract that lets us store an arbitrary value deployTx := types.NewTx(&types.DepositTx{ - From: fromAddr, - Value: common.Big0, - Data: deployData, - Gas: 1_000_000, - /* [Kroma: START] + From: fromAddr, + Value: common.Big0, + Data: deployData, + Gas: 1_000_000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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{ - From: fromAddr, - To: &storeContractAddr, - Value: common.Big0, - Data: []byte{0x06}, - Gas: 1_000_000, - /* [Kroma: START] + From: fromAddr, + To: &storeContractAddr, + Value: common.Big0, + Data: []byte{0x06}, + Gas: 1_000_000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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{ - From: fromAddr, - To: &storeContractAddr, - Value: common.Big0, - Data: []byte{0x00}, - Gas: 1_000_000, - /* [Kroma: START] + From: fromAddr, + To: &storeContractAddr, + Value: common.Big0, + Data: []byte{0x00}, + Gas: 1_000_000, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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 rezeroTx := types.NewTx(&types.DepositTx{ - From: fromAddr, - To: &storeContractAddr, - Value: common.Big0, - Data: []byte{0x00}, - Gas: 1_000_001, - /* [Kroma: START] + From: fromAddr, + To: &storeContractAddr, + Value: common.Big0, + Data: []byte{0x00}, + Gas: 1_000_001, IsSystemTransaction: false, - [Kroma: END] */ }) + // [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) @@ -815,10 +841,12 @@ func TestPreCanyon(t *testing.T) { Data: []byte{ byte(vm.PUSH0), }, - /* [Kroma: START] IsSystemTransaction: false, - [Kroma: END] */ }) + // [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) @@ -891,10 +919,12 @@ func TestCanyon(t *testing.T) { Data: []byte{ byte(vm.PUSH0), }, - /* [Kroma: START] IsSystemTransaction: false, - [Kroma: END] */ }) + // [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) @@ -961,10 +991,12 @@ func TestPreEcotone(t *testing.T) { byte(vm.PUSH2), byte(vm.TSTORE), }, - /* [Kroma: START] IsSystemTransaction: false, - [Kroma: END] */ }) + // [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) @@ -1044,10 +1076,12 @@ func TestEcotone(t *testing.T) { byte(vm.TSTORE), byte(vm.PUSH0), }, - /* [Kroma: START] IsSystemTransaction: false, - [Kroma: END] */ }) + // [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) @@ -1061,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-e2e/system_adminrpc_test.go b/op-e2e/system_adminrpc_test.go index e7c0af673b..dc28afeb7e 100644 --- a/op-e2e/system_adminrpc_test.go +++ b/op-e2e/system_adminrpc_test.go @@ -198,7 +198,7 @@ func TestPostUnsafePayload(t *testing.T) { blockNumberOne, err := l2Seq.BlockByNumber(ctx, big.NewInt(1)) require.NoError(t, err) - payload, err := eth.BlockAsPayload(blockNumberOne, sys.RollupConfig.CanyonTime) + payload, err := eth.BlockAsPayload(blockNumberOne, sys.RollupConfig.CanyonTime, sys.RollupConfig.KromaMPTTime) require.NoError(t, err) err = rollupClient.PostUnsafePayload(ctx, ð.ExecutionPayloadEnvelope{ExecutionPayload: payload}) require.NoError(t, err) @@ -207,7 +207,7 @@ func TestPostUnsafePayload(t *testing.T) { // Test validation blockNumberTwo, err := l2Seq.BlockByNumber(ctx, big.NewInt(2)) require.NoError(t, err) - payload, err = eth.BlockAsPayload(blockNumberTwo, sys.RollupConfig.CanyonTime) + payload, err = eth.BlockAsPayload(blockNumberTwo, sys.RollupConfig.CanyonTime, sys.RollupConfig.KromaMPTTime) require.NoError(t, err) payload.BlockHash = common.Hash{0xaa} err = rollupClient.PostUnsafePayload(ctx, ð.ExecutionPayloadEnvelope{ExecutionPayload: payload}) diff --git a/op-e2e/system_tob_test.go b/op-e2e/system_tob_test.go index f3a57bb12c..6e97efe870 100644 --- a/op-e2e/system_tob_test.go +++ b/op-e2e/system_tob_test.go @@ -139,13 +139,14 @@ func TestL2SequencerRPCDepositTx(t *testing.T) { // Create a deposit tx to send over RPC. tx := types.NewTx(&types.DepositTx{ - SourceHash: common.Hash{}, - From: crypto.PubkeyToAddress(txSigningKey.PublicKey), - To: &common.Address{0xff, 0xff}, - Mint: big.NewInt(1000), - Value: big.NewInt(1000), - Gas: 0, - Data: nil, + SourceHash: common.Hash{}, + From: crypto.PubkeyToAddress(txSigningKey.PublicKey), + To: &common.Address{0xff, 0xff}, + Mint: big.NewInt(1000), + Value: big.NewInt(1000), + Gas: 0, + IsSystemTransaction: false, + Data: nil, }) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) diff --git a/op-e2e/testdata/challenge_test_data.go b/op-e2e/testdata/challenge_test_data.go index f13ca750b9..70fec7f888 100644 --- a/op-e2e/testdata/challenge_test_data.go +++ b/op-e2e/testdata/challenge_test_data.go @@ -167,7 +167,7 @@ func SetPrevOutputWithProofResponse(o *eth.OutputWithProofResponse) error { } toAddr := common.HexToAddress("0x4200000000000000000000000000000000000002") o.PublicInputProof.NextTransactions = types.Transactions{ - types.NewTx(&types.DepositTx{ + types.NewTx(&types.KromaDepositTx{ SourceHash: common.HexToHash("0x81e84a0b340571d1b0ef61008afa413d4dc9b50884003177f02294cb961b7503"), From: common.HexToAddress("0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001"), To: &toAddr, @@ -259,7 +259,7 @@ func SetTargetOutputWithProofResponse(o *eth.OutputWithProofResponse) error { } toAddr := common.HexToAddress("0x4200000000000000000000000000000000000002") o.PublicInputProof.NextTransactions = types.Transactions{ - types.NewTx(&types.DepositTx{ + types.NewTx(&types.KromaDepositTx{ SourceHash: common.HexToHash("0x40bcbd870b6c68f66e727762654cf39e1491b20be579a13d231a6a6d21f204ce"), From: common.HexToAddress("0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001"), To: &toAddr, diff --git a/op-e2e/tx_helper.go b/op-e2e/tx_helper.go index fd7c7eed46..8f9f573cdf 100644 --- a/op-e2e/tx_helper.go +++ b/op-e2e/tx_helper.go @@ -3,10 +3,12 @@ package op_e2e import ( "context" "crypto/ecdsa" + "errors" "math/big" "testing" "time" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -50,6 +52,19 @@ func SendDepositTx(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l reconstructedDep, err := derive.UnmarshalDepositLogEvent(l1Receipt.Logs[0]) require.NoError(t, err, "Could not reconstruct L2 Deposit") tx = types.NewTx(reconstructedDep) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + // If a receipt cannot be found using the DepositTx hash, it is converted to a KromaDepositTx. + _, err = l2Client.TransactionReceipt(ctx, tx.Hash()) + if err != nil { + if errors.Is(err, ethereum.NotFound) { + tx, err = tx.ToKromaDepositTx() + require.NoError(t, err, "failed to convert DepositTx to KromaDepositTx") + } else { + require.Fail(t, "failed to get deposit tx with reconstructed tx hash", err) + } + } + require.NoError(t, err) + // [Kroma: END] l2Receipt, err := wait.ForReceipt(ctx, l2Client, tx.Hash(), l2Opts.ExpectedStatus) require.NoError(t, err, "Waiting for deposit tx on L2") return l2Receipt diff --git a/op-node/rollup/derive/attributes.go b/op-node/rollup/derive/attributes.go index 19cc47a000..0150ab0569 100644 --- a/op-node/rollup/derive/attributes.go +++ b/op-node/rollup/derive/attributes.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/kroma-network/kroma/kroma-bindings/predeploys" ) // L1ReceiptsFetcher fetches L1 header info and receipts for the payload attributes derivation (the info tx and deposits) @@ -117,6 +118,24 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex txs = append(txs, depositTxs...) txs = append(txs, upgradeTxs...) + // [Kroma: START] + // In Kroma, the IsSystemTransaction field was deleted from DepositTx. + // After transitioning to MPT, we bring back the IsSystemTransaction field for compatibility with OP. + // Therefore, before MPT time, use KromaDepositTx struct to create deposit transactions without that field. + if !ba.rollupCfg.IsKromaMPT(nextL2Time) { + for i, otx := range txs { + if otx[0] != types.DepositTxType { + continue + } + tx, err := ToKromaDepositBytes(otx) + if err != nil { + return nil, NewCriticalError(fmt.Errorf("failed to convert deposit tx to KromaDepositTx: %w", err)) + } + txs[i] = tx + } + } + // [Kroma: END] + var withdrawals *types.Withdrawals if ba.rollupCfg.IsCanyon(nextL2Time) { withdrawals = &types.Withdrawals{} @@ -130,10 +149,17 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex } } + // [Kroma: START] + suggestedFeeRecipient := common.Address{} + if ba.rollupCfg.IsKromaMPT(nextL2Time) { + suggestedFeeRecipient = predeploys.ProtocolVaultAddr + } + // [Kroma: END] + return ð.PayloadAttributes{ Timestamp: hexutil.Uint64(nextL2Time), PrevRandao: eth.Bytes32(l1Info.MixDigest()), - SuggestedFeeRecipient: common.Address{}, + SuggestedFeeRecipient: suggestedFeeRecipient, Transactions: txs, NoTxPool: true, GasLimit: (*eth.Uint64Quantity)(&sysConfig.GasLimit), @@ -141,3 +167,18 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex ParentBeaconBlockRoot: parentBeaconRoot, }, nil } + +func ToKromaDepositBytes(input hexutil.Bytes) (hexutil.Bytes, error) { + if input[0] != types.DepositTxType { + return nil, fmt.Errorf("unexpected transaction type: %d", input[0]) + } + var tx types.Transaction + if err := tx.UnmarshalBinary(input); err != nil { + return nil, fmt.Errorf("failed to decode deposit tx: %w", err) + } + kromaDepTx, err := tx.ToKromaDepositTx() + if err != nil { + return nil, fmt.Errorf("failed to convert deposit tx to KromaDepositTx: %w", err) + } + return kromaDepTx.MarshalBinary() +} diff --git a/op-node/rollup/derive/attributes_queue_test.go b/op-node/rollup/derive/attributes_queue_test.go index 8257a5485d..c742d98358 100644 --- a/op-node/rollup/derive/attributes_queue_test.go +++ b/op-node/rollup/derive/attributes_queue_test.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testutils" + "github.com/kroma-network/kroma/kroma-bindings/predeploys" ) // TestAttributesQueue checks that it properly uses the PreparePayloadAttributes function @@ -32,11 +33,6 @@ func TestAttributesQueue(t *testing.T) { rng := rand.New(rand.NewSource(1234)) l1Info := testutils.RandomBlockInfo(rng) - l1Fetcher := &testutils.MockL1Source{} - defer l1Fetcher.AssertExpectations(t) - - l1Fetcher.ExpectInfoByHash(l1Info.InfoHash, l1Info, nil) - safeHead := testutils.RandomL2BlockRef(rng) safeHead.L1Origin = l1Info.ID() safeHead.Time = l1Info.InfoTime @@ -64,26 +60,49 @@ func TestAttributesQueue(t *testing.T) { ValidatorRewardScalar: [32]byte{}, } - l2Fetcher := &testutils.MockL2Client{} - l2Fetcher.ExpectSystemConfigByL2Hash(safeHead.Hash, parentL1Cfg, nil) - - rollupCfg := rollup.Config{} - l1InfoTx, err := L1InfoDepositBytes(&rollupCfg, expectedL1Cfg, safeHead.SequenceNumber+1, l1Info, 0) - require.NoError(t, err) - attrs := eth.PayloadAttributes{ - Timestamp: eth.Uint64Quantity(safeHead.Time + cfg.BlockTime), - PrevRandao: eth.Bytes32(l1Info.InfoMixDigest), - SuggestedFeeRecipient: common.Address{}, - Transactions: []eth.Data{l1InfoTx, eth.Data("foobar"), eth.Data("example")}, - NoTxPool: true, - GasLimit: (*eth.Uint64Quantity)(&expectedL1Cfg.GasLimit), + testAttributes := func(l1InfoTx []byte, suggestedFeeRecipient common.Address) { + l1Fetcher := &testutils.MockL1Source{} + defer l1Fetcher.AssertExpectations(t) + l1Fetcher.ExpectInfoByHash(l1Info.InfoHash, l1Info, nil) + l2Fetcher := &testutils.MockL2Client{} + l2Fetcher.ExpectSystemConfigByL2Hash(safeHead.Hash, parentL1Cfg, nil) + + attrs := eth.PayloadAttributes{ + Timestamp: eth.Uint64Quantity(safeHead.Time + cfg.BlockTime), + PrevRandao: eth.Bytes32(l1Info.InfoMixDigest), + SuggestedFeeRecipient: suggestedFeeRecipient, + Transactions: []eth.Data{l1InfoTx, eth.Data("foobar"), eth.Data("example")}, + NoTxPool: true, + GasLimit: (*eth.Uint64Quantity)(&expectedL1Cfg.GasLimit), + } + attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l2Fetcher) + + aq := NewAttributesQueue(testlog.Logger(t, log.LevelError), cfg, attrBuilder, nil) + + actual, err := aq.createNextAttributes(context.Background(), &batch, safeHead) + + require.NoError(t, err) + require.Equal(t, attrs, *actual) } - attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l2Fetcher) - aq := NewAttributesQueue(testlog.Logger(t, log.LevelError), cfg, attrBuilder, nil) + t.Run("before kroma mpt time", func(st *testing.T) { + rollupCfg := rollup.Config{} + l1InfoTx, err := L1InfoDepositBytes(&rollupCfg, expectedL1Cfg, safeHead.SequenceNumber+1, l1Info, 0) + require.NoError(st, err) - actual, err := aq.createNextAttributes(context.Background(), &batch, safeHead) + kromaDepTx, err := ToKromaDepositBytes(l1InfoTx) + require.NoError(st, err) + testAttributes(kromaDepTx, common.Address{}) + }) - require.NoError(t, err) - require.Equal(t, attrs, *actual) + t.Run("after kroma mpt time", func(st *testing.T) { + zero := uint64(0) + cfg.KromaMPTTime = &zero + rollupCfg := rollup.Config{ + KromaMPTTime: &zero, + } + l1InfoTx, err := L1InfoDepositBytes(&rollupCfg, expectedL1Cfg, safeHead.SequenceNumber+1, l1Info, 0) + require.NoError(st, err) + testAttributes(l1InfoTx, predeploys.ProtocolVaultAddr) + }) } diff --git a/op-node/rollup/derive/attributes_test.go b/op-node/rollup/derive/attributes_test.go index db2b76a6de..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) @@ -153,7 +157,12 @@ func TestPreparePayloadAttributes(t *testing.T) { require.NoError(t, err) l2Txs := append(append(make([]eth.Data, 0), l1InfoTx), usedDepositTxs...) - + // [Kroma: START] Use KromaDepositTx instead of DepositTx + for i, otx := range l2Txs { + l2Txs[i], err = ToKromaDepositBytes(otx) + require.NoError(t, err) + } + // [Kroma: END] l1Fetcher.ExpectFetchReceipts(epoch.Hash, l1Info, receipts, nil) attrBuilder := NewFetchingAttributesBuilder(cfg, l1Fetcher, l1CfgFetcher) attrs, err := attrBuilder.PreparePayloadAttributes(context.Background(), l2Parent, epoch) @@ -180,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) @@ -236,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/deposit_log.go b/op-node/rollup/derive/deposit_log.go index 465a4d17ae..74fde28c59 100644 --- a/op-node/rollup/derive/deposit_log.go +++ b/op-node/rollup/derive/deposit_log.go @@ -81,9 +81,7 @@ func UnmarshalDepositLogEvent(ev *types.Log) (*types.DepositTx, error) { } dep.SourceHash = source.SourceHash() dep.From = from - /* [Kroma: START] dep.IsSystemTransaction = false - [Kroma: END] */ var err error switch version { diff --git a/op-node/rollup/derive/deposit_log_tob_test.go b/op-node/rollup/derive/deposit_log_tob_test.go index 21d838552f..c8d3b1dcf1 100644 --- a/op-node/rollup/derive/deposit_log_tob_test.go +++ b/op-node/rollup/derive/deposit_log_tob_test.go @@ -61,16 +61,14 @@ func fuzzReceipts(typeProvider *fuzz.Fuzzer, blockHash common.Hash, depositContr // Create our deposit transaction dep := &types.DepositTx{ - SourceHash: source.SourceHash(), - From: *fuzzedDepositInfo.FromAddr, - To: fuzzedDepositInfo.ToAddr, - Value: fuzzedDepositInfo.Value, - Gas: fuzzedDepositInfo.Gas, - Data: fuzzedDepositInfo.Data, - Mint: fuzzedDepositInfo.Mint, - /* [Kroma: START] + SourceHash: source.SourceHash(), + From: *fuzzedDepositInfo.FromAddr, + To: fuzzedDepositInfo.ToAddr, + Value: fuzzedDepositInfo.Value, + Gas: fuzzedDepositInfo.Gas, + Data: fuzzedDepositInfo.Data, + Mint: fuzzedDepositInfo.Mint, IsSystemTransaction: false, - [Kroma: END] */ } // Marshal our actual log event diff --git a/op-node/rollup/derive/ecotone_upgrade_transactions.go b/op-node/rollup/derive/ecotone_upgrade_transactions.go index 582035c65b..119a4abf84 100644 --- a/op-node/rollup/derive/ecotone_upgrade_transactions.go +++ b/op-node/rollup/derive/ecotone_upgrade_transactions.go @@ -53,8 +53,8 @@ func EcotoneNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { Data: l1BlockDeploymentBytecode, // [Kroma: START] Gas: 500_000, - // IsSystemTransaction: false, // [Kroma: END] + IsSystemTransaction: false, }).MarshalBinary() if err != nil { return nil, err @@ -63,16 +63,14 @@ func EcotoneNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { upgradeTxns = append(upgradeTxns, deployL1BlockTransaction) deployGasPriceOracle, err := types.NewTx(&types.DepositTx{ - SourceHash: deployGasPriceOracleSource.SourceHash(), - From: GasPriceOracleDeployerAddress, - To: nil, - Mint: big.NewInt(0), - Value: big.NewInt(0), - Gas: 1_000_000, - /* [Kroma: START] + SourceHash: deployGasPriceOracleSource.SourceHash(), + From: GasPriceOracleDeployerAddress, + To: nil, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 1_000_000, IsSystemTransaction: false, - [Kroma: END] */ - Data: gasPriceOracleDeploymentBytecode, + Data: gasPriceOracleDeploymentBytecode, }).MarshalBinary() if err != nil { return nil, err @@ -81,16 +79,14 @@ func EcotoneNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { upgradeTxns = append(upgradeTxns, deployGasPriceOracle) updateL1BlockProxy, err := types.NewTx(&types.DepositTx{ - SourceHash: updateL1BlockProxySource.SourceHash(), - From: common.Address{}, - To: &predeploys.L1BlockAddr, - Mint: big.NewInt(0), - Value: big.NewInt(0), - Gas: 50_000, - /* [Kroma: START] + SourceHash: updateL1BlockProxySource.SourceHash(), + From: common.Address{}, + To: &predeploys.L1BlockAddr, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 50_000, IsSystemTransaction: false, - [Kroma: END] */ - Data: upgradeToCalldata(newL1BlockAddress), + Data: upgradeToCalldata(newL1BlockAddress), }).MarshalBinary() if err != nil { return nil, err @@ -99,16 +95,14 @@ func EcotoneNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { upgradeTxns = append(upgradeTxns, updateL1BlockProxy) updateGasPriceOracleProxy, err := types.NewTx(&types.DepositTx{ - SourceHash: updateGasPriceOracleSource.SourceHash(), - From: common.Address{}, - To: &predeploys.GasPriceOracleAddr, - Mint: big.NewInt(0), - Value: big.NewInt(0), - Gas: 50_000, - /* [Kroma: START] + SourceHash: updateGasPriceOracleSource.SourceHash(), + From: common.Address{}, + To: &predeploys.GasPriceOracleAddr, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 50_000, IsSystemTransaction: false, - [Kroma: END] */ - Data: upgradeToCalldata(newGasPriceOracleAddress), + Data: upgradeToCalldata(newGasPriceOracleAddress), }).MarshalBinary() if err != nil { return nil, err @@ -117,16 +111,14 @@ func EcotoneNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { upgradeTxns = append(upgradeTxns, updateGasPriceOracleProxy) enableEcotone, err := types.NewTx(&types.DepositTx{ - SourceHash: enableEcotoneSource.SourceHash(), - From: L1InfoDepositerAddress, - To: &predeploys.GasPriceOracleAddr, - Mint: big.NewInt(0), - Value: big.NewInt(0), - Gas: 80_000, - /* [Kroma: START] + SourceHash: enableEcotoneSource.SourceHash(), + From: L1InfoDepositerAddress, + To: &predeploys.GasPriceOracleAddr, + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 80_000, IsSystemTransaction: false, - [Kroma: END] */ - Data: enableEcotoneInput, + Data: enableEcotoneInput, }).MarshalBinary() if err != nil { return nil, err @@ -134,16 +126,14 @@ func EcotoneNetworkUpgradeTransactions() ([]hexutil.Bytes, error) { upgradeTxns = append(upgradeTxns, enableEcotone) deployEIP4788, err := types.NewTx(&types.DepositTx{ - From: EIP4788From, - To: nil, // contract-deployment tx - Mint: big.NewInt(0), - Value: big.NewInt(0), - Gas: 0x3d090, // hex constant, as defined in EIP-4788 - Data: eip4788CreationData, - /* [Kroma: START] + From: EIP4788From, + To: nil, // contract-deployment tx + Mint: big.NewInt(0), + Value: big.NewInt(0), + Gas: 0x3d090, // hex constant, as defined in EIP-4788 + Data: eip4788CreationData, IsSystemTransaction: false, - [Kroma: END] */ - SourceHash: beaconRootsSource.SourceHash(), + SourceHash: beaconRootsSource.SourceHash(), }).MarshalBinary() if err != nil { return nil, err diff --git a/op-node/rollup/derive/engine_consolidate.go b/op-node/rollup/derive/engine_consolidate.go index 121a740325..65f97c70de 100644 --- a/op-node/rollup/derive/engine_consolidate.go +++ b/op-node/rollup/derive/engine_consolidate.go @@ -41,7 +41,18 @@ func AttributesMatchBlock(rollupCfg *rollup.Config, attrs *eth.PayloadAttributes return fmt.Errorf("transaction count does not match. expected: %d. got: %d", len(attrs.Transactions), len(block.Transactions)) } for i, otx := range attrs.Transactions { - if expect := block.Transactions[i]; !bytes.Equal(otx, expect) { + // [Kroma: START] + // DepositTx in the RPC response does not come as KromaDepositTx, so it is converted to KromaDepositTx. + expect := block.Transactions[i] + if expect[0] == types.DepositTxType && !rollupCfg.IsKromaMPT(uint64(attrs.Timestamp)) { + var err error + expect, err = ToKromaDepositBytes(expect) + if err != nil { + return err + } + } + // [Kroma: END] + if !bytes.Equal(otx, expect) { if i == 0 { logL1InfoTxns(rollupCfg, l, uint64(block.BlockNumber), uint64(block.Timestamp), otx, block.Transactions[i]) } diff --git a/op-node/rollup/derive/engine_queue.go b/op-node/rollup/derive/engine_queue.go index 4dd4bebec4..1e6ce5d569 100644 --- a/op-node/rollup/derive/engine_queue.go +++ b/op-node/rollup/derive/engine_queue.go @@ -99,7 +99,6 @@ type LocalEngineControl interface { // The safe head may advance by more than one block in a single update // The l1Block specified is the first L1 block that includes sufficient information to derive the new safe head type SafeHeadListener interface { - // Enabled reports if this safe head listener is actively using the posted data. This allows the engine queue to // optionally skip making calls that may be expensive to prepare. // Callbacks may still be made if Enabled returns false but are not guaranteed. 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 864826aaf3..3f098e9305 100644 --- a/op-node/rollup/derive/l1_block_info.go +++ b/op-node/rollup/derive/l1_block_info.go @@ -324,22 +324,18 @@ func L1InfoDeposit(rollupCfg *rollup.Config, sysCfg eth.SystemConfig, seqNumber // Set a very large gas limit with `IsSystemTransaction` to ensure // that the L1 Attributes Transaction does not run out of gas. out := &types.DepositTx{ - SourceHash: source.SourceHash(), - From: L1InfoDepositerAddress, - To: &L1BlockAddress, - Mint: nil, - Value: big.NewInt(0), - Gas: 150_000_000, - /* [Kroma: START] + SourceHash: source.SourceHash(), + From: L1InfoDepositerAddress, + To: &L1BlockAddress, + Mint: nil, + Value: big.NewInt(0), + Gas: 150_000_000, IsSystemTransaction: true, - [Kroma: END] */ - Data: data, + Data: data, } // With the regolith fork we disable the IsSystemTx functionality, and allocate real gas if rollupCfg.IsRegolith(l2BlockTime) { - /* [Kroma: START] out.IsSystemTransaction = false - [Kroma: END] */ out.Gas = RegolithSystemTxGas } return out, nil diff --git a/op-node/rollup/derive/l1_block_info_test.go b/op-node/rollup/derive/l1_block_info_test.go index ebfe974d26..4e8e1989b5 100644 --- a/op-node/rollup/derive/l1_block_info_test.go +++ b/op-node/rollup/derive/l1_block_info_test.go @@ -117,9 +117,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { } depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 0) require.NoError(t, err) - /* [Kroma: START] require.False(t, depTx.IsSystemTransaction) - [Kroma: END] */ require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) }) t.Run("ecotone", func(t *testing.T) { @@ -132,9 +130,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { } depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 1) require.NoError(t, err) - /* [Kroma: START] require.False(t, depTx.IsSystemTransaction) - [Kroma: END] */ require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) require.Equal(t, L1InfoEcotoneLen, len(depTx.Data)) }) @@ -149,9 +145,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { } depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 2) require.NoError(t, err) - /* [Kroma: START] require.False(t, depTx.IsSystemTransaction) - [Kroma: END] */ require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) require.Equal(t, L1InfoBedrockLen, len(depTx.Data)) }) @@ -166,9 +160,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { } depTx, err := L1InfoDeposit(&rollupCfg, randomL1Cfg(rng, info), randomSeqNr(rng), info, 0) require.NoError(t, err) - /* [Kroma: START] require.False(t, depTx.IsSystemTransaction) - [Kroma: END] */ require.Equal(t, depTx.Gas, uint64(RegolithSystemTxGas)) require.Equal(t, L1InfoEcotoneLen, len(depTx.Data)) }) 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{ diff --git a/op-service/client/l2/engineapi/l2_engine_api.go b/op-service/client/l2/engineapi/l2_engine_api.go index e17c42d720..703a41bce3 100644 --- a/op-service/client/l2/engineapi/l2_engine_api.go +++ b/op-service/client/l2/engineapi/l2_engine_api.go @@ -9,7 +9,6 @@ import ( "math/big" "time" - "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" @@ -20,6 +19,8 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" + + "github.com/ethereum-optimism/optimism/op-service/eth" ) type EngineBackend interface { @@ -316,7 +317,7 @@ func (ea *L2EngineAPI) getPayload(_ context.Context, payloadId eth.PayloadID) (* return nil, engine.UnknownPayload } - return eth.BlockAsPayloadEnv(bl, ea.config().CanyonTime) + return eth.BlockAsPayloadEnv(bl, ea.config().CanyonTime, ea.config().KromaMPTTime) } func (ea *L2EngineAPI) forkchoiceUpdated(_ context.Context, state *eth.ForkchoiceState, attr *eth.PayloadAttributes) (*eth.ForkchoiceUpdatedResult, error) { diff --git a/op-service/client/l2/engineapi/test/l2_engine_api_tests.go b/op-service/client/l2/engineapi/test/l2_engine_api_tests.go index 65925232d9..9ff2ac0976 100644 --- a/op-service/client/l2/engineapi/test/l2_engine_api_tests.go +++ b/op-service/client/l2/engineapi/test/l2_engine_api_tests.go @@ -38,6 +38,10 @@ func RunEngineAPITests(t *testing.T, createBackend func(t *testing.T) engineapi. txData, err := derive.L1InfoDeposit(rollupCfg, eth.SystemConfig{}, 1, eth.HeaderBlockInfo(genesis), 0) api.assert.NoError(err) tx := types.NewTx(txData) + // [Kroma: START] Use KromaDepositTx instead of DepositTx + tx, err = tx.ToKromaDepositTx() + require.NoError(t, err) + // [Kroma: END] block := api.addBlock(tx) api.assert.Equal(block.BlockHash, api.headHash(), "should create and import new block") imported := api.backend.GetBlockByHash(block.BlockHash) diff --git a/op-service/eth/types.go b/op-service/eth/types.go index 199139ef0b..50fa8d85b2 100644 --- a/op-service/eth/types.go +++ b/op-service/eth/types.go @@ -249,7 +249,7 @@ func (envelope *ExecutionPayloadEnvelope) CheckBlockHash() (actual common.Hash, return blockHash, blockHash == payload.BlockHash } -func BlockAsPayload(bl *types.Block, canyonForkTime *uint64) (*ExecutionPayload, error) { +func BlockAsPayload(bl *types.Block, canyonForkTime, mptForkTime *uint64) (*ExecutionPayload, error) { baseFee, overflow := uint256.FromBig(bl.BaseFee()) if overflow { return nil, fmt.Errorf("invalid base fee in block: %s", bl.BaseFee()) @@ -260,6 +260,20 @@ func BlockAsPayload(bl *types.Block, canyonForkTime *uint64) (*ExecutionPayload, if err != nil { return nil, fmt.Errorf("tx %d failed to marshal: %w", i, err) } + + // [Kroma: START] Use KromaDepositTx instead DepositTx + if tx.Type() == types.DepositTxType && (mptForkTime == nil || bl.Time() < *mptForkTime) { + kromaDepTx, err := tx.ToKromaDepositTx() + if err != nil { + return nil, fmt.Errorf("tx %d failed to convert to KromaDepositTx: %w", i, err) + } + otx, err = kromaDepTx.MarshalBinary() + if err != nil { + return nil, fmt.Errorf("tx %d failed to marshal: %w", i, err) + } + } + // [Kroma: END] + opaqueTxs[i] = otx } @@ -289,8 +303,8 @@ func BlockAsPayload(bl *types.Block, canyonForkTime *uint64) (*ExecutionPayload, return payload, nil } -func BlockAsPayloadEnv(bl *types.Block, canyonForkTime *uint64) (*ExecutionPayloadEnvelope, error) { - payload, err := BlockAsPayload(bl, canyonForkTime) +func BlockAsPayloadEnv(bl *types.Block, canyonForkTime, mptForkTime *uint64) (*ExecutionPayloadEnvelope, error) { + payload, err := BlockAsPayload(bl, canyonForkTime, mptForkTime) if err != nil { return nil, err } diff --git a/op-service/testutils/deposits.go b/op-service/testutils/deposits.go index ae24177cfc..dfe8d07f43 100644 --- a/op-service/testutils/deposits.go +++ b/op-service/testutils/deposits.go @@ -25,13 +25,14 @@ func GenerateDeposit(sourceHash common.Hash, rng *rand.Rand) *types.DepositTx { } dep := &types.DepositTx{ - SourceHash: sourceHash, - From: RandomAddress(rng), - To: to, - Value: RandomETH(rng, 200), - Gas: uint64(rng.Int63n(10 * 1e6)), // 10 M gas max - Data: data, - Mint: mint, + SourceHash: sourceHash, + From: RandomAddress(rng), + To: to, + Value: RandomETH(rng, 200), + Gas: uint64(rng.Int63n(10 * 1e6)), // 10 M gas max + Data: data, + IsSystemTransaction: false, + Mint: mint, } return dep } diff --git a/ops-devnet/docker-compose.yml b/ops-devnet/docker-compose.yml index 728871a89a..8816ea79a5 100644 --- a/ops-devnet/docker-compose.yml +++ b/ops-devnet/docker-compose.yml @@ -108,7 +108,7 @@ services: l2: pid: host # allow debugging - image: kromanetwork/geth:mpt-056a5b4d + image: kromanetwork/geth:mpt-fd7e2919 ports: - "9545:8545" - "9546:8546" @@ -128,7 +128,7 @@ services: l2-historical: pid: host # allow debugging - image: kromanetwork/geth:mpt-056a5b4d + image: kromanetwork/geth:mpt-fd7e2919 ports: - "9445:8545" - "9446:8546" diff --git a/packages/contracts/contracts/libraries/Encoding.sol b/packages/contracts/contracts/libraries/Encoding.sol index 033a378a49..94cacb59c6 100644 --- a/packages/contracts/contracts/libraries/Encoding.sol +++ b/packages/contracts/contracts/libraries/Encoding.sol @@ -11,18 +11,35 @@ library Encoding { /// @notice RLP encodes the L2 transaction that would be generated when a given deposit is sent /// to the L2 system. Useful for searching for a deposit in the L2 system. The /// transaction is prefixed with 0x7e to identify its EIP-2718 type. - /// @param _tx User deposit transaction to encode. + /// @param _tx User deposit transaction to encode. + /// @param _isKromaDepTx Whether the given transaction is a KromaDepositTx. /// @return RLP encoded L2 deposit transaction. - function encodeDepositTransaction(Types.UserDepositTransaction memory _tx) internal pure returns (bytes memory) { + function encodeDepositTransaction( + Types.UserDepositTransaction memory _tx, + bool _isKromaDepTx + ) internal pure returns (bytes memory) { bytes32 source = Hashing.hashDepositSource(_tx.l1BlockHash, _tx.logIndex); - bytes[] memory raw = new bytes[](7); - raw[0] = RLPWriter.writeBytes(abi.encodePacked(source)); - raw[1] = RLPWriter.writeAddress(_tx.from); - raw[2] = _tx.isCreation ? RLPWriter.writeBytes("") : RLPWriter.writeAddress(_tx.to); - raw[3] = RLPWriter.writeUint(_tx.mint); - raw[4] = RLPWriter.writeUint(_tx.value); - raw[5] = RLPWriter.writeUint(uint256(_tx.gasLimit)); - raw[6] = RLPWriter.writeBytes(_tx.data); + bytes[] memory raw; + if (_isKromaDepTx) { + raw = new bytes[](7); + raw[0] = RLPWriter.writeBytes(abi.encodePacked(source)); + raw[1] = RLPWriter.writeAddress(_tx.from); + raw[2] = _tx.isCreation ? RLPWriter.writeBytes("") : RLPWriter.writeAddress(_tx.to); + raw[3] = RLPWriter.writeUint(_tx.mint); + raw[4] = RLPWriter.writeUint(_tx.value); + raw[5] = RLPWriter.writeUint(uint256(_tx.gasLimit)); + raw[6] = RLPWriter.writeBytes(_tx.data); + } else { + raw = new bytes[](8); + raw[0] = RLPWriter.writeBytes(abi.encodePacked(source)); + raw[1] = RLPWriter.writeAddress(_tx.from); + raw[2] = _tx.isCreation ? RLPWriter.writeBytes("") : RLPWriter.writeAddress(_tx.to); + raw[3] = RLPWriter.writeUint(_tx.mint); + raw[4] = RLPWriter.writeUint(_tx.value); + raw[5] = RLPWriter.writeUint(uint256(_tx.gasLimit)); + raw[6] = RLPWriter.writeBool(false); + raw[7] = RLPWriter.writeBytes(_tx.data); + } return abi.encodePacked(uint8(0x7e), RLPWriter.writeList(raw)); } diff --git a/packages/contracts/contracts/libraries/Hashing.sol b/packages/contracts/contracts/libraries/Hashing.sol index 6a93b1e117..53a901b033 100644 --- a/packages/contracts/contracts/libraries/Hashing.sol +++ b/packages/contracts/contracts/libraries/Hashing.sol @@ -15,14 +15,16 @@ library Hashing { * given deposit is sent to the L2 system. Useful for searching for a deposit in the L2 * system. * - * @param _tx User deposit transaction to hash. + * @param _tx User deposit transaction to hash. + * @param _isKromaDepTx Whether the given transaction is a KromaDepositTx. * * @return Hash of the RLP encoded L2 deposit transaction. */ function hashDepositTransaction( - Types.UserDepositTransaction memory _tx + Types.UserDepositTransaction memory _tx, + bool _isKromaDepTx ) internal pure returns (bytes32) { - return keccak256(Encoding.encodeDepositTransaction(_tx)); + return keccak256(Encoding.encodeDepositTransaction(_tx, _isKromaDepTx)); } /** diff --git a/packages/contracts/contracts/test/Encoding.t.sol b/packages/contracts/contracts/test/Encoding.t.sol index c3a1b5c8ff..24e99a240a 100644 --- a/packages/contracts/contracts/test/Encoding.t.sol +++ b/packages/contracts/contracts/test/Encoding.t.sol @@ -56,6 +56,7 @@ contract Encoding_Test is CommonTest { assertEq(encoding, _encoding); } + // [Kroma: START] function testDiff_encodeDepositTransaction_succeeds( address _from, address _to, @@ -78,9 +79,19 @@ contract Encoding_Test is CommonTest { _logIndex ); - bytes memory txn = Encoding.encodeDepositTransaction(t); - bytes memory _txn = ffi.encodeDepositTransaction(t); + // assert DepositTx + bytes memory txn = Encoding.encodeDepositTransaction(t, false); + bytes memory _txn = ffi.encodeDepositTransaction(t, false); - assertEq(txn, _txn); + assertEq(txn, _txn, "failed to assert deposit tx"); + + // assert KromaDepositTx + { + bytes memory txn = Encoding.encodeDepositTransaction(t, true); + bytes memory _txn = ffi.encodeDepositTransaction(t, true); + + assertEq(txn, _txn, "failed to assert kroma deposit tx"); + } } + // [Kroma: END] } diff --git a/packages/contracts/contracts/test/Hashing.t.sol b/packages/contracts/contracts/test/Hashing.t.sol index 8155ddb6a6..a044dccd5e 100644 --- a/packages/contracts/contracts/test/Hashing.t.sol +++ b/packages/contracts/contracts/test/Hashing.t.sol @@ -92,7 +92,6 @@ contract Hashing_hashOutputRootProof_Test is CommonTest { ); } } -// [Kroma: END] contract Hashing_hashDepositTransaction_Test is CommonTest { /// @notice Tests that hashDepositTransaction returns the correct hash in a simple case. @@ -107,21 +106,29 @@ contract Hashing_hashDepositTransaction_Test is CommonTest { ) external { + Types.UserDepositTransaction memory userDeposit = Types.UserDepositTransaction( + _from, + _to, + false, // isCreate + _value, + _mint, + _gas, + _data, + bytes32(uint256(0)), + _logIndex + ); + + // assert DepositTx assertEq( - Hashing.hashDepositTransaction( - Types.UserDepositTransaction( - _from, - _to, - false, // isCreate - _value, - _mint, - _gas, - _data, - bytes32(uint256(0)), - _logIndex - ) - ), - ffi.hashDepositTransaction(_from, _to, _mint, _value, _gas, _data, _logIndex) + Hashing.hashDepositTransaction(userDeposit, false), + ffi.hashDepositTransaction(_from, _to, _mint, _value, _gas, _data, _logIndex, false) + ); + + // asset KromaDepositTx + assertEq( + Hashing.hashDepositTransaction(userDeposit, true), + ffi.hashDepositTransaction(_from, _to, _mint, _value, _gas, _data, _logIndex, true) ); } } +// [Kroma: END] diff --git a/packages/contracts/contracts/test/setup/FFIInterface.sol b/packages/contracts/contracts/test/setup/FFIInterface.sol index bcfc78f75f..c3b1d39cc7 100644 --- a/packages/contracts/contracts/test/setup/FFIInterface.sol +++ b/packages/contracts/contracts/test/setup/FFIInterface.sol @@ -118,7 +118,6 @@ contract FFIInterface { bytes memory result = vm.ffi(cmds); return abi.decode(result, (bytes32)); } - // [Kroma: END] function hashDepositTransaction( address _from, @@ -127,12 +126,13 @@ contract FFIInterface { uint256 _value, uint64 _gas, bytes memory _data, - uint64 _logIndex + uint64 _logIndex, + bool _isKromaDepTx ) external returns (bytes32) { - string[] memory cmds = new string[](11); + string[] memory cmds = new string[](12); cmds[0] = "scripts/go-ffi/go-ffi"; cmds[1] = "diff"; cmds[2] = "hashDepositTransaction"; @@ -144,13 +144,19 @@ contract FFIInterface { cmds[8] = vm.toString(_value); cmds[9] = vm.toString(_gas); cmds[10] = vm.toString(_data); + cmds[11] = vm.toString(_isKromaDepTx); bytes memory result = vm.ffi(cmds); return abi.decode(result, (bytes32)); } - function encodeDepositTransaction(Types.UserDepositTransaction calldata txn) external returns (bytes memory) { - string[] memory cmds = new string[](12); + function encodeDepositTransaction( + Types.UserDepositTransaction calldata txn, + bool isKromaDepTx + ) + external returns + (bytes memory) { + string[] memory cmds = new string[](13); cmds[0] = "scripts/go-ffi/go-ffi"; cmds[1] = "diff"; cmds[2] = "encodeDepositTransaction"; @@ -163,10 +169,12 @@ contract FFIInterface { cmds[9] = vm.toString(txn.data); cmds[10] = vm.toString(txn.l1BlockHash); cmds[11] = vm.toString(txn.logIndex); + cmds[12] = vm.toString(isKromaDepTx); bytes memory result = vm.ffi(cmds); return abi.decode(result, (bytes)); } + // [Kroma: END] function encodeCrossDomainMessage( uint256 _nonce, diff --git a/packages/contracts/scripts/go-ffi/differential-testing.go b/packages/contracts/scripts/go-ffi/differential-testing.go index 6e2bf03fa6..423b1a9ffc 100644 --- a/packages/contracts/scripts/go-ffi/differential-testing.go +++ b/packages/contracts/scripts/go-ffi/differential-testing.go @@ -19,6 +19,7 @@ import ( "github.com/kroma-network/kroma/kroma-bindings/predeploys" "github.com/kroma-network/kroma/kroma-chain-ops/crossdomain" + "github.com/kroma-network/kroma/op-node/rollup/derive" ) // [Kroma: START] @@ -180,6 +181,13 @@ func DiffTestUtils() { // RLP encode deposit transaction encoded, err := types.NewTx(&depositTx).MarshalBinary() checkErr(err, "Error encoding deposit transaction") + // [Kroma: START] + isKromaDepositTx := args[9] == "true" + if isKromaDepositTx { + encoded, err = derive.ToKromaDepositBytes(encoded) + checkErr(err, "Error converting deposit transaction to KromaDepositTx") + } + // [Kroma: END] // Hash encoded deposit transaction hash := crypto.Keccak256Hash(encoded) @@ -206,9 +214,17 @@ func DiffTestUtils() { checkOk(ok) depositTx := makeDepositTx(from, to, value, mint, gasLimit, isCreate, data, l1BlockHash, logIndex) - // RLP encode deposit transaction encoded, err := types.NewTx(&depositTx).MarshalBinary() + checkErr(err, "Error encoding deposit transaction") + // [Kroma: START] + isKromaDepositTx := args[10] == "true" + if isKromaDepositTx { + encoded, err = derive.ToKromaDepositBytes(encoded) + checkErr(err, "Error converting deposit transaction to KromaDepositTx") + } + // [Kroma: END] + checkErr(err, "Failed to RLP encode deposit transaction") // Pack rlp encoded deposit transaction packed, err := bytesArgs.Pack(&encoded) diff --git a/packages/contracts/scripts/go-ffi/utils.go b/packages/contracts/scripts/go-ffi/utils.go index ace626f6d4..8db10a4df0 100644 --- a/packages/contracts/scripts/go-ffi/utils.go +++ b/packages/contracts/scripts/go-ffi/utils.go @@ -117,14 +117,12 @@ func makeDepositTx( // Create deposit transaction depositTx := types.DepositTx{ - SourceHash: udp.SourceHash(), - From: from, - Value: value, - Gas: gasLimit.Uint64(), - /* [Kroma: START] + SourceHash: udp.SourceHash(), + From: from, + Value: value, + Gas: gasLimit.Uint64(), IsSystemTransaction: false, // This will never be a system transaction in the tests. - [Kroma: END] */ - Data: data, + Data: data, } // Fill optional fields