Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

filter non eth txs in block rpc response #741

Merged
merged 17 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (evm, test) [tharsis#649](https://github.com/tharsis/ethermint/pull/649) Test DynamicFeeTx.
* (evm) [tharsis#702](https://github.com/tharsis/ethermint/pull/702) Fix panic in web3 RPC handlers
* (rpc) [tharsis#720](https://github.com/tharsis/ethermint/pull/720) Fix `debug_traceTransaction` failure
* (rpc) [tharsis#741](https://github.com/tharsis/ethermint/pull/741) Fix `eth_getBlockByNumberAndHash` return with non eth txs
* (rpc) [tharsis#743](https://github.com/tharsis/ethermint/pull/743) Fix debug JSON RPC handler crash on non-existing block

### Improvements
Expand Down
68 changes: 55 additions & 13 deletions rpc/ethereum/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type Backend interface {

ChainConfig() *params.ChainConfig
SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.TransactionArgs, error)
GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock) []*evmtypes.MsgEthereumTx
}

var _ Backend = (*EVMBackend)(nil)
Expand Down Expand Up @@ -370,6 +371,13 @@ func (e *EVMBackend) EthBlockFromTendermint(

tx := ethMsg.AsTransaction()

// check tx exists on EVM and it has the correct block height
ethTx, err := e.GetTxByEthHash(tx.Hash())
if err != nil || ethTx.Height != block.Height {
e.logger.Debug("failed to query eth tx", "hash", tx.Hash().Hex())
continue
}

if !fullTx {
hash := tx.Hash()
ethRPCTxs = append(ethRPCTxs, hash)
Expand Down Expand Up @@ -641,11 +649,12 @@ func (e *EVMBackend) GetCoinbase() (sdk.AccAddress, error) {
// GetTransactionByHash returns the Ethereum format transaction identified by Ethereum transaction hash
func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error) {
res, err := e.GetTxByEthHash(txHash)
hexTx := txHash.Hex()
if err != nil {
// try to find tx in mempool
txs, err := e.PendingTransactions()
if err != nil {
e.logger.Debug("tx not found", "hash", txHash.Hex(), "error", err.Error())
e.logger.Debug("tx not found", "hash", hexTx, "error", err.Error())
return nil, nil
}

Expand All @@ -656,7 +665,7 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac
continue
}

if msg.Hash == txHash.Hex() {
if msg.Hash == hexTx {
rpctx, err := types.NewTransactionFromMsg(
msg,
common.Hash{},
Expand All @@ -671,7 +680,7 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac
}
}

e.logger.Debug("tx not found", "hash", txHash.Hex())
e.logger.Debug("tx not found", "hash", hexTx)
return nil, nil
}

Expand All @@ -681,23 +690,23 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac
return nil, nil
}

tx, err := e.clientCtx.TxConfig.TxDecoder()(res.Tx)
if err != nil {
e.logger.Debug("decoding failed", "error", err.Error())
return nil, fmt.Errorf("failed to decode tx: %w", err)
}
var txIndex uint64
msgs := e.GetEthereumMsgsFromTendermintBlock(resBlock)

msg, err := evmtypes.UnwrapEthereumMsg(&tx)
if err != nil {
e.logger.Debug("invalid tx", "error", err.Error())
return nil, err
for i := range msgs {
if msgs[i].Hash == hexTx {
txIndex = uint64(i)
break
}
}

msg := msgs[txIndex]

return types.NewTransactionFromMsg(
msg,
common.BytesToHash(resBlock.Block.Hash()),
uint64(res.Height),
uint64(res.Index),
txIndex,
e.chainID,
)
}
Expand Down Expand Up @@ -1001,6 +1010,39 @@ BLOCKS:
return matchedBlocks, nil
}

// GetEthereumMsgsFromTendermintBlock returns all real MsgEthereumTxs from a Tendermint block.
// It also ensures consistency over the correct txs indexes across RPC endpoints
func (e *EVMBackend) GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock) []*evmtypes.MsgEthereumTx {
var result []*evmtypes.MsgEthereumTx

for _, tx := range block.Block.Txs {
tx, err := e.clientCtx.TxConfig.TxDecoder()(tx)
if err != nil {
e.logger.Debug("failed to decode transaction in block", "height", block.Block.Height, "error", err.Error())
continue
}

for _, msg := range tx.GetMsgs() {
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)
}
}

return result
}

// checkMatches revised the function from
// https://github.com/ethereum/go-ethereum/blob/401354976bb44f0ad4455ca1e0b5c0dc31d9a5f5/core/types/bloom9.go#L88
func checkMatches(bloom ethtypes.Bloom, filter []filters.BloomIV) bool {
Expand Down
59 changes: 26 additions & 33 deletions rpc/ethereum/namespaces/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,8 @@ func (e *PublicAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Ui
return nil
}

n := hexutil.Uint(len(resBlock.Block.Txs))
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
n := hexutil.Uint(len(ethMsgs))
return &n
}

Expand All @@ -333,7 +334,8 @@ func (e *PublicAPI) GetBlockTransactionCountByNumber(blockNum rpctypes.BlockNumb
return nil
}

n := hexutil.Uint(len(resBlock.Block.Txs))
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
n := hexutil.Uint(len(ethMsgs))
return &n
}

Expand Down Expand Up @@ -673,23 +675,13 @@ func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexu
}

i := int(idx)
if i >= len(resBlock.Block.Txs) {
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
if i >= len(ethMsgs) {
e.logger.Debug("block txs index out of bound", "index", i)
return nil, nil
}

txBz := resBlock.Block.Txs[i]
tx, err := e.clientCtx.TxConfig.TxDecoder()(txBz)
if err != nil {
e.logger.Debug("decoding failed", "error", err.Error())
return nil, fmt.Errorf("failed to decode tx: %w", err)
}

msg, err := evmtypes.UnwrapEthereumMsg(&tx)
if err != nil {
e.logger.Debug("invalid tx", "error", err.Error())
return nil, err
}
msg := ethMsgs[i]
fedekunze marked this conversation as resolved.
Show resolved Hide resolved

baseFee, err := e.backend.BaseFee(resBlock.Block.Height)
if err != nil {
Expand Down Expand Up @@ -721,23 +713,13 @@ func (e *PublicAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockN
}

i := int(idx)
if i >= len(resBlock.Block.Txs) {
ethMsgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
if i >= len(ethMsgs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L723 (txBz := resBlock.Block.Txs[i] ) is inconsistent with the L685. See comment about assuming the index corresponds to an ethereum tx

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 723-730 needs to be removed @crypto-facs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! If we agree this #741 (comment) is the right approach to handle index across the endpoints I will add the filter here too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok please remove

e.logger.Debug("block txs index out of bound", "index", i)
return nil, nil
}

txBz := resBlock.Block.Txs[i]
tx, err := e.clientCtx.TxConfig.TxDecoder()(txBz)
if err != nil {
e.logger.Debug("decoding failed", "error", err.Error())
return nil, fmt.Errorf("failed to decode tx: %w", err)
}

msg, err := evmtypes.UnwrapEthereumMsg(&tx)
if err != nil {
e.logger.Debug("invalid tx", "error", err.Error())
return nil, err
}
msg := ethMsgs[i]

return rpctypes.NewTransactionFromMsg(
msg,
Expand All @@ -750,11 +732,12 @@ func (e *PublicAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockN

// GetTransactionReceipt returns the transaction receipt identified by hash.
func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
e.logger.Debug("eth_getTransactionReceipt", "hash", hash.Hex())
hexTx := hash.Hex()
e.logger.Debug("eth_getTransactionReceipt", "hash", hexTx)

res, err := e.backend.GetTxByEthHash(hash)
if err != nil {
e.logger.Debug("tx not found", "hash", hash.Hex(), "error", err.Error())
e.logger.Debug("tx not found", "hash", hexTx, "error", err.Error())
return nil, nil
}

Expand Down Expand Up @@ -808,7 +791,17 @@ func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interfac

logs, err := e.backend.GetTransactionLogs(hash)
if err != nil {
e.logger.Debug("logs not found", "hash", hash.Hex(), "error", err.Error())
e.logger.Debug("logs not found", "hash", hexTx, "error", err.Error())
}

// get eth index based on block's txs
var txIndex uint64
msgs := e.backend.GetEthereumMsgsFromTendermintBlock(resBlock)
for i := range msgs {
if msgs[i].Hash == hexTx {
txIndex = uint64(i)
break
}
}

receipt := map[string]interface{}{
Expand All @@ -829,7 +822,7 @@ func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interfac
// transaction corresponding to this receipt.
"blockHash": common.BytesToHash(resBlock.Block.Header.Hash()).Hex(),
"blockNumber": hexutil.Uint64(res.Height),
"transactionIndex": hexutil.Uint64(res.Index),
"transactionIndex": hexutil.Uint64(txIndex),

// sender and receiver (contract or EOA) addreses
"from": from,
Expand All @@ -848,7 +841,7 @@ func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interfac
return receipt, nil
}

// PendingTransactions returns the transactions that are in the transaction pool
// GetPendingTransactions returns the transactions that are in the transaction pool
// and have a from address that is one of the accounts this node manages.
func (e *PublicAPI) GetPendingTransactions() ([]*rpctypes.RPCTransaction, error) {
e.logger.Debug("eth_getPendingTransactions")
Expand Down