diff --git a/changelog.md b/changelog.md index 5f1d3abbce..c6396ae86f 100644 --- a/changelog.md +++ b/changelog.md @@ -81,6 +81,7 @@ Getting the correct TSS address for Bitcoin now requires proviidng the Bitcoin c * [1546](https://github.com/zeta-chain/node/pull/1546) - fix reset of pending nonces on genesis import * [1555](https://github.com/zeta-chain/node/pull/1555) - Reduce websocket message limit to 10MB * [1567](https://github.com/zeta-chain/node/pull/1567) - add bitcoin chain id to fetch the tss address rpc endpoint +* [1501](https://github.com/zeta-chain/node/pull/1501) - fix stress test - use new refactored config file and smoketest runner * [1589](https://github.com/zeta-chain/node/pull/1589) - add bitcoin chain id to `get tss address` and `get tss address historical` cli query ### Refactoring diff --git a/cmd/zetae2e/init.go b/cmd/zetae2e/init.go new file mode 100644 index 0000000000..66d7e4fd3f --- /dev/null +++ b/cmd/zetae2e/init.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + + "github.com/zeta-chain/zetacore/cmd/zetae2e/local" + + "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/config" +) + +var initConf = config.Config{} +var configFile = "" + +func NewInitCmd() *cobra.Command { + var InitCmd = &cobra.Command{ + Use: "init", + Short: "initialize config file for e2e tests", + Run: initConfig, + } + + InitCmd.Flags().StringVar(&initConf.RPCs.EVM, "ethURL", "http://eth:8545", "--ethURL http://eth:8545") + InitCmd.Flags().StringVar(&initConf.RPCs.ZetaCoreGRPC, "grpcURL", "zetacore0:9090", "--grpcURL zetacore0:9090") + InitCmd.Flags().StringVar(&initConf.RPCs.ZetaCoreRPC, "rpcURL", "http://zetacore0:26657", "--rpcURL http://zetacore0:26657") + InitCmd.Flags().StringVar(&initConf.RPCs.Zevm, "zevmURL", "http://zetacore0:8545", "--zevmURL http://zetacore0:8545") + InitCmd.Flags().StringVar(&initConf.RPCs.Bitcoin, "btcURL", "bitcoin:18443", "--grpcURL bitcoin:18443") + + InitCmd.Flags().StringVar(&initConf.ZetaChainID, "chainID", "athens_101-1", "--chainID athens_101-1") + InitCmd.Flags().StringVar(&configFile, local.FlagConfigFile, "smoketest.config", "--cfg ./smoketest.config") + + return InitCmd +} + +func initConfig(_ *cobra.Command, _ []string) { + err := config.WriteConfig(configFile, initConf) + if err != nil { + fmt.Printf("error writing config file: %s", err.Error()) + } +} diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index b31c6869d4..92b16526f3 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -18,7 +18,7 @@ import ( const ( flagContractsDeployed = "deployed" flagWaitForHeight = "wait-for" - flagConfigFile = "config" + FlagConfigFile = "config" flagVerbose = "verbose" flagTestAdmin = "test-admin" flagTestCustom = "test-custom" @@ -51,7 +51,7 @@ func NewLocalCmd() *cobra.Command { "block height for tests to begin, ex. --wait-for 100", ) cmd.Flags().String( - flagConfigFile, + FlagConfigFile, "", "config file to use for the tests", ) @@ -149,7 +149,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { }() // initialize tests config - conf, err := getConfig(cmd) + conf, err := GetConfig(cmd) if err != nil { panic(err) } diff --git a/cmd/zetae2e/local/utils.go b/cmd/zetae2e/local/utils.go index 8e1ab210c1..e190b45df1 100644 --- a/cmd/zetae2e/local/utils.go +++ b/cmd/zetae2e/local/utils.go @@ -16,9 +16,9 @@ import ( crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) -// getConfig returns config from file from the command line flag -func getConfig(cmd *cobra.Command) (config.Config, error) { - configFile, err := cmd.Flags().GetString(flagConfigFile) +// GetConfig returns config from file from the command line flag +func GetConfig(cmd *cobra.Command) (config.Config, error) { + configFile, err := cmd.Flags().GetString(FlagConfigFile) if err != nil { return config.Config{}, err } diff --git a/cmd/zetae2e/root.go b/cmd/zetae2e/root.go index 8f514a6584..fb93caa131 100644 --- a/cmd/zetae2e/root.go +++ b/cmd/zetae2e/root.go @@ -13,6 +13,8 @@ func NewRootCmd() *cobra.Command { cmd.AddCommand( NewRunCmd(), local.NewLocalCmd(), + NewStressTestCmd(), + NewInitCmd(), ) return cmd diff --git a/cmd/zetae2e/stress.go b/cmd/zetae2e/stress.go index 670922056f..26a2169b95 100644 --- a/cmd/zetae2e/stress.go +++ b/cmd/zetae2e/stress.go @@ -1,321 +1,318 @@ package main -//import ( -// "context" -// "errors" -// "fmt" -// "math/big" -// "os" -// "sort" -// "time" -// -// 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" -// ethcommon "github.com/ethereum/go-ethereum/common" -// "github.com/ethereum/go-ethereum/crypto" -// "github.com/ethereum/go-ethereum/ethclient" -// "github.com/spf13/cobra" -// "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" -// crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" -// fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" -// observertypes "github.com/zeta-chain/zetacore/x/observer/types" -// "google.golang.org/grpc" -//) -// -//const ( -// StatInterval = 5 -// StressTestTimeout = 100 * time.Minute -//) -// -//var ( -// zevmNonce = big.NewInt(1) -//) -// -//var StressCmd = &cobra.Command{ -// Use: "stress", -// Short: "Run Local Stress Test", -// Run: StressTest, -//} -// -//type stressArguments struct { -// ethURL string -// grpcURL string -// zevmURL string -// deployerAddress string -// deployerPrivateKey string -// network string -// txnInterval int64 -//} -// -//var stressTestArgs = stressArguments{} -// -//func init() { -// RootCmd.AddCommand(StressCmd) -// StressCmd.Flags().StringVar(&stressTestArgs.ethURL, "ethURL", "http://eth:8545", "--ethURL http://eth:8545") -// StressCmd.Flags().StringVar(&stressTestArgs.grpcURL, "grpcURL", "zetacore0:9090", "--grpcURL zetacore0:9090") -// StressCmd.Flags().StringVar(&stressTestArgs.zevmURL, "zevmURL", zevmRPC, "--zevmURL http://zetacore0:8545") -// StressCmd.Flags().StringVar(&stressTestArgs.deployerAddress, "addr", "0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC", "--addr ") -// StressCmd.Flags().StringVar(&stressTestArgs.deployerPrivateKey, "privKey", "d87baf7bf6dc560a252596678c12e41f7d1682837f05b29d411bc3f78ae2c263", "--privKey ") -// StressCmd.Flags().StringVar(&stressTestArgs.network, "network", "PRIVNET", "--network PRIVNET") -// StressCmd.Flags().Int64Var(&stressTestArgs.txnInterval, "tx-interval", 500, "--tx-interval [TIME_INTERVAL_MILLISECONDS]") -// -// DeployerAddress = ethcommon.HexToAddress(stressTestArgs.deployerAddress) -//} -// -//func StressTest(_ *cobra.Command, _ []string) { -// testStartTime := time.Now() -// defer func() { -// fmt.Println("Smoke test took", time.Since(testStartTime)) -// }() -// go func() { -// time.Sleep(StressTestTimeout) -// fmt.Println("Smoke test timed out after", StressTestTimeout) -// os.Exit(1) -// }() -// -// goerliClient, err := ethclient.Dial(stressTestArgs.ethURL) -// if err != nil { -// panic(err) -// } -// -// bal, err := goerliClient.BalanceAt(context.TODO(), DeployerAddress, nil) -// if err != nil { -// panic(err) -// } -// fmt.Printf("Deployer address: %s, balance: %d Wei\n", DeployerAddress.Hex(), bal) -// -// chainid, err := goerliClient.ChainID(context.Background()) -// if err != nil { -// panic(err) -// } -// deployerPrivkey, err := crypto.HexToECDSA(stressTestArgs.deployerPrivateKey) -// if err != nil { -// panic(err) -// } -// goerliAuth, err := bind.NewKeyedTransactorWithChainID(deployerPrivkey, chainid) -// if err != nil { -// panic(err) -// } -// -// grpcConn, err := grpc.Dial(stressTestArgs.grpcURL, grpc.WithInsecure()) -// if err != nil { -// panic(err) -// } -// -// cctxClient := crosschaintypes.NewQueryClient(grpcConn) -// fungibleClient := fungibletypes.NewQueryClient(grpcConn) -// bankClient := banktypes.NewQueryClient(grpcConn) -// authClient := authtypes.NewQueryClient(grpcConn) -// observerClient := observertypes.NewQueryClient(grpcConn) -// -// // Wait for Genesis and keygen to be completed. ~ height 30 -// time.Sleep(20 * time.Second) -// for { -// time.Sleep(5 * time.Second) -// response, err := cctxClient.LastZetaHeight(context.Background(), &crosschaintypes.QueryLastZetaHeightRequest{}) -// if err != nil { -// fmt.Printf("cctxClient.LastZetaHeight error: %s", err) -// continue -// } -// if response.Height >= 30 { -// break -// } -// fmt.Printf("Last ZetaHeight: %d\n", response.Height) -// } -// -// // get the clients for tests -// var zevmClient *ethclient.Client -// for { -// time.Sleep(5 * time.Second) -// fmt.Printf("dialing zevm client: %s\n", stressTestArgs.zevmURL) -// zevmClient, err = ethclient.Dial(stressTestArgs.zevmURL) -// if err != nil { -// continue -// } -// break -// } -// chainid, err = zevmClient.ChainID(context.Background()) -// if err != nil { -// panic(err) -// } -// zevmAuth, err := bind.NewKeyedTransactorWithChainID(deployerPrivkey, chainid) -// if err != nil { -// panic(err) -// } -// -// smokeTest := NewSmokeTest( -// goerliClient, -// zevmClient, -// cctxClient, -// ZetaTxServer{}, // not used in stress test -// fungibleClient, -// authClient, -// bankClient, -// observerClient, -// goerliAuth, -// zevmAuth, -// nil, -// ) -// -// // If stress test is running on local docker environment -// if stressTestArgs.network == "PRIVNET" { -// smokeTest.TestSetupZetaTokenAndConnectorAndZEVMContracts() -// smokeTest.TestDepositEtherIntoZRC20() -// smokeTest.TestSendZetaIn() -// } else if stressTestArgs.network == "TESTNET" { -// ethZRC20Addr, err := smokeTest.SystemContract.GasCoinZRC20ByChainId(&bind.CallOpts{}, big.NewInt(5)) -// if err != nil { -// panic(err) -// } -// smokeTest.ETHZRC20Addr = ethZRC20Addr -// smokeTest.ETHZRC20, err = zrc20.NewZRC20(smokeTest.ETHZRC20Addr, smokeTest.zevmClient) -// if err != nil { -// panic(err) -// } -// } else { -// err := errors.New("invalid network argument: " + stressTestArgs.network) -// panic(err) -// } -// -// // Check zrc20 balance of Deployer address -// ethZRC20Balance, err := smokeTest.ETHZRC20.BalanceOf(nil, DeployerAddress) -// if err != nil { -// panic(err) -// } -// fmt.Printf("eth zrc20 balance: %s Wei \n", ethZRC20Balance.String()) -// -// //Pre-approve ETH withdraw on ZEVM -// fmt.Printf("approving ETH ZRC20...\n") -// ethZRC20 := smokeTest.ETHZRC20 -// tx, err := ethZRC20.Approve(smokeTest.zevmAuth, smokeTest.ETHZRC20Addr, big.NewInt(1e18)) -// if err != nil { -// panic(err) -// } -// receipt := MustWaitForTxReceipt(smokeTest.zevmClient, tx) -// fmt.Printf("eth zrc20 approve receipt: status %d\n", receipt.Status) -// -// // Get current nonce on zevm for DeployerAddress - Need to keep track of nonce at client level -// blockNum, err := smokeTest.zevmClient.BlockNumber(context.Background()) -// if err != nil { -// panic(err) -// } -// -// // #nosec G701 smoketest - always in range -// nonce, err := smokeTest.zevmClient.NonceAt(context.Background(), DeployerAddress, big.NewInt(int64(blockNum))) -// if err != nil { -// panic(err) -// } -// -// // #nosec G701 smoketest - always in range -// zevmNonce = big.NewInt(int64(nonce)) -// -// // -------------- TEST BEGINS ------------------ -// -// fmt.Println("**** STRESS TEST BEGINS ****") -// fmt.Println(" 1. Periodically Withdraw ETH from ZEVM to EVM - goerli") -// fmt.Println(" 2. Display Network metrics to monitor performance [Num Pending outbound tx], [Num Trackers]") -// -// smokeTest.wg.Add(2) -// go smokeTest.WithdrawCCtx() // Withdraw USDT from ZEVM to EVM - goerli -// go smokeTest.EchoNetworkMetrics() // Display Network metrics periodically to monitor performance -// -// smokeTest.wg.Wait() -//} -// -//// WithdrawCCtx withdraw USDT from ZEVM to EVM -//func (sm *SmokeTest) WithdrawCCtx() { -// ticker := time.NewTicker(time.Millisecond * time.Duration(stressTestArgs.txnInterval)) -// for { -// select { -// case <-ticker.C: -// sm.WithdrawETHZRC20() -// } -// } -//} -// -//func (sm *SmokeTest) EchoNetworkMetrics() { -// ticker := time.NewTicker(time.Second * StatInterval) -// var queue = make([]uint64, 0) -// var numTicks = 0 -// var totalMinedTxns = uint64(0) -// var previousMinedTxns = uint64(0) -// -// for { -// select { -// case <-ticker.C: -// numTicks++ -// // Get all pending outbound transactions -// cctxResp, err := sm.cctxClient.CctxListPending(context.Background(), &crosschaintypes.QueryListCctxPendingRequest{ -// ChainId: getChainID(), -// }) -// if err != nil { -// continue -// } -// sends := cctxResp.CrossChainTx -// sort.Slice(sends, func(i, j int) bool { -// return sends[i].GetCurrentOutTxParam().OutboundTxTssNonce < sends[j].GetCurrentOutTxParam().OutboundTxTssNonce -// }) -// if len(sends) > 0 { -// fmt.Printf("pending nonces %d to %d\n", sends[0].GetCurrentOutTxParam().OutboundTxTssNonce, sends[len(sends)-1].GetCurrentOutTxParam().OutboundTxTssNonce) -// } else { -// continue -// } -// // -// // Get all trackers -// trackerResp, err := sm.cctxClient.OutTxTrackerAll(context.Background(), &crosschaintypes.QueryAllOutTxTrackerRequest{}) -// if err != nil { -// continue -// } -// -// currentMinedTxns := sends[0].GetCurrentOutTxParam().OutboundTxTssNonce -// newMinedTxCnt := currentMinedTxns - previousMinedTxns -// previousMinedTxns = currentMinedTxns -// -// // Add new mined txn count to queue and remove the oldest entry -// queue = append(queue, newMinedTxCnt) -// if numTicks > 60/StatInterval { -// totalMinedTxns -= queue[0] -// queue = queue[1:] -// numTicks = 60/StatInterval + 1 //prevent overflow -// } -// -// //Calculate rate -> tx/min -// totalMinedTxns += queue[len(queue)-1] -// rate := totalMinedTxns -// -// numPending := len(cctxResp.CrossChainTx) -// numTrackers := len(trackerResp.OutTxTracker) -// -// fmt.Println("Network Stat => Num of Pending cctx: ", numPending, "Num active trackers: ", numTrackers, "Tx Rate: ", rate, " tx/min") -// } -// } -//} -// -//func (sm *SmokeTest) WithdrawETHZRC20() { -// defer func() { -// zevmNonce.Add(zevmNonce, big.NewInt(1)) -// }() -// -// ethZRC20 := sm.ETHZRC20 -// -// sm.zevmAuth.Nonce = zevmNonce -// _, err := ethZRC20.Withdraw(sm.zevmAuth, DeployerAddress.Bytes(), big.NewInt(100)) -// if err != nil { -// panic(err) -// } -//} -// -//// Get ETH based chain ID - Build flags are conflicting with current lib, need to do this manually -//func getChainID() int64 { -// switch stressTestArgs.network { -// case "PRIVNET": -// return 1337 -// case "TESTNET": -// return 5 -// case "MAINNET": -// return 1 -// default: -// return 1337 -// } -//} +import ( + "context" + "errors" + "fmt" + "math/big" + "os" + "sort" + "time" + + "github.com/fatih/color" + zetae2econfig "github.com/zeta-chain/zetacore/cmd/zetae2e/config" + "github.com/zeta-chain/zetacore/cmd/zetae2e/local" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/app" + "github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/runner" + "github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/utils" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/spf13/cobra" + "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + "google.golang.org/grpc" +) + +const ( + StatInterval = 5 + StressTestTimeout = 100 * time.Minute +) + +var ( + zevmNonce = big.NewInt(1) +) + +type stressArguments struct { + deployerAddress string + deployerPrivateKey string + network string + txnInterval int64 + contractsDeployed bool + config string +} + +var stressTestArgs = stressArguments{} + +func NewStressTestCmd() *cobra.Command { + var StressCmd = &cobra.Command{ + Use: "stress", + Short: "Run Stress Test", + Run: StressTest, + } + + StressCmd.Flags().StringVar(&stressTestArgs.deployerAddress, "addr", "0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC", "--addr ") + StressCmd.Flags().StringVar(&stressTestArgs.deployerPrivateKey, "privKey", "d87baf7bf6dc560a252596678c12e41f7d1682837f05b29d411bc3f78ae2c263", "--privKey ") + StressCmd.Flags().StringVar(&stressTestArgs.network, "network", "LOCAL", "--network TESTNET") + StressCmd.Flags().Int64Var(&stressTestArgs.txnInterval, "tx-interval", 500, "--tx-interval [TIME_INTERVAL_MILLISECONDS]") + StressCmd.Flags().BoolVar(&stressTestArgs.contractsDeployed, "contracts-deployed", false, "--contracts-deployed=false") + StressCmd.Flags().StringVar(&stressTestArgs.config, local.FlagConfigFile, "", "config file to use for the smoketest") + StressCmd.Flags().Bool(flagVerbose, false, "set to true to enable verbose logging") + + local.DeployerAddress = ethcommon.HexToAddress(stressTestArgs.deployerAddress) + + return StressCmd +} + +func StressTest(cmd *cobra.Command, _ []string) { + testStartTime := time.Now() + defer func() { + fmt.Println("Smoke test took", time.Since(testStartTime)) + }() + go func() { + time.Sleep(StressTestTimeout) + fmt.Println("Smoke test timed out after", StressTestTimeout) + os.Exit(1) + }() + + // set account prefix to zeta + cosmosConf := sdk.GetConfig() + cosmosConf.SetBech32PrefixForAccount(app.Bech32PrefixAccAddr, app.Bech32PrefixAccPub) + cosmosConf.Seal() + + // initialize smoke tests config + conf, err := local.GetConfig(cmd) + if err != nil { + panic(err) + } + + // Initialize clients ---------------------------------------------------------------- + goerliClient, err := ethclient.Dial(conf.RPCs.EVM) + if err != nil { + panic(err) + } + + bal, err := goerliClient.BalanceAt(context.TODO(), local.DeployerAddress, nil) + if err != nil { + panic(err) + } + fmt.Printf("Deployer address: %s, balance: %d Wei\n", local.DeployerAddress.Hex(), bal) + + grpcConn, err := grpc.Dial(conf.RPCs.ZetaCoreGRPC, grpc.WithInsecure()) + if err != nil { + panic(err) + } + + cctxClient := crosschaintypes.NewQueryClient(grpcConn) + // ----------------------------------------------------------------------------------- + + // Wait for Genesis and keygen to be completed if network is local. ~ height 30 + if stressTestArgs.network == "LOCAL" { + time.Sleep(20 * time.Second) + for { + time.Sleep(5 * time.Second) + response, err := cctxClient.LastZetaHeight(context.Background(), &crosschaintypes.QueryLastZetaHeightRequest{}) + if err != nil { + fmt.Printf("cctxClient.LastZetaHeight error: %s", err) + continue + } + if response.Height >= 30 { + break + } + fmt.Printf("Last ZetaHeight: %d\n", response.Height) + } + } + + // initialize context + ctx, cancel := context.WithCancel(context.Background()) + + verbose, err := cmd.Flags().GetBool(flagVerbose) + if err != nil { + panic(err) + } + logger := runner.NewLogger(verbose, color.FgWhite, "setup") + + // initialize smoke test runner + smokeTest, err := zetae2econfig.RunnerFromConfig( + ctx, + "deployer", + cancel, + conf, + local.DeployerAddress, + local.DeployerPrivateKey, + utils.FungibleAdminName, + FungibleAdminMnemonic, + logger, + ) + if err != nil { + panic(err) + } + + // setup TSS addresses + smokeTest.SetTSSAddresses() + + smokeTest.SetupEVM(stressTestArgs.contractsDeployed) + + // If stress test is running on local docker environment + if stressTestArgs.network == "LOCAL" { + // deploy and set zevm contract + smokeTest.SetZEVMContracts() + + // deposit on ZetaChain + smokeTest.DepositEther(false) + smokeTest.DepositZeta() + } else if stressTestArgs.network == "TESTNET" { + ethZRC20Addr, err := smokeTest.SystemContract.GasCoinZRC20ByChainId(&bind.CallOpts{}, big.NewInt(5)) + if err != nil { + panic(err) + } + smokeTest.ETHZRC20Addr = ethZRC20Addr + smokeTest.ETHZRC20, err = zrc20.NewZRC20(smokeTest.ETHZRC20Addr, smokeTest.ZevmClient) + if err != nil { + panic(err) + } + } else { + err := errors.New("invalid network argument: " + stressTestArgs.network) + panic(err) + } + + // Check zrc20 balance of Deployer address + ethZRC20Balance, err := smokeTest.ETHZRC20.BalanceOf(nil, local.DeployerAddress) + if err != nil { + panic(err) + } + fmt.Printf("eth zrc20 balance: %s Wei \n", ethZRC20Balance.String()) + + //Pre-approve ETH withdraw on ZEVM + fmt.Printf("approving ETH ZRC20...\n") + ethZRC20 := smokeTest.ETHZRC20 + tx, err := ethZRC20.Approve(smokeTest.ZevmAuth, smokeTest.ETHZRC20Addr, big.NewInt(1e18)) + if err != nil { + panic(err) + } + receipt := utils.MustWaitForTxReceipt(ctx, smokeTest.ZevmClient, tx, logger, smokeTest.ReceiptTimeout) + fmt.Printf("eth zrc20 approve receipt: status %d\n", receipt.Status) + + // Get current nonce on zevm for DeployerAddress - Need to keep track of nonce at client level + blockNum, err := smokeTest.ZevmClient.BlockNumber(context.Background()) + if err != nil { + panic(err) + } + + // #nosec G701 smoketest - always in range + nonce, err := smokeTest.ZevmClient.NonceAt(context.Background(), local.DeployerAddress, big.NewInt(int64(blockNum))) + if err != nil { + panic(err) + } + + // #nosec G701 smoketest - always in range + zevmNonce = big.NewInt(int64(nonce)) + + // -------------- TEST BEGINS ------------------ + + fmt.Println("**** STRESS TEST BEGINS ****") + fmt.Println(" 1. Periodically Withdraw ETH from ZEVM to EVM - goerli") + fmt.Println(" 2. Display Network metrics to monitor performance [Num Pending outbound tx], [Num Trackers]") + + smokeTest.WG.Add(2) + go WithdrawCCtx(smokeTest) // Withdraw USDT from ZEVM to EVM - goerli + go EchoNetworkMetrics(smokeTest) // Display Network metrics periodically to monitor performance + + smokeTest.WG.Wait() +} + +// WithdrawCCtx withdraw USDT from ZEVM to EVM +func WithdrawCCtx(sm *runner.SmokeTestRunner) { + ticker := time.NewTicker(time.Millisecond * time.Duration(stressTestArgs.txnInterval)) + for { + select { + case <-ticker.C: + WithdrawETHZRC20(sm) + } + } +} + +func EchoNetworkMetrics(sm *runner.SmokeTestRunner) { + ticker := time.NewTicker(time.Second * StatInterval) + var queue = make([]uint64, 0) + var numTicks = 0 + var totalMinedTxns = uint64(0) + var previousMinedTxns = uint64(0) + chainID, err := getChainID(sm.GoerliClient) + + if err != nil { + panic(err) + } + + for { + select { + case <-ticker.C: + numTicks++ + // Get all pending outbound transactions + cctxResp, err := sm.CctxClient.CctxListPending(context.Background(), &crosschaintypes.QueryListCctxPendingRequest{ + ChainId: chainID.Int64(), + }) + if err != nil { + continue + } + sends := cctxResp.CrossChainTx + sort.Slice(sends, func(i, j int) bool { + return sends[i].GetCurrentOutTxParam().OutboundTxTssNonce < sends[j].GetCurrentOutTxParam().OutboundTxTssNonce + }) + if len(sends) > 0 { + fmt.Printf("pending nonces %d to %d\n", sends[0].GetCurrentOutTxParam().OutboundTxTssNonce, sends[len(sends)-1].GetCurrentOutTxParam().OutboundTxTssNonce) + } else { + continue + } + // + // Get all trackers + trackerResp, err := sm.CctxClient.OutTxTrackerAll(context.Background(), &crosschaintypes.QueryAllOutTxTrackerRequest{}) + if err != nil { + continue + } + + currentMinedTxns := sends[0].GetCurrentOutTxParam().OutboundTxTssNonce + newMinedTxCnt := currentMinedTxns - previousMinedTxns + previousMinedTxns = currentMinedTxns + + // Add new mined txn count to queue and remove the oldest entry + queue = append(queue, newMinedTxCnt) + if numTicks > 60/StatInterval { + totalMinedTxns -= queue[0] + queue = queue[1:] + numTicks = 60/StatInterval + 1 //prevent overflow + } + + //Calculate rate -> tx/min + totalMinedTxns += queue[len(queue)-1] + rate := totalMinedTxns + + numPending := len(cctxResp.CrossChainTx) + numTrackers := len(trackerResp.OutTxTracker) + + fmt.Println("Network Stat => Num of Pending cctx: ", numPending, "Num active trackers: ", numTrackers, "Tx Rate: ", rate, " tx/min") + } + } +} + +func WithdrawETHZRC20(sm *runner.SmokeTestRunner) { + defer func() { + zevmNonce.Add(zevmNonce, big.NewInt(1)) + }() + + ethZRC20 := sm.ETHZRC20 + + sm.ZevmAuth.Nonce = zevmNonce + _, err := ethZRC20.Withdraw(sm.ZevmAuth, local.DeployerAddress.Bytes(), big.NewInt(100)) + if err != nil { + panic(err) + } +} + +// Get ETH based chain ID +func getChainID(client *ethclient.Client) (*big.Int, error) { + return client.ChainID(context.Background()) +} diff --git a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/local.go b/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/local.go index f4aabbcf8b..170e8a644c 100644 --- a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/local.go +++ b/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/local.go @@ -112,7 +112,7 @@ func localSmokeTest(cmd *cobra.Command, _ []string) { }() // initialize smoke tests config - conf, err := getConfig(cmd) + conf, err := GetConfig(cmd) if err != nil { panic(err) } diff --git a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/utils.go b/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/utils.go index 4ca541a406..3cc27582dc 100644 --- a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/utils.go +++ b/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/utils.go @@ -24,8 +24,8 @@ import ( "google.golang.org/grpc" ) -// getConfig returns config from file from the command line flag -func getConfig(cmd *cobra.Command) (config.Config, error) { +// GetConfig returns config from file from the command line flag +func GetConfig(cmd *cobra.Command) (config.Config, error) { configFile, err := cmd.Flags().GetString(flagConfigFile) if err != nil { return config.Config{}, err diff --git a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/stress.go b/contrib/localnet/orchestrator/smoketest/cmd/smoketest/stress.go deleted file mode 100644 index 670922056f..0000000000 --- a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/stress.go +++ /dev/null @@ -1,321 +0,0 @@ -package main - -//import ( -// "context" -// "errors" -// "fmt" -// "math/big" -// "os" -// "sort" -// "time" -// -// 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" -// ethcommon "github.com/ethereum/go-ethereum/common" -// "github.com/ethereum/go-ethereum/crypto" -// "github.com/ethereum/go-ethereum/ethclient" -// "github.com/spf13/cobra" -// "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" -// crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" -// fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" -// observertypes "github.com/zeta-chain/zetacore/x/observer/types" -// "google.golang.org/grpc" -//) -// -//const ( -// StatInterval = 5 -// StressTestTimeout = 100 * time.Minute -//) -// -//var ( -// zevmNonce = big.NewInt(1) -//) -// -//var StressCmd = &cobra.Command{ -// Use: "stress", -// Short: "Run Local Stress Test", -// Run: StressTest, -//} -// -//type stressArguments struct { -// ethURL string -// grpcURL string -// zevmURL string -// deployerAddress string -// deployerPrivateKey string -// network string -// txnInterval int64 -//} -// -//var stressTestArgs = stressArguments{} -// -//func init() { -// RootCmd.AddCommand(StressCmd) -// StressCmd.Flags().StringVar(&stressTestArgs.ethURL, "ethURL", "http://eth:8545", "--ethURL http://eth:8545") -// StressCmd.Flags().StringVar(&stressTestArgs.grpcURL, "grpcURL", "zetacore0:9090", "--grpcURL zetacore0:9090") -// StressCmd.Flags().StringVar(&stressTestArgs.zevmURL, "zevmURL", zevmRPC, "--zevmURL http://zetacore0:8545") -// StressCmd.Flags().StringVar(&stressTestArgs.deployerAddress, "addr", "0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC", "--addr ") -// StressCmd.Flags().StringVar(&stressTestArgs.deployerPrivateKey, "privKey", "d87baf7bf6dc560a252596678c12e41f7d1682837f05b29d411bc3f78ae2c263", "--privKey ") -// StressCmd.Flags().StringVar(&stressTestArgs.network, "network", "PRIVNET", "--network PRIVNET") -// StressCmd.Flags().Int64Var(&stressTestArgs.txnInterval, "tx-interval", 500, "--tx-interval [TIME_INTERVAL_MILLISECONDS]") -// -// DeployerAddress = ethcommon.HexToAddress(stressTestArgs.deployerAddress) -//} -// -//func StressTest(_ *cobra.Command, _ []string) { -// testStartTime := time.Now() -// defer func() { -// fmt.Println("Smoke test took", time.Since(testStartTime)) -// }() -// go func() { -// time.Sleep(StressTestTimeout) -// fmt.Println("Smoke test timed out after", StressTestTimeout) -// os.Exit(1) -// }() -// -// goerliClient, err := ethclient.Dial(stressTestArgs.ethURL) -// if err != nil { -// panic(err) -// } -// -// bal, err := goerliClient.BalanceAt(context.TODO(), DeployerAddress, nil) -// if err != nil { -// panic(err) -// } -// fmt.Printf("Deployer address: %s, balance: %d Wei\n", DeployerAddress.Hex(), bal) -// -// chainid, err := goerliClient.ChainID(context.Background()) -// if err != nil { -// panic(err) -// } -// deployerPrivkey, err := crypto.HexToECDSA(stressTestArgs.deployerPrivateKey) -// if err != nil { -// panic(err) -// } -// goerliAuth, err := bind.NewKeyedTransactorWithChainID(deployerPrivkey, chainid) -// if err != nil { -// panic(err) -// } -// -// grpcConn, err := grpc.Dial(stressTestArgs.grpcURL, grpc.WithInsecure()) -// if err != nil { -// panic(err) -// } -// -// cctxClient := crosschaintypes.NewQueryClient(grpcConn) -// fungibleClient := fungibletypes.NewQueryClient(grpcConn) -// bankClient := banktypes.NewQueryClient(grpcConn) -// authClient := authtypes.NewQueryClient(grpcConn) -// observerClient := observertypes.NewQueryClient(grpcConn) -// -// // Wait for Genesis and keygen to be completed. ~ height 30 -// time.Sleep(20 * time.Second) -// for { -// time.Sleep(5 * time.Second) -// response, err := cctxClient.LastZetaHeight(context.Background(), &crosschaintypes.QueryLastZetaHeightRequest{}) -// if err != nil { -// fmt.Printf("cctxClient.LastZetaHeight error: %s", err) -// continue -// } -// if response.Height >= 30 { -// break -// } -// fmt.Printf("Last ZetaHeight: %d\n", response.Height) -// } -// -// // get the clients for tests -// var zevmClient *ethclient.Client -// for { -// time.Sleep(5 * time.Second) -// fmt.Printf("dialing zevm client: %s\n", stressTestArgs.zevmURL) -// zevmClient, err = ethclient.Dial(stressTestArgs.zevmURL) -// if err != nil { -// continue -// } -// break -// } -// chainid, err = zevmClient.ChainID(context.Background()) -// if err != nil { -// panic(err) -// } -// zevmAuth, err := bind.NewKeyedTransactorWithChainID(deployerPrivkey, chainid) -// if err != nil { -// panic(err) -// } -// -// smokeTest := NewSmokeTest( -// goerliClient, -// zevmClient, -// cctxClient, -// ZetaTxServer{}, // not used in stress test -// fungibleClient, -// authClient, -// bankClient, -// observerClient, -// goerliAuth, -// zevmAuth, -// nil, -// ) -// -// // If stress test is running on local docker environment -// if stressTestArgs.network == "PRIVNET" { -// smokeTest.TestSetupZetaTokenAndConnectorAndZEVMContracts() -// smokeTest.TestDepositEtherIntoZRC20() -// smokeTest.TestSendZetaIn() -// } else if stressTestArgs.network == "TESTNET" { -// ethZRC20Addr, err := smokeTest.SystemContract.GasCoinZRC20ByChainId(&bind.CallOpts{}, big.NewInt(5)) -// if err != nil { -// panic(err) -// } -// smokeTest.ETHZRC20Addr = ethZRC20Addr -// smokeTest.ETHZRC20, err = zrc20.NewZRC20(smokeTest.ETHZRC20Addr, smokeTest.zevmClient) -// if err != nil { -// panic(err) -// } -// } else { -// err := errors.New("invalid network argument: " + stressTestArgs.network) -// panic(err) -// } -// -// // Check zrc20 balance of Deployer address -// ethZRC20Balance, err := smokeTest.ETHZRC20.BalanceOf(nil, DeployerAddress) -// if err != nil { -// panic(err) -// } -// fmt.Printf("eth zrc20 balance: %s Wei \n", ethZRC20Balance.String()) -// -// //Pre-approve ETH withdraw on ZEVM -// fmt.Printf("approving ETH ZRC20...\n") -// ethZRC20 := smokeTest.ETHZRC20 -// tx, err := ethZRC20.Approve(smokeTest.zevmAuth, smokeTest.ETHZRC20Addr, big.NewInt(1e18)) -// if err != nil { -// panic(err) -// } -// receipt := MustWaitForTxReceipt(smokeTest.zevmClient, tx) -// fmt.Printf("eth zrc20 approve receipt: status %d\n", receipt.Status) -// -// // Get current nonce on zevm for DeployerAddress - Need to keep track of nonce at client level -// blockNum, err := smokeTest.zevmClient.BlockNumber(context.Background()) -// if err != nil { -// panic(err) -// } -// -// // #nosec G701 smoketest - always in range -// nonce, err := smokeTest.zevmClient.NonceAt(context.Background(), DeployerAddress, big.NewInt(int64(blockNum))) -// if err != nil { -// panic(err) -// } -// -// // #nosec G701 smoketest - always in range -// zevmNonce = big.NewInt(int64(nonce)) -// -// // -------------- TEST BEGINS ------------------ -// -// fmt.Println("**** STRESS TEST BEGINS ****") -// fmt.Println(" 1. Periodically Withdraw ETH from ZEVM to EVM - goerli") -// fmt.Println(" 2. Display Network metrics to monitor performance [Num Pending outbound tx], [Num Trackers]") -// -// smokeTest.wg.Add(2) -// go smokeTest.WithdrawCCtx() // Withdraw USDT from ZEVM to EVM - goerli -// go smokeTest.EchoNetworkMetrics() // Display Network metrics periodically to monitor performance -// -// smokeTest.wg.Wait() -//} -// -//// WithdrawCCtx withdraw USDT from ZEVM to EVM -//func (sm *SmokeTest) WithdrawCCtx() { -// ticker := time.NewTicker(time.Millisecond * time.Duration(stressTestArgs.txnInterval)) -// for { -// select { -// case <-ticker.C: -// sm.WithdrawETHZRC20() -// } -// } -//} -// -//func (sm *SmokeTest) EchoNetworkMetrics() { -// ticker := time.NewTicker(time.Second * StatInterval) -// var queue = make([]uint64, 0) -// var numTicks = 0 -// var totalMinedTxns = uint64(0) -// var previousMinedTxns = uint64(0) -// -// for { -// select { -// case <-ticker.C: -// numTicks++ -// // Get all pending outbound transactions -// cctxResp, err := sm.cctxClient.CctxListPending(context.Background(), &crosschaintypes.QueryListCctxPendingRequest{ -// ChainId: getChainID(), -// }) -// if err != nil { -// continue -// } -// sends := cctxResp.CrossChainTx -// sort.Slice(sends, func(i, j int) bool { -// return sends[i].GetCurrentOutTxParam().OutboundTxTssNonce < sends[j].GetCurrentOutTxParam().OutboundTxTssNonce -// }) -// if len(sends) > 0 { -// fmt.Printf("pending nonces %d to %d\n", sends[0].GetCurrentOutTxParam().OutboundTxTssNonce, sends[len(sends)-1].GetCurrentOutTxParam().OutboundTxTssNonce) -// } else { -// continue -// } -// // -// // Get all trackers -// trackerResp, err := sm.cctxClient.OutTxTrackerAll(context.Background(), &crosschaintypes.QueryAllOutTxTrackerRequest{}) -// if err != nil { -// continue -// } -// -// currentMinedTxns := sends[0].GetCurrentOutTxParam().OutboundTxTssNonce -// newMinedTxCnt := currentMinedTxns - previousMinedTxns -// previousMinedTxns = currentMinedTxns -// -// // Add new mined txn count to queue and remove the oldest entry -// queue = append(queue, newMinedTxCnt) -// if numTicks > 60/StatInterval { -// totalMinedTxns -= queue[0] -// queue = queue[1:] -// numTicks = 60/StatInterval + 1 //prevent overflow -// } -// -// //Calculate rate -> tx/min -// totalMinedTxns += queue[len(queue)-1] -// rate := totalMinedTxns -// -// numPending := len(cctxResp.CrossChainTx) -// numTrackers := len(trackerResp.OutTxTracker) -// -// fmt.Println("Network Stat => Num of Pending cctx: ", numPending, "Num active trackers: ", numTrackers, "Tx Rate: ", rate, " tx/min") -// } -// } -//} -// -//func (sm *SmokeTest) WithdrawETHZRC20() { -// defer func() { -// zevmNonce.Add(zevmNonce, big.NewInt(1)) -// }() -// -// ethZRC20 := sm.ETHZRC20 -// -// sm.zevmAuth.Nonce = zevmNonce -// _, err := ethZRC20.Withdraw(sm.zevmAuth, DeployerAddress.Bytes(), big.NewInt(100)) -// if err != nil { -// panic(err) -// } -//} -// -//// Get ETH based chain ID - Build flags are conflicting with current lib, need to do this manually -//func getChainID() int64 { -// switch stressTestArgs.network { -// case "PRIVNET": -// return 1337 -// case "TESTNET": -// return 5 -// case "MAINNET": -// return 1 -// default: -// return 1337 -// } -//}