From 4ec6c09c1de74a8bffbd1f491bffc89afc32b12f Mon Sep 17 00:00:00 2001 From: codchen Date: Mon, 20 May 2024 21:06:58 +0800 Subject: [PATCH] handle error cases --- app/ante.go | 1 - app/ante_test.go | 2 + app/app.go | 12 +++ x/evm/ante/error.go | 40 -------- x/evm/ante/error_test.go | 124 ------------------------- x/evm/keeper/deferred.go | 58 ++++++------ x/evm/keeper/keeper.go | 5 + x/evm/keeper/keeper_test.go | 51 +++++++++- x/evm/keeper/msg_server.go | 3 +- x/evm/module.go | 3 +- x/evm/module_test.go | 52 ++++++++++- x/evm/types/message_evm_transaction.go | 11 +++ 12 files changed, 153 insertions(+), 209 deletions(-) delete mode 100644 x/evm/ante/error.go delete mode 100644 x/evm/ante/error_test.go diff --git a/app/ante.go b/app/ante.go index b37d2218ab..9f42a7b313 100644 --- a/app/ante.go +++ b/app/ante.go @@ -124,7 +124,6 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk sdk.DefaultWrappedAnteDecorator(evmante.NewGasLimitDecorator(options.EVMKeeper)), } evmAnteHandler, evmAnteDepGenerator := sdk.ChainAnteDecorators(evmAnteDecorators...) - evmAnteHandler = evmante.NewAnteErrorHandler(evmAnteHandler, options.EVMKeeper).Handle router := evmante.NewEVMRouterDecorator(anteHandler, evmAnteHandler, anteDepGenerator, evmAnteDepGenerator) diff --git a/app/ante_test.go b/app/ante_test.go index 608b97deeb..7d2a7544ca 100644 --- a/app/ante_test.go +++ b/app/ante_test.go @@ -259,7 +259,9 @@ func TestEvmAnteErrorHandler(t *testing.T) { require.NotEqual(t, 0, res.Code) testkeeper.EVMTestApp.EvmKeeper.SetTxResults([]*abci.ExecTxResult{{ Code: res.Code, + Log: "nonce too high", }}) + testkeeper.EVMTestApp.EvmKeeper.SetMsgs([]*evmtypes.MsgEVMTransaction{req}) deferredInfo := testkeeper.EVMTestApp.EvmKeeper.GetEVMTxDeferredInfo(ctx) require.Equal(t, 1, len(deferredInfo)) require.Contains(t, deferredInfo[0].Error, "nonce too high") diff --git a/app/app.go b/app/app.go index e0deeb562f..208b844fe0 100644 --- a/app/app.go +++ b/app/app.go @@ -1529,6 +1529,7 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ beginBlockResp := app.BeginBlock(ctx, beginBlockReq) events = append(events, beginBlockResp.Events...) + evmTxs := make([]*evmtypes.MsgEVMTransaction, len(txs)) // nil for non-EVM txs txResults := make([]*abci.ExecTxResult, len(txs)) typedTxs := app.DecodeTransactionsConcurrently(ctx, txs) @@ -1538,6 +1539,11 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ prioritizedResults, ctx := app.ExecuteTxsConcurrently(ctx, prioritizedTxs, prioritizedTypedTxs, prioritizedIndices) for relativePrioritizedIndex, originalIndex := range prioritizedIndices { txResults[originalIndex] = prioritizedResults[relativePrioritizedIndex] + if emsg := evmtypes.GetEVMTransactionMessage(prioritizedTypedTxs[relativePrioritizedIndex]); emsg != nil { + evmTxs[originalIndex] = emsg + } else { + evmTxs[originalIndex] = nil + } } // Finalize all Bank Module Transfers here so that events are included for prioritiezd txs @@ -1550,8 +1556,14 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ otherResults, ctx := app.ExecuteTxsConcurrently(ctx, otherTxs, otherTypedTxs, otherIndices) for relativeOtherIndex, originalIndex := range otherIndices { txResults[originalIndex] = otherResults[relativeOtherIndex] + if emsg := evmtypes.GetEVMTransactionMessage(otherTypedTxs[relativeOtherIndex]); emsg != nil { + evmTxs[originalIndex] = emsg + } else { + evmTxs[originalIndex] = nil + } } app.EvmKeeper.SetTxResults(txResults) + app.EvmKeeper.SetMsgs(evmTxs) // Finalize all Bank Module Transfers here so that events are included lazyWriteEvents := app.BankKeeper.WriteDeferredBalances(ctx) diff --git a/x/evm/ante/error.go b/x/evm/ante/error.go deleted file mode 100644 index d1d7ab5a67..0000000000 --- a/x/evm/ante/error.go +++ /dev/null @@ -1,40 +0,0 @@ -package ante - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/sei-protocol/sei-chain/x/evm/keeper" - "github.com/sei-protocol/sei-chain/x/evm/types" - "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" -) - -type AnteErrorHandler struct { - wrapped sdk.AnteHandler - k *keeper.Keeper -} - -func NewAnteErrorHandler(wrapped sdk.AnteHandler, k *keeper.Keeper) *AnteErrorHandler { - return &AnteErrorHandler{wrapped: wrapped, k: k} -} - -// if there is any error in ante handler, record it in deferred info so that a receipt -// can be written for it in the EndBlock. (we can't directly write receipt here since -// we still need to return an error which will cause any write here to revert) -func (a *AnteErrorHandler) Handle(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { - newCtx, err = a.wrapped(ctx, tx, simulate) - if err != nil && !ctx.IsCheckTx() && !ctx.IsReCheckTx() && !simulate { - msg := types.MustGetEVMTransactionMessage(tx) - txData, unpackerr := types.UnpackTxData(msg.Data) - if unpackerr != nil { - ctx.Logger().Error(fmt.Sprintf("failed to unpack message data %X", msg.Data.Value)) - return - } - if _, ok := txData.(*ethtx.AssociateTx); ok { - return - } - a.k.AppendErrorToEvmTxDeferredInfo(ctx, ethtypes.NewTx(txData.AsEthereumData()).Hash(), err.Error()) - } - return -} diff --git a/x/evm/ante/error_test.go b/x/evm/ante/error_test.go deleted file mode 100644 index 8b312a64f3..0000000000 --- a/x/evm/ante/error_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package ante_test - -import ( - "errors" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/golang/protobuf/proto" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/abci/example/code" - abci "github.com/tendermint/tendermint/abci/types" - - testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/sei-protocol/sei-chain/x/evm/ante" - "github.com/sei-protocol/sei-chain/x/evm/keeper" - "github.com/sei-protocol/sei-chain/x/evm/types" - "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" -) - -type test struct { - name string - tx proto.Message - simulate bool - ctxSetup func(ctx sdk.Context) sdk.Context - handlerErr error - txResultCode uint32 - assertions func(t *testing.T, ctx sdk.Context, k *keeper.Keeper, err error) -} - -var testErr = errors.New("test") - -func TestAnteErrorHandler_Handle(t *testing.T) { - tests := []test{ - { - name: "no error should avoid appending an error", - txResultCode: abci.CodeTypeOK, - tx: ðtx.LegacyTx{}, - assertions: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper, err error) { - require.Len(t, k.GetEVMTxDeferredInfo(ctx), 0) - }, - }, - { - name: "error should append error to deferred info", - handlerErr: testErr, - txResultCode: code.CodeTypeUnknownError, - tx: ðtx.LegacyTx{}, - assertions: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper, err error) { - require.ErrorIs(t, err, testErr) - require.Len(t, k.GetEVMTxDeferredInfo(ctx), 1) - require.Equal(t, k.GetEVMTxDeferredInfo(ctx)[0].Error, testErr.Error()) - }, - }, - { - name: "error on check tx should avoid appending an error", - txResultCode: code.CodeTypeUnknownError, - ctxSetup: func(ctx sdk.Context) sdk.Context { - return ctx.WithIsCheckTx(true) - }, - handlerErr: testErr, - tx: ðtx.LegacyTx{}, - assertions: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper, err error) { - require.Len(t, k.GetEVMTxDeferredInfo(ctx), 0) - }, - }, - { - name: "error on re-check tx should avoid appending an error", - txResultCode: code.CodeTypeUnknownError, - ctxSetup: func(ctx sdk.Context) sdk.Context { - return ctx.WithIsReCheckTx(true) - }, - handlerErr: testErr, - tx: ðtx.LegacyTx{}, - assertions: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper, err error) { - require.Len(t, k.GetEVMTxDeferredInfo(ctx), 0) - }, - }, - { - name: "error with simulate should avoid appending an error", - txResultCode: code.CodeTypeUnknownError, - handlerErr: testErr, - simulate: true, - tx: ðtx.LegacyTx{}, - assertions: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper, err error) { - require.Len(t, k.GetEVMTxDeferredInfo(ctx), 0) - }, - }, - { - name: "error should not append error to deferred info if associate tx", - handlerErr: testErr, - txResultCode: code.CodeTypeUnknownError, - tx: ðtx.AssociateTx{}, - assertions: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper, err error) { - require.ErrorIs(t, err, testErr) - require.Len(t, k.GetEVMTxDeferredInfo(ctx), 0) - }, - }, - { - name: "error should not append error if data of tx cannot be decoded (not an evm message)", - handlerErr: testErr, - txResultCode: code.CodeTypeUnknownError, - tx: &sdk.GasInfo{ // not a valid eth tx, just a random proto so it will fail - GasWanted: 100, - GasUsed: 100, - }, - assertions: func(t *testing.T, ctx sdk.Context, k *keeper.Keeper, err error) { - require.Error(t, err, "failed to unpack message data") - require.Len(t, k.GetEVMTxDeferredInfo(ctx), 0) - }, - }, - } - for _, test := range tests { - k, ctx := testkeeper.MockEVMKeeper() - if test.ctxSetup != nil { - ctx = test.ctxSetup(ctx) - } - eh := ante.NewAnteErrorHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { - return ctx, test.handlerErr - }, k) - k.SetTxResults([]*abci.ExecTxResult{{Code: test.txResultCode}}) - msg, _ := types.NewMsgEVMTransaction(test.tx) - newCtx, err := eh.Handle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, test.simulate) - test.assertions(t, newCtx, k, err) - } -} diff --git a/x/evm/keeper/deferred.go b/x/evm/keeper/deferred.go index 035d79b269..af3d47cb65 100644 --- a/x/evm/keeper/deferred.go +++ b/x/evm/keeper/deferred.go @@ -13,23 +13,34 @@ import ( func (k *Keeper) GetEVMTxDeferredInfo(ctx sdk.Context) (res []*types.DeferredInfo) { store := prefix.NewStore(ctx.TransientStore(k.tStoreKey), types.DeferredInfoPrefix) - iter := store.Iterator(nil, nil) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - key := binary.BigEndian.Uint64(iter.Key()) - if key >= uint64(len(k.txResults)) { - ctx.Logger().Error(fmt.Sprintf("getting invalid tx index in EVM deferred info: %d, num of txs: %d", key, len(k.txResults))) + for txIdx, msg := range k.msgs { + if msg == nil { continue } - val := &types.DeferredInfo{} - if err := val.Unmarshal(iter.Value()); err != nil { - // unable to unmarshal deferred info is serious, because it could cause - // balance surplus to be mishandled and thus affect total supply - panic(err) - } - // cast is safe here because of the check above - if k.txResults[int(key)].Code == 0 || val.Error != "" { - res = append(res, val) + txRes := k.txResults[txIdx] + key := make([]byte, 8) + binary.BigEndian.PutUint64(key, uint64(txIdx)) + val := store.Get(key) + if val == nil { + // this means the transaction got reverted during execution, either in ante handler + // or due to a panic in msg server + etx, _ := msg.AsTransaction() + if txRes.Code == 0 { + ctx.Logger().Error(fmt.Sprintf("transaction %s has code 0 but no deferred info", etx.Hash().Hex())) + } + res = append(res, &types.DeferredInfo{ + TxIndex: uint32(txIdx), + TxHash: etx.Hash().Bytes(), + Error: txRes.Log, + }) + } else { + info := &types.DeferredInfo{} + if err := info.Unmarshal(val); err != nil { + // unable to unmarshal deferred info is serious, because it could cause + // balance surplus to be mishandled and thus affect total supply + panic(err) + } + res = append(res, info) } } return @@ -52,20 +63,3 @@ func (k *Keeper) AppendToEvmTxDeferredInfo(ctx sdk.Context, bloom ethtypes.Bloom } prefix.NewStore(ctx.TransientStore(k.tStoreKey), types.DeferredInfoPrefix).Set(key, bz) } - -func (k *Keeper) AppendErrorToEvmTxDeferredInfo(ctx sdk.Context, txHash common.Hash, err string) { - key := make([]byte, 8) - binary.BigEndian.PutUint64(key, uint64(ctx.TxIndex())) - val := &types.DeferredInfo{ - TxIndex: uint32(ctx.TxIndex()), - TxHash: txHash[:], - Error: err, - } - bz, e := val.Marshal() - if e != nil { - // unable to marshal deferred info is serious, because it could cause - // balance surplus to be mishandled and thus affect total supply - panic(e) - } - prefix.NewStore(ctx.TransientStore(k.tStoreKey), types.DeferredInfoPrefix).Set(key, bz) -} diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 680ecee1f1..06f2c4e368 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -45,6 +45,7 @@ type Keeper struct { Paramstore paramtypes.Subspace txResults []*abci.ExecTxResult + msgs []*types.MsgEVMTransaction bankKeeper bankkeeper.Keeper accountKeeper *authkeeper.AccountKeeper @@ -348,6 +349,10 @@ func (k *Keeper) SetTxResults(txResults []*abci.ExecTxResult) { k.txResults = txResults } +func (k *Keeper) SetMsgs(msgs []*types.MsgEVMTransaction) { + k.msgs = msgs +} + // Test use only func (k *Keeper) GetPendingTxs() map[string][]*PendingTx { return k.pendingTxs diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index d1e9584892..90de9a83b9 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -2,7 +2,9 @@ package keeper_test import ( "context" + "encoding/hex" "math" + "math/big" "sync" "testing" @@ -10,10 +12,14 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/testutil/keeper" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/config" evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/rand" @@ -199,18 +205,18 @@ func TestKeeper_CalculateNextNonce(t *testing.T) { } func TestDeferredInfo(t *testing.T) { - a := keeper.EVMTestApp + a := app.Setup(false, false) k := a.EvmKeeper ctx := a.GetContextForDeliverTx([]byte{}) ctx = ctx.WithTxIndex(1) k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{1, 2, 3}, common.Hash{4, 5, 6}, sdk.NewInt(1)) ctx = ctx.WithTxIndex(2) k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{7, 8}, common.Hash{9, 0}, sdk.NewInt(1)) - ctx = ctx.WithTxIndex(3) // should be ignored because txResult has non-zero code - k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{11, 12}, common.Hash{13, 14}, sdk.NewInt(1)) - k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}, {Code: 1}}) + k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}, {Code: 1, Log: "test error"}}) + msg := mockEVMTransactionMessage(t) + k.SetMsgs([]*types.MsgEVMTransaction{nil, {}, {}, msg}) infoList := k.GetEVMTxDeferredInfo(ctx) - require.Equal(t, 2, len(infoList)) + require.Equal(t, 3, len(infoList)) require.Equal(t, uint32(1), infoList[0].TxIndex) require.Equal(t, ethtypes.Bloom{1, 2, 3}, ethtypes.BytesToBloom(infoList[0].TxBloom)) require.Equal(t, common.Hash{4, 5, 6}, common.BytesToHash(infoList[0].TxHash)) @@ -219,9 +225,16 @@ func TestDeferredInfo(t *testing.T) { require.Equal(t, ethtypes.Bloom{7, 8}, ethtypes.BytesToBloom(infoList[1].TxBloom)) require.Equal(t, common.Hash{9, 0}, common.BytesToHash(infoList[1].TxHash)) require.Equal(t, sdk.NewInt(1), infoList[1].Surplus) + require.Equal(t, uint32(3), infoList[2].TxIndex) + require.Equal(t, ethtypes.Bloom{}, ethtypes.BytesToBloom(infoList[2].TxBloom)) + etx, _ := msg.AsTransaction() + require.Equal(t, etx.Hash(), common.BytesToHash(infoList[2].TxHash)) + require.Equal(t, "test error", infoList[2].Error) // test clear tx deferred info a.SetDeliverStateToCommit() a.Commit(context.Background()) // commit would clear transient stores + k.SetTxResults([]*abci.ExecTxResult{}) + k.SetMsgs([]*types.MsgEVMTransaction{}) infoList = k.GetEVMTxDeferredInfo(ctx) require.Empty(t, len(infoList)) } @@ -246,3 +259,31 @@ func TestAddPendingNonce(t *testing.T) { require.Equal(t, uint64(2), keyToNonce[tmtypes.TxKey{3}].Nonce) require.NotContains(t, keyToNonce, tmtypes.TxKey{2}) } + +func mockEVMTransactionMessage(t *testing.T) *types.MsgEVMTransaction { + k, ctx := testkeeper.MockEVMKeeper() + chainID := k.ChainID(ctx) + chainCfg := types.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + blockNum := big.NewInt(ctx.BlockHeight()) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + to := new(common.Address) + txData := ethtypes.DynamicFeeTx{ + Nonce: 1, + GasFeeCap: big.NewInt(10000000000000), + Gas: 1000, + To: to, + Value: big.NewInt(1000000000000000), + Data: []byte("abc"), + ChainID: chainID, + } + + signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + typedTx, err := ethtx.NewDynamicFeeTx(tx) + msg, err := types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + return msg +} diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 52929d7605..4ac0610139 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -66,7 +66,8 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT debug.PrintStack() ctx.Logger().Error(fmt.Sprintf("EVM PANIC: %s", pe)) telemetry.IncrCounter(1, types.ModuleName, "panics") - server.AppendErrorToEvmTxDeferredInfo(ctx, tx.Hash(), fmt.Sprintf("%s", pe)) + + panic(pe) } if err != nil { ctx.Logger().Error(fmt.Sprintf("Got EVM state transition error (not VM error): %s", err)) diff --git a/x/evm/module.go b/x/evm/module.go index b7f511bbae..ccf7935895 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -179,7 +179,8 @@ func (AppModule) ConsensusVersion() uint64 { return 7 } // BeginBlock executes all ABCI BeginBlock logic respective to the capability module. func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { - // clear tx responses from last block + // clear tx/tx responses from last block + am.keeper.SetMsgs([]*types.MsgEVMTransaction{}) am.keeper.SetTxResults([]*abci.ExecTxResult{}) // mock beacon root if replaying if am.keeper.EthReplayConfig.Enabled { diff --git a/x/evm/module_test.go b/x/evm/module_test.go index d63463838e..9044026adb 100644 --- a/x/evm/module_test.go +++ b/x/evm/module_test.go @@ -1,6 +1,8 @@ package evm_test import ( + "context" + "encoding/hex" "math" "math/big" "testing" @@ -12,10 +14,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/sei-protocol/sei-chain/app" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm" "github.com/sei-protocol/sei-chain/x/evm/state" "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -84,6 +89,7 @@ func TestABCI(t *testing.T) { require.Equal(t, sdk.ZeroInt(), surplus) k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(3), ethtypes.Bloom{}, common.Hash{3}, surplus) k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}, {Code: 0}}) + k.SetMsgs([]*types.MsgEVMTransaction{nil, {}, nil, {}}) m.EndBlock(ctx, abci.RequestEndBlock{}) require.Equal(t, uint64(0), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), "usei").Amount.Uint64()) require.Equal(t, uint64(2), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName), "usei").Amount.Uint64()) @@ -99,16 +105,19 @@ func TestABCI(t *testing.T) { require.Equal(t, sdk.NewInt(1000000000000), surplus) k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(2), ethtypes.Bloom{}, common.Hash{2}, surplus) k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}}) + k.SetMsgs([]*types.MsgEVMTransaction{nil, nil, {}}) m.EndBlock(ctx, abci.RequestEndBlock{}) require.Equal(t, uint64(1), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), "usei").Amount.Uint64()) require.Equal(t, uint64(2), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName), "usei").Amount.Uint64()) // third block m.BeginBlock(ctx, abci.RequestBeginBlock{}) - k.AppendErrorToEvmTxDeferredInfo(ctx.WithTxIndex(0), common.Hash{1}, "test error") - k.SetTxResults([]*abci.ExecTxResult{{Code: 1}}) + msg := mockEVMTransactionMessage(t) + k.SetMsgs([]*types.MsgEVMTransaction{msg}) + k.SetTxResults([]*abci.ExecTxResult{{Code: 1, Log: "test error"}}) m.EndBlock(ctx, abci.RequestEndBlock{}) - receipt, err := k.GetReceipt(ctx, common.Hash{1}) + tx, _ := msg.AsTransaction() + receipt, err := k.GetReceipt(ctx, tx.Hash()) require.Nil(t, err) require.Equal(t, receipt.BlockNumber, uint64(ctx.BlockHeight())) require.Equal(t, receipt.VmError, "test error") @@ -132,6 +141,7 @@ func TestABCI(t *testing.T) { require.Nil(t, err) k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(2), ethtypes.Bloom{}, common.Hash{}, surplus) k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}}) + k.SetMsgs([]*types.MsgEVMTransaction{nil, nil, {}}) require.Equal(t, sdk.OneInt(), k.BankKeeper().SpendableCoins(ctx, coinbase).AmountOf("usei")) m.EndBlock(ctx, abci.RequestEndBlock{}) // should not crash require.Equal(t, sdk.OneInt(), k.BankKeeper().GetBalance(ctx, coinbase, "usei").Amount) @@ -139,8 +149,10 @@ func TestABCI(t *testing.T) { } func TestAnteSurplus(t *testing.T) { - k, ctx := testkeeper.MockEVMKeeper() - m := evm.NewAppModule(nil, k) + a := app.Setup(false, false) + k := a.EvmKeeper + ctx := a.GetContextForDeliverTx([]byte{}) + m := evm.NewAppModule(nil, &k) // first block m.BeginBlock(ctx, abci.RequestBeginBlock{}) k.AddAnteSurplus(ctx, common.BytesToHash([]byte("1234")), sdk.NewInt(1_000_000_000_001)) @@ -148,5 +160,35 @@ func TestAnteSurplus(t *testing.T) { require.Equal(t, uint64(1), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), "usei").Amount.Uint64()) require.Equal(t, uint64(1), k.BankKeeper().GetWeiBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName)).Uint64()) // ante surplus should be cleared + a.SetDeliverStateToCommit() + a.Commit(context.Background()) require.Equal(t, uint64(0), k.GetAnteSurplusSum(ctx).Uint64()) } + +func mockEVMTransactionMessage(t *testing.T) *types.MsgEVMTransaction { + k, ctx := testkeeper.MockEVMKeeper() + chainID := k.ChainID(ctx) + chainCfg := types.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + blockNum := big.NewInt(ctx.BlockHeight()) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + to := new(common.Address) + txData := ethtypes.DynamicFeeTx{ + Nonce: 1, + GasFeeCap: big.NewInt(10000000000000), + Gas: 1000, + To: to, + Value: big.NewInt(1000000000000000), + Data: []byte("abc"), + ChainID: chainID, + } + + signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + typedTx, err := ethtx.NewDynamicFeeTx(tx) + msg, err := types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + return msg +} diff --git a/x/evm/types/message_evm_transaction.go b/x/evm/types/message_evm_transaction.go index b68793830a..affcc37014 100644 --- a/x/evm/types/message_evm_transaction.go +++ b/x/evm/types/message_evm_transaction.go @@ -79,6 +79,17 @@ func MustGetEVMTransactionMessage(tx sdk.Tx) *MsgEVMTransaction { return msg } +func GetEVMTransactionMessage(tx sdk.Tx) *MsgEVMTransaction { + if len(tx.GetMsgs()) != 1 { + return nil + } + msg, ok := tx.GetMsgs()[0].(*MsgEVMTransaction) + if !ok { + return nil + } + return msg +} + func (res *MsgEVMTransactionResponse) DecorateSdkResult(sdkRes *sdk.Result) { if res == nil { return