forked from cerc-io/laconicd-deprecated
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:
parent
1f962044e2
commit
1c06553746
@ -5,6 +5,13 @@ package rpc
|
|||||||
import (
|
import (
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"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"
|
"github.com/tharsis/ethermint/ethereum/rpc/types"
|
||||||
|
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
|
rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
|
||||||
@ -24,14 +31,14 @@ const (
|
|||||||
// GetRPCAPIs returns the list of all APIs
|
// GetRPCAPIs returns the list of all APIs
|
||||||
func GetRPCAPIs(clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API {
|
func GetRPCAPIs(clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API {
|
||||||
nonceLock := new(types.AddrLocker)
|
nonceLock := new(types.AddrLocker)
|
||||||
backend := NewEVMBackend(clientCtx)
|
backend := backend.NewEVMBackend(clientCtx)
|
||||||
ethAPI := NewPublicEthAPI(clientCtx, backend, nonceLock)
|
ethAPI := eth.NewPublicAPI(clientCtx, backend, nonceLock)
|
||||||
|
|
||||||
return []rpc.API{
|
return []rpc.API{
|
||||||
{
|
{
|
||||||
Namespace: Web3Namespace,
|
Namespace: Web3Namespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: NewPublicWeb3API(),
|
Service: web3.NewPublicAPI(),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -43,25 +50,25 @@ func GetRPCAPIs(clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.
|
|||||||
{
|
{
|
||||||
Namespace: EthNamespace,
|
Namespace: EthNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: NewPublicFilterAPI(tmWSClient, backend),
|
Service: filters.NewPublicAPI(tmWSClient, backend),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: NetNamespace,
|
Namespace: NetNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: NewPublicNetAPI(clientCtx),
|
Service: net.NewPublicAPI(clientCtx),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: PersonalNamespace,
|
Namespace: PersonalNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: NewPersonalAPI(ethAPI),
|
Service: personal.NewAPI(ethAPI),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: TxPoolNamespace,
|
Namespace: TxPoolNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: NewPublicTxPoolAPI(),
|
Service: txpool.NewPublicAPI(),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package rpc
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
@ -1,4 +1,4 @@
|
|||||||
package rpc
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -30,28 +30,29 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
||||||
"github.com/tharsis/ethermint/crypto/hd"
|
"github.com/tharsis/ethermint/crypto/hd"
|
||||||
|
"github.com/tharsis/ethermint/ethereum/rpc/backend"
|
||||||
rpctypes "github.com/tharsis/ethermint/ethereum/rpc/types"
|
rpctypes "github.com/tharsis/ethermint/ethereum/rpc/types"
|
||||||
ethermint "github.com/tharsis/ethermint/types"
|
ethermint "github.com/tharsis/ethermint/types"
|
||||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PublicEthAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
// PublicAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
||||||
type PublicEthAPI struct {
|
type PublicAPI struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
clientCtx client.Context
|
clientCtx client.Context
|
||||||
queryClient *rpctypes.QueryClient
|
queryClient *rpctypes.QueryClient
|
||||||
chainIDEpoch *big.Int
|
chainIDEpoch *big.Int
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
backend Backend
|
backend backend.Backend
|
||||||
nonceLock *rpctypes.AddrLocker
|
nonceLock *rpctypes.AddrLocker
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublicEthAPI creates an instance of the public ETH Web3 API.
|
// NewPublicAPI creates an instance of the public ETH Web3 API.
|
||||||
func NewPublicEthAPI(
|
func NewPublicAPI(
|
||||||
clientCtx client.Context,
|
clientCtx client.Context,
|
||||||
backend Backend,
|
backend backend.Backend,
|
||||||
nonceLock *rpctypes.AddrLocker,
|
nonceLock *rpctypes.AddrLocker,
|
||||||
) *PublicEthAPI {
|
) *PublicAPI {
|
||||||
epoch, err := ethermint.ParseChainID(clientCtx.ChainID)
|
epoch, err := ethermint.ParseChainID(clientCtx.ChainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -75,7 +76,7 @@ func NewPublicEthAPI(
|
|||||||
clientCtx = clientCtx.WithKeyring(kr)
|
clientCtx = clientCtx.WithKeyring(kr)
|
||||||
}
|
}
|
||||||
|
|
||||||
api := &PublicEthAPI{
|
api := &PublicAPI{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
clientCtx: clientCtx,
|
clientCtx: clientCtx,
|
||||||
queryClient: rpctypes.NewQueryClient(clientCtx),
|
queryClient: rpctypes.NewQueryClient(clientCtx),
|
||||||
@ -89,25 +90,25 @@ func NewPublicEthAPI(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ClientCtx returns client context
|
// ClientCtx returns client context
|
||||||
func (e *PublicEthAPI) ClientCtx() client.Context {
|
func (e *PublicAPI) ClientCtx() client.Context {
|
||||||
return e.clientCtx
|
return e.clientCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProtocolVersion returns the supported Ethereum protocol version.
|
// ProtocolVersion returns the supported Ethereum protocol version.
|
||||||
func (e *PublicEthAPI) ProtocolVersion() hexutil.Uint {
|
func (e *PublicAPI) ProtocolVersion() hexutil.Uint {
|
||||||
e.logger.Debugln("eth_protocolVersion")
|
e.logger.Debugln("eth_protocolVersion")
|
||||||
return hexutil.Uint(ethermint.ProtocolVersion)
|
return hexutil.Uint(ethermint.ProtocolVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainId returns the chain's identifier in hex format
|
// 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")
|
e.logger.Debugln("eth_chainId")
|
||||||
return hexutil.Uint(uint(e.chainIDEpoch.Uint64())), nil
|
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
|
// 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.
|
// 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")
|
e.logger.Debugln("eth_syncing")
|
||||||
|
|
||||||
status, err := e.clientCtx.Client.Status(e.ctx)
|
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).
|
// 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")
|
e.logger.Debugln("eth_coinbase")
|
||||||
|
|
||||||
node, err := e.clientCtx.GetNode()
|
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.
|
// 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")
|
e.logger.Debugln("eth_mining")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hashrate returns the current node's hashrate. Always 0.
|
// 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")
|
e.logger.Debugln("eth_hashrate")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// GasPrice returns the current gas price based on Ethermint's gas price oracle.
|
// 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")
|
e.logger.Debugln("eth_gasPrice")
|
||||||
// TODO: use minimum value defined in config instead of default or implement oracle
|
// TODO: use minimum value defined in config instead of default or implement oracle
|
||||||
out := big.NewInt(ethermint.DefaultGasPrice)
|
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.
|
// 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")
|
e.logger.Debugln("eth_accounts")
|
||||||
|
|
||||||
addresses := make([]common.Address, 0) // return [] instead of nil if empty
|
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.
|
// 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")
|
//e.logger.Debugln("eth_blockNumber")
|
||||||
return e.backend.BlockNumber()
|
return e.backend.BlockNumber()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBalance returns the provided account's balance up to the provided block number.
|
// 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)
|
e.logger.Debugln("eth_getBalance", "address", address.String(), "block number", blockNum)
|
||||||
|
|
||||||
req := &evmtypes.QueryBalanceRequest{
|
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.
|
// 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)
|
e.logger.Debugln("eth_getStorageAt", "address", address.Hex(), "key", key, "block number", blockNum)
|
||||||
|
|
||||||
req := &evmtypes.QueryStorageRequest{
|
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.
|
// 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)
|
e.logger.Debugln("eth_getTransactionCount", "address", address.Hex(), "block number", blockNum)
|
||||||
|
|
||||||
// Get nonce (sequence) from account
|
// 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.
|
// 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())
|
e.logger.Debugln("eth_getBlockTransactionCountByHash", "hash", hash.Hex())
|
||||||
|
|
||||||
resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes())
|
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.
|
// 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)
|
e.logger.Debugln("eth_getBlockTransactionCountByNumber", "block number", blockNum)
|
||||||
resBlock, err := e.clientCtx.Client.Block(e.ctx, blockNum.TmHeight())
|
resBlock, err := e.clientCtx.Client.Block(e.ctx, blockNum.TmHeight())
|
||||||
if err != nil {
|
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.
|
// 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
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUncleCountByBlockNumber returns the number of uncles in the block identified by number. Always zero.
|
// 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
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCode returns the contract code at the given address and block number.
|
// 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)
|
e.logger.Debugln("eth_getCode", "address", address.Hex(), "block number", blockNumber)
|
||||||
|
|
||||||
req := &evmtypes.QueryCodeRequest{
|
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.
|
// 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)
|
e.logger.Debugln("eth_getTransactionLogs", "hash", txHash)
|
||||||
return e.backend.GetTransactionLogs(txHash)
|
return e.backend.GetTransactionLogs(txHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign signs the provided data using the private key of address via Geth's signature standard.
|
// 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))
|
e.logger.Debugln("eth_sign", "address", address.Hex(), "data", common.Bytes2Hex(data))
|
||||||
|
|
||||||
from := sdk.AccAddress(address.Bytes())
|
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.
|
// 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)
|
e.logger.Debugln("eth_sendTransaction", "args", args)
|
||||||
|
|
||||||
// Look up the wallet containing the requested signer
|
// 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.
|
// 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))
|
e.logger.Debugln("eth_sendRawTransaction", "data_len", len(data))
|
||||||
|
|
||||||
// RLP decode raw transaction bytes
|
// 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.
|
// 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)
|
e.logger.Debugln("eth_call", "args", args, "block number", blockNr)
|
||||||
simRes, err := e.doCall(args, blockNr, big.NewInt(ethermint.DefaultRPCGasLimit))
|
simRes, err := e.doCall(args, blockNr, big.NewInt(ethermint.DefaultRPCGasLimit))
|
||||||
if err != nil {
|
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
|
// DoCall performs a simulated call operation through the evmtypes. It returns the
|
||||||
// estimated gas used on the operation or an error if fails.
|
// 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,
|
args rpctypes.CallArgs, blockNr rpctypes.BlockNumber, globalGasCap *big.Int,
|
||||||
) (*sdk.SimulationResponse, error) {
|
) (*sdk.SimulationResponse, error) {
|
||||||
// Set default gas & gas price if none were set
|
// 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.
|
// 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
|
// It adds 1,000 gas to the returned value instead of using the gas adjustment
|
||||||
// param from the SDK.
|
// 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")
|
e.logger.Debugln("eth_estimateGas")
|
||||||
|
|
||||||
// From ContextWithHeight: if the provided height is 0,
|
// 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.
|
// 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)
|
e.logger.Debugln("eth_getBlockByHash", "hash", hash.Hex(), "full", fullTx)
|
||||||
return e.backend.GetBlockByHash(hash, fullTx)
|
return e.backend.GetBlockByHash(hash, fullTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockByNumber returns the block identified by number.
|
// 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)
|
e.logger.Debugln("eth_getBlockByNumber", "number", ethBlockNum, "full", fullTx)
|
||||||
return e.backend.GetBlockByNumber(ethBlockNum, fullTx)
|
return e.backend.GetBlockByNumber(ethBlockNum, fullTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionByHash returns the transaction identified by hash.
|
// 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())
|
e.logger.Debugln("eth_getTransactionByHash", "hash", hash.Hex())
|
||||||
|
|
||||||
res, err := e.clientCtx.Client.Tx(e.ctx, hash.Bytes(), false)
|
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.
|
// 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)
|
e.logger.Debugln("eth_getTransactionByBlockHashAndIndex", "hash", hash.Hex(), "index", idx)
|
||||||
|
|
||||||
resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes())
|
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.
|
// 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)
|
e.logger.Debugln("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx)
|
||||||
|
|
||||||
resBlock, err := e.clientCtx.Client.Block(e.ctx, blockNum.TmHeight())
|
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.
|
// 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())
|
e.logger.Debugln("eth_getTransactionReceipt", "hash", hash.Hex())
|
||||||
|
|
||||||
res, err := e.clientCtx.Client.Tx(e.ctx, hash.Bytes(), false)
|
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
|
// PendingTransactions returns the transactions that are in the transaction pool
|
||||||
// and have a from address that is one of the accounts this node manages.
|
// 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")
|
e.logger.Debugln("eth_getPendingTransactions")
|
||||||
return e.backend.PendingTransactions()
|
return e.backend.PendingTransactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUncleByBlockHashAndIndex returns the uncle identified by hash and index. Always returns nil.
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUncleByBlockNumberAndIndex returns the uncle identified by number and index. Always returns 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProof returns an account object with proof and any storage proofs
|
// 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()
|
height := blockNumber.Int64()
|
||||||
e.logger.Debugln("eth_getProof", "address", address.Hex(), "keys", storageKeys, "number", height)
|
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
|
// setTxDefaults populates tx message with default values in case they are not
|
||||||
// provided on the args
|
// 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
|
// Get nonce (sequence) from sender account
|
||||||
from := sdk.AccAddress(args.From.Bytes())
|
from := sdk.AccAddress(args.From.Bytes())
|
@ -1,4 +1,4 @@
|
|||||||
package rpc
|
package filters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -57,8 +57,8 @@ type PublicFilterAPI struct {
|
|||||||
filters map[rpc.ID]*filter
|
filters map[rpc.ID]*filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublicFilterAPI returns a new PublicFilterAPI instance.
|
// NewPublicAPI returns a new PublicFilterAPI instance.
|
||||||
func NewPublicFilterAPI(tmWSClient *rpcclient.WSClient, backend FiltersBackend) *PublicFilterAPI {
|
func NewPublicAPI(tmWSClient *rpcclient.WSClient, backend FiltersBackend) *PublicFilterAPI {
|
||||||
api := &PublicFilterAPI{
|
api := &PublicFilterAPI{
|
||||||
backend: backend,
|
backend: backend,
|
||||||
filters: make(map[rpc.ID]*filter),
|
filters: make(map[rpc.ID]*filter),
|
||||||
@ -371,7 +371,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit filters.FilterCriteri
|
|||||||
return
|
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 {
|
for _, log := range logs {
|
||||||
err = notifier.Notify(rpcSub.ID, log)
|
err = notifier.Notify(rpcSub.ID, log)
|
||||||
@ -448,7 +448,7 @@ func (api *PublicFilterAPI) NewFilter(criteria filters.FilterCriteria) (rpc.ID,
|
|||||||
return
|
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()
|
api.filtersMu.Lock()
|
||||||
if f, found := api.filters[filterID]; found {
|
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)
|
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
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package rpc
|
package filters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -297,49 +297,3 @@ func (es *EventSystem) consumeEvents() {
|
|||||||
time.Sleep(time.Second)
|
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
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package rpc
|
package filters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -198,7 +198,7 @@ func (f *Filter) blockLogs(header *ethtypes.Header) ([]*ethtypes.Log, error) {
|
|||||||
unfiltered = append(unfiltered, logs...)
|
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 {
|
if len(logs) == 0 {
|
||||||
return []*ethtypes.Log{}, nil
|
return []*ethtypes.Log{}, nil
|
||||||
}
|
}
|
||||||
@ -222,81 +222,5 @@ func (f *Filter) checkMatches(transactions []common.Hash) []*ethtypes.Log {
|
|||||||
unfiltered = append(unfiltered, logs...)
|
unfiltered = append(unfiltered, logs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return filterLogs(unfiltered, f.criteria.FromBlock, f.criteria.ToBlock, f.criteria.Addresses, f.criteria.Topics)
|
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
|
|
||||||
}
|
}
|
62
ethereum/rpc/namespaces/eth/filters/subscription.go
Normal file
62
ethereum/rpc/namespaces/eth/filters/subscription.go
Normal 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
|
||||||
|
}
|
102
ethereum/rpc/namespaces/eth/filters/utils.go
Normal file
102
ethereum/rpc/namespaces/eth/filters/utils.go
Normal 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
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package rpc
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -8,25 +8,25 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PublicNetAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
// PublicAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
||||||
type PublicNetAPI struct {
|
type PublicAPI struct {
|
||||||
networkVersion uint64
|
networkVersion uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublicNetAPI creates an instance of the public Net Web3 API.
|
// NewPublicAPI creates an instance of the public Net Web3 API.
|
||||||
func NewPublicNetAPI(clientCtx client.Context) *PublicNetAPI {
|
func NewPublicAPI(clientCtx client.Context) *PublicAPI {
|
||||||
// parse the chainID from a integer string
|
// parse the chainID from a integer string
|
||||||
chainIDEpoch, err := ethermint.ParseChainID(clientCtx.ChainID)
|
chainIDEpoch, err := ethermint.ParseChainID(clientCtx.ChainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &PublicNetAPI{
|
return &PublicAPI{
|
||||||
networkVersion: chainIDEpoch.Uint64(),
|
networkVersion: chainIDEpoch.Uint64(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version returns the current ethereum protocol version.
|
// Version returns the current ethereum protocol version.
|
||||||
func (s *PublicNetAPI) Version() string {
|
func (s *PublicAPI) Version() string {
|
||||||
return fmt.Sprintf("%d", s.networkVersion)
|
return fmt.Sprintf("%d", s.networkVersion)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package rpc
|
package personal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -21,17 +21,18 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
||||||
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
|
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
|
||||||
|
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/eth"
|
||||||
rpctypes "github.com/tharsis/ethermint/ethereum/rpc/types"
|
rpctypes "github.com/tharsis/ethermint/ethereum/rpc/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrivateAccountAPI is the personal_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
// PrivateAccountAPI is the personal_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
||||||
type PrivateAccountAPI struct {
|
type PrivateAccountAPI struct {
|
||||||
ethAPI *PublicEthAPI
|
ethAPI *eth.PublicAPI
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPersonalAPI creates an instance of the public Personal Eth API.
|
// NewAPI creates an instance of the public Personal Eth API.
|
||||||
func NewPersonalAPI(ethAPI *PublicEthAPI) *PrivateAccountAPI {
|
func NewAPI(ethAPI *eth.PublicAPI) *PrivateAccountAPI {
|
||||||
return &PrivateAccountAPI{
|
return &PrivateAccountAPI{
|
||||||
ethAPI: ethAPI,
|
ethAPI: ethAPI,
|
||||||
logger: log.WithField("module", "personal"),
|
logger: log.WithField("module", "personal"),
|
@ -1,4 +1,4 @@
|
|||||||
package rpc
|
package txpool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
@ -6,21 +6,21 @@ import (
|
|||||||
log "github.com/xlab/suplog"
|
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
|
// 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
|
logger log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublicTxPoolAPI creates a new tx pool service that gives information about the transaction pool.
|
// NewPublicAPI creates a new tx pool service that gives information about the transaction pool.
|
||||||
func NewPublicTxPoolAPI() *PublicTxPoolAPI {
|
func NewPublicAPI() *PublicAPI {
|
||||||
return &PublicTxPoolAPI{
|
return &PublicAPI{
|
||||||
logger: log.WithField("module", "txpool"),
|
logger: log.WithField("module", "txpool"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content returns the transactions contained within the transaction pool
|
// 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")
|
api.logger.Debug("txpool_content")
|
||||||
content := map[string]map[string]map[string]*types.RPCTransaction{
|
content := map[string]map[string]map[string]*types.RPCTransaction{
|
||||||
"pending": make(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
|
// 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")
|
api.logger.Debug("txpool_inspect")
|
||||||
content := map[string]map[string]map[string]string{
|
content := map[string]map[string]map[string]string{
|
||||||
"pending": make(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.
|
// 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")
|
api.logger.Debug("txpool_status")
|
||||||
return map[string]hexutil.Uint{
|
return map[string]hexutil.Uint{
|
||||||
"pending": hexutil.Uint(0),
|
"pending": hexutil.Uint(0),
|
26
ethereum/rpc/namespaces/web3/api.go
Normal file
26
ethereum/rpc/namespaces/web3/api.go
Normal 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)
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
|
@ -9,6 +9,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"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/mux"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -19,7 +23,6 @@ import (
|
|||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
"github.com/tharsis/ethermint/ethereum/rpc/types"
|
"github.com/tharsis/ethermint/ethereum/rpc/types"
|
||||||
@ -262,7 +265,7 @@ func (s *websocketsServer) tcpGetAndSendResponse(wsConn *wsConn, mb []byte) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
type wsSubscription struct {
|
type wsSubscription struct {
|
||||||
sub *Subscription
|
sub *rpcfilters.Subscription
|
||||||
unsubscribed chan struct{} // closed when unsubscribing
|
unsubscribed chan struct{} // closed when unsubscribing
|
||||||
wsConn *wsConn
|
wsConn *wsConn
|
||||||
query string
|
query string
|
||||||
@ -270,7 +273,7 @@ type wsSubscription struct {
|
|||||||
|
|
||||||
// pubSubAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec
|
// pubSubAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec
|
||||||
type pubSubAPI struct {
|
type pubSubAPI struct {
|
||||||
events *EventSystem
|
events *rpcfilters.EventSystem
|
||||||
filtersMu *sync.RWMutex
|
filtersMu *sync.RWMutex
|
||||||
filters map[rpc.ID]*wsSubscription
|
filters map[rpc.ID]*wsSubscription
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
@ -279,7 +282,7 @@ type pubSubAPI struct {
|
|||||||
// newPubSubAPI creates an instance of the ethereum PubSub API.
|
// newPubSubAPI creates an instance of the ethereum PubSub API.
|
||||||
func newPubSubAPI(tmWSClient *rpcclient.WSClient) *pubSubAPI {
|
func newPubSubAPI(tmWSClient *rpcclient.WSClient) *pubSubAPI {
|
||||||
return &pubSubAPI{
|
return &pubSubAPI{
|
||||||
events: NewEventSystem(tmWSClient),
|
events: rpcfilters.NewEventSystem(tmWSClient),
|
||||||
filtersMu: new(sync.RWMutex),
|
filtersMu: new(sync.RWMutex),
|
||||||
filters: make(map[rpc.ID]*wsSubscription),
|
filters: make(map[rpc.ID]*wsSubscription),
|
||||||
logger: log.WithField("module", "websocket-client"),
|
logger: log.WithField("module", "websocket-client"),
|
||||||
@ -414,7 +417,7 @@ func (api *pubSubAPI) subscribeNewHeads(wsConn *wsConn) (rpc.ID, error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(sub.eventCh, sub.Err())
|
}(sub.Event(), sub.Err())
|
||||||
|
|
||||||
return subID, nil
|
return subID, nil
|
||||||
}
|
}
|
||||||
@ -604,7 +607,7 @@ func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, extra interface{}) (rpc.ID,
|
|||||||
return
|
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 {
|
if len(logs) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -653,7 +656,7 @@ func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, extra interface{}) (rpc.ID,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(sub.eventCh, sub.Err(), subID)
|
}(sub.Event(), sub.Err(), subID)
|
||||||
|
|
||||||
return subID, nil
|
return subID, nil
|
||||||
}
|
}
|
||||||
@ -730,7 +733,7 @@ func (api *pubSubAPI) subscribePendingTransactions(wsConn *wsConn) (rpc.ID, erro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(sub.eventCh, sub.Err())
|
}(sub.Event(), sub.Err())
|
||||||
|
|
||||||
return subID, nil
|
return subID, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user