rpc: optimize tx index lookup (#810)
Closes: #760 Solution: - emit tx index to cosmos events - rpc side try to use the events, but fallback to heavier approach when fails. Update rpc/ethereum/namespaces/eth/api.go changelog fix lint fix TxIndexFromEvents fix Update rpc/ethereum/backend/backend.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
parent
e752d80e9f
commit
514785bd89
@ -65,6 +65,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
* (app) [tharsis#794](https://github.com/tharsis/ethermint/pull/794) Setup in-place store migrators.
|
* (app) [tharsis#794](https://github.com/tharsis/ethermint/pull/794) Setup in-place store migrators.
|
||||||
* (ci) [tharsis#784](https://github.com/tharsis/ethermint/pull/784) Enable automatic backport of PRs.
|
* (ci) [tharsis#784](https://github.com/tharsis/ethermint/pull/784) Enable automatic backport of PRs.
|
||||||
* (rpc) [tharsis#786](https://github.com/tharsis/ethermint/pull/786) Improve error message of `SendTransaction`/`SendRawTransaction` JSON-RPC APIs.
|
* (rpc) [tharsis#786](https://github.com/tharsis/ethermint/pull/786) Improve error message of `SendTransaction`/`SendRawTransaction` JSON-RPC APIs.
|
||||||
|
* (rpc) [tharsis#810](https://github.com/tharsis/ethermint/pull/810) Optimize tx index lookup in web3 rpc
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ type Backend interface {
|
|||||||
GetCoinbase() (sdk.AccAddress, error)
|
GetCoinbase() (sdk.AccAddress, error)
|
||||||
GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error)
|
GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error)
|
||||||
GetTxByEthHash(txHash common.Hash) (*tmrpctypes.ResultTx, error)
|
GetTxByEthHash(txHash common.Hash) (*tmrpctypes.ResultTx, error)
|
||||||
|
GetTxByTxIndex(height int64, txIndex uint) (*tmrpctypes.ResultTx, error)
|
||||||
EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error)
|
EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error)
|
||||||
BaseFee(height int64) (*big.Int, error)
|
BaseFee(height int64) (*big.Int, error)
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ type Backend interface {
|
|||||||
GetFilteredBlocks(from int64, to int64, filter [][]filters.BloomIV, filterAddresses bool) ([]int64, error)
|
GetFilteredBlocks(from int64, to int64, filter [][]filters.BloomIV, filterAddresses bool) ([]int64, error)
|
||||||
ChainConfig() *params.ChainConfig
|
ChainConfig() *params.ChainConfig
|
||||||
SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.TransactionArgs, error)
|
SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.TransactionArgs, error)
|
||||||
GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock) []*evmtypes.MsgEthereumTx
|
GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults) []*evmtypes.MsgEthereumTx
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Backend = (*EVMBackend)(nil)
|
var _ Backend = (*EVMBackend)(nil)
|
||||||
@ -688,27 +689,57 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
resBlock, err := e.clientCtx.Client.Block(e.ctx, &res.Height)
|
if res.TxResult.Code != 0 {
|
||||||
|
return nil, errors.New("invalid ethereum tx")
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := e.clientCtx.TxConfig.TxDecoder()(res.Tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tx.GetMsgs()) != 1 {
|
||||||
|
return nil, errors.New("invalid ethereum tx")
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, ok := tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("invalid ethereum tx")
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := e.clientCtx.Client.Block(e.ctx, &res.Height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.logger.Debug("block not found", "height", res.Height, "error", err.Error())
|
e.logger.Debug("block not found", "height", res.Height, "error", err.Error())
|
||||||
return nil, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var txIndex uint64
|
// Try to find txIndex from events
|
||||||
msgs := e.GetEthereumMsgsFromTendermintBlock(resBlock)
|
found := false
|
||||||
|
txIndex, err := types.TxIndexFromEvents(res.TxResult.Events)
|
||||||
for i := range msgs {
|
if err == nil {
|
||||||
if msgs[i].Hash == hexTx {
|
found = true
|
||||||
txIndex = uint64(i)
|
} else {
|
||||||
break
|
// Fallback to find tx index by iterating all valid eth transactions
|
||||||
|
blockRes, err := e.clientCtx.Client.BlockResults(e.ctx, &block.Block.Height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
msgs := e.GetEthereumMsgsFromTendermintBlock(block, blockRes)
|
||||||
|
for i := range msgs {
|
||||||
|
if msgs[i].Hash == hexTx {
|
||||||
|
txIndex = uint64(i)
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !found {
|
||||||
msg := msgs[txIndex]
|
return nil, errors.New("can't find index of ethereum tx")
|
||||||
|
}
|
||||||
|
|
||||||
return types.NewTransactionFromMsg(
|
return types.NewTransactionFromMsg(
|
||||||
msg,
|
msg,
|
||||||
common.BytesToHash(resBlock.Block.Hash()),
|
common.BytesToHash(block.BlockID.Hash.Bytes()),
|
||||||
uint64(res.Height),
|
uint64(res.Height),
|
||||||
txIndex,
|
txIndex,
|
||||||
e.chainID,
|
e.chainID,
|
||||||
@ -730,6 +761,22 @@ func (e *EVMBackend) GetTxByEthHash(hash common.Hash) (*tmrpctypes.ResultTx, err
|
|||||||
return resTxs.Txs[0], nil
|
return resTxs.Txs[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTxByTxIndex uses `/tx_query` to find transaction by tx index of valid ethereum txs
|
||||||
|
func (e *EVMBackend) GetTxByTxIndex(height int64, index uint) (*tmrpctypes.ResultTx, error) {
|
||||||
|
query := fmt.Sprintf("tx.height=%d AND %s.%s=%d",
|
||||||
|
height, evmtypes.TypeMsgEthereumTx,
|
||||||
|
evmtypes.AttributeKeyTxIndex, index,
|
||||||
|
)
|
||||||
|
resTxs, err := e.clientCtx.Client.TxSearch(e.ctx, query, false, nil, nil, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(resTxs.Txs) == 0 {
|
||||||
|
return nil, errors.Errorf("ethereum tx not found for block %d index %d", height, index)
|
||||||
|
}
|
||||||
|
return resTxs.Txs[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, error) {
|
func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, error) {
|
||||||
// Look up the wallet containing the requested signer
|
// Look up the wallet containing the requested signer
|
||||||
_, err := e.clientCtx.Keyring.KeyByAddress(sdk.AccAddress(args.From.Bytes()))
|
_, err := e.clientCtx.Keyring.KeyByAddress(sdk.AccAddress(args.From.Bytes()))
|
||||||
@ -1021,32 +1068,34 @@ BLOCKS:
|
|||||||
|
|
||||||
// GetEthereumMsgsFromTendermintBlock returns all real MsgEthereumTxs from a Tendermint block.
|
// GetEthereumMsgsFromTendermintBlock returns all real MsgEthereumTxs from a Tendermint block.
|
||||||
// It also ensures consistency over the correct txs indexes across RPC endpoints
|
// It also ensures consistency over the correct txs indexes across RPC endpoints
|
||||||
func (e *EVMBackend) GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock) []*evmtypes.MsgEthereumTx {
|
func (e *EVMBackend) GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults) []*evmtypes.MsgEthereumTx {
|
||||||
|
// nolint: prealloc
|
||||||
var result []*evmtypes.MsgEthereumTx
|
var result []*evmtypes.MsgEthereumTx
|
||||||
|
|
||||||
for _, tx := range block.Block.Txs {
|
txResults := blockRes.TxsResults
|
||||||
|
|
||||||
|
for i, tx := range block.Block.Txs {
|
||||||
|
// check tx exists on EVM by cross checking with blockResults
|
||||||
|
if txResults[i].Code != 0 {
|
||||||
|
e.logger.Debug("invalid tx result code", "cosmos-hash", hexutil.Encode(tx.Hash()))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
tx, err := e.clientCtx.TxConfig.TxDecoder()(tx)
|
tx, err := e.clientCtx.TxConfig.TxDecoder()(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.logger.Debug("failed to decode transaction in block", "height", block.Block.Height, "error", err.Error())
|
e.logger.Debug("failed to decode transaction in block", "height", block.Block.Height, "error", err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if len(tx.GetMsgs()) != 1 {
|
||||||
for _, msg := range tx.GetMsgs() {
|
continue
|
||||||
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
hash := ethMsg.AsTransaction().Hash()
|
|
||||||
// check tx exists on EVM and has the correct block height
|
|
||||||
ethTx, err := e.GetTxByEthHash(hash)
|
|
||||||
if err != nil || ethTx.Height != block.Block.Height {
|
|
||||||
e.logger.Debug("failed to query eth tx hash", "hash", hash.Hex())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result = append(result, ethMsg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ethMsg, ok := tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, ethMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
|
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
@ -309,18 +310,23 @@ func (e *PublicAPI) GetTransactionCount(address common.Address, blockNrOrHash rp
|
|||||||
func (e *PublicAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint {
|
func (e *PublicAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint {
|
||||||
e.logger.Debug("eth_getBlockTransactionCountByHash", "hash", hash.Hex())
|
e.logger.Debug("eth_getBlockTransactionCountByHash", "hash", hash.Hex())
|
||||||
|
|
||||||
resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes())
|
block, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.logger.Debug("block not found", "hash", hash.Hex(), "error", err.Error())
|
e.logger.Debug("block not found", "hash", hash.Hex(), "error", err.Error())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if resBlock.Block == nil {
|
if block.Block == nil {
|
||||||
e.logger.Debug("block not found", "hash", hash.Hex())
|
e.logger.Debug("block not found", "hash", hash.Hex())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
|
blockRes, err := e.clientCtx.Client.BlockResults(e.ctx, &block.Block.Height)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(block, blockRes)
|
||||||
n := hexutil.Uint(len(ethMsgs))
|
n := hexutil.Uint(len(ethMsgs))
|
||||||
return &n
|
return &n
|
||||||
}
|
}
|
||||||
@ -328,18 +334,23 @@ func (e *PublicAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Ui
|
|||||||
// GetBlockTransactionCountByNumber returns the number of transactions in the block identified by number.
|
// GetBlockTransactionCountByNumber returns the number of transactions in the block identified by number.
|
||||||
func (e *PublicAPI) GetBlockTransactionCountByNumber(blockNum rpctypes.BlockNumber) *hexutil.Uint {
|
func (e *PublicAPI) GetBlockTransactionCountByNumber(blockNum rpctypes.BlockNumber) *hexutil.Uint {
|
||||||
e.logger.Debug("eth_getBlockTransactionCountByNumber", "height", blockNum.Int64())
|
e.logger.Debug("eth_getBlockTransactionCountByNumber", "height", blockNum.Int64())
|
||||||
resBlock, err := e.clientCtx.Client.Block(e.ctx, blockNum.TmHeight())
|
block, err := e.clientCtx.Client.Block(e.ctx, blockNum.TmHeight())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.logger.Debug("block not found", "height", blockNum.Int64(), "error", err.Error())
|
e.logger.Debug("block not found", "height", blockNum.Int64(), "error", err.Error())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if resBlock.Block == nil {
|
if block.Block == nil {
|
||||||
e.logger.Debug("block not found", "height", blockNum.Int64())
|
e.logger.Debug("block not found", "height", blockNum.Int64())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
|
blockRes, err := e.clientCtx.Client.BlockResults(e.ctx, &block.Block.Height)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(block, blockRes)
|
||||||
n := hexutil.Uint(len(ethMsgs))
|
n := hexutil.Uint(len(ethMsgs))
|
||||||
return &n
|
return &n
|
||||||
}
|
}
|
||||||
@ -664,75 +675,86 @@ func (e *PublicAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransac
|
|||||||
return e.backend.GetTransactionByHash(hash)
|
return e.backend.GetTransactionByHash(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getTransactionByBlockAndIndex is the common code shared by `GetTransactionByBlockNumberAndIndex` and `GetTransactionByBlockHashAndIndex`.
|
||||||
|
func (e *PublicAPI) getTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
|
||||||
|
var msg *evmtypes.MsgEthereumTx
|
||||||
|
// try /tx_search first
|
||||||
|
res, err := e.backend.GetTxByTxIndex(block.Block.Height, uint(idx))
|
||||||
|
if err == nil {
|
||||||
|
tx, err := e.clientCtx.TxConfig.TxDecoder()(res.Tx)
|
||||||
|
if err != nil {
|
||||||
|
e.logger.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if len(tx.GetMsgs()) != 1 {
|
||||||
|
e.logger.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
var ok bool
|
||||||
|
msg, ok = tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||||
|
if !ok {
|
||||||
|
e.logger.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blockRes, err := e.clientCtx.Client.BlockResults(e.ctx, &block.Block.Height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
i := int(idx)
|
||||||
|
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(block, blockRes)
|
||||||
|
if i >= len(ethMsgs) {
|
||||||
|
e.logger.Debug("block txs index out of bound", "index", i)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ethMsgs[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpctypes.NewTransactionFromMsg(
|
||||||
|
msg,
|
||||||
|
common.BytesToHash(block.Block.Hash()),
|
||||||
|
uint64(block.Block.Height),
|
||||||
|
uint64(idx),
|
||||||
|
e.chainIDEpoch,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index.
|
// GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index.
|
||||||
func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
|
func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
|
||||||
e.logger.Debug("eth_getTransactionByBlockHashAndIndex", "hash", hash.Hex(), "index", idx)
|
e.logger.Debug("eth_getTransactionByBlockHashAndIndex", "hash", hash.Hex(), "index", idx)
|
||||||
|
|
||||||
resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes())
|
block, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.logger.Debug("block not found", "hash", hash.Hex(), "error", err.Error())
|
e.logger.Debug("block not found", "hash", hash.Hex(), "error", err.Error())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if resBlock.Block == nil {
|
if block.Block == nil {
|
||||||
e.logger.Debug("block not found", "hash", hash.Hex())
|
e.logger.Debug("block not found", "hash", hash.Hex())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
i := int(idx)
|
return e.getTransactionByBlockAndIndex(block, idx)
|
||||||
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
|
|
||||||
if i >= len(ethMsgs) {
|
|
||||||
e.logger.Debug("block txs index out of bound", "index", i)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := ethMsgs[i]
|
|
||||||
|
|
||||||
baseFee, err := e.backend.BaseFee(resBlock.Block.Height)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return rpctypes.NewTransactionFromMsg(
|
|
||||||
msg,
|
|
||||||
hash,
|
|
||||||
uint64(resBlock.Block.Height),
|
|
||||||
uint64(idx),
|
|
||||||
baseFee,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index.
|
// GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index.
|
||||||
func (e *PublicAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
|
func (e *PublicAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
|
||||||
e.logger.Debug("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx)
|
e.logger.Debug("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx)
|
||||||
|
|
||||||
resBlock, err := e.clientCtx.Client.Block(e.ctx, blockNum.TmHeight())
|
block, err := e.clientCtx.Client.Block(e.ctx, blockNum.TmHeight())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.logger.Debug("block not found", "height", blockNum.Int64(), "error", err.Error())
|
e.logger.Debug("block not found", "height", blockNum.Int64(), "error", err.Error())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if resBlock.Block == nil {
|
if block.Block == nil {
|
||||||
e.logger.Debug("block not found", "height", blockNum.Int64())
|
e.logger.Debug("block not found", "height", blockNum.Int64())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
i := int(idx)
|
return e.getTransactionByBlockAndIndex(block, idx)
|
||||||
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
|
|
||||||
if i >= len(ethMsgs) {
|
|
||||||
e.logger.Debug("block txs index out of bound", "index", i)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := ethMsgs[i]
|
|
||||||
|
|
||||||
return rpctypes.NewTransactionFromMsg(
|
|
||||||
msg,
|
|
||||||
common.BytesToHash(resBlock.Block.Hash()),
|
|
||||||
uint64(resBlock.Block.Height),
|
|
||||||
uint64(idx),
|
|
||||||
e.chainIDEpoch,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionReceipt returns the transaction receipt identified by hash.
|
// GetTransactionReceipt returns the transaction receipt identified by hash.
|
||||||
@ -801,7 +823,7 @@ func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interfac
|
|||||||
|
|
||||||
// get eth index based on block's txs
|
// get eth index based on block's txs
|
||||||
var txIndex uint64
|
var txIndex uint64
|
||||||
msgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
|
msgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock, blockRes)
|
||||||
for i := range msgs {
|
for i := range msgs {
|
||||||
if msgs[i].Hash == hexTx {
|
if msgs[i].Hash == hexTx {
|
||||||
txIndex = uint64(i)
|
txIndex = uint64(i)
|
||||||
|
@ -4,8 +4,10 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
@ -244,3 +246,26 @@ func BaseFeeFromEvents(events []abci.Event) *big.Int {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TxIndexFromEvents parses the tx index from cosmos events
|
||||||
|
func TxIndexFromEvents(events []abci.Event) (uint64, error) {
|
||||||
|
for _, event := range events {
|
||||||
|
if event.Type != evmtypes.EventTypeEthereumTx {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attr := range event.Attributes {
|
||||||
|
if bytes.Equal(attr.Key, []byte(evmtypes.AttributeKeyTxIndex)) {
|
||||||
|
result, err := strconv.ParseInt(string(attr.Value), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if result < 0 {
|
||||||
|
return 0, errors.New("negative tx index")
|
||||||
|
}
|
||||||
|
return uint64(result), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, errors.New("not found")
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
@ -26,6 +27,7 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t
|
|||||||
|
|
||||||
sender := msg.From
|
sender := msg.From
|
||||||
tx := msg.AsTransaction()
|
tx := msg.AsTransaction()
|
||||||
|
txIndex := k.GetTxIndexTransient()
|
||||||
|
|
||||||
response, err := k.ApplyTransaction(tx)
|
response, err := k.ApplyTransaction(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -36,6 +38,8 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t
|
|||||||
sdk.NewAttribute(sdk.AttributeKeyAmount, tx.Value().String()),
|
sdk.NewAttribute(sdk.AttributeKeyAmount, tx.Value().String()),
|
||||||
// add event for ethereum transaction hash format
|
// add event for ethereum transaction hash format
|
||||||
sdk.NewAttribute(types.AttributeKeyEthereumTxHash, response.Hash),
|
sdk.NewAttribute(types.AttributeKeyEthereumTxHash, response.Hash),
|
||||||
|
// add event for index of valid ethereum tx
|
||||||
|
sdk.NewAttribute(types.AttributeKeyTxIndex, strconv.FormatInt(int64(txIndex), 10)),
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ctx.TxBytes()) > 0 {
|
if len(ctx.TxBytes()) > 0 {
|
||||||
|
@ -15,6 +15,7 @@ The `x/evm` module emits the Cosmos SDK events after a state execution. The EVM
|
|||||||
| ethereum_tx | `"contract"` | `{hex_address}` |
|
| ethereum_tx | `"contract"` | `{hex_address}` |
|
||||||
| ethereum_tx | `"txHash"` | `{tendermint_hex_hash}` |
|
| ethereum_tx | `"txHash"` | `{tendermint_hex_hash}` |
|
||||||
| ethereum_tx | `"ethereumTxHash"` | `{hex_hash}` |
|
| ethereum_tx | `"ethereumTxHash"` | `{hex_hash}` |
|
||||||
|
| ethereum_tx | `"txIndex"` | `{tx_index}` |
|
||||||
| tx_log | `"txLog"` | `{tx_log}` |
|
| tx_log | `"txLog"` | `{tx_log}` |
|
||||||
| message | `"sender"` | `{eth_address}` |
|
| message | `"sender"` | `{eth_address}` |
|
||||||
| message | `"action"` | `"ethereum"` |
|
| message | `"action"` | `"ethereum"` |
|
||||||
|
@ -10,6 +10,7 @@ const (
|
|||||||
AttributeKeyRecipient = "recipient"
|
AttributeKeyRecipient = "recipient"
|
||||||
AttributeKeyTxHash = "txHash"
|
AttributeKeyTxHash = "txHash"
|
||||||
AttributeKeyEthereumTxHash = "ethereumTxHash"
|
AttributeKeyEthereumTxHash = "ethereumTxHash"
|
||||||
|
AttributeKeyTxIndex = "txIndex"
|
||||||
AttributeKeyTxType = "txType"
|
AttributeKeyTxType = "txType"
|
||||||
AttributeKeyTxLog = "txLog"
|
AttributeKeyTxLog = "txLog"
|
||||||
// tx failed in eth vm execution
|
// tx failed in eth vm execution
|
||||||
|
Loading…
Reference in New Issue
Block a user