From 351e6d6eb3f23f72a8e2566fed86769f0ba1f3df Mon Sep 17 00:00:00 2001 From: yihuang Date: Sun, 16 Jan 2022 23:36:19 +0800 Subject: [PATCH] rpc: make trace transaction api work with batch tx (#907) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * make trace transaction api work with batch tx Closes: #906 fix linter * review suggestion Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> --- rpc/ethereum/namespaces/debug/api.go | 47 +++++++++++++++++----------- rpc/ethereum/namespaces/eth/api.go | 7 +++-- rpc/ethereum/types/utils.go | 25 +++++++++++++++ 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/rpc/ethereum/namespaces/debug/api.go b/rpc/ethereum/namespaces/debug/api.go index ad516afefc..5dacaeb2aa 100644 --- a/rpc/ethereum/namespaces/debug/api.go +++ b/rpc/ethereum/namespaces/debug/api.go @@ -89,13 +89,17 @@ func (a *API) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) ( return nil, err } + msgIndex, _ := rpctypes.FindTxAttributes(transaction.TxResult.Events, hash.Hex()) + if msgIndex < 0 { + return nil, fmt.Errorf("ethereum tx not found in msgs: %s", hash.Hex()) + } + // check tx index is not out of bound if uint32(len(blk.Block.Txs)) < transaction.Index { a.logger.Debug("tx index out of bounds", "index", transaction.Index, "hash", hash.String(), "height", blk.Block.Height) return nil, fmt.Errorf("transaction not included in block %v", blk.Block.Height) } - // nolint: prealloc var predecessors []*evmtypes.MsgEthereumTx for _, txBz := range blk.Block.Txs[:transaction.Index] { tx, err := a.clientCtx.TxConfig.TxDecoder()(txBz) @@ -103,13 +107,14 @@ func (a *API) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) ( a.logger.Debug("failed to decode transaction in block", "height", blk.Block.Height, "error", err.Error()) continue } - msg := tx.GetMsgs()[0] - ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { - continue - } + for _, msg := range tx.GetMsgs() { + ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) + if !ok { + continue + } - predecessors = append(predecessors, ethMsg) + predecessors = append(predecessors, ethMsg) + } } tx, err := a.clientCtx.TxConfig.TxDecoder()(transaction.Tx) @@ -118,7 +123,16 @@ func (a *API) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) ( return nil, err } - ethMessage, ok := tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx) + // add predecessor messages in current cosmos tx + for i := 0; i < msgIndex; i++ { + ethMsg, ok := tx.GetMsgs()[i].(*evmtypes.MsgEthereumTx) + if !ok { + continue + } + predecessors = append(predecessors, ethMsg) + } + + ethMessage, ok := tx.GetMsgs()[msgIndex].(*evmtypes.MsgEthereumTx) if !ok { a.logger.Debug("invalid transaction type", "type", fmt.Sprintf("%T", tx)) return nil, fmt.Errorf("invalid transaction type %T", tx) @@ -209,7 +223,6 @@ func (a *API) traceBlock(height rpctypes.BlockNumber, config *evmtypes.TraceConf txDecoder := a.clientCtx.TxConfig.TxDecoder() - // nolint: prealloc var txsMessages []*evmtypes.MsgEthereumTx for i, tx := range txs { decodedTx, err := txDecoder(tx) @@ -218,16 +231,14 @@ func (a *API) traceBlock(height rpctypes.BlockNumber, config *evmtypes.TraceConf continue } - messages := decodedTx.GetMsgs() - if len(messages) == 0 { - continue - } - ethMessage, ok := messages[0].(*evmtypes.MsgEthereumTx) - if !ok { - // Just considers Ethereum transactions - continue + for _, msg := range decodedTx.GetMsgs() { + ethMessage, ok := msg.(*evmtypes.MsgEthereumTx) + if !ok { + // Just considers Ethereum transactions + continue + } + txsMessages = append(txsMessages, ethMessage) } - txsMessages = append(txsMessages, ethMessage) } // minus one to get the context at the beginning of the block diff --git a/rpc/ethereum/namespaces/eth/api.go b/rpc/ethereum/namespaces/eth/api.go index 084929f6fd..2cac0699d8 100644 --- a/rpc/ethereum/namespaces/eth/api.go +++ b/rpc/ethereum/namespaces/eth/api.go @@ -699,12 +699,15 @@ func (e *PublicAPI) getTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, e.logger.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx) return nil, nil } - if len(tx.GetMsgs()) != 1 { + // find msg index in events + msgIndex := rpctypes.FindTxAttributesByIndex(res.TxResult.Events, uint64(idx)) + if msgIndex < 0 { 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) + // msgIndex is inferred from tx events, should be within bound. + msg, ok = tx.GetMsgs()[msgIndex].(*evmtypes.MsgEthereumTx) if !ok { e.logger.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx) return nil, nil diff --git a/rpc/ethereum/types/utils.go b/rpc/ethereum/types/utils.go index 81d84d57be..31abc28645 100644 --- a/rpc/ethereum/types/utils.go +++ b/rpc/ethereum/types/utils.go @@ -282,6 +282,31 @@ func FindTxAttributes(events []abci.Event, txHash string) (int, map[string]strin return -1, nil } +// FindTxAttributesByIndex search the msg in tx events by txIndex +// returns the msgIndex, returns -1 if not found. +func FindTxAttributesByIndex(events []abci.Event, txIndex uint64) int { + strIndex := []byte(strconv.FormatUint(txIndex, 10)) + txIndexKey := []byte(evmtypes.AttributeKeyTxIndex) + msgIndex := -1 + for _, event := range events { + if event.Type != evmtypes.EventTypeEthereumTx { + continue + } + + msgIndex++ + + value := FindAttribute(event.Attributes, txIndexKey) + if !bytes.Equal(value, strIndex) { + continue + } + + // found, convert attributes to map for later lookup + return msgIndex + } + // not found + return -1 +} + // FindAttribute find event attribute with specified key, if not found returns nil. func FindAttribute(attrs []abci.EventAttribute, key []byte) []byte { for _, attr := range attrs {