Skip to content

Commit

Permalink
feat: modify rpc methods to include synthetic txs (#2282)
Browse files Browse the repository at this point in the history
  • Loading branch information
skosito authored May 31, 2024
1 parent 54de761 commit 0a3b8dc
Show file tree
Hide file tree
Showing 10 changed files with 243 additions and 188 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 support synthetic txs
* [2258](https://github.com/zeta-chain/node/pull/2258) - add Optimism and Base in static chain information
* [2287](https://github.com/zeta-chain/node/pull/2287) - implement `MsgUpdateChainInfo` message
* [2279](https://github.com/zeta-chain/node/pull/2279) - add a CCTXGateway field to chain static data
Expand Down
13 changes: 6 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@ 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/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
github.com/tendermint/tendermint v0.34.12
go.nhat.io/grpcmock v0.25.0
)

Expand All @@ -77,7 +79,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
Expand All @@ -95,10 +96,8 @@ 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/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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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-20240531172701-61d040058c94
5 changes: 2 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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-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=
Expand Down
90 changes: 70 additions & 20 deletions rpc/backend/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -272,14 +274,14 @@ 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
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

Expand All @@ -294,30 +296,78 @@ func (b *Backend) EthMsgsFromTendermintBlock(
}

tx, err := b.clientCtx.TxConfig.TxDecoder()(tx)
if err != nil {
// assumption is that if regular ethermint msg is found in tx
// there should not be synthetic one as well
shouldCheckForSyntheticTx := true
// 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())
continue
}
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(),
}

// if tx can not be decoded or MsgEthereumTx was not found, try to parse it from block results
if shouldCheckForSyntheticTx {
ethMsg, additional := b.parseSyntheticTxFromBlockResults(txResults, i, tx, block)
if ethMsg != nil {
ethMsgs = append(ethMsgs, ethMsg)
txsAdditional = append(txsAdditional, additional)
} else {
ethMsg.Hash = ethMsg.AsTransaction().Hash().Hex()
txsAdditional = append(txsAdditional, nil)
}
result = append(result, ethMsg)
}
}
return result, txsAdditional
return ethMsgs, txsAdditional
}

func (b *Backend) parseSyntheticTxFromBlockResults(
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)
// 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
}

func (b *Backend) parseSyntethicTxFromAdditionalFields(
additional *rpctypes.TxResultAdditionalFields,
) *evmtypes.MsgEthereumTx {
recipient := additional.Recipient
t := ethtypes.NewTx(&ethtypes.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
}
ethMsg.Hash = additional.Hash.Hex()
ethMsg.From = additional.Sender.Hex()
return ethMsg
}

// HeaderByNumber returns the block header identified by height.
Expand Down
89 changes: 15 additions & 74 deletions rpc/backend/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ 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"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"github.com/pkg/errors"

Expand Down Expand Up @@ -50,62 +49,28 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi
return nil, err
}

// 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 _, 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
}
for _, msg := range tx.GetMsgs() {
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
continue
}

predecessors = append(predecessors, ethMsg)
}
}

tx, err := b.clientCtx.TxConfig.TxDecoder()(blk.Block.Txs[transaction.TxIndex])
blockResult, err := b.TendermintBlockResultByNumber(&blk.Block.Height)
if err != nil {
b.logger.Debug("tx not found", "hash", hash)
return nil, err
return nil, fmt.Errorf("block result not found for height %d", blk.Block.Height)
}

// add predecessor messages in current cosmos tx
// #nosec G701 always in range
for i := 0; i < int(transaction.MsgIndex); i++ {
ethMsg, ok := tx.GetMsgs()[i].(*evmtypes.MsgEthereumTx)
if !ok {
continue
predecessors := []*evmtypes.MsgEthereumTx{}
msgs, _ := b.EthMsgsFromTendermintBlock(blk, blockResult)
var ethMsg *evmtypes.MsgEthereumTx
for _, m := range msgs {
if m.Hash == hash.Hex() {
ethMsg = m
break
}
predecessors = append(predecessors, ethMsg)
predecessors = append(predecessors, m)
}

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 ethMsg == nil {
return nil, fmt.Errorf("tx not found in block %d", blk.Block.Height)
}

traceTxRequest := evmtypes.QueryTraceTxRequest{
Msg: ethMessage,
Msg: ethMsg,
Predecessors: predecessors,
BlockNumber: blk.Block.Height,
BlockTime: blk.Block.Time,
Expand Down Expand Up @@ -160,31 +125,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
Expand All @@ -195,7 +136,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,
Expand Down
Loading

0 comments on commit 0a3b8dc

Please sign in to comment.