rpc: namespaces refractor (#170)

* refactor: rpc namespace refactor - txpool

* refactor: rpc namespace refactor - net

* refactor: rpc namespace refactor - web3

* refactor: rpc namespace refactor - eth

* refactor: rpc namespace refactor - personal

* fix: api to uppercase

* fix: fix import cycle

* fix: fix import cycle
This commit is contained in:
crypto-facs 2021-06-23 02:38:05 -04:00 committed by GitHub
parent 1f962044e2
commit 1c06553746
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 292 additions and 256 deletions

View File

@ -5,6 +5,13 @@ package rpc
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/ethereum/go-ethereum/rpc"
"github.com/tharsis/ethermint/ethereum/rpc/backend"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/eth"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/eth/filters"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/net"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/personal"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/txpool"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/web3"
"github.com/tharsis/ethermint/ethereum/rpc/types"
rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
@ -24,14 +31,14 @@ const (
// GetRPCAPIs returns the list of all APIs
func GetRPCAPIs(clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API {
nonceLock := new(types.AddrLocker)
backend := NewEVMBackend(clientCtx)
ethAPI := NewPublicEthAPI(clientCtx, backend, nonceLock)
backend := backend.NewEVMBackend(clientCtx)
ethAPI := eth.NewPublicAPI(clientCtx, backend, nonceLock)
return []rpc.API{
{
Namespace: Web3Namespace,
Version: apiVersion,
Service: NewPublicWeb3API(),
Service: web3.NewPublicAPI(),
Public: true,
},
{
@ -43,25 +50,25 @@ func GetRPCAPIs(clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.
{
Namespace: EthNamespace,
Version: apiVersion,
Service: NewPublicFilterAPI(tmWSClient, backend),
Service: filters.NewPublicAPI(tmWSClient, backend),
Public: true,
},
{
Namespace: NetNamespace,
Version: apiVersion,
Service: NewPublicNetAPI(clientCtx),
Service: net.NewPublicAPI(clientCtx),
Public: true,
},
{
Namespace: PersonalNamespace,
Version: apiVersion,
Service: NewPersonalAPI(ethAPI),
Service: personal.NewAPI(ethAPI),
Public: true,
},
{
Namespace: TxPoolNamespace,
Version: apiVersion,
Service: NewPublicTxPoolAPI(),
Service: txpool.NewPublicAPI(),
Public: true,
},
}

View File

@ -1,4 +1,4 @@
package rpc
package backend
import (
"context"

View File

@ -1,4 +1,4 @@
package rpc
package eth
import (
"bytes"
@ -30,28 +30,29 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/tharsis/ethermint/crypto/hd"
"github.com/tharsis/ethermint/ethereum/rpc/backend"
rpctypes "github.com/tharsis/ethermint/ethereum/rpc/types"
ethermint "github.com/tharsis/ethermint/types"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
// PublicEthAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PublicEthAPI struct {
// PublicAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PublicAPI struct {
ctx context.Context
clientCtx client.Context
queryClient *rpctypes.QueryClient
chainIDEpoch *big.Int
logger log.Logger
backend Backend
backend backend.Backend
nonceLock *rpctypes.AddrLocker
}
// NewPublicEthAPI creates an instance of the public ETH Web3 API.
func NewPublicEthAPI(
// NewPublicAPI creates an instance of the public ETH Web3 API.
func NewPublicAPI(
clientCtx client.Context,
backend Backend,
backend backend.Backend,
nonceLock *rpctypes.AddrLocker,
) *PublicEthAPI {
) *PublicAPI {
epoch, err := ethermint.ParseChainID(clientCtx.ChainID)
if err != nil {
panic(err)
@ -75,7 +76,7 @@ func NewPublicEthAPI(
clientCtx = clientCtx.WithKeyring(kr)
}
api := &PublicEthAPI{
api := &PublicAPI{
ctx: context.Background(),
clientCtx: clientCtx,
queryClient: rpctypes.NewQueryClient(clientCtx),
@ -89,25 +90,25 @@ func NewPublicEthAPI(
}
// ClientCtx returns client context
func (e *PublicEthAPI) ClientCtx() client.Context {
func (e *PublicAPI) ClientCtx() client.Context {
return e.clientCtx
}
// ProtocolVersion returns the supported Ethereum protocol version.
func (e *PublicEthAPI) ProtocolVersion() hexutil.Uint {
func (e *PublicAPI) ProtocolVersion() hexutil.Uint {
e.logger.Debugln("eth_protocolVersion")
return hexutil.Uint(ethermint.ProtocolVersion)
}
// ChainId returns the chain's identifier in hex format
func (e *PublicEthAPI) ChainId() (hexutil.Uint, error) { // nolint
func (e *PublicAPI) ChainId() (hexutil.Uint, error) { // nolint
e.logger.Debugln("eth_chainId")
return hexutil.Uint(uint(e.chainIDEpoch.Uint64())), nil
}
// Syncing returns whether or not the current node is syncing with other peers. Returns false if not, or a struct
// outlining the state of the sync if it is.
func (e *PublicEthAPI) Syncing() (interface{}, error) {
func (e *PublicAPI) Syncing() (interface{}, error) {
e.logger.Debugln("eth_syncing")
status, err := e.clientCtx.Client.Status(e.ctx)
@ -129,7 +130,7 @@ func (e *PublicEthAPI) Syncing() (interface{}, error) {
}
// Coinbase is the address that staking rewards will be send to (alias for Etherbase).
func (e *PublicEthAPI) Coinbase() (string, error) {
func (e *PublicAPI) Coinbase() (string, error) {
e.logger.Debugln("eth_coinbase")
node, err := e.clientCtx.GetNode()
@ -157,19 +158,19 @@ func (e *PublicEthAPI) Coinbase() (string, error) {
}
// Mining returns whether or not this node is currently mining. Always false.
func (e *PublicEthAPI) Mining() bool {
func (e *PublicAPI) Mining() bool {
e.logger.Debugln("eth_mining")
return false
}
// Hashrate returns the current node's hashrate. Always 0.
func (e *PublicEthAPI) Hashrate() hexutil.Uint64 {
func (e *PublicAPI) Hashrate() hexutil.Uint64 {
e.logger.Debugln("eth_hashrate")
return 0
}
// GasPrice returns the current gas price based on Ethermint's gas price oracle.
func (e *PublicEthAPI) GasPrice() *hexutil.Big {
func (e *PublicAPI) GasPrice() *hexutil.Big {
e.logger.Debugln("eth_gasPrice")
// TODO: use minimum value defined in config instead of default or implement oracle
out := big.NewInt(ethermint.DefaultGasPrice)
@ -177,7 +178,7 @@ func (e *PublicEthAPI) GasPrice() *hexutil.Big {
}
// Accounts returns the list of accounts available to this node.
func (e *PublicEthAPI) Accounts() ([]common.Address, error) {
func (e *PublicAPI) Accounts() ([]common.Address, error) {
e.logger.Debugln("eth_accounts")
addresses := make([]common.Address, 0) // return [] instead of nil if empty
@ -196,13 +197,13 @@ func (e *PublicEthAPI) Accounts() ([]common.Address, error) {
}
// BlockNumber returns the current block number.
func (e *PublicEthAPI) BlockNumber() (hexutil.Uint64, error) {
func (e *PublicAPI) BlockNumber() (hexutil.Uint64, error) {
//e.logger.Debugln("eth_blockNumber")
return e.backend.BlockNumber()
}
// GetBalance returns the provided account's balance up to the provided block number.
func (e *PublicEthAPI) GetBalance(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Big, error) { // nolint: interfacer
func (e *PublicAPI) GetBalance(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Big, error) { // nolint: interfacer
e.logger.Debugln("eth_getBalance", "address", address.String(), "block number", blockNum)
req := &evmtypes.QueryBalanceRequest{
@ -223,7 +224,7 @@ func (e *PublicEthAPI) GetBalance(address common.Address, blockNum rpctypes.Bloc
}
// GetStorageAt returns the contract storage at the given address, block number, and key.
func (e *PublicEthAPI) GetStorageAt(address common.Address, key string, blockNum rpctypes.BlockNumber) (hexutil.Bytes, error) { // nolint: interfacer
func (e *PublicAPI) GetStorageAt(address common.Address, key string, blockNum rpctypes.BlockNumber) (hexutil.Bytes, error) { // nolint: interfacer
e.logger.Debugln("eth_getStorageAt", "address", address.Hex(), "key", key, "block number", blockNum)
req := &evmtypes.QueryStorageRequest{
@ -241,7 +242,7 @@ func (e *PublicEthAPI) GetStorageAt(address common.Address, key string, blockNum
}
// GetTransactionCount returns the number of transactions at the given address up to the given block number.
func (e *PublicEthAPI) GetTransactionCount(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Uint64, error) {
func (e *PublicAPI) GetTransactionCount(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Uint64, error) {
e.logger.Debugln("eth_getTransactionCount", "address", address.Hex(), "block number", blockNum)
// Get nonce (sequence) from account
@ -265,7 +266,7 @@ func (e *PublicEthAPI) GetTransactionCount(address common.Address, blockNum rpct
}
// GetBlockTransactionCountByHash returns the number of transactions in the block identified by hash.
func (e *PublicEthAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint {
func (e *PublicAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint {
e.logger.Debugln("eth_getBlockTransactionCountByHash", "hash", hash.Hex())
resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes())
@ -278,7 +279,7 @@ func (e *PublicEthAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil
}
// GetBlockTransactionCountByNumber returns the number of transactions in the block identified by number.
func (e *PublicEthAPI) GetBlockTransactionCountByNumber(blockNum rpctypes.BlockNumber) *hexutil.Uint {
func (e *PublicAPI) GetBlockTransactionCountByNumber(blockNum rpctypes.BlockNumber) *hexutil.Uint {
e.logger.Debugln("eth_getBlockTransactionCountByNumber", "block number", blockNum)
resBlock, err := e.clientCtx.Client.Block(e.ctx, blockNum.TmHeight())
if err != nil {
@ -290,17 +291,17 @@ func (e *PublicEthAPI) GetBlockTransactionCountByNumber(blockNum rpctypes.BlockN
}
// GetUncleCountByBlockHash returns the number of uncles in the block identified by hash. Always zero.
func (e *PublicEthAPI) GetUncleCountByBlockHash(hash common.Hash) hexutil.Uint {
func (e *PublicAPI) GetUncleCountByBlockHash(hash common.Hash) hexutil.Uint {
return 0
}
// GetUncleCountByBlockNumber returns the number of uncles in the block identified by number. Always zero.
func (e *PublicEthAPI) GetUncleCountByBlockNumber(blockNum rpctypes.BlockNumber) hexutil.Uint {
func (e *PublicAPI) GetUncleCountByBlockNumber(blockNum rpctypes.BlockNumber) hexutil.Uint {
return 0
}
// GetCode returns the contract code at the given address and block number.
func (e *PublicEthAPI) GetCode(address common.Address, blockNumber rpctypes.BlockNumber) (hexutil.Bytes, error) { // nolint: interfacer
func (e *PublicAPI) GetCode(address common.Address, blockNumber rpctypes.BlockNumber) (hexutil.Bytes, error) { // nolint: interfacer
e.logger.Debugln("eth_getCode", "address", address.Hex(), "block number", blockNumber)
req := &evmtypes.QueryCodeRequest{
@ -316,13 +317,13 @@ func (e *PublicEthAPI) GetCode(address common.Address, blockNumber rpctypes.Bloc
}
// GetTransactionLogs returns the logs given a transaction hash.
func (e *PublicEthAPI) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) {
func (e *PublicAPI) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) {
e.logger.Debugln("eth_getTransactionLogs", "hash", txHash)
return e.backend.GetTransactionLogs(txHash)
}
// Sign signs the provided data using the private key of address via Geth's signature standard.
func (e *PublicEthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
func (e *PublicAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
e.logger.Debugln("eth_sign", "address", address.Hex(), "data", common.Bytes2Hex(data))
from := sdk.AccAddress(address.Bytes())
@ -345,7 +346,7 @@ func (e *PublicEthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil
}
// SendTransaction sends an Ethereum transaction.
func (e *PublicEthAPI) SendTransaction(args rpctypes.SendTxArgs) (common.Hash, error) {
func (e *PublicAPI) SendTransaction(args rpctypes.SendTxArgs) (common.Hash, error) {
e.logger.Debugln("eth_sendTransaction", "args", args)
// Look up the wallet containing the requested signer
@ -428,7 +429,7 @@ func (e *PublicEthAPI) SendTransaction(args rpctypes.SendTxArgs) (common.Hash, e
}
// SendRawTransaction send a raw Ethereum transaction.
func (e *PublicEthAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
e.logger.Debugln("eth_sendRawTransaction", "data_len", len(data))
// RLP decode raw transaction bytes
@ -491,7 +492,7 @@ func (e *PublicEthAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, erro
}
// Call performs a raw contract call.
func (e *PublicEthAPI) Call(args rpctypes.CallArgs, blockNr rpctypes.BlockNumber, _ *rpctypes.StateOverride) (hexutil.Bytes, error) {
func (e *PublicAPI) Call(args rpctypes.CallArgs, blockNr rpctypes.BlockNumber, _ *rpctypes.StateOverride) (hexutil.Bytes, error) {
e.logger.Debugln("eth_call", "args", args, "block number", blockNr)
simRes, err := e.doCall(args, blockNr, big.NewInt(ethermint.DefaultRPCGasLimit))
if err != nil {
@ -513,7 +514,7 @@ func (e *PublicEthAPI) Call(args rpctypes.CallArgs, blockNr rpctypes.BlockNumber
// DoCall performs a simulated call operation through the evmtypes. It returns the
// estimated gas used on the operation or an error if fails.
func (e *PublicEthAPI) doCall(
func (e *PublicAPI) doCall(
args rpctypes.CallArgs, blockNr rpctypes.BlockNumber, globalGasCap *big.Int,
) (*sdk.SimulationResponse, error) {
// Set default gas & gas price if none were set
@ -627,7 +628,7 @@ func (e *PublicEthAPI) doCall(
// EstimateGas returns an estimate of gas usage for the given smart contract call.
// It adds 1,000 gas to the returned value instead of using the gas adjustment
// param from the SDK.
func (e *PublicEthAPI) EstimateGas(args rpctypes.CallArgs) (hexutil.Uint64, error) {
func (e *PublicAPI) EstimateGas(args rpctypes.CallArgs) (hexutil.Uint64, error) {
e.logger.Debugln("eth_estimateGas")
// From ContextWithHeight: if the provided height is 0,
@ -656,19 +657,19 @@ func (e *PublicEthAPI) EstimateGas(args rpctypes.CallArgs) (hexutil.Uint64, erro
}
// GetBlockByHash returns the block identified by hash.
func (e *PublicEthAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
func (e *PublicAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
e.logger.Debugln("eth_getBlockByHash", "hash", hash.Hex(), "full", fullTx)
return e.backend.GetBlockByHash(hash, fullTx)
}
// GetBlockByNumber returns the block identified by number.
func (e *PublicEthAPI) GetBlockByNumber(ethBlockNum rpctypes.BlockNumber, fullTx bool) (map[string]interface{}, error) {
func (e *PublicAPI) GetBlockByNumber(ethBlockNum rpctypes.BlockNumber, fullTx bool) (map[string]interface{}, error) {
e.logger.Debugln("eth_getBlockByNumber", "number", ethBlockNum, "full", fullTx)
return e.backend.GetBlockByNumber(ethBlockNum, fullTx)
}
// GetTransactionByHash returns the transaction identified by hash.
func (e *PublicEthAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransaction, error) {
func (e *PublicAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransaction, error) {
e.logger.Debugln("eth_getTransactionByHash", "hash", hash.Hex())
res, err := e.clientCtx.Client.Tx(e.ctx, hash.Bytes(), false)
@ -713,7 +714,7 @@ func (e *PublicEthAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTran
}
// GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index.
func (e *PublicEthAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
e.logger.Debugln("eth_getTransactionByBlockHashAndIndex", "hash", hash.Hex(), "index", idx)
resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes())
@ -756,7 +757,7 @@ func (e *PublicEthAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx h
}
// GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index.
func (e *PublicEthAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
func (e *PublicAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
e.logger.Debugln("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx)
resBlock, err := e.clientCtx.Client.Block(e.ctx, blockNum.TmHeight())
@ -803,7 +804,7 @@ func (e *PublicEthAPI) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.Blo
}
// GetTransactionReceipt returns the transaction receipt identified by hash.
func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
e.logger.Debugln("eth_getTransactionReceipt", "hash", hash.Hex())
res, err := e.clientCtx.Client.Tx(e.ctx, hash.Bytes(), false)
@ -908,23 +909,23 @@ func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]inter
// 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 *PublicEthAPI) PendingTransactions() ([]*rpctypes.RPCTransaction, error) {
func (e *PublicAPI) PendingTransactions() ([]*rpctypes.RPCTransaction, error) {
e.logger.Debugln("eth_getPendingTransactions")
return e.backend.PendingTransactions()
}
// GetUncleByBlockHashAndIndex returns the uncle identified by hash and index. Always returns nil.
func (e *PublicEthAPI) GetUncleByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) map[string]interface{} {
func (e *PublicAPI) GetUncleByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) map[string]interface{} {
return nil
}
// GetUncleByBlockNumberAndIndex returns the uncle identified by number and index. Always returns nil.
func (e *PublicEthAPI) GetUncleByBlockNumberAndIndex(number hexutil.Uint, idx hexutil.Uint) map[string]interface{} {
func (e *PublicAPI) GetUncleByBlockNumberAndIndex(number hexutil.Uint, idx hexutil.Uint) map[string]interface{} {
return nil
}
// GetProof returns an account object with proof and any storage proofs
func (e *PublicEthAPI) GetProof(address common.Address, storageKeys []string, blockNumber rpctypes.BlockNumber) (*rpctypes.AccountResult, error) {
func (e *PublicAPI) GetProof(address common.Address, storageKeys []string, blockNumber rpctypes.BlockNumber) (*rpctypes.AccountResult, error) {
height := blockNumber.Int64()
e.logger.Debugln("eth_getProof", "address", address.Hex(), "keys", storageKeys, "number", height)
@ -994,7 +995,7 @@ func (e *PublicEthAPI) GetProof(address common.Address, storageKeys []string, bl
// setTxDefaults populates tx message with default values in case they are not
// provided on the args
func (e *PublicEthAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs, error) {
func (e *PublicAPI) setTxDefaults(args rpctypes.SendTxArgs) (rpctypes.SendTxArgs, error) {
// Get nonce (sequence) from sender account
from := sdk.AccAddress(args.From.Bytes())

View File

@ -1,4 +1,4 @@
package rpc
package filters
import (
"context"
@ -57,8 +57,8 @@ type PublicFilterAPI struct {
filters map[rpc.ID]*filter
}
// NewPublicFilterAPI returns a new PublicFilterAPI instance.
func NewPublicFilterAPI(tmWSClient *rpcclient.WSClient, backend FiltersBackend) *PublicFilterAPI {
// NewPublicAPI returns a new PublicFilterAPI instance.
func NewPublicAPI(tmWSClient *rpcclient.WSClient, backend FiltersBackend) *PublicFilterAPI {
api := &PublicFilterAPI{
backend: backend,
filters: make(map[rpc.ID]*filter),
@ -371,7 +371,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit filters.FilterCriteri
return
}
logs := filterLogs(evmtypes.LogsToEthereum(txResponse.Logs), crit.FromBlock, crit.ToBlock, crit.Addresses, crit.Topics)
logs := FilterLogs(evmtypes.LogsToEthereum(txResponse.Logs), crit.FromBlock, crit.ToBlock, crit.Addresses, crit.Topics)
for _, log := range logs {
err = notifier.Notify(rpcSub.ID, log)
@ -448,7 +448,7 @@ func (api *PublicFilterAPI) NewFilter(criteria filters.FilterCriteria) (rpc.ID,
return
}
logs := filterLogs(evmtypes.LogsToEthereum(txResponse.Logs), criteria.FromBlock, criteria.ToBlock, criteria.Addresses, criteria.Topics)
logs := FilterLogs(evmtypes.LogsToEthereum(txResponse.Logs), criteria.FromBlock, criteria.ToBlock, criteria.Addresses, criteria.Topics)
api.filtersMu.Lock()
if f, found := api.filters[filterID]; found {
@ -595,21 +595,3 @@ func (api *PublicFilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
return nil, fmt.Errorf("invalid filter %s type %d", id, f.typ)
}
}
// returnHashes is a helper that will return an empty hash array case the given hash array is nil,
// otherwise the given hashes array is returned.
func returnHashes(hashes []common.Hash) []common.Hash {
if hashes == nil {
return []common.Hash{}
}
return hashes
}
// returnLogs is a helper that will return an empty log array in case the given logs array is nil,
// otherwise the given logs array is returned.
func returnLogs(logs []*ethtypes.Log) []*ethtypes.Log {
if logs == nil {
return []*ethtypes.Log{}
}
return logs
}

View File

@ -1,4 +1,4 @@
package rpc
package filters
import (
"context"
@ -297,49 +297,3 @@ func (es *EventSystem) consumeEvents() {
time.Sleep(time.Second)
}
}
// Subscription defines a wrapper for the private subscription
type Subscription struct {
id rpc.ID
typ filters.Type
event string
created time.Time
logsCrit filters.FilterCriteria
logs chan []*ethtypes.Log
hashes chan []common.Hash
headers chan *ethtypes.Header
installed chan struct{} // closed when the filter is installed
eventCh <-chan coretypes.ResultEvent
err chan error
}
// ID returns the underlying subscription RPC identifier.
func (s Subscription) ID() rpc.ID {
return s.id
}
// Unsubscribe from the current subscription to Tendermint Websocket. It sends an error to the
// subscription error channel if unsubscription fails.
func (s *Subscription) Unsubscribe(es *EventSystem) {
go func() {
uninstallLoop:
for {
// write uninstall request and consume logs/hashes. This prevents
// the eventLoop broadcast method to deadlock when writing to the
// filter event channel while the subscription loop is waiting for
// this method to return (and thus not reading these events).
select {
case es.uninstall <- s:
break uninstallLoop
case <-s.logs:
case <-s.hashes:
case <-s.headers:
}
}
}()
}
// Err returns the error channel
func (s *Subscription) Err() <-chan error {
return s.err
}

View File

@ -1,4 +1,4 @@
package rpc
package filters
import (
"context"
@ -198,7 +198,7 @@ func (f *Filter) blockLogs(header *ethtypes.Header) ([]*ethtypes.Log, error) {
unfiltered = append(unfiltered, logs...)
}
logs := filterLogs(unfiltered, nil, nil, f.criteria.Addresses, f.criteria.Topics)
logs := FilterLogs(unfiltered, nil, nil, f.criteria.Addresses, f.criteria.Topics)
if len(logs) == 0 {
return []*ethtypes.Log{}, nil
}
@ -222,81 +222,5 @@ func (f *Filter) checkMatches(transactions []common.Hash) []*ethtypes.Log {
unfiltered = append(unfiltered, logs...)
}
return filterLogs(unfiltered, f.criteria.FromBlock, f.criteria.ToBlock, f.criteria.Addresses, f.criteria.Topics)
}
// filterLogs creates a slice of logs matching the given criteria.
// [] -> anything
// [A] -> A in first position of log topics, anything after
// [null, B] -> anything in first position, B in second position
// [A, B] -> A in first position and B in second position
// [[A, B], [A, B]] -> A or B in first position, A or B in second position
func filterLogs(logs []*ethtypes.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*ethtypes.Log {
var ret []*ethtypes.Log
Logs:
for _, log := range logs {
if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > log.BlockNumber {
continue
}
if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber {
continue
}
if len(addresses) > 0 && !includes(addresses, log.Address) {
continue
}
// If the to filtered topics is greater than the amount of topics in logs, skip.
if len(topics) > len(log.Topics) {
continue
}
for i, sub := range topics {
match := len(sub) == 0 // empty rule set == wildcard
for _, topic := range sub {
if log.Topics[i] == topic {
match = true
break
}
}
if !match {
continue Logs
}
}
ret = append(ret, log)
}
return ret
}
func includes(addresses []common.Address, a common.Address) bool {
for _, addr := range addresses {
if addr == a {
return true
}
}
return false
}
func bloomFilter(bloom ethtypes.Bloom, addresses []common.Address, topics [][]common.Hash) bool {
var included bool
if len(addresses) > 0 {
for _, addr := range addresses {
if ethtypes.BloomLookup(bloom, addr) {
included = true
break
}
}
if !included {
return false
}
}
for _, sub := range topics {
included = len(sub) == 0 // empty rule set == wildcard
for _, topic := range sub {
if ethtypes.BloomLookup(bloom, topic) {
included = true
break
}
}
}
return included
return FilterLogs(unfiltered, f.criteria.FromBlock, f.criteria.ToBlock, f.criteria.Addresses, f.criteria.Topics)
}

View File

@ -0,0 +1,62 @@
package filters
import (
"time"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/rpc"
coretypes "github.com/tendermint/tendermint/rpc/core/types"
)
// Subscription defines a wrapper for the private subscription
type Subscription struct {
id rpc.ID
typ filters.Type
event string
created time.Time
logsCrit filters.FilterCriteria
logs chan []*ethtypes.Log
hashes chan []common.Hash
headers chan *ethtypes.Header
installed chan struct{} // closed when the filter is installed
eventCh <-chan coretypes.ResultEvent
err chan error
}
// ID returns the underlying subscription RPC identifier.
func (s Subscription) ID() rpc.ID {
return s.id
}
// Unsubscribe from the current subscription to Tendermint Websocket. It sends an error to the
// subscription error channel if unsubscription fails.
func (s *Subscription) Unsubscribe(es *EventSystem) {
go func() {
uninstallLoop:
for {
// write uninstall request and consume logs/hashes. This prevents
// the eventLoop broadcast method to deadlock when writing to the
// filter event channel while the subscription loop is waiting for
// this method to return (and thus not reading these events).
select {
case es.uninstall <- s:
break uninstallLoop
case <-s.logs:
case <-s.hashes:
case <-s.headers:
}
}
}()
}
// Err returns the error channel
func (s *Subscription) Err() <-chan error {
return s.err
}
// Event returns the tendermint result event channel
func (s *Subscription) Event() <-chan coretypes.ResultEvent {
return s.eventCh
}

View File

@ -0,0 +1,102 @@
package filters
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
// FilterLogs creates a slice of logs matching the given criteria.
// [] -> anything
// [A] -> A in first position of log topics, anything after
// [null, B] -> anything in first position, B in second position
// [A, B] -> A in first position and B in second position
// [[A, B], [A, B]] -> A or B in first position, A or B in second position
func FilterLogs(logs []*ethtypes.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*ethtypes.Log {
var ret []*ethtypes.Log
Logs:
for _, log := range logs {
if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > log.BlockNumber {
continue
}
if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber {
continue
}
if len(addresses) > 0 && !includes(addresses, log.Address) {
continue
}
// If the to filtered topics is greater than the amount of topics in logs, skip.
if len(topics) > len(log.Topics) {
continue
}
for i, sub := range topics {
match := len(sub) == 0 // empty rule set == wildcard
for _, topic := range sub {
if log.Topics[i] == topic {
match = true
break
}
}
if !match {
continue Logs
}
}
ret = append(ret, log)
}
return ret
}
func includes(addresses []common.Address, a common.Address) bool {
for _, addr := range addresses {
if addr == a {
return true
}
}
return false
}
func bloomFilter(bloom ethtypes.Bloom, addresses []common.Address, topics [][]common.Hash) bool {
var included bool
if len(addresses) > 0 {
for _, addr := range addresses {
if ethtypes.BloomLookup(bloom, addr) {
included = true
break
}
}
if !included {
return false
}
}
for _, sub := range topics {
included = len(sub) == 0 // empty rule set == wildcard
for _, topic := range sub {
if ethtypes.BloomLookup(bloom, topic) {
included = true
break
}
}
}
return included
}
// returnHashes is a helper that will return an empty hash array case the given hash array is nil,
// otherwise the given hashes array is returned.
func returnHashes(hashes []common.Hash) []common.Hash {
if hashes == nil {
return []common.Hash{}
}
return hashes
}
// returnLogs is a helper that will return an empty log array in case the given logs array is nil,
// otherwise the given logs array is returned.
func returnLogs(logs []*ethtypes.Log) []*ethtypes.Log {
if logs == nil {
return []*ethtypes.Log{}
}
return logs
}

View File

@ -1,4 +1,4 @@
package rpc
package net
import (
"fmt"
@ -8,25 +8,25 @@ import (
"github.com/cosmos/cosmos-sdk/client"
)
// PublicNetAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PublicNetAPI struct {
// PublicAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PublicAPI struct {
networkVersion uint64
}
// NewPublicNetAPI creates an instance of the public Net Web3 API.
func NewPublicNetAPI(clientCtx client.Context) *PublicNetAPI {
// NewPublicAPI creates an instance of the public Net Web3 API.
func NewPublicAPI(clientCtx client.Context) *PublicAPI {
// parse the chainID from a integer string
chainIDEpoch, err := ethermint.ParseChainID(clientCtx.ChainID)
if err != nil {
panic(err)
}
return &PublicNetAPI{
return &PublicAPI{
networkVersion: chainIDEpoch.Uint64(),
}
}
// Version returns the current ethereum protocol version.
func (s *PublicNetAPI) Version() string {
func (s *PublicAPI) Version() string {
return fmt.Sprintf("%d", s.networkVersion)
}

View File

@ -1,4 +1,4 @@
package rpc
package personal
import (
"context"
@ -21,17 +21,18 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/eth"
rpctypes "github.com/tharsis/ethermint/ethereum/rpc/types"
)
// PrivateAccountAPI is the personal_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PrivateAccountAPI struct {
ethAPI *PublicEthAPI
ethAPI *eth.PublicAPI
logger log.Logger
}
// NewPersonalAPI creates an instance of the public Personal Eth API.
func NewPersonalAPI(ethAPI *PublicEthAPI) *PrivateAccountAPI {
// NewAPI creates an instance of the public Personal Eth API.
func NewAPI(ethAPI *eth.PublicAPI) *PrivateAccountAPI {
return &PrivateAccountAPI{
ethAPI: ethAPI,
logger: log.WithField("module", "personal"),

View File

@ -1,4 +1,4 @@
package rpc
package txpool
import (
"github.com/ethereum/go-ethereum/common/hexutil"
@ -6,21 +6,21 @@ import (
log "github.com/xlab/suplog"
)
// PublicTxPoolAPI offers and API for the transaction pool. It only operates on data that is non-confidential.
// PublicAPI offers and API for the transaction pool. It only operates on data that is non-confidential.
// NOTE: For more info about the current status of this endpoints see https://github.com/tharsis/ethermint/issues/124
type PublicTxPoolAPI struct {
type PublicAPI struct {
logger log.Logger
}
// NewPublicTxPoolAPI creates a new tx pool service that gives information about the transaction pool.
func NewPublicTxPoolAPI() *PublicTxPoolAPI {
return &PublicTxPoolAPI{
// NewPublicAPI creates a new tx pool service that gives information about the transaction pool.
func NewPublicAPI() *PublicAPI {
return &PublicAPI{
logger: log.WithField("module", "txpool"),
}
}
// Content returns the transactions contained within the transaction pool
func (api *PublicTxPoolAPI) Content() (map[string]map[string]map[string]*types.RPCTransaction, error) {
func (api *PublicAPI) Content() (map[string]map[string]map[string]*types.RPCTransaction, error) {
api.logger.Debug("txpool_content")
content := map[string]map[string]map[string]*types.RPCTransaction{
"pending": make(map[string]map[string]*types.RPCTransaction),
@ -30,7 +30,7 @@ func (api *PublicTxPoolAPI) Content() (map[string]map[string]map[string]*types.R
}
// Inspect returns the content of the transaction pool and flattens it into an
func (api *PublicTxPoolAPI) Inspect() (map[string]map[string]map[string]string, error) {
func (api *PublicAPI) Inspect() (map[string]map[string]map[string]string, error) {
api.logger.Debug("txpool_inspect")
content := map[string]map[string]map[string]string{
"pending": make(map[string]map[string]string),
@ -40,7 +40,7 @@ func (api *PublicTxPoolAPI) Inspect() (map[string]map[string]map[string]string,
}
// Status returns the number of pending and queued transaction in the pool.
func (api *PublicTxPoolAPI) Status() map[string]hexutil.Uint {
func (api *PublicAPI) Status() map[string]hexutil.Uint {
api.logger.Debug("txpool_status")
return map[string]hexutil.Uint{
"pending": hexutil.Uint(0),

View File

@ -0,0 +1,26 @@
package web3
import (
"github.com/tharsis/ethermint/version"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
// PublicAPI is the web3_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PublicAPI struct{}
// NewPublicAPI creates an instance of the Web3 API.
func NewPublicAPI() *PublicAPI {
return &PublicAPI{}
}
// ClientVersion returns the client version in the Web3 user agent format.
func (a *PublicAPI) ClientVersion() string {
return version.Version()
}
// Sha3 returns the keccak-256 hash of the passed-in input.
func (a *PublicAPI) Sha3(input hexutil.Bytes) hexutil.Bytes {
return crypto.Keccak256(input)
}

View File

@ -1,26 +0,0 @@
package rpc
import (
"github.com/tharsis/ethermint/version"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
// PublicWeb3API is the web3_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PublicWeb3API struct{}
// NewPublicWeb3API creates an instance of the Web3 API.
func NewPublicWeb3API() *PublicWeb3API {
return &PublicWeb3API{}
}
// ClientVersion returns the client version in the Web3 user agent format.
func (a *PublicWeb3API) ClientVersion() string {
return version.Version()
}
// Sha3 returns the keccak-256 hash of the passed-in input.
func (a *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
return crypto.Keccak256(input)
}

View File

@ -9,6 +9,10 @@ import (
"net/http"
"sync"
"github.com/ethereum/go-ethereum/eth/filters"
rpcfilters "github.com/tharsis/ethermint/ethereum/rpc/namespaces/eth/filters"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
@ -19,7 +23,6 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/rpc"
"github.com/tharsis/ethermint/ethereum/rpc/types"
@ -262,7 +265,7 @@ func (s *websocketsServer) tcpGetAndSendResponse(wsConn *wsConn, mb []byte) erro
}
type wsSubscription struct {
sub *Subscription
sub *rpcfilters.Subscription
unsubscribed chan struct{} // closed when unsubscribing
wsConn *wsConn
query string
@ -270,7 +273,7 @@ type wsSubscription struct {
// pubSubAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec
type pubSubAPI struct {
events *EventSystem
events *rpcfilters.EventSystem
filtersMu *sync.RWMutex
filters map[rpc.ID]*wsSubscription
logger log.Logger
@ -279,7 +282,7 @@ type pubSubAPI struct {
// newPubSubAPI creates an instance of the ethereum PubSub API.
func newPubSubAPI(tmWSClient *rpcclient.WSClient) *pubSubAPI {
return &pubSubAPI{
events: NewEventSystem(tmWSClient),
events: rpcfilters.NewEventSystem(tmWSClient),
filtersMu: new(sync.RWMutex),
filters: make(map[rpc.ID]*wsSubscription),
logger: log.WithField("module", "websocket-client"),
@ -414,7 +417,7 @@ func (api *pubSubAPI) subscribeNewHeads(wsConn *wsConn) (rpc.ID, error) {
return
}
}
}(sub.eventCh, sub.Err())
}(sub.Event(), sub.Err())
return subID, nil
}
@ -604,7 +607,7 @@ func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, extra interface{}) (rpc.ID,
return
}
logs := filterLogs(evmtypes.LogsToEthereum(txResponse.Logs), crit.FromBlock, crit.ToBlock, crit.Addresses, crit.Topics)
logs := rpcfilters.FilterLogs(evmtypes.LogsToEthereum(txResponse.Logs), crit.FromBlock, crit.ToBlock, crit.Addresses, crit.Topics)
if len(logs) == 0 {
continue
}
@ -653,7 +656,7 @@ func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, extra interface{}) (rpc.ID,
return
}
}
}(sub.eventCh, sub.Err(), subID)
}(sub.Event(), sub.Err(), subID)
return subID, nil
}
@ -730,7 +733,7 @@ func (api *pubSubAPI) subscribePendingTransactions(wsConn *wsConn) (rpc.ID, erro
return
}
}
}(sub.eventCh, sub.Err())
}(sub.Event(), sub.Err())
return subID, nil
}