diff --git a/changelog.md b/changelog.md index 02fe0dacd0..ac1225b0c0 100644 --- a/changelog.md +++ b/changelog.md @@ -58,6 +58,7 @@ * [2266](https://github.com/zeta-chain/node/pull/2266) - try fixing E2E test `crosschain_swap` failure `btc transaction not signed` * [2294](https://github.com/zeta-chain/node/pull/2294) - add and fix existing ethermint rpc unit test * [2329](https://github.com/zeta-chain/node/pull/2329) - fix TODOs in rpc unit tests +* [2342](https://github.com/zeta-chain/node/pull/2342) - extend rpc unit tests with testing extension to include synthetic ethereum txs * [2299](https://github.com/zeta-chain/node/pull/2299) - add `zetae2e` command to deploy test contracts ### Fixes diff --git a/rpc/backend/backend_suite_test.go b/rpc/backend/backend_suite_test.go index 18a74edfd8..1abd882fd2 100644 --- a/rpc/backend/backend_suite_test.go +++ b/rpc/backend/backend_suite_test.go @@ -8,6 +8,7 @@ import ( "testing" dbm "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -35,6 +36,30 @@ type BackendTestSuite struct { signer keyring.Signer } +// testTx is a dummy implementation of cosmos Tx used for testing. +type testTx struct { +} + +func (tx testTx) GetMsgs() []sdk.Msg { return nil } +func (tx testTx) GetSigners() []sdk.AccAddress { return nil } + +func (tx testTx) ValidateBasic() error { return nil } +func (t testTx) ProtoMessage() { panic("not implemented") } +func (t testTx) Reset() { panic("not implemented") } + +func (t testTx) String() string { panic("not implemented") } + +func (t testTx) Bytes() []byte { panic("not implemented") } + +func (t testTx) VerifySignature(msg []byte, sig []byte) bool { panic("not implemented") } + +func (t testTx) Type() string { panic("not implemented") } + +var ( + _ sdk.Tx = (*testTx)(nil) + _ sdk.Msg = (*testTx)(nil) +) + func TestBackendTestSuite(t *testing.T) { suite.Run(t, new(BackendTestSuite)) } @@ -118,6 +143,34 @@ func (suite *BackendTestSuite) buildEthereumTx() (*evmtypes.MsgEthereumTx, []byt return msgEthereumTx, bz } +func (suite *BackendTestSuite) buildSyntheticTxResult(txHash string) ([]byte, abci.ResponseDeliverTx) { + testTx := &testTx{} + txBuilder := suite.backend.clientCtx.TxConfig.NewTxBuilder() + txBuilder.SetSignatures() + txBuilder.SetMsgs(testTx) + bz, _ := suite.backend.clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) + return bz, abci.ResponseDeliverTx{ + Code: 0, + Events: []abci.Event{ + {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ + {Key: "ethereumTxHash", Value: txHash}, + {Key: "txIndex", Value: "8888"}, + {Key: "amount", Value: "1000"}, + {Key: "txGasUsed", Value: "21000"}, + {Key: "txHash", Value: ""}, + {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, + }}, + { + Type: "message", Attributes: []abci.EventAttribute{ + {Key: "sender", Value: "0x735b14BB79463307AAcBED86DAf3322B1e6226aB"}, + {Key: "txType", Value: "88"}, + {Key: "txNonce", Value: "1"}, + }, + }, + }, + } +} + // buildFormattedBlock returns a formatted block for testing func (suite *BackendTestSuite) buildFormattedBlock( blockRes *tmrpctypes.ResultBlockResults, diff --git a/rpc/backend/blocks_test.go b/rpc/backend/blocks_test.go index 218680ebe5..bec50ff5a5 100644 --- a/rpc/backend/blocks_test.go +++ b/rpc/backend/blocks_test.go @@ -6,6 +6,7 @@ import ( sdkmath "cosmossdk.io/math" "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/bytes" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -19,6 +20,7 @@ import ( "github.com/zeta-chain/zetacore/rpc/backend/mocks" ethrpc "github.com/zeta-chain/zetacore/rpc/types" + "github.com/zeta-chain/zetacore/testutil/sample" ) func (suite *BackendTestSuite) TestBlockNumber() { @@ -140,7 +142,7 @@ func (suite *BackendTestSuite) TestGetBlockByNumber() { func(blockNum ethrpc.BlockNumber, baseFee sdkmath.Int, validator sdk.AccAddress, txBz []byte) { height := blockNum.Int64() client := suite.backend.clientCtx.Client.(*mocks.Client) - resBlock, _ = RegisterBlock(client, height, txBz) + resBlock, _ = RegisterBlock(client, height, []tmtypes.Tx{txBz}) RegisterBlockResultsError(client, blockNum.Int64()) }, true, @@ -157,7 +159,7 @@ func (suite *BackendTestSuite) TestGetBlockByNumber() { func(blockNum ethrpc.BlockNumber, baseFee sdkmath.Int, validator sdk.AccAddress, txBz []byte) { height := blockNum.Int64() client := suite.backend.clientCtx.Client.(*mocks.Client) - resBlock, _ = RegisterBlock(client, height, txBz) + resBlock, _ = RegisterBlock(client, height, []tmtypes.Tx{txBz}) blockRes, _ = RegisterBlockResults(client, blockNum.Int64()) RegisterConsensusParams(client, height) @@ -179,7 +181,7 @@ func (suite *BackendTestSuite) TestGetBlockByNumber() { func(blockNum ethrpc.BlockNumber, baseFee sdkmath.Int, validator sdk.AccAddress, txBz []byte) { height := blockNum.Int64() client := suite.backend.clientCtx.Client.(*mocks.Client) - resBlock, _ = RegisterBlock(client, height, txBz) + resBlock, _ = RegisterBlock(client, height, []tmtypes.Tx{txBz}) blockRes, _ = RegisterBlockResults(client, blockNum.Int64()) RegisterConsensusParams(client, height) @@ -497,7 +499,7 @@ func (suite *BackendTestSuite) TestGetBlockTransactionCountByNumber() { func(blockNum ethrpc.BlockNumber) { height := blockNum.Int64() client := suite.backend.clientCtx.Client.(*mocks.Client) - RegisterBlock(client, height, bz) + RegisterBlock(client, height, []tmtypes.Tx{bz}) RegisterBlockResults(client, height) }, hexutil.Uint(1), @@ -1268,7 +1270,7 @@ func (suite *BackendTestSuite) TestHeaderByNumber() { func(blockNum ethrpc.BlockNumber, baseFee sdkmath.Int) { height := blockNum.Int64() client := suite.backend.clientCtx.Client.(*mocks.Client) - expResultBlock, _ = RegisterBlock(client, height, bz) + expResultBlock, _ = RegisterBlock(client, height, []tmtypes.Tx{bz}) RegisterBlockResults(client, height) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) @@ -1471,7 +1473,7 @@ func (suite *BackendTestSuite) TestEthBlockByNumber() { func(blockNum ethrpc.BlockNumber) { height := blockNum.Int64() client := suite.backend.clientCtx.Client.(*mocks.Client) - RegisterBlock(client, height, bz) + RegisterBlock(client, height, []tmtypes.Tx{bz}) RegisterBlockResults(client, blockNum.Int64()) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) @@ -1613,3 +1615,108 @@ func (suite *BackendTestSuite) TestEthBlockFromTendermintBlock() { }) } } + +func (suite *BackendTestSuite) TestEthAndSyntheticMsgsFromTendermintBlock() { + // synthetic tx + hash := sample.Hash().Hex() + tx, txRes := suite.buildSyntheticTxResult(hash) + + // real tx + msgEthereumTx, _ := suite.buildEthereumTx() + realTx := suite.signAndEncodeEthTx(msgEthereumTx) + + suite.backend.indexer = nil + // block contains block real and synthetic tx + emptyBlock := tmtypes.MakeBlock(1, []tmtypes.Tx{realTx, tx}, nil, nil) + emptyBlock.ChainID = ChainID + blockHash := common.BigToHash(big.NewInt(1)).Bytes() + resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock, BlockID: tmtypes.BlockID{Hash: bytes.HexBytes(blockHash)}} + blockRes := &tmrpctypes.ResultBlockResults{ + Height: 1, + TxsResults: []*types.ResponseDeliverTx{{}, &txRes}, + } + + // both real and synthetic should be returned + msgs, additionals := suite.backend.EthMsgsFromTendermintBlock(resBlock, blockRes) + suite.Require().Equal(2, len(msgs)) + suite.Require().Equal(2, len(additionals)) + + suite.Require().Nil(additionals[0]) + suite.Require().NotNil(additionals[1]) + + suite.Require().Equal(msgEthereumTx.Hash, msgs[0].Hash) + suite.Require().Equal(hash, msgs[1].Hash) +} + +func (suite *BackendTestSuite) TestEthAndSyntheticEthBlockByNumber() { + // synthetic tx + hash := sample.Hash().Hex() + tx, txRes := suite.buildSyntheticTxResult(hash) + + // real tx + msgEthereumTx, _ := suite.buildEthereumTx() + realTx := suite.signAndEncodeEthTx(msgEthereumTx) + + suite.backend.indexer = nil + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + // block contains block real and synthetic tx + RegisterBlock(client, 1, []tmtypes.Tx{realTx, tx}) + RegisterBlockResultsWithTxResults(client, 1, []*types.ResponseDeliverTx{{}, &txRes}) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + + // only real should be returned + block, err := suite.backend.EthBlockByNumber(1) + suite.Require().NoError(err) + suite.Require().Equal(1, len(block.Transactions())) + suite.Require().Equal(msgEthereumTx.Hash, block.Transactions()[0].Hash().String()) +} + +func (suite *BackendTestSuite) TestEthAndSyntheticGetBlockByNumber() { + // synthetic tx + hash := sample.Hash().Hex() + tx, txRes := suite.buildSyntheticTxResult(hash) + + // real tx + msgEthereumTx, _ := suite.buildEthereumTx() + realTx := suite.signAndEncodeEthTx(msgEthereumTx) + + suite.backend.indexer = nil + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + // block contains block real and synthetic tx + RegisterBlock(client, 1, []tmtypes.Tx{realTx, tx}) + RegisterBlockResultsWithTxResults(client, 1, []*types.ResponseDeliverTx{{}, &txRes}) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + RegisterValidatorAccount(queryClient, sdk.AccAddress(common.Address{}.Bytes())) + RegisterConsensusParams(client, 1) + + // both real and synthetic should be returned + block, err := suite.backend.GetBlockByNumber(1, false) + suite.Require().NoError(err) + + transactions := block["transactions"].([]interface{}) + suite.Require().Equal(2, len(transactions)) + suite.Require().Equal(common.HexToHash(msgEthereumTx.Hash), transactions[0]) + suite.Require().Equal(common.HexToHash(hash), transactions[1]) + + // both real and synthetic should be returned + block, err = suite.backend.GetBlockByNumber(1, true) + suite.Require().NoError(err) + + transactions = block["transactions"].([]interface{}) + suite.Require().Equal(2, len(transactions)) + resRealTx := transactions[0].(*ethrpc.RPCTransaction) + suite.Require().Equal(common.HexToHash(msgEthereumTx.Hash), resRealTx.Hash) + resSyntheticTx := transactions[1].(*ethrpc.RPCTransaction) + suite.Require().Equal(common.HexToHash(hash), resSyntheticTx.Hash) + + suite.Require().Equal(hash, resSyntheticTx.Hash.Hex()) + suite.Require().Equal("0x735b14BB79463307AAcBED86DAf3322B1e6226aB", resSyntheticTx.From.Hex()) + suite.Require().Equal("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7", resSyntheticTx.To.Hex()) + suite.Require().Equal("0x58", resSyntheticTx.Type.String()) + suite.Require().Equal("0x1", resSyntheticTx.Nonce.String()) + suite.Require().Nil(resSyntheticTx.V) + suite.Require().Nil(resSyntheticTx.R) + suite.Require().Nil(resSyntheticTx.S) +} diff --git a/rpc/backend/call_tx_test.go b/rpc/backend/call_tx_test.go index e0c7158ceb..a30ef6a941 100644 --- a/rpc/backend/call_tx_test.go +++ b/rpc/backend/call_tx_test.go @@ -5,6 +5,7 @@ import ( "fmt" "math/big" + tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -400,7 +401,7 @@ func (suite *BackendTestSuite) TestDoCall() { func() { client := suite.backend.clientCtx.Client.(*mocks.Client) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) - RegisterBlock(client, 1, bz) + RegisterBlock(client, 1, []tmtypes.Tx{bz}) RegisterEthCallError( queryClient, &evmtypes.EthCallRequest{Args: argsBz, ChainId: suite.backend.chainID.Int64()}, @@ -416,7 +417,7 @@ func (suite *BackendTestSuite) TestDoCall() { func() { client := suite.backend.clientCtx.Client.(*mocks.Client) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) - RegisterBlock(client, 1, bz) + RegisterBlock(client, 1, []tmtypes.Tx{bz}) RegisterEthCall( queryClient, &evmtypes.EthCallRequest{Args: argsBz, ChainId: suite.backend.chainID.Int64()}, diff --git a/rpc/backend/client_test.go b/rpc/backend/client_test.go index c94c7cc0e0..952bc215b7 100644 --- a/rpc/backend/client_test.go +++ b/rpc/backend/client_test.go @@ -2,6 +2,7 @@ package backend import ( "context" + "math/big" "testing" abci "github.com/cometbft/cometbft/abci/types" @@ -38,6 +39,12 @@ func RegisterTxSearch(client *mocks.Client, query string, txBz []byte) { Return(&tmrpctypes.ResultTxSearch{Txs: resulTxs, TotalCount: 1}, nil) } +func RegisterTxSearchWithTxResult(client *mocks.Client, query string, txBz []byte, res abci.ResponseDeliverTx) { + resulTxs := []*tmrpctypes.ResultTx{{Tx: txBz, Height: 1, TxResult: res}} + client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), ""). + Return(&tmrpctypes.ResultTxSearch{Txs: resulTxs, TotalCount: 1}, nil) +} + func RegisterTxSearchEmpty(client *mocks.Client, query string) { client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), ""). Return(&tmrpctypes.ResultTxSearch{}, nil) @@ -94,36 +101,26 @@ func RegisterStatusError(client *mocks.Client) { } // Block -func RegisterBlockMultipleTxs( - client *mocks.Client, - height int64, - txs []types.Tx, -) (*tmrpctypes.ResultBlock, error) { - block := types.MakeBlock(height, txs, nil, nil) - block.ChainID = ChainID - resBlock := &tmrpctypes.ResultBlock{Block: block} - client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil) - return resBlock, nil -} - func RegisterBlock( client *mocks.Client, height int64, - tx []byte, + txs []types.Tx, ) (*tmrpctypes.ResultBlock, error) { // without tx - if tx == nil { + if len(txs) == 0 { emptyBlock := types.MakeBlock(height, []types.Tx{}, nil, nil) emptyBlock.ChainID = ChainID - resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock} + blockHash := common.BigToHash(big.NewInt(height)).Bytes() + resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock, BlockID: types.BlockID{Hash: bytes.HexBytes(blockHash)}} client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil) return resBlock, nil } // with tx - block := types.MakeBlock(height, []types.Tx{tx}, nil, nil) + block := types.MakeBlock(height, txs, nil, nil) block.ChainID = ChainID - resBlock := &tmrpctypes.ResultBlock{Block: block} + blockHash := common.BigToHash(big.NewInt(height)).Bytes() + resBlock := &tmrpctypes.ResultBlock{Block: block, BlockID: types.BlockID{Hash: bytes.HexBytes(blockHash)}} client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil) return resBlock, nil } @@ -154,7 +151,8 @@ func TestRegisterBlock(t *testing.T) { emptyBlock := types.MakeBlock(height, []types.Tx{}, nil, nil) emptyBlock.ChainID = ChainID - resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock} + blockHash := common.BigToHash(big.NewInt(height)).Bytes() + resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock, BlockID: types.BlockID{Hash: blockHash}} require.Equal(t, resBlock, res) require.NoError(t, err) } diff --git a/rpc/backend/evm_query_client_test.go b/rpc/backend/evm_query_client_test.go index 24b32b1328..de50ef7ca6 100644 --- a/rpc/backend/evm_query_client_test.go +++ b/rpc/backend/evm_query_client_test.go @@ -39,14 +39,23 @@ func RegisterTraceTransactionWithPredecessors( predecessors []*evmtypes.MsgEthereumTx, ) { data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d} - queryClient.On("TraceTx", rpc.ContextWithHeight(1), - &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1, Predecessors: predecessors, ChainId: 7001}). + queryClient.On( + "TraceTx", + rpc.ContextWithHeight(1), + &evmtypes.QueryTraceTxRequest{ + Msg: msgEthTx, + BlockHash: "0000000000000000000000000000000000000000000000000000000000000001", + BlockNumber: 1, + Predecessors: predecessors, + ChainId: 7001, + }, + ). Return(&evmtypes.QueryTraceTxResponse{Data: data}, nil) } func RegisterTraceTransaction(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx) { data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d} - queryClient.On("TraceTx", rpc.ContextWithHeight(1), &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1, Predecessors: []*evmtypes.MsgEthereumTx{}, ChainId: 7001}). + queryClient.On("TraceTx", rpc.ContextWithHeight(1), &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockHash: "0000000000000000000000000000000000000000000000000000000000000001", BlockNumber: 1, Predecessors: []*evmtypes.MsgEthereumTx{}, ChainId: 7001}). Return(&evmtypes.QueryTraceTxResponse{Data: data}, nil) } diff --git a/rpc/backend/tracing_test.go b/rpc/backend/tracing_test.go index feb6ca2c42..1abae1818b 100644 --- a/rpc/backend/tracing_test.go +++ b/rpc/backend/tracing_test.go @@ -117,7 +117,7 @@ func (suite *BackendTestSuite) TestTraceTransaction() { func() { queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) client := suite.backend.clientCtx.Client.(*mocks.Client) - RegisterBlockMultipleTxs(client, 1, []types.Tx{txBz, txBz2}) + RegisterBlock(client, 1, []types.Tx{txBz, txBz2}) RegisterTraceTransactionWithPredecessors( queryClient, msgEthereumTx2, @@ -195,7 +195,7 @@ func (suite *BackendTestSuite) TestTraceTransaction() { func() { queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) client := suite.backend.clientCtx.Client.(*mocks.Client) - RegisterBlock(client, 1, txBz) + RegisterBlock(client, 1, []types.Tx{txBz}) RegisterTraceTransaction(queryClient, msgEthereumTx) txResults := []*abci.ResponseDeliverTx{ { diff --git a/rpc/backend/tx_info_test.go b/rpc/backend/tx_info_test.go index 9827c6eff1..c76a26ead8 100644 --- a/rpc/backend/tx_info_test.go +++ b/rpc/backend/tx_info_test.go @@ -19,8 +19,149 @@ import ( "github.com/zeta-chain/zetacore/rpc/backend/mocks" rpctypes "github.com/zeta-chain/zetacore/rpc/types" + "github.com/zeta-chain/zetacore/testutil/sample" ) +func (suite *BackendTestSuite) TestGetSyntheticTransactionByHash() { + hash := sample.Hash().Hex() + _, txRes := suite.buildSyntheticTxResult(hash) + + suite.backend.indexer = nil + client := suite.backend.clientCtx.Client.(*mocks.Client) + query := fmt.Sprintf( + "%s.%s='%s'", + evmtypes.TypeMsgEthereumTx, + evmtypes.AttributeKeyEthereumTxHash, + common.HexToHash(hash).Hex(), + ) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + RegisterTxSearchWithTxResult(client, query, []byte{}, txRes) + RegisterBlock(client, 1, nil) + RegisterBlockResultsWithTxResults(client, 1, []*abci.ResponseDeliverTx{&txRes}) + + res, err := suite.backend.GetTransactionByHash(common.HexToHash(hash)) + suite.Require().NoError(err) + + // assert fields + suite.Require().Equal(hash, res.Hash.Hex()) + nonce, _ := hexutil.DecodeUint64(res.Nonce.String()) + suite.Require().Equal(uint64(1), nonce) + suite.Require().Equal(int64(1), res.BlockNumber.ToInt().Int64()) + suite.Require().Equal("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7", res.To.Hex()) + suite.Require().Equal("0x735b14BB79463307AAcBED86DAf3322B1e6226aB", res.From.Hex()) + txIndex, _ := hexutil.DecodeUint64(res.TransactionIndex.String()) + suite.Require().Equal(uint64(8888), txIndex) + txType, _ := hexutil.DecodeUint64(res.Type.String()) + suite.Require().Equal(uint64(88), txType) + suite.Require().Equal(int64(7001), res.ChainID.ToInt().Int64()) + suite.Require().Equal(int64(1000), res.Value.ToInt().Int64()) + suite.Require().Nil(res.V) + suite.Require().Nil(res.R) + suite.Require().Nil(res.S) +} + +func (suite *BackendTestSuite) TestGetSyntheticTransactionReceiptByHash() { + hash := sample.Hash().Hex() + _, txRes := suite.buildSyntheticTxResult(hash) + + suite.backend.indexer = nil + client := suite.backend.clientCtx.Client.(*mocks.Client) + query := fmt.Sprintf( + "%s.%s='%s'", + evmtypes.TypeMsgEthereumTx, + evmtypes.AttributeKeyEthereumTxHash, + common.HexToHash(hash).Hex(), + ) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + var header metadata.MD + RegisterParams(queryClient, &header, 1) + RegisterParamsWithoutHeader(queryClient, 1) + RegisterTxSearchWithTxResult(client, query, []byte{}, txRes) + RegisterBlock(client, 1, nil) + RegisterBlockResultsWithTxResults(client, 1, []*abci.ResponseDeliverTx{&txRes}) + + res, err := suite.backend.GetTransactionReceipt(common.HexToHash(hash)) + suite.Require().NoError(err) + + // assert fields + suite.Require().Equal(common.HexToHash(hash), res["transactionHash"]) + blockNumber, _ := hexutil.DecodeUint64(res["blockNumber"].(hexutil.Uint64).String()) + suite.Require().Equal(uint64(1), blockNumber) + toAddress := common.HexToAddress("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7") + fromAddress := common.HexToAddress("0x735b14BB79463307AAcBED86DAf3322B1e6226aB") + suite.Require().Equal(&toAddress, res["to"]) + suite.Require().Equal(fromAddress, res["from"]) + status, _ := hexutil.DecodeUint64(res["status"].(hexutil.Uint).String()) + suite.Require().Equal(uint64(1), status) + txType, _ := hexutil.DecodeUint64(res["type"].(hexutil.Uint).String()) + suite.Require().Equal(uint64(88), txType) + txIndex, _ := hexutil.DecodeUint64(res["transactionIndex"].(hexutil.Uint64).String()) + suite.Require().Equal(uint64(8888), txIndex) +} + +func (suite *BackendTestSuite) TestGetSyntheticTransactionByBlockNumberAndIndex() { + hash := sample.Hash().Hex() + tx, txRes := suite.buildSyntheticTxResult(hash) + + suite.backend.indexer = nil + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterBlock(client, 1, []types.Tx{tx}) + RegisterBlockResultsWithTxResults(client, 1, []*abci.ResponseDeliverTx{&txRes}) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + + res, err := suite.backend.GetTransactionByBlockNumberAndIndex(rpctypes.BlockNumber(1), 0) + suite.Require().NoError(err) + + // assert fields + suite.Require().Equal(hash, res.Hash.Hex()) + nonce, _ := hexutil.DecodeUint64(res.Nonce.String()) + suite.Require().Equal(uint64(1), nonce) + suite.Require().Equal("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7", res.To.Hex()) + suite.Require().Equal("0x735b14BB79463307AAcBED86DAf3322B1e6226aB", res.From.Hex()) + txType, _ := hexutil.DecodeUint64(res.Type.String()) + suite.Require().Equal(uint64(88), txType) + suite.Require().Equal(int64(7001), res.ChainID.ToInt().Int64()) + suite.Require().Equal(int64(1000), res.Value.ToInt().Int64()) + suite.Require().Nil(res.V) + suite.Require().Nil(res.R) + suite.Require().Nil(res.S) +} + +func (suite *BackendTestSuite) TestGetSyntheticTransactionByBlockNumberAndIndexWithRealTransaction() { + hash := sample.Hash().Hex() + tx, txRes := suite.buildSyntheticTxResult(hash) + msgEthereumTx, _ := suite.buildEthereumTx() + + realTx := suite.signAndEncodeEthTx(msgEthereumTx) + + suite.backend.indexer = nil + client := suite.backend.clientCtx.Client.(*mocks.Client) + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + // synthetic tx with real MsgEthereumTx + RegisterBlock(client, 1, []types.Tx{realTx, tx}) + RegisterBlockResultsWithTxResults(client, 1, []*abci.ResponseDeliverTx{{}, &txRes}) + RegisterBaseFee(queryClient, sdk.NewInt(1)) + + res, err := suite.backend.GetTransactionByBlockNumberAndIndex(rpctypes.BlockNumber(1), 1) + suite.Require().NoError(err) + + // assert fields + suite.Require().Equal(hash, res.Hash.Hex()) + nonce, _ := hexutil.DecodeUint64(res.Nonce.String()) + suite.Require().Equal(uint64(1), nonce) + suite.Require().Equal("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7", res.To.Hex()) + suite.Require().Equal("0x735b14BB79463307AAcBED86DAf3322B1e6226aB", res.From.Hex()) + txType, _ := hexutil.DecodeUint64(res.Type.String()) + suite.Require().Equal(uint64(88), txType) + suite.Require().Equal(int64(7001), res.ChainID.ToInt().Int64()) + suite.Require().Equal(int64(1000), res.Value.ToInt().Int64()) + suite.Require().Nil(res.V) + suite.Require().Nil(res.R) + suite.Require().Nil(res.S) +} + func (suite *BackendTestSuite) TestGetTransactionByHash() { msgEthereumTx, _ := suite.buildEthereumTx() txHash := msgEthereumTx.AsTransaction().Hash() @@ -45,8 +186,8 @@ func (suite *BackendTestSuite) TestGetTransactionByHash() { rpcTransaction, err := rpctypes.NewRPCTransaction( msgEthereumTx.AsTransaction(), - common.Hash{}, - 0, + common.HexToHash("0x1"), + 1, 0, big.NewInt(1), suite.backend.chainID, @@ -74,7 +215,7 @@ func (suite *BackendTestSuite) TestGetTransactionByHash() { "fail - Block Result error", func() { client := suite.backend.clientCtx.Client.(*mocks.Client) - RegisterBlock(client, 1, txBz) + RegisterBlock(client, 1, []types.Tx{txBz}) RegisterBlockResultsError(client, 1) }, msgEthereumTx, @@ -86,7 +227,7 @@ func (suite *BackendTestSuite) TestGetTransactionByHash() { func() { client := suite.backend.clientCtx.Client.(*mocks.Client) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) - RegisterBlock(client, 1, txBz) + RegisterBlock(client, 1, []types.Tx{txBz}) RegisterBlockResults(client, 1) RegisterBaseFeeError(queryClient) }, @@ -99,7 +240,7 @@ func (suite *BackendTestSuite) TestGetTransactionByHash() { func() { client := suite.backend.clientCtx.Client.(*mocks.Client) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) - RegisterBlock(client, 1, txBz) + RegisterBlock(client, 1, []types.Tx{txBz}) RegisterBlockResults(client, 1) RegisterBaseFee(queryClient, sdk.NewInt(1)) }, @@ -459,7 +600,7 @@ func (suite *BackendTestSuite) TestGetTransactionByBlockNumberAndIndex() { func() { client := suite.backend.clientCtx.Client.(*mocks.Client) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) - RegisterBlock(client, 1, bz) + RegisterBlock(client, 1, []types.Tx{bz}) RegisterBlockResults(client, 1) RegisterBaseFee(queryClient, sdk.NewInt(1)) }, @@ -592,7 +733,7 @@ func (suite *BackendTestSuite) TestGetTransactionReceipt() { client := suite.backend.clientCtx.Client.(*mocks.Client) RegisterParams(queryClient, &header, 1) RegisterParamsWithoutHeader(queryClient, 1) - RegisterBlock(client, 1, txBz) + RegisterBlock(client, 1, []types.Tx{txBz}) RegisterBlockResults(client, 1) }, msgEthereumTx, diff --git a/rpc/types/events.go b/rpc/types/events.go index 3839fb84df..4a265f2c6d 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -240,6 +240,8 @@ func ParseTxIndexerResult( Type: parsedTx.Type, Recipient: parsedTx.Recipient, Sender: parsedTx.Sender, + Data: parsedTx.Data, + Nonce: parsedTx.Nonce, }, nil } return ðermint.TxResult{ diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index 9a7ed00d5b..43bffb6e75 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -680,7 +680,7 @@ func (k Keeper) CallEVM( // value is the amount of wei to send; gaslimit is the custom gas limit, if nil EstimateGas is used // to bisect the correct gas limit (this may sometimes result in insufficient gas limit; not sure why) // -// noEthereumTxEvent flag is used to control if ethereum_tx eventsshould emitted +// noEthereumTxEvent flag is used to control if ethereum_tx events should be emitted // which will mean these txs are indexed and available in rpc methods // // returns (msg,err) the EVM execution result if there is any, even if error is non-nil due to contract reverts