diff --git a/changelog.md b/changelog.md index 1d44bd26fe..56e002b735 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ * [2644](https://github.com/zeta-chain/node/pull/2644) - add created_timestamp to cctx status * [2673](https://github.com/zeta-chain/node/pull/2673) - add relayer key importer, encryption and decryption * [2633](https://github.com/zeta-chain/node/pull/2633) - support for stateful precompiled contracts. +* [2788](https://github.com/zeta-chain/node/pull/2788) - add common importable zetacored rpc package ### Refactor diff --git a/cmd/zetae2e/config/clients.go b/cmd/zetae2e/config/clients.go index ac4686fc23..3aec591737 100644 --- a/cmd/zetae2e/config/clients.go +++ b/cmd/zetae2e/config/clients.go @@ -5,8 +5,6 @@ import ( "fmt" "github.com/btcsuite/btcd/rpcclient" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/ethclient" "github.com/gagliardetto/solana-go/rpc" @@ -14,90 +12,46 @@ import ( "google.golang.org/grpc/credentials/insecure" "github.com/zeta-chain/zetacore/e2e/config" - authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" - crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" - fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" - lightclienttypes "github.com/zeta-chain/zetacore/x/lightclient/types" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" + "github.com/zeta-chain/zetacore/e2e/runner" + zetacore_rpc "github.com/zeta-chain/zetacore/pkg/rpc" ) -// E2EClients contains all the RPC clients and gRPC clients for E2E tests -type E2EClients struct { - // the RPC clients for external chains in the localnet - BtcRPCClient *rpcclient.Client - SolanaClient *rpc.Client - EvmClient *ethclient.Client - EvmAuth *bind.TransactOpts - - // the gRPC clients for ZetaChain - AuthorityClient authoritytypes.QueryClient - CctxClient crosschaintypes.QueryClient - FungibleClient fungibletypes.QueryClient - AuthClient authtypes.QueryClient - BankClient banktypes.QueryClient - ObserverClient observertypes.QueryClient - LightClient lightclienttypes.QueryClient - - // the RPC clients for ZetaChain - ZevmClient *ethclient.Client - ZevmAuth *bind.TransactOpts -} - -// zetaChainClients contains all the RPC clients and gRPC clients for ZetaChain -type zetaChainClients struct { - AuthorityClient authoritytypes.QueryClient - CctxClient crosschaintypes.QueryClient - FungibleClient fungibletypes.QueryClient - AuthClient authtypes.QueryClient - BankClient banktypes.QueryClient - ObserverClient observertypes.QueryClient - LightClient lightclienttypes.QueryClient -} - // getClientsFromConfig get clients from config func getClientsFromConfig(ctx context.Context, conf config.Config, account config.Account) ( - E2EClients, + runner.Clients, error, ) { var solanaClient *rpc.Client if conf.RPCs.Solana != "" { if solanaClient = rpc.New(conf.RPCs.Solana); solanaClient == nil { - return E2EClients{}, fmt.Errorf("failed to get solana client") + return runner.Clients{}, fmt.Errorf("failed to get solana client") } } btcRPCClient, err := getBtcClient(conf.RPCs.Bitcoin) if err != nil { - return E2EClients{}, fmt.Errorf("failed to get btc client: %w", err) + return runner.Clients{}, fmt.Errorf("failed to get btc client: %w", err) } evmClient, evmAuth, err := getEVMClient(ctx, conf.RPCs.EVM, account) if err != nil { - return E2EClients{}, fmt.Errorf("failed to get evm client: %w", err) + return runner.Clients{}, fmt.Errorf("failed to get evm client: %w", err) } - zetaChainClients, err := getZetaClients( - conf.RPCs.ZetaCoreGRPC, - ) + zetaCoreClients, err := GetZetacoreClient(conf) if err != nil { - return E2EClients{}, fmt.Errorf("failed to get zeta clients: %w", err) + return runner.Clients{}, fmt.Errorf("failed to get zetacore client: %w", err) } zevmClient, zevmAuth, err := getEVMClient(ctx, conf.RPCs.Zevm, account) if err != nil { - return E2EClients{}, fmt.Errorf("failed to get zevm client: %w", err) + return runner.Clients{}, fmt.Errorf("failed to get zevm client: %w", err) } - return E2EClients{ - BtcRPCClient: btcRPCClient, - SolanaClient: solanaClient, - EvmClient: evmClient, - EvmAuth: evmAuth, - AuthorityClient: zetaChainClients.AuthorityClient, - CctxClient: zetaChainClients.CctxClient, - FungibleClient: zetaChainClients.FungibleClient, - AuthClient: zetaChainClients.AuthClient, - BankClient: zetaChainClients.BankClient, - ObserverClient: zetaChainClients.ObserverClient, - LightClient: zetaChainClients.LightClient, - ZevmClient: zevmClient, - ZevmAuth: zevmAuth, + return runner.Clients{ + Zetacore: zetaCoreClients, + BtcRPC: btcRPCClient, + Solana: solanaClient, + Evm: evmClient, + EvmAuth: evmAuth, + Zevm: zevmClient, + ZevmAuth: zevmAuth, }, nil } @@ -152,31 +106,15 @@ func getEVMClient( return evmClient, evmAuth, nil } -// getZetaClients get zeta clients -func getZetaClients(rpc string) ( - zetaChainClients, - error, -) { - grpcConn, err := grpc.Dial(rpc, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return zetaChainClients{}, err +func GetZetacoreClient(conf config.Config) (zetacore_rpc.Clients, error) { + if conf.RPCs.ZetaCoreGRPC != "" { + return zetacore_rpc.NewGRPCClients( + conf.RPCs.ZetaCoreGRPC, + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) } - - authorityClient := authoritytypes.NewQueryClient(grpcConn) - cctxClient := crosschaintypes.NewQueryClient(grpcConn) - fungibleClient := fungibletypes.NewQueryClient(grpcConn) - authClient := authtypes.NewQueryClient(grpcConn) - bankClient := banktypes.NewQueryClient(grpcConn) - observerClient := observertypes.NewQueryClient(grpcConn) - lightclientClient := lightclienttypes.NewQueryClient(grpcConn) - - return zetaChainClients{ - AuthorityClient: authorityClient, - CctxClient: cctxClient, - FungibleClient: fungibleClient, - AuthClient: authClient, - BankClient: bankClient, - ObserverClient: observerClient, - LightClient: lightclientClient, - }, nil + if conf.RPCs.ZetaCoreRPC != "" { + return zetacore_rpc.NewCometBFTClients(conf.RPCs.ZetaCoreRPC) + } + return zetacore_rpc.Clients{}, fmt.Errorf("no ZetaCore gRPC or RPC specified") } diff --git a/cmd/zetae2e/config/config.go b/cmd/zetae2e/config/config.go index ce1b03717b..7cf2afb461 100644 --- a/cmd/zetae2e/config/config.go +++ b/cmd/zetae2e/config/config.go @@ -30,19 +30,7 @@ func RunnerFromConfig( name, ctxCancel, account, - e2eClients.EvmClient, - e2eClients.ZevmClient, - e2eClients.AuthorityClient, - e2eClients.CctxClient, - e2eClients.FungibleClient, - e2eClients.AuthClient, - e2eClients.BankClient, - e2eClients.ObserverClient, - e2eClients.LightClient, - e2eClients.EvmAuth, - e2eClients.ZevmAuth, - e2eClients.BtcRPCClient, - e2eClients.SolanaClient, + e2eClients, logger, opts..., diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index dd00666e25..c8d92fce28 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -166,7 +166,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { noError(err) // set the authority client to the zeta tx server to be able to query message permissions - deployerRunner.ZetaTxServer.SetAuthorityClient(deployerRunner.AutorithyClient) + deployerRunner.ZetaTxServer.SetAuthorityClient(deployerRunner.AuthorityClient) // wait for keygen to be completed // if setup is skipped, we assume that the keygen is already completed diff --git a/cmd/zetae2e/run.go b/cmd/zetae2e/run.go index 9c36d8e3d2..5f38a39cbd 100644 --- a/cmd/zetae2e/run.go +++ b/cmd/zetae2e/run.go @@ -16,10 +16,14 @@ import ( "github.com/zeta-chain/zetacore/e2e/config" "github.com/zeta-chain/zetacore/e2e/e2etests" "github.com/zeta-chain/zetacore/e2e/runner" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) const flagVerbose = "verbose" const flagConfig = "config" +const flagERC20ChainName = "erc20-chain-name" +const flagERC20Symbol = "erc20-symbol" // NewRunCmd returns the run command // which runs the E2E from a config file describing the tests, networks, and accounts @@ -41,6 +45,9 @@ For example: zetae2e run deposit:1000 withdraw: --config config.yml`, os.Exit(1) } + cmd.Flags().String(flagERC20ChainName, "", "chain_name from /zeta-chain/observer/supportedChains") + cmd.Flags().String(flagERC20Symbol, "", "symbol from /zeta-chain/fungible/foreign_coins") + // Retain the verbose flag cmd.Flags().Bool(flagVerbose, false, "set to true to enable verbose logging") @@ -67,6 +74,29 @@ func runE2ETest(cmd *cobra.Command, args []string) error { // initialize logger logger := runner.NewLogger(verbose, color.FgHiCyan, "e2e") + // update config with dynamic ERC20 + erc20ChainName, err := cmd.Flags().GetString(flagERC20ChainName) + if err != nil { + return err + } + erc20Symbol, err := cmd.Flags().GetString(flagERC20Symbol) + if err != nil { + return err + } + if erc20ChainName != "" && erc20Symbol != "" { + erc20Asset, zrc20ContractAddress, err := findERC20( + cmd.Context(), + conf, + erc20ChainName, + erc20Symbol, + ) + if err != nil { + return err + } + conf.Contracts.EVM.ERC20 = config.DoubleQuotedString(erc20Asset) + conf.Contracts.ZEVM.ERC20ZRC20Addr = config.DoubleQuotedString(zrc20ContractAddress) + } + // set config app.SetConfig() @@ -99,11 +129,6 @@ func runE2ETest(cmd *cobra.Command, args []string) error { testRunner.CctxTimeout = 60 * time.Minute testRunner.ReceiptTimeout = 60 * time.Minute - balancesBefore, err := testRunner.GetAccountBalances(true) - if err != nil { - return err - } - // parse test names and arguments from cmd args and run them userTestsConfigs, err := parseCmdArgsToE2ETestRunConfig(args) if err != nil { @@ -119,15 +144,9 @@ func runE2ETest(cmd *cobra.Command, args []string) error { return err } - balancesAfter, err := testRunner.GetAccountBalances(true) - if err != nil { - return err - } - // Print tests completion info logger.Print("tests finished successfully in %s", time.Since(testStartTime).String()) testRunner.Logger.SetColor(color.FgHiRed) - testRunner.PrintTotalDiff(runner.GetAccountBalancesDiff(balancesBefore, balancesAfter)) testRunner.Logger.SetColor(color.FgHiGreen) testRunner.PrintTestReports(reports) @@ -157,3 +176,43 @@ func parseCmdArgsToE2ETestRunConfig(args []string) ([]runner.E2ETestRunConfig, e } return tests, nil } + +// findERC20 loads ERC20 addresses via gRPC given CLI flags +func findERC20(ctx context.Context, conf config.Config, erc20ChainName, erc20Symbol string) (string, string, error) { + clients, err := zetae2econfig.GetZetacoreClient(conf) + if err != nil { + return "", "", fmt.Errorf("get zeta clients: %w", err) + } + + supportedChainsRes, err := clients.Observer.SupportedChains(ctx, &observertypes.QuerySupportedChains{}) + if err != nil { + return "", "", fmt.Errorf("get chain params: %w", err) + } + + chainID := int64(0) + for _, chain := range supportedChainsRes.Chains { + if chain.Name == erc20ChainName { + chainID = chain.ChainId + break + } + } + if chainID == 0 { + return "", "", fmt.Errorf("chain %s not found", erc20ChainName) + } + + foreignCoinsRes, err := clients.Fungible.ForeignCoinsAll(ctx, &fungibletypes.QueryAllForeignCoinsRequest{}) + if err != nil { + return "", "", fmt.Errorf("get foreign coins: %w", err) + } + + for _, coin := range foreignCoinsRes.ForeignCoins { + if coin.ForeignChainId != chainID { + continue + } + // sometimes symbol is USDT, sometimes it's like USDT.SEPOLIA + if strings.HasPrefix(coin.Symbol, erc20Symbol) || strings.HasSuffix(coin.Symbol, erc20Symbol) { + return coin.Asset, coin.Zrc20ContractAddress, nil + } + } + return "", "", fmt.Errorf("erc20 %s not found on %s", erc20Symbol, erc20ChainName) +} diff --git a/e2e/e2etests/test_migrate_chain_support.go b/e2e/e2etests/test_migrate_chain_support.go index 62c9bac84f..b5222a81d7 100644 --- a/e2e/e2etests/test_migrate_chain_support.go +++ b/e2e/e2etests/test_migrate_chain_support.go @@ -201,19 +201,7 @@ func configureEVM2(r *runner.E2ERunner) (*runner.E2ERunner, error) { "admin-evm2", r.CtxCancel, r.Account, - r.EVMClient, - r.ZEVMClient, - r.AutorithyClient, - r.CctxClient, - r.FungibleClient, - r.AuthClient, - r.BankClient, - r.ObserverClient, - r.LightclientClient, - r.EVMAuth, - r.ZEVMAuth, - r.BtcRPCClient, - r.SolanaClient, + r.Clients, runner.NewLogger(true, color.FgHiYellow, "admin-evm2"), runner.WithZetaTxServer(r.ZetaTxServer), ) diff --git a/e2e/runner/balances.go b/e2e/runner/balances.go index f7ab0938c1..f1e1fe3f22 100644 --- a/e2e/runner/balances.go +++ b/e2e/runner/balances.go @@ -8,8 +8,11 @@ import ( "github.com/btcsuite/btcutil" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/pkg/errors" + "github.com/zeta-chain/protocol-contracts/v2/pkg/zrc20.sol" ) +var errNilZRC20 = errors.New("zrc20 contract is nil") + // AccountBalances is a struct that contains the balances of the accounts used in the E2E test type AccountBalances struct { ZetaETH *big.Int @@ -31,6 +34,13 @@ type AccountBalancesDiff struct { ERC20 *big.Int } +func (r *E2ERunner) getZRC20BalanceSafe(z *zrc20.ZRC20) (*big.Int, error) { + if z == nil { + return new(big.Int), errNilZRC20 + } + return z.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) +} + // GetAccountBalances returns the account balances of the accounts used in the E2E test func (r *E2ERunner) GetAccountBalances(skipBTC bool) (AccountBalances, error) { // zevm @@ -42,21 +52,21 @@ func (r *E2ERunner) GetAccountBalances(skipBTC bool) (AccountBalances, error) { if err != nil { return AccountBalances{}, err } - zetaEth, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) + zetaEth, err := r.getZRC20BalanceSafe(r.ETHZRC20) if err != nil { return AccountBalances{}, err } - zetaErc20, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) + zetaErc20, err := r.getZRC20BalanceSafe(r.ERC20ZRC20) if err != nil { return AccountBalances{}, err } - zetaBtc, err := r.BTCZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) + zetaBtc, err := r.getZRC20BalanceSafe(r.BTCZRC20) if err != nil { return AccountBalances{}, err } - zetaSol, err := r.SOLZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) + zetaSol, err := r.getZRC20BalanceSafe(r.SOLZRC20) if err != nil { - return AccountBalances{}, err + r.Logger.Error("get SOL balance: %v", err) } // evm diff --git a/e2e/runner/clients.go b/e2e/runner/clients.go new file mode 100644 index 0000000000..9573a53e29 --- /dev/null +++ b/e2e/runner/clients.go @@ -0,0 +1,25 @@ +package runner + +import ( + "github.com/btcsuite/btcd/rpcclient" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/gagliardetto/solana-go/rpc" + + zetacore_rpc "github.com/zeta-chain/zetacore/pkg/rpc" +) + +// Clients contains all the RPC clients and gRPC clients for E2E tests +type Clients struct { + Zetacore zetacore_rpc.Clients + + // the RPC clients for external chains in the localnet + BtcRPC *rpcclient.Client + Solana *rpc.Client + Evm *ethclient.Client + EvmAuth *bind.TransactOpts + + // the RPC clients for ZetaChain + Zevm *ethclient.Client + ZevmAuth *bind.TransactOpts +} diff --git a/e2e/runner/report.go b/e2e/runner/report.go index 31cd085fc6..d80024e0dd 100644 --- a/e2e/runner/report.go +++ b/e2e/runner/report.go @@ -59,7 +59,7 @@ func (r *E2ERunner) PrintTestReports(tr TestReports) { if err != nil { r.Logger.Print("Error rendering test report: %s", err) } - r.Logger.PrintNoPrefix(table, "") + r.Logger.PrintNoPrefix(table) } // NetworkReport is a struct that contains the report for the network used after running e2e tests diff --git a/e2e/runner/runner.go b/e2e/runner/runner.go index 77d068c398..90bffd1ed1 100644 --- a/e2e/runner/runner.go +++ b/e2e/runner/runner.go @@ -70,14 +70,18 @@ type E2ERunner struct { BTCDeployerAddress *btcutil.AddressWitnessPubKeyHash SolanaDeployerAddress solana.PublicKey + // all clients. + // a reference to this type is required to enable creating a new E2ERunner. + Clients Clients + // rpc clients ZEVMClient *ethclient.Client EVMClient *ethclient.Client BtcRPCClient *rpcclient.Client SolanaClient *rpc.Client - // grpc clients - AutorithyClient authoritytypes.QueryClient + // zetacored grpc clients + AuthorityClient authoritytypes.QueryClient CctxClient crosschaintypes.QueryClient FungibleClient fungibletypes.QueryClient AuthClient authtypes.QueryClient @@ -165,19 +169,7 @@ func NewE2ERunner( name string, ctxCancel context.CancelFunc, account config.Account, - evmClient *ethclient.Client, - zevmClient *ethclient.Client, - authorityClient authoritytypes.QueryClient, - cctxClient crosschaintypes.QueryClient, - fungibleClient fungibletypes.QueryClient, - authClient authtypes.QueryClient, - bankClient banktypes.QueryClient, - observerClient observertypes.QueryClient, - lightclientClient lightclienttypes.QueryClient, - evmAuth *bind.TransactOpts, - zevmAuth *bind.TransactOpts, - btcRPCClient *rpcclient.Client, - solanaClient *rpc.Client, + clients Clients, logger *Logger, opts ...E2ERunnerOption, ) *E2ERunner { @@ -187,20 +179,22 @@ func NewE2ERunner( Account: account, - ZEVMClient: zevmClient, - EVMClient: evmClient, - AutorithyClient: authorityClient, - CctxClient: cctxClient, - FungibleClient: fungibleClient, - AuthClient: authClient, - BankClient: bankClient, - ObserverClient: observerClient, - LightclientClient: lightclientClient, - - EVMAuth: evmAuth, - ZEVMAuth: zevmAuth, - BtcRPCClient: btcRPCClient, - SolanaClient: solanaClient, + Clients: clients, + + ZEVMClient: clients.Zevm, + EVMClient: clients.Evm, + AuthorityClient: clients.Zetacore.Authority, + CctxClient: clients.Zetacore.Crosschain, + FungibleClient: clients.Zetacore.Fungible, + AuthClient: clients.Zetacore.Auth, + BankClient: clients.Zetacore.Bank, + ObserverClient: clients.Zetacore.Observer, + LightclientClient: clients.Zetacore.Lightclient, + + EVMAuth: clients.EvmAuth, + ZEVMAuth: clients.ZevmAuth, + BtcRPCClient: clients.BtcRPC, + SolanaClient: clients.Solana, Logger: logger, } diff --git a/pkg/rpc/clients.go b/pkg/rpc/clients.go new file mode 100644 index 0000000000..2fef17cf26 --- /dev/null +++ b/pkg/rpc/clients.go @@ -0,0 +1,101 @@ +package rpc + +import ( + "fmt" + + rpcclient "github.com/cometbft/cometbft/rpc/client/http" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + feemarkettypes "github.com/zeta-chain/ethermint/x/feemarket/types" + "google.golang.org/grpc" + + etherminttypes "github.com/zeta-chain/zetacore/rpc/types" + authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + lightclienttypes "github.com/zeta-chain/zetacore/x/lightclient/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +// Clients contains RPC client interfaces to interact with ZetaCore +// +// Clients also has some high level wrappers for the clients +type Clients struct { + // Cosmos SDK clients + + // Auth is a github.com/cosmos/cosmos-sdk/x/auth/types QueryClient + Auth authtypes.QueryClient + // Bank is a github.com/cosmos/cosmos-sdk/x/bank/types QueryClient + Bank banktypes.QueryClient + // Upgrade is a github.com/cosmos/cosmos-sdk/x/upgrade/types QueryClient + Upgrade upgradetypes.QueryClient + + // ZetaCore specific clients + + // Authority is a github.com/zeta-chain/zetacore/x/authority/types QueryClient + Authority authoritytypes.QueryClient + // Crosschain is a github.com/zeta-chain/zetacore/x/crosschain/types QueryClient + Crosschain crosschaintypes.QueryClient + // Fungible is a github.com/zeta-chain/zetacore/x/fungible/types QueryClient + Fungible fungibletypes.QueryClient + // Observer is a github.com/zeta-chain/zetacore/x/observer/types QueryClient + Observer observertypes.QueryClient + // Lightclient is a github.com/zeta-chain/zetacore/x/lightclient/types QueryClient + Lightclient lightclienttypes.QueryClient + + // Ethermint specific clients + + // Ethermint is a github.com/zeta-chain/zetacore/rpc/types QueryClient + Ethermint *etherminttypes.QueryClient + // EthermintFeeMarket is a github.com/zeta-chain/ethermint/x/feemarket/types QueryClient + EthermintFeeMarket feemarkettypes.QueryClient + + // Tendermint specific clients + + // Tendermint is a github.com/cosmos/cosmos-sdk/client/grpc/tmservice QueryClient + Tendermint tmservice.ServiceClient +} + +func newClients(ctx client.Context) (Clients, error) { + return Clients{ + // Cosmos SDK clients + Auth: authtypes.NewQueryClient(ctx), + Bank: banktypes.NewQueryClient(ctx), + Upgrade: upgradetypes.NewQueryClient(ctx), + Authority: authoritytypes.NewQueryClient(ctx), + // ZetaCore specific clients + Crosschain: crosschaintypes.NewQueryClient(ctx), + Fungible: fungibletypes.NewQueryClient(ctx), + Observer: observertypes.NewQueryClient(ctx), + Lightclient: lightclienttypes.NewQueryClient(ctx), + // Ethermint specific clients + Ethermint: etherminttypes.NewQueryClient(ctx), + EthermintFeeMarket: feemarkettypes.NewQueryClient(ctx), + // Tendermint specific clients + Tendermint: tmservice.NewServiceClient(ctx), + }, nil +} + +// NewCometBFTClients creates a Clients which uses cometbft abci_query as the transport +func NewCometBFTClients(url string) (Clients, error) { + cometRPCClient, err := rpcclient.New(url, "/websocket") + if err != nil { + return Clients{}, fmt.Errorf("create cometbft rpc client: %w", err) + } + clientCtx := client.Context{}.WithClient(cometRPCClient) + + return newClients(clientCtx) +} + +// NewGRPCClient creates a Clients which uses gRPC as the transport +func NewGRPCClients(url string, opts ...grpc.DialOption) (Clients, error) { + grpcConn, err := grpc.Dial(url, opts...) + if err != nil { + return Clients{}, err + } + clientCtx := client.Context{}.WithGRPCClient(grpcConn) + return newClients(clientCtx) +} diff --git a/zetaclient/zetacore/client_query_authority.go b/pkg/rpc/clients_authority.go similarity index 58% rename from zetaclient/zetacore/client_query_authority.go rename to pkg/rpc/clients_authority.go index 044a3d47ee..68baa01271 100644 --- a/zetaclient/zetacore/client_query_authority.go +++ b/pkg/rpc/clients_authority.go @@ -1,4 +1,4 @@ -package zetacore +package rpc import ( "context" @@ -8,8 +8,8 @@ import ( ) // GetAdditionalChains returns the additional chains -func (c *Client) GetAdditionalChains(ctx context.Context) ([]chains.Chain, error) { - resp, err := c.client.authority.ChainInfo(ctx, &authoritytypes.QueryGetChainInfoRequest{}) +func (c *Clients) GetAdditionalChains(ctx context.Context) ([]chains.Chain, error) { + resp, err := c.Authority.ChainInfo(ctx, &authoritytypes.QueryGetChainInfoRequest{}) if err != nil { return nil, err } diff --git a/pkg/rpc/clients_cosmos.go b/pkg/rpc/clients_cosmos.go new file mode 100644 index 0000000000..36d41acea2 --- /dev/null +++ b/pkg/rpc/clients_cosmos.go @@ -0,0 +1,37 @@ +package rpc + +import ( + "context" + + sdkmath "cosmossdk.io/math" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/pkg/errors" + + "github.com/zeta-chain/zetacore/cmd/zetacored/config" +) + +// GetUpgradePlan returns the current upgrade plan. +// if there is no active upgrade plan, plan will be nil, err will be nil as well. +func (c *Clients) GetUpgradePlan(ctx context.Context) (*upgradetypes.Plan, error) { + in := &upgradetypes.QueryCurrentPlanRequest{} + + resp, err := c.Upgrade.CurrentPlan(ctx, in) + if err != nil { + return nil, errors.Wrap(err, "failed to get current upgrade plan") + } + + return resp.Plan, nil +} + +// GetZetaTokenSupplyOnNode returns the zeta token supply on the node +func (c *Clients) GetZetaTokenSupplyOnNode(ctx context.Context) (sdkmath.Int, error) { + in := &banktypes.QuerySupplyOfRequest{Denom: config.BaseDenom} + + resp, err := c.Bank.SupplyOf(ctx, in) + if err != nil { + return sdkmath.ZeroInt(), errors.Wrap(err, "failed to get zeta token supply") + } + + return resp.GetAmount().Amount, nil +} diff --git a/zetaclient/zetacore/client_query_crosschain.go b/pkg/rpc/clients_crosschain.go similarity index 66% rename from zetaclient/zetacore/client_query_crosschain.go rename to pkg/rpc/clients_crosschain.go index 262b766a6b..3fa5b06675 100644 --- a/zetaclient/zetacore/client_query_crosschain.go +++ b/pkg/rpc/clients_crosschain.go @@ -1,4 +1,4 @@ -package zetacore +package rpc import ( "context" @@ -17,8 +17,8 @@ import ( var maxSizeOption = grpc.MaxCallRecvMsgSize(32 * 1024 * 1024) // GetLastBlockHeight returns the zetachain block height -func (c *Client) GetLastBlockHeight(ctx context.Context) (uint64, error) { - resp, err := c.client.crosschain.LastBlockHeight(ctx, &types.QueryGetLastBlockHeightRequest{}) +func (c *Clients) GetLastBlockHeight(ctx context.Context) (uint64, error) { + resp, err := c.Crosschain.LastBlockHeight(ctx, &types.QueryGetLastBlockHeightRequest{}) if err != nil { return 0, errors.Wrap(err, "failed to get block height") } @@ -27,8 +27,8 @@ func (c *Client) GetLastBlockHeight(ctx context.Context) (uint64, error) { } // GetBlockHeight returns the zetachain block height -func (c *Client) GetBlockHeight(ctx context.Context) (int64, error) { - resp, err := c.client.crosschain.LastZetaHeight(ctx, &types.QueryLastZetaHeightRequest{}) +func (c *Clients) GetBlockHeight(ctx context.Context) (int64, error) { + resp, err := c.Crosschain.LastZetaHeight(ctx, &types.QueryLastZetaHeightRequest{}) if err != nil { return 0, err } @@ -37,8 +37,8 @@ func (c *Client) GetBlockHeight(ctx context.Context) (int64, error) { } // GetAbortedZetaAmount returns the amount of zeta that has been aborted -func (c *Client) GetAbortedZetaAmount(ctx context.Context) (string, error) { - resp, err := c.client.crosschain.ZetaAccounting(ctx, &types.QueryZetaAccountingRequest{}) +func (c *Clients) GetAbortedZetaAmount(ctx context.Context) (string, error) { + resp, err := c.Crosschain.ZetaAccounting(ctx, &types.QueryZetaAccountingRequest{}) if err != nil { return "", errors.Wrap(err, "failed to get aborted zeta amount") } @@ -47,8 +47,8 @@ func (c *Client) GetAbortedZetaAmount(ctx context.Context) (string, error) { } // GetRateLimiterFlags returns the rate limiter flags -func (c *Client) GetRateLimiterFlags(ctx context.Context) (types.RateLimiterFlags, error) { - resp, err := c.client.crosschain.RateLimiterFlags(ctx, &types.QueryRateLimiterFlagsRequest{}) +func (c *Clients) GetRateLimiterFlags(ctx context.Context) (types.RateLimiterFlags, error) { + resp, err := c.Crosschain.RateLimiterFlags(ctx, &types.QueryRateLimiterFlagsRequest{}) if err != nil { return types.RateLimiterFlags{}, errors.Wrap(err, "failed to get rate limiter flags") } @@ -57,10 +57,10 @@ func (c *Client) GetRateLimiterFlags(ctx context.Context) (types.RateLimiterFlag } // GetRateLimiterInput returns input data for the rate limit checker -func (c *Client) GetRateLimiterInput(ctx context.Context, window int64) (*types.QueryRateLimiterInputResponse, error) { +func (c *Clients) GetRateLimiterInput(ctx context.Context, window int64) (*types.QueryRateLimiterInputResponse, error) { in := &types.QueryRateLimiterInputRequest{Window: window} - resp, err := c.client.crosschain.RateLimiterInput(ctx, in, maxSizeOption) + resp, err := c.Crosschain.RateLimiterInput(ctx, in, maxSizeOption) if err != nil { return nil, errors.Wrap(err, "failed to get rate limiter input") } @@ -69,8 +69,8 @@ func (c *Client) GetRateLimiterInput(ctx context.Context, window int64) (*types. } // GetAllCctx returns all cross chain transactions -func (c *Client) GetAllCctx(ctx context.Context) ([]*types.CrossChainTx, error) { - resp, err := c.client.crosschain.CctxAll(ctx, &types.QueryAllCctxRequest{}) +func (c *Clients) GetAllCctx(ctx context.Context) ([]*types.CrossChainTx, error) { + resp, err := c.Crosschain.CctxAll(ctx, &types.QueryAllCctxRequest{}) if err != nil { return nil, errors.Wrap(err, "failed to get all cross chain transactions") } @@ -78,9 +78,9 @@ func (c *Client) GetAllCctx(ctx context.Context) ([]*types.CrossChainTx, error) return resp.CrossChainTx, nil } -func (c *Client) GetCctxByHash(ctx context.Context, sendHash string) (*types.CrossChainTx, error) { +func (c *Clients) GetCctxByHash(ctx context.Context, sendHash string) (*types.CrossChainTx, error) { in := &types.QueryGetCctxRequest{Index: sendHash} - resp, err := c.client.crosschain.Cctx(ctx, in) + resp, err := c.Crosschain.Cctx(ctx, in) if err != nil { return nil, errors.Wrap(err, "failed to get cctx by hash") } @@ -89,8 +89,8 @@ func (c *Client) GetCctxByHash(ctx context.Context, sendHash string) (*types.Cro } // GetCctxByNonce returns a cross chain transaction by nonce -func (c *Client) GetCctxByNonce(ctx context.Context, chainID int64, nonce uint64) (*types.CrossChainTx, error) { - resp, err := c.client.crosschain.CctxByNonce(ctx, &types.QueryGetCctxByNonceRequest{ +func (c *Clients) GetCctxByNonce(ctx context.Context, chainID int64, nonce uint64) (*types.CrossChainTx, error) { + resp, err := c.Crosschain.CctxByNonce(ctx, &types.QueryGetCctxByNonceRequest{ ChainID: chainID, Nonce: nonce, }) @@ -104,12 +104,12 @@ func (c *Client) GetCctxByNonce(ctx context.Context, chainID int64, nonce uint64 // ListPendingCCTXWithinRateLimit returns a list of pending cctxs that do not exceed the outbound rate limit // - The max size of the list is crosschainkeeper.MaxPendingCctxs // - The returned `rateLimitExceeded` flag indicates if the rate limit is exceeded or not -func (c *Client) ListPendingCCTXWithinRateLimit( +func (c *Clients) ListPendingCCTXWithinRateLimit( ctx context.Context, ) (*types.QueryListPendingCctxWithinRateLimitResponse, error) { in := &types.QueryListPendingCctxWithinRateLimitRequest{} - resp, err := c.client.crosschain.ListPendingCctxWithinRateLimit(ctx, in, maxSizeOption) + resp, err := c.Crosschain.ListPendingCctxWithinRateLimit(ctx, in, maxSizeOption) if err != nil { return nil, errors.Wrap(err, "failed to get pending cctxs within rate limit") } @@ -119,10 +119,10 @@ func (c *Client) ListPendingCCTXWithinRateLimit( // ListPendingCCTX returns a list of pending cctxs for a given chainID // - The max size of the list is crosschainkeeper.MaxPendingCctxs -func (c *Client) ListPendingCCTX(ctx context.Context, chainID int64) ([]*types.CrossChainTx, uint64, error) { +func (c *Clients) ListPendingCCTX(ctx context.Context, chainID int64) ([]*types.CrossChainTx, uint64, error) { in := &types.QueryListPendingCctxRequest{ChainId: chainID} - resp, err := c.client.crosschain.ListPendingCctx(ctx, in, maxSizeOption) + resp, err := c.Crosschain.ListPendingCctx(ctx, in, maxSizeOption) if err != nil { return nil, 0, errors.Wrap(err, "failed to get pending cctxs") } @@ -131,14 +131,14 @@ func (c *Client) ListPendingCCTX(ctx context.Context, chainID int64) ([]*types.C } // GetOutboundTracker returns the outbound tracker for a chain and nonce -func (c *Client) GetOutboundTracker( +func (c *Clients) GetOutboundTracker( ctx context.Context, chain chains.Chain, nonce uint64, ) (*types.OutboundTracker, error) { in := &types.QueryGetOutboundTrackerRequest{ChainID: chain.ChainId, Nonce: nonce} - resp, err := c.client.crosschain.OutboundTracker(ctx, in) + resp, err := c.Crosschain.OutboundTracker(ctx, in) if err != nil { return nil, err } @@ -147,10 +147,10 @@ func (c *Client) GetOutboundTracker( } // GetInboundTrackersForChain returns the inbound trackers for a chain -func (c *Client) GetInboundTrackersForChain(ctx context.Context, chainID int64) ([]types.InboundTracker, error) { +func (c *Clients) GetInboundTrackersForChain(ctx context.Context, chainID int64) ([]types.InboundTracker, error) { in := &types.QueryAllInboundTrackerByChainRequest{ChainId: chainID} - resp, err := c.client.crosschain.InboundTrackerAllByChain(ctx, in) + resp, err := c.Crosschain.InboundTrackerAllByChain(ctx, in) if err != nil { return nil, err } @@ -159,7 +159,7 @@ func (c *Client) GetInboundTrackersForChain(ctx context.Context, chainID int64) } // GetAllOutboundTrackerByChain returns all outbound trackers for a chain -func (c *Client) GetAllOutboundTrackerByChain( +func (c *Clients) GetAllOutboundTrackerByChain( ctx context.Context, chainID int64, order interfaces.Order, @@ -175,7 +175,7 @@ func (c *Client) GetAllOutboundTrackerByChain( }, } - resp, err := c.client.crosschain.OutboundTrackerAllByChain(ctx, in) + resp, err := c.Crosschain.OutboundTrackerAllByChain(ctx, in) if err != nil { return nil, errors.Wrap(err, "failed to get all outbound trackers") } diff --git a/zetaclient/zetacore/client_query_ethermint.go b/pkg/rpc/clients_ethermint.go similarity index 68% rename from zetaclient/zetacore/client_query_ethermint.go rename to pkg/rpc/clients_ethermint.go index b9fc5a4a7a..0a559fbf7f 100644 --- a/zetaclient/zetacore/client_query_ethermint.go +++ b/pkg/rpc/clients_ethermint.go @@ -1,4 +1,4 @@ -package zetacore +package rpc import ( "context" @@ -9,8 +9,8 @@ import ( ) // GetBaseGasPrice returns the base gas price -func (c *Client) GetBaseGasPrice(ctx context.Context) (int64, error) { - resp, err := c.client.fees.Params(ctx, &feemarkettypes.QueryParamsRequest{}) +func (c *Clients) GetBaseGasPrice(ctx context.Context) (int64, error) { + resp, err := c.EthermintFeeMarket.Params(ctx, &feemarkettypes.QueryParamsRequest{}) if err != nil { return 0, errors.Wrap(err, "failed to get base gas price") } diff --git a/zetaclient/zetacore/client_query_lightclient.go b/pkg/rpc/clients_lightclient.go similarity index 68% rename from zetaclient/zetacore/client_query_lightclient.go rename to pkg/rpc/clients_lightclient.go index f5999a5d2a..cb3e0e0c3c 100644 --- a/zetaclient/zetacore/client_query_lightclient.go +++ b/pkg/rpc/clients_lightclient.go @@ -1,4 +1,4 @@ -package zetacore +package rpc import ( "context" @@ -10,8 +10,8 @@ import ( ) // GetBlockHeaderEnabledChains returns the enabled chains for block headers -func (c *Client) GetBlockHeaderEnabledChains(ctx context.Context) ([]types.HeaderSupportedChain, error) { - resp, err := c.client.light.HeaderEnabledChains(ctx, &types.QueryHeaderEnabledChainsRequest{}) +func (c *Clients) GetBlockHeaderEnabledChains(ctx context.Context) ([]types.HeaderSupportedChain, error) { + resp, err := c.Lightclient.HeaderEnabledChains(ctx, &types.QueryHeaderEnabledChainsRequest{}) if err != nil { return []types.HeaderSupportedChain{}, err } @@ -20,10 +20,10 @@ func (c *Client) GetBlockHeaderEnabledChains(ctx context.Context) ([]types.Heade } // GetBlockHeaderChainState returns the block header chain state -func (c *Client) GetBlockHeaderChainState(ctx context.Context, chainID int64) (*types.ChainState, error) { +func (c *Clients) GetBlockHeaderChainState(ctx context.Context, chainID int64) (*types.ChainState, error) { in := &types.QueryGetChainStateRequest{ChainId: chainID} - resp, err := c.client.light.ChainState(ctx, in) + resp, err := c.Lightclient.ChainState(ctx, in) if err != nil { return nil, errors.Wrap(err, "failed to get chain state") } @@ -32,7 +32,7 @@ func (c *Client) GetBlockHeaderChainState(ctx context.Context, chainID int64) (* } // Prove returns whether a proof is valid -func (c *Client) Prove( +func (c *Clients) Prove( ctx context.Context, blockHash string, txHash string, @@ -48,7 +48,7 @@ func (c *Client) Prove( TxHash: txHash, } - resp, err := c.client.light.Prove(ctx, in) + resp, err := c.Lightclient.Prove(ctx, in) if err != nil { return false, errors.Wrap(err, "failed to prove") } diff --git a/zetaclient/zetacore/client_query_observer.go b/pkg/rpc/clients_observer.go similarity index 61% rename from zetaclient/zetacore/client_query_observer.go rename to pkg/rpc/clients_observer.go index a8ed20c998..a5c7455e91 100644 --- a/zetaclient/zetacore/client_query_observer.go +++ b/pkg/rpc/clients_observer.go @@ -1,4 +1,4 @@ -package zetacore +package rpc import ( "context" @@ -12,8 +12,8 @@ import ( ) // GetCrosschainFlags returns the crosschain flags -func (c *Client) GetCrosschainFlags(ctx context.Context) (types.CrosschainFlags, error) { - resp, err := c.client.observer.CrosschainFlags(ctx, &types.QueryGetCrosschainFlagsRequest{}) +func (c *Clients) GetCrosschainFlags(ctx context.Context) (types.CrosschainFlags, error) { + resp, err := c.Observer.CrosschainFlags(ctx, &types.QueryGetCrosschainFlagsRequest{}) if err != nil { return types.CrosschainFlags{}, err } @@ -22,8 +22,8 @@ func (c *Client) GetCrosschainFlags(ctx context.Context) (types.CrosschainFlags, } // GetSupportedChains returns the supported chains -func (c *Client) GetSupportedChains(ctx context.Context) ([]chains.Chain, error) { - resp, err := c.client.observer.SupportedChains(ctx, &types.QuerySupportedChains{}) +func (c *Clients) GetSupportedChains(ctx context.Context) ([]chains.Chain, error) { + resp, err := c.Observer.SupportedChains(ctx, &types.QuerySupportedChains{}) if err != nil { return nil, errors.Wrap(err, "failed to get supported chains") } @@ -32,11 +32,11 @@ func (c *Client) GetSupportedChains(ctx context.Context) ([]chains.Chain, error) } // GetChainParams returns all the chain params -func (c *Client) GetChainParams(ctx context.Context) ([]*types.ChainParams, error) { +func (c *Clients) GetChainParams(ctx context.Context) ([]*types.ChainParams, error) { in := &types.QueryGetChainParamsRequest{} resp, err := retry.DoTypedWithRetry(func() (*types.QueryGetChainParamsResponse, error) { - return c.client.observer.GetChainParams(ctx, in) + return c.Observer.GetChainParams(ctx, in) }) if err != nil { @@ -47,13 +47,13 @@ func (c *Client) GetChainParams(ctx context.Context) ([]*types.ChainParams, erro } // GetChainParamsForChainID returns the chain params for a given chain ID -func (c *Client) GetChainParamsForChainID( +func (c *Clients) GetChainParamsForChainID( ctx context.Context, externalChainID int64, ) (*types.ChainParams, error) { in := &types.QueryGetChainParamsForChainRequest{ChainId: externalChainID} - resp, err := c.client.observer.GetChainParamsForChain(ctx, in) + resp, err := c.Observer.GetChainParamsForChain(ctx, in) if err != nil { return &types.ChainParams{}, err } @@ -62,11 +62,11 @@ func (c *Client) GetChainParamsForChainID( } // GetObserverList returns the list of observers -func (c *Client) GetObserverList(ctx context.Context) ([]string, error) { +func (c *Clients) GetObserverList(ctx context.Context) ([]string, error) { in := &types.QueryObserverSet{} resp, err := retry.DoTypedWithRetry(func() (*types.QueryObserverSetResponse, error) { - return c.client.observer.ObserverSet(ctx, in) + return c.Observer.ObserverSet(ctx, in) }) if err != nil { @@ -77,17 +77,17 @@ func (c *Client) GetObserverList(ctx context.Context) ([]string, error) { } // GetBallotByID returns a ballot by ID -func (c *Client) GetBallotByID(ctx context.Context, id string) (*types.QueryBallotByIdentifierResponse, error) { +func (c *Clients) GetBallotByID(ctx context.Context, id string) (*types.QueryBallotByIdentifierResponse, error) { in := &types.QueryBallotByIdentifierRequest{BallotIdentifier: id} - return c.client.observer.BallotByIdentifier(ctx, in) + return c.Observer.BallotByIdentifier(ctx, in) } // GetNonceByChain returns the nonce by chain -func (c *Client) GetNonceByChain(ctx context.Context, chain chains.Chain) (types.ChainNonces, error) { +func (c *Clients) GetNonceByChain(ctx context.Context, chain chains.Chain) (types.ChainNonces, error) { in := &types.QueryGetChainNoncesRequest{ChainId: chain.ChainId} - resp, err := c.client.observer.ChainNonces(ctx, in) + resp, err := c.Observer.ChainNonces(ctx, in) if err != nil { return types.ChainNonces{}, errors.Wrap(err, "failed to get nonce by chain") } @@ -96,11 +96,11 @@ func (c *Client) GetNonceByChain(ctx context.Context, chain chains.Chain) (types } // GetKeyGen returns the keygen -func (c *Client) GetKeyGen(ctx context.Context) (types.Keygen, error) { +func (c *Clients) GetKeyGen(ctx context.Context) (types.Keygen, error) { in := &types.QueryGetKeygenRequest{} resp, err := retry.DoTypedWithRetry(func() (*types.QueryGetKeygenResponse, error) { - return c.client.observer.Keygen(ctx, in) + return c.Observer.Keygen(ctx, in) }) switch { @@ -114,25 +114,23 @@ func (c *Client) GetKeyGen(ctx context.Context) (types.Keygen, error) { } // GetAllNodeAccounts returns all node accounts -func (c *Client) GetAllNodeAccounts(ctx context.Context) ([]*types.NodeAccount, error) { - resp, err := c.client.observer.NodeAccountAll(ctx, &types.QueryAllNodeAccountRequest{}) +func (c *Clients) GetAllNodeAccounts(ctx context.Context) ([]*types.NodeAccount, error) { + resp, err := c.Observer.NodeAccountAll(ctx, &types.QueryAllNodeAccountRequest{}) if err != nil { return nil, errors.Wrap(err, "failed to get all node accounts") } - c.logger.Debug().Int("node_account.len", len(resp.NodeAccount)).Msg("GetAllNodeAccounts: OK") - return resp.NodeAccount, nil } // GetBallot returns a ballot by ID -func (c *Client) GetBallot( +func (c *Clients) GetBallot( ctx context.Context, ballotIdentifier string, ) (*types.QueryBallotByIdentifierResponse, error) { in := &types.QueryBallotByIdentifierRequest{BallotIdentifier: ballotIdentifier} - resp, err := c.client.observer.BallotByIdentifier(ctx, in) + resp, err := c.Observer.BallotByIdentifier(ctx, in) if err != nil { return nil, errors.Wrap(err, "failed to get ballot") } @@ -141,8 +139,8 @@ func (c *Client) GetBallot( } // GetEVMTSSAddress returns the current EVM TSS address. -func (c *Client) GetEVMTSSAddress(ctx context.Context) (string, error) { - resp, err := c.client.observer.GetTssAddress(ctx, &types.QueryGetTssAddressRequest{}) +func (c *Clients) GetEVMTSSAddress(ctx context.Context) (string, error) { + resp, err := c.Observer.GetTssAddress(ctx, &types.QueryGetTssAddressRequest{}) if err != nil { return "", errors.Wrap(err, "failed to get eth tss address") } @@ -151,10 +149,10 @@ func (c *Client) GetEVMTSSAddress(ctx context.Context) (string, error) { } // GetBTCTSSAddress returns the current BTC TSS address -func (c *Client) GetBTCTSSAddress(ctx context.Context, chainID int64) (string, error) { +func (c *Clients) GetBTCTSSAddress(ctx context.Context, chainID int64) (string, error) { in := &types.QueryGetTssAddressRequest{BitcoinChainId: chainID} - resp, err := c.client.observer.GetTssAddress(ctx, in) + resp, err := c.Observer.GetTssAddress(ctx, in) if err != nil { return "", errors.Wrap(err, "failed to get btc tss address") } @@ -162,8 +160,8 @@ func (c *Client) GetBTCTSSAddress(ctx context.Context, chainID int64) (string, e } // GetTSS returns the current TSS -func (c *Client) GetTSS(ctx context.Context) (types.TSS, error) { - resp, err := c.client.observer.TSS(ctx, &types.QueryGetTSSRequest{}) +func (c *Clients) GetTSS(ctx context.Context) (types.TSS, error) { + resp, err := c.Observer.TSS(ctx, &types.QueryGetTSSRequest{}) if err != nil { return types.TSS{}, errors.Wrap(err, "failed to get tss") } @@ -171,8 +169,8 @@ func (c *Client) GetTSS(ctx context.Context) (types.TSS, error) { } // GetTSSHistory returns the historical list of TSS -func (c *Client) GetTSSHistory(ctx context.Context) ([]types.TSS, error) { - resp, err := c.client.observer.TssHistory(ctx, &types.QueryTssHistoryRequest{}) +func (c *Clients) GetTSSHistory(ctx context.Context) ([]types.TSS, error) { + resp, err := c.Observer.TssHistory(ctx, &types.QueryTssHistoryRequest{}) if err != nil { return nil, errors.Wrap(err, "failed to get tss history") } @@ -181,8 +179,8 @@ func (c *Client) GetTSSHistory(ctx context.Context) ([]types.TSS, error) { } // GetPendingNonces returns the pending nonces -func (c *Client) GetPendingNonces(ctx context.Context) (*types.QueryAllPendingNoncesResponse, error) { - resp, err := c.client.observer.PendingNoncesAll(ctx, &types.QueryAllPendingNoncesRequest{}) +func (c *Clients) GetPendingNonces(ctx context.Context) (*types.QueryAllPendingNoncesResponse, error) { + resp, err := c.Observer.PendingNoncesAll(ctx, &types.QueryAllPendingNoncesRequest{}) if err != nil { return nil, errors.Wrap(err, "failed to get pending nonces") } @@ -191,10 +189,10 @@ func (c *Client) GetPendingNonces(ctx context.Context) (*types.QueryAllPendingNo } // GetPendingNoncesByChain returns the pending nonces for a chain and current tss address -func (c *Client) GetPendingNoncesByChain(ctx context.Context, chainID int64) (types.PendingNonces, error) { +func (c *Clients) GetPendingNoncesByChain(ctx context.Context, chainID int64) (types.PendingNonces, error) { in := &types.QueryPendingNoncesByChainRequest{ChainId: chainID} - resp, err := c.client.observer.PendingNoncesByChain(ctx, in) + resp, err := c.Observer.PendingNoncesByChain(ctx, in) if err != nil { return types.PendingNonces{}, errors.Wrap(err, "failed to get pending nonces by chain") } @@ -203,13 +201,13 @@ func (c *Client) GetPendingNoncesByChain(ctx context.Context, chainID int64) (ty } // HasVoted returns whether an observer has voted -func (c *Client) HasVoted(ctx context.Context, ballotIndex string, voterAddress string) (bool, error) { +func (c *Clients) HasVoted(ctx context.Context, ballotIndex string, voterAddress string) (bool, error) { in := &types.QueryHasVotedRequest{ BallotIdentifier: ballotIndex, VoterAddress: voterAddress, } - resp, err := c.client.observer.HasVoted(ctx, in) + resp, err := c.Observer.HasVoted(ctx, in) if err != nil { return false, errors.Wrap(err, "failed to check if observer has voted") } diff --git a/zetaclient/zetacore/client_query_tendermint.go b/pkg/rpc/clients_tendermint.go similarity index 60% rename from zetaclient/zetacore/client_query_tendermint.go rename to pkg/rpc/clients_tendermint.go index adb38d0bab..e1df340a71 100644 --- a/zetaclient/zetacore/client_query_tendermint.go +++ b/pkg/rpc/clients_tendermint.go @@ -1,4 +1,4 @@ -package zetacore +package rpc import ( "context" @@ -10,8 +10,8 @@ import ( ) // GetLatestZetaBlock returns the latest zeta block -func (c *Client) GetLatestZetaBlock(ctx context.Context) (*tmservice.Block, error) { - res, err := c.client.tendermint.GetLatestBlock(ctx, &tmservice.GetLatestBlockRequest{}) +func (c *Clients) GetLatestZetaBlock(ctx context.Context) (*tmservice.Block, error) { + res, err := c.Tendermint.GetLatestBlock(ctx, &tmservice.GetLatestBlockRequest{}) if err != nil { return nil, errors.Wrap(err, "failed to get latest zeta block") } @@ -20,11 +20,11 @@ func (c *Client) GetLatestZetaBlock(ctx context.Context) (*tmservice.Block, erro } // GetNodeInfo returns the node info -func (c *Client) GetNodeInfo(ctx context.Context) (*tmservice.GetNodeInfoResponse, error) { +func (c *Clients) GetNodeInfo(ctx context.Context) (*tmservice.GetNodeInfoResponse, error) { var err error res, err := retry.DoTypedWithRetry(func() (*tmservice.GetNodeInfoResponse, error) { - return c.client.tendermint.GetNodeInfo(ctx, &tmservice.GetNodeInfoRequest{}) + return c.Tendermint.GetNodeInfo(ctx, &tmservice.GetNodeInfoRequest{}) }) if err != nil { diff --git a/zetaclient/zetacore/client_query_test.go b/pkg/rpc/clients_test.go similarity index 80% rename from zetaclient/zetacore/client_query_test.go rename to pkg/rpc/clients_test.go index cf3ddb8d50..ed4f7ccffa 100644 --- a/zetaclient/zetacore/client_query_test.go +++ b/pkg/rpc/clients_test.go @@ -1,4 +1,4 @@ -package zetacore +package rpc import ( "context" @@ -6,22 +6,17 @@ import ( "testing" authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" - abci "github.com/cometbft/cometbft/abci/types" tmtypes "github.com/cometbft/cometbft/proto/tendermint/types" - cosmosclient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" - "github.com/cosmos/cosmos-sdk/testutil/mock" "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/golang/mock/gomock" - "github.com/rs/zerolog" "github.com/stretchr/testify/require" feemarkettypes "github.com/zeta-chain/ethermint/x/feemarket/types" - keyinterfaces "github.com/zeta-chain/zetacore/zetaclient/keys/interfaces" "go.nhat.io/grpcmock" "go.nhat.io/grpcmock/planner" @@ -33,11 +28,10 @@ import ( lightclienttypes "github.com/zeta-chain/zetacore/x/lightclient/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" - "github.com/zeta-chain/zetacore/zetaclient/keys" - "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" ) const skipMethod = "skip" +const gRPCListenPath = "127.0.0.1:47392" // setupMockServer setup mock zetacore GRPC server func setupMockServer( @@ -45,7 +39,7 @@ func setupMockServer( serviceFunc any, method string, input any, expectedOutput any, extra ...grpcmock.ServerOption, ) *grpcmock.Server { - listener, err := net.Listen("tcp", "127.0.0.1:9090") + listener, err := net.Listen("tcp", gRPCListenPath) require.NoError(t, err) opts := []grpcmock.ServerOption{ @@ -76,91 +70,8 @@ func setupMockServer( return server } -func withDummyServer(zetaBlockHeight int64) []grpcmock.ServerOption { - return []grpcmock.ServerOption{ - grpcmock.RegisterService(crosschaintypes.RegisterQueryServer), - grpcmock.RegisterService(crosschaintypes.RegisterMsgServer), - grpcmock.RegisterService(feemarkettypes.RegisterQueryServer), - grpcmock.RegisterService(authtypes.RegisterQueryServer), - grpcmock.RegisterService(abci.RegisterABCIApplicationServer), - func(s *grpcmock.Server) { - // Block Height - s.ExpectUnary("/zetachain.zetacore.crosschain.Query/LastZetaHeight"). - UnlimitedTimes(). - Return(crosschaintypes.QueryLastZetaHeightResponse{Height: zetaBlockHeight}) - - // London Base Fee - s.ExpectUnary("/ethermint.feemarket.v1.Query/Params"). - UnlimitedTimes(). - Return(feemarkettypes.QueryParamsResponse{ - Params: feemarkettypes.Params{BaseFee: types.NewInt(100)}, - }) - }, - } -} - -type clientTestConfig struct { - keys keyinterfaces.ObserverKeys - opts []Opt -} - -type clientTestOpt func(*clientTestConfig) - -func withObserverKeys(keys keyinterfaces.ObserverKeys) clientTestOpt { - return func(cfg *clientTestConfig) { cfg.keys = keys } -} - -func withDefaultObserverKeys() clientTestOpt { - var ( - key = mocks.TestKeyringPair - address = types.AccAddress(key.PubKey().Address().Bytes()) - keyRing = mocks.NewKeyring() - ) - - return withObserverKeys(keys.NewKeysWithKeybase(keyRing, address, testSigner, "")) -} - -func withTendermint(client cosmosclient.TendermintRPC) clientTestOpt { - return func(cfg *clientTestConfig) { cfg.opts = append(cfg.opts, WithTendermintClient(client)) } -} - -func withAccountRetriever(t *testing.T, accNum uint64, accSeq uint64) clientTestOpt { - ctrl := gomock.NewController(t) - ac := mock.NewMockAccountRetriever(ctrl) - ac.EXPECT(). - GetAccountNumberSequence(gomock.Any(), gomock.Any()). - AnyTimes(). - Return(accNum, accSeq, nil) - - return func(cfg *clientTestConfig) { - cfg.opts = append(cfg.opts, WithCustomAccountRetriever(ac)) - } -} - -func setupZetacoreClient(t *testing.T, opts ...clientTestOpt) *Client { - const ( - chainIP = "127.0.0.1" - signer = testSigner - chainID = "zetachain_7000-1" - ) - - var cfg clientTestConfig - for _, opt := range opts { - opt(&cfg) - } - - if cfg.keys == nil { - cfg.keys = &keys.Keys{} - } - - c, err := NewClient( - cfg.keys, - chainIP, signer, - chainID, - false, - zerolog.Nop(), - cfg.opts..., - ) +func setupZetacoreClients(t *testing.T) Clients { + c, err := NewGRPCClients(gRPCListenPath, grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) @@ -180,7 +91,7 @@ func TestZetacore_GetBallot(t *testing.T) { method := "/zetachain.zetacore.observer.Query/BallotByIdentifier" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetBallotByID(ctx, "123") require.NoError(t, err) @@ -199,7 +110,7 @@ func TestZetacore_GetCrosschainFlags(t *testing.T) { method := "/zetachain.zetacore.observer.Query/CrosschainFlags" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetCrosschainFlags(ctx) require.NoError(t, err) @@ -220,7 +131,7 @@ func TestZetacore_GetRateLimiterFlags(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/RateLimiterFlags" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) // query resp, err := client.GetRateLimiterFlags(ctx) @@ -247,7 +158,7 @@ func TestZetacore_HeaderEnabledChains(t *testing.T) { method := "/zetachain.zetacore.lightclient.Query/HeaderEnabledChains" setupMockServer(t, lightclienttypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetBlockHeaderEnabledChains(ctx) require.NoError(t, err) @@ -266,7 +177,7 @@ func TestZetacore_GetChainParamsForChainID(t *testing.T) { method := "/zetachain.zetacore.observer.Query/GetChainParamsForChain" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetChainParamsForChainID(ctx, 123) require.NoError(t, err) @@ -289,7 +200,7 @@ func TestZetacore_GetChainParams(t *testing.T) { method := "/zetachain.zetacore.observer.Query/GetChainParams" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetChainParams(ctx) require.NoError(t, err) @@ -309,7 +220,7 @@ func TestZetacore_GetUpgradePlan(t *testing.T) { method := "/cosmos.upgrade.v1beta1.Query/CurrentPlan" setupMockServer(t, upgradetypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetUpgradePlan(ctx) require.NoError(t, err) @@ -331,7 +242,7 @@ func TestZetacore_GetAllCctx(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/CctxAll" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetAllCctx(ctx) require.NoError(t, err) @@ -350,7 +261,7 @@ func TestZetacore_GetCctxByHash(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/Cctx" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetCctxByHash(ctx, "9c8d02b6956b9c78ecb6090a8160faaa48e7aecfd0026fcdf533721d861436a3") require.NoError(t, err) @@ -370,7 +281,7 @@ func TestZetacore_GetCctxByNonce(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/CctxByNonce" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetCctxByNonce(ctx, 7000, 55) require.NoError(t, err) @@ -391,7 +302,7 @@ func TestZetacore_GetObserverList(t *testing.T) { method := "/zetachain.zetacore.observer.Query/ObserverSet" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetObserverList(ctx) require.NoError(t, err) @@ -414,7 +325,7 @@ func TestZetacore_GetRateLimiterInput(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/RateLimiterInput" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetRateLimiterInput(ctx, 10) require.NoError(t, err) @@ -436,7 +347,7 @@ func TestZetacore_ListPendingCctx(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/ListPendingCctx" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, totalPending, err := client.ListPendingCCTX(ctx, 7000) require.NoError(t, err) @@ -452,7 +363,7 @@ func TestZetacore_GetAbortedZetaAmount(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/ZetaAccounting" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetAbortedZetaAmount(ctx) require.NoError(t, err) @@ -475,7 +386,7 @@ func TestZetacore_GetZetaTokenSupplyOnNode(t *testing.T) { method := "/cosmos.bank.v1beta1.Query/SupplyOf" setupMockServer(t, banktypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetZetaTokenSupplyOnNode(ctx) require.NoError(t, err) @@ -491,9 +402,7 @@ func TestZetacore_GetBlockHeight(t *testing.T) { setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, output) - client := setupZetacoreClient(t, - withDefaultObserverKeys(), - ) + client := setupZetacoreClients(t) t.Run("last block height", func(t *testing.T) { height, err := client.GetBlockHeight(ctx) @@ -517,7 +426,7 @@ func TestZetacore_GetLatestZetaBlock(t *testing.T) { method := "/cosmos.base.tendermint.v1beta1.Service/GetLatestBlock" setupMockServer(t, tmservice.RegisterServiceServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetLatestZetaBlock(ctx) require.NoError(t, err) @@ -535,7 +444,7 @@ func TestZetacore_GetNodeInfo(t *testing.T) { method := "/cosmos.base.tendermint.v1beta1.Service/GetNodeInfo" setupMockServer(t, tmservice.RegisterServiceServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetNodeInfo(ctx) require.NoError(t, err) @@ -554,7 +463,7 @@ func TestZetacore_GetBaseGasPrice(t *testing.T) { method := "/ethermint.feemarket.v1.Query/Params" setupMockServer(t, feemarkettypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetBaseGasPrice(ctx) require.NoError(t, err) @@ -578,7 +487,7 @@ func TestZetacore_GetNonceByChain(t *testing.T) { method := "/zetachain.zetacore.observer.Query/ChainNonces" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetNonceByChain(ctx, chain) require.NoError(t, err) @@ -602,7 +511,7 @@ func TestZetacore_GetAllNodeAccounts(t *testing.T) { method := "/zetachain.zetacore.observer.Query/NodeAccountAll" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetAllNodeAccounts(ctx) require.NoError(t, err) @@ -622,7 +531,7 @@ func TestZetacore_GetKeyGen(t *testing.T) { method := "/zetachain.zetacore.observer.Query/Keygen" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetKeyGen(ctx) require.NoError(t, err) @@ -639,7 +548,7 @@ func TestZetacore_GetBallotByID(t *testing.T) { method := "/zetachain.zetacore.observer.Query/BallotByIdentifier" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetBallot(ctx, "ballot1235") require.NoError(t, err) @@ -663,7 +572,7 @@ func TestZetacore_GetInboundTrackersForChain(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/InboundTrackerAllByChain" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetInboundTrackersForChain(ctx, chainID) require.NoError(t, err) @@ -686,7 +595,7 @@ func TestZetacore_GetTss(t *testing.T) { method := "/zetachain.zetacore.observer.Query/TSS" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetTSS(ctx) require.NoError(t, err) @@ -704,7 +613,7 @@ func TestZetacore_GetEthTssAddress(t *testing.T) { method := "/zetachain.zetacore.observer.Query/GetTssAddress" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetEVMTSSAddress(ctx) require.NoError(t, err) @@ -722,7 +631,7 @@ func TestZetacore_GetBtcTssAddress(t *testing.T) { method := "/zetachain.zetacore.observer.Query/GetTssAddress" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetBTCTSSAddress(ctx, 8332) require.NoError(t, err) @@ -747,7 +656,7 @@ func TestZetacore_GetTssHistory(t *testing.T) { method := "/zetachain.zetacore.observer.Query/TssHistory" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetTSSHistory(ctx) require.NoError(t, err) @@ -771,7 +680,7 @@ func TestZetacore_GetOutboundTracker(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/OutboundTracker" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) ctx := context.Background() resp, err := client.GetOutboundTracker(ctx, chain, 456) @@ -806,7 +715,7 @@ func TestZetacore_GetAllOutboundTrackerByChain(t *testing.T) { method := "/zetachain.zetacore.crosschain.Query/OutboundTrackerAllByChain" setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetAllOutboundTrackerByChain(ctx, chain.ChainId, interfaces.Ascending) require.NoError(t, err) @@ -832,7 +741,7 @@ func TestZetacore_GetPendingNoncesByChain(t *testing.T) { method := "/zetachain.zetacore.observer.Query/PendingNoncesByChain" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetPendingNoncesByChain(ctx, chains.Ethereum.ChainId) require.NoError(t, err) @@ -853,7 +762,7 @@ func TestZetacore_GetBlockHeaderChainState(t *testing.T) { method := "/zetachain.zetacore.lightclient.Query/ChainState" setupMockServer(t, lightclienttypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetBlockHeaderChainState(ctx, chainID) require.NoError(t, err) @@ -889,7 +798,7 @@ func TestZetacore_GetSupportedChains(t *testing.T) { method := "/zetachain.zetacore.observer.Query/SupportedChains" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetSupportedChains(ctx) require.NoError(t, err) @@ -912,11 +821,7 @@ func TestZetacore_GetAdditionalChains(t *testing.T) { setupMockServer(t, authoritytypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, - withDefaultObserverKeys(), - withAccountRetriever(t, 100, 100), - withTendermint(mocks.NewSDKClientWithErr(t, nil, 0).SetBroadcastTxHash(sampleHash)), - ) + client := setupZetacoreClients(t) resp, err := client.GetAdditionalChains(ctx) require.NoError(t, err) @@ -940,7 +845,7 @@ func TestZetacore_GetPendingNonces(t *testing.T) { method := "/zetachain.zetacore.observer.Query/PendingNoncesAll" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.GetPendingNonces(ctx) require.NoError(t, err) @@ -967,7 +872,7 @@ func TestZetacore_Prove(t *testing.T) { method := "/zetachain.zetacore.lightclient.Query/Prove" setupMockServer(t, lightclienttypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.Prove(ctx, blockHash, txHash, int64(txIndex), nil, chainId) require.NoError(t, err) @@ -985,40 +890,9 @@ func TestZetacore_HasVoted(t *testing.T) { method := "/zetachain.zetacore.observer.Query/HasVoted" setupMockServer(t, observertypes.RegisterQueryServer, method, input, expectedOutput) - client := setupZetacoreClient(t, withDefaultObserverKeys()) + client := setupZetacoreClients(t) resp, err := client.HasVoted(ctx, "123456asdf", "zeta1l40mm7meacx03r4lp87s9gkxfan32xnznp42u6") require.NoError(t, err) require.Equal(t, expectedOutput.HasVoted, resp) } - -func TestZetacore_GetZetaHotKeyBalance(t *testing.T) { - ctx := context.Background() - - expectedOutput := banktypes.QueryBalanceResponse{ - Balance: &types.Coin{ - Denom: config.BaseDenom, - Amount: types.NewInt(55646484), - }, - } - input := banktypes.QueryBalanceRequest{ - Address: types.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()).String(), - Denom: config.BaseDenom, - } - method := "/cosmos.bank.v1beta1.Query/Balance" - setupMockServer(t, banktypes.RegisterQueryServer, method, input, expectedOutput) - - client := setupZetacoreClient(t, withDefaultObserverKeys()) - - // should be able to get balance of signer - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), types.AccAddress{}, "bob", "") - resp, err := client.GetZetaHotKeyBalance(ctx) - require.NoError(t, err) - require.Equal(t, expectedOutput.Balance.Amount, resp) - - // should return error on empty signer - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), types.AccAddress{}, "", "") - resp, err = client.GetZetaHotKeyBalance(ctx) - require.Error(t, err) - require.Equal(t, types.ZeroInt(), resp) -} diff --git a/zetaclient/zetacore/client.go b/zetaclient/zetacore/client.go index aee2e51784..dc5a888678 100644 --- a/zetaclient/zetacore/client.go +++ b/zetaclient/zetacore/client.go @@ -10,23 +10,17 @@ import ( rpchttp "github.com/cometbft/cometbft/rpc/client/http" cosmosclient "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/pkg/errors" "github.com/rs/zerolog" etherminttypes "github.com/zeta-chain/ethermint/types" - feemarkettypes "github.com/zeta-chain/ethermint/x/feemarket/types" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "github.com/zeta-chain/zetacore/app" "github.com/zeta-chain/zetacore/pkg/authz" "github.com/zeta-chain/zetacore/pkg/chains" - authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" - crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" - lightclienttypes "github.com/zeta-chain/zetacore/x/lightclient/types" + zetacore_rpc "github.com/zeta-chain/zetacore/pkg/rpc" observertypes "github.com/zeta-chain/zetacore/x/observer/types" "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" "github.com/zeta-chain/zetacore/zetaclient/config" @@ -38,10 +32,11 @@ var _ interfaces.ZetacoreClient = &Client{} // Client is the client to send tx to zetacore type Client struct { + zetacore_rpc.Clients + logger zerolog.Logger config config.ClientConfiguration - client clients cosmosClientContext cosmosclient.Context blockHeight int64 @@ -58,17 +53,6 @@ type Client struct { mu sync.RWMutex } -type clients struct { - observer observertypes.QueryClient - light lightclienttypes.QueryClient - crosschain crosschaintypes.QueryClient - bank banktypes.QueryClient - upgrade upgradetypes.QueryClient - fees feemarkettypes.QueryClient - authority authoritytypes.QueryClient - tendermint tmservice.ServiceClient -} - var unsecureGRPC = grpc.WithTransportCredentials(insecure.NewCredentials()) type constructOpts struct { @@ -129,7 +113,7 @@ func NewClient( encodingCfg := app.MakeEncodingConfig() - grpcConn, err := grpc.Dial(cosmosGRPC(chainIP), unsecureGRPC) + zetacoreClients, err := zetacore_rpc.NewGRPCClients(cosmosGRPC(chainIP), unsecureGRPC) if err != nil { return nil, errors.Wrap(err, "grpc dial fail") } @@ -147,20 +131,11 @@ func NewClient( } return &Client{ - logger: log, - config: cfg, + Clients: zetacoreClients, + logger: log, + config: cfg, cosmosClientContext: cosmosContext, - client: clients{ - observer: observertypes.NewQueryClient(grpcConn), - light: lightclienttypes.NewQueryClient(grpcConn), - crosschain: crosschaintypes.NewQueryClient(grpcConn), - bank: banktypes.NewQueryClient(grpcConn), - upgrade: upgradetypes.NewQueryClient(grpcConn), - fees: feemarkettypes.NewQueryClient(grpcConn), - authority: authoritytypes.NewQueryClient(grpcConn), - tendermint: tmservice.NewServiceClient(grpcConn), - }, accountNumber: accountsMap, seqNumber: seqMap, diff --git a/zetaclient/zetacore/client_query_cosmos.go b/zetaclient/zetacore/client_cosmos.go similarity index 64% rename from zetaclient/zetacore/client_query_cosmos.go rename to zetaclient/zetacore/client_cosmos.go index 61d690d54a..815615c3bd 100644 --- a/zetaclient/zetacore/client_query_cosmos.go +++ b/zetaclient/zetacore/client_cosmos.go @@ -8,7 +8,6 @@ import ( tmhttp "github.com/cometbft/cometbft/rpc/client/http" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/pkg/errors" "github.com/zeta-chain/zetacore/cmd/zetacored/config" @@ -42,31 +41,6 @@ func (c *Client) GetGenesisSupply(ctx context.Context) (sdkmath.Int, error) { return bankstate.Supply.AmountOf(config.BaseDenom), nil } -// GetUpgradePlan returns the current upgrade plan. -// if there is no active upgrade plan, plan will be nil, err will be nil as well. -func (c *Client) GetUpgradePlan(ctx context.Context) (*upgradetypes.Plan, error) { - in := &upgradetypes.QueryCurrentPlanRequest{} - - resp, err := c.client.upgrade.CurrentPlan(ctx, in) - if err != nil { - return nil, errors.Wrap(err, "failed to get current upgrade plan") - } - - return resp.Plan, nil -} - -// GetZetaTokenSupplyOnNode returns the zeta token supply on the node -func (c *Client) GetZetaTokenSupplyOnNode(ctx context.Context) (sdkmath.Int, error) { - in := &banktypes.QuerySupplyOfRequest{Denom: config.BaseDenom} - - resp, err := c.client.bank.SupplyOf(ctx, in) - if err != nil { - return sdkmath.ZeroInt(), errors.Wrap(err, "failed to get zeta token supply") - } - - return resp.GetAmount().Amount, nil -} - // GetZetaHotKeyBalance returns the zeta hot key balance func (c *Client) GetZetaHotKeyBalance(ctx context.Context) (sdkmath.Int, error) { address, err := c.keys.GetAddress() @@ -79,7 +53,7 @@ func (c *Client) GetZetaHotKeyBalance(ctx context.Context) (sdkmath.Int, error) Denom: config.BaseDenom, } - resp, err := c.client.bank.Balance(ctx, in) + resp, err := c.Clients.Bank.Balance(ctx, in) if err != nil { return sdkmath.ZeroInt(), errors.Wrap(err, "failed to get zeta hot key balance") } diff --git a/zetaclient/zetacore/client_test.go b/zetaclient/zetacore/client_test.go new file mode 100644 index 0000000000..723f29084d --- /dev/null +++ b/zetaclient/zetacore/client_test.go @@ -0,0 +1,191 @@ +package zetacore + +import ( + "context" + "net" + "testing" + + abci "github.com/cometbft/cometbft/abci/types" + cosmosclient "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/testutil/mock" + "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/golang/mock/gomock" + "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + feemarkettypes "github.com/zeta-chain/ethermint/x/feemarket/types" + keyinterfaces "github.com/zeta-chain/zetacore/zetaclient/keys/interfaces" + "go.nhat.io/grpcmock" + "go.nhat.io/grpcmock/planner" + + "github.com/zeta-chain/zetacore/cmd/zetacored/config" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + "github.com/zeta-chain/zetacore/zetaclient/keys" + "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" +) + +const skipMethod = "skip" + +// setupMockServer setup mock zetacore GRPC server +func setupMockServer( + t *testing.T, + serviceFunc any, method string, input any, expectedOutput any, + extra ...grpcmock.ServerOption, +) *grpcmock.Server { + listener, err := net.Listen("tcp", "127.0.0.1:9090") + require.NoError(t, err) + + opts := []grpcmock.ServerOption{ + grpcmock.RegisterService(serviceFunc), + grpcmock.WithPlanner(planner.FirstMatch()), + grpcmock.WithListener(listener), + } + + opts = append(opts, extra...) + + if method != skipMethod { + opts = append(opts, func(s *grpcmock.Server) { + s.ExpectUnary(method). + UnlimitedTimes(). + WithPayload(input). + Return(expectedOutput) + }) + } + + server := grpcmock.MockUnstartedServer(opts...)(t) + + server.Serve() + + t.Cleanup(func() { + require.NoError(t, server.Close()) + }) + + return server +} + +func withDummyServer(zetaBlockHeight int64) []grpcmock.ServerOption { + return []grpcmock.ServerOption{ + grpcmock.RegisterService(crosschaintypes.RegisterQueryServer), + grpcmock.RegisterService(crosschaintypes.RegisterMsgServer), + grpcmock.RegisterService(feemarkettypes.RegisterQueryServer), + grpcmock.RegisterService(authtypes.RegisterQueryServer), + grpcmock.RegisterService(abci.RegisterABCIApplicationServer), + func(s *grpcmock.Server) { + // Block Height + s.ExpectUnary("/zetachain.zetacore.crosschain.Query/LastZetaHeight"). + UnlimitedTimes(). + Return(crosschaintypes.QueryLastZetaHeightResponse{Height: zetaBlockHeight}) + + // London Base Fee + s.ExpectUnary("/ethermint.feemarket.v1.Query/Params"). + UnlimitedTimes(). + Return(feemarkettypes.QueryParamsResponse{ + Params: feemarkettypes.Params{BaseFee: types.NewInt(100)}, + }) + }, + } +} + +type clientTestConfig struct { + keys keyinterfaces.ObserverKeys + opts []Opt +} + +type clientTestOpt func(*clientTestConfig) + +func withObserverKeys(keys keyinterfaces.ObserverKeys) clientTestOpt { + return func(cfg *clientTestConfig) { cfg.keys = keys } +} + +func withDefaultObserverKeys() clientTestOpt { + var ( + key = mocks.TestKeyringPair + address = types.AccAddress(key.PubKey().Address().Bytes()) + keyRing = mocks.NewKeyring() + ) + + return withObserverKeys(keys.NewKeysWithKeybase(keyRing, address, testSigner, "")) +} + +func withTendermint(client cosmosclient.TendermintRPC) clientTestOpt { + return func(cfg *clientTestConfig) { cfg.opts = append(cfg.opts, WithTendermintClient(client)) } +} + +func withAccountRetriever(t *testing.T, accNum uint64, accSeq uint64) clientTestOpt { + ctrl := gomock.NewController(t) + ac := mock.NewMockAccountRetriever(ctrl) + ac.EXPECT(). + GetAccountNumberSequence(gomock.Any(), gomock.Any()). + AnyTimes(). + Return(accNum, accSeq, nil) + + return func(cfg *clientTestConfig) { + cfg.opts = append(cfg.opts, WithCustomAccountRetriever(ac)) + } +} + +func setupZetacoreClient(t *testing.T, opts ...clientTestOpt) *Client { + const ( + chainIP = "127.0.0.1" + signer = testSigner + chainID = "zetachain_7000-1" + ) + + var cfg clientTestConfig + for _, opt := range opts { + opt(&cfg) + } + + if cfg.keys == nil { + cfg.keys = &keys.Keys{} + } + + c, err := NewClient( + cfg.keys, + chainIP, signer, + chainID, + false, + zerolog.Nop(), + cfg.opts..., + ) + + require.NoError(t, err) + + return c +} + +// Need to test after refactor +func TestZetacore_GetGenesisSupply(t *testing.T) { +} + +func TestZetacore_GetZetaHotKeyBalance(t *testing.T) { + ctx := context.Background() + + expectedOutput := banktypes.QueryBalanceResponse{ + Balance: &types.Coin{ + Denom: config.BaseDenom, + Amount: types.NewInt(55646484), + }, + } + input := banktypes.QueryBalanceRequest{ + Address: types.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()).String(), + Denom: config.BaseDenom, + } + method := "/cosmos.bank.v1beta1.Query/Balance" + setupMockServer(t, banktypes.RegisterQueryServer, method, input, expectedOutput) + + client := setupZetacoreClient(t, withDefaultObserverKeys()) + + // should be able to get balance of signer + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), types.AccAddress{}, "bob", "") + resp, err := client.GetZetaHotKeyBalance(ctx) + require.NoError(t, err) + require.Equal(t, expectedOutput.Balance.Amount, resp) + + // should return error on empty signer + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), types.AccAddress{}, "", "") + resp, err = client.GetZetaHotKeyBalance(ctx) + require.Error(t, err) + require.Equal(t, types.ZeroInt(), resp) +}