Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support multi gRPC query clients serve with old binary (backport: #1603) #308

Open
wants to merge 5 commits into
base: release/v0.20.x-cronos
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features

* (rpc) [#1682](https://github.com/evmos/ethermint/pull/1682) Add config for maximum number of bytes returned from eth_call.
* (rpc) [#1603](https://github.com/evmos/ethermint/pull/1603) Support multi gRPC query clients serve with old binary.

### Bug Fixes

Expand Down
44 changes: 36 additions & 8 deletions rpc/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
ethermint "github.com/evmos/ethermint/types"

rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
"google.golang.org/grpc"
)

// RPC namespaces and API version
Expand All @@ -47,6 +48,7 @@ const (
type APICreator = func(
ctx *server.Context,
clientCtx client.Context,
backupGRPCClientConns map[[2]int]*grpc.ClientConn,
tendermintWebsocketClient *rpcclient.WSClient,
allowUnprotectedTxs bool,
indexer ethermint.EVMTxIndexer,
Expand All @@ -59,11 +61,12 @@ func init() {
apiCreators = map[string]APICreator{
EthNamespace: func(ctx *server.Context,
clientCtx client.Context,
backupGRPCClientConns map[[2]int]*grpc.ClientConn,
tmWSClient *rpcclient.WSClient,
allowUnprotectedTxs bool,
indexer ethermint.EVMTxIndexer,
) []rpc.API {
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer)
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, backupGRPCClientConns, allowUnprotectedTxs, indexer)
return []rpc.API{
{
Namespace: EthNamespace,
Expand All @@ -79,7 +82,14 @@ func init() {
},
}
},
Web3Namespace: func(*server.Context, client.Context, *rpcclient.WSClient, bool, ethermint.EVMTxIndexer) []rpc.API {
Web3Namespace: func(
*server.Context,
client.Context,
map[[2]int]*grpc.ClientConn,
*rpcclient.WSClient,
bool,
ethermint.EVMTxIndexer,
) []rpc.API {
return []rpc.API{
{
Namespace: Web3Namespace,
Expand All @@ -89,7 +99,14 @@ func init() {
},
}
},
NetNamespace: func(_ *server.Context, clientCtx client.Context, _ *rpcclient.WSClient, _ bool, _ ethermint.EVMTxIndexer) []rpc.API {
NetNamespace: func(
_ *server.Context,
clientCtx client.Context,
_ map[[2]int]*grpc.ClientConn,
_ *rpcclient.WSClient,
_ bool,
_ ethermint.EVMTxIndexer,
) []rpc.API {
return []rpc.API{
{
Namespace: NetNamespace,
Expand All @@ -101,11 +118,12 @@ func init() {
},
PersonalNamespace: func(ctx *server.Context,
clientCtx client.Context,
backupGRPCClientConns map[[2]int]*grpc.ClientConn,
_ *rpcclient.WSClient,
allowUnprotectedTxs bool,
indexer ethermint.EVMTxIndexer,
) []rpc.API {
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer)
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, backupGRPCClientConns, allowUnprotectedTxs, indexer)
return []rpc.API{
{
Namespace: PersonalNamespace,
Expand All @@ -115,7 +133,14 @@ func init() {
},
}
},
TxPoolNamespace: func(ctx *server.Context, _ client.Context, _ *rpcclient.WSClient, _ bool, _ ethermint.EVMTxIndexer) []rpc.API {
TxPoolNamespace: func(
ctx *server.Context,
_ client.Context,
_ map[[2]int]*grpc.ClientConn,
_ *rpcclient.WSClient,
_ bool,
_ ethermint.EVMTxIndexer,
) []rpc.API {
return []rpc.API{
{
Namespace: TxPoolNamespace,
Expand All @@ -127,11 +152,12 @@ func init() {
},
DebugNamespace: func(ctx *server.Context,
clientCtx client.Context,
backupGRPCClientConns map[[2]int]*grpc.ClientConn,
_ *rpcclient.WSClient,
allowUnprotectedTxs bool,
indexer ethermint.EVMTxIndexer,
) []rpc.API {
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer)
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, backupGRPCClientConns, allowUnprotectedTxs, indexer)
return []rpc.API{
{
Namespace: DebugNamespace,
Expand All @@ -143,11 +169,12 @@ func init() {
},
MinerNamespace: func(ctx *server.Context,
clientCtx client.Context,
backupGRPCClientConns map[[2]int]*grpc.ClientConn,
_ *rpcclient.WSClient,
allowUnprotectedTxs bool,
indexer ethermint.EVMTxIndexer,
) []rpc.API {
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer)
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, backupGRPCClientConns, allowUnprotectedTxs, indexer)
return []rpc.API{
{
Namespace: MinerNamespace,
Expand All @@ -163,6 +190,7 @@ func init() {
// GetRPCAPIs returns the list of all APIs
func GetRPCAPIs(ctx *server.Context,
clientCtx client.Context,
backupGRPCClientConns map[[2]int]*grpc.ClientConn,
tmWSClient *rpcclient.WSClient,
allowUnprotectedTxs bool,
indexer ethermint.EVMTxIndexer,
Expand All @@ -172,7 +200,7 @@ func GetRPCAPIs(ctx *server.Context,

for _, ns := range selectedAPIs {
if creator, ok := apiCreators[ns]; ok {
apis = append(apis, creator(ctx, clientCtx, tmWSClient, allowUnprotectedTxs, indexer)...)
apis = append(apis, creator(ctx, clientCtx, backupGRPCClientConns, tmWSClient, allowUnprotectedTxs, indexer)...)
} else {
ctx.Logger.Error("invalid namespace value", "namespace", ns)
}
Expand Down
20 changes: 11 additions & 9 deletions rpc/backend/account_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ func (b *Backend) GetCode(address common.Address, blockNrOrHash rpctypes.BlockNu
req := &evmtypes.QueryCodeRequest{
Address: address.String(),
}

res, err := b.queryClient.Code(rpctypes.ContextWithHeight(blockNum.Int64()), req)
height := blockNum.Int64()
queryClient := b.getGrpcClient(height)
res, err := queryClient.Code(rpctypes.ContextWithHeight(height), req)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -68,10 +69,10 @@ func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNr

// query storage proofs
storageProofs := make([]rpctypes.StorageResult, len(storageKeys))

queryClient := b.getGrpcClient(height)
for i, key := range storageKeys {
hexKey := common.HexToHash(key)
valueBz, proof, err := b.queryClient.GetProof(clientCtx, evmtypes.StoreKey, evmtypes.StateKey(address, hexKey.Bytes()))
valueBz, proof, err := queryClient.GetProof(clientCtx, evmtypes.StoreKey, evmtypes.StateKey(address, hexKey.Bytes()))
if err != nil {
return nil, err
}
Expand All @@ -88,14 +89,14 @@ func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNr
Address: address.String(),
}

res, err := b.queryClient.Account(ctx, req)
res, err := queryClient.Account(ctx, req)
if err != nil {
return nil, err
}

// query account proofs
accountKey := authtypes.AddressStoreKey(sdk.AccAddress(address.Bytes()))
_, proof, err := b.queryClient.GetProof(clientCtx, authtypes.StoreKey, accountKey)
_, proof, err := queryClient.GetProof(clientCtx, authtypes.StoreKey, accountKey)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -127,8 +128,9 @@ func (b *Backend) GetStorageAt(address common.Address, key string, blockNrOrHash
Address: address.String(),
Key: key,
}

res, err := b.queryClient.Storage(rpctypes.ContextWithHeight(blockNum.Int64()), req)
height := blockNum.Int64()
queryClient := b.getGrpcClient(height)
res, err := queryClient.Storage(rpctypes.ContextWithHeight(height), req)
if err != nil {
return nil, err
}
Expand All @@ -153,7 +155,7 @@ func (b *Backend) GetBalance(address common.Address, blockNrOrHash rpctypes.Bloc
return nil, err
}

res, err := b.queryClient.Balance(rpctypes.ContextWithHeight(blockNum.Int64()), req)
res, err := b.getGrpcClient(blockNum.Int64()).Balance(rpctypes.ContextWithHeight(blockNum.Int64()), req)
if err != nil {
return nil, err
}
Expand Down
16 changes: 15 additions & 1 deletion rpc/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
Expand All @@ -21,9 +22,11 @@ import (
"github.com/evmos/ethermint/server/config"
ethermint "github.com/evmos/ethermint/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/log"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
"google.golang.org/grpc"
)

// BackendI implements the Cosmos and EVM backend.
Expand Down Expand Up @@ -137,6 +140,7 @@ type Backend struct {
ctx context.Context
clientCtx client.Context
queryClient *rpctypes.QueryClient // gRPC query client
backupQueryClients map[[2]int]*rpctypes.QueryClient
logger log.Logger
chainID *big.Int
cfg config.Config
Expand All @@ -149,6 +153,7 @@ func NewBackend(
ctx *server.Context,
logger log.Logger,
clientCtx client.Context,
backupGRPCClientConns map[[2]int]*grpc.ClientConn,
allowUnprotectedTxs bool,
indexer ethermint.EVMTxIndexer,
) *Backend {
Expand Down Expand Up @@ -179,14 +184,23 @@ func NewBackend(
clientCtx = clientCtx.WithKeyring(kr)
}

return &Backend{
backend := &Backend{
ctx: context.Background(),
clientCtx: clientCtx,
queryClient: rpctypes.NewQueryClient(clientCtx),
backupQueryClients: make(map[[2]int]*rpctypes.QueryClient),
logger: logger.With("module", "backend"),
chainID: chainID,
cfg: appConf,
allowUnprotectedTxs: allowUnprotectedTxs,
indexer: indexer,
}
for key, conn := range backupGRPCClientConns {
backend.backupQueryClients[key] = &rpctypes.QueryClient{
ServiceClient: tx.NewServiceClient(conn),
QueryClient: evmtypes.NewQueryClient(conn),
FeeMarket: feemarkettypes.NewQueryClient(conn),
}
}
Comment on lines +198 to +204

Check failure

Code scanning / gosec

the value in the range statement should be _ unless copying a map: want: for key := range m

the value in the range statement should be _ unless copying a map: want: for key := range m
return backend
}
3 changes: 2 additions & 1 deletion rpc/backend/backend_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
rpctypes "github.com/evmos/ethermint/rpc/types"
"github.com/evmos/ethermint/tests"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"google.golang.org/grpc"
)

type BackendTestSuite struct {
Expand Down Expand Up @@ -74,7 +75,7 @@ func (suite *BackendTestSuite) SetupTest() {

idxer := indexer.NewKVIndexer(dbm.NewMemDB(), ctx.Logger, clientCtx)

suite.backend = NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer)
suite.backend = NewBackend(ctx, ctx.Logger, clientCtx, make(map[[2]int]*grpc.ClientConn), allowUnprotectedTxs, idxer)
suite.backend.queryClient.QueryClient = mocks.NewEVMQueryClient(suite.T())
suite.backend.clientCtx.Client = mocks.NewClient(suite.T())
suite.backend.ctx = rpctypes.ContextWithHeight(1)
Expand Down
3 changes: 2 additions & 1 deletion rpc/backend/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
func (b *Backend) BlockNumber() (hexutil.Uint64, error) {
// do any grpc query, ignore the response and use the returned block height
var header metadata.MD
// use latest queryClient to get block height
_, err := b.queryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{}, grpc.Header(&header))
if err != nil {
return hexutil.Uint64(0), err
Expand Down Expand Up @@ -396,7 +397,7 @@ func (b *Backend) RPCBlockFromTendermintBlock(
var validatorAccAddr sdk.AccAddress

ctx := rpctypes.ContextWithHeight(block.Height)
res, err := b.queryClient.ValidatorAccount(ctx, req)
res, err := b.getGrpcClient(block.Height).ValidatorAccount(ctx, req)
if err != nil {
b.logger.Debug(
"failed to query validator operator address",
Expand Down
8 changes: 5 additions & 3 deletions rpc/backend/call_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ func (b *Backend) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
}

// Query params to use the EVM denomination
// use latest queryClient in send
res, err := b.queryClient.QueryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{})
if err != nil {
b.logger.Error("failed to query evm params", "error", err.Error())
Expand Down Expand Up @@ -331,6 +332,7 @@ func (b *Backend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rp
// From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use
// the latest block height for querying.
// use latest queryClient to estimate
res, err := b.queryClient.EstimateGas(rpctypes.ContextWithHeight(blockNr.Int64()), &req)
if err != nil {
return 0, err
Expand Down Expand Up @@ -366,7 +368,8 @@ func (b *Backend) DoCall(
// From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use
// the latest block height for querying.
ctx := rpctypes.ContextWithHeight(blockNr.Int64())
height := blockNr.Int64()
ctx := rpctypes.ContextWithHeight(height)
timeout := b.RPCEVMTimeout()

// Setup context so it may be canceled the call has completed
Expand All @@ -381,8 +384,7 @@ func (b *Backend) DoCall(
// Make sure the context is canceled when the call has completed
// this makes sure resources are cleaned up.
defer cancel()

res, err := b.queryClient.EthCall(ctx, &req)
res, err := b.getGrpcClient(height).EthCall(ctx, &req)
if err != nil {
return nil, err
}
Expand Down
10 changes: 7 additions & 3 deletions rpc/backend/chain_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func (b *Backend) ChainID() (*hexutil.Big, error) {

// ChainConfig returns the latest ethereum chain configuration
func (b *Backend) ChainConfig() *params.ChainConfig {
// use latest queryClient to get config
params, err := b.queryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{})
if err != nil {
return nil
Expand All @@ -51,6 +52,7 @@ func (b *Backend) ChainConfig() *params.ChainConfig {

// GlobalMinGasPrice returns MinGasPrice param from FeeMarket
func (b *Backend) GlobalMinGasPrice() (sdk.Dec, error) {
// use latest queryClient to get MinGasPrice
res, err := b.queryClient.FeeMarket.Params(b.ctx, &feemarkettypes.QueryParamsRequest{})
if err != nil {
return sdk.ZeroDec(), err
Expand All @@ -64,7 +66,9 @@ func (b *Backend) GlobalMinGasPrice() (sdk.Dec, error) {
// return nil.
func (b *Backend) BaseFee(blockRes *tmrpctypes.ResultBlockResults) (*big.Int, error) {
// return BaseFee if London hard fork is activated and feemarket is enabled
res, err := b.queryClient.BaseFee(rpctypes.ContextWithHeight(blockRes.Height), &evmtypes.QueryBaseFeeRequest{})
height := blockRes.Height
queryClient := b.getGrpcClient(height)
res, err := queryClient.BaseFee(rpctypes.ContextWithHeight(height), &evmtypes.QueryBaseFeeRequest{})
if err != nil || res.BaseFee == nil {
// we can't tell if it's london HF not enabled or the state is pruned,
// in either case, we'll fallback to parsing from begin blocker event,
Expand Down Expand Up @@ -130,7 +134,7 @@ func (b *Backend) GetCoinbase() (sdk.AccAddress, error) {
req := &evmtypes.QueryValidatorAccountRequest{
ConsAddress: sdk.ConsAddress(status.ValidatorInfo.Address).String(),
}

// use latest queryClient to get coinbase
res, err := b.queryClient.ValidatorAccount(b.ctx, req)
if err != nil {
return nil, err
Expand Down Expand Up @@ -283,7 +287,7 @@ func (b *Backend) SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) {
// london hardfork not enabled or feemarket not enabled
return big.NewInt(0), nil
}

// use latest queryClient to get gas info
params, err := b.queryClient.FeeMarket.Params(b.ctx, &feemarkettypes.QueryParamsRequest{})
if err != nil {
return nil, err
Expand Down
1 change: 1 addition & 0 deletions rpc/backend/node_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ func (b *Backend) RPCBlockRangeCap() int32 {
// the node config. If set value is 0, it will default to 20.

func (b *Backend) RPCMinGasPrice() int64 {
// use latest queryClient to get gas price
evmParams, err := b.queryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{})
if err != nil {
return ethermint.DefaultGasPrice
Expand Down
1 change: 1 addition & 0 deletions rpc/backend/sign_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, e
}

// Query params to use the EVM denomination
// use latest queryClient in send
res, err := b.queryClient.QueryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{})
if err != nil {
b.logger.Error("failed to query evm params", "error", err.Error())
Expand Down
Loading