From 4c4b0ca31903a88d4ee1b5c87885c799ca0670d3 Mon Sep 17 00:00:00 2001 From: skosito Date: Tue, 21 May 2024 19:19:41 +0200 Subject: [PATCH 01/25] Add eth tx bytes to events and decode in tracing --- rpc/backend/tracing.go | 67 ++++++++++++++++++++++++++++++++++++++-- x/fungible/keeper/evm.go | 15 +++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/rpc/backend/tracing.go b/rpc/backend/tracing.go index d9cd79af6b..5f77b73c45 100644 --- a/rpc/backend/tracing.go +++ b/rpc/backend/tracing.go @@ -23,6 +23,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + ethtypes "github.com/ethereum/go-ethereum/core/types" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/pkg/errors" rpctypes "github.com/zeta-chain/zetacore/rpc/types" @@ -32,7 +33,7 @@ import ( // and returns them as a JSON object. func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) (interface{}, error) { // Get transaction by hash - transaction, _, err := b.GetTxByEthHash(hash) + transaction, additional, err := b.GetTxByEthHash(hash) if err != nil { b.logger.Debug("tx not found", "hash", hash) return nil, err @@ -49,6 +50,38 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return nil, err } + blockResult, err := b.TendermintBlockResultByNumber(&blk.Block.Height) + if err != nil { + return nil, fmt.Errorf("block result not found for height %d", blk.Block.Height) + } + + // pull out txBytes from event and convert to MsgEthereumTx + ethTx88 := evmtypes.MsgEthereumTx{} + txRes := blockResult.TxsResults[transaction.TxIndex] + for _, ev := range txRes.Events { + for _, attr := range ev.Attributes { + if string(attr.Key) == "TxBytes" { + hexBytes, err := hexutil.Decode(string(attr.Value)) + if err != nil { + return nil, err + } + t := ethtypes.Transaction{} + if err := t.UnmarshalBinary(hexBytes); err != nil { + return nil, err + } + + if err := ethTx88.FromEthereumTx(&t); err != nil { + return nil, err + } + } + + if string(attr.Key) == "sender" { + ethTx88.From = string(attr.Value) + } + } + } + ethTx88.Hash = hash.Hex() + // check tx index is not out of bound // #nosec G701 txs number in block is always less than MaxUint32 if uint32(len(blk.Block.Txs)) < transaction.TxIndex { @@ -91,10 +124,20 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi ethMessage, ok := tx.GetMsgs()[transaction.MsgIndex].(*evmtypes.MsgEthereumTx) if !ok { - b.logger.Debug("invalid transaction type", "type", fmt.Sprintf("%T", tx)) - return nil, fmt.Errorf("invalid transaction type %T", tx) + if additional == nil { + b.logger.Debug("invalid transaction type", "type", fmt.Sprintf("%T", tx)) + return nil, fmt.Errorf("invalid transaction type %T", tx) + } + fmt.Println("predecessors ", len(predecessors), hash.Hex()) + fmt.Println("sender ", len(predecessors), additional.Sender) + + ethMessage = &evmtypes.MsgEthereumTx{ + Hash: hash.Hex(), + From: additional.Sender.Hex(), + } } + fmt.Println("checkpoint 1") traceTxRequest := evmtypes.QueryTraceTxRequest{ Msg: ethMessage, Predecessors: predecessors, @@ -104,11 +147,25 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi ProposerAddress: sdk.ConsAddress(blk.Block.ProposerAddress), ChainId: b.chainID.Int64(), } + fmt.Println("checkpoint 2") + if additional != nil { + traceTxRequest = evmtypes.QueryTraceTxRequest{ + Msg: ðTx88, + Predecessors: []*evmtypes.MsgEthereumTx{}, + BlockNumber: blk.Block.Height, + BlockTime: blk.Block.Time, + BlockHash: common.Bytes2Hex(blk.BlockID.Hash), + ProposerAddress: sdk.ConsAddress(blk.Block.ProposerAddress), + ChainId: b.chainID.Int64(), + } + } if config != nil { traceTxRequest.TraceConfig = config } + fmt.Println("checkpoint 3") + // minus one to get the context of block beginning contextHeight := transaction.Height - 1 if contextHeight < 1 { @@ -120,6 +177,8 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return nil, err } + fmt.Println("checkpoint 4") + // Response format is unknown due to custom tracer config param // More information can be found here https://geth.ethereum.org/docs/dapp/tracing-filtered var decodedResult interface{} @@ -128,6 +187,8 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return nil, err } + fmt.Println("checkpoint 5") + return decodedResult, nil } diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index c4ab0d81de..b4d3aab6af 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -756,6 +756,21 @@ func (k Keeper) CallEVMWithData( } if !noEthereumTxEvent { + fmt.Println("88 tx", ethTxHash.Hex()) + txBytes, err := ethtypes.NewTx(ðtypes.DynamicFeeTx{ + ChainID: k.evmKeeper.ChainID(), + Nonce: nonce, + GasTipCap: msg.GasTipCap(), + GasFeeCap: msg.GasFeeCap(), + Gas: msg.Gas(), + To: msg.To(), + Value: msg.Value(), + Data: msg.Data(), + }).MarshalBinary() + if err != nil { + return nil, fmt.Errorf("failed to convert tx msg, err=%w", err) + } + attrs = append(attrs, sdk.NewAttribute("TxBytes", hexutil.Encode(txBytes))) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( evmtypes.EventTypeEthereumTx, From 22ebd864b913aff4e4daee395967b2c8a7710dfd Mon Sep 17 00:00:00 2001 From: skosito Date: Tue, 21 May 2024 19:46:43 +0200 Subject: [PATCH 02/25] bump ethermint --- go.mod | 11 +++++------ go.sum | 5 ++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 5cba25e884..a2132365b6 100644 --- a/go.mod +++ b/go.mod @@ -59,11 +59,12 @@ require ( cosmossdk.io/tools/rosetta v0.2.1 github.com/binance-chain/tss-lib v0.0.0-20201118045712-70b2cb4bf916 github.com/btcsuite/btcd/btcutil v1.1.3 + github.com/cockroachdb/errors v1.10.0 github.com/cometbft/cometbft v0.37.4 github.com/cometbft/cometbft-db v0.8.0 + github.com/huandu/skiplist v1.2.0 github.com/nanmu42/etherscan-api v1.10.0 github.com/onrik/ethrpc v1.2.0 - github.com/tendermint/tendermint v0.34.12 go.nhat.io/grpcmock v0.25.0 ) @@ -77,7 +78,6 @@ require ( github.com/agl/ed25519 v0.0.0-20200225211852-fd4d107ace12 // indirect github.com/bool64/shared v0.1.5 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cockroachdb/errors v1.10.0 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 // indirect github.com/cockroachdb/redact v1.1.5 // indirect @@ -98,7 +98,6 @@ require ( github.com/golang/mock v1.6.0 // indirect github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/ipfs/boxo v0.10.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect @@ -216,7 +215,7 @@ require ( github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.4 // indirect + github.com/hashicorp/go-getter v1.7.4 github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect @@ -321,7 +320,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.17.0 - golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect + golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb golang.org/x/mod v0.11.0 // indirect golang.org/x/net v0.19.0 golang.org/x/oauth2 v0.15.0 // indirect @@ -354,4 +353,4 @@ replace ( replace github.com/cometbft/cometbft-db => github.com/notional-labs/cometbft-db v0.0.0-20230321185329-6dc7c0ca6345 -replace github.com/evmos/ethermint => github.com/zeta-chain/ethermint v0.0.0-20240429123701-35f3f79bf83f +replace github.com/evmos/ethermint => github.com/zeta-chain/ethermint v0.0.0-20240521172746-9b5396dad803 diff --git a/go.sum b/go.sum index 21f0ee7415..9688db69e9 100644 --- a/go.sum +++ b/go.sum @@ -1639,7 +1639,6 @@ github.com/tendermint/tendermint v0.34.0-rc6/go.mod h1:ugzyZO5foutZImv0Iyx/gOFCX github.com/tendermint/tendermint v0.34.0/go.mod h1:Aj3PIipBFSNO21r+Lq3TtzQ+uKESxkbA3yo/INM4QwQ= github.com/tendermint/tendermint v0.34.10/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= github.com/tendermint/tendermint v0.34.11/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= -github.com/tendermint/tendermint v0.34.12 h1:m+kUYNhONedhJfHmHG8lqsdZvbR5t6vmhaok1yXjpKg= github.com/tendermint/tendermint v0.34.12/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs+yAcLvGI= github.com/tendermint/tm-db v0.6.3/go.mod h1:lfA1dL9/Y/Y8wwyPp2NMLyn5P5Ptr/gvDFNWtrCWSf8= @@ -1733,8 +1732,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeta-chain/ethermint v0.0.0-20240429123701-35f3f79bf83f h1:joafCsPgohPEn93VCbNXi9IAl6kNvKy8u+kv5amEvUk= -github.com/zeta-chain/ethermint v0.0.0-20240429123701-35f3f79bf83f/go.mod h1:s1zA6OpXv3Tb5I0M6M6j5fo/AssaZL/pgkc7G0W2kN8= +github.com/zeta-chain/ethermint v0.0.0-20240521172746-9b5396dad803 h1:HnLKFC5Z0IfvlVivc3TxqeZUudF/rsUFFGz/nhmFm7Y= +github.com/zeta-chain/ethermint v0.0.0-20240521172746-9b5396dad803/go.mod h1:s1zA6OpXv3Tb5I0M6M6j5fo/AssaZL/pgkc7G0W2kN8= github.com/zeta-chain/go-tss v0.1.1-0.20240430111318-1785e48eb127 h1:AGQepvsMIVHAHPlplzNcSCyMoGBY1DfO4WHG/QHUSIU= github.com/zeta-chain/go-tss v0.1.1-0.20240430111318-1785e48eb127/go.mod h1:bVpAoSlRYYCY/R34horVU3cheeHqhSVxygelc++emIU= github.com/zeta-chain/keystone/keys v0.0.0-20231105174229-903bc9405da2 h1:gd2uE0X+ZbdFJ8DubxNqLbOVlCB12EgWdzSNRAR82tM= From 7e0e446ab85cb9440c40cdcb57f192b64d094570 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 22 May 2024 02:18:11 +0200 Subject: [PATCH 03/25] cleanup and add predecessors handling --- go.mod | 2 +- go.sum | 4 +- rpc/backend/tracing.go | 102 +++++++++++++++++++-------------------- x/fungible/keeper/evm.go | 1 + 4 files changed, 54 insertions(+), 55 deletions(-) diff --git a/go.mod b/go.mod index a2132365b6..4a7e28f411 100644 --- a/go.mod +++ b/go.mod @@ -353,4 +353,4 @@ replace ( replace github.com/cometbft/cometbft-db => github.com/notional-labs/cometbft-db v0.0.0-20230321185329-6dc7c0ca6345 -replace github.com/evmos/ethermint => github.com/zeta-chain/ethermint v0.0.0-20240521172746-9b5396dad803 +replace github.com/evmos/ethermint => github.com/zeta-chain/ethermint v0.0.0-20240521185249-8bae394152de diff --git a/go.sum b/go.sum index 9688db69e9..05683f638c 100644 --- a/go.sum +++ b/go.sum @@ -1732,8 +1732,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeta-chain/ethermint v0.0.0-20240521172746-9b5396dad803 h1:HnLKFC5Z0IfvlVivc3TxqeZUudF/rsUFFGz/nhmFm7Y= -github.com/zeta-chain/ethermint v0.0.0-20240521172746-9b5396dad803/go.mod h1:s1zA6OpXv3Tb5I0M6M6j5fo/AssaZL/pgkc7G0W2kN8= +github.com/zeta-chain/ethermint v0.0.0-20240521185249-8bae394152de h1:TvN2pOvj+PxXeFdrBzCbNGSfXU+Bnnl7ZGlBJ3lmgoM= +github.com/zeta-chain/ethermint v0.0.0-20240521185249-8bae394152de/go.mod h1:s1zA6OpXv3Tb5I0M6M6j5fo/AssaZL/pgkc7G0W2kN8= github.com/zeta-chain/go-tss v0.1.1-0.20240430111318-1785e48eb127 h1:AGQepvsMIVHAHPlplzNcSCyMoGBY1DfO4WHG/QHUSIU= github.com/zeta-chain/go-tss v0.1.1-0.20240430111318-1785e48eb127/go.mod h1:bVpAoSlRYYCY/R34horVU3cheeHqhSVxygelc++emIU= github.com/zeta-chain/keystone/keys v0.0.0-20231105174229-903bc9405da2 h1:gd2uE0X+ZbdFJ8DubxNqLbOVlCB12EgWdzSNRAR82tM= diff --git a/rpc/backend/tracing.go b/rpc/backend/tracing.go index 5f77b73c45..fc6bfba82c 100644 --- a/rpc/backend/tracing.go +++ b/rpc/backend/tracing.go @@ -19,6 +19,7 @@ import ( "encoding/json" "fmt" + "github.com/cometbft/cometbft/abci/types" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" @@ -55,33 +56,6 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return nil, fmt.Errorf("block result not found for height %d", blk.Block.Height) } - // pull out txBytes from event and convert to MsgEthereumTx - ethTx88 := evmtypes.MsgEthereumTx{} - txRes := blockResult.TxsResults[transaction.TxIndex] - for _, ev := range txRes.Events { - for _, attr := range ev.Attributes { - if string(attr.Key) == "TxBytes" { - hexBytes, err := hexutil.Decode(string(attr.Value)) - if err != nil { - return nil, err - } - t := ethtypes.Transaction{} - if err := t.UnmarshalBinary(hexBytes); err != nil { - return nil, err - } - - if err := ethTx88.FromEthereumTx(&t); err != nil { - return nil, err - } - } - - if string(attr.Key) == "sender" { - ethTx88.From = string(attr.Value) - } - } - } - ethTx88.Hash = hash.Hex() - // check tx index is not out of bound // #nosec G701 txs number in block is always less than MaxUint32 if uint32(len(blk.Block.Txs)) < transaction.TxIndex { @@ -90,7 +64,7 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi } var predecessors []*evmtypes.MsgEthereumTx - for _, txBz := range blk.Block.Txs[:transaction.TxIndex] { + for i, txBz := range blk.Block.Txs[:transaction.TxIndex] { tx, err := b.clientCtx.TxConfig.TxDecoder()(txBz) if err != nil { b.logger.Debug("failed to decode transaction in block", "height", blk.Block.Height, "error", err.Error()) @@ -99,6 +73,10 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi for _, msg := range tx.GetMsgs() { ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { + ethTx, err := tryGetEthereumTxFromTxRes(blockResult.TxsResults[i]) + if ethTx != nil && err == nil { + predecessors = append(predecessors, ethTx) + } continue } @@ -115,6 +93,7 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi // add predecessor messages in current cosmos tx // #nosec G701 always in range for i := 0; i < int(transaction.MsgIndex); i++ { + // TODO: same fallback for predecessors? ethMsg, ok := tx.GetMsgs()[i].(*evmtypes.MsgEthereumTx) if !ok { continue @@ -128,16 +107,14 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi b.logger.Debug("invalid transaction type", "type", fmt.Sprintf("%T", tx)) return nil, fmt.Errorf("invalid transaction type %T", tx) } - fmt.Println("predecessors ", len(predecessors), hash.Hex()) - fmt.Println("sender ", len(predecessors), additional.Sender) - ethMessage = &evmtypes.MsgEthereumTx{ - Hash: hash.Hex(), - From: additional.Sender.Hex(), + ethMessage, err = tryGetEthereumTxFromTxRes(blockResult.TxsResults[transaction.TxIndex]) + if err != nil { + b.logger.Debug("invalid transaction type", "type", fmt.Sprintf("%T", tx)) + return nil, fmt.Errorf("invalid transaction type %T", tx) } } - fmt.Println("checkpoint 1") traceTxRequest := evmtypes.QueryTraceTxRequest{ Msg: ethMessage, Predecessors: predecessors, @@ -147,25 +124,11 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi ProposerAddress: sdk.ConsAddress(blk.Block.ProposerAddress), ChainId: b.chainID.Int64(), } - fmt.Println("checkpoint 2") - if additional != nil { - traceTxRequest = evmtypes.QueryTraceTxRequest{ - Msg: ðTx88, - Predecessors: []*evmtypes.MsgEthereumTx{}, - BlockNumber: blk.Block.Height, - BlockTime: blk.Block.Time, - BlockHash: common.Bytes2Hex(blk.BlockID.Hash), - ProposerAddress: sdk.ConsAddress(blk.Block.ProposerAddress), - ChainId: b.chainID.Int64(), - } - } if config != nil { traceTxRequest.TraceConfig = config } - fmt.Println("checkpoint 3") - // minus one to get the context of block beginning contextHeight := transaction.Height - 1 if contextHeight < 1 { @@ -177,8 +140,6 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return nil, err } - fmt.Println("checkpoint 4") - // Response format is unknown due to custom tracer config param // More information can be found here https://geth.ethereum.org/docs/dapp/tracing-filtered var decodedResult interface{} @@ -187,11 +148,48 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return nil, err } - fmt.Println("checkpoint 5") - return decodedResult, nil } +func tryGetEthereumTxFromTxRes(txRes *types.ResponseDeliverTx) (*evmtypes.MsgEthereumTx, error) { + ethTx := &evmtypes.MsgEthereumTx{} + txFound := false + for _, ev := range txRes.Events { + if ev.Type == evmtypes.EventTypeEthereumTx { + for _, attr := range ev.Attributes { + if string(attr.Key) == "TxBytes" { + txFound = true + hexBytes, err := hexutil.Decode(string(attr.Value)) + if err != nil { + return nil, err + } + t := ethtypes.Transaction{} + if err := t.UnmarshalBinary(hexBytes); err != nil { + return nil, err + } + + if err := ethTx.FromEthereumTx(&t); err != nil { + return nil, err + } + } + + if string(attr.Key) == "sender" { + ethTx.From = string(attr.Value) + } + + if string(attr.Key) == "TxHash" { + ethTx.Hash = string(attr.Value) + } + } + } + } + + if !txFound { + return nil, nil + } + return ethTx, nil +} + // TraceBlock configures a new tracer according to the provided configuration, and // executes all the transactions contained within. The return value will be one item // per transaction, dependent on the requested tracer. diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index b4d3aab6af..5dece902cf 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -771,6 +771,7 @@ func (k Keeper) CallEVMWithData( return nil, fmt.Errorf("failed to convert tx msg, err=%w", err) } attrs = append(attrs, sdk.NewAttribute("TxBytes", hexutil.Encode(txBytes))) + attrs = append(attrs, sdk.NewAttribute("TxHash", ethTxHash.Hex())) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( evmtypes.EventTypeEthereumTx, From 134036e67a98b012f787a4608cef724d8b69fa10 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 22 May 2024 14:46:49 +0200 Subject: [PATCH 04/25] cleanup --- rpc/backend/tracing.go | 43 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/rpc/backend/tracing.go b/rpc/backend/tracing.go index fc6bfba82c..79f6083d84 100644 --- a/rpc/backend/tracing.go +++ b/rpc/backend/tracing.go @@ -155,32 +155,33 @@ func tryGetEthereumTxFromTxRes(txRes *types.ResponseDeliverTx) (*evmtypes.MsgEth ethTx := &evmtypes.MsgEthereumTx{} txFound := false for _, ev := range txRes.Events { - if ev.Type == evmtypes.EventTypeEthereumTx { - for _, attr := range ev.Attributes { - if string(attr.Key) == "TxBytes" { - txFound = true - hexBytes, err := hexutil.Decode(string(attr.Value)) - if err != nil { - return nil, err - } - t := ethtypes.Transaction{} - if err := t.UnmarshalBinary(hexBytes); err != nil { - return nil, err - } - - if err := ethTx.FromEthereumTx(&t); err != nil { - return nil, err - } + if ev.Type != evmtypes.EventTypeEthereumTx { + continue + } + for _, attr := range ev.Attributes { + if string(attr.Key) == "TxBytes" { + txFound = true + hexBytes, err := hexutil.Decode(string(attr.Value)) + if err != nil { + return nil, err } - - if string(attr.Key) == "sender" { - ethTx.From = string(attr.Value) + t := ethtypes.Transaction{} + if err := t.UnmarshalBinary(hexBytes); err != nil { + return nil, err } - if string(attr.Key) == "TxHash" { - ethTx.Hash = string(attr.Value) + if err := ethTx.FromEthereumTx(&t); err != nil { + return nil, err } } + + if attr.Key == "sender" { + ethTx.From = attr.Value + } + + if attr.Key == "TxHash" { + ethTx.Hash = attr.Value + } } } From 2e275f89a70fdbee5a59cd5606dbd6401251ea8c Mon Sep 17 00:00:00 2001 From: skosito Date: Thu, 23 May 2024 01:42:57 +0200 Subject: [PATCH 05/25] POC for alternative solution to pull tx info from events --- rpc/backend/tracing.go | 121 ++++++++++++++++++--------------------- rpc/types/events.go | 30 ++++++++++ x/fungible/keeper/evm.go | 15 +---- 3 files changed, 88 insertions(+), 78 deletions(-) diff --git a/rpc/backend/tracing.go b/rpc/backend/tracing.go index 79f6083d84..2bed7dbce8 100644 --- a/rpc/backend/tracing.go +++ b/rpc/backend/tracing.go @@ -18,8 +18,8 @@ package backend import ( "encoding/json" "fmt" + "math/big" - "github.com/cometbft/cometbft/abci/types" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" @@ -34,7 +34,7 @@ import ( // and returns them as a JSON object. func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) (interface{}, error) { // Get transaction by hash - transaction, additional, err := b.GetTxByEthHash(hash) + transaction, _, err := b.GetTxByEthHash(hash) if err != nil { b.logger.Debug("tx not found", "hash", hash) return nil, err @@ -70,16 +70,18 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi b.logger.Debug("failed to decode transaction in block", "height", blk.Block.Height, "error", err.Error()) continue } - for _, msg := range tx.GetMsgs() { - ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { - ethTx, err := tryGetEthereumTxFromTxRes(blockResult.TxsResults[i]) - if ethTx != nil && err == nil { - predecessors = append(predecessors, ethTx) - } + + // get parsed eth txs from events from tx result + parsed, err := rpctypes.ParseTxResult(blockResult.TxsResults[i], tx) + if err != nil { + return nil, err + } + + for _, parsedTx := range parsed.Txs { + ethMsg := getMsgEthereumTxFromParsedTx(parsedTx, tx) + if ethMsg == nil { continue } - predecessors = append(predecessors, ethMsg) } } @@ -90,33 +92,30 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return nil, err } - // add predecessor messages in current cosmos tx - // #nosec G701 always in range - for i := 0; i < int(transaction.MsgIndex); i++ { - // TODO: same fallback for predecessors? - ethMsg, ok := tx.GetMsgs()[i].(*evmtypes.MsgEthereumTx) - if !ok { - continue - } - predecessors = append(predecessors, ethMsg) + // get parsed eth txs from events from tx result + parsed, err := rpctypes.ParseTxResult(blockResult.TxsResults[transaction.TxIndex], tx) + if err != nil { + return nil, err } - ethMessage, ok := tx.GetMsgs()[transaction.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { - if additional == nil { - b.logger.Debug("invalid transaction type", "type", fmt.Sprintf("%T", tx)) - return nil, fmt.Errorf("invalid transaction type %T", tx) + // iterate parsed eth txs, if its type 88, recreate it and get MsgEthereumTx, otherwise pull it from sdk.Msgs + // when requested tx is found, break, no more predecessors + var ethMsg *evmtypes.MsgEthereumTx + for _, parsedTx := range parsed.Txs { + ethMsg = getMsgEthereumTxFromParsedTx(parsedTx, tx) + if parsedTx.Hash.Hex() == hash.Hex() { + if ethMsg == nil { + return nil, errors.New("error while parsing tx") + } + break } - - ethMessage, err = tryGetEthereumTxFromTxRes(blockResult.TxsResults[transaction.TxIndex]) - if err != nil { - b.logger.Debug("invalid transaction type", "type", fmt.Sprintf("%T", tx)) - return nil, fmt.Errorf("invalid transaction type %T", tx) + if ethMsg == nil { + continue } + predecessors = append(predecessors, ethMsg) } - traceTxRequest := evmtypes.QueryTraceTxRequest{ - Msg: ethMessage, + Msg: ethMsg, Predecessors: predecessors, BlockNumber: blk.Block.Height, BlockTime: blk.Block.Time, @@ -151,44 +150,34 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return decodedResult, nil } -func tryGetEthereumTxFromTxRes(txRes *types.ResponseDeliverTx) (*evmtypes.MsgEthereumTx, error) { - ethTx := &evmtypes.MsgEthereumTx{} - txFound := false - for _, ev := range txRes.Events { - if ev.Type != evmtypes.EventTypeEthereumTx { - continue +func getMsgEthereumTxFromParsedTx(parsedTx rpctypes.ParsedTx, tx sdk.Tx) *evmtypes.MsgEthereumTx { + if parsedTx.Type == 88 { + recipient := parsedTx.Recipient + // TODO: is this ok? + t := ethtypes.NewTx(ðtypes.LegacyTx{ + Nonce: parsedTx.Nonce, + Data: parsedTx.Data, + Gas: parsedTx.GasUsed, + To: &recipient, + GasPrice: nil, + Value: parsedTx.Amount, + V: big.NewInt(0), + R: big.NewInt(0), + S: big.NewInt(0), + }) + ethMsg := &evmtypes.MsgEthereumTx{} + err := ethMsg.FromEthereumTx(t) + if err != nil { + return nil } - for _, attr := range ev.Attributes { - if string(attr.Key) == "TxBytes" { - txFound = true - hexBytes, err := hexutil.Decode(string(attr.Value)) - if err != nil { - return nil, err - } - t := ethtypes.Transaction{} - if err := t.UnmarshalBinary(hexBytes); err != nil { - return nil, err - } - - if err := ethTx.FromEthereumTx(&t); err != nil { - return nil, err - } - } - - if attr.Key == "sender" { - ethTx.From = attr.Value - } - - if attr.Key == "TxHash" { - ethTx.Hash = attr.Value - } + return ethMsg + } else { + ethMsg, ok := tx.GetMsgs()[parsedTx.MsgIndex].(*evmtypes.MsgEthereumTx) + if !ok { + return nil } + return ethMsg } - - if !txFound { - return nil, nil - } - return ethTx, nil } // TraceBlock configures a new tracer according to the provided configuration, and diff --git a/rpc/types/events.go b/rpc/types/events.go index 3f40668719..3c67d78927 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -17,6 +17,7 @@ package types import ( "fmt" + "math" "math/big" "strconv" @@ -24,6 +25,7 @@ import ( tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" ethermint "github.com/evmos/ethermint/types" evmtypes "github.com/evmos/ethermint/x/evm/types" ) @@ -68,6 +70,7 @@ const ( // ParsedTx is the tx infos parsed from events. type ParsedTx struct { + // max uint32 means there is no sdk.Msg corresponding to eth tx MsgIndex int // the following fields are parsed from events @@ -83,6 +86,8 @@ type ParsedTx struct { Amount *big.Int Recipient common.Address Sender common.Address + Nonce uint64 + Data []byte } // NewParsedTx initialize a ParsedTx @@ -176,6 +181,18 @@ func ParseTxResult(result *abci.ResponseDeliverTx, tx sdk.Tx) (*ParsedTxs, error p.Txs[i].GasUsed = gasLimit } } + + // fix msg indexes, because some eth txs indexed here don't have corresponding sdk.Msg + currMsgIndex := -1 + for _, tx := range p.Txs { + if tx.Type == 88 { + tx.MsgIndex = math.MaxUint32 + // todo: fix mapping as well + } else { + currMsgIndex++ + tx.MsgIndex = currMsgIndex + } + } return p, nil } @@ -371,6 +388,19 @@ func fillTxAttribute(tx *ParsedTx, key []byte, value []byte) error { if !success { return nil } + case "TxNonce": + nonce, err := strconv.ParseUint(string(value), 10, 64) + if err != nil { + return err + } + tx.Nonce = nonce + + case "TxData": + hexBytes, err := hexutil.Decode(string(value)) + if err != nil { + return err + } + tx.Data = hexBytes } return nil } diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index 5dece902cf..55feead317 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -688,7 +688,6 @@ func (k Keeper) CallEVMWithData( if gasLimit != nil { gasCap = gasLimit.Uint64() } - msg := ethtypes.NewMessage( from, contract, @@ -757,20 +756,12 @@ func (k Keeper) CallEVMWithData( if !noEthereumTxEvent { fmt.Println("88 tx", ethTxHash.Hex()) - txBytes, err := ethtypes.NewTx(ðtypes.DynamicFeeTx{ - ChainID: k.evmKeeper.ChainID(), - Nonce: nonce, - GasTipCap: msg.GasTipCap(), - GasFeeCap: msg.GasFeeCap(), - Gas: msg.Gas(), - To: msg.To(), - Value: msg.Value(), - Data: msg.Data(), - }).MarshalBinary() if err != nil { return nil, fmt.Errorf("failed to convert tx msg, err=%w", err) } - attrs = append(attrs, sdk.NewAttribute("TxBytes", hexutil.Encode(txBytes))) + attrs = append(attrs, sdk.NewAttribute("TxData", hexutil.Encode(msg.Data()))) + attrs = append(attrs, sdk.NewAttribute("TxNonce", fmt.Sprint(nonce))) + attrs = append(attrs, sdk.NewAttribute("TxHash", ethTxHash.Hex())) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( From f6cb6eb55bc0b4e6655c96f583cd0f7eeddf41ba Mon Sep 17 00:00:00 2001 From: skosito Date: Thu, 23 May 2024 19:26:27 +0200 Subject: [PATCH 06/25] cleanup --- x/fungible/keeper/evm.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index 55feead317..a6bb251402 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -755,14 +755,11 @@ func (k Keeper) CallEVMWithData( } if !noEthereumTxEvent { - fmt.Println("88 tx", ethTxHash.Hex()) if err != nil { return nil, fmt.Errorf("failed to convert tx msg, err=%w", err) } - attrs = append(attrs, sdk.NewAttribute("TxData", hexutil.Encode(msg.Data()))) - attrs = append(attrs, sdk.NewAttribute("TxNonce", fmt.Sprint(nonce))) - - attrs = append(attrs, sdk.NewAttribute("TxHash", ethTxHash.Hex())) + attrs = append(attrs, sdk.NewAttribute("TxData", hexutil.Encode(msg.Data()))) // adding txData for more info in rpc methods + attrs = append(attrs, sdk.NewAttribute("TxNonce", fmt.Sprint(nonce))) // adding nonce for more info in rpc methods ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( evmtypes.EventTypeEthereumTx, From 8f611cbb0f87edc83319710321fc1b090ff6885f Mon Sep 17 00:00:00 2001 From: skosito Date: Thu, 23 May 2024 19:31:54 +0200 Subject: [PATCH 07/25] cleanup --- rpc/types/events.go | 4 ++-- x/fungible/keeper/evm.go | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/rpc/types/events.go b/rpc/types/events.go index 3c67d78927..fef0bba498 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -183,14 +183,14 @@ func ParseTxResult(result *abci.ResponseDeliverTx, tx sdk.Tx) (*ParsedTxs, error } // fix msg indexes, because some eth txs indexed here don't have corresponding sdk.Msg - currMsgIndex := -1 + currMsgIndex := 0 for _, tx := range p.Txs { if tx.Type == 88 { tx.MsgIndex = math.MaxUint32 // todo: fix mapping as well } else { - currMsgIndex++ tx.MsgIndex = currMsgIndex + currMsgIndex++ } } return p, nil diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index a6bb251402..035419a1e7 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -755,9 +755,6 @@ func (k Keeper) CallEVMWithData( } if !noEthereumTxEvent { - if err != nil { - return nil, fmt.Errorf("failed to convert tx msg, err=%w", err) - } attrs = append(attrs, sdk.NewAttribute("TxData", hexutil.Encode(msg.Data()))) // adding txData for more info in rpc methods attrs = append(attrs, sdk.NewAttribute("TxNonce", fmt.Sprint(nonce))) // adding nonce for more info in rpc methods ctx.EventManager().EmitEvents(sdk.Events{ From 51761da48ab38e30a962813b562d0ff6058a5560 Mon Sep 17 00:00:00 2001 From: skosito Date: Tue, 28 May 2024 23:45:04 +0200 Subject: [PATCH 08/25] Modify rpc methods to include synthetic txs --- rpc/backend/blocks.go | 72 ++++++++++++++++--- rpc/backend/tracing.go | 122 +++----------------------------- rpc/backend/tx_info.go | 155 +++++++++++++++++++++++------------------ rpc/types/events.go | 32 ++++++++- rpc/types/types.go | 2 + rpc/types/utils.go | 6 +- 6 files changed, 194 insertions(+), 195 deletions(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index b2a5870a16..0df1e01d83 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -284,25 +284,79 @@ func (b *Backend) EthMsgsFromTendermintBlock( tx, err := b.clientCtx.TxConfig.TxDecoder()(tx) if err != nil { b.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error()) + // try to check if there is synthetic eth tx in tx result + res, additional, err := rpctypes.ParseTxBlockResult(txResults[i], nil, i, block.Height) + if err != nil || additional == nil || res == nil { + continue + } + recipient := additional.Recipient + t := ethtypes.NewTx(ðtypes.LegacyTx{ + Nonce: additional.Nonce, + Data: additional.Data, + Gas: additional.GasUsed, + To: &recipient, + GasPrice: nil, + Value: additional.Value, + V: big.NewInt(0), + R: big.NewInt(0), + S: big.NewInt(0), + }) + ethMsg := &evmtypes.MsgEthereumTx{} + err = ethMsg.FromEthereumTx(t) + if err != nil { + b.logger.Debug("can not create eth msg", err.Error()) + continue + } + ethMsg.Hash = additional.Hash.Hex() + ethMsg.From = additional.Sender.Hex() + result = append(result, ethMsg) + txsAdditional = append(txsAdditional, additional) continue } + + // assumption is that if regular ethermint msg is found in tx + // there should not be synthetic one as well + shouldCheckForSyntheticTx := true for _, msg := range tx.GetMsgs() { ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - res, additional, err := rpctypes.ParseTxBlockResult(txResults[i], tx, i, block.Height) - if err != nil || additional == nil || res == nil { - continue - } - ethMsg = &evmtypes.MsgEthereumTx{ - From: additional.Sender.Hex(), - Hash: additional.Hash.Hex(), - } - txsAdditional = append(txsAdditional, additional) + continue } else { + shouldCheckForSyntheticTx = false ethMsg.Hash = ethMsg.AsTransaction().Hash().Hex() + result = append(result, ethMsg) txsAdditional = append(txsAdditional, nil) } + } + + if shouldCheckForSyntheticTx { + // try to check if there is synthetic eth tx in tx result + res, additional, err := rpctypes.ParseTxBlockResult(txResults[i], tx, i, block.Height) + if err != nil || additional == nil || res == nil { + continue + } + recipient := additional.Recipient + t := ethtypes.NewTx(ðtypes.LegacyTx{ + Nonce: additional.Nonce, + Data: additional.Data, + Gas: additional.GasUsed, + To: &recipient, + GasPrice: nil, + Value: additional.Value, + V: big.NewInt(0), + R: big.NewInt(0), + S: big.NewInt(0), + }) + ethMsg := &evmtypes.MsgEthereumTx{} + err = ethMsg.FromEthereumTx(t) + if err != nil { + b.logger.Debug("can not create eth msg", err.Error()) + continue + } + ethMsg.Hash = additional.Hash.Hex() + ethMsg.From = additional.Sender.Hex() result = append(result, ethMsg) + txsAdditional = append(txsAdditional, additional) } } return result, txsAdditional diff --git a/rpc/backend/tracing.go b/rpc/backend/tracing.go index 2bed7dbce8..352acab3c3 100644 --- a/rpc/backend/tracing.go +++ b/rpc/backend/tracing.go @@ -18,13 +18,10 @@ package backend import ( "encoding/json" "fmt" - "math/big" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - ethtypes "github.com/ethereum/go-ethereum/core/types" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/pkg/errors" rpctypes "github.com/zeta-chain/zetacore/rpc/types" @@ -56,64 +53,21 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return nil, fmt.Errorf("block result not found for height %d", blk.Block.Height) } - // check tx index is not out of bound - // #nosec G701 txs number in block is always less than MaxUint32 - if uint32(len(blk.Block.Txs)) < transaction.TxIndex { - b.logger.Debug("tx index out of bounds", "index", transaction.TxIndex, "hash", hash.String(), "height", blk.Block.Height) - return nil, fmt.Errorf("transaction not included in block %v", blk.Block.Height) - } - var predecessors []*evmtypes.MsgEthereumTx - for i, txBz := range blk.Block.Txs[:transaction.TxIndex] { - tx, err := b.clientCtx.TxConfig.TxDecoder()(txBz) - if err != nil { - b.logger.Debug("failed to decode transaction in block", "height", blk.Block.Height, "error", err.Error()) - continue - } - - // get parsed eth txs from events from tx result - parsed, err := rpctypes.ParseTxResult(blockResult.TxsResults[i], tx) - if err != nil { - return nil, err - } - - for _, parsedTx := range parsed.Txs { - ethMsg := getMsgEthereumTxFromParsedTx(parsedTx, tx) - if ethMsg == nil { - continue - } - predecessors = append(predecessors, ethMsg) + msgs, _ := b.EthMsgsFromTendermintBlock(blk, blockResult) + var ethMsg *evmtypes.MsgEthereumTx + for _, m := range msgs { + if m.Hash == hash.Hex() { + ethMsg = m + break } + predecessors = append(predecessors, m) } - tx, err := b.clientCtx.TxConfig.TxDecoder()(blk.Block.Txs[transaction.TxIndex]) - if err != nil { - b.logger.Debug("tx not found", "hash", hash) - return nil, err - } - - // get parsed eth txs from events from tx result - parsed, err := rpctypes.ParseTxResult(blockResult.TxsResults[transaction.TxIndex], tx) - if err != nil { - return nil, err + if ethMsg == nil { + return nil, fmt.Errorf("tx not found in block %d", blk.Block.Height) } - // iterate parsed eth txs, if its type 88, recreate it and get MsgEthereumTx, otherwise pull it from sdk.Msgs - // when requested tx is found, break, no more predecessors - var ethMsg *evmtypes.MsgEthereumTx - for _, parsedTx := range parsed.Txs { - ethMsg = getMsgEthereumTxFromParsedTx(parsedTx, tx) - if parsedTx.Hash.Hex() == hash.Hex() { - if ethMsg == nil { - return nil, errors.New("error while parsing tx") - } - break - } - if ethMsg == nil { - continue - } - predecessors = append(predecessors, ethMsg) - } traceTxRequest := evmtypes.QueryTraceTxRequest{ Msg: ethMsg, Predecessors: predecessors, @@ -150,36 +104,6 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return decodedResult, nil } -func getMsgEthereumTxFromParsedTx(parsedTx rpctypes.ParsedTx, tx sdk.Tx) *evmtypes.MsgEthereumTx { - if parsedTx.Type == 88 { - recipient := parsedTx.Recipient - // TODO: is this ok? - t := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: parsedTx.Nonce, - Data: parsedTx.Data, - Gas: parsedTx.GasUsed, - To: &recipient, - GasPrice: nil, - Value: parsedTx.Amount, - V: big.NewInt(0), - R: big.NewInt(0), - S: big.NewInt(0), - }) - ethMsg := &evmtypes.MsgEthereumTx{} - err := ethMsg.FromEthereumTx(t) - if err != nil { - return nil - } - return ethMsg - } else { - ethMsg, ok := tx.GetMsgs()[parsedTx.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { - return nil - } - return ethMsg - } -} - // TraceBlock configures a new tracer according to the provided configuration, and // executes all the transactions contained within. The return value will be one item // per transaction, dependent on the requested tracer. @@ -200,31 +124,7 @@ func (b *Backend) TraceBlock(height rpctypes.BlockNumber, b.logger.Debug("block result not found", "height", block.Block.Height, "error", err.Error()) return nil, nil } - - txDecoder := b.clientCtx.TxConfig.TxDecoder() - - var txsMessages []*evmtypes.MsgEthereumTx - for i, tx := range txs { - if !rpctypes.TxSuccessOrExceedsBlockGasLimit(blockRes.TxsResults[i]) { - b.logger.Debug("invalid tx result code", "cosmos-hash", hexutil.Encode(tx.Hash())) - continue - } - - decodedTx, err := txDecoder(tx) - if err != nil { - b.logger.Error("failed to decode transaction", "hash", txs[i].Hash(), "error", err.Error()) - continue - } - - for _, msg := range decodedTx.GetMsgs() { - ethMessage, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { - // Just considers Ethereum transactions - continue - } - txsMessages = append(txsMessages, ethMessage) - } - } + msgs, _ := b.EthMsgsFromTendermintBlock(block, blockRes) // minus one to get the context at the beginning of the block contextHeight := height - 1 @@ -235,7 +135,7 @@ func (b *Backend) TraceBlock(height rpctypes.BlockNumber, ctxWithHeight := rpctypes.ContextWithHeight(int64(contextHeight)) traceBlockRequest := &evmtypes.QueryTraceBlockRequest{ - Txs: txsMessages, + Txs: msgs, TraceConfig: config, BlockNumber: block.Block.Height, BlockTime: block.Block.Time, diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 6195668a15..31ca9448ad 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -17,6 +17,7 @@ package backend import ( "fmt" + "math/big" errorsmod "cosmossdk.io/errors" tmrpcclient "github.com/cometbft/cometbft/rpc/client" @@ -29,6 +30,7 @@ import ( ethermint "github.com/evmos/ethermint/types" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/pkg/errors" + rpctypes "github.com/zeta-chain/zetacore/rpc/types" ) @@ -47,7 +49,10 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac tx, err := b.clientCtx.TxConfig.TxDecoder()(block.Block.Txs[res.TxIndex]) if err != nil { - return nil, err + // only return error if tx can not contain synthetic tx + if additional == nil { + return nil, err + } } blockRes, err := b.TendermintBlockResultByNumber(&block.Block.Height) @@ -56,31 +61,28 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac return nil, nil } - // the `res.MsgIndex` is inferred from tx index, should be within the bound. - msg, ok := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { - if additional == nil { - return nil, err - } - msg = &evmtypes.MsgEthereumTx{ - Hash: hexTx, - From: additional.Sender.Hex(), + var msg *evmtypes.MsgEthereumTx + if tx != nil { + // the `res.MsgIndex` is inferred from tx index, should be within the bound. + ethermintMsg, ok := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) + if !ok { + return nil, errors.New("can not find msg") } - } else { - additional = nil + msg = ethermintMsg } - if res.EthTxIndex == -1 { - // Fallback to find tx index by iterating all valid eth transactions + if msg == nil || res.EthTxIndex == -1 { + // Fallback to find tx by iterating all valid eth transactions msgs, _ := b.EthMsgsFromTendermintBlock(block, blockRes) for i := range msgs { if msgs[i].Hash == hexTx { // #nosec G701 always in range - res.EthTxIndex = int32(i) + msg = msgs[i] break } } } + // if we still unable to find the eth tx index, return error, shouldn't happen. if res.EthTxIndex == -1 && additional == nil { return nil, errors.New("can't find index of ethereum tx") @@ -92,7 +94,13 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac baseFee, err := b.BaseFee(blockRes) if err != nil { // handle the error for pruned node. - b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", blockRes.Height, "error", err) + b.logger.Error( + "failed to fetch Base Fee from prunned block. Check node prunning configuration", + "height", + blockRes.Height, + "error", + err, + ) } return rpctypes.NewTransactionFromMsg( @@ -151,7 +159,6 @@ func (b *Backend) getTransactionByHashPending(txHash common.Hash) (*rpctypes.RPC func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) { hexTx := hash.Hex() b.logger.Debug("eth_getTransactionReceipt", "hash", hexTx) - res, additional, err := b.GetTxByEthHash(hash) if err != nil { b.logger.Debug("tx not found", "hash", hexTx, "error", err.Error()) @@ -163,15 +170,15 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ b.logger.Debug("block not found", "height", res.Height, "error", err.Error()) return nil, nil } - tx, err := b.clientCtx.TxConfig.TxDecoder()(resBlock.Block.Txs[res.TxIndex]) - if err != nil { - b.logger.Debug("decoding failed", "error", err.Error()) - return nil, fmt.Errorf("failed to decode tx: %w", err) - } var txData evmtypes.TxData var ethMsg *evmtypes.MsgEthereumTx if additional == nil { + tx, err := b.clientCtx.TxConfig.TxDecoder()(resBlock.Block.Txs[res.TxIndex]) + if err != nil { + b.logger.Debug("decoding failed", "error", err.Error()) + return nil, fmt.Errorf("failed to decode tx: %w", err) + } ethMsg = tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) txData, err = evmtypes.UnpackTxData(ethMsg.Data) @@ -180,10 +187,26 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, err } } else { - ethMsg = &evmtypes.MsgEthereumTx{ - From: additional.Sender.Hex(), - Hash: additional.Hash.Hex(), + recipient := additional.Recipient + t := ethtypes.NewTx(ðtypes.LegacyTx{ + Nonce: additional.Nonce, + Data: additional.Data, + Gas: additional.GasUsed, + To: &recipient, + GasPrice: nil, + Value: additional.Value, + V: big.NewInt(0), + R: big.NewInt(0), + S: big.NewInt(0), + }) + ethMsg = &evmtypes.MsgEthereumTx{} + err = ethMsg.FromEthereumTx(t) + if err != nil { + b.logger.Error("can not create eth msg", err.Error()) + return nil, err } + ethMsg.Hash = additional.Hash.Hex() + ethMsg.From = additional.Sender.Hex() } cumulativeGasUsed := uint64(0) @@ -211,13 +234,13 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ } var from common.Address - if ethMsg.Data != nil { + if additional != nil { + from = common.HexToAddress(ethMsg.From) + } else if ethMsg.Data != nil { from, err = ethMsg.GetSender(chainID.ToInt()) if err != nil { return nil, err } - } else if additional != nil { - from = common.HexToAddress(ethMsg.From) } else { return nil, errors.New("failed to parse receipt") } @@ -240,6 +263,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ } } } + // return error if still unable to find the eth tx index if res.EthTxIndex == -1 { if additional != nil { @@ -309,9 +333,11 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ } // GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index. -func (b *Backend) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) { +func (b *Backend) GetTransactionByBlockHashAndIndex( + hash common.Hash, + idx hexutil.Uint, +) (*rpctypes.RPCTransaction, error) { b.logger.Debug("eth_getTransactionByBlockHashAndIndex", "hash", hash.Hex(), "index", idx) - sc, ok := b.clientCtx.Client.(tmrpcclient.SignClient) if !ok { return nil, errors.New("invalid rpc client") @@ -331,7 +357,10 @@ func (b *Backend) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexuti } // GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index. -func (b *Backend) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) { +func (b *Backend) GetTransactionByBlockNumberAndIndex( + blockNum rpctypes.BlockNumber, + idx hexutil.Uint, +) (*rpctypes.RPCTransaction, error) { b.logger.Debug("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx) block, err := b.TendermintBlockByNumber(blockNum) @@ -371,7 +400,10 @@ func (b *Backend) GetTxByEthHash(hash common.Hash) (*ethermint.TxResult, *rpctyp } // GetTxByTxIndex uses `/tx_query` to find transaction by tx index of valid ethereum txs -func (b *Backend) GetTxByTxIndex(height int64, index uint) (*ethermint.TxResult, *rpctypes.TxResultAdditionalFields, error) { +func (b *Backend) GetTxByTxIndex( + height int64, + index uint, +) (*ethermint.TxResult, *rpctypes.TxResultAdditionalFields, error) { if b.indexer != nil { // #nosec G701 always in range txRes, err := b.indexer.GetByBlockAndIndex(height, int32(index)) @@ -396,7 +428,10 @@ func (b *Backend) GetTxByTxIndex(height int64, index uint) (*ethermint.TxResult, } // queryTendermintTxIndexer query tx in tendermint tx indexer -func (b *Backend) queryTendermintTxIndexer(query string, txGetter func(*rpctypes.ParsedTxs) *rpctypes.ParsedTx) (*ethermint.TxResult, *rpctypes.TxResultAdditionalFields, error) { +func (b *Backend) queryTendermintTxIndexer( + query string, + txGetter func(*rpctypes.ParsedTxs) *rpctypes.ParsedTx, +) (*ethermint.TxResult, *rpctypes.TxResultAdditionalFields, error) { resTxs, err := b.clientCtx.Client.TxSearch(b.ctx, query, false, nil, nil, "") if err != nil { return nil, nil, err @@ -422,52 +457,34 @@ func (b *Backend) queryTendermintTxIndexer(query string, txGetter func(*rpctypes } // GetTransactionByBlockAndIndex is the common code shared by `GetTransactionByBlockNumberAndIndex` and `GetTransactionByBlockHashAndIndex`. -func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) { +func (b *Backend) GetTransactionByBlockAndIndex( + block *tmrpctypes.ResultBlock, + idx hexutil.Uint, +) (*rpctypes.RPCTransaction, error) { blockRes, err := b.TendermintBlockResultByNumber(&block.Block.Height) if err != nil { return nil, nil } - var msg *evmtypes.MsgEthereumTx - // find in tx indexer - // #nosec G701 always in range - res, additional, 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.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx) - return nil, nil - } - - var ok bool - // msgIndex is inferred from tx events, should be within bound. - msg, ok = tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { - if additional == nil { - b.logger.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx) - return nil, nil - } - msg = &evmtypes.MsgEthereumTx{ - Hash: additional.Hash.Hex(), - From: additional.Sender.Hex(), - } - } - } else { - // #nosec G701 always in range - i := int(idx) - ethMsgs, _ := b.EthMsgsFromTendermintBlock(block, blockRes) - if i >= len(ethMsgs) { - b.logger.Debug("block txs index out of bound", "index", i) - return nil, nil - } - - msg = ethMsgs[i] + i := int(idx) + ethMsgs, additionals := b.EthMsgsFromTendermintBlock(block, blockRes) + if i >= len(ethMsgs) { + b.logger.Debug("block txs index out of bound", "index", i) + return nil, nil } + msg := ethMsgs[i] + additional := additionals[i] baseFee, err := b.BaseFee(blockRes) if err != nil { // handle the error for pruned node. - b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", block.Block.Height, "error", err) + b.logger.Error( + "failed to fetch Base Fee from prunned block. Check node prunning configuration", + "height", + block.Block.Height, + "error", + err, + ) } return rpctypes.NewTransactionFromMsg( diff --git a/rpc/types/events.go b/rpc/types/events.go index fef0bba498..b54fae4c2d 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -16,10 +16,12 @@ package types import ( + "encoding/base64" "fmt" "math" "math/big" "strconv" + "strings" abci "github.com/cometbft/cometbft/abci/types" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" @@ -268,6 +270,8 @@ func ParseTxBlockResult(txResult *abci.ResponseDeliverTx, tx sdk.Tx, txIndex int Recipient: parsedTx.Recipient, Sender: parsedTx.Sender, GasUsed: parsedTx.GasUsed, + Data: parsedTx.Data, + Nonce: parsedTx.Nonce, }, nil } return ðermint.TxResult{ @@ -351,8 +355,8 @@ func (p *ParsedTxs) AccumulativeGasUsed(msgIndex int) (result uint64) { // fillTxAttribute parse attributes by name, less efficient than hardcode the index, but more stable against event // format changes. -func fillTxAttribute(tx *ParsedTx, key []byte, value []byte) error { - switch string(key) { +func fillTxAttribute(tx *ParsedTx, key, value string) error { + switch key { case evmtypes.AttributeKeyEthereumTxHash: tx.Hash = common.HexToHash(string(value)) case evmtypes.AttributeKeyTxIndex: @@ -406,10 +410,32 @@ func fillTxAttribute(tx *ParsedTx, key []byte, value []byte) error { } func fillTxAttributes(tx *ParsedTx, attrs []abci.EventAttribute) error { + isLegacyAttrs := isLegacyAttrEncoding(attrs) for _, attr := range attrs { - if err := fillTxAttribute(tx, []byte(attr.Key), []byte(attr.Value)); err != nil { + if isLegacyAttrs { + decKey, err := base64.StdEncoding.DecodeString(attr.Key) + if err == nil { + attr.Key = string(decKey) + } + decValue, err := base64.StdEncoding.DecodeString(attr.Value) + if err == nil { + attr.Value = string(decValue) + } + } + + if err := fillTxAttribute(tx, attr.Key, attr.Value); err != nil { return err } } return nil } + +func isLegacyAttrEncoding(attrs []abci.EventAttribute) bool { + for _, attr := range attrs { + if strings.Contains(attr.Key, "==") || strings.Contains(attr.Value, "==") { + return true + } + } + + return false +} diff --git a/rpc/types/types.go b/rpc/types/types.go index 62d4b343a9..907eff4740 100644 --- a/rpc/types/types.go +++ b/rpc/types/types.go @@ -53,6 +53,8 @@ type TxResultAdditionalFields struct { Recipient common.Address `json:"recipient"` Sender common.Address `json:"sender"` GasUsed uint64 `json:"gasUsed"` + Nonce uint64 `json:"nonce"` + Data []byte `json:"data"` } // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction diff --git a/rpc/types/utils.go b/rpc/types/utils.go index b142e18240..56912d6eb7 100644 --- a/rpc/types/utils.go +++ b/rpc/types/utils.go @@ -170,10 +170,10 @@ func NewTransactionFromMsg( chainID *big.Int, txAdditional *TxResultAdditionalFields, ) (*RPCTransaction, error) { - tx := msg.AsTransaction() - if tx == nil { + if txAdditional != nil { return NewRPCTransactionFromIncompleteMsg(msg, blockHash, blockNumber, index, baseFee, chainID, txAdditional) } + tx := msg.AsTransaction() return NewRPCTransaction(tx, blockHash, blockNumber, index, baseFee, chainID) } @@ -256,7 +256,7 @@ func NewRPCTransactionFromIncompleteMsg( GasPrice: (*hexutil.Big)(baseFee), Hash: common.HexToHash(msg.Hash), Input: []byte{}, - Nonce: 0, // TODO: get nonce for "from" from ethermint + Nonce: hexutil.Uint64(txAdditional.Nonce), // TODO: get nonce for "from" from ethermint To: to, Value: (*hexutil.Big)(txAdditional.Value), V: nil, From c0b889152467a63adce07c5cdb7ffa28b9e9910d Mon Sep 17 00:00:00 2001 From: skosito Date: Tue, 28 May 2024 23:49:05 +0200 Subject: [PATCH 09/25] Add todos --- rpc/backend/blocks.go | 1 + rpc/types/utils.go | 1 + 2 files changed, 2 insertions(+) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 0df1e01d83..086e552e64 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -263,6 +263,7 @@ func (b *Backend) BlockNumberFromTendermintByHash(blockHash common.Hash) (*big.I // EthMsgsFromTendermintBlock returns all real MsgEthereumTxs from a // Tendermint block. It also ensures consistency over the correct txs indexes // across RPC endpoints +// TODO: check if additionals array can be removed func (b *Backend) EthMsgsFromTendermintBlock( resBlock *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults, diff --git a/rpc/types/utils.go b/rpc/types/utils.go index 56912d6eb7..b24b3d8da0 100644 --- a/rpc/types/utils.go +++ b/rpc/types/utils.go @@ -170,6 +170,7 @@ func NewTransactionFromMsg( chainID *big.Int, txAdditional *TxResultAdditionalFields, ) (*RPCTransaction, error) { + // TODO: check if this condition can be removed if txAdditional != nil { return NewRPCTransactionFromIncompleteMsg(msg, blockHash, blockNumber, index, baseFee, chainID, txAdditional) } From 567002374748b19705b9ef62dd5e659c2de70f40 Mon Sep 17 00:00:00 2001 From: skosito Date: Tue, 28 May 2024 23:56:56 +0200 Subject: [PATCH 10/25] cleanup --- rpc/backend/blocks.go | 78 +++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 086e552e64..1ac69d169d 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -22,8 +22,10 @@ import ( "math/big" "strconv" + abci "github.com/cometbft/cometbft/abci/types" tmrpcclient "github.com/cometbft/cometbft/rpc/client" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" + tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" "github.com/ethereum/go-ethereum/common" @@ -286,30 +288,10 @@ func (b *Backend) EthMsgsFromTendermintBlock( if err != nil { b.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error()) // try to check if there is synthetic eth tx in tx result - res, additional, err := rpctypes.ParseTxBlockResult(txResults[i], nil, i, block.Height) - if err != nil || additional == nil || res == nil { + ethMsg, additional := b.parseSyntheticTx(txResults, i, tx, block) + if ethMsg == nil { continue } - recipient := additional.Recipient - t := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: additional.Nonce, - Data: additional.Data, - Gas: additional.GasUsed, - To: &recipient, - GasPrice: nil, - Value: additional.Value, - V: big.NewInt(0), - R: big.NewInt(0), - S: big.NewInt(0), - }) - ethMsg := &evmtypes.MsgEthereumTx{} - err = ethMsg.FromEthereumTx(t) - if err != nil { - b.logger.Debug("can not create eth msg", err.Error()) - continue - } - ethMsg.Hash = additional.Hash.Hex() - ethMsg.From = additional.Sender.Hex() result = append(result, ethMsg) txsAdditional = append(txsAdditional, additional) continue @@ -332,30 +314,10 @@ func (b *Backend) EthMsgsFromTendermintBlock( if shouldCheckForSyntheticTx { // try to check if there is synthetic eth tx in tx result - res, additional, err := rpctypes.ParseTxBlockResult(txResults[i], tx, i, block.Height) - if err != nil || additional == nil || res == nil { - continue - } - recipient := additional.Recipient - t := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: additional.Nonce, - Data: additional.Data, - Gas: additional.GasUsed, - To: &recipient, - GasPrice: nil, - Value: additional.Value, - V: big.NewInt(0), - R: big.NewInt(0), - S: big.NewInt(0), - }) - ethMsg := &evmtypes.MsgEthereumTx{} - err = ethMsg.FromEthereumTx(t) - if err != nil { - b.logger.Debug("can not create eth msg", err.Error()) + ethMsg, additional := b.parseSyntheticTx(txResults, i, tx, block) + if ethMsg == nil { continue } - ethMsg.Hash = additional.Hash.Hex() - ethMsg.From = additional.Sender.Hex() result = append(result, ethMsg) txsAdditional = append(txsAdditional, additional) } @@ -363,6 +325,34 @@ func (b *Backend) EthMsgsFromTendermintBlock( return result, txsAdditional } +func (b *Backend) parseSyntheticTx(txResults []*abci.ResponseDeliverTx, i int, tx sdk.Tx, block *tmtypes.Block) (*evmtypes.MsgEthereumTx, *rpctypes.TxResultAdditionalFields) { + res, additional, err := rpctypes.ParseTxBlockResult(txResults[i], tx, i, block.Height) + if err != nil || additional == nil || res == nil { + return nil, nil + } + recipient := additional.Recipient + t := ethtypes.NewTx(ðtypes.LegacyTx{ + Nonce: additional.Nonce, + Data: additional.Data, + Gas: additional.GasUsed, + To: &recipient, + GasPrice: nil, + Value: additional.Value, + V: big.NewInt(0), + R: big.NewInt(0), + S: big.NewInt(0), + }) + ethMsg := &evmtypes.MsgEthereumTx{} + err = ethMsg.FromEthereumTx(t) + if err != nil { + b.logger.Debug("can not create eth msg", err.Error()) + return nil, nil + } + ethMsg.Hash = additional.Hash.Hex() + ethMsg.From = additional.Sender.Hex() + return ethMsg, additional +} + // HeaderByNumber returns the block header identified by height. func (b *Backend) HeaderByNumber(blockNum rpctypes.BlockNumber) (*ethtypes.Header, error) { resBlock, err := b.TendermintBlockByNumber(blockNum) From 299fd84ddf8d04ecc222fa32118b551653768880 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 00:00:13 +0200 Subject: [PATCH 11/25] cleanup --- rpc/backend/tx_info.go | 62 +++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 31ca9448ad..783bfc12b7 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -47,37 +47,61 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac return nil, err } - tx, err := b.clientCtx.TxConfig.TxDecoder()(block.Block.Txs[res.TxIndex]) + resBlock, err := b.TendermintBlockByNumber(rpctypes.BlockNumber(res.Height)) if err != nil { - // only return error if tx can not contain synthetic tx - if additional == nil { - return nil, err - } + b.logger.Debug("block not found", "height", res.Height, "error", err.Error()) + return nil, nil } - blockRes, err := b.TendermintBlockResultByNumber(&block.Block.Height) + blockRes, err := b.TendermintBlockResultByNumber(&res.Height) if err != nil { - b.logger.Debug("block result not found", "height", block.Block.Height, "error", err.Error()) + b.logger.Debug("failed to retrieve block results", "height", res.Height, "error", err.Error()) return nil, nil } - var msg *evmtypes.MsgEthereumTx - if tx != nil { - // the `res.MsgIndex` is inferred from tx index, should be within the bound. - ethermintMsg, ok := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { - return nil, errors.New("can not find msg") + var ethMsg *evmtypes.MsgEthereumTx + if additional == nil { + tx, err := b.clientCtx.TxConfig.TxDecoder()(resBlock.Block.Txs[res.TxIndex]) + if err != nil { + b.logger.Debug("decoding failed", "error", err.Error()) + return nil, fmt.Errorf("failed to decode tx: %w", err) + } + ethMsg = tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) + + if err != nil { + b.logger.Error("failed to unpack tx data", "error", err.Error()) + return nil, err + } + } else { + recipient := additional.Recipient + t := ethtypes.NewTx(ðtypes.LegacyTx{ + Nonce: additional.Nonce, + Data: additional.Data, + Gas: additional.GasUsed, + To: &recipient, + GasPrice: nil, + Value: additional.Value, + V: big.NewInt(0), + R: big.NewInt(0), + S: big.NewInt(0), + }) + ethMsg = &evmtypes.MsgEthereumTx{} + err = ethMsg.FromEthereumTx(t) + if err != nil { + b.logger.Error("can not create eth msg", err.Error()) + return nil, err } - msg = ethermintMsg + ethMsg.Hash = additional.Hash.Hex() + ethMsg.From = additional.Sender.Hex() } - if msg == nil || res.EthTxIndex == -1 { - // Fallback to find tx by iterating all valid eth transactions - msgs, _ := b.EthMsgsFromTendermintBlock(block, blockRes) + if res.EthTxIndex == -1 { + // Fallback to find tx index by iterating all valid eth transactions + msgs, _ := b.EthMsgsFromTendermintBlock(resBlock, blockRes) for i := range msgs { if msgs[i].Hash == hexTx { // #nosec G701 always in range - msg = msgs[i] + res.EthTxIndex = int32(i) break } } @@ -104,7 +128,7 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac } return rpctypes.NewTransactionFromMsg( - msg, + ethMsg, common.BytesToHash(block.BlockID.Hash.Bytes()), // #nosec G701 always positive uint64(res.Height), From 531052e88d06983f28b881ee618946629d9c77fd Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 00:13:45 +0200 Subject: [PATCH 12/25] changelog --- changelog.md | 1 + rpc/backend/blocks.go | 2 +- rpc/backend/tx_info.go | 7 +------ 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 49cf98f8f3..23ad1985ea 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ * [2152](https://github.com/zeta-chain/node/pull/2152) - custom priority nonce mempool * [2113](https://github.com/zeta-chain/node/pull/2113) - add zetaclientd-supervisor process * [2154](https://github.com/zeta-chain/node/pull/2154) - add `ibccrosschain` module +* [2282](https://github.com/zeta-chain/node/pull/2282) - modify rpc methods to include synthetic txs ### Refactor diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 1ac69d169d..e6199e65de 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -345,7 +345,7 @@ func (b *Backend) parseSyntheticTx(txResults []*abci.ResponseDeliverTx, i int, t ethMsg := &evmtypes.MsgEthereumTx{} err = ethMsg.FromEthereumTx(t) if err != nil { - b.logger.Debug("can not create eth msg", err.Error()) + b.logger.Error("can not create eth msg", err.Error()) return nil, nil } ethMsg.Hash = additional.Hash.Hex() diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 783bfc12b7..11946b7d05 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -42,11 +42,6 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac return b.getTransactionByHashPending(txHash) } - block, err := b.TendermintBlockByNumber(rpctypes.BlockNumber(res.Height)) - if err != nil { - return nil, err - } - resBlock, err := b.TendermintBlockByNumber(rpctypes.BlockNumber(res.Height)) if err != nil { b.logger.Debug("block not found", "height", res.Height, "error", err.Error()) @@ -129,7 +124,7 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac return rpctypes.NewTransactionFromMsg( ethMsg, - common.BytesToHash(block.BlockID.Hash.Bytes()), + common.BytesToHash(resBlock.BlockID.Hash.Bytes()), // #nosec G701 always positive uint64(res.Height), // #nosec G701 always positive From 9a43e437a8de1a8e4a1dec34f403333245a1d919 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 00:19:08 +0200 Subject: [PATCH 13/25] comments --- x/fungible/keeper/evm.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index 9c58f9b096..1b8a9494aa 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -788,8 +788,10 @@ func (k Keeper) CallEVMWithData( } if !noEthereumTxEvent { - attrs = append(attrs, sdk.NewAttribute("TxData", hexutil.Encode(msg.Data()))) // adding txData for more info in rpc methods - attrs = append(attrs, sdk.NewAttribute("TxNonce", fmt.Sprint(nonce))) // adding nonce for more info in rpc methods + // adding txData for more info in rpc methods in order to parse synthetic txs + attrs = append(attrs, sdk.NewAttribute("TxData", hexutil.Encode(msg.Data()))) + // adding nonce for more info in rpc methods in order to parse synthetic txs + attrs = append(attrs, sdk.NewAttribute("TxNonce", fmt.Sprint(nonce))) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( evmtypes.EventTypeEthereumTx, From da06e6035e1c3510804f84d43f4601db9e847e8b Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 00:25:47 +0200 Subject: [PATCH 14/25] refactor duplicate code --- rpc/backend/blocks.go | 10 +++++--- rpc/backend/tx_info.go | 58 +++++++++++------------------------------- 2 files changed, 22 insertions(+), 46 deletions(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 92a31a6eaa..dfbb92cdfb 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -342,6 +342,10 @@ func (b *Backend) parseSyntheticTx(txResults []*abci.ResponseDeliverTx, i int, t if err != nil || additional == nil || res == nil { return nil, nil } + return b.parseSyntethicTxFromAdditionalFields(additional), additional +} + +func (b *Backend) parseSyntethicTxFromAdditionalFields(additional *rpctypes.TxResultAdditionalFields) *evmtypes.MsgEthereumTx { recipient := additional.Recipient t := ethtypes.NewTx(ðtypes.LegacyTx{ Nonce: additional.Nonce, @@ -355,14 +359,14 @@ func (b *Backend) parseSyntheticTx(txResults []*abci.ResponseDeliverTx, i int, t S: big.NewInt(0), }) ethMsg := &evmtypes.MsgEthereumTx{} - err = ethMsg.FromEthereumTx(t) + err := ethMsg.FromEthereumTx(t) if err != nil { b.logger.Error("can not create eth msg", err.Error()) - return nil, nil + return nil } ethMsg.Hash = additional.Hash.Hex() ethMsg.From = additional.Sender.Hex() - return ethMsg, additional + return ethMsg } // HeaderByNumber returns the block header identified by height. diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 11946b7d05..d3828a5f8c 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -17,7 +17,6 @@ package backend import ( "fmt" - "math/big" errorsmod "cosmossdk.io/errors" tmrpcclient "github.com/cometbft/cometbft/rpc/client" @@ -62,32 +61,16 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac return nil, fmt.Errorf("failed to decode tx: %w", err) } ethMsg = tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) - - if err != nil { - b.logger.Error("failed to unpack tx data", "error", err.Error()) - return nil, err + if ethMsg == nil { + b.logger.Error("failed to get eth msg") + return nil, fmt.Errorf("failed to get eth msg") } } else { - recipient := additional.Recipient - t := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: additional.Nonce, - Data: additional.Data, - Gas: additional.GasUsed, - To: &recipient, - GasPrice: nil, - Value: additional.Value, - V: big.NewInt(0), - R: big.NewInt(0), - S: big.NewInt(0), - }) - ethMsg = &evmtypes.MsgEthereumTx{} - err = ethMsg.FromEthereumTx(t) - if err != nil { - b.logger.Error("can not create eth msg", err.Error()) - return nil, err + ethMsg = b.parseSyntethicTxFromAdditionalFields(additional) + if ethMsg == nil { + b.logger.Error("failed to parse tx") + return nil, fmt.Errorf("failed to parse tx") } - ethMsg.Hash = additional.Hash.Hex() - ethMsg.From = additional.Sender.Hex() } if res.EthTxIndex == -1 { @@ -199,6 +182,10 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, fmt.Errorf("failed to decode tx: %w", err) } ethMsg = tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) + if ethMsg == nil { + b.logger.Error("failed to get eth msg") + return nil, fmt.Errorf("failed to get eth msg") + } txData, err = evmtypes.UnpackTxData(ethMsg.Data) if err != nil { @@ -206,26 +193,11 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, err } } else { - recipient := additional.Recipient - t := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: additional.Nonce, - Data: additional.Data, - Gas: additional.GasUsed, - To: &recipient, - GasPrice: nil, - Value: additional.Value, - V: big.NewInt(0), - R: big.NewInt(0), - S: big.NewInt(0), - }) - ethMsg = &evmtypes.MsgEthereumTx{} - err = ethMsg.FromEthereumTx(t) - if err != nil { - b.logger.Error("can not create eth msg", err.Error()) - return nil, err + ethMsg = b.parseSyntethicTxFromAdditionalFields(additional) + if ethMsg == nil { + b.logger.Error("failed to parse tx") + return nil, fmt.Errorf("failed to parse tx") } - ethMsg.Hash = additional.Hash.Hex() - ethMsg.From = additional.Sender.Hex() } cumulativeGasUsed := uint64(0) From 85f8bf8e9956b92149f703da30685aa1cb314d90 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 00:39:38 +0200 Subject: [PATCH 15/25] make generate --- rpc/backend/blocks.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index dfbb92cdfb..0e83f61255 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -337,7 +337,12 @@ func (b *Backend) EthMsgsFromTendermintBlock( return result, txsAdditional } -func (b *Backend) parseSyntheticTx(txResults []*abci.ResponseDeliverTx, i int, tx sdk.Tx, block *tmtypes.Block) (*evmtypes.MsgEthereumTx, *rpctypes.TxResultAdditionalFields) { +func (b *Backend) parseSyntheticTx( + txResults []*abci.ResponseDeliverTx, + i int, + tx sdk.Tx, + block *tmtypes.Block, +) (*evmtypes.MsgEthereumTx, *rpctypes.TxResultAdditionalFields) { res, additional, err := rpctypes.ParseTxBlockResult(txResults[i], tx, i, block.Height) if err != nil || additional == nil || res == nil { return nil, nil @@ -345,7 +350,9 @@ func (b *Backend) parseSyntheticTx(txResults []*abci.ResponseDeliverTx, i int, t return b.parseSyntethicTxFromAdditionalFields(additional), additional } -func (b *Backend) parseSyntethicTxFromAdditionalFields(additional *rpctypes.TxResultAdditionalFields) *evmtypes.MsgEthereumTx { +func (b *Backend) parseSyntethicTxFromAdditionalFields( + additional *rpctypes.TxResultAdditionalFields, +) *evmtypes.MsgEthereumTx { recipient := additional.Recipient t := ethtypes.NewTx(ðtypes.LegacyTx{ Nonce: additional.Nonce, From 51d22a2afa8eff40b8c448e207e1f8ad1199934f Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 00:47:50 +0200 Subject: [PATCH 16/25] lint fixes --- rpc/backend/blocks.go | 4 +--- rpc/backend/tracing.go | 2 +- rpc/backend/tx_info.go | 1 + rpc/types/events.go | 20 ++++++++++---------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 0e83f61255..a88987e115 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -314,9 +314,7 @@ func (b *Backend) EthMsgsFromTendermintBlock( shouldCheckForSyntheticTx := true for _, msg := range tx.GetMsgs() { ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { - continue - } else { + if ok { shouldCheckForSyntheticTx = false ethMsg.Hash = ethMsg.AsTransaction().Hash().Hex() result = append(result, ethMsg) diff --git a/rpc/backend/tracing.go b/rpc/backend/tracing.go index 1998733ff1..84a78dc6c7 100644 --- a/rpc/backend/tracing.go +++ b/rpc/backend/tracing.go @@ -54,7 +54,7 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi return nil, fmt.Errorf("block result not found for height %d", blk.Block.Height) } - var predecessors []*evmtypes.MsgEthereumTx + predecessors := []*evmtypes.MsgEthereumTx{} msgs, _ := b.EthMsgsFromTendermintBlock(blk, blockResult) var ethMsg *evmtypes.MsgEthereumTx for _, m := range msgs { diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index d3828a5f8c..601ae89b4d 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -457,6 +457,7 @@ func (b *Backend) GetTransactionByBlockAndIndex( return nil, nil } + // #nosec G701 always in range i := int(idx) ethMsgs, additionals := b.EthMsgsFromTendermintBlock(block, blockRes) if i >= len(ethMsgs) { diff --git a/rpc/types/events.go b/rpc/types/events.go index d7a4037018..c9d20c093c 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -377,16 +377,16 @@ func (p *ParsedTxs) AccumulativeGasUsed(msgIndex int) (result uint64) { func fillTxAttribute(tx *ParsedTx, key, value string) error { switch key { case evmtypes.AttributeKeyEthereumTxHash: - tx.Hash = common.HexToHash(string(value)) + tx.Hash = common.HexToHash(value) case evmtypes.AttributeKeyTxIndex: - txIndex, err := strconv.ParseUint(string(value), 10, 31) + txIndex, err := strconv.ParseUint(value, 10, 31) if err != nil { return err } // #nosec G701 always in range tx.EthTxIndex = int32(txIndex) case evmtypes.AttributeKeyTxGasUsed: - gasUsed, err := strconv.ParseUint(string(value), 10, 64) + gasUsed, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } @@ -394,32 +394,32 @@ func fillTxAttribute(tx *ParsedTx, key, value string) error { case evmtypes.AttributeKeyEthereumTxFailed: tx.Failed = len(value) > 0 case SenderType: - tx.Sender = common.HexToAddress(string(value)) + tx.Sender = common.HexToAddress(value) case evmtypes.AttributeKeyRecipient: - tx.Recipient = common.HexToAddress(string(value)) + tx.Recipient = common.HexToAddress(value) case evmtypes.AttributeKeyTxHash: - tx.TxHash = string(value) + tx.TxHash = value case evmtypes.AttributeKeyTxType: - txType, err := strconv.ParseUint(string(value), 10, 31) + txType, err := strconv.ParseUint(value, 10, 31) if err != nil { return err } tx.Type = txType case AmountType: var success bool - tx.Amount, success = big.NewInt(0).SetString(string(value), 10) + tx.Amount, success = big.NewInt(0).SetString(value, 10) if !success { return nil } case "TxNonce": - nonce, err := strconv.ParseUint(string(value), 10, 64) + nonce, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } tx.Nonce = nonce case "TxData": - hexBytes, err := hexutil.Decode(string(value)) + hexBytes, err := hexutil.Decode(value) if err != nil { return err } From 51f265ad3b5cf1ae09d645e9e50ff1d6a26aad69 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 00:52:46 +0200 Subject: [PATCH 17/25] cleanup --- rpc/backend/blocks.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index a88987e115..0ed6c2a87f 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -274,7 +274,7 @@ func (b *Backend) BlockNumberFromTendermintByHash(blockHash common.Hash) (*big.I return big.NewInt(resBlock.Block.Height), nil } -// EthMsgsFromTendermintBlock returns all real MsgEthereumTxs from a +// EthMsgsFromTendermintBlock returns all real and synthetic MsgEthereumTxs from a // Tendermint block. It also ensures consistency over the correct txs indexes // across RPC endpoints // TODO: check if additionals array can be removed @@ -300,7 +300,7 @@ func (b *Backend) EthMsgsFromTendermintBlock( if err != nil { b.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error()) // try to check if there is synthetic eth tx in tx result - ethMsg, additional := b.parseSyntheticTx(txResults, i, tx, block) + ethMsg, additional := b.parseSyntheticTxFromBlockResults(txResults, i, tx, block) if ethMsg == nil { continue } @@ -324,7 +324,7 @@ func (b *Backend) EthMsgsFromTendermintBlock( if shouldCheckForSyntheticTx { // try to check if there is synthetic eth tx in tx result - ethMsg, additional := b.parseSyntheticTx(txResults, i, tx, block) + ethMsg, additional := b.parseSyntheticTxFromBlockResults(txResults, i, tx, block) if ethMsg == nil { continue } @@ -335,7 +335,7 @@ func (b *Backend) EthMsgsFromTendermintBlock( return result, txsAdditional } -func (b *Backend) parseSyntheticTx( +func (b *Backend) parseSyntheticTxFromBlockResults( txResults []*abci.ResponseDeliverTx, i int, tx sdk.Tx, From e9408a454aa8a789983170c119213cce4146fc8c Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 01:24:32 +0200 Subject: [PATCH 18/25] link issue to todo --- rpc/backend/blocks.go | 2 +- rpc/types/utils.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 0ed6c2a87f..a32b3eadbb 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -277,7 +277,7 @@ func (b *Backend) BlockNumberFromTendermintByHash(blockHash common.Hash) (*big.I // EthMsgsFromTendermintBlock returns all real and synthetic MsgEthereumTxs from a // Tendermint block. It also ensures consistency over the correct txs indexes // across RPC endpoints -// TODO: check if additionals array can be removed +// TODO (https://github.com/zeta-chain/node/issues/2283): check if additionals array can be removed func (b *Backend) EthMsgsFromTendermintBlock( resBlock *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults, diff --git a/rpc/types/utils.go b/rpc/types/utils.go index 50c72b7758..f21b3e165f 100644 --- a/rpc/types/utils.go +++ b/rpc/types/utils.go @@ -167,7 +167,7 @@ func NewTransactionFromMsg( chainID *big.Int, txAdditional *TxResultAdditionalFields, ) (*RPCTransaction, error) { - // TODO: check if this condition can be removed + // TODO (https://github.com/zeta-chain/node/issues/2283): check if this condition can be removed if txAdditional != nil { return NewRPCTransactionFromIncompleteMsg(msg, blockHash, blockNumber, index, baseFee, chainID, txAdditional) } From 9ff0b69fd017be129df917ce6a0452e3a1f5619e Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 21:43:45 +0200 Subject: [PATCH 19/25] PR comments --- changelog.md | 2 +- rpc/backend/blocks.go | 27 +++++++++++++++------------ rpc/backend/tx_info.go | 8 ++++++++ rpc/types/events.go | 14 ++++++++++---- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/changelog.md b/changelog.md index e70f4f1195..a24a13ad9c 100644 --- a/changelog.md +++ b/changelog.md @@ -15,7 +15,7 @@ * [2152](https://github.com/zeta-chain/node/pull/2152) - custom priority nonce mempool * [2113](https://github.com/zeta-chain/node/pull/2113) - add zetaclientd-supervisor process * [2154](https://github.com/zeta-chain/node/pull/2154) - add `ibccrosschain` module -* [2282](https://github.com/zeta-chain/node/pull/2282) - modify rpc methods to include synthetic txs +* [2282](https://github.com/zeta-chain/node/pull/2282) - modify rpc methods to support synthetic txs * [2258](https://github.com/zeta-chain/node/pull/2258) - add Optimism and Base in static chain information * [2279](https://github.com/zeta-chain/node/pull/2279) - add a CCTXGateway field to chain static data * [2275](https://github.com/zeta-chain/node/pull/2275) - add ChainInfo singleton state variable in authority diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index a32b3eadbb..81f82a92db 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -282,7 +282,7 @@ func (b *Backend) EthMsgsFromTendermintBlock( resBlock *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults, ) ([]*evmtypes.MsgEthereumTx, []*rpctypes.TxResultAdditionalFields) { - var result []*evmtypes.MsgEthereumTx + var ethMsgs []*evmtypes.MsgEthereumTx var txsAdditional []*rpctypes.TxResultAdditionalFields block := resBlock.Block @@ -301,11 +301,10 @@ func (b *Backend) EthMsgsFromTendermintBlock( b.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error()) // try to check if there is synthetic eth tx in tx result ethMsg, additional := b.parseSyntheticTxFromBlockResults(txResults, i, tx, block) - if ethMsg == nil { - continue + if ethMsg != nil { + ethMsgs = append(ethMsgs, ethMsg) + txsAdditional = append(txsAdditional, additional) } - result = append(result, ethMsg) - txsAdditional = append(txsAdditional, additional) continue } @@ -317,7 +316,7 @@ func (b *Backend) EthMsgsFromTendermintBlock( if ok { shouldCheckForSyntheticTx = false ethMsg.Hash = ethMsg.AsTransaction().Hash().Hex() - result = append(result, ethMsg) + ethMsgs = append(ethMsgs, ethMsg) txsAdditional = append(txsAdditional, nil) } } @@ -325,14 +324,13 @@ func (b *Backend) EthMsgsFromTendermintBlock( if shouldCheckForSyntheticTx { // try to check if there is synthetic eth tx in tx result ethMsg, additional := b.parseSyntheticTxFromBlockResults(txResults, i, tx, block) - if ethMsg == nil { - continue + if ethMsg != nil { + ethMsgs = append(ethMsgs, ethMsg) + txsAdditional = append(txsAdditional, additional) } - result = append(result, ethMsg) - txsAdditional = append(txsAdditional, additional) } } - return result, txsAdditional + return ethMsgs, txsAdditional } func (b *Backend) parseSyntheticTxFromBlockResults( @@ -342,7 +340,12 @@ func (b *Backend) parseSyntheticTxFromBlockResults( block *tmtypes.Block, ) (*evmtypes.MsgEthereumTx, *rpctypes.TxResultAdditionalFields) { res, additional, err := rpctypes.ParseTxBlockResult(txResults[i], tx, i, block.Height) - if err != nil || additional == nil || res == nil { + // just skip tx if it can not be parsed, so remaining txs from the block are parsed + if err != nil { + b.logger.Error(err.Error()) + return nil, nil + } + if additional == nil || res == nil { return nil, nil } return b.parseSyntethicTxFromAdditionalFields(additional), additional diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 601ae89b4d..b5b8435551 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -55,6 +55,10 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac var ethMsg *evmtypes.MsgEthereumTx if additional == nil { + if int(res.TxIndex) >= len(resBlock.Block.Txs) { + b.logger.Error("tx out of bounds") + return nil, fmt.Errorf("tx out of bounds") + } tx, err := b.clientCtx.TxConfig.TxDecoder()(resBlock.Block.Txs[res.TxIndex]) if err != nil { b.logger.Debug("decoding failed", "error", err.Error()) @@ -176,6 +180,10 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ var txData evmtypes.TxData var ethMsg *evmtypes.MsgEthereumTx if additional == nil { + if int(res.TxIndex) >= len(resBlock.Block.Txs) { + b.logger.Error("tx out of bounds") + return nil, fmt.Errorf("tx out of bounds") + } tx, err := b.clientCtx.TxConfig.TxDecoder()(resBlock.Block.Txs[res.TxIndex]) if err != nil { b.logger.Debug("decoding failed", "error", err.Error()) diff --git a/rpc/types/events.go b/rpc/types/events.go index c9d20c093c..cf16d06024 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -429,17 +429,23 @@ func fillTxAttribute(tx *ParsedTx, key, value string) error { } func fillTxAttributes(tx *ParsedTx, attrs []abci.EventAttribute) error { + // before cosmos upgrade to 0.47, attributes are base64 encoded + // purpose of this is to support older txs as well isLegacyAttrs := isLegacyAttrEncoding(attrs) for _, attr := range attrs { if isLegacyAttrs { + // only decode if value can be decoded + // (error should not happen because at this point it is determined it is legacy attr) decKey, err := base64.StdEncoding.DecodeString(attr.Key) - if err == nil { - attr.Key = string(decKey) + if err != nil { + return err } + attr.Key = string(decKey) decValue, err := base64.StdEncoding.DecodeString(attr.Value) - if err == nil { - attr.Value = string(decValue) + if err != nil { + return err } + attr.Value = string(decValue) } if err := fillTxAttribute(tx, attr.Key, attr.Value); err != nil { From a8468e6f4aac12bf03e34f6fb357bbd0e3ff5d65 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 21:48:48 +0200 Subject: [PATCH 20/25] Remove todos --- rpc/backend/blocks.go | 1 - rpc/types/utils.go | 1 - 2 files changed, 2 deletions(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 81f82a92db..1b65c1d61d 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -277,7 +277,6 @@ func (b *Backend) BlockNumberFromTendermintByHash(blockHash common.Hash) (*big.I // EthMsgsFromTendermintBlock returns all real and synthetic MsgEthereumTxs from a // Tendermint block. It also ensures consistency over the correct txs indexes // across RPC endpoints -// TODO (https://github.com/zeta-chain/node/issues/2283): check if additionals array can be removed func (b *Backend) EthMsgsFromTendermintBlock( resBlock *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults, diff --git a/rpc/types/utils.go b/rpc/types/utils.go index f21b3e165f..dfda689557 100644 --- a/rpc/types/utils.go +++ b/rpc/types/utils.go @@ -167,7 +167,6 @@ func NewTransactionFromMsg( chainID *big.Int, txAdditional *TxResultAdditionalFields, ) (*RPCTransaction, error) { - // TODO (https://github.com/zeta-chain/node/issues/2283): check if this condition can be removed if txAdditional != nil { return NewRPCTransactionFromIncompleteMsg(msg, blockHash, blockNumber, index, baseFee, chainID, txAdditional) } From 9be7452df2354e1b606b949788272be7bc391795 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 29 May 2024 21:52:20 +0200 Subject: [PATCH 21/25] bump ethermint and use new attr constants --- go.mod | 4 ++-- go.sum | 4 ++-- rpc/types/events.go | 4 ++-- x/fungible/keeper/evm.go | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 4a7e28f411..2ff55e24ed 100644 --- a/go.mod +++ b/go.mod @@ -62,6 +62,7 @@ require ( github.com/cockroachdb/errors v1.10.0 github.com/cometbft/cometbft v0.37.4 github.com/cometbft/cometbft-db v0.8.0 + github.com/golang/mock v1.6.0 github.com/huandu/skiplist v1.2.0 github.com/nanmu42/etherscan-api v1.10.0 github.com/onrik/ethrpc v1.2.0 @@ -95,7 +96,6 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/golang/glog v1.1.2 // indirect - github.com/golang/mock v1.6.0 // indirect github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect @@ -353,4 +353,4 @@ replace ( replace github.com/cometbft/cometbft-db => github.com/notional-labs/cometbft-db v0.0.0-20230321185329-6dc7c0ca6345 -replace github.com/evmos/ethermint => github.com/zeta-chain/ethermint v0.0.0-20240521185249-8bae394152de +replace github.com/evmos/ethermint => github.com/zeta-chain/ethermint v0.0.0-20240529195014-204348d5452d diff --git a/go.sum b/go.sum index 05683f638c..1f0a6991ac 100644 --- a/go.sum +++ b/go.sum @@ -1732,8 +1732,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeta-chain/ethermint v0.0.0-20240521185249-8bae394152de h1:TvN2pOvj+PxXeFdrBzCbNGSfXU+Bnnl7ZGlBJ3lmgoM= -github.com/zeta-chain/ethermint v0.0.0-20240521185249-8bae394152de/go.mod h1:s1zA6OpXv3Tb5I0M6M6j5fo/AssaZL/pgkc7G0W2kN8= +github.com/zeta-chain/ethermint v0.0.0-20240529195014-204348d5452d h1:uOpeOcEJoIG7F7/I1peSOQA3Q6VP8W7L7Cu/Xd5yEzM= +github.com/zeta-chain/ethermint v0.0.0-20240529195014-204348d5452d/go.mod h1:s1zA6OpXv3Tb5I0M6M6j5fo/AssaZL/pgkc7G0W2kN8= github.com/zeta-chain/go-tss v0.1.1-0.20240430111318-1785e48eb127 h1:AGQepvsMIVHAHPlplzNcSCyMoGBY1DfO4WHG/QHUSIU= github.com/zeta-chain/go-tss v0.1.1-0.20240430111318-1785e48eb127/go.mod h1:bVpAoSlRYYCY/R34horVU3cheeHqhSVxygelc++emIU= github.com/zeta-chain/keystone/keys v0.0.0-20231105174229-903bc9405da2 h1:gd2uE0X+ZbdFJ8DubxNqLbOVlCB12EgWdzSNRAR82tM= diff --git a/rpc/types/events.go b/rpc/types/events.go index cf16d06024..50f6f04513 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -411,14 +411,14 @@ func fillTxAttribute(tx *ParsedTx, key, value string) error { if !success { return nil } - case "TxNonce": + case evmtypes.AttributeKeyTxNonce: nonce, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } tx.Nonce = nonce - case "TxData": + case evmtypes.AttributeKeyTxData: hexBytes, err := hexutil.Decode(value) if err != nil { return err diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index 1b8a9494aa..c2cdd1d7ed 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -789,9 +789,9 @@ func (k Keeper) CallEVMWithData( if !noEthereumTxEvent { // adding txData for more info in rpc methods in order to parse synthetic txs - attrs = append(attrs, sdk.NewAttribute("TxData", hexutil.Encode(msg.Data()))) + attrs = append(attrs, sdk.NewAttribute(evmtypes.AttributeKeyTxData, hexutil.Encode(msg.Data()))) // adding nonce for more info in rpc methods in order to parse synthetic txs - attrs = append(attrs, sdk.NewAttribute("TxNonce", fmt.Sprint(nonce))) + attrs = append(attrs, sdk.NewAttribute(evmtypes.AttributeKeyTxNonce, fmt.Sprint(nonce))) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( evmtypes.EventTypeEthereumTx, From d761ed988df23f6cfec0a1f5bad8a1b0d207da1e Mon Sep 17 00:00:00 2001 From: skosito Date: Thu, 30 May 2024 19:13:25 +0200 Subject: [PATCH 22/25] lint --- rpc/backend/tx_info.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index b5b8435551..ef02e62fa6 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -55,6 +55,7 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac var ethMsg *evmtypes.MsgEthereumTx if additional == nil { + // #nosec G701 always in range if int(res.TxIndex) >= len(resBlock.Block.Txs) { b.logger.Error("tx out of bounds") return nil, fmt.Errorf("tx out of bounds") @@ -180,6 +181,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ var txData evmtypes.TxData var ethMsg *evmtypes.MsgEthereumTx if additional == nil { + // #nosec G701 always in range if int(res.TxIndex) >= len(resBlock.Block.Txs) { b.logger.Error("tx out of bounds") return nil, fmt.Errorf("tx out of bounds") From 89bd917ae71b2a02be79d92744b985a20f258405 Mon Sep 17 00:00:00 2001 From: skosito Date: Thu, 30 May 2024 19:55:40 +0200 Subject: [PATCH 23/25] PR comments --- rpc/backend/blocks.go | 32 +++++++++++++------------------- rpc/backend/tx_info.go | 4 ++++ rpc/types/events.go | 6 +++--- x/fungible/keeper/evm.go | 3 +++ 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 1b65c1d61d..d28b8345da 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -296,32 +296,26 @@ func (b *Backend) EthMsgsFromTendermintBlock( } tx, err := b.clientCtx.TxConfig.TxDecoder()(tx) - if err != nil { - b.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error()) - // try to check if there is synthetic eth tx in tx result - ethMsg, additional := b.parseSyntheticTxFromBlockResults(txResults, i, tx, block) - if ethMsg != nil { - ethMsgs = append(ethMsgs, ethMsg) - txsAdditional = append(txsAdditional, additional) - } - continue - } - // assumption is that if regular ethermint msg is found in tx // there should not be synthetic one as well shouldCheckForSyntheticTx := true - for _, msg := range tx.GetMsgs() { - ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if ok { - shouldCheckForSyntheticTx = false - ethMsg.Hash = ethMsg.AsTransaction().Hash().Hex() - ethMsgs = append(ethMsgs, ethMsg) - txsAdditional = append(txsAdditional, nil) + // if tx can be decoded, try to find MsgEthereumTx inside + if err == nil { + for _, msg := range tx.GetMsgs() { + ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) + if ok { + shouldCheckForSyntheticTx = false + ethMsg.Hash = ethMsg.AsTransaction().Hash().Hex() + ethMsgs = append(ethMsgs, ethMsg) + txsAdditional = append(txsAdditional, nil) + } } + } else { + b.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error()) } + // if tx can not be decoded or MsgEthereumTx was not found, try to parse it from block results if shouldCheckForSyntheticTx { - // try to check if there is synthetic eth tx in tx result ethMsg, additional := b.parseSyntheticTxFromBlockResults(txResults, i, tx, block) if ethMsg != nil { ethMsgs = append(ethMsgs, ethMsg) diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index ef02e62fa6..740981f010 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -54,6 +54,7 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac } var ethMsg *evmtypes.MsgEthereumTx + // if additional fields are empty we can try to get MsgEthereumTx from sdk.Msg array if additional == nil { // #nosec G701 always in range if int(res.TxIndex) >= len(resBlock.Block.Txs) { @@ -71,6 +72,7 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac return nil, fmt.Errorf("failed to get eth msg") } } else { + // if additional fields are not empty try to parse synthetic tx from them ethMsg = b.parseSyntethicTxFromAdditionalFields(additional) if ethMsg == nil { b.logger.Error("failed to parse tx") @@ -180,6 +182,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ var txData evmtypes.TxData var ethMsg *evmtypes.MsgEthereumTx + // if additional fields are empty we can try to get MsgEthereumTx from sdk.Msg array if additional == nil { // #nosec G701 always in range if int(res.TxIndex) >= len(resBlock.Block.Txs) { @@ -203,6 +206,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, err } } else { + // if additional fields are not empty try to parse synthetic tx from them ethMsg = b.parseSyntethicTxFromAdditionalFields(additional) if ethMsg == nil { b.logger.Error("failed to parse tx") diff --git a/rpc/types/events.go b/rpc/types/events.go index 50f6f04513..3839fb84df 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -188,7 +188,7 @@ func ParseTxResult(result *abci.ResponseDeliverTx, tx sdk.Tx) (*ParsedTxs, error // fix msg indexes, because some eth txs indexed here don't have corresponding sdk.Msg currMsgIndex := 0 for _, tx := range p.Txs { - if tx.Type == 88 { + if tx.Type == CosmosEVMTxType { tx.MsgIndex = math.MaxUint32 // todo: fix mapping as well } else { @@ -223,7 +223,7 @@ func ParseTxIndexerResult( txResult.Index, ) } - if parsedTx.Type == 88 { + if parsedTx.Type == CosmosEVMTxType { return ðermint.TxResult{ Height: txResult.Height, TxIndex: txResult.Index, @@ -270,7 +270,7 @@ func ParseTxBlockResult( return nil, nil, fmt.Errorf("ethereum tx not found in msgs: block %d, index %d", height, txIndex) } parsedTx := txs.Txs[0] - if parsedTx.Type == 88 { + if parsedTx.Type == CosmosEVMTxType { return ðermint.TxResult{ Height: height, // #nosec G701 always in range diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index c2cdd1d7ed..9a7ed00d5b 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -680,6 +680,9 @@ 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 +// 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 // Furthermore, err!=nil && msg!=nil && msg.Failed() means the contract call reverted; in which case // msg.Ret gives the RET code if contract revert with REVERT opcode with parameters. From 2e8600fbda39467d8e75ecfe4901e5d3b99f35f4 Mon Sep 17 00:00:00 2001 From: skosito Date: Fri, 31 May 2024 19:29:34 +0200 Subject: [PATCH 24/25] bump ethermint --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2ff55e24ed..709983e8cc 100644 --- a/go.mod +++ b/go.mod @@ -353,4 +353,4 @@ replace ( replace github.com/cometbft/cometbft-db => github.com/notional-labs/cometbft-db v0.0.0-20230321185329-6dc7c0ca6345 -replace github.com/evmos/ethermint => github.com/zeta-chain/ethermint v0.0.0-20240529195014-204348d5452d +replace github.com/evmos/ethermint => github.com/zeta-chain/ethermint v0.0.0-20240531172701-61d040058c94 diff --git a/go.sum b/go.sum index 1f0a6991ac..ac3eb6cc0b 100644 --- a/go.sum +++ b/go.sum @@ -1732,8 +1732,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeta-chain/ethermint v0.0.0-20240529195014-204348d5452d h1:uOpeOcEJoIG7F7/I1peSOQA3Q6VP8W7L7Cu/Xd5yEzM= -github.com/zeta-chain/ethermint v0.0.0-20240529195014-204348d5452d/go.mod h1:s1zA6OpXv3Tb5I0M6M6j5fo/AssaZL/pgkc7G0W2kN8= +github.com/zeta-chain/ethermint v0.0.0-20240531172701-61d040058c94 h1:M54ljayJvy+WlEVdUmX8pgo1nA+XguB3mLhm3wi2z9o= +github.com/zeta-chain/ethermint v0.0.0-20240531172701-61d040058c94/go.mod h1:s1zA6OpXv3Tb5I0M6M6j5fo/AssaZL/pgkc7G0W2kN8= github.com/zeta-chain/go-tss v0.1.1-0.20240430111318-1785e48eb127 h1:AGQepvsMIVHAHPlplzNcSCyMoGBY1DfO4WHG/QHUSIU= github.com/zeta-chain/go-tss v0.1.1-0.20240430111318-1785e48eb127/go.mod h1:bVpAoSlRYYCY/R34horVU3cheeHqhSVxygelc++emIU= github.com/zeta-chain/keystone/keys v0.0.0-20231105174229-903bc9405da2 h1:gd2uE0X+ZbdFJ8DubxNqLbOVlCB12EgWdzSNRAR82tM= From f947a6e1af569564b1ecfc355c401228fa0742ed Mon Sep 17 00:00:00 2001 From: skosito Date: Fri, 31 May 2024 20:20:17 +0200 Subject: [PATCH 25/25] more descriptive err message --- rpc/backend/tx_info.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 740981f010..e08f36db42 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -68,15 +68,15 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac } ethMsg = tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) if ethMsg == nil { - b.logger.Error("failed to get eth msg") - return nil, fmt.Errorf("failed to get eth msg") + b.logger.Error("failed to get eth msg from sdk.Msgs") + return nil, fmt.Errorf("failed to get eth msg from sdk.Msgs") } } else { // if additional fields are not empty try to parse synthetic tx from them ethMsg = b.parseSyntethicTxFromAdditionalFields(additional) if ethMsg == nil { - b.logger.Error("failed to parse tx") - return nil, fmt.Errorf("failed to parse tx") + b.logger.Error("failed to get synthetic eth msg from additional fields") + return nil, fmt.Errorf("failed to get synthetic eth msg from additional fields") } }