From 7951852bb066d262b8be5e884eafb82caddb57bd Mon Sep 17 00:00:00 2001 From: yihuang Date: Fri, 9 Jul 2021 16:34:49 +0800 Subject: [PATCH] rpc: implement pending nonce with `UnconfirmedTx` (#243) * implement pending nonce with UnconfirmedTx Closes #242 fix lint * return early on error --- ethereum/rpc/backend/backend.go | 21 +++++++++++-- ethereum/rpc/namespaces/eth/api.go | 49 ++++++++++++++++-------------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/ethereum/rpc/backend/backend.go b/ethereum/rpc/backend/backend.go index cfe29b6a..b8452770 100644 --- a/ethereum/rpc/backend/backend.go +++ b/ethereum/rpc/backend/backend.go @@ -13,6 +13,7 @@ import ( log "github.com/xlab/suplog" "github.com/cosmos/cosmos-sdk/client" + 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" @@ -36,7 +37,7 @@ type Backend interface { GetLogs(blockHash common.Hash) ([][]*ethtypes.Log, error) // Used by pending transaction filter - PendingTransactions() ([]*types.RPCTransaction, error) + PendingTransactions() ([]*sdk.Tx, error) // Used by log filter GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) @@ -294,8 +295,22 @@ func (e *EVMBackend) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, er // PendingTransactions returns the transactions that are in the transaction pool // and have a from address that is one of the accounts this node manages. -func (e *EVMBackend) PendingTransactions() ([]*types.RPCTransaction, error) { - return []*types.RPCTransaction{}, nil +func (e *EVMBackend) PendingTransactions() ([]*sdk.Tx, error) { + res, err := e.clientCtx.Client.UnconfirmedTxs(e.ctx, nil) + if err != nil { + return nil, err + } + + result := make([]*sdk.Tx, 0, len(res.Txs)) + for _, txBz := range res.Txs { + tx, err := e.clientCtx.TxConfig.TxDecoder()(txBz) + if err != nil { + return nil, err + } + result = append(result, &tx) + } + + return result, nil } // GetLogs returns all the logs from all the ethereum transactions in a block. diff --git a/ethereum/rpc/namespaces/eth/api.go b/ethereum/rpc/namespaces/eth/api.go index 51ddc5c6..da9a117e 100644 --- a/ethereum/rpc/namespaces/eth/api.go +++ b/ethereum/rpc/namespaces/eth/api.go @@ -5,21 +5,18 @@ import ( "context" "fmt" "math/big" - "strconv" "strings" "github.com/gogo/protobuf/jsonpb" "github.com/pkg/errors" "github.com/spf13/viper" log "github.com/xlab/suplog" - "google.golang.org/grpc/metadata" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" - grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -260,7 +257,7 @@ func (e *PublicAPI) GetTransactionCount(address common.Address, blockNum rpctype } includePending := blockNum == rpctypes.EthPendingBlockNumber - nonce, err := e.getAccountNonce(address, includePending, blockNum.TmHeight(), e.logger) + nonce, err := e.getAccountNonce(address, includePending, blockNum.Int64(), e.logger) if err != nil { return nil, err } @@ -585,7 +582,7 @@ func (e *PublicAPI) doCall( } includePending := blockNr == rpctypes.EthPendingBlockNumber - seq, err := e.getAccountNonce(*args.From, includePending, blockNr.TmHeight(), e.logger) + seq, err := e.getAccountNonce(*args.From, includePending, 0, e.logger) if err != nil { return nil, err } @@ -985,7 +982,9 @@ func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interfac // and have a from address that is one of the accounts this node manages. func (e *PublicAPI) PendingTransactions() ([]*rpctypes.RPCTransaction, error) { e.logger.Debugln("eth_getPendingTransactions") - return e.backend.PendingTransactions() + + // FIXME https://github.com/tharsis/ethermint/issues/244 + return []*rpctypes.RPCTransaction{}, nil } // GetUncleByBlockHashAndIndex returns the uncle identified by hash and index. Always returns nil. @@ -1082,7 +1081,7 @@ func (e *PublicAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs if args.Nonce == nil { // get the nonce from the account retriever // ignore error in case tge account doesn't exist yet - nonce, _ := e.getAccountNonce(args.From, true, nil, e.logger) + nonce, _ := e.getAccountNonce(args.From, true, 0, e.logger) args.Nonce = (*hexutil.Uint64)(&nonce) } @@ -1140,13 +1139,9 @@ func (e *PublicAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs // If the pending value is true, it will iterate over the mempool (pending) // txs in order to compute and return the pending tx sequence. // Todo: include the ability to specify a blockNumber -func (e *PublicAPI) getAccountNonce(accAddr common.Address, pending bool, height *int64, logger log.Logger) (uint64, error) { - ctx := e.ctx - if height != nil { - ctx = metadata.AppendToOutgoingContext(e.ctx, grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(*height, 10)) - } +func (e *PublicAPI) getAccountNonce(accAddr common.Address, pending bool, height int64, logger log.Logger) (uint64, error) { queryClient := authtypes.NewQueryClient(e.clientCtx) - res, err := queryClient.Account(ctx, &authtypes.QueryAccountRequest{Address: sdk.AccAddress(accAddr.Bytes()).String()}) + res, err := queryClient.Account(rpctypes.ContextWithHeight(height), &authtypes.QueryAccountRequest{Address: sdk.AccAddress(accAddr.Bytes()).String()}) if err != nil { return 0, err } @@ -1165,19 +1160,29 @@ func (e *PublicAPI) getAccountNonce(accAddr common.Address, pending bool, height // to manually add them. pendingTxs, err := e.backend.PendingTransactions() if err != nil { - logger.Errorln("fails to fetch pending transactions") + logger.WithError(err).Errorln("fails to fetch pending transactions") return nonce, nil } // add the uncommitted txs to the nonce counter - if len(pendingTxs) != 0 { - for i := range pendingTxs { - if pendingTxs[i] == nil { - continue - } - if pendingTxs[i].From == accAddr { - nonce++ - } + // only supports `MsgEthereumTx` style tx + for _, tx := range pendingTxs { + if tx == nil { + continue + } + if len((*tx).GetMsgs()) != 1 { + continue + } + msg, ok := (*tx).GetMsgs()[0].(*evmtypes.MsgEthereumTx) + if !ok { + continue + } + sender, err := msg.GetSender(e.chainIDEpoch) + if err != nil { + continue + } + if sender == accAddr { + nonce++ } }