From 78282ed1e5e344bbbc7843370d6f1da1613e8afd Mon Sep 17 00:00:00 2001 From: heejekim12 Date: Thu, 23 Jul 2026 23:36:58 +0900 Subject: [PATCH] update tx_info --- .../modules/evm/rpc/backend/tx_info.go | 166 ++++++++++++------ 1 file changed, 110 insertions(+), 56 deletions(-) diff --git a/injective-chain/modules/evm/rpc/backend/tx_info.go b/injective-chain/modules/evm/rpc/backend/tx_info.go index fbae784..0e3e984 100644 --- a/injective-chain/modules/evm/rpc/backend/tx_info.go +++ b/injective-chain/modules/evm/rpc/backend/tx_info.go @@ -32,6 +32,10 @@ func (b *Backend) GetTxHashByEthHash(ethHash common.Hash) (common.Hash, error) { return common.Hash{}, fmt.Errorf("block not found, err: %w", err) } + if int(res.TxIndex) >= len(block.Block.Txs) { + return common.Hash{}, fmt.Errorf("tx index out of bounds") + } + bftHash := block.Block.Txs[res.TxIndex].Hash() return common.Hash(bftHash), nil @@ -52,13 +56,22 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac return nil, nil } + if int(res.TxIndex) >= len(block.Block.Txs) { + return nil, errors.New("tx index out of range") + } + tx, err := b.clientCtx.TxConfig.TxDecoder()(block.Block.Txs[res.TxIndex]) if err != nil { return nil, err } + msgs := tx.GetMsgs() + if int(res.MsgIndex) >= len(msgs) { + return nil, errors.New("msg index out of range") + } + // the `res.MsgIndex` is inferred from tx index, should be within the bound. - msg, ok := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) + msg, ok := msgs[res.MsgIndex].(*evmtypes.MsgEthereumTx) if !ok { return nil, errors.New("invalid ethereum tx") } @@ -71,9 +84,9 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac if res.EthTxIndex == -1 { // Fallback to find tx index by iterating all valid eth transactions - msgs := b.EthMsgsFromTendermintBlock(block) - for i := range msgs { - if msgs[i].Hash() == txHash { + ethMsgs := b.EthMsgsFromTendermintBlock(block) + for i := range ethMsgs { + if ethMsgs[i].Hash() == txHash { res.EthTxIndex = int32(i) break } @@ -156,31 +169,52 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ b.logger.Debug("block not found", "height", res.Height, "error", err.Error()) return nil, err } - if resBlock == nil { + if resBlock == nil || resBlock.Block == nil { b.logger.Debug("block not found", "height", res.Height) return nil, nil } + if int(res.TxIndex) >= len(resBlock.Block.Txs) { + b.logger.Warn("txIndex out of range", "txIndex", res.TxIndex, "len", len(resBlock.Block.Txs)) + return nil, nil + } + tx, err := b.clientCtx.TxConfig.TxDecoder()(resBlock.Block.Txs[res.TxIndex]) if err != nil { b.logger.Warn("decoding failed", "error", err.Error()) return nil, fmt.Errorf("failed to decode tx: %w", err) } - ethMsg := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) + + msgs := tx.GetMsgs() + if int(res.MsgIndex) >= len(msgs) { + b.logger.Warn("msgIndex out of range", "msgIndex", res.MsgIndex, "len", len(msgs)) + return nil, nil + } + + ethMsg, ok := msgs[res.MsgIndex].(*evmtypes.MsgEthereumTx) + if !ok { + b.logger.Error("invalid ethereum tx type") + return nil, errors.New("invalid ethereum tx") + } txData := ethMsg.AsTransaction() if txData == nil { b.logger.Error("failed to unpack tx data") - return nil, err + return nil, errors.New("failed to unpack tx data") } - cumulativeGasUsed := uint64(0) blockRes, err := b.TendermintBlockResultByNumber(&res.Height) if err != nil { b.logger.Warn("failed to retrieve block results", "height", res.Height, "error", err.Error()) return nil, nil } - for _, txResult := range blockRes.TxResults[0:res.TxIndex] { + + cumulativeGasUsed := uint64(0) + maxTxIndex := int(res.TxIndex) + if maxTxIndex > len(blockRes.TxResults) { + maxTxIndex = len(blockRes.TxResults) + } + for _, txResult := range blockRes.TxResults[0:maxTxIndex] { cumulativeGasUsed += uint64(txResult.GasUsed) } cumulativeGasUsed += res.CumulativeGasUsed @@ -197,21 +231,13 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, err } - // parse tx logs from events - logs, err := evmtypes.DecodeMsgLogs( - blockRes.TxResults[res.TxIndex].Data, - int(res.MsgIndex), - uint64(blockRes.Height), - ) - if err != nil { - b.logger.Warn("failed to parse logs", "hash", hash, "error", err.Error()) - } + blockHash := common.BytesToHash(resBlock.Block.Header.Hash()) if res.EthTxIndex == -1 { // Fallback to find tx index by iterating all valid eth transactions - msgs := b.EthMsgsFromTendermintBlock(resBlock) - for i := range msgs { - if msgs[i].Hash() == hash { + ethMsgs := b.EthMsgsFromTendermintBlock(resBlock) + for i := range ethMsgs { + if ethMsgs[i].Hash() == hash { res.EthTxIndex = int32(i) break } @@ -222,6 +248,28 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, errors.New("can't find index of ethereum tx") } + // parse tx logs from events + var logs []*ethtypes.Log + if int(res.TxIndex) < len(blockRes.TxResults) { + logs, err = evmtypes.DecodeMsgLogs( + blockRes.TxResults[res.TxIndex].Data, + int(res.MsgIndex), + uint64(blockRes.Height), + ) + if err != nil { + b.logger.Warn("failed to parse logs", "hash", hash, "error", err.Error()) + logs = nil + } + } + + // Enrich log fields (blockHash, transactionHash, transactionIndex, etc.) + for i, log := range logs { + log.BlockHash = blockHash + log.TxHash = hash + log.TxIndex = uint(res.EthTxIndex) + log.Index = uint(i) + } + var baseFee *big.Int if txData.Type() == ethtypes.DynamicFeeTxType { baseFee, err = b.BaseFee(blockRes) @@ -230,41 +278,40 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ } } + var contractAddress interface{} = nil + if txData.To() == nil { + contractAddress = crypto.CreateAddress(from, txData.Nonce()) + } + + formattedLogs := logs + if formattedLogs == nil { + formattedLogs = []*ethtypes.Log{} + } + receipt := map[string]interface{}{ // Consensus fields: These fields are defined by the Yellow Paper "status": status, "cumulativeGasUsed": hexutil.Uint64(cumulativeGasUsed), "logsBloom": ethtypes.BytesToBloom(evmtypes.LogsBloom(logs)), - "logs": logs, + "logs": formattedLogs, // Implementation fields: These fields are added by geth when processing a transaction. - // They are stored in the chain database. "transactionHash": hash, - "contractAddress": nil, + "contractAddress": contractAddress, "gasUsed": hexutil.Uint64(b.GetGasUsed(res, txData.Gas())), - // Inclusion information: These fields provide information about the inclusion of the - // transaction corresponding to this receipt. - "blockHash": common.BytesToHash(resBlock.Block.Header.Hash()).Hex(), + // Inclusion information: These fields provide information about the inclusion + "blockHash": blockHash.Hex(), "blockNumber": hexutil.Uint64(res.Height), "transactionIndex": hexutil.Uint64(res.EthTxIndex), // https://github.com/foundry-rs/foundry/issues/7640 "effectiveGasPrice": (*hexutil.Big)(effectiveGasPrice(txData, baseFee)), - // sender and receiver (contract or EOA) addreses + // sender and receiver (contract or EOA) addresses "from": from, "to": txData.To(), - "type": hexutil.Uint(ethMsg.AsTransaction().Type()), - } - - if logs == nil { - receipt["logs"] = [][]*ethtypes.Log{} - } - - // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation - if txData.To() == nil { - receipt["contractAddress"] = crypto.CreateAddress(from, txData.Nonce()) + "type": hexutil.Uint(txData.Type()), } return receipt, nil @@ -312,11 +359,12 @@ func (b *Backend) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNum } // GetTxByEthHash uses `/tx_query` to find transaction by ethereum tx hash -// TODO: Don't need to convert once hashing is fixed on Tendermint -// https://github.com/tendermint/tendermint/issues/6539 func (b *Backend) GetTxByEthHash(hash common.Hash) (*chaintypes.TxResult, error) { if b.indexer != nil { - return b.indexer.GetByTxHash(hash) + res, err := b.indexer.GetByTxHash(hash) + if err == nil && res != nil { + return res, nil + } } // fallback to tendermint tx indexer @@ -334,7 +382,10 @@ func (b *Backend) GetTxByEthHash(hash common.Hash) (*chaintypes.TxResult, error) // GetTxByTxIndex uses `/tx_query` to find transaction by tx index of valid ethereum txs func (b *Backend) GetTxByTxIndex(height int64, index uint) (*chaintypes.TxResult, error) { if b.indexer != nil { - return b.indexer.GetByBlockAndIndex(height, int32(index)) + res, err := b.indexer.GetByBlockAndIndex(height, int32(index)) + if err == nil && res != nil { + return res, nil + } } // fallback to tendermint tx indexer @@ -390,21 +441,24 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *cmrpctypes.ResultBlock, i var msg *evmtypes.MsgEthereumTx // find in tx indexer res, err := b.GetTxByTxIndex(block.Block.Height, uint(idx)) - if err == nil { - tx, err := b.clientCtx.TxConfig.TxDecoder()(block.Block.Txs[res.TxIndex]) - if err != nil { - b.logger.Warn("invalid ethereum tx", "height", block.Block.Header, "index", idx) - return nil, nil + if err == nil && res != nil { + if int(res.TxIndex) < len(block.Block.Txs) { + tx, err := b.clientCtx.TxConfig.TxDecoder()(block.Block.Txs[res.TxIndex]) + if err == nil { + msgs := tx.GetMsgs() + if int(res.MsgIndex) < len(msgs) { + var ok bool + msg, ok = msgs[res.MsgIndex].(*evmtypes.MsgEthereumTx) + if !ok { + msg = nil + } + } + } } + } - var ok bool - // msgIndex is inferred from tx events, should be within bound. - msg, ok = tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { - b.logger.Warn("invalid ethereum tx", "height", block.Block.Header, "index", idx) - return nil, nil - } - } else { + // Fallback when indexer fail or returned invalid msg + if msg == nil { i := int(idx) if i < 0 { i = 0 @@ -432,4 +486,4 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *cmrpctypes.ResultBlock, i baseFee, b.ChainID().ToInt(), ) -} +} \ No newline at end of file