diff --git a/app/rpc/apis.go b/app/rpc/apis.go index 46657b8455..470179247c 100644 --- a/app/rpc/apis.go +++ b/app/rpc/apis.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" "github.com/ethereum/go-ethereum/rpc" "github.com/go-kit/kit/metrics/prometheus" + "github.com/okex/exchain/app/rpc/namespaces/eth/txpool" evmtypes "github.com/okex/exchain/x/evm/types" stdprometheus "github.com/prometheus/client_golang/prometheus" "github.com/spf13/viper" @@ -33,6 +34,7 @@ const ( EthNamespace = "eth" PersonalNamespace = "personal" NetNamespace = "net" + TxpoolNamespace = "txpool" apiVersion = "1.0" ) @@ -77,6 +79,12 @@ func GetAPIs(clientCtx context.CLIContext, log log.Logger, keys ...ethsecp256k1. Service: net.NewAPI(clientCtx, log), Public: true, }, + { + Namespace: TxpoolNamespace, + Version: apiVersion, + Service: txpool.NewAPI(clientCtx, log, ethBackend), + Public: true, + }, } if viper.GetBool(FlagPersonalAPI) { diff --git a/app/rpc/backend/backend.go b/app/rpc/backend/backend.go index e73c8de74b..0a6bc8509d 100644 --- a/app/rpc/backend/backend.go +++ b/app/rpc/backend/backend.go @@ -43,6 +43,7 @@ type Backend interface { PendingTransactionsByHash(target common.Hash) (*rpctypes.Transaction, error) UserPendingTransactionsCnt(address string) (int, error) UserPendingTransactions(address string, limit int) ([]*rpctypes.Transaction, error) + PendingAddressList() ([]string, error) // Used by log filter GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) @@ -235,7 +236,7 @@ func (b *EthermintBackend) PendingTransactions() ([]*rpctypes.Transaction, error return nil, err } - transactions := make([]*rpctypes.Transaction, 0) + transactions := make([]*rpctypes.Transaction, 0, len(pendingTxs.Txs)) for _, tx := range pendingTxs.Txs { ethTx, err := rpctypes.RawTxToEthTx(b.clientCtx, tx) if err != nil { @@ -256,7 +257,7 @@ func (b *EthermintBackend) PendingTransactions() ([]*rpctypes.Transaction, error } func (b *EthermintBackend) PendingTransactionCnt() (int, error) { - result, err := b.clientCtx.Client.UnconfirmedTxs(-1) + result, err := b.clientCtx.Client.NumUnconfirmedTxs() if err != nil { return 0, err } @@ -276,8 +277,7 @@ func (b *EthermintBackend) UserPendingTransactions(address string, limit int) ([ if err != nil { return nil, err } - - transactions := make([]*rpctypes.Transaction, len(result.Txs)) + transactions := make([]*rpctypes.Transaction, 0, len(result.Txs)) for _, tx := range result.Txs { ethTx, err := rpctypes.RawTxToEthTx(b.clientCtx, tx) if err != nil { @@ -297,6 +297,14 @@ func (b *EthermintBackend) UserPendingTransactions(address string, limit int) ([ return transactions, nil } +func (b *EthermintBackend) PendingAddressList() ([]string, error) { + res, err := b.clientCtx.Client.GetAddressList() + if err != nil { + return nil, err + } + return res.Addresses, nil +} + // PendingTransactions returns the transaction that is in the transaction pool // and have a from address that is one of the accounts this node manages. func (b *EthermintBackend) PendingTransactionsByHash(target common.Hash) (*rpctypes.Transaction, error) { diff --git a/app/rpc/namespaces/eth/txpool/api.go b/app/rpc/namespaces/eth/txpool/api.go new file mode 100644 index 0000000000..63b802a23d --- /dev/null +++ b/app/rpc/namespaces/eth/txpool/api.go @@ -0,0 +1,102 @@ +package txpool + +import ( + "fmt" + clientcontext "github.com/cosmos/cosmos-sdk/client/context" + "github.com/ethereum/go-ethereum/common/hexutil" + rpctypes "github.com/okex/exchain/app/rpc/types" + + "github.com/okex/exchain/app/rpc/backend" + "github.com/tendermint/tendermint/libs/log" +) + +// PublicTxPoolAPI offers and API for the transaction pool. It only operates on data that is non confidential. +type PublicTxPoolAPI struct { + clientCtx clientcontext.CLIContext + logger log.Logger + backend backend.Backend +} + +// NewPublicTxPoolAPI creates a new tx pool service that gives information about the transaction pool. +func NewAPI(clientCtx clientcontext.CLIContext, log log.Logger, backend backend.Backend) *PublicTxPoolAPI { + api := &PublicTxPoolAPI{ + clientCtx: clientCtx, + backend: backend, + logger: log.With("module", "json-rpc", "namespace", "txpool"), + } + return api +} + +// Content returns the transactions contained within the transaction pool. +func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*rpctypes.Transaction { + addressList, err := s.backend.PendingAddressList() + if err != nil { + s.logger.Error("txpool.Content addressList err: ", err) + } + content := map[string]map[string]map[string]*rpctypes.Transaction{ + "queued": make(map[string]map[string]*rpctypes.Transaction), + } + + for _, address := range addressList { + txs, err := s.backend.UserPendingTransactions(address, -1) + if err != nil { + s.logger.Error("txpool.Content err: ", err) + } + + // Flatten the queued transactions + dump := make(map[string]*rpctypes.Transaction) + for _, tx := range txs { + dump[fmt.Sprintf("%d", tx.Nonce)] = tx + } + content["queued"][address] = dump + } + + return content +} + +// Status returns the number of pending and queued transaction in the pool. +func (s *PublicTxPoolAPI) Status() map[string]hexutil.Uint { + numRes, err := s.backend.PendingTransactionCnt() + if err != nil { + s.logger.Error("txpool.Status err: ", err) + return nil + } + return map[string]hexutil.Uint{ + "queued": hexutil.Uint(numRes), + } +} + +// Inspect retrieves the content of the transaction pool and flattens it into an +// easily inspectable list. +func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string { + addressList, err := s.backend.PendingAddressList() + if err != nil { + s.logger.Error("txpool.Inspect addressList err: ", err) + } + content := map[string]map[string]map[string]string{ + "queued": make(map[string]map[string]string), + } + for _, address := range addressList { + txs, err := s.backend.UserPendingTransactions(address, -1) + if err != nil { + s.logger.Error("txpool.Inspect err: ", err) + } + + // Define a formatter to flatten a transaction into a string + var format = func(tx *rpctypes.Transaction) string { + if to := tx.To; to != nil { + return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To.Hex(), tx.Value, tx.Gas, tx.GasPrice) + } + return fmt.Sprintf("contract creation: %v wei + %v gas × %v wei", tx.Value, tx.Gas, tx.GasPrice) + } + + // Flatten the queued transactions + dump := make(map[string]string) + for _, tx := range txs { + dump[fmt.Sprintf("%d", tx.Nonce)] = format(tx) + } + content["queued"][address] = dump + } + + return content +} diff --git a/go.mod b/go.mod index dea45c9e94..62f72c7b47 100644 --- a/go.mod +++ b/go.mod @@ -56,7 +56,7 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/okex/cosmos-sdk v0.39.2-exchain6 + github.com/cosmos/cosmos-sdk => github.com/okex/cosmos-sdk v0.39.2-exchain7 github.com/tendermint/iavl => github.com/okex/iavl v0.14.3-exchain - github.com/tendermint/tendermint => github.com/okex/tendermint v0.33.9-exchain4 + github.com/tendermint/tendermint => github.com/okex/tendermint v0.33.9-exchain5 ) diff --git a/go.sum b/go.sum index 7678013aed..983501d980 100644 --- a/go.sum +++ b/go.sum @@ -499,12 +499,12 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/okex/cosmos-sdk v0.39.2-exchain6 h1:QERnXF6F8FTDkDKVEa2YSqNj66+Ef5Bkdc0Q/Bp/7TM= -github.com/okex/cosmos-sdk v0.39.2-exchain6/go.mod h1:IvlniaZoJAtzILHgcmnfaJ5S125TYJWfJvGqY9zSXb4= +github.com/okex/cosmos-sdk v0.39.2-exchain7 h1:ySr9r+EErCK31LakC+fkV6TsOYf6rG64PQlwhEqFOrs= +github.com/okex/cosmos-sdk v0.39.2-exchain7/go.mod h1:IvlniaZoJAtzILHgcmnfaJ5S125TYJWfJvGqY9zSXb4= github.com/okex/iavl v0.14.3-exchain h1:kwRIwpFD6B8mDDqoaxeUN3Pg2GW0Vr+sA+b86renWcA= github.com/okex/iavl v0.14.3-exchain/go.mod h1:vHLYxU/zuxBmxxr1v+5Vnd/JzcIsyK17n9P9RDubPVU= -github.com/okex/tendermint v0.33.9-exchain4 h1:PKXnawZpuczfcIwuaUuvqobv/qcKnW2e7Apk5Ei4TUM= -github.com/okex/tendermint v0.33.9-exchain4/go.mod h1:EoGTbJUufUueNIigY3zyO6f7GOj29OdpFhuR8sxWdSU= +github.com/okex/tendermint v0.33.9-exchain5 h1:8nSeDVzcO+g2bFUMcT34Wkv0x/yEPD/eAFoSVExicQk= +github.com/okex/tendermint v0.33.9-exchain5/go.mod h1:EoGTbJUufUueNIigY3zyO6f7GOj29OdpFhuR8sxWdSU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=