From 72dc5f0723e29a9c7fa6a666fd84a7012d2c62e9 Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Mon, 24 Jun 2024 15:44:48 +0200 Subject: [PATCH 01/23] test(e2e): eliminate panic usage across testing suite (#2368) * Change runner receiver name to `r` * Remove panics from e2e runner * Remove panics from e2e tests * Remove panics from wait* helpers; minor improvements * Remove panics from "routines" * Remove panics from zetae2e cmd * Update changelog * Lint * Address PR comments [1] * Address PR comments [2] * Lint * Fix conflict --- changelog.md | 2 + cmd/zetaclientd/gen_pre_params.go | 2 +- cmd/zetae2e/local/admin.go | 12 - cmd/zetae2e/local/bitcoin.go | 13 - cmd/zetae2e/local/erc20.go | 13 - cmd/zetae2e/local/ethereum.go | 13 - cmd/zetae2e/local/local.go | 120 ++----- cmd/zetae2e/local/misc.go | 13 - cmd/zetae2e/local/performance.go | 25 -- cmd/zetae2e/local/zeta.go | 13 - cmd/zetae2e/local/zevm_mp.go | 13 - cmd/zetae2e/run.go | 22 +- cmd/zetae2e/stress.go | 125 +++---- e2e/contracts/contextapp/bindings.go | 3 +- e2e/e2etests/helpers.go | 18 +- e2e/e2etests/test_bitcoin_deposit.go | 20 +- .../test_bitcoin_withdraw_invalid_address.go | 42 +-- e2e/e2etests/test_bitcoin_withdraw_legacy.go | 12 +- e2e/e2etests/test_bitcoin_withdraw_p2sh.go | 10 +- e2e/e2etests/test_bitcoin_withdraw_p2wsh.go | 11 +- ...est_bitcoin_withdraw_restricted_address.go | 28 +- e2e/e2etests/test_bitcoin_withdraw_segwit.go | 11 +- e2e/e2etests/test_bitcoin_withdraw_taproot.go | 12 +- e2e/e2etests/test_context_upgrade.go | 39 +-- e2e/e2etests/test_crosschain_swap.go | 137 +++----- e2e/e2etests/test_deploy_contract.go | 17 +- e2e/e2etests/test_donation.go | 19 +- e2e/e2etests/test_erc20_deposit.go | 10 +- e2e/e2etests/test_erc20_deposit_refund.go | 120 +++---- .../test_erc20_deposit_restricted_address.go | 9 +- e2e/e2etests/test_erc20_multiple_deposits.go | 55 +--- e2e/e2etests/test_erc20_multiple_withdraws.go | 72 ++-- e2e/e2etests/test_erc20_withdraw.go | 26 +- e2e/e2etests/test_eth_deposit.go | 10 +- e2e/e2etests/test_eth_deposit_call.go | 111 +++---- .../test_eth_deposit_liquidity_cap.go | 105 +++--- e2e/e2etests/test_eth_deposit_refund.go | 127 +++---- e2e/e2etests/test_eth_withdraw.go | 41 +-- .../test_eth_withdraw_restricted_address.go | 46 ++- .../test_message_passing_evm_to_zevm.go | 82 ++--- ...test_message_passing_evm_to_zevm_revert.go | 99 +++--- ...message_passing_evm_to_zevm_revert_fail.go | 85 ++--- .../test_message_passing_external_chains.go | 61 ++-- ..._message_passing_external_chains_revert.go | 60 ++-- ...age_passing_external_chains_revert_fail.go | 50 ++- .../test_message_passing_zevm_to_evm.go | 112 +++---- ...test_message_passing_zevm_to_evm_revert.go | 102 ++---- ...message_passing_zevm_to_evm_revert_fail.go | 73 ++--- e2e/e2etests/test_migrate_chain_support.go | 87 ++--- e2e/e2etests/test_pause_zrc20.go | 148 ++++----- e2e/e2etests/test_rate_limiter.go | 33 +- e2e/e2etests/test_stress_btc_deposit.go | 26 +- e2e/e2etests/test_stress_btc_withdraw.go | 42 +-- e2e/e2etests/test_stress_eth_deposit.go | 24 +- e2e/e2etests/test_stress_eth_withdraw.go | 38 +-- .../test_update_bytecode_connector.go | 51 +-- e2e/e2etests/test_update_bytecode_zrc20.go | 179 ++++------ e2e/e2etests/test_zeta_deposit.go | 10 +- e2e/e2etests/test_zeta_deposit_new_address.go | 10 +- .../test_zeta_deposit_restricted_address.go | 9 +- e2e/e2etests/test_zeta_withdraw.go | 20 +- .../test_zeta_withdraw_bitcoin_revert.go | 38 +-- e2e/e2etests/test_zrc20_swap.go | 40 +-- e2e/runner/accounting.go | 44 +-- e2e/runner/balances.go | 70 ++-- e2e/runner/bitcoin.go | 310 +++++++----------- e2e/runner/e2etest.go | 6 +- e2e/runner/evm.go | 232 ++++++------- e2e/runner/report.go | 26 +- e2e/runner/run.go | 39 +-- e2e/runner/runner.go | 134 ++++---- e2e/runner/setup_bitcoin.go | 71 ++-- e2e/runner/setup_evm.go | 201 +++++------- e2e/runner/setup_zeta.go | 227 ++++++------- e2e/runner/zeta.go | 258 ++++++--------- e2e/utils/evm.go | 16 +- e2e/utils/require.go | 47 +++ e2e/utils/utils.go | 19 ++ e2e/utils/zetacore.go | 97 +++--- testutil/helpers.go | 38 +++ 80 files changed, 1831 insertions(+), 2980 deletions(-) create mode 100644 e2e/utils/require.go create mode 100644 testutil/helpers.go diff --git a/changelog.md b/changelog.md index ba3c0ed790..bf1a778f93 100644 --- a/changelog.md +++ b/changelog.md @@ -66,8 +66,10 @@ * [2299](https://github.com/zeta-chain/node/pull/2299) - add `zetae2e` command to deploy test contracts * [2360](https://github.com/zeta-chain/node/pull/2360) - add stateful e2e tests. * [2349](https://github.com/zeta-chain/node/pull/2349) - add TestBitcoinDepositRefund and WithdrawBitcoinMultipleTimes E2E tests +* [2368](https://github.com/zeta-chain/node/pull/2368) - eliminate panic usage across testing suite * [2369](https://github.com/zeta-chain/node/pull/2369) - fix random cross-chain swap failure caused by using tiny UTXO + ### Fixes * [1484](https://github.com/zeta-chain/node/issues/1484) - replaced hard-coded `MaxLookaheadNonce` with a default lookback factor diff --git a/cmd/zetaclientd/gen_pre_params.go b/cmd/zetaclientd/gen_pre_params.go index c797a9f206..7837867b74 100644 --- a/cmd/zetaclientd/gen_pre_params.go +++ b/cmd/zetaclientd/gen_pre_params.go @@ -18,7 +18,7 @@ var GenPrePramsCmd = &cobra.Command{ Use: "gen-pre-params ", Short: "Generate pre parameters for TSS", Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, args []string) error { startTime := time.Now() preParams, err := keygen.GeneratePreParams(time.Second * 300) if err != nil { diff --git a/cmd/zetae2e/local/admin.go b/cmd/zetae2e/local/admin.go index 1ac4cb6b60..63cff6fe23 100644 --- a/cmd/zetae2e/local/admin.go +++ b/cmd/zetae2e/local/admin.go @@ -2,7 +2,6 @@ package local import ( "fmt" - "runtime" "time" "github.com/fatih/color" @@ -20,17 +19,6 @@ func adminTestRoutine( testNames ...string, ) func() error { return func() (err error) { - // return an error on panic - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("admin panic: %v, stack trace %s", r, stack[:n]) - } - }() - // initialize runner for erc20 advanced test adminRunner, err := initTestRunner( "admin", diff --git a/cmd/zetae2e/local/bitcoin.go b/cmd/zetae2e/local/bitcoin.go index d0f4d8bb12..cfb0501a8c 100644 --- a/cmd/zetae2e/local/bitcoin.go +++ b/cmd/zetae2e/local/bitcoin.go @@ -2,7 +2,6 @@ package local import ( "fmt" - "runtime" "time" "github.com/fatih/color" @@ -22,18 +21,6 @@ func bitcoinTestRoutine( testNames ...string, ) func() error { return func() (err error) { - // return an error on panic - // TODO: remove and instead return errors in the tests - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("bitcoin panic: %v, stack trace %s", r, stack[:n]) - } - }() - // initialize runner for bitcoin test bitcoinRunner, err := initTestRunner( "bitcoin", diff --git a/cmd/zetae2e/local/erc20.go b/cmd/zetae2e/local/erc20.go index b7fd74f0d8..fe0fa8bb8a 100644 --- a/cmd/zetae2e/local/erc20.go +++ b/cmd/zetae2e/local/erc20.go @@ -2,7 +2,6 @@ package local import ( "fmt" - "runtime" "time" "github.com/fatih/color" @@ -20,18 +19,6 @@ func erc20TestRoutine( testNames ...string, ) func() error { return func() (err error) { - // return an error on panic - // TODO: remove and instead return errors in the tests - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("erc20 panic: %v, stack trace %s", r, stack[:n]) - } - }() - // initialize runner for erc20 test erc20Runner, err := initTestRunner( "erc20", diff --git a/cmd/zetae2e/local/ethereum.go b/cmd/zetae2e/local/ethereum.go index efb37f1fa1..fa9e7754e2 100644 --- a/cmd/zetae2e/local/ethereum.go +++ b/cmd/zetae2e/local/ethereum.go @@ -2,7 +2,6 @@ package local import ( "fmt" - "runtime" "time" "github.com/fatih/color" @@ -21,18 +20,6 @@ func ethereumTestRoutine( testNames ...string, ) func() error { return func() (err error) { - // return an error on panic - // TODO: remove and instead return errors in the tests - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("ethereum panic: %v, stack trace %s", r, stack[:n]) - } - }() - // initialize runner for ether test ethereumRunner, err := initTestRunner( "ether", diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 364bdf80a4..bd9dd654a2 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -2,7 +2,6 @@ package local import ( "context" - "fmt" "os" "path/filepath" "time" @@ -18,6 +17,7 @@ import ( "github.com/zeta-chain/zetacore/e2e/txserver" "github.com/zeta-chain/zetacore/e2e/utils" "github.com/zeta-chain/zetacore/pkg/chains" + "github.com/zeta-chain/zetacore/testutil" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -42,6 +42,8 @@ var ( TestTimeout = 15 * time.Minute ) +var noError = testutil.NoError + // NewLocalCmd returns the local command // which runs the E2E tests locally on the machine with localnet for each blockchain func NewLocalCmd() *cobra.Command { @@ -70,58 +72,21 @@ func NewLocalCmd() *cobra.Command { func localE2ETest(cmd *cobra.Command, _ []string) { // fetch flags - waitForHeight, err := cmd.Flags().GetInt64(flagWaitForHeight) - if err != nil { - panic(err) - } - contractsDeployed, err := cmd.Flags().GetBool(flagContractsDeployed) - if err != nil { - panic(err) - } - verbose, err := cmd.Flags().GetBool(flagVerbose) - if err != nil { - panic(err) - } - configOut, err := cmd.Flags().GetString(flagConfigOut) - if err != nil { - panic(err) - } - testAdmin, err := cmd.Flags().GetBool(flagTestAdmin) - if err != nil { - panic(err) - } - testPerformance, err := cmd.Flags().GetBool(flagTestPerformance) - if err != nil { - panic(err) - } - testCustom, err := cmd.Flags().GetBool(flagTestCustom) - if err != nil { - panic(err) - } - skipRegular, err := cmd.Flags().GetBool(flagSkipRegular) - if err != nil { - panic(err) - } - light, err := cmd.Flags().GetBool(flagLight) - if err != nil { - panic(err) - } - setupOnly, err := cmd.Flags().GetBool(flagSetupOnly) - if err != nil { - panic(err) - } - skipSetup, err := cmd.Flags().GetBool(flagSkipSetup) - if err != nil { - panic(err) - } - skipBitcoinSetup, err := cmd.Flags().GetBool(flagSkipBitcoinSetup) - if err != nil { - panic(err) - } - skipHeaderProof, err := cmd.Flags().GetBool(flagSkipHeaderProof) - if err != nil { - panic(err) - } + var ( + waitForHeight = must(cmd.Flags().GetInt64(flagWaitForHeight)) + contractsDeployed = must(cmd.Flags().GetBool(flagContractsDeployed)) + verbose = must(cmd.Flags().GetBool(flagVerbose)) + configOut = must(cmd.Flags().GetString(flagConfigOut)) + testAdmin = must(cmd.Flags().GetBool(flagTestAdmin)) + testPerformance = must(cmd.Flags().GetBool(flagTestPerformance)) + testCustom = must(cmd.Flags().GetBool(flagTestCustom)) + skipRegular = must(cmd.Flags().GetBool(flagSkipRegular)) + light = must(cmd.Flags().GetBool(flagLight)) + setupOnly = must(cmd.Flags().GetBool(flagSetupOnly)) + skipSetup = must(cmd.Flags().GetBool(flagSkipSetup)) + skipBitcoinSetup = must(cmd.Flags().GetBool(flagSkipBitcoinSetup)) + skipHeaderProof = must(cmd.Flags().GetBool(flagSkipHeaderProof)) + ) logger := runner.NewLogger(verbose, color.FgWhite, "setup") @@ -146,16 +111,14 @@ func localE2ETest(cmd *cobra.Command, _ []string) { // initialize tests config conf, err := GetConfig(cmd) - if err != nil { - panic(err) - } + noError(err) // initialize context ctx, cancel := context.WithCancel(context.Background()) // wait for a specific height on ZetaChain if waitForHeight != 0 { - utils.WaitForBlockHeight(ctx, waitForHeight, conf.RPCs.ZetaCoreRPC, logger) + noError(utils.WaitForBlockHeight(ctx, waitForHeight, conf.RPCs.ZetaCoreRPC, logger)) } // set account prefix to zeta @@ -167,9 +130,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { []string{UserFungibleAdminPrivateKey}, conf.ZetaChainID, ) - if err != nil { - panic(fmt.Errorf("failed to initialize ZetaChain tx server: %w", err)) - } + noError(err) // initialize deployer runner with config deployerRunner, err := zetae2econfig.RunnerFromConfig( @@ -182,9 +143,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { logger, runner.WithZetaTxServer(zetaTxServer), ) - if err != nil { - panic(err) - } + noError(err) // wait for keygen to be completed // if setup is skipped, we assume that the keygen is already completed @@ -193,16 +152,13 @@ func localE2ETest(cmd *cobra.Command, _ []string) { } // query and set the TSS - if err := deployerRunner.SetTSSAddresses(); err != nil { - panic(err) - } + noError(deployerRunner.SetTSSAddresses()) if !skipHeaderProof { - if err := deployerRunner.EnableHeaderVerification([]int64{ + noError(deployerRunner.EnableHeaderVerification([]int64{ chains.GoerliLocalnet.ChainId, - chains.BitcoinRegtest.ChainId}); err != nil { - panic(err) - } + chains.BitcoinRegtest.ChainId, + })) } // setting up the networks @@ -212,30 +168,22 @@ func localE2ETest(cmd *cobra.Command, _ []string) { deployerRunner.SetupEVM(contractsDeployed, true) deployerRunner.SetZEVMContracts() - - // NOTE: this method return an error so we handle it and panic if it occurs unlike other method that panics directly - // TODO: all methods should return errors instead of panicking and this current function should also return an error - // https://github.com/zeta-chain/node/issues/1500 - if err := deployerRunner.FundEmissionsPool(); err != nil { - panic(err) - } + noError(deployerRunner.FundEmissionsPool()) deployerRunner.MintERC20OnEvm(10000) logger.Print("✅ setup completed in %s", time.Since(startTime)) } + // if a config output is specified, write the config if configOut != "" { newConfig := zetae2econfig.ExportContractsFromRunner(deployerRunner, conf) - configOut, err := filepath.Abs(configOut) - if err != nil { - panic(err) - } // write config into stdout - if err := config.WriteConfig(configOut, newConfig); err != nil { - panic(err) - } + configOut, err := filepath.Abs(configOut) + noError(err) + + noError(config.WriteConfig(configOut, newConfig)) logger.Print("✅ config file written in %s", configOut) } @@ -407,3 +355,7 @@ func waitKeygenHeight( logger.Info("Last ZetaHeight: %d", response.Height) } } + +func must[T any](v T, err error) T { + return testutil.Must(v, err) +} diff --git a/cmd/zetae2e/local/misc.go b/cmd/zetae2e/local/misc.go index 081905b5ee..65467ec9e5 100644 --- a/cmd/zetae2e/local/misc.go +++ b/cmd/zetae2e/local/misc.go @@ -2,7 +2,6 @@ package local import ( "fmt" - "runtime" "time" "github.com/fatih/color" @@ -20,18 +19,6 @@ func miscTestRoutine( testNames ...string, ) func() error { return func() (err error) { - // return an error on panic - // TODO: remove and instead return errors in the tests - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("misc panic: %v, stack trace %s", r, stack[:n]) - } - }() - // initialize runner for misc test miscRunner, err := initTestRunner( "misc", diff --git a/cmd/zetae2e/local/performance.go b/cmd/zetae2e/local/performance.go index 4b83d66307..7d289c4e90 100644 --- a/cmd/zetae2e/local/performance.go +++ b/cmd/zetae2e/local/performance.go @@ -5,7 +5,6 @@ package local import ( "fmt" - "runtime" "time" "github.com/fatih/color" @@ -23,18 +22,6 @@ func ethereumDepositPerformanceRoutine( testNames ...string, ) func() error { return func() (err error) { - // return an error on panic - // TODO: remove and instead return errors in the tests - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("ethereum deposit perf panic: %v, stack trace %s", r, stack[:n]) - } - }() - // initialize runner for ether test r, err := initTestRunner( "ether", @@ -77,18 +64,6 @@ func ethereumWithdrawPerformanceRoutine( testNames ...string, ) func() error { return func() (err error) { - // return an error on panic - // TODO: remove and instead return errors in the tests - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("ethereum withdraw perf panic: %v, stack trace %s", r, stack[:n]) - } - }() - // initialize runner for ether test r, err := initTestRunner( "ether", diff --git a/cmd/zetae2e/local/zeta.go b/cmd/zetae2e/local/zeta.go index 1f95c5f6d6..6f5039b63f 100644 --- a/cmd/zetae2e/local/zeta.go +++ b/cmd/zetae2e/local/zeta.go @@ -2,7 +2,6 @@ package local import ( "fmt" - "runtime" "time" "github.com/fatih/color" @@ -20,18 +19,6 @@ func zetaTestRoutine( testNames ...string, ) func() error { return func() (err error) { - // return an error on panic - // TODO: remove and instead return errors in the tests - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("zeta panic: %v, stack trace %s", r, stack[:n]) - } - }() - // initialize runner for zeta test zetaRunner, err := initTestRunner( "zeta", diff --git a/cmd/zetae2e/local/zevm_mp.go b/cmd/zetae2e/local/zevm_mp.go index 969dcfda64..f95fa24390 100644 --- a/cmd/zetae2e/local/zevm_mp.go +++ b/cmd/zetae2e/local/zevm_mp.go @@ -2,7 +2,6 @@ package local import ( "fmt" - "runtime" "time" "github.com/fatih/color" @@ -20,18 +19,6 @@ func zevmMPTestRoutine( testNames ...string, ) func() error { return func() (err error) { - // return an error on panic - // TODO: remove and instead return errors in the tests - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("zevm mp panic: %v, stack trace %s", r, stack[:n]) - } - }() - // initialize runner for zevm mp test zevmMPRunner, err := initTestRunner( "zevm_mp", diff --git a/cmd/zetae2e/run.go b/cmd/zetae2e/run.go index 5ed6babf6b..7d57500823 100644 --- a/cmd/zetae2e/run.go +++ b/cmd/zetae2e/run.go @@ -3,6 +3,8 @@ package main import ( "context" "errors" + "fmt" + "os" "strings" "time" @@ -35,17 +37,13 @@ For example: zetae2e run deposit:1000 withdraw: --config config.yml`, } cmd.Flags().StringVarP(&configFile, flagConfig, "c", "", "path to the configuration file") - err := cmd.MarkFlagRequired(flagConfig) - if err != nil { - panic(err) + if err := cmd.MarkFlagRequired(flagConfig); err != nil { + fmt.Println("Error marking flag as required") + os.Exit(1) } // Retain the verbose flag - cmd.Flags().Bool( - flagVerbose, - false, - "set to true to enable verbose logging", - ) + cmd.Flags().Bool(flagVerbose, false, "set to true to enable verbose logging") return cmd } @@ -75,11 +73,11 @@ func runE2ETest(cmd *cobra.Command, args []string) error { // initialize context ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // get EVM address from config evmAddr := conf.Accounts.EVMAddress if !ethcommon.IsHexAddress(evmAddr) { - cancel() return errors.New("invalid EVM address") } @@ -94,7 +92,6 @@ func runE2ETest(cmd *cobra.Command, args []string) error { logger, ) if err != nil { - cancel() return err } @@ -112,31 +109,26 @@ func runE2ETest(cmd *cobra.Command, args []string) error { balancesBefore, err := testRunner.GetAccountBalances(true) if err != nil { - cancel() return err } // parse test names and arguments from cmd args and run them userTestsConfigs, err := parseCmdArgsToE2ETestRunConfig(args) if err != nil { - cancel() return err } testsToRun, err := testRunner.GetE2ETestsToRunByConfig(e2etests.AllE2ETests, userTestsConfigs) if err != nil { - cancel() return err } reports, err := testRunner.RunE2ETestsIntoReport(testsToRun) if err != nil { - cancel() return err } balancesAfter, err := testRunner.GetAccountBalances(true) if err != nil { - cancel() return err } diff --git a/cmd/zetae2e/stress.go b/cmd/zetae2e/stress.go index 472b01fc50..ca0446cbc9 100644 --- a/cmd/zetae2e/stress.go +++ b/cmd/zetae2e/stress.go @@ -24,6 +24,7 @@ import ( "github.com/zeta-chain/zetacore/cmd/zetae2e/local" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" + "github.com/zeta-chain/zetacore/testutil" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -47,6 +48,8 @@ type stressArguments struct { var stressTestArgs = stressArguments{} +var noError = testutil.NoError + func NewStressTestCmd() *cobra.Command { var StressCmd = &cobra.Command{ Use: "stress", @@ -88,27 +91,15 @@ func StressTest(cmd *cobra.Command, _ []string) { cosmosConf.Seal() // initialize E2E tests config - conf, err := local.GetConfig(cmd) - if err != nil { - panic(err) - } + conf := must(local.GetConfig(cmd)) // Initialize clients ---------------------------------------------------------------- - evmClient, err := ethclient.Dial(conf.RPCs.EVM) - if err != nil { - panic(err) - } + evmClient := must(ethclient.Dial(conf.RPCs.EVM)) + bal := must(evmClient.BalanceAt(context.TODO(), local.DeployerAddress, nil)) - bal, err := evmClient.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) - } + grpcConn := must(grpc.Dial(conf.RPCs.ZetaCoreGRPC, grpc.WithInsecure())) cctxClient := crosschaintypes.NewQueryClient(grpcConn) // ----------------------------------------------------------------------------------- @@ -136,14 +127,11 @@ func StressTest(cmd *cobra.Command, _ []string) { // initialize context ctx, cancel := context.WithCancel(context.Background()) - verbose, err := cmd.Flags().GetBool(flagVerbose) - if err != nil { - panic(err) - } + verbose := must(cmd.Flags().GetBool(flagVerbose)) logger := runner.NewLogger(verbose, color.FgWhite, "setup") // initialize E2E test runner - e2eTest, err := zetae2econfig.RunnerFromConfig( + e2eTest := must(zetae2econfig.RunnerFromConfig( ctx, "deployer", cancel, @@ -151,69 +139,47 @@ func StressTest(cmd *cobra.Command, _ []string) { local.DeployerAddress, local.DeployerPrivateKey, logger, - ) - if err != nil { - panic(err) - } + )) // setup TSS addresses - if err := e2eTest.SetTSSAddresses(); err != nil { - panic(err) - } - + noError(e2eTest.SetTSSAddresses()) e2eTest.SetupEVM(stressTestArgs.contractsDeployed, true) // If stress test is running on local docker environment - if stressTestArgs.network == "LOCAL" { + switch stressTestArgs.network { + case "LOCAL": // deploy and set zevm contract e2eTest.SetZEVMContracts() // deposit on ZetaChain e2eTest.DepositEther(false) e2eTest.DepositZeta() - } else if stressTestArgs.network == "TESTNET" { - ethZRC20Addr, err := e2eTest.SystemContract.GasCoinZRC20ByChainId(&bind.CallOpts{}, big.NewInt(5)) - if err != nil { - panic(err) - } + case "TESTNET": + ethZRC20Addr := must(e2eTest.SystemContract.GasCoinZRC20ByChainId(&bind.CallOpts{}, big.NewInt(5))) e2eTest.ETHZRC20Addr = ethZRC20Addr - e2eTest.ETHZRC20, err = zrc20.NewZRC20(e2eTest.ETHZRC20Addr, e2eTest.ZEVMClient) - if err != nil { - panic(err) - } - } else { - err := errors.New("invalid network argument: " + stressTestArgs.network) - panic(err) + + e2eTest.ETHZRC20 = must(zrc20.NewZRC20(e2eTest.ETHZRC20Addr, e2eTest.ZEVMClient)) + default: + noError(errors.New("invalid network argument: " + stressTestArgs.network)) } // Check zrc20 balance of Deployer address - ethZRC20Balance, err := e2eTest.ETHZRC20.BalanceOf(nil, local.DeployerAddress) - if err != nil { - panic(err) - } + ethZRC20Balance := must(e2eTest.ETHZRC20.BalanceOf(nil, local.DeployerAddress)) fmt.Printf("eth zrc20 balance: %s Wei \n", ethZRC20Balance.String()) //Pre-approve ETH withdraw on ZEVM - fmt.Printf("approving ETH ZRC20...\n") + fmt.Println("approving ETH ZRC20...") ethZRC20 := e2eTest.ETHZRC20 - tx, err := ethZRC20.Approve(e2eTest.ZEVMAuth, e2eTest.ETHZRC20Addr, big.NewInt(1e18)) - if err != nil { - panic(err) - } - receipt := utils.MustWaitForTxReceipt(ctx, e2eTest.ZEVMClient, tx, logger, e2eTest.ReceiptTimeout) + tx := must(ethZRC20.Approve(e2eTest.ZEVMAuth, e2eTest.ETHZRC20Addr, big.NewInt(1e18))) + + receipt := utils.MustWaitForTxReceipt(e2eTest.Ctx, e2eTest.ZEVMClient, tx, logger, e2eTest.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 := e2eTest.ZEVMClient.BlockNumber(context.Background()) - if err != nil { - panic(err) - } + blockNum := must(e2eTest.ZEVMClient.BlockNumber(ctx)) // #nosec G701 e2eTest - always in range - nonce, err := e2eTest.ZEVMClient.NonceAt(context.Background(), local.DeployerAddress, big.NewInt(int64(blockNum))) - if err != nil { - panic(err) - } + nonce := must(e2eTest.ZEVMClient.NonceAt(ctx, local.DeployerAddress, big.NewInt(int64(blockNum)))) // #nosec G701 e2e - always in range zevmNonce = big.NewInt(int64(nonce)) @@ -256,24 +222,22 @@ func WithdrawCCtx(runner *runner.E2ERunner) { } } -func EchoNetworkMetrics(runner *runner.E2ERunner) { - 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(runner.EVMClient) - - if err != nil { - panic(err) - } +func EchoNetworkMetrics(r *runner.E2ERunner) { + var ( + ticker = time.NewTicker(time.Second * StatInterval) + queue = make([]uint64, 0) + numTicks int + totalMinedTxns uint64 + previousMinedTxns uint64 + chainID = must(getChainID(r.EVMClient)) + ) for { select { case <-ticker.C: numTicks++ // Get all pending outbound transactions - cctxResp, err := runner.CctxClient.ListPendingCctx( + cctxResp, err := r.CctxClient.ListPendingCctx( context.Background(), &crosschaintypes.QueryListPendingCctxRequest{ ChainId: chainID.Int64(), @@ -297,7 +261,7 @@ func EchoNetworkMetrics(runner *runner.E2ERunner) { } // // Get all trackers - trackerResp, err := runner.CctxClient.OutboundTrackerAll( + trackerResp, err := r.CctxClient.OutboundTrackerAll( context.Background(), &crosschaintypes.QueryAllOutboundTrackerRequest{}, ) @@ -337,21 +301,22 @@ func EchoNetworkMetrics(runner *runner.E2ERunner) { } } -func WithdrawETHZRC20(runner *runner.E2ERunner) { +func WithdrawETHZRC20(r *runner.E2ERunner) { defer func() { zevmNonce.Add(zevmNonce, big.NewInt(1)) }() - ethZRC20 := runner.ETHZRC20 + ethZRC20 := r.ETHZRC20 + r.ZEVMAuth.Nonce = zevmNonce - runner.ZEVMAuth.Nonce = zevmNonce - _, err := ethZRC20.Withdraw(runner.ZEVMAuth, local.DeployerAddress.Bytes(), big.NewInt(100)) - if err != nil { - panic(err) - } + must(ethZRC20.Withdraw(r.ZEVMAuth, local.DeployerAddress.Bytes(), big.NewInt(100))) } // Get ETH based chain ID func getChainID(client *ethclient.Client) (*big.Int, error) { return client.ChainID(context.Background()) } + +func must[T any](v T, err error) T { + return testutil.Must(v, err) +} diff --git a/e2e/contracts/contextapp/bindings.go b/e2e/contracts/contextapp/bindings.go index e3246d6be5..6b077d4020 100644 --- a/e2e/contracts/contextapp/bindings.go +++ b/e2e/contracts/contextapp/bindings.go @@ -28,8 +28,7 @@ var ( ) func init() { - err := json.Unmarshal(ContextAppJSON, &ContextAppContract) - if err != nil { + if err := json.Unmarshal(ContextAppJSON, &ContextAppContract); err != nil { panic(err) } diff --git a/e2e/e2etests/helpers.go b/e2e/e2etests/helpers.go index 5980679b63..4dc37498d9 100644 --- a/e2e/e2etests/helpers.go +++ b/e2e/e2etests/helpers.go @@ -8,7 +8,6 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcutil" ethcommon "github.com/ethereum/go-ethereum/common" - ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" @@ -26,7 +25,7 @@ func withdrawBTCZRC20(r *runner.E2ERunner, to btcutil.Address, amount *big.Int) require.NoError(r, err) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - requireReceiptApproved(r, receipt) + utils.RequireTxSuccessful(r, receipt) // mine blocks if testing on regnet stop := r.MineBlocksIfLocalBitcoin() @@ -37,7 +36,7 @@ func withdrawBTCZRC20(r *runner.E2ERunner, to btcutil.Address, amount *big.Int) require.NoError(r, err) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - requireReceiptApproved(r, receipt) + utils.RequireTxSuccessful(r, receipt) // mine 10 blocks to confirm the withdrawal tx _, err = r.GenerateToAddressIfLocalBitcoin(10, to) @@ -45,7 +44,7 @@ func withdrawBTCZRC20(r *runner.E2ERunner, to btcutil.Address, amount *big.Int) // get cctx and check status cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - requireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) + utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) // get bitcoin tx according to the outTxHash in cctx outTxHash := cctx.GetCurrentOutboundParam().Hash @@ -134,14 +133,3 @@ func parseBitcoinWithdrawArgs(r *runner.E2ERunner, args []string, defaultReceive return receiver, amount } - -// Testify aliases ==========================================> - -func requireReceiptApproved(t require.TestingT, receipt *ethtypes.Receipt) { - require.Equal(t, ethtypes.ReceiptStatusSuccessful, receipt.Status, "receipt status is not successful") -} - -func requireCCTXStatus(t require.TestingT, cctx *crosschaintypes.CrossChainTx, expected crosschaintypes.CctxStatus) { - require.NotNil(t, cctx.CctxStatus) - require.Equal(t, expected, cctx.CctxStatus.Status, "cctx status is not %q", expected.String()) -} diff --git a/e2e/e2etests/test_bitcoin_deposit.go b/e2e/e2etests/test_bitcoin_deposit.go index 6c70f226f4..48460c42be 100644 --- a/e2e/e2etests/test_bitcoin_deposit.go +++ b/e2e/e2etests/test_bitcoin_deposit.go @@ -1,8 +1,7 @@ package e2etests import ( - "fmt" - "strconv" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -10,14 +9,9 @@ import ( ) func TestBitcoinDeposit(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestBitcoinDeposit requires exactly one argument for the amount.") - } + require.Len(r, args, 1) - depositAmount, err := strconv.ParseFloat(args[0], 64) - if err != nil { - panic("Invalid deposit amount specified for TestBitcoinDeposit.") - } + depositAmount := parseFloat(r, args[0]) r.SetBtcAddress(r.Name, false) @@ -26,11 +20,5 @@ func TestBitcoinDeposit(r *runner.E2ERunner, args []string) { // wait for the cctx to be mined cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "deposit") - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { - panic(fmt.Sprintf( - "expected mined status; got %s, message: %s", - cctx.CctxStatus.Status.String(), - cctx.CctxStatus.StatusMessage), - ) - } + utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) } diff --git a/e2e/e2etests/test_bitcoin_withdraw_invalid_address.go b/e2e/e2etests/test_bitcoin_withdraw_invalid_address.go index aaa0725a99..00a9ecb5fe 100644 --- a/e2e/e2etests/test_bitcoin_withdraw_invalid_address.go +++ b/e2e/e2etests/test_bitcoin_withdraw_invalid_address.go @@ -1,31 +1,19 @@ package e2etests import ( - "fmt" "math/big" - "strconv" - "github.com/btcsuite/btcutil" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" ) func TestBitcoinWithdrawToInvalidAddress(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestBitcoinWithdrawToInvalidAddress requires exactly one argument for the amount.") - } + require.Len(r, args, 1) - withdrawalAmount, err := strconv.ParseFloat(args[0], 64) - if err != nil { - panic("Invalid withdrawal amount specified for TestBitcoinWithdrawToInvalidAddress.") - } - - withdrawalAmountSat, err := btcutil.NewAmount(withdrawalAmount) - if err != nil { - panic(err) - } - amount := big.NewInt(int64(withdrawalAmountSat)) + withdrawalAmount := parseFloat(r, args[0]) + amount := btcAmountFromFloat64(r, withdrawalAmount) r.SetBtcAddress(r.Name, false) @@ -37,28 +25,20 @@ func withdrawToInvalidAddress(r *runner.E2ERunner, amount *big.Int) { // approve the ZRC20 contract to spend approvalAmount BTC from the deployer address. // the actual amount transferred is provided as test arg BTC, but we approve more to cover withdraw fee tx, err := r.BTCZRC20.Approve(r.ZEVMAuth, r.BTCZRC20Addr, big.NewInt(int64(approvalAmount))) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic(fmt.Errorf("approve receipt status is not 1")) - } + utils.RequireTxSuccessful(r, receipt) // mine blocks if testing on regnet stop := r.MineBlocksIfLocalBitcoin() + defer stop() // withdraw amount provided as test arg BTC from ZRC20 to BTC legacy address // the address "1EYVvXLusCxtVuEwoYvWRyN5EZTXwPVvo3" is for mainnet, not regtest tx, err = r.BTCZRC20.Withdraw(r.ZEVMAuth, []byte("1EYVvXLusCxtVuEwoYvWRyN5EZTXwPVvo3"), amount) - if err != nil { - panic(err) - } - receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 1 { - panic(fmt.Errorf("withdraw receipt status is successful for an invalid BTC address")) - } + require.NoError(r, err) - // stop mining - stop() + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequiredTxFailed(r, receipt) } diff --git a/e2e/e2etests/test_bitcoin_withdraw_legacy.go b/e2e/e2etests/test_bitcoin_withdraw_legacy.go index fc2f7b2ca7..57b96034dc 100644 --- a/e2e/e2etests/test_bitcoin_withdraw_legacy.go +++ b/e2e/e2etests/test_bitcoin_withdraw_legacy.go @@ -2,24 +2,22 @@ package e2etests import ( "github.com/btcsuite/btcutil" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" ) func TestBitcoinWithdrawLegacy(r *runner.E2ERunner, args []string) { // check length of arguments - if len(args) != 2 { - panic("TestBitcoinWithdrawLegacy requires two arguments: [receiver, amount]") - } + require.Len(r, args, 2) + r.SetBtcAddress(r.Name, false) // parse arguments and withdraw BTC - defaultReceiver := "mxpYha3UJKUgSwsAz2qYRqaDSwAkKZ3YEY" receiver, amount := parseBitcoinWithdrawArgs(r, args, defaultReceiver) + _, ok := receiver.(*btcutil.AddressPubKeyHash) - if !ok { - panic("Invalid receiver address specified for TestBitcoinWithdrawLegacy.") - } + require.True(r, ok, "Invalid receiver address specified for TestBitcoinWithdrawLegacy.") withdrawBTCZRC20(r, receiver, amount) } diff --git a/e2e/e2etests/test_bitcoin_withdraw_p2sh.go b/e2e/e2etests/test_bitcoin_withdraw_p2sh.go index 97de7675ca..c63a2d2c6b 100644 --- a/e2e/e2etests/test_bitcoin_withdraw_p2sh.go +++ b/e2e/e2etests/test_bitcoin_withdraw_p2sh.go @@ -2,24 +2,22 @@ package e2etests import ( "github.com/btcsuite/btcutil" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" ) func TestBitcoinWithdrawP2SH(r *runner.E2ERunner, args []string) { // check length of arguments - if len(args) != 2 { - panic("TestBitcoinWithdrawP2SH requires two arguments: [receiver, amount]") - } + require.Len(r, args, 2) + r.SetBtcAddress(r.Name, false) // parse arguments and withdraw BTC defaultReceiver := "2N6AoUj3KPS7wNGZXuCckh8YEWcSYNsGbqd" receiver, amount := parseBitcoinWithdrawArgs(r, args, defaultReceiver) _, ok := receiver.(*btcutil.AddressScriptHash) - if !ok { - panic("Invalid receiver address specified for TestBitcoinWithdrawP2SH.") - } + require.True(r, ok, "Invalid receiver address specified for TestBitcoinWithdrawP2SH.") withdrawBTCZRC20(r, receiver, amount) } diff --git a/e2e/e2etests/test_bitcoin_withdraw_p2wsh.go b/e2e/e2etests/test_bitcoin_withdraw_p2wsh.go index 79943dc948..5748e0b671 100644 --- a/e2e/e2etests/test_bitcoin_withdraw_p2wsh.go +++ b/e2e/e2etests/test_bitcoin_withdraw_p2wsh.go @@ -2,24 +2,21 @@ package e2etests import ( "github.com/btcsuite/btcutil" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" ) func TestBitcoinWithdrawP2WSH(r *runner.E2ERunner, args []string) { - // check length of arguments - if len(args) != 2 { - panic("TestBitcoinWithdrawP2WSH requires two arguments: [receiver, amount]") - } + require.Len(r, args, 2) + r.SetBtcAddress(r.Name, false) // parse arguments and withdraw BTC defaultReceiver := "bcrt1qm9mzhyky4w853ft2ms6dtqdyyu3z2tmrq8jg8xglhyuv0dsxzmgs2f0sqy" receiver, amount := parseBitcoinWithdrawArgs(r, args, defaultReceiver) _, ok := receiver.(*btcutil.AddressWitnessScriptHash) - if !ok { - panic("Invalid receiver address specified for TestBitcoinWithdrawP2WSH.") - } + require.True(r, ok, "Invalid receiver address specified for TestBitcoinWithdrawP2WSH.") withdrawBTCZRC20(r, receiver, amount) } diff --git a/e2e/e2etests/test_bitcoin_withdraw_restricted_address.go b/e2e/e2etests/test_bitcoin_withdraw_restricted_address.go index 918a4fe6e3..96cdc9ed0a 100644 --- a/e2e/e2etests/test_bitcoin_withdraw_restricted_address.go +++ b/e2e/e2etests/test_bitcoin_withdraw_restricted_address.go @@ -1,11 +1,9 @@ package e2etests import ( - "fmt" "math/big" - "strconv" - "github.com/btcsuite/btcutil" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/pkg/chains" @@ -13,20 +11,10 @@ import ( ) func TestBitcoinWithdrawRestricted(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestBitcoinWithdrawRestricted requires exactly one argument for the amount.") - } + require.Len(r, args, 1) - withdrawalAmount, err := strconv.ParseFloat(args[0], 64) - if err != nil { - panic("Invalid withdrawal amount specified for TestBitcoinWithdrawRestricted.") - } - - withdrawalAmountSat, err := btcutil.NewAmount(withdrawalAmount) - if err != nil { - panic(err) - } - amount := big.NewInt(int64(withdrawalAmountSat)) + withdrawalAmount := parseFloat(r, args[0]) + amount := btcAmountFromFloat64(r, withdrawalAmount) r.SetBtcAddress(r.Name, false) @@ -39,13 +27,9 @@ func withdrawBitcoinRestricted(r *runner.E2ERunner, amount *big.Int) { testutils.RestrictedBtcAddressTest, chains.BitcoinRegtest.ChainId, ) - if err != nil { - panic(err) - } + require.NoError(r, err) // the cctx should be cancelled rawTx := withdrawBTCZRC20(r, addressRestricted, amount) - if len(rawTx.Vout) != 2 { - panic(fmt.Errorf("BTC cancelled outtx rawTx.Vout should have 2 outputs")) - } + require.Len(r, rawTx.Vout, 2, "BTC cancelled outtx rawTx.Vout should have 2 outputs") } diff --git a/e2e/e2etests/test_bitcoin_withdraw_segwit.go b/e2e/e2etests/test_bitcoin_withdraw_segwit.go index 31d5d1176b..2bd763693e 100644 --- a/e2e/e2etests/test_bitcoin_withdraw_segwit.go +++ b/e2e/e2etests/test_bitcoin_withdraw_segwit.go @@ -2,24 +2,21 @@ package e2etests import ( "github.com/btcsuite/btcutil" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" ) func TestBitcoinWithdrawSegWit(r *runner.E2ERunner, args []string) { - // check length of arguments - if len(args) != 2 { - panic("TestBitcoinWithdrawSegWit requires two arguments: [receiver, amount]") - } + require.Len(r, args, 2) + r.SetBtcAddress(r.Name, false) // parse arguments defaultReceiver := r.BTCDeployerAddress.EncodeAddress() receiver, amount := parseBitcoinWithdrawArgs(r, args, defaultReceiver) _, ok := receiver.(*btcutil.AddressWitnessPubKeyHash) - if !ok { - panic("Invalid receiver address specified for TestBitcoinWithdrawSegWit.") - } + require.True(r, ok, "Invalid receiver address specified for TestBitcoinWithdrawSegWit.") withdrawBTCZRC20(r, receiver, amount) } diff --git a/e2e/e2etests/test_bitcoin_withdraw_taproot.go b/e2e/e2etests/test_bitcoin_withdraw_taproot.go index 5473a947e5..cc1c5feb87 100644 --- a/e2e/e2etests/test_bitcoin_withdraw_taproot.go +++ b/e2e/e2etests/test_bitcoin_withdraw_taproot.go @@ -1,24 +1,22 @@ package e2etests import ( + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/pkg/chains" ) func TestBitcoinWithdrawTaproot(r *runner.E2ERunner, args []string) { - // check length of arguments - if len(args) != 2 { - panic("TestBitcoinWithdrawTaproot requires two arguments: [receiver, amount]") - } + require.Len(r, args, 2) + r.SetBtcAddress(r.Name, false) // parse arguments and withdraw BTC defaultReceiver := "bcrt1pqqqsyqcyq5rqwzqfpg9scrgwpugpzysnzs23v9ccrydpk8qarc0sj9hjuh" receiver, amount := parseBitcoinWithdrawArgs(r, args, defaultReceiver) _, ok := receiver.(*chains.AddressTaproot) - if !ok { - panic("Invalid receiver address specified for TestBitcoinWithdrawTaproot.") - } + require.True(r, ok, "Invalid receiver address specified for TestBitcoinWithdrawTaproot.") withdrawBTCZRC20(r, receiver, amount) } diff --git a/e2e/e2etests/test_context_upgrade.go b/e2e/e2etests/test_context_upgrade.go index fc1e7599de..4d06ee84d1 100644 --- a/e2e/e2etests/test_context_upgrade.go +++ b/e2e/e2etests/test_context_upgrade.go @@ -6,6 +6,7 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -13,30 +14,24 @@ import ( // TestContextUpgrade tests sending ETH on ZetaChain and check context data func TestContextUpgrade(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestContextUpgrade requires exactly one argument for the value.") - } + require.Len(r, args, 1) // parse the value from the provided arguments value, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid value specified for TestContextUpgrade.") - } + require.True(r, ok, "Invalid value specified for TestContextUpgrade.") data := make([]byte, 0, 32) data = append(data, r.ContextAppAddr.Bytes()...) data = append(data, []byte("filler")...) // just to make sure that this is a contract call; signedTx, err := r.SendEther(r.TSSAddress, value, data) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("EVM tx sent: %s; to %s, nonce %d", signedTx.Hash().String(), signedTx.To().Hex(), signedTx.Nonce()) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, signedTx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("EVM tx receipt: %d", receipt.Status) r.Logger.Info(" tx hash: %s", receipt.TxHash.String()) r.Logger.Info(" to: %s", signedTx.To().String()) @@ -60,18 +55,13 @@ func TestContextUpgrade(r *runner.E2ERunner, args []string) { r.Logger.Info(" sender: %s", eventIter.Event.Sender.Hex()) r.Logger.Info(" chainid: %d", eventIter.Event.ChainID) r.Logger.Info(" msgsender: %s", eventIter.Event.MsgSender.Hex()) + found = true - if bytes.Compare(eventIter.Event.Origin, r.DeployerAddress.Bytes()) != 0 { - panic("origin mismatch") - } - chainID, err := r.EVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } - if eventIter.Event.ChainID.Cmp(chainID) != 0 { - panic("chainID mismatch") - } + require.Equal(r, 0, bytes.Compare(eventIter.Event.Origin, r.DeployerAddress.Bytes()), "origin mismatch") + chainID, err := r.EVMClient.ChainID(r.Ctx) + require.NoError(r, err) + require.Equal(r, 0, eventIter.Event.ChainID.Cmp(chainID), "chainID mismatch") } if found { break @@ -79,8 +69,5 @@ func TestContextUpgrade(r *runner.E2ERunner, args []string) { time.Sleep(2 * time.Second) } - if !found { - panic("event not found") - } - + require.True(r, found, "event not found") } diff --git a/e2e/e2etests/test_crosschain_swap.go b/e2e/e2etests/test_crosschain_swap.go index 358e9ba7d7..f1fe6f54aa 100644 --- a/e2e/e2etests/test_crosschain_swap.go +++ b/e2e/e2etests/test_crosschain_swap.go @@ -1,12 +1,13 @@ package e2etests import ( - "fmt" "math/big" "time" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/ethereum/go-ethereum/accounts/abi/bind" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -24,38 +25,30 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { if err != nil { r.Logger.Print("ℹ️create pair error") } + txERC20ZRC20Approve, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, big.NewInt(1e18)) - if err != nil { - panic(err) - } + require.NoError(r, err) + txBTCApprove, err := r.BTCZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, big.NewInt(1e18)) - if err != nil { - panic(err) - } + require.NoError(r, err) // Fund ZEVMSwapApp with gas ZRC20s txTransferETH, err := r.ETHZRC20.Transfer(r.ZEVMAuth, r.ZEVMSwapAppAddr, big.NewInt(1e7)) - if err != nil { - panic(err) - } + require.NoError(r, err) + txTransferBTC, err := r.BTCZRC20.Transfer(r.ZEVMAuth, r.ZEVMSwapAppAddr, big.NewInt(1e6)) - if err != nil { - panic(err) - } + require.NoError(r, err) - if receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txERC20ZRC20Approve, r.Logger, r.ReceiptTimeout); receipt.Status != 1 { - panic("ZRC20 ERC20 approve failed") - } - if receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txBTCApprove, r.Logger, r.ReceiptTimeout); receipt.Status != 1 { - panic("btc approve failed") - } - if receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txTransferETH, r.Logger, r.ReceiptTimeout); receipt.Status != 1 { - panic("ETH ZRC20 transfer failed") - } - if receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txTransferBTC, r.Logger, r.ReceiptTimeout); receipt.Status != 1 { - panic("BTC ZRC20 transfer failed") + ensureTxReceipt := func(tx *ethtypes.Transaction, failMessage string) { + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequireTxSuccessful(r, receipt, failMessage) } + ensureTxReceipt(txERC20ZRC20Approve, "ZRC20 ERC20 approve failed") + ensureTxReceipt(txBTCApprove, "BTC approve failed") + ensureTxReceipt(txTransferETH, "ETH ZRC20 transfer failed") + ensureTxReceipt(txTransferBTC, "BTC ZRC20 transfer failed") + // Add 100 erc20 zrc20 liq and 0.001 BTC txAddLiquidity, err := r.UniswapV2Router.AddLiquidity( r.ZEVMAuth, @@ -68,13 +61,8 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { r.DeployerAddress, big.NewInt(time.Now().Add(10*time.Minute).Unix()), ) - if err != nil { - panic(fmt.Sprintf("Error liq %s", err.Error())) - } - - if receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txAddLiquidity, r.Logger, r.ReceiptTimeout); receipt.Status != 1 { - panic("add liq receipt status is not 1") - } + require.NoError(r, err) + ensureTxReceipt(txAddLiquidity, "add liq failed") // msg would be [ZEVMSwapAppAddr, memobytes] // memobytes is dApp specific; see the contracts/ZEVMSwapApp.sol for details @@ -85,10 +73,8 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { r.BTCZRC20Addr, []byte(r.BTCDeployerAddress.EncodeAddress()), ) + require.NoError(r, err) - if err != nil { - panic(err) - } r.Logger.Info("memobytes(%d) %x", len(memobytes), memobytes) msg = append(msg, memobytes...) @@ -98,80 +84,52 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { cctx1 := utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) // check the cctx status - if cctx1.CctxStatus.Status != types.CctxStatus_OutboundMined { - panic( - fmt.Sprintf( - "expected outbound mined status; got %s, message: %s", - cctx1.CctxStatus.Status.String(), - cctx1.CctxStatus.StatusMessage, - ), - ) - } + utils.RequireCCTXStatus(r, cctx1, types.CctxStatus_OutboundMined) // mine 10 blocks to confirm the outbound tx _, err = r.GenerateToAddressIfLocalBitcoin(10, r.BTCDeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) // mine blocks if testing on regnet stop := r.MineBlocksIfLocalBitcoin() + defer stop() // cctx1 index acts like the inboundHash for the second cctx (the one that withdraws BTC) cctx2 := utils.WaitCctxMinedByInboundHash(r.Ctx, cctx1.Index, r.CctxClient, r.Logger, r.CctxTimeout) // check the cctx status - if cctx2.CctxStatus.Status != types.CctxStatus_OutboundMined { - panic(fmt.Sprintf( - "expected outbound mined status; got %s, message: %s", - cctx2.CctxStatus.Status.String(), - cctx2.CctxStatus.StatusMessage), - ) - } + utils.RequireCCTXStatus(r, cctx2, types.CctxStatus_OutboundMined) r.Logger.Info("cctx2 outbound tx hash %s", cctx2.GetCurrentOutboundParam().Hash) r.Logger.Info("******* Second test: BTC -> ERC20ZRC20") // list deployer utxos utxos, err := r.ListDeployerUTXOs() - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("#utxos %d", len(utxos)) r.Logger.Info("memo address %s", r.ERC20ZRC20Addr) + memo, err := r.ZEVMSwapApp.EncodeMemo(&bind.CallOpts{}, r.ERC20ZRC20Addr, r.DeployerAddress.Bytes()) - if err != nil { - panic(err) - } + require.NoError(r, err) + memo = append(r.ZEVMSwapAppAddr.Bytes(), memo...) r.Logger.Info("memo length %d", len(memo)) txID, err := r.SendToTSSFromDeployerWithMemo(0.01, utxos[0:1], memo) - if err != nil { - panic(err) - } + require.NoError(r, err) cctx3 := utils.WaitCctxMinedByInboundHash(r.Ctx, txID.String(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx3.CctxStatus.Status != types.CctxStatus_OutboundMined { - panic(fmt.Sprintf( - "expected outbound mined status; got %s, message: %s", - cctx3.CctxStatus.Status.String(), - cctx3.CctxStatus.StatusMessage), - ) - } + utils.RequireCCTXStatus(r, cctx3, types.CctxStatus_OutboundMined) + r.Logger.Info("cctx3 index %s", cctx3.Index) r.Logger.Info(" inbound tx hash %s", cctx3.InboundParams.ObservedHash) r.Logger.Info(" status %s", cctx3.CctxStatus.Status.String()) r.Logger.Info(" status msg: %s", cctx3.CctxStatus.StatusMessage) cctx4 := utils.WaitCctxMinedByInboundHash(r.Ctx, cctx3.Index, r.CctxClient, r.Logger, r.CctxTimeout) - if cctx4.CctxStatus.Status != types.CctxStatus_OutboundMined { - panic(fmt.Sprintf( - "expected outbound mined status; got %s, message: %s", - cctx3.CctxStatus.Status.String(), - cctx3.CctxStatus.StatusMessage), - ) - } + utils.RequireCCTXStatus(r, cctx4, types.CctxStatus_OutboundMined) + r.Logger.Info("cctx4 index %s", cctx4.Index) r.Logger.Info(" outbound tx hash %s", cctx4.GetCurrentOutboundParam().Hash) r.Logger.Info(" status %s", cctx4.CctxStatus.Status.String()) @@ -181,17 +139,14 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { // the following memo will result in a revert in the contract call as targetZRC20 is set to DeployerAddress // which is apparently not a ZRC20 contract; the UNISWAP call will revert memo, err := r.ZEVMSwapApp.EncodeMemo(&bind.CallOpts{}, r.DeployerAddress, r.DeployerAddress.Bytes()) - if err != nil { - panic(err) - } + require.NoError(r, err) + memo = append(r.ZEVMSwapAppAddr.Bytes(), memo...) r.Logger.Info("memo length %d", len(memo)) amount := 0.1 txid, err := r.SendToTSSFromDeployerWithMemo(amount, utxos[1:2], memo) - if err != nil { - panic(err) - } + require.NoError(r, err) cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, txid.String(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.Info("cctx3 index %s", cctx.Index) @@ -199,17 +154,14 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { r.Logger.Info(" status %s", cctx.CctxStatus.Status.String()) r.Logger.Info(" status msg: %s", cctx.CctxStatus.StatusMessage) - if cctx.CctxStatus.Status != types.CctxStatus_Reverted { - panic(fmt.Sprintf("expected reverted status; got %s", cctx.CctxStatus.Status.String())) - } + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_Reverted) + outboundHash, err := chainhash.NewHashFromStr(cctx.GetCurrentOutboundParam().Hash) - if err != nil { - panic(err) - } + require.NoError(r, err) + txraw, err := r.BtcRPCClient.GetRawTransactionVerbose(outboundHash) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("out txid %s", txraw.Txid) for _, vout := range txraw.Vout { r.Logger.Info(" vout %d", vout.N) @@ -218,7 +170,4 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { r.Logger.Info(" p2wpkh address: %s", utils.ScriptPKToAddress(vout.ScriptPubKey.Hex, r.BitcoinParams)) } } - - // stop mining - stop() } diff --git a/e2e/e2etests/test_deploy_contract.go b/e2e/e2etests/test_deploy_contract.go index 860ae2e0dc..6133942f60 100644 --- a/e2e/e2etests/test_deploy_contract.go +++ b/e2e/e2etests/test_deploy_contract.go @@ -4,6 +4,7 @@ import ( "fmt" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testdapp" "github.com/zeta-chain/zetacore/e2e/runner" @@ -21,28 +22,20 @@ var deployMap = map[string]deployFunc{ // TestDeployContract deploys the specified contract func TestDeployContract(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) + availableContractNames := make([]string, 0, len(deployMap)) for contractName := range deployMap { availableContractNames = append(availableContractNames, contractName) } availableContractNamesMessage := fmt.Sprintf("Available contract names: %v", availableContractNames) - - if len(args) != 1 { - panic( - "TestDeployContract requires exactly one argument for the contract name. " + availableContractNamesMessage, - ) - } contractName := args[0] deployFunc, ok := deployMap[contractName] - if !ok { - panic(fmt.Sprintf("Unknown contract name: %s, %s", contractName, availableContractNamesMessage)) - } + require.True(r, ok, "Unknown contract name: %s, %s", contractName, availableContractNamesMessage) addr, err := deployFunc(r) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Print("%s deployed at %s", contractName, addr.Hex()) } diff --git a/e2e/e2etests/test_donation.go b/e2e/e2etests/test_donation.go index f6d9bac3ff..2347e97e23 100644 --- a/e2e/e2etests/test_donation.go +++ b/e2e/e2etests/test_donation.go @@ -3,6 +3,8 @@ package e2etests import ( "math/big" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" "github.com/zeta-chain/zetacore/pkg/constant" @@ -10,25 +12,18 @@ import ( // TestDonationEther tests donation of ether to the tss address func TestDonationEther(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestDonationEther requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestDonationEther.") - } + require.True(r, ok, "Invalid amount specified for TestDonationEther.") txDonation, err := r.SendEther(r.TSSAddress, amount, []byte(constant.DonationMessage)) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.EVMTransaction(*txDonation, "donation") // check contract deployment receipt receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, txDonation, r.Logger, r.ReceiptTimeout) r.Logger.EVMReceipt(*receipt, "donation") - if receipt.Status != 1 { - panic("donation tx failed") - } + utils.RequireTxSuccessful(r, receipt) } diff --git a/e2e/e2etests/test_erc20_deposit.go b/e2e/e2etests/test_erc20_deposit.go index f550ce4aa7..2f763f34b0 100644 --- a/e2e/e2etests/test_erc20_deposit.go +++ b/e2e/e2etests/test_erc20_deposit.go @@ -3,19 +3,17 @@ package e2etests import ( "math/big" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" ) func TestERC20Deposit(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestERC20Deposit requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestERC20Deposit.") - } + require.True(r, ok, "Invalid amount specified for TestERC20Deposit.") hash := r.DepositERC20WithAmountAndMessage(r.DeployerAddress, amount, []byte{}) diff --git a/e2e/e2etests/test_erc20_deposit_refund.go b/e2e/e2etests/test_erc20_deposit_refund.go index 684adf3d6f..ad0a962507 100644 --- a/e2e/e2etests/test_erc20_deposit_refund.go +++ b/e2e/e2etests/test_erc20_deposit_refund.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -17,9 +18,7 @@ import ( func TestERC20DepositAndCallRefund(r *runner.E2ERunner, _ []string) { // Get the initial balance of the deployer initialBal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("Sending a deposit that should revert without a liquidity pool makes the cctx aborted") @@ -27,46 +26,34 @@ func TestERC20DepositAndCallRefund(r *runner.E2ERunner, _ []string) { // send the deposit inboundHash, err := sendInvalidERC20Deposit(r, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) // There is no liquidity pool, therefore the cctx should abort cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, inboundHash, r.CctxClient, r.Logger, r.CctxTimeout) + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_Aborted) + require.False(r, cctx.CctxStatus.IsAbortRefunded, "expected cctx status to be not refunded") + r.Logger.CCTX(*cctx, "deposit") - if cctx.CctxStatus.Status != types.CctxStatus_Aborted { - panic(fmt.Sprintf("expected cctx status to be Aborted; got %s", cctx.CctxStatus.Status)) - } + r.Logger.Info("Refunding the cctx via admin") - if cctx.CctxStatus.IsAbortRefunded != false { - panic(fmt.Sprintf("expected cctx status to be not refunded; got %t", cctx.CctxStatus.IsAbortRefunded)) - } + msg := types.NewMsgRefundAbortedCCTX(r.ZetaTxServer.GetAccountAddress(0), cctx.Index, r.DeployerAddress.String()) - r.Logger.Info("Refunding the cctx via admin") - msg := types.NewMsgRefundAbortedCCTX( - r.ZetaTxServer.GetAccountAddress(0), - cctx.Index, - r.DeployerAddress.String()) _, err = r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, msg) - if err != nil { - panic(err) - } + require.NoError(r, err) // Check that the erc20 in the aborted cctx was refunded on ZetaChain newBalance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) + expectedBalance := initialBal.Add(initialBal, amount) - if newBalance.Cmp(expectedBalance) != 0 { - panic( - fmt.Sprintf( - "expected balance to be %s after refund; got %s", - expectedBalance.String(), - newBalance.String(), - ), - ) - } + require.Equal( + r, + 0, + newBalance.Cmp(expectedBalance), + "expected balance to be %s after refund; got %s", + expectedBalance.String(), + newBalance.String(), + ) r.Logger.Info("CCTX has been aborted on ZetaChain") // test refund when there is a liquidity pool @@ -74,67 +61,54 @@ func TestERC20DepositAndCallRefund(r *runner.E2ERunner, _ []string) { r.Logger.Info("Creating the liquidity pool USTD/ZETA") err = createZetaERC20LiquidityPool(r) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("Liquidity pool created") erc20Balance, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) // send the deposit amount = big.NewInt(1e7) inboundHash, err = sendInvalidERC20Deposit(r, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) + erc20BalanceAfterSend := big.NewInt(0).Sub(erc20Balance, amount) // there is a liquidity pool, therefore the cctx should revert - cctx = utils.WaitCctxMinedByInboundHash(r.Ctx, inboundHash, r.CctxClient, r.Logger, r.CctxTimeout) - // the revert tx creation will fail because the sender, used as the recipient, is not defined in the cctx - if cctx.CctxStatus.Status != types.CctxStatus_Reverted { - panic(fmt.Sprintf( - "expected cctx status to be PendingRevert; got %s, aborted message: %s", - cctx.CctxStatus.Status, - cctx.CctxStatus.StatusMessage, - )) - } + cctx = utils.WaitCctxMinedByInboundHash(r.Ctx, inboundHash, r.CctxClient, r.Logger, r.CctxTimeout) + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_Reverted) // get revert tx revertTxHash := cctx.GetCurrentOutboundParam().Hash receipt, err := r.EVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(revertTxHash)) - if err != nil { - panic(err) - } - if receipt.Status == 0 { - panic("expected the revert tx receipt to have status 1; got 0") - } + require.NoError(r, err) + utils.RequireTxSuccessful(r, receipt) // check that the erc20 in the reverted cctx was refunded on EVM erc20BalanceAfterRefund, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) + // the new balance must be higher than the previous one because of the revert refund - if erc20BalanceAfterSend.Cmp(erc20BalanceAfterRefund) != -1 { - panic(fmt.Sprintf( - "expected balance to be higher after refund than after send %s < %s", - erc20BalanceAfterSend.String(), - erc20BalanceAfterRefund.String(), - )) - } + require.Equal( + r, + -1, + erc20BalanceAfterSend.Cmp(erc20BalanceAfterRefund), + "expected balance to be higher after refund than after send %s < %s", + erc20BalanceAfterSend.String(), + erc20BalanceAfterRefund.String(), + ) + // it must also be lower than the previous balance + the amount because of the gas fee for the revert tx - if erc20BalanceAfterRefund.Cmp(erc20Balance) != -1 { - panic(fmt.Sprintf( - "expected balance to be lower after refund than before send %s < %s", - erc20BalanceAfterRefund.String(), - erc20Balance.String()), - ) - } + require.Equal( + r, + -1, + erc20BalanceAfterRefund.Cmp(erc20Balance), + "expected balance to be lower after refund than before send %s < %s", + erc20BalanceAfterRefund.String(), + erc20Balance.String(), + ) r.Logger.Info("ERC20 CCTX successfully reverted") r.Logger.Info("\tbalance before refund: %s", erc20Balance.String()) diff --git a/e2e/e2etests/test_erc20_deposit_restricted_address.go b/e2e/e2etests/test_erc20_deposit_restricted_address.go index 1823f9236d..758da5a969 100644 --- a/e2e/e2etests/test_erc20_deposit_restricted_address.go +++ b/e2e/e2etests/test_erc20_deposit_restricted_address.go @@ -4,20 +4,17 @@ import ( "math/big" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/zetaclient/testutils" ) func TestERC20DepositRestricted(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestERC20DepositRestricted requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestERC20DepositRestricted.") - } + require.True(r, ok) // deposit ERC20 to restricted address r.DepositERC20WithAmountAndMessage(ethcommon.HexToAddress(testutils.RestrictedEVMAddressTest), amount, []byte{}) diff --git a/e2e/e2etests/test_erc20_multiple_deposits.go b/e2e/e2etests/test_erc20_multiple_deposits.go index b09c363c8d..a99642f356 100644 --- a/e2e/e2etests/test_erc20_multiple_deposits.go +++ b/e2e/e2etests/test_erc20_multiple_deposits.go @@ -1,11 +1,11 @@ package e2etests import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -13,24 +13,17 @@ import ( ) func TestMultipleERC20Deposit(r *runner.E2ERunner, args []string) { - if len(args) != 2 { - panic("TestMultipleERC20Deposit requires exactly two arguments: the deposit amount and the number of deposits.") - } + require.Len(r, args, 2) depositAmount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid deposit amount specified for TestMultipleERC20Deposit.") - } + require.True(r, ok) numberOfDeposits, ok := big.NewInt(0).SetString(args[1], 10) - if !ok || numberOfDeposits.Int64() < 1 { - panic("Invalid number of deposits specified for TestMultipleERC20Deposit.") - } + require.True(r, ok) + require.NotZero(r, numberOfDeposits.Int64()) initialBal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) txhash := multipleDeposits(r, depositAmount, numberOfDeposits) cctxs := utils.WaitCctxsMinedByInboundHash( @@ -41,51 +34,39 @@ func TestMultipleERC20Deposit(r *runner.E2ERunner, args []string) { r.Logger, r.CctxTimeout, ) - if len(cctxs) != 3 { - panic(fmt.Sprintf("cctxs length is not correct: %d", len(cctxs))) - } + require.Len(r, cctxs, 3) // check new balance is increased by amount * count bal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) + diff := big.NewInt(0).Sub(bal, initialBal) total := depositAmount.Mul(depositAmount, numberOfDeposits) - if diff.Cmp(total) != 0 { - panic(fmt.Sprintf("balance difference is not correct: %d", diff.Int64())) - } + + require.Equal(r, 0, diff.Cmp(total), "balance difference is not correct") } func multipleDeposits(r *runner.E2ERunner, amount, count *big.Int) ethcommon.Hash { // deploy depositor depositorAddr, _, depositor, err := testcontract.DeployDepositor(r.EVMAuth, r.EVMClient, r.ERC20CustodyAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) fullAmount := big.NewInt(0).Mul(amount, count) // approve tx, err := r.ERC20.Approve(r.EVMAuth, depositorAddr, fullAmount) - if err != nil { - panic(err) - } + require.NoError(r, err) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("approve failed") - } + utils.RequireTxSuccessful(r, receipt) r.Logger.Info("ERC20 Approve receipt tx hash: %s", tx.Hash().Hex()) // deposit tx, err = depositor.RunDeposits(r.EVMAuth, r.DeployerAddress.Bytes(), r.ERC20Addr, amount, []byte{}, count) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("deposits failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("Deposits receipt tx hash: %s", tx.Hash().Hex()) for _, log := range receipt.Logs { diff --git a/e2e/e2etests/test_erc20_multiple_withdraws.go b/e2e/e2etests/test_erc20_multiple_withdraws.go index de13c7b6b8..14bbb176ca 100644 --- a/e2e/e2etests/test_erc20_multiple_withdraws.go +++ b/e2e/e2etests/test_erc20_multiple_withdraws.go @@ -1,10 +1,10 @@ package e2etests import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -12,67 +12,55 @@ import ( ) func TestMultipleERC20Withdraws(r *runner.E2ERunner, args []string) { + require.Len(r, args, 2) + approvedAmount := big.NewInt(1e18) - if len(args) != 2 { - panic( - "TestMultipleWithdraws requires exactly two arguments: the withdrawal amount and the number of withdrawals.", - ) - } withdrawalAmount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok || withdrawalAmount.Cmp(approvedAmount) >= 0 { - panic("Invalid withdrawal amount specified for TestMultipleWithdraws.") - } + require.True(r, ok) + require.Equal( + r, + -1, + withdrawalAmount.Cmp(approvedAmount), + "Invalid withdrawal amount specified for TestMultipleWithdraws.", + ) numberOfWithdrawals, ok := big.NewInt(0).SetString(args[1], 10) - if !ok || numberOfWithdrawals.Int64() < 1 { - panic("Invalid number of withdrawals specified for TestMultipleWithdraws.") - } + require.True(r, ok) + require.NotEmpty(r, numberOfWithdrawals.Int64()) // calculate total withdrawal to ensure it doesn't exceed approved amount. totalWithdrawal := big.NewInt(0).Mul(withdrawalAmount, numberOfWithdrawals) - if totalWithdrawal.Cmp(approvedAmount) >= 0 { - panic("Total withdrawal amount exceeds approved limit.") - } + require.Equal(r, -1, totalWithdrawal.Cmp(approvedAmount), "Total withdrawal amount exceeds approved limit.") // deploy withdrawer withdrawerAddr, _, withdrawer, err := testcontract.DeployWithdrawer(r.ZEVMAuth, r.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) // approve tx, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, withdrawerAddr, approvedAmount) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("approve failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("ERC20 ZRC20 approve receipt: status %d", receipt.Status) // approve gas token tx, err = r.ETHZRC20.Approve(r.ZEVMAuth, withdrawerAddr, approvedAmount) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("approve gas token failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("eth zrc20 approve receipt: status %d", receipt.Status) // check the balance bal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("balance of deployer on ERC20 ZRC20: %d", bal) - if bal.Int64() < totalWithdrawal.Int64() { - panic("not enough ERC20 ZRC20 balance!") - } + require.Less(r, totalWithdrawal.Int64(), bal.Int64(), "not enough ERC20 ZRC20 balance!") // withdraw tx, err = withdrawer.RunWithdraws( @@ -82,13 +70,9 @@ func TestMultipleERC20Withdraws(r *runner.E2ERunner, args []string) { withdrawalAmount, numberOfWithdrawals, ) - if err != nil { - panic(err) - } + require.NoError(r, err) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("withdraw failed") - } + utils.RequireTxSuccessful(r, receipt) cctxs := utils.WaitCctxsMinedByInboundHash( r.Ctx, @@ -98,9 +82,7 @@ func TestMultipleERC20Withdraws(r *runner.E2ERunner, args []string) { r.Logger, r.CctxTimeout, ) - if len(cctxs) != 3 { - panic(fmt.Sprintf("cctxs length is not correct: %d", len(cctxs))) - } + require.Len(r, cctxs, 3) // verify the withdraw value for _, cctx := range cctxs { diff --git a/e2e/e2etests/test_erc20_withdraw.go b/e2e/e2etests/test_erc20_withdraw.go index 3d24b1670a..f2ce31b5c3 100644 --- a/e2e/e2etests/test_erc20_withdraw.go +++ b/e2e/e2etests/test_erc20_withdraw.go @@ -3,34 +3,27 @@ package e2etests import ( "math/big" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" ) func TestERC20Withdraw(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) + approvedAmount := big.NewInt(1e18) - if len(args) != 1 { - panic("TestERC20Withdraw requires exactly one argument for the withdrawal amount.") - } withdrawalAmount, ok := new(big.Int).SetString(args[0], 10) - if !ok { - panic("Invalid withdrawal amount specified for TestERC20Withdraw.") - } - - if withdrawalAmount.Cmp(approvedAmount) >= 0 { - panic("Withdrawal amount must be less than the approved amount (1e18).") - } + require.True(r, ok, "Invalid withdrawal amount specified for TestERC20Withdraw.") + require.Equal(r, -1, withdrawalAmount.Cmp(approvedAmount)) // approve tx, err := r.ETHZRC20.Approve(r.ZEVMAuth, r.ERC20ZRC20Addr, approvedAmount) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("approve failed") - } + utils.RequireTxSuccessful(r, receipt) r.Logger.Info("eth zrc20 approve receipt: status %d", receipt.Status) // withdraw @@ -38,5 +31,6 @@ func TestERC20Withdraw(r *runner.E2ERunner, args []string) { // verify the withdraw value cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + verifyTransferAmountFromCCTX(r, cctx, withdrawalAmount.Int64()) } diff --git a/e2e/e2etests/test_eth_deposit.go b/e2e/e2etests/test_eth_deposit.go index 5b06bfe3bc..03da8f6da4 100644 --- a/e2e/e2etests/test_eth_deposit.go +++ b/e2e/e2etests/test_eth_deposit.go @@ -3,20 +3,18 @@ package e2etests import ( "math/big" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" ) // TestEtherDeposit tests deposit of ethers func TestEtherDeposit(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestEtherDeposit requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestEtherDeposit.") - } + require.True(r, ok, "Invalid amount specified for TestEtherDeposit.") hash := r.DepositEtherWithAmount(false, amount) // in wei // wait for the cctx to be mined diff --git a/e2e/e2etests/test_eth_deposit_call.go b/e2e/e2etests/test_eth_deposit_call.go index dc6cc5cb32..0d7734fbdb 100644 --- a/e2e/e2etests/test_eth_deposit_call.go +++ b/e2e/e2etests/test_eth_deposit_call.go @@ -1,13 +1,12 @@ package e2etests import ( - "fmt" "math/big" - "strings" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -17,125 +16,91 @@ import ( // TestEtherDepositAndCall tests deposit of ethers calling a example contract func TestEtherDepositAndCall(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestEtherDepositAndCall requires exactly one argument for the amount.") - } + require.Len(r, args, 1) value, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestEtherDepositAndCall.") - } + require.True(r, ok, "Invalid amount specified for TestEtherDepositAndCall.") r.Logger.Info("Deploying example contract") exampleAddr, _, exampleContract, err := testcontract.DeployExample(r.ZEVMAuth, r.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("Example contract deployed") // preparing tx evmClient := r.EVMClient gasLimit := uint64(23000) gasPrice, err := evmClient.SuggestGasPrice(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) + nonce, err := evmClient.PendingNonceAt(r.Ctx, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) data := append(exampleAddr.Bytes(), []byte("hello sailors")...) tx := ethtypes.NewTransaction(nonce, r.TSSAddress, value, gasLimit, gasPrice, data) chainID, err := evmClient.NetworkID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) + deployerPrivkey, err := crypto.HexToECDSA(r.DeployerPrivateKey) - if err != nil { - panic(err) - } + require.NoError(r, err) + signedTx, err := ethtypes.SignTx(tx, ethtypes.NewEIP155Signer(chainID), deployerPrivkey) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("Sending a cross-chain call to example contract") err = evmClient.SendTransaction(r.Ctx, signedTx) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, signedTx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, signedTx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != types.CctxStatus_OutboundMined { - panic(fmt.Sprintf("expected cctx status to be mined; got %s", cctx.CctxStatus.Status)) - } + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_OutboundMined) // Checking example contract has been called, bar value should be set to amount bar, err := exampleContract.Bar(&bind.CallOpts{}) - if err != nil { - panic(err) - } - if bar.Cmp(value) != 0 { - panic( - fmt.Sprintf( - "cross-chain call failed bar value %s should be equal to amount %s", - bar.String(), - value.String(), - ), - ) - } + require.NoError(r, err) + require.Equal( + r, + 0, + bar.Cmp(value), + "cross-chain call failed bar value %s should be equal to amount %s", + bar.String(), + value.String(), + ) r.Logger.Info("Cross-chain call succeeded") r.Logger.Info("Deploying reverter contract") reverterAddr, _, _, err := testcontract.DeployReverter(r.ZEVMAuth, r.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("Example reverter deployed") // preparing tx for reverter gasPrice, err = evmClient.SuggestGasPrice(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) + nonce, err = evmClient.PendingNonceAt(r.Ctx, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) data = append(reverterAddr.Bytes(), []byte("hello sailors")...) tx = ethtypes.NewTransaction(nonce, r.TSSAddress, value, gasLimit, gasPrice, data) signedTx, err = ethtypes.SignTx(tx, ethtypes.NewEIP155Signer(chainID), deployerPrivkey) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("Sending a cross-chain call to reverter contract") err = evmClient.SendTransaction(r.Ctx, signedTx) - if err != nil { - panic(err) - } + require.NoError(r, err) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, signedTx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) cctx = utils.WaitCctxMinedByInboundHash(r.Ctx, signedTx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != types.CctxStatus_Reverted { - panic(fmt.Sprintf("expected cctx status to be reverted; got %s", cctx.CctxStatus.Status)) - } + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_Reverted) + r.Logger.Info("Cross-chain call to reverter reverted") // check the status message contains revert error hash in case of revert // 0xbfb4ebcf is the hash of "Foo()" - if !strings.Contains(cctx.CctxStatus.StatusMessage, "0xbfb4ebcf") { - panic( - fmt.Sprintf("expected cctx status message to contain revert reason; got %s", cctx.CctxStatus.StatusMessage), - ) - } + require.Contains(r, cctx.CctxStatus.StatusMessage, "0xbfb4ebcf") } diff --git a/e2e/e2etests/test_eth_deposit_liquidity_cap.go b/e2e/e2etests/test_eth_deposit_liquidity_cap.go index a132fdd35e..f64b041478 100644 --- a/e2e/e2etests/test_eth_deposit_liquidity_cap.go +++ b/e2e/e2etests/test_eth_deposit_liquidity_cap.go @@ -1,11 +1,11 @@ package e2etests import ( - "fmt" "math/big" "cosmossdk.io/math" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -15,15 +15,11 @@ import ( // TestDepositEtherLiquidityCap tests depositing Ethers in a context where a liquidity cap is set func TestDepositEtherLiquidityCap(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestDepositEtherLiquidityCap requires exactly one argument for the liquidity cap.") - } + require.Len(r, args, 1) liquidityCapArg := math.NewUintFromString(args[0]) supply, err := r.ETHZRC20.TotalSupply(&bind.CallOpts{}) - if err != nil { - panic(err) - } + require.NoError(r, err) liquidityCap := math.NewUintFromBigInt(supply).Add(liquidityCapArg) amountLessThanCap := liquidityCapArg.BigInt().Div(liquidityCapArg.BigInt(), big.NewInt(10)) // 1/10 of the cap @@ -34,63 +30,41 @@ func TestDepositEtherLiquidityCap(r *runner.E2ERunner, args []string) { liquidityCap, ) res, err := r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, msg) - if err != nil { - panic(err) - } - r.Logger.Info("set liquidity cap tx hash: %s", res.TxHash) + require.NoError(r, err) + r.Logger.Info("set liquidity cap tx hash: %s", res.TxHash) r.Logger.Info("Depositing more than liquidity cap should make cctx reverted") + signedTx, err := r.SendEther(r.TSSAddress, amountMoreThanCap, nil) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, signedTx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("deposit eth tx failed") - } + utils.RequireTxSuccessful(r, receipt) + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, signedTx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != types.CctxStatus_Reverted { - panic(fmt.Sprintf("expected cctx status to be Reverted; got %s", cctx.CctxStatus.Status)) - } + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_Reverted) + r.Logger.Info("CCTX has been reverted") r.Logger.Info("Depositing less than liquidity cap should still succeed") initialBal, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) + signedTx, err = r.SendEther(r.TSSAddress, amountLessThanCap, nil) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, signedTx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("deposit eth tx failed") - } + utils.RequireTxSuccessful(r, receipt) + cctx = utils.WaitCctxMinedByInboundHash(r.Ctx, signedTx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != types.CctxStatus_OutboundMined { - - panic(fmt.Sprintf( - "expected cctx status to be Success; got %s; message: %s; supply: %s; liquidity cap: %s, amountLessThanCap: %s, amountMoreThanCap: %s", - cctx.CctxStatus.Status, - cctx.CctxStatus.StatusMessage, - supply.String(), - liquidityCap.String(), - amountLessThanCap.String(), - amountMoreThanCap.String(), - )) - } + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_OutboundMined) expectedBalance := big.NewInt(0).Add(initialBal, amountLessThanCap) bal, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } - if bal.Cmp(expectedBalance) != 0 { + require.NoError(r, err) + require.Equal(r, 0, bal.Cmp(expectedBalance)) - panic(fmt.Sprintf("expected balance to be %s; got %s", expectedBalance.String(), bal.String())) - } r.Logger.Info("Deposit succeeded") r.Logger.Info("Removing the liquidity cap") @@ -99,32 +73,33 @@ func TestDepositEtherLiquidityCap(r *runner.E2ERunner, args []string) { r.ETHZRC20Addr.Hex(), math.ZeroUint(), ) + res, err = r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, msg) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("remove liquidity cap tx hash: %s", res.TxHash) + initialBal, err = r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) + signedTx, err = r.SendEther(r.TSSAddress, amountMoreThanCap, nil) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, signedTx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("deposit eth tx failed") - } + utils.RequireTxSuccessful(r, receipt) + utils.WaitCctxMinedByInboundHash(r.Ctx, signedTx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) expectedBalance = big.NewInt(0).Add(initialBal, amountMoreThanCap) bal, err = r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } - if bal.Cmp(expectedBalance) != 0 { - panic(fmt.Sprintf("expected balance to be %s; got %s", expectedBalance.String(), bal.String())) - } + require.NoError(r, err) + require.Equal(r, + 0, + bal.Cmp(expectedBalance), + "expected balance to be %s; got %s", + expectedBalance.String(), + bal.String(), + ) + r.Logger.Info("New deposit succeeded") } diff --git a/e2e/e2etests/test_eth_deposit_refund.go b/e2e/e2etests/test_eth_deposit_refund.go index 2de41965ea..394ffdd8e4 100644 --- a/e2e/e2etests/test_eth_deposit_refund.go +++ b/e2e/e2etests/test_eth_deposit_refund.go @@ -1,12 +1,12 @@ package e2etests import ( - "fmt" "math/big" ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -14,109 +14,74 @@ import ( ) func TestEtherDepositAndCallRefund(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestEtherDepositAndCallRefund requires exactly one argument for the amount.") - } + require.Len(r, args, 1) value, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestEtherDepositAndCallRefund.") - } + require.True(r, ok, "Invalid amount specified for TestEtherDepositAndCallRefund.") evmClient := r.EVMClient nonce, err := evmClient.PendingNonceAt(r.Ctx, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) gasLimit := uint64(23000) // in units gasPrice, err := evmClient.SuggestGasPrice(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) data := append(r.BTCZRC20Addr.Bytes(), []byte("hello sailors")...) // this data tx := ethtypes.NewTransaction(nonce, r.TSSAddress, value, gasLimit, gasPrice, data) chainID, err := evmClient.NetworkID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) + deployerPrivkey, err := crypto.HexToECDSA(r.DeployerPrivateKey) - if err != nil { - panic(err) - } + require.NoError(r, err) signedTx, err := ethtypes.SignTx(tx, ethtypes.NewEIP155Signer(chainID), deployerPrivkey) - if err != nil { - panic(err) - } + require.NoError(r, err) + err = evmClient.SendTransaction(r.Ctx, signedTx) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("EVM tx sent: %s; to %s, nonce %d", signedTx.Hash().String(), signedTx.To().Hex(), signedTx.Nonce()) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, signedTx, r.Logger, r.ReceiptTimeout) + r.Logger.Info("EVM tx receipt: %d", receipt.Status) r.Logger.Info(" tx hash: %s", receipt.TxHash.String()) r.Logger.Info(" to: %s", signedTx.To().String()) r.Logger.Info(" value: %d", signedTx.Value()) r.Logger.Info(" block num: %d", receipt.BlockNumber) - func() { - cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, signedTx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - r.Logger.Info("cctx status message: %s", cctx.CctxStatus.StatusMessage) - revertTxHash := cctx.GetCurrentOutboundParam().Hash - r.Logger.Info("EVM revert tx receipt: status %d", receipt.Status) - - tx, _, err := r.EVMClient.TransactionByHash(r.Ctx, ethcommon.HexToHash(revertTxHash)) - if err != nil { - panic(err) - } - receipt, err := r.EVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(revertTxHash)) - if err != nil { - panic(err) - } - - printTxInfo := func() { - // debug info when test fails - r.Logger.Info(" tx: %+v", tx) - r.Logger.Info(" receipt: %+v", receipt) - r.Logger.Info("cctx http://localhost:1317/zeta-chain/crosschain/cctx/%s", cctx.Index) - } - - if cctx.CctxStatus.Status != types.CctxStatus_Reverted { - printTxInfo() - panic(fmt.Sprintf("expected cctx status to be PendingRevert; got %s", cctx.CctxStatus.Status)) - } - - if receipt.Status == 0 { - printTxInfo() - panic("expected the revert tx receipt to have status 1; got 0") - } - - if *tx.To() != r.DeployerAddress { - printTxInfo() - panic(fmt.Sprintf("expected tx to %s; got %s", r.DeployerAddress.Hex(), tx.To().Hex())) - } - - // the received value must be lower than the original value because of the paid fees for the revert tx - // we check that the value is still greater than 0 - if tx.Value().Cmp(value) != -1 || tx.Value().Cmp(big.NewInt(0)) != 1 { - printTxInfo() - panic( - fmt.Sprintf( - "expected tx value %s; should be non-null and lower than %s", - tx.Value().String(), - value.String(), - ), - ) - } - - r.Logger.Info("REVERT tx receipt: %d", receipt.Status) - r.Logger.Info(" tx hash: %s", receipt.TxHash.String()) - r.Logger.Info(" to: %s", tx.To().String()) - r.Logger.Info(" value: %s", tx.Value().String()) - r.Logger.Info(" block num: %d", receipt.BlockNumber) - }() + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, signedTx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.Info("cctx status message: %s", cctx.CctxStatus.StatusMessage) + revertTxHash := cctx.GetCurrentOutboundParam().Hash + r.Logger.Info("EVM revert tx receipt: status %d", receipt.Status) + + tx, _, err = r.EVMClient.TransactionByHash(r.Ctx, ethcommon.HexToHash(revertTxHash)) + require.NoError(r, err) + + receipt, err = r.EVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(revertTxHash)) + require.NoError(r, err) + + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_Reverted) + utils.RequireTxSuccessful(r, receipt) + + require.Equal(r, r.DeployerAddress, *tx.To(), "expected tx to %s; got %s", r.DeployerAddress.Hex(), tx.To().Hex()) + + // the received value must be lower than the original value because of the paid fees for the revert tx + // we check that the value is still greater than 0 + invariant := tx.Value().Cmp(value) != -1 || tx.Value().Cmp(big.NewInt(0)) != 1 + require.False( + r, + invariant, + "expected tx value %s; should be non-null and lower than %s", + tx.Value().String(), + value.String(), + ) + + r.Logger.Info("REVERT tx receipt: %d", receipt.Status) + r.Logger.Info(" tx hash: %s", receipt.TxHash.String()) + r.Logger.Info(" to: %s", tx.To().String()) + r.Logger.Info(" value: %s", tx.Value().String()) + r.Logger.Info(" block num: %d", receipt.BlockNumber) } diff --git a/e2e/e2etests/test_eth_withdraw.go b/e2e/e2etests/test_eth_withdraw.go index 5a71ec65fb..798704fe39 100644 --- a/e2e/e2etests/test_eth_withdraw.go +++ b/e2e/e2etests/test_eth_withdraw.go @@ -3,51 +3,46 @@ package e2etests import ( "math/big" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) -// TestEtherWithdraw tests the withdraw of ether +// TestEtherWithdraw tests the withdrawal of ether func TestEtherWithdraw(r *runner.E2ERunner, args []string) { - r.Logger.Info("TestEtherWithdraw") + require.Len(r, args, 1) approvedAmount := big.NewInt(1e18) - if len(args) != 1 { - panic("TestEtherWithdraw requires exactly one argument for the withdrawal amount.") - } - withdrawalAmount, ok := new(big.Int).SetString(args[0], 10) - if !ok { - panic("Invalid withdrawal amount specified for TestEtherWithdraw.") - } - - if withdrawalAmount.Cmp(approvedAmount) >= 0 { - panic("Withdrawal amount must be less than the approved amount (1e18).") - } + require.True(r, ok, "Invalid withdrawal amount specified for TestEtherWithdraw.") + require.Equal( + r, + -1, + withdrawalAmount.Cmp(approvedAmount), + "Withdrawal amount must be less than the approved amount (1e18).", + ) // approve tx, err := r.ETHZRC20.Approve(r.ZEVMAuth, r.ETHZRC20Addr, approvedAmount) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.EVMTransaction(*tx, "approve") receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("approve failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.EVMReceipt(*receipt, "approve") // withdraw tx = r.WithdrawEther(withdrawalAmount) - // verify the withdraw value + // verify the withdrawal value cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "withdraw") - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { - panic("cctx status is not outbound mined") - } + + utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) r.Logger.Info("TestEtherWithdraw completed") } diff --git a/e2e/e2etests/test_eth_withdraw_restricted_address.go b/e2e/e2etests/test_eth_withdraw_restricted_address.go index 8f17cb4edb..793bfc42c5 100644 --- a/e2e/e2etests/test_eth_withdraw_restricted_address.go +++ b/e2e/e2etests/test_eth_withdraw_restricted_address.go @@ -4,6 +4,7 @@ import ( "math/big" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -13,54 +14,47 @@ import ( // TestEtherWithdrawRestricted tests the withdrawal to a restricted receiver address func TestEtherWithdrawRestricted(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) + approvedAmount := big.NewInt(1e18) - if len(args) != 1 { - panic("TestEtherWithdrawRestricted requires exactly one argument for the withdrawal amount.") - } withdrawalAmount, ok := new(big.Int).SetString(args[0], 10) - if !ok { - panic("Invalid withdrawal amount specified for TestEtherWithdrawRestricted.") - } - - if withdrawalAmount.Cmp(approvedAmount) >= 0 { - panic("Withdrawal amount must be less than the approved amount (1e18).") - } + require.True(r, ok) + require.True( + r, + withdrawalAmount.Cmp(approvedAmount) <= 0, + "Withdrawal amount must be less than the approved amount (1e18)", + ) // approve tx, err := r.ETHZRC20.Approve(r.ZEVMAuth, r.ETHZRC20Addr, approvedAmount) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.EVMTransaction(*tx, "approve") receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("approve failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.EVMReceipt(*receipt, "approve") // withdraw restrictedAddress := ethcommon.HexToAddress(testutils.RestrictedEVMAddressTest) tx, err = r.ETHZRC20.Withdraw(r.ZEVMAuth, restrictedAddress.Bytes(), withdrawalAmount) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.EVMTransaction(*tx, "withdraw to restricted address") receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("withdraw failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.EVMReceipt(*receipt, "withdraw") r.Logger.ZRC20Withdrawal(r.ETHZRC20, *receipt, "withdraw") - // verify the withdraw value + // verify the withdrawal value cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "withdraw") - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { - panic("cctx status is not outbound mined") - } + + utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) // the cctx should be cancelled with zero value verifyTransferAmountFromCCTX(r, cctx, 0) diff --git a/e2e/e2etests/test_message_passing_evm_to_zevm.go b/e2e/e2etests/test_message_passing_evm_to_zevm.go index bedfd50965..4a7ac7f906 100644 --- a/e2e/e2etests/test_message_passing_evm_to_zevm.go +++ b/e2e/e2etests/test_message_passing_evm_to_zevm.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testdapp" "github.com/zeta-chain/zetacore/e2e/runner" @@ -14,81 +15,56 @@ import ( ) func TestMessagePassingEVMtoZEVM(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestMessagePassingEVMtoZEVM requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestMessagePassingEVMtoZEVM.") - } + require.True(r, ok, "Invalid amount specified for TestMessagePassingEVMtoZEVM.") // Set destination details zEVMChainID, err := r.ZEVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) destinationAddress := r.ZevmTestDAppAddr // Contract call originates from EVM chain tx, err := r.ZetaEth.Approve(r.EVMAuth, r.EvmTestDAppAddr, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("Approve tx hash: %s", tx.Hash().Hex()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("approve tx failed") - } + utils.RequireTxSuccessful(r, receipt) r.Logger.Info("Approve tx receipt: %d", receipt.Status) testDAppEVM, err := testdapp.NewTestDApp(r.EvmTestDAppAddr, r.EVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) // Get ZETA balance on ZEVM TestDApp previousBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZevmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) previousBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.EVMAuth.From) - if err != nil { - panic(err) - } + require.NoError(r, err) // Call the SendHelloWorld function on the EVM dapp Contract which would in turn create a new send, to be picked up by the zeta-clients // set Do revert to false which adds a message to signal the ZEVM zetaReceiver to not revert the transaction tx, err = testDAppEVM.SendHelloWorld(r.EVMAuth, destinationAddress, zEVMChainID, amount, false) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("TestDApp.SendHello tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) // New inbound message picked up by zeta-clients and voted on by observers to initiate a contract call on zEVM cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_OutboundMined { - panic("expected cctx to be outbound_mined") - } + utils.RequireCCTXStatus(r, cctx, cctxtypes.CctxStatus_OutboundMined) + r.Logger.Info(fmt.Sprintf("🔄 Cctx mined for contract call chain zevm %s", cctx.Index)) // On finalization the Fungible module calls the onReceive function which in turn calls the onZetaMessage function on the destination contract receipt, err = r.ZEVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(cctx.GetCurrentOutboundParam().Hash)) - if err != nil { - panic(err) - } - if receipt.Status != 1 { - panic("tx failed") - } + require.NoError(r, err) + utils.RequireTxSuccessful(r, receipt) testDAppZEVM, err := testdapp.NewTestDApp(r.ZevmTestDAppAddr, r.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) // Check event emitted receivedHelloWorldEvent := false @@ -99,33 +75,15 @@ func TestMessagePassingEVMtoZEVM(r *runner.E2ERunner, args []string) { receivedHelloWorldEvent = true } } - if !receivedHelloWorldEvent { - panic(fmt.Sprintf("expected HelloWorld event, logs: %+v", receipt.Logs)) - } + require.True(r, receivedHelloWorldEvent, "expected HelloWorld event") // Check ZETA balance on ZEVM TestDApp and check new balance is previous balance + amount newBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZevmTestDAppAddr) - if err != nil { - panic(err) - } - if newBalanceZEVM.Cmp(big.NewInt(0).Add(previousBalanceZEVM, amount)) != 0 { - panic(fmt.Sprintf( - "expected new balance to be %s, got %s", - big.NewInt(0).Add(previousBalanceZEVM, amount).String(), - newBalanceZEVM.String()), - ) - } + require.NoError(r, err) + require.Equal(r, 0, newBalanceZEVM.Cmp(big.NewInt(0).Add(previousBalanceZEVM, amount))) // Check ZETA balance on EVM TestDApp and check new balance is previous balance - amount newBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.EVMAuth.From) - if err != nil { - panic(err) - } - if newBalanceEVM.Cmp(big.NewInt(0).Sub(previousBalanceEVM, amount)) != 0 { - panic(fmt.Sprintf( - "expected new balance to be %s, got %s", - big.NewInt(0).Sub(previousBalanceEVM, amount).String(), - newBalanceEVM.String()), - ) - } + require.NoError(r, err) + require.Equal(r, 0, newBalanceEVM.Cmp(big.NewInt(0).Sub(previousBalanceEVM, amount))) } diff --git a/e2e/e2etests/test_message_passing_evm_to_zevm_revert.go b/e2e/e2etests/test_message_passing_evm_to_zevm_revert.go index 3c12711aed..b99ea8513f 100644 --- a/e2e/e2etests/test_message_passing_evm_to_zevm_revert.go +++ b/e2e/e2etests/test_message_passing_evm_to_zevm_revert.go @@ -1,11 +1,11 @@ package e2etests import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testdapp" "github.com/zeta-chain/zetacore/e2e/runner" @@ -14,57 +14,43 @@ import ( ) func TestMessagePassingEVMtoZEVMRevert(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestMessagePassingEVMtoZEVMRevert requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestMessagePassingEVMtoZEVMRevert.") - } + require.True(r, ok) // Set destination details zEVMChainID, err := r.ZEVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) destinationAddress := r.ZevmTestDAppAddr // Contract call originates from EVM chain tx, err := r.ZetaEth.Approve(r.EVMAuth, r.EvmTestDAppAddr, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("Approve tx hash: %s", tx.Hash().Hex()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("Approve tx receipt: %d", receipt.Status) testDAppEVM, err := testdapp.NewTestDApp(r.EvmTestDAppAddr, r.EVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) // Get ZETA balance before test previousBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZevmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) + previousBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.EvmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) // Call the SendHelloWorld function on the EVM dapp Contract which would in turn create a new send, to be picked up by the zeta-clients // set Do revert to true which adds a message to signal the ZEVM zetaReceiver to revert the transaction tx, err = testDAppEVM.SendHelloWorld(r.EVMAuth, destinationAddress, zEVMChainID, amount, true) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("TestDApp.SendHello tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) @@ -72,18 +58,13 @@ func TestMessagePassingEVMtoZEVMRevert(r *runner.E2ERunner, args []string) { // New inbound message picked up by zeta-clients and voted on by observers to initiate a contract call on zEVM which would revert the transaction // A revert transaction is created and gets fialized on the original sender chain. cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Reverted { - panic("expected cctx to be reverted") - } + utils.RequireCCTXStatus(r, cctx, cctxtypes.CctxStatus_Reverted) // On finalization the Tss address calls the onRevert function which in turn calls the onZetaRevert function on the sender contract receipt, err = r.EVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(cctx.GetCurrentOutboundParam().Hash)) - if err != nil { - panic(err) - } - if receipt.Status != 1 { - panic("tx failed") - } + require.NoError(r, err) + utils.RequireTxSuccessful(r, receipt) + receivedHelloWorldEvent := false for _, log := range receipt.Logs { _, err := testDAppEVM.ParseRevertedHelloWorldEvent(*log) @@ -92,37 +73,37 @@ func TestMessagePassingEVMtoZEVMRevert(r *runner.E2ERunner, args []string) { receivedHelloWorldEvent = true } } - if !receivedHelloWorldEvent { - panic(fmt.Sprintf("expected Reverted HelloWorld event, logs: %+v", receipt.Logs)) - } + require.True(r, receivedHelloWorldEvent, "expected Reverted HelloWorld event") // Check ZETA balance on ZEVM TestDApp and check new balance is previous balance newBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZevmTestDAppAddr) - if err != nil { - panic(err) - } - if newBalanceZEVM.Cmp(previousBalanceZEVM) != 0 { - panic( - fmt.Sprintf("expected new balance to be %s, got %s", previousBalanceZEVM.String(), newBalanceZEVM.String()), - ) - } + require.NoError(r, err) + require.Equal( + r, + 0, + newBalanceZEVM.Cmp(previousBalanceZEVM), + "expected new balance to be %s, got %s", + previousBalanceZEVM.String(), + newBalanceZEVM.String(), + ) // Check ZETA balance on EVM TestDApp and check new balance is between previous balance and previous balance + amount // New balance is increased because ZETA are sent from the sender but sent back to the contract // New balance is less than previous balance + amount because of the gas fee to pay newBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.EvmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) + previousBalanceAndAmountEVM := big.NewInt(0).Add(previousBalanceEVM, amount) // check higher than previous balance and lower than previous balance + amount - if newBalanceEVM.Cmp(previousBalanceEVM) <= 0 || newBalanceEVM.Cmp(previousBalanceAndAmountEVM) > 0 { - panic(fmt.Sprintf( - "expected new balance to be between %s and %s, got %s", - previousBalanceEVM.String(), - previousBalanceAndAmountEVM.String(), - newBalanceEVM.String()), - ) - } + invariant := newBalanceEVM.Cmp(previousBalanceEVM) <= 0 || newBalanceEVM.Cmp(previousBalanceAndAmountEVM) > 0 + require.False( + r, + invariant, + "expected new balance to be between %s and %s, got %s", + previousBalanceEVM.String(), + previousBalanceAndAmountEVM.String(), + newBalanceEVM.String(), + ) + } diff --git a/e2e/e2etests/test_message_passing_evm_to_zevm_revert_fail.go b/e2e/e2etests/test_message_passing_evm_to_zevm_revert_fail.go index 352fe959a8..a767f619ad 100644 --- a/e2e/e2etests/test_message_passing_evm_to_zevm_revert_fail.go +++ b/e2e/e2etests/test_message_passing_evm_to_zevm_revert_fail.go @@ -1,10 +1,10 @@ package e2etests import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testdappnorevert" "github.com/zeta-chain/zetacore/e2e/runner" @@ -13,14 +13,10 @@ import ( ) func TestMessagePassingEVMtoZEVMRevertFail(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestMessagePassingEVMtoZEVMRevertFail requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestMessagePassingEVMtoZEVMRevertFail.") - } + require.True(r, ok, "Invalid amount specified for TestMessagePassingEVMtoZEVMRevertFail.") // Deploying a test contract not containing a logic for reverting the cctx testDappNoRevertEVMAddr, tx, testDappNoRevertEVM, err := testdappnorevert.DeployTestDAppNoRevert( @@ -29,87 +25,66 @@ func TestMessagePassingEVMtoZEVMRevertFail(r *runner.E2ERunner, args []string) { r.ConnectorEthAddr, r.ZetaEthAddr, ) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("TestDAppNoRevertEVM deployed at: %s", testDappNoRevertEVMAddr.Hex()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequireTxSuccessful(r, receipt) + r.Logger.EVMReceipt(*receipt, "deploy TestDAppNoRevert") - if receipt.Status == 0 { - panic("deploy TestDAppNoRevert failed") - } // Set destination details zEVMChainID, err := r.ZEVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) destinationAddress := r.ZevmTestDAppAddr // Contract call originates from EVM chain tx, err = r.ZetaEth.Approve(r.EVMAuth, testDappNoRevertEVMAddr, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("Approve tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("Approve tx receipt: %d", receipt.Status) // Get ZETA balance before test previousBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZevmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) + previousBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, testDappNoRevertEVMAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) // Send message with doRevert tx, err = testDappNoRevertEVM.SendHelloWorld(r.EVMAuth, destinationAddress, zEVMChainID, amount, true) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("TestDAppNoRevert.SendHello tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) // New inbound message picked up by zeta-clients and voted on by observers to initiate a contract call on zEVM which would revert the transaction - // A revert transaction is created and gets fialized on the original sender chain. + // A revert transaction is created and gets finalized on the original sender chain. cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Aborted { - panic("expected cctx to be reverted") - } + utils.RequireCCTXStatus(r, cctx, cctxtypes.CctxStatus_Aborted) // Check ZETA balance on ZEVM TestDApp and check new balance is previous balance newBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZevmTestDAppAddr) - if err != nil { - panic(err) - } - if newBalanceZEVM.Cmp(previousBalanceZEVM) != 0 { - panic(fmt.Sprintf( - "expected new balance to be %s, got %s", - previousBalanceZEVM.String(), - newBalanceZEVM.String()), - ) - } + require.NoError(r, err) + require.Equal( + r, + 0, + newBalanceZEVM.Cmp(previousBalanceZEVM), + "expected new balance to be %s, got %s", + previousBalanceZEVM.String(), + newBalanceZEVM.String(), + ) // Check ZETA balance on EVM TestDApp and check new balance is previous balance newBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, testDappNoRevertEVMAddr) - if err != nil { - panic(err) - } - if newBalanceEVM.Cmp(previousBalanceEVM) != 0 { - panic(fmt.Sprintf( - "expected new balance to be %s, got %s", - previousBalanceEVM.String(), - newBalanceEVM.String()), - ) - } + require.NoError(r, err) + require.Equal(r, 0, newBalanceEVM.Cmp(previousBalanceEVM)) } diff --git a/e2e/e2etests/test_message_passing_external_chains.go b/e2e/e2etests/test_message_passing_external_chains.go index 5a6fed227e..317665920b 100644 --- a/e2e/e2etests/test_message_passing_external_chains.go +++ b/e2e/e2etests/test_message_passing_external_chains.go @@ -1,10 +1,10 @@ package e2etests import ( - "fmt" "math/big" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" zetaconnectoreth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.eth.sol" "github.com/zeta-chain/zetacore/e2e/runner" @@ -16,32 +16,25 @@ import ( // TODO: Use two external EVM chains for these tests // https://github.com/zeta-chain/node/issues/2185 func TestMessagePassingExternalChains(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestMessagePassing requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestMessagePassing.") - } + require.True(r, ok, "Invalid amount specified for TestMessagePassing.") chainID, err := r.EVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("Approving ConnectorEth to spend deployer's ZetaEth") auth := r.EVMAuth + tx, err := r.ZetaEth.Approve(auth, r.ConnectorEthAddr, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("Approve tx hash: %s", tx.Hash().Hex()) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("Approve tx receipt: %d", receipt.Status) r.Logger.Info("Calling ConnectorEth.Send") tx, err = r.ConnectorEth.Send(auth, zetaconnectoreth.ZetaInterfacesSendInput{ @@ -52,15 +45,13 @@ func TestMessagePassingExternalChains(r *runner.E2ERunner, args []string) { ZetaValueAndGas: amount, ZetaParams: nil, }) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("ConnectorEth.Send tx hash: %s", tx.Hash().Hex()) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("ConnectorEth.Send tx receipt: status %d", receipt.Status) r.Logger.Info(" Logs:") for _, log := range receipt.Logs { @@ -75,22 +66,14 @@ func TestMessagePassingExternalChains(r *runner.E2ERunner, args []string) { r.Logger.Info("Waiting for ConnectorEth.Send CCTX to be mined...") r.Logger.Info(" INTX hash: %s", receipt.TxHash.String()) + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_OutboundMined { - panic(fmt.Sprintf( - "expected cctx status to be %s; got %s, message %s", - cctxtypes.CctxStatus_OutboundMined, - cctx.CctxStatus.Status.String(), - cctx.CctxStatus.StatusMessage, - )) - } + utils.RequireCCTXStatus(r, cctx, cctxtypes.CctxStatus_OutboundMined) + receipt, err = r.EVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(cctx.GetCurrentOutboundParam().Hash)) - if err != nil { - panic(err) - } - if receipt.Status != 1 { - panic("tx failed") - } + require.NoError(r, err) + utils.RequireTxSuccessful(r, receipt) + for _, log := range receipt.Logs { event, err := r.ConnectorEth.ParseZetaReceived(*log) if err == nil { @@ -98,9 +81,9 @@ func TestMessagePassingExternalChains(r *runner.E2ERunner, args []string) { r.Logger.Info(" Dest Addr: %s", event.DestinationAddress) r.Logger.Info(" Zeta Value: %d", event.ZetaValue) r.Logger.Info(" src chainid: %d", event.SourceChainId) - if event.ZetaValue.Cmp(cctx.GetCurrentOutboundParam().Amount.BigInt()) != 0 { - panic("Zeta value mismatch") - } + + comp := event.ZetaValue.Cmp(cctx.GetCurrentOutboundParam().Amount.BigInt()) + require.Equal(r, 0, comp, "Zeta value mismatch") } } } diff --git a/e2e/e2etests/test_message_passing_external_chains_revert.go b/e2e/e2etests/test_message_passing_external_chains_revert.go index fee09b3bb0..37146a4c78 100644 --- a/e2e/e2etests/test_message_passing_external_chains_revert.go +++ b/e2e/e2etests/test_message_passing_external_chains_revert.go @@ -5,6 +5,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testdapp" "github.com/zeta-chain/zetacore/e2e/runner" @@ -16,65 +17,48 @@ import ( // TODO: Use two external EVM chains for these tests // https://github.com/zeta-chain/node/issues/2185 func TestMessagePassingRevertSuccessExternalChains(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestMessagePassingRevertSuccess requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestMessagePassingRevertSuccess.") - } + require.True(r, ok) chainID, err := r.EVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) auth := r.EVMAuth tx, err := r.ZetaEth.Approve(auth, r.EvmTestDAppAddr, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("Approve tx hash: %s", tx.Hash().Hex()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) r.Logger.Info("Approve tx receipt: %d", receipt.Status) r.Logger.Info("Calling TestDApp.SendHello on contract address %s", r.EvmTestDAppAddr.Hex()) testDApp, err := testdapp.NewTestDApp(r.EvmTestDAppAddr, r.EVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) + + res2, err := r.BankClient.SupplyOf(r.Ctx, &banktypes.QuerySupplyOfRequest{Denom: "azeta"}) + require.NoError(r, err) - res2, err := r.BankClient.SupplyOf(r.Ctx, &banktypes.QuerySupplyOfRequest{ - Denom: "azeta", - }) - if err != nil { - panic(err) - } r.Logger.Info("$$$ Before: SUPPLY OF AZETA: %d", res2.Amount.Amount) tx, err = testDApp.SendHelloWorld(auth, r.EvmTestDAppAddr, chainID, amount, true) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("TestDApp.SendHello tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.Info("TestDApp.SendHello tx receipt: status %d", receipt.Status) cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Reverted { - panic("expected cctx to be reverted") - } + utils.RequireCCTXStatus(r, cctx, cctxtypes.CctxStatus_Reverted) + outTxHash := cctx.GetCurrentOutboundParam().Hash receipt, err = r.EVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(outTxHash)) - if err != nil { - panic(err) - } + require.NoError(r, err) + for _, log := range receipt.Logs { event, err := r.ConnectorEth.ParseZetaReverted(*log) if err == nil { @@ -85,12 +69,10 @@ func TestMessagePassingRevertSuccessExternalChains(r *runner.E2ERunner, args []s r.Logger.Info(" Message: %x", event.Message) } } - res3, err := r.BankClient.SupplyOf(r.Ctx, &banktypes.QuerySupplyOfRequest{ - Denom: "azeta", - }) - if err != nil { - panic(err) - } + + res3, err := r.BankClient.SupplyOf(r.Ctx, &banktypes.QuerySupplyOfRequest{Denom: "azeta"}) + require.NoError(r, err) + r.Logger.Info("$$$ After: SUPPLY OF AZETA: %d", res3.Amount.Amount.BigInt()) r.Logger.Info("$$$ Diff: SUPPLY OF AZETA: %d", res3.Amount.Amount.Sub(res2.Amount.Amount).BigInt()) } diff --git a/e2e/e2etests/test_message_passing_external_chains_revert_fail.go b/e2e/e2etests/test_message_passing_external_chains_revert_fail.go index e9bdeb0c7e..3950a8cdd5 100644 --- a/e2e/e2etests/test_message_passing_external_chains_revert_fail.go +++ b/e2e/e2etests/test_message_passing_external_chains_revert_fail.go @@ -4,6 +4,8 @@ import ( "math/big" ethcommon "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" zetaconnectoreth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.eth.sol" "github.com/zeta-chain/zetacore/e2e/runner" @@ -15,32 +17,26 @@ import ( // TODO: Use two external EVM chains for these tests // https://github.com/zeta-chain/node/issues/2185 func TestMessagePassingRevertFailExternalChains(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestMessagePassingRevertFail requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestMessagePassingRevertFail.") - } + require.True(r, ok, "Invalid amount specified for TestMessagePassingRevertFail.") chainID, err := r.EVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) auth := r.EVMAuth tx, err := r.ZetaEth.Approve(auth, r.ConnectorEthAddr, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("Approve tx hash: %s", tx.Hash().Hex()) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("Approve tx receipt: %d", receipt.Status) r.Logger.Info("Calling ConnectorEth.Send") + tx, err = r.ConnectorEth.Send(auth, zetaconnectoreth.ZetaInterfacesSendInput{ DestinationChainId: chainID, DestinationAddress: r.DeployerAddress.Bytes(), @@ -51,14 +47,13 @@ func TestMessagePassingRevertFailExternalChains(r *runner.E2ERunner, args []stri ZetaValueAndGas: amount, ZetaParams: nil, }) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("ConnectorEth.Send tx hash: %s", tx.Hash().Hex()) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("ConnectorEth.Send tx receipt: status %d", receipt.Status) r.Logger.Info(" Logs:") for _, log := range receipt.Logs { @@ -74,14 +69,9 @@ func TestMessagePassingRevertFailExternalChains(r *runner.E2ERunner, args []stri // expect revert tx to fail cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) receipt, err = r.EVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(cctx.GetCurrentOutboundParam().Hash)) - if err != nil { - panic(err) - } + require.NoError(r, err) + // expect revert tx to fail as well - if receipt.Status != 0 { - panic("expected revert tx to fail") - } - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Aborted { - panic("expected cctx to be aborted") - } + require.Equal(r, ethtypes.ReceiptStatusFailed, receipt.Status) + utils.RequireCCTXStatus(r, cctx, cctxtypes.CctxStatus_Aborted) } diff --git a/e2e/e2etests/test_message_passing_zevm_to_evm.go b/e2e/e2etests/test_message_passing_zevm_to_evm.go index 0e7c888be2..dde161f2f9 100644 --- a/e2e/e2etests/test_message_passing_zevm_to_evm.go +++ b/e2e/e2etests/test_message_passing_zevm_to_evm.go @@ -1,11 +1,11 @@ package e2etests import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testdapp" "github.com/zeta-chain/zetacore/e2e/runner" @@ -14,96 +14,65 @@ import ( ) func TestMessagePassingZEVMtoEVM(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestMessagePassingZEVMtoEVM requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestMessagePassingZEVMtoEVM.") - } + require.True(r, ok, "Invalid amount specified for TestMessagePassingZEVMtoEVM.") // Set destination details EVMChainID, err := r.EVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) + destinationAddress := r.EvmTestDAppAddr // Contract call originates from ZEVM chain r.ZEVMAuth.Value = amount tx, err := r.WZeta.Deposit(r.ZEVMAuth) - if err != nil { - panic(err) - } + require.NoError(r, err) r.ZEVMAuth.Value = big.NewInt(0) r.Logger.Info("wzeta deposit tx hash: %s", tx.Hash().Hex()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.EVMReceipt(*receipt, "wzeta deposit") - if receipt.Status == 0 { - panic("deposit failed") - } + utils.RequireTxSuccessful(r, receipt) tx, err = r.WZeta.Approve(r.ZEVMAuth, r.ZevmTestDAppAddr, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("wzeta approve tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.EVMReceipt(*receipt, "wzeta approve") - if receipt.Status == 0 { - panic(fmt.Sprintf("approve failed, logs: %+v", receipt.Logs)) - } + utils.RequireTxSuccessful(r, receipt) testDAppZEVM, err := testdapp.NewTestDApp(r.ZevmTestDAppAddr, r.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) // Get previous balances previousBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.EvmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) previousBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZEVMAuth.From) - if err != nil { - panic(err) - } + require.NoError(r, err) // Call the SendHelloWorld function on the ZEVM dapp Contract which would in turn create a new send, to be picked up by the zetanode evm hooks // set Do revert to false which adds a message to signal the EVM zetaReceiver to not revert the transaction tx, err = testDAppZEVM.SendHelloWorld(r.ZEVMAuth, destinationAddress, EVMChainID, amount, false) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("TestDApp.SendHello tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic(fmt.Sprintf("send failed, logs: %+v", receipt.Logs)) - } + utils.RequireTxSuccessful(r, receipt) // Transaction is picked up by the zetanode evm hooks and a new contract call is initiated on the EVM chain cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_OutboundMined { - panic("expected cctx to be outbound_mined") - } + utils.RequireCCTXStatus(r, cctx, cctxtypes.CctxStatus_OutboundMined) // On finalization the Tss calls the onReceive function which in turn calls the onZetaMessage function on the destination contract. receipt, err = r.EVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(cctx.GetCurrentOutboundParam().Hash)) - if err != nil { - panic(err) - } - if receipt.Status != 1 { - panic("tx failed") - } + require.NoError(r, err) + utils.RequireTxSuccessful(r, receipt) testDAppEVM, err := testdapp.NewTestDApp(r.EvmTestDAppAddr, r.EVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) receivedHelloWorldEvent := false for _, log := range receipt.Logs { @@ -113,38 +82,35 @@ func TestMessagePassingZEVMtoEVM(r *runner.E2ERunner, args []string) { receivedHelloWorldEvent = true } } - if !receivedHelloWorldEvent { - panic(fmt.Sprintf("expected HelloWorld event, logs: %+v", receipt.Logs)) - } + require.True(r, receivedHelloWorldEvent, "expected HelloWorld event") // Check ZETA balance on EVM TestDApp and check new balance between previous balance and previous balance + amount // Contract receive less than the amount because of the gas fee to pay newBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.EvmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) + previousBalanceAndAmountEVM := big.NewInt(0).Add(previousBalanceEVM, amount) // check higher than previous balance and lower than previous balance + amount - if newBalanceEVM.Cmp(previousBalanceEVM) <= 0 || newBalanceEVM.Cmp(previousBalanceAndAmountEVM) > 0 { - panic(fmt.Sprintf( - "expected new balance to be between %s and %s, got %s", - previousBalanceEVM.String(), - previousBalanceAndAmountEVM.String(), - newBalanceEVM.String()), - ) - } + invariant := newBalanceEVM.Cmp(previousBalanceEVM) <= 0 || newBalanceEVM.Cmp(previousBalanceAndAmountEVM) > 0 + require.False( + r, + invariant, + "expected new balance to be between %s and %s, got %s", + previousBalanceEVM.String(), + previousBalanceAndAmountEVM.String(), + newBalanceEVM.String(), + ) // Check ZETA balance on ZEVM TestDApp and check new balance is previous balance - amount newBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZEVMAuth.From) - if err != nil { - panic(err) - } - if newBalanceZEVM.Cmp(big.NewInt(0).Sub(previousBalanceZEVM, amount)) != 0 { - panic(fmt.Sprintf( - "expected new balance to be %s, got %s", - big.NewInt(0).Sub(previousBalanceZEVM, amount).String(), - newBalanceZEVM.String()), - ) - } + require.NoError(r, err) + require.Equal( + r, + 0, + newBalanceZEVM.Cmp(big.NewInt(0).Sub(previousBalanceZEVM, amount)), + "expected new balance to be %s, got %s", + big.NewInt(0).Sub(previousBalanceZEVM, amount).String(), + newBalanceZEVM.String(), + ) } diff --git a/e2e/e2etests/test_message_passing_zevm_to_evm_revert.go b/e2e/e2etests/test_message_passing_zevm_to_evm_revert.go index 0badfefdcb..85f81f0a04 100644 --- a/e2e/e2etests/test_message_passing_zevm_to_evm_revert.go +++ b/e2e/e2etests/test_message_passing_zevm_to_evm_revert.go @@ -1,11 +1,11 @@ package e2etests import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testdapp" "github.com/zeta-chain/zetacore/e2e/runner" @@ -14,91 +14,64 @@ import ( ) func TestMessagePassingZEVMtoEVMRevert(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestMessagePassingZEVMtoEVMRevert requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestMessagePassingZEVMtoEVMRevert.") - } + require.True(r, ok, "Invalid amount specified for TestMessagePassingZEVMtoEVMRevert.") // Set destination details EVMChainID, err := r.EVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) + destinationAddress := r.EvmTestDAppAddr // Contract call originates from ZEVM chain r.ZEVMAuth.Value = amount tx, err := r.WZeta.Deposit(r.ZEVMAuth) - if err != nil { - panic(err) - } + require.NoError(r, err) r.ZEVMAuth.Value = big.NewInt(0) r.Logger.Info("wzeta deposit tx hash: %s", tx.Hash().Hex()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.EVMReceipt(*receipt, "wzeta deposit") - if receipt.Status == 0 { - panic("deposit failed") - } + utils.RequireTxSuccessful(r, receipt) tx, err = r.WZeta.Approve(r.ZEVMAuth, r.ZevmTestDAppAddr, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("wzeta approve tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.EVMReceipt(*receipt, "wzeta approve") - if receipt.Status == 0 { - panic(fmt.Sprintf("approve failed, logs: %+v", receipt.Logs)) - } + utils.RequireTxSuccessful(r, receipt) testDAppZEVM, err := testdapp.NewTestDApp(r.ZevmTestDAppAddr, r.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) // Get ZETA balance before test previousBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZevmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) + previousBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.EvmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) // Call the SendHelloWorld function on the ZEVM dapp Contract which would in turn create a new send, to be picked up by the zetanode evm hooks // set Do revert to true which adds a message to signal the EVM zetaReceiver to revert the transaction tx, err = testDAppZEVM.SendHelloWorld(r.ZEVMAuth, destinationAddress, EVMChainID, amount, true) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("TestDApp.SendHello tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic(fmt.Sprintf("send failed, logs: %+v", receipt.Logs)) - } + utils.RequireTxSuccessful(r, receipt) // New inbound message picked up by zetanode evm hooks and processed directly to initiate a contract call on EVM which would revert the transaction cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Reverted { - panic("expected cctx to be reverted") - } + utils.RequireCCTXStatus(r, cctx, cctxtypes.CctxStatus_Reverted) // On finalization the Fungible module calls the onRevert function which in turn calls the onZetaRevert function on the sender contract receipt, err = r.ZEVMClient.TransactionReceipt(r.Ctx, ethcommon.HexToHash(cctx.GetCurrentOutboundParam().Hash)) - if err != nil { - panic(err) - } - if receipt.Status != 1 { - panic("tx failed") - } + require.NoError(r, err) + utils.RequireTxSuccessful(r, receipt) receivedHelloWorldEvent := false for _, log := range receipt.Logs { @@ -108,39 +81,28 @@ func TestMessagePassingZEVMtoEVMRevert(r *runner.E2ERunner, args []string) { receivedHelloWorldEvent = true } } - if !receivedHelloWorldEvent { - panic(fmt.Sprintf("expected Reverted HelloWorld event, logs: %+v", receipt.Logs)) - } + require.True(r, receivedHelloWorldEvent, "expected Reverted HelloWorld event") // Check ZETA balance on ZEVM TestDApp and check new balance is between previous balance and previous balance + amount // New balance is increased because ZETA are sent from the sender but sent back to the contract // Contract receive less than the amount because of the gas fee to pay newBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.ZevmTestDAppAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) + previousBalanceAndAmountZEVM := big.NewInt(0).Add(previousBalanceZEVM, amount) // check higher than previous balance and lower than previous balance + amount - if newBalanceZEVM.Cmp(previousBalanceZEVM) <= 0 || newBalanceZEVM.Cmp(previousBalanceAndAmountZEVM) > 0 { - panic(fmt.Sprintf( - "expected new balance to be between %s and %s, got %s", - previousBalanceZEVM.String(), - previousBalanceAndAmountZEVM.String(), - newBalanceZEVM.String()), - ) - } + invariant := newBalanceZEVM.Cmp(previousBalanceZEVM) <= 0 || newBalanceZEVM.Cmp(previousBalanceAndAmountZEVM) > 0 + require.False(r, + invariant, + "expected new balance to be between %s and %s, got %s", + previousBalanceZEVM.String(), + previousBalanceAndAmountZEVM.String(), + newBalanceZEVM.String(), + ) // Check ZETA balance on EVM TestDApp and check new balance is previous balance newBalanceEVM, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.EvmTestDAppAddr) - if err != nil { - panic(err) - } - if newBalanceEVM.Cmp(previousBalanceEVM) != 0 { - panic(fmt.Sprintf( - "expected new balance to be %s, got %s", - previousBalanceEVM.String(), - newBalanceEVM.String()), - ) - } + require.NoError(r, err) + require.Equal(r, 0, newBalanceEVM.Cmp(previousBalanceEVM), "expected new balance to be equal to previous balance") } diff --git a/e2e/e2etests/test_message_passing_zevm_to_evm_revert_fail.go b/e2e/e2etests/test_message_passing_zevm_to_evm_revert_fail.go index b822199af6..cc22db23a3 100644 --- a/e2e/e2etests/test_message_passing_zevm_to_evm_revert_fail.go +++ b/e2e/e2etests/test_message_passing_zevm_to_evm_revert_fail.go @@ -1,10 +1,10 @@ package e2etests import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testdappnorevert" "github.com/zeta-chain/zetacore/e2e/runner" @@ -13,14 +13,10 @@ import ( ) func TestMessagePassingZEVMtoEVMRevertFail(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestMessagePassingZEVMtoEVMRevertFail requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestMessagePassingZEVMtoEVMRevertFail.") - } + require.True(r, ok, "Invalid amount specified for TestMessagePassingZEVMtoEVMRevertFail.") // Deploying a test contract not containing a logic for reverting the cctx testDappNoRevertAddr, tx, testDappNoRevert, err := testdappnorevert.DeployTestDAppNoRevert( @@ -29,83 +25,64 @@ func TestMessagePassingZEVMtoEVMRevertFail(r *runner.E2ERunner, args []string) { r.ConnectorZEVMAddr, r.WZetaAddr, ) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("TestDAppNoRevert deployed at: %s", testDappNoRevertAddr.Hex()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.EVMReceipt(*receipt, "deploy TestDAppNoRevert") - if receipt.Status == 0 { - panic("deploy TestDAppNoRevert failed") - } + utils.RequireTxSuccessful(r, receipt) // Set destination details EVMChainID, err := r.EVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } + require.NoError(r, err) + destinationAddress := r.EvmTestDAppAddr // Contract call originates from ZEVM chain r.ZEVMAuth.Value = amount tx, err = r.WZeta.Deposit(r.ZEVMAuth) - if err != nil { - panic(err) - } + require.NoError(r, err) r.ZEVMAuth.Value = big.NewInt(0) r.Logger.Info("wzeta deposit tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.EVMReceipt(*receipt, "wzeta deposit") - if receipt.Status == 0 { - panic("deposit failed") - } + utils.RequireTxSuccessful(r, receipt) tx, err = r.WZeta.Approve(r.ZEVMAuth, testDappNoRevertAddr, amount) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("wzeta approve tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.EVMReceipt(*receipt, "wzeta approve") - if receipt.Status == 0 { - panic(fmt.Sprintf("approve failed, logs: %+v", receipt.Logs)) - } + utils.RequireTxSuccessful(r, receipt) // Get previous balances to check funds are not minted anywhere when aborted previousBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, testDappNoRevertAddr) - if err != nil { - panic(err) - } + require.NoError(r, err) // Send message with doRevert tx, err = testDappNoRevert.SendHelloWorld(r.ZEVMAuth, destinationAddress, EVMChainID, amount, true) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("TestDAppNoRevert.SendHello tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic(fmt.Sprintf("send failed, logs: %+v", receipt.Logs)) - } + utils.RequireTxSuccessful(r, receipt) // The revert tx will fail, the cctx state should be aborted cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, receipt.TxHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_Aborted { - panic("expected cctx to be reverted") - } + utils.RequireCCTXStatus(r, cctx, cctxtypes.CctxStatus_Aborted) // Check the funds are not minted to the contract as the cctx has been aborted newBalanceZEVM, err := r.WZeta.BalanceOf(&bind.CallOpts{}, testDappNoRevertAddr) - if err != nil { - panic(err) - } - if newBalanceZEVM.Cmp(previousBalanceZEVM) != 0 { - panic( - fmt.Sprintf("expected new balance to be %s, got %s", previousBalanceZEVM.String(), newBalanceZEVM.String()), - ) - } + require.NoError(r, err) + require.Equal(r, + 0, + newBalanceZEVM.Cmp(previousBalanceZEVM), + "expected new balance to be %s, got %s", + previousBalanceZEVM.String(), + newBalanceZEVM.String(), + ) } diff --git a/e2e/e2etests/test_migrate_chain_support.go b/e2e/e2etests/test_migrate_chain_support.go index f39bcbc2a3..848335ddef 100644 --- a/e2e/e2etests/test_migrate_chain_support.go +++ b/e2e/e2etests/test_migrate_chain_support.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/fatih/color" + "github.com/stretchr/testify/require" "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" "github.com/zeta-chain/zetacore/e2e/runner" @@ -44,9 +45,8 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { // create runner for the new EVM and set it up newRunner, err := configureEVM2(r) - if err != nil { - panic(err) - } + require.NoError(r, err) + newRunner.SetupEVM(false, false) // mint some ERC20 @@ -59,21 +59,16 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { // update the chain params to set up the chain chainParams := getNewEVMChainParams(newRunner) adminAddr, err := newRunner.ZetaTxServer.GetAccountAddressFromName(utils.FungibleAdminName) - if err != nil { - panic(err) - } + require.NoError(r, err) + _, err = newRunner.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, observertypes.NewMsgUpdateChainParams( adminAddr, chainParams, )) - if err != nil { - panic(err) - } + require.NoError(r, err) // setup the gas token - if err != nil { - panic(err) - } + require.NoError(r, err) _, err = newRunner.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, fungibletypes.NewMsgDeployFungibleCoinZRC20( adminAddr, "", @@ -84,26 +79,19 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { coin.CoinType_Gas, 100000, )) - if err != nil { - panic(err) - } + require.NoError(r, err) // set the gas token in the runner ethZRC20Addr, err := newRunner.SystemContract.GasCoinZRC20ByChainId( &bind.CallOpts{}, big.NewInt(chainParams.ChainId), ) - if err != nil { - panic(err) - } - if (ethZRC20Addr == ethcommon.Address{}) { - panic("eth zrc20 not found") - } + require.NoError(r, err) + require.NotEqual(r, ethcommon.Address{}, ethZRC20Addr) + newRunner.ETHZRC20Addr = ethZRC20Addr ethZRC20, err := zrc20.NewZRC20(ethZRC20Addr, newRunner.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) newRunner.ETHZRC20 = ethZRC20 // set the chain nonces for the new chain @@ -113,9 +101,7 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { 0, 0, )) - if err != nil { - panic(err) - } + require.NoError(r, err) // deactivate the previous chain chainParams = observertypes.GetDefaultGoerliLocalnetChainParams() @@ -124,15 +110,11 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { adminAddr, chainParams, )) - if err != nil { - panic(err) - } + require.NoError(r, err) // restart ZetaClient to pick up the new chain r.Logger.Print("🔄 restarting ZetaClient to pick up the new chain") - if err := restartZetaClient(); err != nil { - panic(err) - } + require.NoError(r, restartZetaClient()) // wait 10 set for the chain to start time.Sleep(10 * time.Second) @@ -141,18 +123,14 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { txWithdraw, err := r.ETHZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), big.NewInt(10000000000000000)) if err == nil { receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txWithdraw, r.Logger, r.ReceiptTimeout) - if receipt.Status == 1 { - panic("withdraw should have failed on the previous chain") - } + utils.RequiredTxFailed(r, receipt) } // test cross-chain functionalities on the new network // we use a Go routine to manually mine blocks because Anvil network only mine blocks on tx by default // we need automatic block mining to get the necessary confirmations for the cross-chain functionalities stopMining, err := newRunner.AnvilMineBlocks(EVM2RPCURL, 3) - if err != nil { - panic(err) - } + require.NoError(r, err) // deposit Ethers and ERC20 on ZetaChain etherAmount := big.NewInt(1e18) @@ -166,14 +144,7 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { tx := newRunner.WithdrawZeta(amount, true) cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "zeta withdraw") - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { - panic(fmt.Errorf( - "expected cctx status to be %s; got %s, message %s", - crosschaintypes.CctxStatus_OutboundMined, - cctx.CctxStatus.Status.String(), - cctx.CctxStatus.StatusMessage, - )) - } + utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) TestEtherWithdraw(newRunner, []string{"50000000000000000"}) @@ -193,32 +164,24 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { 18, 100000, )) - if err != nil { - panic(err) - } + require.NoError(r, err) // retrieve zrc20 and cctx from event whitelistCCTXIndex, err := txserver.FetchAttributeFromTxResponse(res, "whitelist_cctx_index") - if err != nil { - panic(err) - } + require.NoError(r, err) erc20zrc20Addr, err := txserver.FetchAttributeFromTxResponse(res, "zrc20_address") - if err != nil { - panic(err) - } + require.NoError(r, err) // wait for the whitelist cctx to be mined newRunner.WaitForMinedCCTXFromIndex(whitelistCCTXIndex) // set erc20 zrc20 contract address - if !ethcommon.IsHexAddress(erc20zrc20Addr) { - panic(fmt.Errorf("invalid contract address: %s", erc20zrc20Addr)) - } + require.True(r, ethcommon.IsHexAddress(erc20zrc20Addr), "invalid contract address: %s", erc20zrc20Addr) + erc20ZRC20, err := zrc20.NewZRC20(ethcommon.HexToAddress(erc20zrc20Addr), newRunner.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) + newRunner.ERC20ZRC20 = erc20ZRC20 // deposit ERC20 on ZetaChain diff --git a/e2e/e2etests/test_pause_zrc20.go b/e2e/e2etests/test_pause_zrc20.go index dbe5182e80..1495a7ac60 100644 --- a/e2e/e2etests/test_pause_zrc20.go +++ b/e2e/e2etests/test_pause_zrc20.go @@ -1,9 +1,10 @@ package e2etests import ( - "fmt" "math/big" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/contracts/vault" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -16,26 +17,20 @@ func TestPauseZRC20(r *runner.E2ERunner, _ []string) { // Setup vault used to test zrc20 interactions r.Logger.Info("Deploying vault") vaultAddr, _, vaultContract, err := vault.DeployVault(r.ZEVMAuth, r.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) + // Approving vault to spend ZRC20 tx, err := r.ETHZRC20.Approve(r.ZEVMAuth, vaultAddr, big.NewInt(1e18)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("Vault approval should succeed") - } + utils.RequireTxSuccessful(r, receipt) + tx, err = r.ERC20ZRC20.Approve(r.ZEVMAuth, vaultAddr, big.NewInt(1e18)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("Vault approval should succeed") - } + utils.RequireTxSuccessful(r, receipt) // Pause ETH ZRC20 r.Logger.Info("Pausing ETH") @@ -44,86 +39,68 @@ func TestPauseZRC20(r *runner.E2ERunner, _ []string) { []string{r.ETHZRC20Addr.Hex()}, ) res, err := r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, msgPause) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("pause zrc20 tx hash: %s", res.TxHash) // Fetch and check pause status fcRes, err := r.FungibleClient.ForeignCoins(r.Ctx, &fungibletypes.QueryGetForeignCoinsRequest{ Index: r.ETHZRC20Addr.Hex(), }) - if err != nil { - panic(err) - } - if !fcRes.GetForeignCoins().Paused { - panic("ETH should be paused") - } + require.NoError(r, err) + require.True(r, fcRes.GetForeignCoins().Paused, "ETH should be paused") + r.Logger.Info("ETH is paused") // Try operations with ETH ZRC20 r.Logger.Info("Can no longer do operations on ETH ZRC20") + tx, err = r.ETHZRC20.Transfer(r.ZEVMAuth, sample.EthAddress(), big.NewInt(1e5)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 1 { - panic("transfer should fail") - } + utils.RequiredTxFailed(r, receipt) + tx, err = r.ETHZRC20.Burn(r.ZEVMAuth, big.NewInt(1e5)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 1 { - panic("burn should fail") - } + utils.RequiredTxFailed(r, receipt) // Operation on a contract that interact with ETH ZRC20 should fail r.Logger.Info("Vault contract can no longer interact with ETH ZRC20: %s", r.ETHZRC20Addr.Hex()) tx, err = vaultContract.Deposit(r.ZEVMAuth, r.ETHZRC20Addr, big.NewInt(1e5)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 1 { - panic("deposit should fail") - } + utils.RequiredTxFailed(r, receipt) + r.Logger.Info("Operations all failed") // Check we can still interact with ERC20 ZRC20 r.Logger.Info("Check other ZRC20 can still be operated") + tx, err = r.ERC20ZRC20.Transfer(r.ZEVMAuth, sample.EthAddress(), big.NewInt(1e3)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("ERC20 ZRC20 transfer should succeed") - } + utils.RequireTxSuccessful(r, receipt) + tx, err = vaultContract.Deposit(r.ZEVMAuth, r.ERC20ZRC20Addr, big.NewInt(1e3)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("ERC20 ZRC20 vault deposit should succeed") - } + utils.RequireTxSuccessful(r, receipt) // Check deposit revert when paused signedTx, err := r.SendEther(r.TSSAddress, big.NewInt(1e17), nil) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, signedTx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("deposit eth tx failed") - } + utils.RequireTxSuccessful(r, receipt) + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, signedTx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - if cctx.CctxStatus.Status != types.CctxStatus_Reverted { - panic(fmt.Sprintf("expected cctx status to be Reverted; got %s", cctx.CctxStatus.Status)) - } + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_Reverted) + r.Logger.Info("CCTX has been reverted") // Unpause ETH ZRC20 @@ -133,51 +110,40 @@ func TestPauseZRC20(r *runner.E2ERunner, _ []string) { []string{r.ETHZRC20Addr.Hex()}, ) res, err = r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, msgUnpause) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("unpause zrc20 tx hash: %s", res.TxHash) // Fetch and check pause status fcRes, err = r.FungibleClient.ForeignCoins(r.Ctx, &fungibletypes.QueryGetForeignCoinsRequest{ Index: r.ETHZRC20Addr.Hex(), }) - if err != nil { - panic(err) - } - if fcRes.GetForeignCoins().Paused { - panic("ETH should be unpaused") - } + require.NoError(r, err) + require.False(r, fcRes.GetForeignCoins().Paused, "ETH should be unpaused") + r.Logger.Info("ETH is unpaused") // Try operations with ETH ZRC20 r.Logger.Info("Can do operations on ETH ZRC20 again") + tx, err = r.ETHZRC20.Transfer(r.ZEVMAuth, sample.EthAddress(), big.NewInt(1e5)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("transfer should succeed") - } + utils.RequireTxSuccessful(r, receipt) + tx, err = r.ETHZRC20.Burn(r.ZEVMAuth, big.NewInt(1e5)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("burn should succeed") - } + utils.RequireTxSuccessful(r, receipt) // Can deposit tokens into the vault again tx, err = vaultContract.Deposit(r.ZEVMAuth, r.ETHZRC20Addr, big.NewInt(1e5)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("deposit should succeed") - } + utils.RequireTxSuccessful(r, receipt) r.Logger.Info("Operations all succeeded") } diff --git a/e2e/e2etests/test_rate_limiter.go b/e2e/e2etests/test_rate_limiter.go index db8d67f348..8b88dc28aa 100644 --- a/e2e/e2etests/test_rate_limiter.go +++ b/e2e/e2etests/test_rate_limiter.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "github.com/zeta-chain/zetacore/e2e/runner" @@ -55,47 +56,31 @@ func TestRateLimiter(r *runner.E2ERunner, _ []string) { erc20Amount := big.NewInt(1e6) // approve tokens for the tests - if err := approveTokens(r); err != nil { - panic(err) - } + require.NoError(r, approveTokens(r)) // add liquidity in the pool to prevent high slippage in WZETA/gas pair - if err := addZetaGasLiquidity(r); err != nil { - panic(err) - } + require.NoError(r, addZetaGasLiquidity(r)) // Set the rate limiter to 0.5ZETA per 10 blocks // These rate limiter flags will only allow to process 1 withdraw per 10 blocks r.Logger.Info("setting up rate limiter flags") - if err := setupRateLimiterFlags(r, rateLimiterFlags); err != nil { - panic(err) - } + require.NoError(r, setupRateLimiterFlags(r, rateLimiterFlags)) // Test with rate limiter // TODO: define proper assertion to check the rate limiter is working // https://github.com/zeta-chain/node/issues/2090 r.Logger.Print("rate limiter enabled") - if err := createAndWaitWithdraws(r, withdrawTypeZETA, zetaAmount); err != nil { - panic(err) - } - if err := createAndWaitWithdraws(r, withdrawTypeETH, ethAmount); err != nil { - panic(err) - } - if err := createAndWaitWithdraws(r, withdrawTypeERC20, erc20Amount); err != nil { - panic(err) - } + require.NoError(r, createAndWaitWithdraws(r, withdrawTypeZETA, zetaAmount)) + require.NoError(r, createAndWaitWithdraws(r, withdrawTypeZETA, ethAmount)) + require.NoError(r, createAndWaitWithdraws(r, withdrawTypeZETA, erc20Amount)) // Disable rate limiter r.Logger.Info("disabling rate limiter") - if err := setupRateLimiterFlags(r, crosschaintypes.RateLimiterFlags{Enabled: false}); err != nil { - panic(err) - } + require.NoError(r, setupRateLimiterFlags(r, crosschaintypes.RateLimiterFlags{Enabled: false})) // Test without rate limiter again and try again ZETA withdraws r.Logger.Print("rate limiter disabled") - if err := createAndWaitWithdraws(r, withdrawTypeZETA, zetaAmount); err != nil { - panic(err) - } + require.NoError(r, createAndWaitWithdraws(r, withdrawTypeZETA, zetaAmount)) } // createAndWaitWithdraws performs RateLimiterWithdrawNumber withdraws diff --git a/e2e/e2etests/test_stress_btc_deposit.go b/e2e/e2etests/test_stress_btc_deposit.go index 51e1b8857f..b6c3e7c6a8 100644 --- a/e2e/e2etests/test_stress_btc_deposit.go +++ b/e2e/e2etests/test_stress_btc_deposit.go @@ -2,10 +2,10 @@ package e2etests import ( "fmt" - "strconv" "time" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "github.com/zeta-chain/zetacore/e2e/runner" @@ -15,19 +15,10 @@ import ( // TestStressBTCDeposit tests the stressing deposit of BTC func TestStressBTCDeposit(r *runner.E2ERunner, args []string) { - if len(args) != 2 { - panic("TestStressBTCDeposit requires exactly two arguments: the deposit amount and the number of deposits.") - } + require.Len(r, args, 2) - depositAmount, err := strconv.ParseFloat(args[1], 64) - if err != nil { - panic("Invalid deposit amount specified for TestStressBTCDeposit.") - } - - numDeposits, err := strconv.Atoi(args[1]) - if err != nil || numDeposits < 1 { - panic("Invalid number of deposits specified for TestStressBTCDeposit.") - } + depositAmount := parseFloat(r, args[0]) + numDeposits := parseInt(r, args[1]) r.SetBtcAddress(r.Name, false) @@ -42,15 +33,10 @@ func TestStressBTCDeposit(r *runner.E2ERunner, args []string) { txHash := r.DepositBTCWithAmount(depositAmount) r.Logger.Print("index %d: starting deposit, tx hash: %s", i, txHash.String()) - eg.Go(func() error { - return monitorBTCDeposit(r, txHash, i, time.Now()) - }) + eg.Go(func() error { return monitorBTCDeposit(r, txHash, i, time.Now()) }) } - // wait for all the deposits to complete - if err := eg.Wait(); err != nil { - panic(err) - } + require.NoError(r, eg.Wait()) r.Logger.Print("all deposits completed") } diff --git a/e2e/e2etests/test_stress_btc_withdraw.go b/e2e/e2etests/test_stress_btc_withdraw.go index 28ccb77178..08c5844448 100644 --- a/e2e/e2etests/test_stress_btc_withdraw.go +++ b/e2e/e2etests/test_stress_btc_withdraw.go @@ -3,11 +3,11 @@ package e2etests import ( "fmt" "math/big" - "strconv" "time" "github.com/btcsuite/btcutil" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "github.com/zeta-chain/zetacore/e2e/runner" @@ -17,21 +17,10 @@ import ( // TestStressBTCWithdraw tests the stressing withdraw of btc func TestStressBTCWithdraw(r *runner.E2ERunner, args []string) { - if len(args) != 2 { - panic( - "TestStressBTCWithdraw requires exactly two arguments: the withdrawal amount and the number of withdrawals.", - ) - } - - withdrawalAmount, err := strconv.ParseFloat(args[0], 64) - if err != nil { - panic("Invalid withdrawal amount specified for TestStressBTCWithdraw.") - } + require.Len(r, args, 2) - numWithdraws, err := strconv.Atoi(args[1]) - if err != nil || numWithdraws < 1 { - panic("Invalid number of withdrawals specified for TestStressBTCWithdraw.") - } + withdrawalAmount := parseFloat(r, args[0]) + numWithdraws := parseInt(r, args[1]) r.SetBtcAddress(r.Name, false) @@ -41,9 +30,7 @@ func TestStressBTCWithdraw(r *runner.E2ERunner, args []string) { var eg errgroup.Group satAmount, err := btcutil.NewAmount(withdrawalAmount) - if err != nil { - panic(err) - } + require.NoError(r, err) // send the withdraws for i := 0; i < numWithdraws; i++ { @@ -53,25 +40,16 @@ func TestStressBTCWithdraw(r *runner.E2ERunner, args []string) { []byte(r.BTCDeployerAddress.EncodeAddress()), big.NewInt(int64(satAmount)), ) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - //r.Logger.Info("index %d: withdraw evm tx failed", index) - panic(fmt.Sprintf("index %d: withdraw btc tx %s failed", i, tx.Hash().Hex())) - } + utils.RequireTxSuccessful(r, receipt) r.Logger.Print("index %d: starting withdraw, tx hash: %s", i, tx.Hash().Hex()) - eg.Go(func() error { - return monitorBTCWithdraw(r, tx, i, time.Now()) - }) + eg.Go(func() error { return monitorBTCWithdraw(r, tx, i, time.Now()) }) } - // wait for all the withdraws to complete - if err := eg.Wait(); err != nil { - panic(err) - } + require.NoError(r, eg.Wait()) r.Logger.Print("all withdraws completed") } diff --git a/e2e/e2etests/test_stress_eth_deposit.go b/e2e/e2etests/test_stress_eth_deposit.go index f3b1e94dc8..9e0208f7e3 100644 --- a/e2e/e2etests/test_stress_eth_deposit.go +++ b/e2e/e2etests/test_stress_eth_deposit.go @@ -3,10 +3,10 @@ package e2etests import ( "fmt" "math/big" - "strconv" "time" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "github.com/zeta-chain/zetacore/e2e/runner" @@ -16,19 +16,12 @@ import ( // TestStressEtherDeposit tests the stressing deposit of ether func TestStressEtherDeposit(r *runner.E2ERunner, args []string) { - if len(args) != 2 { - panic("TestStressEtherDeposit requires exactly two arguments: the deposit amount and the number of deposits.") - } + require.Len(r, args, 2) depositAmount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid deposit amount specified for TestMultipleERC20Deposit.") - } + require.True(r, ok) - numDeposits, err := strconv.Atoi(args[1]) - if err != nil || numDeposits < 1 { - panic("Invalid number of deposits specified for TestStressEtherDeposit.") - } + numDeposits := parseInt(r, args[1]) r.Logger.Print("starting stress test of %d deposits", numDeposits) @@ -41,15 +34,10 @@ func TestStressEtherDeposit(r *runner.E2ERunner, args []string) { hash := r.DepositEtherWithAmount(false, depositAmount) r.Logger.Print("index %d: starting deposit, tx hash: %s", i, hash.Hex()) - eg.Go(func() error { - return monitorEtherDeposit(r, hash, i, time.Now()) - }) + eg.Go(func() error { return monitorEtherDeposit(r, hash, i, time.Now()) }) } - // wait for all the deposits to complete - if err := eg.Wait(); err != nil { - panic(err) - } + require.NoError(r, eg.Wait()) r.Logger.Print("all deposits completed") } diff --git a/e2e/e2etests/test_stress_eth_withdraw.go b/e2e/e2etests/test_stress_eth_withdraw.go index 7f73e863a0..3a67ca8f94 100644 --- a/e2e/e2etests/test_stress_eth_withdraw.go +++ b/e2e/e2etests/test_stress_eth_withdraw.go @@ -7,6 +7,7 @@ import ( "time" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "github.com/zeta-chain/zetacore/e2e/runner" @@ -16,26 +17,18 @@ import ( // TestStressEtherWithdraw tests the stressing withdraw of ether func TestStressEtherWithdraw(r *runner.E2ERunner, args []string) { - if len(args) != 2 { - panic( - "TestStressEtherWithdraw requires exactly two arguments: the withdrawal amount and the number of withdrawals.", - ) - } + require.Len(r, args, 2) withdrawalAmount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid withdrawal amount specified for TestStressEtherWithdraw.") - } + require.True(r, ok, "Invalid withdrawal amount specified for TestStressEtherWithdraw.") numWithdraws, err := strconv.Atoi(args[1]) - if err != nil || numWithdraws < 1 { - panic("Invalid number of withdrawals specified for TestStressEtherWithdraw.") - } + require.NoError(r, err) + require.GreaterOrEqual(r, numWithdraws, 1) tx, err := r.ETHZRC20.Approve(r.ZEVMAuth, r.ETHZRC20Addr, big.NewInt(1e18)) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.WaitForTxReceiptOnZEVM(tx) r.Logger.Print("starting stress test of %d withdraws", numWithdraws) @@ -46,15 +39,13 @@ func TestStressEtherWithdraw(r *runner.E2ERunner, args []string) { // send the withdraws for i := 0; i < numWithdraws; i++ { i := i + tx, err := r.ETHZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), withdrawalAmount) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - //r.Logger.Info("index %d: withdraw evm tx failed", index) - panic(fmt.Sprintf("index %d: withdraw evm tx %s failed", i, tx.Hash().Hex())) - } + utils.RequireTxSuccessful(r, receipt) + r.Logger.Print("index %d: starting withdraw, tx hash: %s", i, tx.Hash().Hex()) eg.Go(func() error { @@ -62,10 +53,7 @@ func TestStressEtherWithdraw(r *runner.E2ERunner, args []string) { }) } - // wait for all the withdraws to complete - if err := eg.Wait(); err != nil { - panic(err) - } + require.NoError(r, eg.Wait()) r.Logger.Print("all withdraws completed") } diff --git a/e2e/e2etests/test_update_bytecode_connector.go b/e2e/e2etests/test_update_bytecode_connector.go index 6b88e14972..73786f2971 100644 --- a/e2e/e2etests/test_update_bytecode_connector.go +++ b/e2e/e2etests/test_update_bytecode_connector.go @@ -1,10 +1,10 @@ package e2etests import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testconnectorzevm" "github.com/zeta-chain/zetacore/e2e/runner" @@ -18,17 +18,12 @@ func TestUpdateBytecodeConnector(r *runner.E2ERunner, _ []string) { // Can withdraw 10ZETA amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) r.DepositAndApproveWZeta(amount) + tx := r.WithdrawZeta(amount, true) cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) + r.Logger.CCTX(*cctx, "zeta withdraw") - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { - panic(fmt.Errorf( - "expected cctx status to be %s; got %s, message %s", - crosschaintypes.CctxStatus_OutboundMined, - cctx.CctxStatus.Status.String(), - cctx.CctxStatus.StatusMessage, - )) - } // Deploy the test contract newTestConnectorAddr, tx, _, err := testconnectorzevm.DeployTestZetaConnectorZEVM( @@ -36,23 +31,17 @@ func TestUpdateBytecodeConnector(r *runner.E2ERunner, _ []string) { r.ZEVMClient, r.WZetaAddr, ) - if err != nil { - panic(err) - } + require.NoError(r, err) // Wait for the contract to be deployed receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("contract deployment failed") - } + utils.RequireTxSuccessful(r, receipt) // Get the code hash of the new contract codeHashRes, err := r.FungibleClient.CodeHash(r.Ctx, &fungibletypes.QueryCodeHashRequest{ Address: newTestConnectorAddr.String(), }) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("New contract code hash: %s", codeHashRes.CodeHash) r.Logger.Info("Updating the bytecode of the Connector") @@ -62,37 +51,21 @@ func TestUpdateBytecodeConnector(r *runner.E2ERunner, _ []string) { codeHashRes.CodeHash, ) res, err := r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, msg) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("Update connector bytecode tx hash: %s", res.TxHash) r.Logger.Info("Can interact with the new code of the contract") testConnectorContract, err := testconnectorzevm.NewTestZetaConnectorZEVM(r.ConnectorZEVMAddr, r.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) response, err := testConnectorContract.Foo(&bind.CallOpts{}) - if err != nil { - panic(err) - } - - if response != "foo" { - panic("unexpected response") - } + require.NoError(r, err) + require.Equal(r, "foo", response) // Can continue to interact with the connector: withdraw 10ZETA r.DepositAndApproveWZeta(amount) tx = r.WithdrawZeta(amount, true) cctx = utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "zeta withdraw") - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { - panic(fmt.Errorf( - "expected cctx status to be %s; got %s, message %s", - crosschaintypes.CctxStatus_OutboundMined, - cctx.CctxStatus.Status.String(), - cctx.CctxStatus.StatusMessage, - )) - } + utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) } diff --git a/e2e/e2etests/test_update_bytecode_zrc20.go b/e2e/e2etests/test_update_bytecode_zrc20.go index 4762ec94bb..ba914655d1 100644 --- a/e2e/e2etests/test_update_bytecode_zrc20.go +++ b/e2e/e2etests/test_update_bytecode_zrc20.go @@ -4,6 +4,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/contracts/testzrc20" "github.com/zeta-chain/zetacore/e2e/runner" @@ -18,13 +19,10 @@ func TestUpdateBytecodeZRC20(r *runner.E2ERunner, _ []string) { // Random approval approved := sample.EthAddress() tx, err := r.ETHZRC20.Approve(r.ZEVMAuth, approved, big.NewInt(1e10)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("approval failed") - } + utils.RequireTxSuccessful(r, receipt) // Deploy the TestZRC20 contract r.Logger.Info("Deploying contract with new bytecode") @@ -35,50 +33,38 @@ func TestUpdateBytecodeZRC20(r *runner.E2ERunner, _ []string) { // #nosec G701 test - always in range uint8(coin.CoinType_Gas), ) - if err != nil { - panic(err) - } + require.NoError(r, err) // Wait for the contract to be deployed receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("contract deployment failed") - } + utils.RequireTxSuccessful(r, receipt) // Get the code hash of the new contract codeHashRes, err := r.FungibleClient.CodeHash(r.Ctx, &fungibletypes.QueryCodeHashRequest{ Address: newZRC20Address.String(), }) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("New contract code hash: %s", codeHashRes.CodeHash) // Get current info of the ZRC20 name, err := r.ETHZRC20.Name(&bind.CallOpts{}) - if err != nil { - panic(err) - } + require.NoError(r, err) + symbol, err := r.ETHZRC20.Symbol(&bind.CallOpts{}) - if err != nil { - panic(err) - } + require.NoError(r, err) + decimals, err := r.ETHZRC20.Decimals(&bind.CallOpts{}) - if err != nil { - panic(err) - } + require.NoError(r, err) + totalSupply, err := r.ETHZRC20.TotalSupply(&bind.CallOpts{}) - if err != nil { - panic(err) - } + require.NoError(r, err) + balance, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) + approval, err := r.ETHZRC20.Allowance(&bind.CallOpts{}, r.DeployerAddress, approved) - if err != nil { - panic(err) - } + require.NoError(r, err) r.Logger.Info("Updating the bytecode of the ZRC20") msg := fungibletypes.NewMsgUpdateContractBytecode( @@ -87,116 +73,75 @@ func TestUpdateBytecodeZRC20(r *runner.E2ERunner, _ []string) { codeHashRes.CodeHash, ) res, err := r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, msg) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("Update zrc20 bytecode tx hash: %s", res.TxHash) // Get new info of the ZRC20 r.Logger.Info("Checking the state of the ZRC20 remains the same") newName, err := r.ETHZRC20.Name(&bind.CallOpts{}) - if err != nil { - panic(err) - } - if name != newName { - panic("name shouldn't change upon bytecode update") - } + require.NoError(r, err) + require.Equal(r, name, newName) + newSymbol, err := r.ETHZRC20.Symbol(&bind.CallOpts{}) - if err != nil { - panic(err) - } - if symbol != newSymbol { - panic("symbol shouldn't change upon bytecode update") - } + require.NoError(r, err) + require.Equal(r, symbol, newSymbol) + newDecimals, err := r.ETHZRC20.Decimals(&bind.CallOpts{}) - if err != nil { - panic(err) - } - if decimals != newDecimals { - panic("decimals shouldn't change upon bytecode update") - } + require.NoError(r, err) + require.Equal(r, decimals, newDecimals) + newTotalSupply, err := r.ETHZRC20.TotalSupply(&bind.CallOpts{}) - if err != nil { - panic(err) - } - if totalSupply.Cmp(newTotalSupply) != 0 { - panic("total supply shouldn't change upon bytecode update") - } + require.NoError(r, err) + require.Equal(r, 0, totalSupply.Cmp(newTotalSupply)) + newBalance, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } - if balance.Cmp(newBalance) != 0 { - panic("balance shouldn't change upon bytecode update") - } + require.NoError(r, err) + require.Equal(r, 0, balance.Cmp(newBalance)) + newApproval, err := r.ETHZRC20.Allowance(&bind.CallOpts{}, r.DeployerAddress, approved) - if err != nil { - panic(err) - } - if approval.Cmp(newApproval) != 0 { - panic("approval shouldn't change upon bytecode update") - } + require.NoError(r, err) + require.Equal(r, 0, approval.Cmp(newApproval)) r.Logger.Info("Can interact with the new code of the contract") + testZRC20Contract, err := testzrc20.NewTestZRC20(r.ETHZRC20Addr, r.ZEVMClient) - if err != nil { - panic(err) - } + require.NoError(r, err) + tx, err = testZRC20Contract.UpdateNewField(r.ZEVMAuth, big.NewInt(1e10)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("update new field failed") - } + utils.RequireTxSuccessful(r, receipt) + newField, err := testZRC20Contract.NewField(&bind.CallOpts{}) - if err != nil { - panic(err) - } - if newField.Cmp(big.NewInt(1e10)) != 0 { - panic("new field value mismatch") - } + require.NoError(r, err) + require.Equal(r, 0, newField.Cmp(big.NewInt(1e10))) r.Logger.Info("Interacting with the bytecode contract doesn't disrupt the zrc20 contract") tx, err = newZRC20Contract.UpdateNewField(r.ZEVMAuth, big.NewInt(1e5)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("update new field failed") - } + utils.RequireTxSuccessful(r, receipt) + newField, err = newZRC20Contract.NewField(&bind.CallOpts{}) - if err != nil { - panic(err) - } - if newField.Cmp(big.NewInt(1e5)) != 0 { - panic("new field value mismatch on bytecode contract") - } + require.NoError(r, err) + require.Equal(r, 0, newField.Cmp(big.NewInt(1e5)), "new field value mismatch on bytecode contract") + newField, err = testZRC20Contract.NewField(&bind.CallOpts{}) - if err != nil { - panic(err) - } - if newField.Cmp(big.NewInt(1e10)) != 0 { - panic("new field value mismatch on zrc20 contract") - } + require.NoError(r, err) + require.Equal(r, 0, newField.Cmp(big.NewInt(1e10)), "new field value mismatch on zrc20 contract") // can continue to operate the ZRC20 r.Logger.Info("Checking the ZRC20 can continue to operate after state change") tx, err = r.ETHZRC20.Transfer(r.ZEVMAuth, approved, big.NewInt(1e14)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status != 1 { - panic("transfer failed") - } + utils.RequireTxSuccessful(r, receipt) + newBalance, err = r.ETHZRC20.BalanceOf(&bind.CallOpts{}, approved) - if err != nil { - panic(err) - } - if newBalance.Cmp(big.NewInt(1e14)) != 0 { - panic("balance not updated") - } + require.NoError(r, err) + require.Equal(r, 0, newBalance.Cmp(big.NewInt(1e14))) } diff --git a/e2e/e2etests/test_zeta_deposit.go b/e2e/e2etests/test_zeta_deposit.go index a6fa98dbcf..056ee5709f 100644 --- a/e2e/e2etests/test_zeta_deposit.go +++ b/e2e/e2etests/test_zeta_deposit.go @@ -3,19 +3,17 @@ package e2etests import ( "math/big" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" ) func TestZetaDeposit(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestZetaDeposit requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestZetaDeposit.") - } + require.True(r, ok, "Invalid amount specified for TestZetaDeposit.") hash := r.DepositZetaWithAmount(r.DeployerAddress, amount) diff --git a/e2e/e2etests/test_zeta_deposit_new_address.go b/e2e/e2etests/test_zeta_deposit_new_address.go index c0be712e33..047fbd7042 100644 --- a/e2e/e2etests/test_zeta_deposit_new_address.go +++ b/e2e/e2etests/test_zeta_deposit_new_address.go @@ -3,20 +3,18 @@ package e2etests import ( "math/big" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" "github.com/zeta-chain/zetacore/testutil/sample" ) func TestZetaDepositNewAddress(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestZetaDepositNewAddress requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestZetaDepositNewAddress.") - } + require.True(r, ok) newAddress := sample.EthAddress() hash := r.DepositZetaWithAmount(newAddress, amount) diff --git a/e2e/e2etests/test_zeta_deposit_restricted_address.go b/e2e/e2etests/test_zeta_deposit_restricted_address.go index e6a9d4f23b..d525a97d79 100644 --- a/e2e/e2etests/test_zeta_deposit_restricted_address.go +++ b/e2e/e2etests/test_zeta_deposit_restricted_address.go @@ -4,20 +4,17 @@ import ( "math/big" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/zetaclient/testutils" ) func TestZetaDepositRestricted(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestZetaDepositRestricted requires exactly one argument for the amount.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestZetaDepositRestricted.") - } + require.True(r, ok, "Invalid amount specified for TestZetaDepositRestricted.") // Deposit amount to restricted address r.DepositZetaWithAmount(ethcommon.HexToAddress(testutils.RestrictedEVMAddressTest), amount) diff --git a/e2e/e2etests/test_zeta_withdraw.go b/e2e/e2etests/test_zeta_withdraw.go index b46a403aa2..25b9d3d34a 100644 --- a/e2e/e2etests/test_zeta_withdraw.go +++ b/e2e/e2etests/test_zeta_withdraw.go @@ -1,35 +1,25 @@ package e2etests import ( - "fmt" "math/big" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) func TestZetaWithdraw(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestZetaWithdraw requires exactly one argument for the withdrawal.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("invalid amount specified") - } + require.True(r, ok) r.DepositAndApproveWZeta(amount) tx := r.WithdrawZeta(amount, true) cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "zeta withdraw") - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { - panic(fmt.Errorf( - "expected cctx status to be %s; got %s, message %s", - crosschaintypes.CctxStatus_OutboundMined, - cctx.CctxStatus.Status.String(), - cctx.CctxStatus.StatusMessage, - )) - } + utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) } diff --git a/e2e/e2etests/test_zeta_withdraw_bitcoin_revert.go b/e2e/e2etests/test_zeta_withdraw_bitcoin_revert.go index 151d140a97..ae34058c94 100644 --- a/e2e/e2etests/test_zeta_withdraw_bitcoin_revert.go +++ b/e2e/e2etests/test_zeta_withdraw_bitcoin_revert.go @@ -3,6 +3,7 @@ package e2etests import ( "math/big" + "github.com/stretchr/testify/require" connectorzevm "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zetaconnectorzevm.sol" "github.com/zeta-chain/zetacore/e2e/runner" @@ -11,40 +12,31 @@ import ( ) func TestZetaWithdrawBTCRevert(r *runner.E2ERunner, args []string) { - if len(args) != 1 { - panic("TestZetaWithdrawBTCRevert requires exactly one argument for the withdrawal.") - } + require.Len(r, args, 1) amount, ok := big.NewInt(0).SetString(args[0], 10) - if !ok { - panic("Invalid amount specified for TestZetaWithdrawBTCRevert.") - } + require.True(r, ok) r.ZEVMAuth.Value = amount tx, err := r.WZeta.Deposit(r.ZEVMAuth) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.ZEVMAuth.Value = big.NewInt(0) r.Logger.Info("Deposit tx hash: %s", tx.Hash().Hex()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.EVMReceipt(*receipt, "Deposit") - if receipt.Status != 1 { - panic("Deposit failed") - } + utils.RequireTxSuccessful(r, receipt) tx, err = r.WZeta.Approve(r.ZEVMAuth, r.ConnectorZEVMAddr, big.NewInt(1e18)) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("wzeta.approve tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequireTxSuccessful(r, receipt) + r.Logger.EVMReceipt(*receipt, "Approve") - if receipt.Status != 1 { - panic("Approve failed") - } lessThanAmount := amount.Div(amount, big.NewInt(10)) // 1/10 of amount tx, err = r.ConnectorZEVM.Send(r.ZEVMAuth, connectorzevm.ZetaInterfacesSendInput{ @@ -55,14 +47,12 @@ func TestZetaWithdrawBTCRevert(r *runner.E2ERunner, args []string) { ZetaValueAndGas: lessThanAmount, ZetaParams: nil, }) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("send tx hash: %s", tx.Hash().Hex()) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequiredTxFailed(r, receipt) + r.Logger.EVMReceipt(*receipt, "send") - if receipt.Status != 0 { - panic("Was able to send ZETA to BTC") - } } diff --git a/e2e/e2etests/test_zrc20_swap.go b/e2e/e2etests/test_zrc20_swap.go index 4dfea02cf1..661d2fc40f 100644 --- a/e2e/e2etests/test_zrc20_swap.go +++ b/e2e/e2etests/test_zrc20_swap.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" @@ -24,22 +25,19 @@ func TestZRC20Swap(r *runner.E2ERunner, _ []string) { } zrc20EthPair, err := r.UniswapV2Factory.GetPair(&bind.CallOpts{}, r.ERC20ZRC20Addr, r.ETHZRC20Addr) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("ZRC20-ETH pair receipt pair addr %s", zrc20EthPair.Hex()) tx, err = r.ERC20ZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, big.NewInt(1e18)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.Info("ERC20 ZRC20 approval receipt txhash %s status %d", receipt.TxHash, receipt.Status) tx, err = r.ETHZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, big.NewInt(1e18)) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.Info("ETH ZRC20 approval receipt txhash %s status %d", receipt.TxHash, receipt.Status) @@ -61,16 +59,14 @@ func TestZRC20Swap(r *runner.E2ERunner, _ []string) { r.DeployerAddress, big.NewInt(time.Now().Add(10*time.Minute).Unix()), ) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.Info("Add liquidity receipt txhash %s status %d", receipt.TxHash, receipt.Status) balETHBefore, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) + ethOutAmout := big.NewInt(1) tx, err = r.UniswapV2Router.SwapExactTokensForTokens( r.ZEVMAuth, @@ -80,18 +76,14 @@ func TestZRC20Swap(r *runner.E2ERunner, _ []string) { r.DeployerAddress, big.NewInt(time.Now().Add(10*time.Minute).Unix()), ) - if err != nil { - panic(err) - } + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.Info("Swap ERC20 ZRC20 for ETH ZRC20 %s status %d", receipt.TxHash, receipt.Status) balETHAfter, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) + ethDiff := big.NewInt(0).Sub(balETHAfter, balETHBefore) - if ethDiff.Cmp(ethOutAmout) < 0 { - panic("swap failed") - } + require.NotEqual(r, -1, ethDiff.Cmp(ethOutAmout), "swap failed") } diff --git a/e2e/runner/accounting.go b/e2e/runner/accounting.go index 31a53f9371..4992d46ad8 100644 --- a/e2e/runner/accounting.go +++ b/e2e/runner/accounting.go @@ -19,46 +19,46 @@ type Response struct { Amount Amount `json:"amount"` } -func (runner *E2ERunner) CheckZRC20ReserveAndSupply() error { - runner.Logger.Info("Checking ZRC20 Reserve and Supply") - if err := runner.checkEthTSSBalance(); err != nil { +func (r *E2ERunner) CheckZRC20ReserveAndSupply() error { + r.Logger.Info("Checking ZRC20 Reserve and Supply") + if err := r.checkEthTSSBalance(); err != nil { return err } - if err := runner.checkERC20TSSBalance(); err != nil { + if err := r.checkERC20TSSBalance(); err != nil { return err } - return runner.checkZetaTSSBalance() + return r.checkZetaTSSBalance() } -func (runner *E2ERunner) checkEthTSSBalance() error { - tssBal, err := runner.EVMClient.BalanceAt(runner.Ctx, runner.TSSAddress, nil) +func (r *E2ERunner) checkEthTSSBalance() error { + tssBal, err := r.EVMClient.BalanceAt(r.Ctx, r.TSSAddress, nil) if err != nil { return err } - zrc20Supply, err := runner.ETHZRC20.TotalSupply(&bind.CallOpts{}) + zrc20Supply, err := r.ETHZRC20.TotalSupply(&bind.CallOpts{}) if err != nil { return err } if tssBal.Cmp(zrc20Supply) < 0 { return fmt.Errorf("ETH: TSS balance (%d) < ZRC20 TotalSupply (%d) ", tssBal, zrc20Supply) } - runner.Logger.Info("ETH: TSS balance (%d) >= ZRC20 TotalSupply (%d)", tssBal, zrc20Supply) + r.Logger.Info("ETH: TSS balance (%d) >= ZRC20 TotalSupply (%d)", tssBal, zrc20Supply) return nil } -func (runner *E2ERunner) CheckBtcTSSBalance() error { - utxos, err := runner.BtcRPCClient.ListUnspent() +func (r *E2ERunner) CheckBtcTSSBalance() error { + utxos, err := r.BtcRPCClient.ListUnspent() if err != nil { return err } var btcBalance float64 for _, utxo := range utxos { - if utxo.Address == runner.BTCTSSAddress.EncodeAddress() { + if utxo.Address == r.BTCTSSAddress.EncodeAddress() { btcBalance += utxo.Amount } } - zrc20Supply, err := runner.BTCZRC20.TotalSupply(&bind.CallOpts{}) + zrc20Supply, err := r.BTCZRC20.TotalSupply(&bind.CallOpts{}) if err != nil { return err } @@ -75,7 +75,7 @@ func (runner *E2ERunner) CheckBtcTSSBalance() error { ) } // #nosec G701 test - always in range - runner.Logger.Info( + r.Logger.Info( "BTC: Balance (%d) >= ZRC20 TotalSupply (%d)", int64(btcBalance*1e8), zrc20Supply.Int64()-10000000, @@ -84,24 +84,24 @@ func (runner *E2ERunner) CheckBtcTSSBalance() error { return nil } -func (runner *E2ERunner) checkERC20TSSBalance() error { - erc20Balance, err := runner.ERC20.BalanceOf(&bind.CallOpts{}, runner.ERC20CustodyAddr) +func (r *E2ERunner) checkERC20TSSBalance() error { + erc20Balance, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.ERC20CustodyAddr) if err != nil { return err } - erc20zrc20Supply, err := runner.ERC20ZRC20.TotalSupply(&bind.CallOpts{}) + erc20zrc20Supply, err := r.ERC20ZRC20.TotalSupply(&bind.CallOpts{}) if err != nil { return err } if erc20Balance.Cmp(erc20zrc20Supply) < 0 { return fmt.Errorf("ERC20: TSS balance (%d) < ZRC20 TotalSupply (%d) ", erc20Balance, erc20zrc20Supply) } - runner.Logger.Info("ERC20: TSS balance (%d) >= ERC20 ZRC20 TotalSupply (%d)", erc20Balance, erc20zrc20Supply) + r.Logger.Info("ERC20: TSS balance (%d) >= ERC20 ZRC20 TotalSupply (%d)", erc20Balance, erc20zrc20Supply) return nil } -func (runner *E2ERunner) checkZetaTSSBalance() error { - zetaLocked, err := runner.ConnectorEth.GetLockedAmount(&bind.CallOpts{}) +func (r *E2ERunner) checkZetaTSSBalance() error { + zetaLocked, err := r.ConnectorEth.GetLockedAmount(&bind.CallOpts{}) if err != nil { return err } @@ -121,9 +121,9 @@ func (runner *E2ERunner) checkZetaTSSBalance() error { } zetaSupply, _ := big.NewInt(0).SetString(result.Amount.Amount, 10) if zetaLocked.Cmp(zetaSupply) < 0 { - runner.Logger.Info(fmt.Sprintf("ZETA: TSS balance (%d) < ZRC20 TotalSupply (%d)", zetaLocked, zetaSupply)) + r.Logger.Info(fmt.Sprintf("ZETA: TSS balance (%d) < ZRC20 TotalSupply (%d)", zetaLocked, zetaSupply)) } else { - runner.Logger.Info("ZETA: TSS balance (%d) >= ZRC20 TotalSupply (%d)", zetaLocked, zetaSupply) + r.Logger.Info("ZETA: TSS balance (%d) >= ZRC20 TotalSupply (%d)", zetaLocked, zetaSupply) } return nil } diff --git a/e2e/runner/balances.go b/e2e/runner/balances.go index 3e176bcb8d..8a0c37782a 100644 --- a/e2e/runner/balances.go +++ b/e2e/runner/balances.go @@ -31,39 +31,39 @@ type AccountBalancesDiff struct { } // GetAccountBalances returns the account balances of the accounts used in the E2E test -func (runner *E2ERunner) GetAccountBalances(skipBTC bool) (AccountBalances, error) { +func (r *E2ERunner) GetAccountBalances(skipBTC bool) (AccountBalances, error) { // zevm - zetaZeta, err := runner.ZEVMClient.BalanceAt(runner.Ctx, runner.DeployerAddress, nil) + zetaZeta, err := r.ZEVMClient.BalanceAt(r.Ctx, r.DeployerAddress, nil) if err != nil { return AccountBalances{}, err } - zetaWZeta, err := runner.WZeta.BalanceOf(&bind.CallOpts{}, runner.DeployerAddress) + zetaWZeta, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) if err != nil { return AccountBalances{}, err } - zetaEth, err := runner.ETHZRC20.BalanceOf(&bind.CallOpts{}, runner.DeployerAddress) + zetaEth, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) if err != nil { return AccountBalances{}, err } - zetaErc20, err := runner.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, runner.DeployerAddress) + zetaErc20, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) if err != nil { return AccountBalances{}, err } - zetaBtc, err := runner.BTCZRC20.BalanceOf(&bind.CallOpts{}, runner.DeployerAddress) + zetaBtc, err := r.BTCZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) if err != nil { return AccountBalances{}, err } // evm - evmEth, err := runner.EVMClient.BalanceAt(runner.Ctx, runner.DeployerAddress, nil) + evmEth, err := r.EVMClient.BalanceAt(r.Ctx, r.DeployerAddress, nil) if err != nil { return AccountBalances{}, err } - evmZeta, err := runner.ZetaEth.BalanceOf(&bind.CallOpts{}, runner.DeployerAddress) + evmZeta, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) if err != nil { return AccountBalances{}, err } - evmErc20, err := runner.ERC20.BalanceOf(&bind.CallOpts{}, runner.DeployerAddress) + evmErc20, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) if err != nil { return AccountBalances{}, err } @@ -71,7 +71,7 @@ func (runner *E2ERunner) GetAccountBalances(skipBTC bool) (AccountBalances, erro // bitcoin var BtcBTC string if !skipBTC { - if BtcBTC, err = runner.GetBitcoinBalance(); err != nil { + if BtcBTC, err = r.GetBitcoinBalance(); err != nil { return AccountBalances{}, err } } @@ -90,18 +90,18 @@ func (runner *E2ERunner) GetAccountBalances(skipBTC bool) (AccountBalances, erro } // GetBitcoinBalance returns the spendable BTC balance of the BTC address -func (runner *E2ERunner) GetBitcoinBalance() (string, error) { - addr, _, err := runner.GetBtcAddress() +func (r *E2ERunner) GetBitcoinBalance() (string, error) { + addr, _, err := r.GetBtcAddress() if err != nil { return "", fmt.Errorf("failed to get BTC address: %w", err) } - address, err := btcutil.DecodeAddress(addr, runner.BitcoinParams) + address, err := btcutil.DecodeAddress(addr, r.BitcoinParams) if err != nil { return "", fmt.Errorf("failed to decode BTC address: %w", err) } - total, err := runner.GetBitcoinBalanceByAddress(address) + total, err := r.GetBitcoinBalanceByAddress(address) if err != nil { return "", err } @@ -110,8 +110,8 @@ func (runner *E2ERunner) GetBitcoinBalance() (string, error) { } // GetBitcoinBalanceByAddress get btc balance by address. -func (runner *E2ERunner) GetBitcoinBalanceByAddress(address btcutil.Address) (btcutil.Amount, error) { - unspentList, err := runner.BtcRPCClient.ListUnspentMinMaxAddresses(1, 9999999, []btcutil.Address{address}) +func (r *E2ERunner) GetBitcoinBalanceByAddress(address btcutil.Address) (btcutil.Amount, error) { + unspentList, err := r.BtcRPCClient.ListUnspentMinMaxAddresses(1, 9999999, []btcutil.Address{address}) if err != nil { return 0, errors.Wrap(err, "failed to list unspent") } @@ -128,43 +128,43 @@ func (runner *E2ERunner) GetBitcoinBalanceByAddress(address btcutil.Address) (bt // PrintAccountBalances shows the account balances of the accounts used in the E2E test // Note: USDT is mentioned as erc20 here because we want to show the balance of any erc20 contract -func (runner *E2ERunner) PrintAccountBalances(balances AccountBalances) { - runner.Logger.Print(" ---💰 Account info %s ---", runner.DeployerAddress.Hex()) +func (r *E2ERunner) PrintAccountBalances(balances AccountBalances) { + r.Logger.Print(" ---💰 Account info %s ---", r.DeployerAddress.Hex()) // zevm - runner.Logger.Print("ZetaChain:") - runner.Logger.Print("* ZETA balance: %s", balances.ZetaZETA.String()) - runner.Logger.Print("* WZETA balance: %s", balances.ZetaWZETA.String()) - runner.Logger.Print("* ETH balance: %s", balances.ZetaETH.String()) - runner.Logger.Print("* ERC20 balance: %s", balances.ZetaERC20.String()) - runner.Logger.Print("* BTC balance: %s", balances.ZetaBTC.String()) + r.Logger.Print("ZetaChain:") + r.Logger.Print("* ZETA balance: %s", balances.ZetaZETA.String()) + r.Logger.Print("* WZETA balance: %s", balances.ZetaWZETA.String()) + r.Logger.Print("* ETH balance: %s", balances.ZetaETH.String()) + r.Logger.Print("* ERC20 balance: %s", balances.ZetaERC20.String()) + r.Logger.Print("* BTC balance: %s", balances.ZetaBTC.String()) // evm - runner.Logger.Print("EVM:") - runner.Logger.Print("* ZETA balance: %s", balances.EvmZETA.String()) - runner.Logger.Print("* ETH balance: %s", balances.EvmETH.String()) - runner.Logger.Print("* ERC20 balance: %s", balances.EvmERC20.String()) + r.Logger.Print("EVM:") + r.Logger.Print("* ZETA balance: %s", balances.EvmZETA.String()) + r.Logger.Print("* ETH balance: %s", balances.EvmETH.String()) + r.Logger.Print("* ERC20 balance: %s", balances.EvmERC20.String()) // bitcoin - runner.Logger.Print("Bitcoin:") - runner.Logger.Print("* BTC balance: %s", balances.BtcBTC) + r.Logger.Print("Bitcoin:") + r.Logger.Print("* BTC balance: %s", balances.BtcBTC) return } // PrintTotalDiff shows the difference in the account balances of the accounts used in the e2e test from two balances structs -func (runner *E2ERunner) PrintTotalDiff(accoutBalancesDiff AccountBalancesDiff) { - runner.Logger.Print(" ---💰 Total gas spent ---") +func (r *E2ERunner) PrintTotalDiff(accoutBalancesDiff AccountBalancesDiff) { + r.Logger.Print(" ---💰 Total gas spent ---") // show the value only if it is not zero if accoutBalancesDiff.ZETA.Cmp(big.NewInt(0)) != 0 { - runner.Logger.Print("* ZETA spent: %s", accoutBalancesDiff.ZETA.String()) + r.Logger.Print("* ZETA spent: %s", accoutBalancesDiff.ZETA.String()) } if accoutBalancesDiff.ETH.Cmp(big.NewInt(0)) != 0 { - runner.Logger.Print("* ETH spent: %s", accoutBalancesDiff.ETH.String()) + r.Logger.Print("* ETH spent: %s", accoutBalancesDiff.ETH.String()) } if accoutBalancesDiff.ERC20.Cmp(big.NewInt(0)) != 0 { - runner.Logger.Print("* ERC20 spent: %s", accoutBalancesDiff.ERC20.String()) + r.Logger.Print("* ERC20 spent: %s", accoutBalancesDiff.ERC20.String()) } } diff --git a/e2e/runner/bitcoin.go b/e2e/runner/bitcoin.go index b2b82d2132..c096bfc748 100644 --- a/e2e/runner/bitcoin.go +++ b/e2e/runner/bitcoin.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/hex" "fmt" - "math/big" "time" "github.com/btcsuite/btcd/btcjson" @@ -30,19 +29,19 @@ import ( var blockHeaderBTCTimeout = 5 * time.Minute // ListDeployerUTXOs list the deployer's UTXOs -func (runner *E2ERunner) ListDeployerUTXOs() ([]btcjson.ListUnspentResult, error) { +func (r *E2ERunner) ListDeployerUTXOs() ([]btcjson.ListUnspentResult, error) { // query UTXOs from node - utxos, err := runner.BtcRPCClient.ListUnspentMinMaxAddresses( + utxos, err := r.BtcRPCClient.ListUnspentMinMaxAddresses( 1, 9999999, - []btcutil.Address{runner.BTCDeployerAddress}, + []btcutil.Address{r.BTCDeployerAddress}, ) if err != nil { return nil, err } // filter big-enough UTXOs for test if running on Regtest - if runner.IsLocalBitcoin() { + if r.IsLocalBitcoin() { utxosFiltered := []btcjson.ListUnspentResult{} for _, utxo := range utxos { if utxo.Amount >= 1.0 { @@ -56,14 +55,12 @@ func (runner *E2ERunner) ListDeployerUTXOs() ([]btcjson.ListUnspentResult, error } // DepositBTCWithAmount deposits BTC on ZetaChain with a specific amount -func (runner *E2ERunner) DepositBTCWithAmount(amount float64) (txHash *chainhash.Hash) { - runner.Logger.Print("⏳ depositing BTC into ZEVM") +func (r *E2ERunner) DepositBTCWithAmount(amount float64) *chainhash.Hash { + r.Logger.Print("⏳ depositing BTC into ZEVM") // list deployer utxos - utxos, err := runner.ListDeployerUTXOs() - if err != nil { - panic(err) - } + utxos, err := r.ListDeployerUTXOs() + require.NoError(r, err) spendableAmount := 0.0 spendableUTXOs := 0 @@ -74,42 +71,33 @@ func (runner *E2ERunner) DepositBTCWithAmount(amount float64) (txHash *chainhash } } - if spendableAmount < amount { - panic(fmt.Errorf( - "not enough spendable BTC to run the test; have %f, require %f", - spendableAmount, - amount, - )) - } + require.LessOrEqual(r, amount, spendableAmount, "not enough spendable BTC to run the test") - runner.Logger.Info("ListUnspent:") - runner.Logger.Info(" spendableAmount: %f", spendableAmount) - runner.Logger.Info(" spendableUTXOs: %d", spendableUTXOs) - runner.Logger.Info("Now sending two txs to TSS address...") + r.Logger.Info("ListUnspent:") + r.Logger.Info(" spendableAmount: %f", spendableAmount) + r.Logger.Info(" spendableUTXOs: %d", spendableUTXOs) + r.Logger.Info("Now sending two txs to TSS address...") - amount = amount + zetabitcoin.DefaultDepositorFee - txHash, err = runner.SendToTSSFromDeployerToDeposit(amount, utxos) - if err != nil { - panic(err) - } - runner.Logger.Info("send BTC to TSS txHash: %s", txHash.String()) + amount += zetabitcoin.DefaultDepositorFee + txHash, err := r.SendToTSSFromDeployerToDeposit(amount, utxos) + require.NoError(r, err) + + r.Logger.Info("send BTC to TSS txHash: %s", txHash.String()) return txHash } // DepositBTC deposits BTC on ZetaChain -func (runner *E2ERunner) DepositBTC(testHeader bool) { - runner.Logger.Print("⏳ depositing BTC into ZEVM") +func (r *E2ERunner) DepositBTC(testHeader bool) { + r.Logger.Print("⏳ depositing BTC into ZEVM") startTime := time.Now() defer func() { - runner.Logger.Print("✅ BTC deposited in %s", time.Since(startTime)) + r.Logger.Print("✅ BTC deposited in %s", time.Since(startTime)) }() // list deployer utxos - utxos, err := runner.ListDeployerUTXOs() - if err != nil { - panic(err) - } + utxos, err := r.ListDeployerUTXOs() + require.NoError(r, err) spendableAmount := 0.0 spendableUTXOs := 0 @@ -120,85 +108,66 @@ func (runner *E2ERunner) DepositBTC(testHeader bool) { } } - if spendableAmount < 1.15 { - panic(fmt.Errorf("not enough spendable BTC to run the test; have %f", spendableAmount)) - } - if spendableUTXOs < 5 { - panic(fmt.Errorf("not enough spendable BTC UTXOs to run the test; have %d", spendableUTXOs)) - } + require.GreaterOrEqual(r, spendableAmount, 1.15, "not enough spendable BTC to run the test") + require.GreaterOrEqual(r, spendableUTXOs, 5, "not enough spendable BTC UTXOs to run the test") - runner.Logger.Info("ListUnspent:") - runner.Logger.Info(" spendableAmount: %f", spendableAmount) - runner.Logger.Info(" spendableUTXOs: %d", spendableUTXOs) - runner.Logger.Info("Now sending two txs to TSS address...") + r.Logger.Info("ListUnspent:") + r.Logger.Info(" spendableAmount: %f", spendableAmount) + r.Logger.Info(" spendableUTXOs: %d", spendableUTXOs) + r.Logger.Info("Now sending two txs to TSS address...") // send two transactions to the TSS address amount1 := 1.1 + zetabitcoin.DefaultDepositorFee - txHash1, err := runner.SendToTSSFromDeployerToDeposit(amount1, utxos[:2]) - if err != nil { - panic(err) - } + txHash1, err := r.SendToTSSFromDeployerToDeposit(amount1, utxos[:2]) + require.NoError(r, err) + amount2 := 0.05 + zetabitcoin.DefaultDepositorFee - txHash2, err := runner.SendToTSSFromDeployerToDeposit(amount2, utxos[2:4]) - if err != nil { - panic(err) - } + txHash2, err := r.SendToTSSFromDeployerToDeposit(amount2, utxos[2:4]) + require.NoError(r, err) // send a donation to the TSS address to compensate for the funds minted automatically during pool creation // and prevent accounting errors - _, err = runner.SendToTSSFromDeployerWithMemo(0.11, utxos[4:5], []byte(constant.DonationMessage)) - if err != nil { - panic(err) - } + _, err = r.SendToTSSFromDeployerWithMemo(0.11, utxos[4:5], []byte(constant.DonationMessage)) + require.NoError(r, err) - runner.Logger.Info("testing if the deposit into BTC ZRC20 is successful...") + r.Logger.Info("testing if the deposit into BTC ZRC20 is successful...") cctx := utils.WaitCctxMinedByInboundHash( - runner.Ctx, + r.Ctx, txHash2.String(), - runner.CctxClient, - runner.Logger, - runner.CctxTimeout, + r.CctxClient, + r.Logger, + r.CctxTimeout, ) - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { - panic(fmt.Sprintf( - "expected mined status; got %s, message: %s", - cctx.CctxStatus.Status.String(), - cctx.CctxStatus.StatusMessage), - ) - } + utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) - balance, err := runner.BTCZRC20.BalanceOf(&bind.CallOpts{}, runner.DeployerAddress) - if err != nil { - panic(err) - } - if balance.Cmp(big.NewInt(0)) != 1 { - panic("balance should be positive") - } + balance, err := r.BTCZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + require.NoError(r, err) + require.Equal(r, 1, balance.Sign(), "balance should be positive") // due to the high block throughput in localnet, ZetaClient might catch up slowly with the blocks // to optimize block header proof test, this test is directly executed here on the first deposit instead of having a separate test if testHeader { - runner.ProveBTCTransaction(txHash1) + r.ProveBTCTransaction(txHash1) } } -func (runner *E2ERunner) SendToTSSFromDeployerToDeposit(amount float64, inputUTXOs []btcjson.ListUnspentResult) ( +func (r *E2ERunner) SendToTSSFromDeployerToDeposit(amount float64, inputUTXOs []btcjson.ListUnspentResult) ( *chainhash.Hash, error, ) { - return runner.SendToTSSFromDeployerWithMemo(amount, inputUTXOs, runner.DeployerAddress.Bytes()) + return r.SendToTSSFromDeployerWithMemo(amount, inputUTXOs, r.DeployerAddress.Bytes()) } -func (runner *E2ERunner) SendToTSSFromDeployerWithMemo( +func (r *E2ERunner) SendToTSSFromDeployerWithMemo( amount float64, inputUTXOs []btcjson.ListUnspentResult, memo []byte, ) (*chainhash.Hash, error) { - btcRPC := runner.BtcRPCClient - to := runner.BTCTSSAddress - btcDeployerAddress := runner.BTCDeployerAddress - require.NotNil(runner, runner.BTCDeployerAddress, "btcDeployerAddress is nil") + btcRPC := r.BtcRPCClient + to := r.BTCTSSAddress + btcDeployerAddress := r.BTCDeployerAddress + require.NotNil(r, r.BTCDeployerAddress, "btcDeployerAddress is nil") // prepare inputs inputs := make([]btcjson.TransactionInput, len(inputUTXOs)) @@ -229,38 +198,32 @@ func (runner *E2ERunner) SendToTSSFromDeployerWithMemo( } // create raw - runner.Logger.Info("ADDRESS: %s, %s", btcDeployerAddress.EncodeAddress(), to.EncodeAddress()) + r.Logger.Info("ADDRESS: %s, %s", btcDeployerAddress.EncodeAddress(), to.EncodeAddress()) tx, err := btcRPC.CreateRawTransaction(inputs, amountMap, nil) - if err != nil { - panic(err) - } + require.NoError(r, err) // this adds a OP_RETURN + single BYTE len prefix to the data nullData, err := txscript.NullDataScript(memo) - if err != nil { - panic(err) - } - runner.Logger.Info("nulldata (len %d): %x", len(nullData), nullData) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("nulldata (len %d): %x", len(nullData), nullData) + require.NoError(r, err) memoOutput := wire.TxOut{Value: 0, PkScript: nullData} tx.TxOut = append(tx.TxOut, &memoOutput) tx.TxOut[1], tx.TxOut[2] = tx.TxOut[2], tx.TxOut[1] // make sure that TxOut[0] is sent to "to" address; TxOut[2] is change to oneself. TxOut[1] is memo. if !bytes.Equal(tx.TxOut[0].PkScript[2:], to.ScriptAddress()) { - runner.Logger.Info("tx.TxOut[0].PkScript: %x", tx.TxOut[0].PkScript) - runner.Logger.Info("to.ScriptAddress(): %x", to.ScriptAddress()) - runner.Logger.Info("swapping txout[0] with txout[2]") + r.Logger.Info("tx.TxOut[0].PkScript: %x", tx.TxOut[0].PkScript) + r.Logger.Info("to.ScriptAddress(): %x", to.ScriptAddress()) + r.Logger.Info("swapping txout[0] with txout[2]") tx.TxOut[0], tx.TxOut[2] = tx.TxOut[2], tx.TxOut[0] } - runner.Logger.Info("raw transaction: \n") + r.Logger.Info("raw transaction: \n") for idx, txout := range tx.TxOut { - runner.Logger.Info("txout %d", idx) - runner.Logger.Info(" value: %d", txout.Value) - runner.Logger.Info(" PkScript: %x", txout.PkScript) + r.Logger.Info("txout %d", idx) + r.Logger.Info(" value: %d", txout.Value) + r.Logger.Info(" PkScript: %x", txout.PkScript) } inputsForSign := make([]btcjson.RawTxWitnessInput, len(inputs)) @@ -274,75 +237,63 @@ func (runner *E2ERunner) SendToTSSFromDeployerWithMemo( } stx, signed, err := btcRPC.SignRawTransactionWithWallet2(tx, inputsForSign) - require.NoError(runner, err) - require.True(runner, signed, "btc transaction is not signed") + require.NoError(r, err) + require.True(r, signed, "btc transaction is not signed") txid, err := btcRPC.SendRawTransaction(stx, true) - if err != nil { - panic(err) - } - runner.Logger.Info("txid: %+v", txid) - _, err = runner.GenerateToAddressIfLocalBitcoin(6, btcDeployerAddress) - if err != nil { - panic(err) - } + require.NoError(r, err) + r.Logger.Info("txid: %+v", txid) + _, err = r.GenerateToAddressIfLocalBitcoin(6, btcDeployerAddress) + require.NoError(r, err) gtx, err := btcRPC.GetTransaction(txid) - if err != nil { - panic(err) - } - runner.Logger.Info("rawtx confirmation: %d", gtx.BlockIndex) + require.NoError(r, err) + r.Logger.Info("rawtx confirmation: %d", gtx.BlockIndex) rawtx, err := btcRPC.GetRawTransactionVerbose(txid) - if err != nil { - panic(err) - } + require.NoError(r, err) depositorFee := zetabitcoin.DefaultDepositorFee events, err := btcobserver.FilterAndParseIncomingTx( btcRPC, []btcjson.TxRawResult{*rawtx}, 0, - runner.BTCTSSAddress.EncodeAddress(), + r.BTCTSSAddress.EncodeAddress(), log.Logger, - runner.BitcoinParams, + r.BitcoinParams, depositorFee, ) - if err != nil { - panic(err) - } - runner.Logger.Info("bitcoin inbound events:") + require.NoError(r, err) + r.Logger.Info("bitcoin inbound events:") for _, event := range events { - runner.Logger.Info(" TxHash: %s", event.TxHash) - runner.Logger.Info(" From: %s", event.FromAddress) - runner.Logger.Info(" To: %s", event.ToAddress) - runner.Logger.Info(" Amount: %f", event.Value) - runner.Logger.Info(" Memo: %x", event.MemoBytes) + r.Logger.Info(" TxHash: %s", event.TxHash) + r.Logger.Info(" From: %s", event.FromAddress) + r.Logger.Info(" To: %s", event.ToAddress) + r.Logger.Info(" Amount: %f", event.Value) + r.Logger.Info(" Memo: %x", event.MemoBytes) } return txid, nil } // GetBitcoinChainID gets the bitcoin chain ID from the network params -func (runner *E2ERunner) GetBitcoinChainID() int64 { - chainID, err := chains.BitcoinChainIDFromNetworkName(runner.BitcoinParams.Name) - if err != nil { - panic(err) - } +func (r *E2ERunner) GetBitcoinChainID() int64 { + chainID, err := chains.BitcoinChainIDFromNetworkName(r.BitcoinParams.Name) + require.NoError(r, err) return chainID } // IsLocalBitcoin returns true if the runner is running on a local bitcoin network -func (runner *E2ERunner) IsLocalBitcoin() bool { - return runner.BitcoinParams.Name == chains.BitcoinRegnetParams.Name +func (r *E2ERunner) IsLocalBitcoin() bool { + return r.BitcoinParams.Name == chains.BitcoinRegnetParams.Name } // GenerateToAddressIfLocalBitcoin generates blocks to an address if the runner is interacting // with a local bitcoin network -func (runner *E2ERunner) GenerateToAddressIfLocalBitcoin( +func (r *E2ERunner) GenerateToAddressIfLocalBitcoin( numBlocks int64, address btcutil.Address, ) ([]*chainhash.Hash, error) { // if not local bitcoin network, do nothing - if runner.IsLocalBitcoin() { - return runner.BtcRPCClient.GenerateToAddress(numBlocks, address, nil) + if r.IsLocalBitcoin() { + return r.BtcRPCClient.GenerateToAddress(numBlocks, address, nil) } return nil, nil } @@ -350,7 +301,7 @@ func (runner *E2ERunner) GenerateToAddressIfLocalBitcoin( // MineBlocksIfLocalBitcoin mines blocks on the local BTC chain at a rate of 1 blocks every 5 seconds // and returns a channel that can be used to stop the mining // If the chain is not local, the function does nothing -func (runner *E2ERunner) MineBlocksIfLocalBitcoin() func() { +func (r *E2ERunner) MineBlocksIfLocalBitcoin() func() { stopChan := make(chan struct{}) go func() { for { @@ -358,10 +309,9 @@ func (runner *E2ERunner) MineBlocksIfLocalBitcoin() func() { case <-stopChan: return default: - _, err := runner.GenerateToAddressIfLocalBitcoin(1, runner.BTCDeployerAddress) - if err != nil { - panic(err) - } + _, err := r.GenerateToAddressIfLocalBitcoin(1, r.BTCDeployerAddress) + require.NoError(r, err) + time.Sleep(3 * time.Second) } } @@ -373,78 +323,61 @@ func (runner *E2ERunner) MineBlocksIfLocalBitcoin() func() { } // ProveBTCTransaction proves that a BTC transaction is in a block header and that the block header is in ZetaChain -func (runner *E2ERunner) ProveBTCTransaction(txHash *chainhash.Hash) { +func (r *E2ERunner) ProveBTCTransaction(txHash *chainhash.Hash) { // get tx result - btc := runner.BtcRPCClient + btc := r.BtcRPCClient txResult, err := btc.GetTransaction(txHash) - if err != nil { - panic("should get outTx result") - } - if txResult.Confirmations <= 0 { - panic("outTx should have already confirmed") - } + require.NoError(r, err, "should get tx result") + require.True(r, txResult.Confirmations > 0, "tx should have already confirmed") + txBytes, err := hex.DecodeString(txResult.Hex) - if err != nil { - panic(err) - } + require.NoError(r, err) // get the block with verbose transactions blockHash, err := chainhash.NewHashFromStr(txResult.BlockHash) - if err != nil { - panic(err) - } + require.NoError(r, err) + blockVerbose, err := btc.GetBlockVerboseTx(blockHash) - if err != nil { - panic("should get block verbose tx") - } + require.NoError(r, err, "should get block verbose tx") // get the block header header, err := btc.GetBlockHeader(blockHash) - if err != nil { - panic("should get block header") - } + require.NoError(r, err, "should get block header") // collect all the txs in the block txns := []*btcutil.Tx{} for _, res := range blockVerbose.Tx { txBytes, err := hex.DecodeString(res.Hex) - if err != nil { - panic(err) - } + require.NoError(r, err) + tx, err := btcutil.NewTxFromBytes(txBytes) - if err != nil { - panic(err) - } + require.NoError(r, err) + txns = append(txns, tx) } // build merkle proof mk := bitcoin.NewMerkle(txns) path, index, err := mk.BuildMerkleProof(int(txResult.BlockIndex)) - if err != nil { - panic("should build merkle proof") - } + require.NoError(r, err, "should build merkle proof") // verify merkle proof statically pass := bitcoin.Prove(*txHash, header.MerkleRoot, path, index) - if !pass { - panic("should verify merkle proof") - } + require.True(r, pass, "should verify merkle proof") // wait for block header to show up in ZetaChain startTime := time.Now() hash := header.BlockHash() for { // timeout - if time.Since(startTime) > blockHeaderBTCTimeout { - panic("timed out waiting for block header to show up in observer") - } + reachedTimeout := time.Since(startTime) > blockHeaderBTCTimeout + require.False(r, reachedTimeout, "timed out waiting for block header to show up in observer") - _, err := runner.LightclientClient.BlockHeader(runner.Ctx, &lightclienttypes.QueryGetBlockHeaderRequest{ + _, err := r.LightclientClient.BlockHeader(r.Ctx, &lightclienttypes.QueryGetBlockHeaderRequest{ BlockHash: hash.CloneBytes(), }) if err != nil { - runner.Logger.Info( + r.Logger.Info( "waiting for block header to show up in observer... current hash %s; err %s", hash.String(), err.Error(), @@ -457,18 +390,15 @@ func (runner *E2ERunner) ProveBTCTransaction(txHash *chainhash.Hash) { } // verify merkle proof through RPC - res, err := runner.LightclientClient.Prove(runner.Ctx, &lightclienttypes.QueryProveRequest{ + res, err := r.LightclientClient.Prove(r.Ctx, &lightclienttypes.QueryProveRequest{ ChainId: chains.BitcoinRegtest.ChainId, TxHash: txHash.String(), BlockHash: blockHash.String(), Proof: proofs.NewBitcoinProof(txBytes, path, index), TxIndex: 0, // bitcoin doesn't use txIndex }) - if err != nil { - panic(err) - } - if !res.Valid { - panic("txProof should be valid") - } - runner.Logger.Info("OK: txProof verified for inTx: %s", txHash.String()) + require.NoError(r, err) + require.True(r, res.Valid, "txProof should be valid") + + r.Logger.Info("OK: txProof verified for inTx: %s", txHash.String()) } diff --git a/e2e/runner/e2etest.go b/e2e/runner/e2etest.go index c6e49bdc9d..1ee9c34c19 100644 --- a/e2e/runner/e2etest.go +++ b/e2e/runner/e2etest.go @@ -61,7 +61,7 @@ type E2ETestRunConfig struct { } // GetE2ETestsToRunByName prepares a list of E2ETests to run based on given test names without arguments -func (runner *E2ERunner) GetE2ETestsToRunByName(availableTests []E2ETest, testNames ...string) ([]E2ETest, error) { +func (r *E2ERunner) GetE2ETestsToRunByName(availableTests []E2ETest, testNames ...string) ([]E2ETest, error) { tests := []E2ETestRunConfig{} for _, testName := range testNames { tests = append(tests, E2ETestRunConfig{ @@ -69,11 +69,11 @@ func (runner *E2ERunner) GetE2ETestsToRunByName(availableTests []E2ETest, testNa Args: []string{}, }) } - return runner.GetE2ETestsToRunByConfig(availableTests, tests) + return r.GetE2ETestsToRunByConfig(availableTests, tests) } // GetE2ETestsToRunByConfig prepares a list of E2ETests to run based on provided test names and their corresponding arguments -func (runner *E2ERunner) GetE2ETestsToRunByConfig( +func (r *E2ERunner) GetE2ETestsToRunByConfig( availableTests []E2ETest, testConfigs []E2ETestRunConfig, ) ([]E2ETest, error) { diff --git a/e2e/runner/evm.go b/e2e/runner/evm.go index 355b692ec5..523e01e207 100644 --- a/e2e/runner/evm.go +++ b/e2e/runner/evm.go @@ -9,6 +9,7 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/utils" "github.com/zeta-chain/zetacore/pkg/chains" @@ -20,169 +21,146 @@ import ( var blockHeaderETHTimeout = 5 * time.Minute // WaitForTxReceiptOnEvm waits for a tx receipt on EVM -func (runner *E2ERunner) WaitForTxReceiptOnEvm(tx *ethtypes.Transaction) { - defer func() { - runner.Unlock() - }() - runner.Lock() +func (r *E2ERunner) WaitForTxReceiptOnEvm(tx *ethtypes.Transaction) { + r.Lock() + defer r.Unlock() - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, tx, runner.Logger, runner.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt) } // MintERC20OnEvm mints ERC20 on EVM // amount is a multiple of 1e18 -func (runner *E2ERunner) MintERC20OnEvm(amountERC20 int64) { - defer func() { - runner.Unlock() - }() - runner.Lock() +func (r *E2ERunner) MintERC20OnEvm(amountERC20 int64) { + r.Lock() + defer r.Unlock() amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(amountERC20)) - tx, err := runner.ERC20.Mint(runner.EVMAuth, amount) - if err != nil { - panic(err) - } - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, tx, runner.Logger, runner.ReceiptTimeout) - if receipt.Status == 0 { - panic("mint failed") - } - runner.Logger.Info("Mint receipt tx hash: %s", tx.Hash().Hex()) + tx, err := r.ERC20.Mint(r.EVMAuth, amount) + require.NoError(r, err) + + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt) + + r.Logger.Info("Mint receipt tx hash: %s", tx.Hash().Hex()) } // SendERC20OnEvm sends ERC20 to an address on EVM // this allows the ERC20 contract deployer to funds other accounts on EVM // amountERC20 is a multiple of 1e18 -func (runner *E2ERunner) SendERC20OnEvm(address ethcommon.Address, amountERC20 int64) *ethtypes.Transaction { +func (r *E2ERunner) SendERC20OnEvm(address ethcommon.Address, amountERC20 int64) *ethtypes.Transaction { // the deployer might be sending ERC20 in different goroutines - defer func() { - runner.Unlock() - }() - runner.Lock() + r.Lock() + defer r.Unlock() amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(amountERC20)) // transfer - tx, err := runner.ERC20.Transfer(runner.EVMAuth, address, amount) - if err != nil { - panic(err) - } + tx, err := r.ERC20.Transfer(r.EVMAuth, address, amount) + require.NoError(r, err) + return tx } -func (runner *E2ERunner) DepositERC20() ethcommon.Hash { - runner.Logger.Print("⏳ depositing ERC20 into ZEVM") +func (r *E2ERunner) DepositERC20() ethcommon.Hash { + r.Logger.Print("⏳ depositing ERC20 into ZEVM") - return runner.DepositERC20WithAmountAndMessage(runner.DeployerAddress, big.NewInt(1e18), []byte{}) + return r.DepositERC20WithAmountAndMessage(r.DeployerAddress, big.NewInt(1e18), []byte{}) } -func (runner *E2ERunner) DepositERC20WithAmountAndMessage( - to ethcommon.Address, - amount *big.Int, - msg []byte, -) ethcommon.Hash { +func (r *E2ERunner) DepositERC20WithAmountAndMessage(to ethcommon.Address, amount *big.Int, msg []byte) ethcommon.Hash { // reset allowance, necessary for USDT - tx, err := runner.ERC20.Approve(runner.EVMAuth, runner.ERC20CustodyAddr, big.NewInt(0)) - if err != nil { - panic(err) - } - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, tx, runner.Logger, runner.ReceiptTimeout) - if receipt.Status == 0 { - panic("approve failed") - } - runner.Logger.Info("ERC20 Approve receipt tx hash: %s", tx.Hash().Hex()) + tx, err := r.ERC20.Approve(r.EVMAuth, r.ERC20CustodyAddr, big.NewInt(0)) + require.NoError(r, err) - tx, err = runner.ERC20.Approve(runner.EVMAuth, runner.ERC20CustodyAddr, amount) - if err != nil { - panic(err) - } - receipt = utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, tx, runner.Logger, runner.ReceiptTimeout) - if receipt.Status == 0 { - panic("approve failed") - } - runner.Logger.Info("ERC20 Approve receipt tx hash: %s", tx.Hash().Hex()) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt) - tx, err = runner.ERC20Custody.Deposit(runner.EVMAuth, to.Bytes(), runner.ERC20Addr, amount, msg) - runner.Logger.Info("TX: %v", tx) + r.Logger.Info("ERC20 Approve receipt tx hash: %s", tx.Hash().Hex()) - if err != nil { - panic(err) - } - receipt = utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, tx, runner.Logger, runner.ReceiptTimeout) - if receipt.Status == 0 { - panic("deposit failed") - } - runner.Logger.Info("Deposit receipt tx hash: %s, status %d", receipt.TxHash.Hex(), receipt.Status) + tx, err = r.ERC20.Approve(r.EVMAuth, r.ERC20CustodyAddr, amount) + require.NoError(r, err) + + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt) + + r.Logger.Info("ERC20 Approve receipt tx hash: %s", tx.Hash().Hex()) + + tx, err = r.ERC20Custody.Deposit(r.EVMAuth, to.Bytes(), r.ERC20Addr, amount, msg) + require.NoError(r, err) + + r.Logger.Info("TX: %v", tx) + + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt) + + r.Logger.Info("Deposit receipt tx hash: %s, status %d", receipt.TxHash.Hex(), receipt.Status) for _, log := range receipt.Logs { - event, err := runner.ERC20Custody.ParseDeposited(*log) + event, err := r.ERC20Custody.ParseDeposited(*log) if err != nil { continue } - runner.Logger.Info("Deposited event:") - runner.Logger.Info(" Recipient address: %x", event.Recipient) - runner.Logger.Info(" ERC20 address: %s", event.Asset.Hex()) - runner.Logger.Info(" Amount: %d", event.Amount) - runner.Logger.Info(" Message: %x", event.Message) + r.Logger.Info("Deposited event:") + r.Logger.Info(" Recipient address: %x", event.Recipient) + r.Logger.Info(" ERC20 address: %s", event.Asset.Hex()) + r.Logger.Info(" Amount: %d", event.Amount) + r.Logger.Info(" Message: %x", event.Message) } return tx.Hash() } // DepositEther sends Ethers into ZEVM -func (runner *E2ERunner) DepositEther(testHeader bool) ethcommon.Hash { +func (r *E2ERunner) DepositEther(testHeader bool) ethcommon.Hash { amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(100)) // 100 eth - return runner.DepositEtherWithAmount(testHeader, amount) + return r.DepositEtherWithAmount(testHeader, amount) } // DepositEtherWithAmount sends Ethers into ZEVM -func (runner *E2ERunner) DepositEtherWithAmount(testHeader bool, amount *big.Int) ethcommon.Hash { - runner.Logger.Print("⏳ depositing Ethers into ZEVM") +func (r *E2ERunner) DepositEtherWithAmount(testHeader bool, amount *big.Int) ethcommon.Hash { + r.Logger.Print("⏳ depositing Ethers into ZEVM") - signedTx, err := runner.SendEther(runner.TSSAddress, amount, nil) - if err != nil { - panic(err) - } - runner.Logger.EVMTransaction(*signedTx, "send to TSS") + signedTx, err := r.SendEther(r.TSSAddress, amount, nil) + require.NoError(r, err) - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, signedTx, runner.Logger, runner.ReceiptTimeout) - if receipt.Status == 0 { - panic("deposit failed") - } - runner.Logger.EVMReceipt(*receipt, "send to TSS") + r.Logger.EVMTransaction(*signedTx, "send to TSS") + + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, signedTx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt, "deposit failed") + + r.Logger.EVMReceipt(*receipt, "send to TSS") // due to the high block throughput in localnet, ZetaClient might catch up slowly with the blocks // to optimize block header proof test, this test is directly executed here on the first deposit instead of having a separate test if testHeader { - runner.ProveEthTransaction(receipt) + r.ProveEthTransaction(receipt) } return signedTx.Hash() } // SendEther sends ethers to the TSS on EVM -func (runner *E2ERunner) SendEther(_ ethcommon.Address, value *big.Int, data []byte) (*ethtypes.Transaction, error) { - evmClient := runner.EVMClient +func (r *E2ERunner) SendEther(_ ethcommon.Address, value *big.Int, data []byte) (*ethtypes.Transaction, error) { + evmClient := r.EVMClient - nonce, err := evmClient.PendingNonceAt(runner.Ctx, runner.DeployerAddress) + nonce, err := evmClient.PendingNonceAt(r.Ctx, r.DeployerAddress) if err != nil { return nil, err } gasLimit := uint64(30000) // in units - gasPrice, err := evmClient.SuggestGasPrice(runner.Ctx) + gasPrice, err := evmClient.SuggestGasPrice(r.Ctx) if err != nil { return nil, err } - tx := ethtypes.NewTransaction(nonce, runner.TSSAddress, value, gasLimit, gasPrice, data) - chainID, err := evmClient.ChainID(runner.Ctx) + tx := ethtypes.NewTransaction(nonce, r.TSSAddress, value, gasLimit, gasPrice, data) + chainID, err := evmClient.ChainID(r.Ctx) if err != nil { return nil, err } - deployerPrivkey, err := crypto.HexToECDSA(runner.DeployerPrivateKey) + deployerPrivkey, err := crypto.HexToECDSA(r.DeployerPrivateKey) if err != nil { return nil, err } @@ -191,7 +169,7 @@ func (runner *E2ERunner) SendEther(_ ethcommon.Address, value *big.Int, data []b if err != nil { return nil, err } - err = evmClient.SendTransaction(runner.Ctx, signedTx) + err = evmClient.SendTransaction(r.Ctx, signedTx) if err != nil { return nil, err } @@ -200,7 +178,7 @@ func (runner *E2ERunner) SendEther(_ ethcommon.Address, value *big.Int, data []b } // ProveEthTransaction proves an ETH transaction on ZetaChain -func (runner *E2ERunner) ProveEthTransaction(receipt *ethtypes.Receipt) { +func (r *E2ERunner) ProveEthTransaction(receipt *ethtypes.Receipt) { startTime := time.Now() txHash := receipt.TxHash @@ -209,23 +187,21 @@ func (runner *E2ERunner) ProveEthTransaction(receipt *ethtypes.Receipt) { // #nosec G701 test - always in range txIndex := int(receipt.TransactionIndex) - block, err := runner.EVMClient.BlockByHash(runner.Ctx, blockHash) - if err != nil { - panic(err) - } + block, err := r.EVMClient.BlockByHash(r.Ctx, blockHash) + require.NoError(r, err) + for { // check timeout - if time.Since(startTime) > blockHeaderETHTimeout { - panic("timeout waiting for block header") - } + reachedTimeout := time.Since(startTime) > blockHeaderETHTimeout + require.False(r, reachedTimeout, "timeout waiting for block header") - _, err := runner.LightclientClient.BlockHeader(runner.Ctx, &lightclienttypes.QueryGetBlockHeaderRequest{ + _, err := r.LightclientClient.BlockHeader(r.Ctx, &lightclienttypes.QueryGetBlockHeaderRequest{ BlockHash: blockHash.Bytes(), }) if err != nil { - runner.Logger.Info("WARN: block header not found; retrying... error: %s", err.Error()) + r.Logger.Info("WARN: block header not found; retrying... error: %s", err.Error()) } else { - runner.Logger.Info("OK: block header found") + r.Logger.Info("OK: block header found") break } @@ -233,42 +209,36 @@ func (runner *E2ERunner) ProveEthTransaction(receipt *ethtypes.Receipt) { } trie := ethereum.NewTrie(block.Transactions()) - if trie.Hash() != block.Header().TxHash { - panic("tx root hash & block tx root mismatch") - } + require.Equal(r, trie.Hash(), block.Header().TxHash, "tx root hash & block tx root mismatch") + txProof, err := trie.GenerateProof(txIndex) - if err != nil { - panic("error generating txProof") - } + require.NoError(r, err, "error generating txProof") + val, err := txProof.Verify(block.TxHash(), txIndex) - if err != nil { - panic("error verifying txProof") - } + require.NoError(r, err, "error verifying txProof") + var txx ethtypes.Transaction - err = txx.UnmarshalBinary(val) - if err != nil { - panic("error unmarshalling txProof'd tx") - } - res, err := runner.LightclientClient.Prove(runner.Ctx, &lightclienttypes.QueryProveRequest{ + require.NoError(r, txx.UnmarshalBinary(val)) + + res, err := r.LightclientClient.Prove(r.Ctx, &lightclienttypes.QueryProveRequest{ BlockHash: blockHash.Hex(), TxIndex: int64(txIndex), TxHash: txHash.Hex(), Proof: proofs.NewEthereumProof(txProof), ChainId: chains.GoerliLocalnet.ChainId, }) - if err != nil { - panic(err) - } - if !res.Valid { - panic("txProof invalid") // FIXME: don't do this in production - } - runner.Logger.Info("OK: txProof verified") + + // FIXME: @lumtis: don't do this in production + require.NoError(r, err) + require.True(r, res.Valid, "txProof invalid") + + r.Logger.Info("OK: txProof verified") } // AnvilMineBlocks mines blocks on Anvil localnet // the block time is provided in seconds // the method returns a function to stop the mining -func (runner *E2ERunner) AnvilMineBlocks(url string, blockTime int) (func(), error) { +func (r *E2ERunner) AnvilMineBlocks(url string, blockTime int) (func(), error) { stop := make(chan struct{}) client, err := rpc.Dial(url) @@ -286,7 +256,7 @@ func (runner *E2ERunner) AnvilMineBlocks(url string, blockTime int) (func(), err time.Sleep(time.Duration(blockTime) * time.Second) var result interface{} - err = client.CallContext(runner.Ctx, &result, "evm_mine") + err = client.CallContext(r.Ctx, &result, "evm_mine") if err != nil { log.Fatalf("Failed to mine a new block: %v", err) } diff --git a/e2e/runner/report.go b/e2e/runner/report.go index a25360a109..82bb263856 100644 --- a/e2e/runner/report.go +++ b/e2e/runner/report.go @@ -53,13 +53,13 @@ func (tr TestReports) String(prefix string) (string, error) { } // PrintTestReports prints the test reports -func (runner *E2ERunner) PrintTestReports(tr TestReports) { - runner.Logger.Print(" ---📈 E2E Test Report ---") +func (r *E2ERunner) PrintTestReports(tr TestReports) { + r.Logger.Print(" ---📈 E2E Test Report ---") table, err := tr.String("") if err != nil { - runner.Logger.Print("Error rendering test report: %s", err) + r.Logger.Print("Error rendering test report: %s", err) } - runner.Logger.PrintNoPrefix(table) + r.Logger.PrintNoPrefix(table) } // NetworkReport is a struct that contains the report for the network used after running e2e tests @@ -87,9 +87,9 @@ func (nr NetworkReport) Validate() error { } // GenerateNetworkReport generates a report for the network used after running e2e tests -func (runner *E2ERunner) GenerateNetworkReport() (NetworkReport, error) { +func (r *E2ERunner) GenerateNetworkReport() (NetworkReport, error) { // get the emissions pool balance - balanceRes, err := runner.BankClient.Balance(runner.Ctx, &banktypes.QueryBalanceRequest{ + balanceRes, err := r.BankClient.Balance(r.Ctx, &banktypes.QueryBalanceRequest{ Address: txserver.EmissionsPoolAddress, Denom: config.BaseDenom, }) @@ -101,13 +101,13 @@ func (runner *E2ERunner) GenerateNetworkReport() (NetworkReport, error) { // fetch the height and number of cctxs, this gives a better idea on the activity of the network // get the block height - blockRes, err := runner.ZEVMClient.BlockNumber(runner.Ctx) + blockRes, err := r.ZEVMClient.BlockNumber(r.Ctx) if err != nil { return NetworkReport{}, err } // get the number of cctxs - cctxsRes, err := runner.CctxClient.CctxAll(runner.Ctx, &crosschaintypes.QueryAllCctxRequest{}) + cctxsRes, err := r.CctxClient.CctxAll(r.Ctx, &crosschaintypes.QueryAllCctxRequest{}) if err != nil { return NetworkReport{}, err } @@ -121,10 +121,10 @@ func (runner *E2ERunner) GenerateNetworkReport() (NetworkReport, error) { } // PrintNetworkReport prints the network report -func (runner *E2ERunner) PrintNetworkReport(nr NetworkReport) { - runner.Logger.Print(" ---📈 Network Report ---") - runner.Logger.Print("Block Height: %d", nr.Height) - runner.Logger.Print("CCTX Processed: %d", nr.CctxCount) - runner.Logger.Print("Emissions Pool Balance: %sZETA", nr.EmissionsPoolBalance.Quo(sdkmath.NewIntFromUint64(1e18))) +func (r *E2ERunner) PrintNetworkReport(nr NetworkReport) { + r.Logger.Print(" ---📈 Network Report ---") + r.Logger.Print("Block Height: %d", nr.Height) + r.Logger.Print("CCTX Processed: %d", nr.CctxCount) + r.Logger.Print("Emissions Pool Balance: %sZETA", nr.EmissionsPoolBalance.Quo(sdkmath.NewIntFromUint64(1e18))) } diff --git a/e2e/runner/run.go b/e2e/runner/run.go index f24ff9d9f8..c05129b775 100644 --- a/e2e/runner/run.go +++ b/e2e/runner/run.go @@ -1,15 +1,13 @@ package runner import ( - "fmt" - "runtime" "time" ) // RunE2ETests runs a list of e2e tests -func (runner *E2ERunner) RunE2ETests(e2eTests []E2ETest) (err error) { +func (r *E2ERunner) RunE2ETests(e2eTests []E2ETest) (err error) { for _, e2eTest := range e2eTests { - if err := runner.RunE2ETest(e2eTest, true); err != nil { + if err := r.RunE2ETest(e2eTest, true); err != nil { return err } } @@ -17,64 +15,53 @@ func (runner *E2ERunner) RunE2ETests(e2eTests []E2ETest) (err error) { } // RunE2ETest runs a e2e test -func (runner *E2ERunner) RunE2ETest(e2eTest E2ETest, checkAccounting bool) (err error) { - // return an error on panic - // https://github.com/zeta-chain/node/issues/1500 - defer func() { - if r := recover(); r != nil { - // print stack trace - stack := make([]byte, 4096) - n := runtime.Stack(stack, false) - err = fmt.Errorf("%s failed: %v, stack trace %s", e2eTest.Name, r, stack[:n]) - } - }() - +func (r *E2ERunner) RunE2ETest(e2eTest E2ETest, checkAccounting bool) error { startTime := time.Now() - runner.Logger.Print("⏳running - %s", e2eTest.Description) + r.Logger.Print("⏳running - %s", e2eTest.Description) // run e2e test, if args are not provided, use default args args := e2eTest.Args if len(args) == 0 { args = e2eTest.DefaultArgs() } - e2eTest.E2ETest(runner, args) + e2eTest.E2ETest(r, args) //check supplies if checkAccounting { - if err := runner.CheckZRC20ReserveAndSupply(); err != nil { + if err := r.CheckZRC20ReserveAndSupply(); err != nil { return err } } - runner.Logger.Print("✅ completed in %s - %s", time.Since(startTime), e2eTest.Description) + r.Logger.Print("✅ completed in %s - %s", time.Since(startTime), e2eTest.Description) - return err + return nil } // RunE2ETestsIntoReport runs a list of e2e tests by name in a list of e2e tests and returns a report // The function doesn't return an error, it returns a report with the error -func (runner *E2ERunner) RunE2ETestsIntoReport(e2eTests []E2ETest) (TestReports, error) { +func (r *E2ERunner) RunE2ETestsIntoReport(e2eTests []E2ETest) (TestReports, error) { // go through all tests reports := make(TestReports, 0, len(e2eTests)) for _, test := range e2eTests { // get info before test - balancesBefore, err := runner.GetAccountBalances(true) + balancesBefore, err := r.GetAccountBalances(true) if err != nil { return nil, err } timeBefore := time.Now() // run test - testErr := runner.RunE2ETest(test, false) + testErr := r.RunE2ETest(test, false) if testErr != nil { - runner.Logger.Print("test %s failed: %s", test.Name, testErr.Error()) + r.Logger.Print("test %s failed: %s", test.Name, testErr.Error()) } // wait 5 sec to make sure we get updated balances time.Sleep(5 * time.Second) // get info after test - balancesAfter, err := runner.GetAccountBalances(true) + balancesAfter, err := r.GetAccountBalances(true) if err != nil { return nil, err } diff --git a/e2e/runner/runner.go b/e2e/runner/runner.go index 2f2f0e49cc..e27de63247 100644 --- a/e2e/runner/runner.go +++ b/e2e/runner/runner.go @@ -13,6 +13,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol" zetaeth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zeta.eth.sol" @@ -28,6 +29,7 @@ import ( "github.com/zeta-chain/zetacore/e2e/contracts/erc20" "github.com/zeta-chain/zetacore/e2e/contracts/zevmswap" "github.com/zeta-chain/zetacore/e2e/txserver" + "github.com/zeta-chain/zetacore/e2e/utils" 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" @@ -144,7 +146,6 @@ func NewE2ERunner( ) *E2ERunner { r := &E2ERunner{ Name: name, - Ctx: ctx, CtxCancel: ctxCancel, DeployerAddress: deployerAddress, @@ -165,91 +166,95 @@ func NewE2ERunner( Logger: logger, } + + r.Ctx = utils.WithTesting(ctx, r) + for _, opt := range opts { opt(r) } + return r } // CopyAddressesFrom copies addresses from another E2ETestRunner that initialized the contracts -func (runner *E2ERunner) CopyAddressesFrom(other *E2ERunner) (err error) { +func (r *E2ERunner) CopyAddressesFrom(other *E2ERunner) (err error) { // copy TSS address - runner.TSSAddress = other.TSSAddress - runner.BTCTSSAddress = other.BTCTSSAddress + r.TSSAddress = other.TSSAddress + r.BTCTSSAddress = other.BTCTSSAddress // copy addresses - runner.ZetaEthAddr = other.ZetaEthAddr - runner.ConnectorEthAddr = other.ConnectorEthAddr - runner.ERC20CustodyAddr = other.ERC20CustodyAddr - runner.ERC20Addr = other.ERC20Addr - runner.ERC20ZRC20Addr = other.ERC20ZRC20Addr - runner.ETHZRC20Addr = other.ETHZRC20Addr - runner.BTCZRC20Addr = other.BTCZRC20Addr - runner.UniswapV2FactoryAddr = other.UniswapV2FactoryAddr - runner.UniswapV2RouterAddr = other.UniswapV2RouterAddr - runner.ConnectorZEVMAddr = other.ConnectorZEVMAddr - runner.WZetaAddr = other.WZetaAddr - runner.EvmTestDAppAddr = other.EvmTestDAppAddr - runner.ZEVMSwapAppAddr = other.ZEVMSwapAppAddr - runner.ContextAppAddr = other.ContextAppAddr - runner.SystemContractAddr = other.SystemContractAddr - runner.ZevmTestDAppAddr = other.ZevmTestDAppAddr + r.ZetaEthAddr = other.ZetaEthAddr + r.ConnectorEthAddr = other.ConnectorEthAddr + r.ERC20CustodyAddr = other.ERC20CustodyAddr + r.ERC20Addr = other.ERC20Addr + r.ERC20ZRC20Addr = other.ERC20ZRC20Addr + r.ETHZRC20Addr = other.ETHZRC20Addr + r.BTCZRC20Addr = other.BTCZRC20Addr + r.UniswapV2FactoryAddr = other.UniswapV2FactoryAddr + r.UniswapV2RouterAddr = other.UniswapV2RouterAddr + r.ConnectorZEVMAddr = other.ConnectorZEVMAddr + r.WZetaAddr = other.WZetaAddr + r.EvmTestDAppAddr = other.EvmTestDAppAddr + r.ZEVMSwapAppAddr = other.ZEVMSwapAppAddr + r.ContextAppAddr = other.ContextAppAddr + r.SystemContractAddr = other.SystemContractAddr + r.ZevmTestDAppAddr = other.ZevmTestDAppAddr // create instances of contracts - runner.ZetaEth, err = zetaeth.NewZetaEth(runner.ZetaEthAddr, runner.EVMClient) + r.ZetaEth, err = zetaeth.NewZetaEth(r.ZetaEthAddr, r.EVMClient) if err != nil { return err } - runner.ConnectorEth, err = zetaconnectoreth.NewZetaConnectorEth(runner.ConnectorEthAddr, runner.EVMClient) + r.ConnectorEth, err = zetaconnectoreth.NewZetaConnectorEth(r.ConnectorEthAddr, r.EVMClient) if err != nil { return err } - runner.ERC20Custody, err = erc20custody.NewERC20Custody(runner.ERC20CustodyAddr, runner.EVMClient) + r.ERC20Custody, err = erc20custody.NewERC20Custody(r.ERC20CustodyAddr, r.EVMClient) if err != nil { return err } - runner.ERC20, err = erc20.NewERC20(runner.ERC20Addr, runner.EVMClient) + r.ERC20, err = erc20.NewERC20(r.ERC20Addr, r.EVMClient) if err != nil { return err } - runner.ERC20ZRC20, err = zrc20.NewZRC20(runner.ERC20ZRC20Addr, runner.ZEVMClient) + r.ERC20ZRC20, err = zrc20.NewZRC20(r.ERC20ZRC20Addr, r.ZEVMClient) if err != nil { return err } - runner.ETHZRC20, err = zrc20.NewZRC20(runner.ETHZRC20Addr, runner.ZEVMClient) + r.ETHZRC20, err = zrc20.NewZRC20(r.ETHZRC20Addr, r.ZEVMClient) if err != nil { return err } - runner.BTCZRC20, err = zrc20.NewZRC20(runner.BTCZRC20Addr, runner.ZEVMClient) + r.BTCZRC20, err = zrc20.NewZRC20(r.BTCZRC20Addr, r.ZEVMClient) if err != nil { return err } - runner.UniswapV2Factory, err = uniswapv2factory.NewUniswapV2Factory(runner.UniswapV2FactoryAddr, runner.ZEVMClient) + r.UniswapV2Factory, err = uniswapv2factory.NewUniswapV2Factory(r.UniswapV2FactoryAddr, r.ZEVMClient) if err != nil { return err } - runner.UniswapV2Router, err = uniswapv2router.NewUniswapV2Router02(runner.UniswapV2RouterAddr, runner.ZEVMClient) + r.UniswapV2Router, err = uniswapv2router.NewUniswapV2Router02(r.UniswapV2RouterAddr, r.ZEVMClient) if err != nil { return err } - runner.ConnectorZEVM, err = connectorzevm.NewZetaConnectorZEVM(runner.ConnectorZEVMAddr, runner.ZEVMClient) + r.ConnectorZEVM, err = connectorzevm.NewZetaConnectorZEVM(r.ConnectorZEVMAddr, r.ZEVMClient) if err != nil { return err } - runner.WZeta, err = wzeta.NewWETH9(runner.WZetaAddr, runner.ZEVMClient) + r.WZeta, err = wzeta.NewWETH9(r.WZetaAddr, r.ZEVMClient) if err != nil { return err } - runner.ZEVMSwapApp, err = zevmswap.NewZEVMSwapApp(runner.ZEVMSwapAppAddr, runner.ZEVMClient) + r.ZEVMSwapApp, err = zevmswap.NewZEVMSwapApp(r.ZEVMSwapAppAddr, r.ZEVMClient) if err != nil { return err } - runner.ContextApp, err = contextapp.NewContextApp(runner.ContextAppAddr, runner.ZEVMClient) + r.ContextApp, err = contextapp.NewContextApp(r.ContextAppAddr, r.ZEVMClient) if err != nil { return err } - runner.SystemContract, err = systemcontract.NewSystemContract(runner.SystemContractAddr, runner.ZEVMClient) + r.SystemContract, err = systemcontract.NewSystemContract(r.SystemContractAddr, r.ZEVMClient) if err != nil { return err } @@ -257,50 +262,55 @@ func (runner *E2ERunner) CopyAddressesFrom(other *E2ERunner) (err error) { } // Lock locks the mutex -func (runner *E2ERunner) Lock() { - runner.mutex.Lock() +func (r *E2ERunner) Lock() { + r.mutex.Lock() } // Unlock unlocks the mutex -func (runner *E2ERunner) Unlock() { - runner.mutex.Unlock() +func (r *E2ERunner) Unlock() { + r.mutex.Unlock() } // PrintContractAddresses prints the addresses of the contracts // the printed contracts are grouped in a zevm and evm section // there is a padding used to print the addresses at the same position -func (runner *E2ERunner) PrintContractAddresses() { +func (r *E2ERunner) PrintContractAddresses() { // zevm contracts - runner.Logger.Print(" --- 📜zEVM contracts ---") - runner.Logger.Print("SystemContract: %s", runner.SystemContractAddr.Hex()) - runner.Logger.Print("ETHZRC20: %s", runner.ETHZRC20Addr.Hex()) - runner.Logger.Print("ERC20ZRC20: %s", runner.ERC20ZRC20Addr.Hex()) - runner.Logger.Print("BTCZRC20: %s", runner.BTCZRC20Addr.Hex()) - runner.Logger.Print("UniswapFactory: %s", runner.UniswapV2FactoryAddr.Hex()) - runner.Logger.Print("UniswapRouter: %s", runner.UniswapV2RouterAddr.Hex()) - runner.Logger.Print("ConnectorZEVM: %s", runner.ConnectorZEVMAddr.Hex()) - runner.Logger.Print("WZeta: %s", runner.WZetaAddr.Hex()) - - runner.Logger.Print("ZEVMSwapApp: %s", runner.ZEVMSwapAppAddr.Hex()) - runner.Logger.Print("ContextApp: %s", runner.ContextAppAddr.Hex()) - runner.Logger.Print("TestDappZEVM: %s", runner.ZevmTestDAppAddr.Hex()) + r.Logger.Print(" --- 📜zEVM contracts ---") + r.Logger.Print("SystemContract: %s", r.SystemContractAddr.Hex()) + r.Logger.Print("ETHZRC20: %s", r.ETHZRC20Addr.Hex()) + r.Logger.Print("ERC20ZRC20: %s", r.ERC20ZRC20Addr.Hex()) + r.Logger.Print("BTCZRC20: %s", r.BTCZRC20Addr.Hex()) + r.Logger.Print("UniswapFactory: %s", r.UniswapV2FactoryAddr.Hex()) + r.Logger.Print("UniswapRouter: %s", r.UniswapV2RouterAddr.Hex()) + r.Logger.Print("ConnectorZEVM: %s", r.ConnectorZEVMAddr.Hex()) + r.Logger.Print("WZeta: %s", r.WZetaAddr.Hex()) + + r.Logger.Print("ZEVMSwapApp: %s", r.ZEVMSwapAppAddr.Hex()) + r.Logger.Print("ContextApp: %s", r.ContextAppAddr.Hex()) + r.Logger.Print("TestDappZEVM: %s", r.ZevmTestDAppAddr.Hex()) // evm contracts - runner.Logger.Print(" --- 📜EVM contracts ---") - runner.Logger.Print("ZetaEth: %s", runner.ZetaEthAddr.Hex()) - runner.Logger.Print("ConnectorEth: %s", runner.ConnectorEthAddr.Hex()) - runner.Logger.Print("ERC20Custody: %s", runner.ERC20CustodyAddr.Hex()) - runner.Logger.Print("ERC20: %s", runner.ERC20Addr.Hex()) - runner.Logger.Print("TestDappEVM: %s", runner.EvmTestDAppAddr.Hex()) + r.Logger.Print(" --- 📜EVM contracts ---") + r.Logger.Print("ZetaEth: %s", r.ZetaEthAddr.Hex()) + r.Logger.Print("ConnectorEth: %s", r.ConnectorEthAddr.Hex()) + r.Logger.Print("ERC20Custody: %s", r.ERC20CustodyAddr.Hex()) + r.Logger.Print("ERC20: %s", r.ERC20Addr.Hex()) + r.Logger.Print("TestDappEVM: %s", r.EvmTestDAppAddr.Hex()) } // Errorf logs an error message. Mimics the behavior of testing.T.Errorf -func (runner *E2ERunner) Errorf(format string, args ...any) { - runner.Logger.Error(format, args...) +func (r *E2ERunner) Errorf(format string, args ...any) { + r.Logger.Error(format, args...) } // FailNow implemented to mimic the behavior of testing.T.FailNow -func (runner *E2ERunner) FailNow() { - runner.Logger.Error("Test failed") +func (r *E2ERunner) FailNow() { + r.Logger.Error("Test failed") + r.CtxCancel() os.Exit(1) } + +func (r *E2ERunner) requireTxSuccessful(receipt *ethtypes.Receipt, msgAndArgs ...any) { + utils.RequireTxSuccessful(r, receipt, msgAndArgs...) +} diff --git a/e2e/runner/setup_bitcoin.go b/e2e/runner/setup_bitcoin.go index 8e39d0143e..92a7eac428 100644 --- a/e2e/runner/setup_bitcoin.go +++ b/e2e/runner/setup_bitcoin.go @@ -2,7 +2,6 @@ package runner import ( "encoding/hex" - "strings" "time" "github.com/btcsuite/btcd/btcec" @@ -11,58 +10,50 @@ import ( "github.com/stretchr/testify/require" ) -func (runner *E2ERunner) SetupBitcoinAccount(initNetwork bool) { - runner.Logger.Print("⚙️ setting up Bitcoin account") +func (r *E2ERunner) SetupBitcoinAccount(initNetwork bool) { + r.Logger.Print("⚙️ setting up Bitcoin account") startTime := time.Now() defer func() { - runner.Logger.Print("✅ Bitcoin account setup in %s\n", time.Since(startTime)) + r.Logger.Print("✅ Bitcoin account setup in %s\n", time.Since(startTime)) }() - _, err := runner.BtcRPCClient.CreateWallet(runner.Name, rpcclient.WithCreateWalletBlank()) + _, err := r.BtcRPCClient.CreateWallet(r.Name, rpcclient.WithCreateWalletBlank()) if err != nil { - if !strings.Contains(err.Error(), "Database already exists") { - panic(err) - } + require.ErrorContains(r, err, "Database already exists") } - runner.SetBtcAddress(runner.Name, true) + r.SetBtcAddress(r.Name, true) if initNetwork { // import the TSS address - err = runner.BtcRPCClient.ImportAddress(runner.BTCTSSAddress.EncodeAddress()) - if err != nil { - panic(err) - } + err = r.BtcRPCClient.ImportAddress(r.BTCTSSAddress.EncodeAddress()) + require.NoError(r, err) // mine some blocks to get some BTC into the deployer address - _, err = runner.GenerateToAddressIfLocalBitcoin(101, runner.BTCDeployerAddress) - if err != nil { - panic(err) - } - - _, err = runner.GenerateToAddressIfLocalBitcoin(4, runner.BTCDeployerAddress) - if err != nil { - panic(err) - } + _, err = r.GenerateToAddressIfLocalBitcoin(101, r.BTCDeployerAddress) + require.NoError(r, err) + + _, err = r.GenerateToAddressIfLocalBitcoin(4, r.BTCDeployerAddress) + require.NoError(r, err) } } // GetBtcAddress returns the BTC address of the deployer from its EVM private key -func (runner *E2ERunner) GetBtcAddress() (string, string, error) { - skBytes, err := hex.DecodeString(runner.DeployerPrivateKey) +func (r *E2ERunner) GetBtcAddress() (string, string, error) { + skBytes, err := hex.DecodeString(r.DeployerPrivateKey) if err != nil { return "", "", err } sk, _ := btcec.PrivKeyFromBytes(btcec.S256(), skBytes) - privkeyWIF, err := btcutil.NewWIF(sk, runner.BitcoinParams, true) + privkeyWIF, err := btcutil.NewWIF(sk, r.BitcoinParams, true) if err != nil { return "", "", err } address, err := btcutil.NewAddressWitnessPubKeyHash( btcutil.Hash160(privkeyWIF.SerializePubKey()), - runner.BitcoinParams, + r.BitcoinParams, ) if err != nil { return "", "", err @@ -73,30 +64,24 @@ func (runner *E2ERunner) GetBtcAddress() (string, string, error) { } // SetBtcAddress imports the deployer's private key into the Bitcoin node -func (runner *E2ERunner) SetBtcAddress(name string, rescan bool) { - skBytes, err := hex.DecodeString(runner.DeployerPrivateKey) - if err != nil { - panic(err) - } +func (r *E2ERunner) SetBtcAddress(name string, rescan bool) { + skBytes, err := hex.DecodeString(r.DeployerPrivateKey) + require.NoError(r, err) sk, _ := btcec.PrivKeyFromBytes(btcec.S256(), skBytes) - privkeyWIF, err := btcutil.NewWIF(sk, runner.BitcoinParams, true) - if err != nil { - panic(err) - } + privkeyWIF, err := btcutil.NewWIF(sk, r.BitcoinParams, true) + require.NoError(r, err) if rescan { - err := runner.BtcRPCClient.ImportPrivKeyRescan(privkeyWIF, name, true) - require.NoError(runner, err, "failed to execute ImportPrivKeyRescan") + err := r.BtcRPCClient.ImportPrivKeyRescan(privkeyWIF, name, true) + require.NoError(r, err, "failed to execute ImportPrivKeyRescan") } - runner.BTCDeployerAddress, err = btcutil.NewAddressWitnessPubKeyHash( + r.BTCDeployerAddress, err = btcutil.NewAddressWitnessPubKeyHash( btcutil.Hash160(privkeyWIF.PrivKey.PubKey().SerializeCompressed()), - runner.BitcoinParams, + r.BitcoinParams, ) - if err != nil { - panic(err) - } + require.NoError(r, err) - runner.Logger.Info("BTCDeployerAddress: %s", runner.BTCDeployerAddress.EncodeAddress()) + r.Logger.Info("BTCDeployerAddress: %s", r.BTCDeployerAddress.EncodeAddress()) } diff --git a/e2e/runner/setup_evm.go b/e2e/runner/setup_evm.go index 2bc0aeb70d..ff5b2e0ddc 100644 --- a/e2e/runner/setup_evm.go +++ b/e2e/runner/setup_evm.go @@ -5,6 +5,8 @@ import ( "time" ethcommon "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol" zetaeth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zeta.eth.sol" zetaconnectoreth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.eth.sol" @@ -21,181 +23,148 @@ const ( ) // SetEVMContractsFromConfig set EVM contracts for e2e test from the config -func (runner *E2ERunner) SetEVMContractsFromConfig() { +func (r *E2ERunner) SetEVMContractsFromConfig() { conf, err := config.ReadConfig(ContractsConfigFile) - if err != nil { - panic(err) - } + require.NoError(r, err) // Set ZetaEthAddr - runner.ZetaEthAddr = ethcommon.HexToAddress(conf.Contracts.EVM.ZetaEthAddress) - runner.ZetaEth, err = zetaeth.NewZetaEth(runner.ZetaEthAddr, runner.EVMClient) - if err != nil { - panic(err) - } + r.ZetaEthAddr = ethcommon.HexToAddress(conf.Contracts.EVM.ZetaEthAddress) + r.ZetaEth, err = zetaeth.NewZetaEth(r.ZetaEthAddr, r.EVMClient) + require.NoError(r, err) // Set ConnectorEthAddr - runner.ConnectorEthAddr = ethcommon.HexToAddress(conf.Contracts.EVM.ConnectorEthAddr) - runner.ConnectorEth, err = zetaconnectoreth.NewZetaConnectorEth(runner.ConnectorEthAddr, runner.EVMClient) - if err != nil { - panic(err) - } + r.ConnectorEthAddr = ethcommon.HexToAddress(conf.Contracts.EVM.ConnectorEthAddr) + r.ConnectorEth, err = zetaconnectoreth.NewZetaConnectorEth(r.ConnectorEthAddr, r.EVMClient) + require.NoError(r, err) } // SetupEVM setup contracts on EVM for e2e test -func (runner *E2ERunner) SetupEVM(contractsDeployed bool, whitelistERC20 bool) { - runner.Logger.Print("⚙️ setting up EVM network") +func (r *E2ERunner) SetupEVM(contractsDeployed bool, whitelistERC20 bool) { + r.Logger.Print("⚙️ setting up EVM network") startTime := time.Now() defer func() { - runner.Logger.Info("EVM setup took %s\n", time.Since(startTime)) + r.Logger.Info("EVM setup took %s\n", time.Since(startTime)) }() // TODO: put this logic outside of this function // We use this config to be consistent with the old implementation // https://github.com/zeta-chain/node-private/issues/41 if contractsDeployed { - runner.SetEVMContractsFromConfig() + r.SetEVMContractsFromConfig() return } conf := config.DefaultConfig() - runner.Logger.InfoLoud("Deploy ZetaETH ConnectorETH ERC20Custody ERC20\n") + r.Logger.InfoLoud("Deploy ZetaETH ConnectorETH ERC20Custody ERC20\n") // donate to the TSS address to avoid account errors because deploying gas token ZRC20 will automatically mint // gas token on ZetaChain to initialize the pool - txDonation, err := runner.SendEther( - runner.TSSAddress, - big.NewInt(101000000000000000), - []byte(constant.DonationMessage), - ) - if err != nil { - panic(err) - } + txDonation, err := r.SendEther(r.TSSAddress, big.NewInt(101000000000000000), []byte(constant.DonationMessage)) + require.NoError(r, err) - runner.Logger.Info("Deploying ZetaEth contract") + r.Logger.Info("Deploying ZetaEth contract") zetaEthAddr, txZetaEth, ZetaEth, err := zetaeth.DeployZetaEth( - runner.EVMAuth, - runner.EVMClient, - runner.DeployerAddress, + r.EVMAuth, + r.EVMClient, + r.DeployerAddress, big.NewInt(21_000_000_000), ) - if err != nil { - panic(err) - } - runner.ZetaEth = ZetaEth - runner.ZetaEthAddr = zetaEthAddr + require.NoError(r, err) + + r.ZetaEth = ZetaEth + r.ZetaEthAddr = zetaEthAddr conf.Contracts.EVM.ZetaEthAddress = zetaEthAddr.String() - runner.Logger.Info("ZetaEth contract address: %s, tx hash: %s", zetaEthAddr.Hex(), zetaEthAddr.Hash().Hex()) + r.Logger.Info("ZetaEth contract address: %s, tx hash: %s", zetaEthAddr.Hex(), zetaEthAddr.Hash().Hex()) - runner.Logger.Info("Deploying ZetaConnectorEth contract") + r.Logger.Info("Deploying ZetaConnectorEth contract") connectorEthAddr, txConnector, ConnectorEth, err := zetaconnectoreth.DeployZetaConnectorEth( - runner.EVMAuth, - runner.EVMClient, + r.EVMAuth, + r.EVMClient, zetaEthAddr, - runner.TSSAddress, - runner.DeployerAddress, - runner.DeployerAddress, + r.TSSAddress, + r.DeployerAddress, + r.DeployerAddress, ) - if err != nil { - panic(err) - } - runner.ConnectorEth = ConnectorEth - runner.ConnectorEthAddr = connectorEthAddr + require.NoError(r, err) + + r.ConnectorEth = ConnectorEth + r.ConnectorEthAddr = connectorEthAddr conf.Contracts.EVM.ConnectorEthAddr = connectorEthAddr.String() - runner.Logger.Info( + r.Logger.Info( "ZetaConnectorEth contract address: %s, tx hash: %s", connectorEthAddr.Hex(), txConnector.Hash().Hex(), ) - runner.Logger.Info("Deploying ERC20Custody contract") + r.Logger.Info("Deploying ERC20Custody contract") erc20CustodyAddr, txCustody, ERC20Custody, err := erc20custody.DeployERC20Custody( - runner.EVMAuth, - runner.EVMClient, - runner.DeployerAddress, - runner.DeployerAddress, + r.EVMAuth, + r.EVMClient, + r.DeployerAddress, + r.DeployerAddress, big.NewInt(0), big.NewInt(1e18), ethcommon.HexToAddress("0x"), ) - if err != nil { - panic(err) - } - runner.ERC20CustodyAddr = erc20CustodyAddr - runner.ERC20Custody = ERC20Custody - runner.Logger.Info("ERC20Custody contract address: %s, tx hash: %s", erc20CustodyAddr.Hex(), txCustody.Hash().Hex()) - - runner.Logger.Info("Deploying ERC20 contract") - erc20Addr, txERC20, erc20, err := erc20.DeployERC20(runner.EVMAuth, runner.EVMClient, "TESTERC20", "TESTERC20", 6) - if err != nil { - panic(err) - } - runner.ERC20 = erc20 - runner.ERC20Addr = erc20Addr - runner.Logger.Info("ERC20 contract address: %s, tx hash: %s", erc20Addr.Hex(), txERC20.Hash().Hex()) + require.NoError(r, err) + + r.ERC20CustodyAddr = erc20CustodyAddr + r.ERC20Custody = ERC20Custody + r.Logger.Info("ERC20Custody contract address: %s, tx hash: %s", erc20CustodyAddr.Hex(), txCustody.Hash().Hex()) + + r.Logger.Info("Deploying ERC20 contract") + erc20Addr, txERC20, erc20, err := erc20.DeployERC20(r.EVMAuth, r.EVMClient, "TESTERC20", "TESTERC20", 6) + require.NoError(r, err) + + r.ERC20 = erc20 + r.ERC20Addr = erc20Addr + r.Logger.Info("ERC20 contract address: %s, tx hash: %s", erc20Addr.Hex(), txERC20.Hash().Hex()) // deploy TestDApp contract appAddr, txApp, _, err := testdapp.DeployTestDApp( - runner.EVMAuth, - runner.EVMClient, - runner.ConnectorEthAddr, - runner.ZetaEthAddr, + r.EVMAuth, + r.EVMClient, + r.ConnectorEthAddr, + r.ZetaEthAddr, ) - if err != nil { - panic(err) + require.NoError(r, err) + + r.EvmTestDAppAddr = appAddr + r.Logger.Info("TestDApp contract address: %s, tx hash: %s", appAddr.Hex(), txApp.Hash().Hex()) + + ensureTxReceipt := func(tx *ethtypes.Transaction, failMessage string) { + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt, failMessage) } - runner.EvmTestDAppAddr = appAddr - runner.Logger.Info("TestDApp contract address: %s, tx hash: %s", appAddr.Hex(), txApp.Hash().Hex()) // check contract deployment receipt - if receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, txDonation, runner.Logger, runner.ReceiptTimeout); receipt.Status != 1 { - panic("EVM donation tx failed") - } - if receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, txZetaEth, runner.Logger, runner.ReceiptTimeout); receipt.Status != 1 { - panic("ZetaEth deployment failed") - } - if receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, txConnector, runner.Logger, runner.ReceiptTimeout); receipt.Status != 1 { - panic("ZetaConnectorEth deployment failed") - } - if receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, txCustody, runner.Logger, runner.ReceiptTimeout); receipt.Status != 1 { - panic("ERC20Custody deployment failed") - } - if receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, txERC20, runner.Logger, runner.ReceiptTimeout); receipt.Status != 1 { - panic("ERC20 deployment failed") - } - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, txApp, runner.Logger, runner.ReceiptTimeout) - if receipt.Status != 1 { - panic("TestDApp deployment failed") - } + ensureTxReceipt(txDonation, "EVM donation tx failed") + ensureTxReceipt(txZetaEth, "ZetaEth deployment failed") + ensureTxReceipt(txConnector, "ZetaConnectorEth deployment failed") + ensureTxReceipt(txCustody, "ERC20Custody deployment failed") + ensureTxReceipt(txERC20, "ERC20 deployment failed") + ensureTxReceipt(txApp, "TestDApp deployment failed") // initialize custody contract - runner.Logger.Info("Whitelist ERC20") + r.Logger.Info("Whitelist ERC20") if whitelistERC20 { - txWhitelist, err := ERC20Custody.Whitelist(runner.EVMAuth, erc20Addr) - if err != nil { - panic(err) - } - if receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, txWhitelist, runner.Logger, runner.ReceiptTimeout); receipt.Status != 1 { - panic("ERC20 whitelist failed") - } + txWhitelist, err := ERC20Custody.Whitelist(r.EVMAuth, erc20Addr) + require.NoError(r, err) + ensureTxReceipt(txWhitelist, "ERC20 whitelist failed") } - runner.Logger.Info("Set TSS address") - txCustody, err = ERC20Custody.UpdateTSSAddress(runner.EVMAuth, runner.TSSAddress) - if err != nil { - panic(err) - } - if receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, txCustody, runner.Logger, runner.ReceiptTimeout); receipt.Status != 1 { - panic("ERC20 update TSS address failed") - } - runner.Logger.Info("TSS set receipt tx hash: %s", txCustody.Hash().Hex()) + r.Logger.Info("Set TSS address") + txCustody, err = ERC20Custody.UpdateTSSAddress(r.EVMAuth, r.TSSAddress) + require.NoError(r, err) + + ensureTxReceipt(txCustody, "ERC20 update TSS address failed") + + r.Logger.Info("TSS set receipt tx hash: %s", txCustody.Hash().Hex()) // save config containing contract addresses // TODO: put this logic outside of this function in a general config // We use this config to be consistent with the old implementation // https://github.com/zeta-chain/node-private/issues/41 - if err := config.WriteConfig(ContractsConfigFile, conf); err != nil { - panic(err) - } + require.NoError(r, config.WriteConfig(ContractsConfigFile, conf)) } diff --git a/e2e/runner/setup_zeta.go b/e2e/runner/setup_zeta.go index ac24c02de2..ef3acbd64b 100644 --- a/e2e/runner/setup_zeta.go +++ b/e2e/runner/setup_zeta.go @@ -7,6 +7,7 @@ import ( "github.com/btcsuite/btcutil" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/systemcontract.sol" "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/wzeta.sol" connectorzevm "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zetaconnectorzevm.sol" @@ -29,23 +30,23 @@ import ( var EmissionsPoolFunding = big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(2e7)) // SetTSSAddresses set TSS addresses from information queried from ZetaChain -func (runner *E2ERunner) SetTSSAddresses() error { - runner.Logger.Print("⚙️ setting up TSS address") +func (r *E2ERunner) SetTSSAddresses() error { + r.Logger.Print("⚙️ setting up TSS address") - btcChainID, err := chains.GetBTCChainIDFromChainParams(runner.BitcoinParams) + btcChainID, err := chains.GetBTCChainIDFromChainParams(r.BitcoinParams) if err != nil { return err } res := &observertypes.QueryGetTssAddressResponse{} for i := 0; ; i++ { - res, err = runner.ObserverClient.GetTssAddress(runner.Ctx, &observertypes.QueryGetTssAddressRequest{ + res, err = r.ObserverClient.GetTssAddress(r.Ctx, &observertypes.QueryGetTssAddressRequest{ BitcoinChainId: btcChainID, }) if err != nil { if i%10 == 0 { - runner.Logger.Info("ObserverClient.TSS error %s", err.Error()) - runner.Logger.Info("TSS not ready yet, waiting for TSS to be appear in zetacore network...") + r.Logger.Info("ObserverClient.TSS error %s", err.Error()) + r.Logger.Info("TSS not ready yet, waiting for TSS to be appear in zetacore network...") } time.Sleep(1 * time.Second) continue @@ -55,199 +56,165 @@ func (runner *E2ERunner) SetTSSAddresses() error { tssAddress := ethcommon.HexToAddress(res.Eth) - btcTSSAddress, err := btcutil.DecodeAddress(res.Btc, runner.BitcoinParams) - if err != nil { - panic(err) - } + btcTSSAddress, err := btcutil.DecodeAddress(res.Btc, r.BitcoinParams) + require.NoError(r, err) - runner.TSSAddress = tssAddress - runner.BTCTSSAddress = btcTSSAddress + r.TSSAddress = tssAddress + r.BTCTSSAddress = btcTSSAddress return nil } // SetZEVMContracts set contracts for the ZEVM -func (runner *E2ERunner) SetZEVMContracts() { - runner.Logger.Print("⚙️ deploying system contracts and ZRC20s on ZEVM") +func (r *E2ERunner) SetZEVMContracts() { + r.Logger.Print("⚙️ deploying system contracts and ZRC20s on ZEVM") startTime := time.Now() defer func() { - runner.Logger.Info("System contract deployments took %s\n", time.Since(startTime)) + r.Logger.Info("System contract deployments took %s\n", time.Since(startTime)) }() // deploy system contracts and ZRC20 contracts on ZetaChain - uniswapV2FactoryAddr, uniswapV2RouterAddr, zevmConnectorAddr, wzetaAddr, erc20zrc20Addr, err := runner.ZetaTxServer.DeploySystemContractsAndZRC20( + uniswapV2FactoryAddr, uniswapV2RouterAddr, zevmConnectorAddr, wzetaAddr, erc20zrc20Addr, err := r.ZetaTxServer.DeploySystemContractsAndZRC20( e2eutils.FungibleAdminName, - runner.ERC20Addr.Hex(), + r.ERC20Addr.Hex(), ) - if err != nil { - panic(err) - } + require.NoError(r, err) // Set ERC20ZRC20Addr - runner.ERC20ZRC20Addr = ethcommon.HexToAddress(erc20zrc20Addr) - runner.ERC20ZRC20, err = zrc20.NewZRC20(runner.ERC20ZRC20Addr, runner.ZEVMClient) - if err != nil { - panic(err) - } + r.ERC20ZRC20Addr = ethcommon.HexToAddress(erc20zrc20Addr) + r.ERC20ZRC20, err = zrc20.NewZRC20(r.ERC20ZRC20Addr, r.ZEVMClient) + require.NoError(r, err) // UniswapV2FactoryAddr - runner.UniswapV2FactoryAddr = ethcommon.HexToAddress(uniswapV2FactoryAddr) - runner.UniswapV2Factory, err = uniswapv2factory.NewUniswapV2Factory(runner.UniswapV2FactoryAddr, runner.ZEVMClient) - if err != nil { - panic(err) - } + r.UniswapV2FactoryAddr = ethcommon.HexToAddress(uniswapV2FactoryAddr) + r.UniswapV2Factory, err = uniswapv2factory.NewUniswapV2Factory(r.UniswapV2FactoryAddr, r.ZEVMClient) + require.NoError(r, err) // UniswapV2RouterAddr - runner.UniswapV2RouterAddr = ethcommon.HexToAddress(uniswapV2RouterAddr) - runner.UniswapV2Router, err = uniswapv2router.NewUniswapV2Router02(runner.UniswapV2RouterAddr, runner.ZEVMClient) - if err != nil { - panic(err) - } + r.UniswapV2RouterAddr = ethcommon.HexToAddress(uniswapV2RouterAddr) + r.UniswapV2Router, err = uniswapv2router.NewUniswapV2Router02(r.UniswapV2RouterAddr, r.ZEVMClient) + require.NoError(r, err) // ZevmConnectorAddr - runner.ConnectorZEVMAddr = ethcommon.HexToAddress(zevmConnectorAddr) - runner.ConnectorZEVM, err = connectorzevm.NewZetaConnectorZEVM(runner.ConnectorZEVMAddr, runner.ZEVMClient) - if err != nil { - panic(err) - } + r.ConnectorZEVMAddr = ethcommon.HexToAddress(zevmConnectorAddr) + r.ConnectorZEVM, err = connectorzevm.NewZetaConnectorZEVM(r.ConnectorZEVMAddr, r.ZEVMClient) + require.NoError(r, err) // WZetaAddr - runner.WZetaAddr = ethcommon.HexToAddress(wzetaAddr) - runner.WZeta, err = wzeta.NewWETH9(runner.WZetaAddr, runner.ZEVMClient) - if err != nil { - panic(err) - } + r.WZetaAddr = ethcommon.HexToAddress(wzetaAddr) + r.WZeta, err = wzeta.NewWETH9(r.WZetaAddr, r.ZEVMClient) + require.NoError(r, err) // query system contract address from the chain - systemContractRes, err := runner.FungibleClient.SystemContract( - runner.Ctx, + systemContractRes, err := r.FungibleClient.SystemContract( + r.Ctx, &fungibletypes.QueryGetSystemContractRequest{}, ) - if err != nil { - panic(err) - } - systemContractAddr := ethcommon.HexToAddress(systemContractRes.SystemContract.SystemContract) + require.NoError(r, err) - SystemContract, err := systemcontract.NewSystemContract( + systemContractAddr := ethcommon.HexToAddress(systemContractRes.SystemContract.SystemContract) + systemContract, err := systemcontract.NewSystemContract( systemContractAddr, - runner.ZEVMClient, + r.ZEVMClient, ) - if err != nil { - panic(err) - } + require.NoError(r, err) - runner.SystemContract = SystemContract - runner.SystemContractAddr = systemContractAddr + r.SystemContract = systemContract + r.SystemContractAddr = systemContractAddr // set ZRC20 contracts - runner.SetupETHZRC20() - runner.SetupBTCZRC20() + r.SetupETHZRC20() + r.SetupBTCZRC20() // deploy TestDApp contract on zEVM appAddr, txApp, _, err := testdapp.DeployTestDApp( - runner.ZEVMAuth, - runner.ZEVMClient, - runner.ConnectorZEVMAddr, - runner.WZetaAddr, + r.ZEVMAuth, + r.ZEVMClient, + r.ConnectorZEVMAddr, + r.WZetaAddr, ) - if err != nil { - panic(err) - } - runner.ZevmTestDAppAddr = appAddr - runner.Logger.Info("TestDApp Zevm contract address: %s, tx hash: %s", appAddr.Hex(), txApp.Hash().Hex()) + require.NoError(r, err) + + r.ZevmTestDAppAddr = appAddr + r.Logger.Info("TestDApp Zevm contract address: %s, tx hash: %s", appAddr.Hex(), txApp.Hash().Hex()) // deploy ZEVMSwapApp and ContextApp zevmSwapAppAddr, txZEVMSwapApp, zevmSwapApp, err := zevmswap.DeployZEVMSwapApp( - runner.ZEVMAuth, - runner.ZEVMClient, - runner.UniswapV2RouterAddr, - runner.SystemContractAddr, + r.ZEVMAuth, + r.ZEVMClient, + r.UniswapV2RouterAddr, + r.SystemContractAddr, ) - if err != nil { - panic(err) - } + require.NoError(r, err) - contextAppAddr, txContextApp, contextApp, err := contextapp.DeployContextApp(runner.ZEVMAuth, runner.ZEVMClient) - if err != nil { - panic(err) - } + contextAppAddr, txContextApp, contextApp, err := contextapp.DeployContextApp(r.ZEVMAuth, r.ZEVMClient) + require.NoError(r, err) receipt := e2eutils.MustWaitForTxReceipt( - runner.Ctx, - runner.ZEVMClient, + r.Ctx, + r.ZEVMClient, txZEVMSwapApp, - runner.Logger, - runner.ReceiptTimeout, + r.Logger, + r.ReceiptTimeout, ) - if receipt.Status != 1 { - panic("ZEVMSwapApp deployment failed") - } - runner.ZEVMSwapAppAddr = zevmSwapAppAddr - runner.ZEVMSwapApp = zevmSwapApp + r.requireTxSuccessful(receipt, "ZEVMSwapApp deployment failed") + + r.ZEVMSwapAppAddr = zevmSwapAppAddr + r.ZEVMSwapApp = zevmSwapApp receipt = e2eutils.MustWaitForTxReceipt( - runner.Ctx, - runner.ZEVMClient, + r.Ctx, + r.ZEVMClient, txContextApp, - runner.Logger, - runner.ReceiptTimeout, + r.Logger, + r.ReceiptTimeout, ) - if receipt.Status != 1 { - panic("ContextApp deployment failed") - } - runner.ContextAppAddr = contextAppAddr - runner.ContextApp = contextApp + r.requireTxSuccessful(receipt, "ContextApp deployment failed") + r.ContextAppAddr = contextAppAddr + r.ContextApp = contextApp } // SetupETHZRC20 sets up the ETH ZRC20 in the runner from the values queried from the chain -func (runner *E2ERunner) SetupETHZRC20() { - ethZRC20Addr, err := runner.SystemContract.GasCoinZRC20ByChainId( +func (r *E2ERunner) SetupETHZRC20() { + ethZRC20Addr, err := r.SystemContract.GasCoinZRC20ByChainId( &bind.CallOpts{}, big.NewInt(chains.GoerliLocalnet.ChainId), ) - if err != nil { - panic(err) - } - if (ethZRC20Addr == ethcommon.Address{}) { - panic("eth zrc20 not found") - } - runner.ETHZRC20Addr = ethZRC20Addr - ethZRC20, err := zrc20.NewZRC20(ethZRC20Addr, runner.ZEVMClient) - if err != nil { - panic(err) - } - runner.ETHZRC20 = ethZRC20 + require.NoError(r, err) + require.NotEqual(r, ethcommon.Address{}, ethZRC20Addr, "eth zrc20 not found") + + r.ETHZRC20Addr = ethZRC20Addr + ethZRC20, err := zrc20.NewZRC20(ethZRC20Addr, r.ZEVMClient) + require.NoError(r, err) + + r.ETHZRC20 = ethZRC20 } // SetupBTCZRC20 sets up the BTC ZRC20 in the runner from the values queried from the chain -func (runner *E2ERunner) SetupBTCZRC20() { - BTCZRC20Addr, err := runner.SystemContract.GasCoinZRC20ByChainId( +func (r *E2ERunner) SetupBTCZRC20() { + BTCZRC20Addr, err := r.SystemContract.GasCoinZRC20ByChainId( &bind.CallOpts{}, big.NewInt(chains.BitcoinRegtest.ChainId), ) - if err != nil { - panic(err) - } - runner.BTCZRC20Addr = BTCZRC20Addr - runner.Logger.Info("BTCZRC20Addr: %s", BTCZRC20Addr.Hex()) - BTCZRC20, err := zrc20.NewZRC20(BTCZRC20Addr, runner.ZEVMClient) - if err != nil { - panic(err) - } - runner.BTCZRC20 = BTCZRC20 + require.NoError(r, err) + r.BTCZRC20Addr = BTCZRC20Addr + r.Logger.Info("BTCZRC20Addr: %s", BTCZRC20Addr.Hex()) + BTCZRC20, err := zrc20.NewZRC20(BTCZRC20Addr, r.ZEVMClient) + require.NoError(r, err) + r.BTCZRC20 = BTCZRC20 } // EnableHeaderVerification enables the header verification for the given chain IDs -func (runner *E2ERunner) EnableHeaderVerification(chainIDList []int64) error { - runner.Logger.Print("⚙️ enabling verification flags for block headers") +func (r *E2ERunner) EnableHeaderVerification(chainIDList []int64) error { + r.Logger.Print("⚙️ enabling verification flags for block headers") - return runner.ZetaTxServer.EnableHeaderVerification(e2eutils.FungibleAdminName, chainIDList) + return r.ZetaTxServer.EnableHeaderVerification(e2eutils.FungibleAdminName, chainIDList) } // FundEmissionsPool funds the emissions pool on ZetaChain with the same value as used originally on mainnet (20M ZETA) -func (runner *E2ERunner) FundEmissionsPool() error { - runner.Logger.Print("⚙️ funding the emissions pool on ZetaChain with 20M ZETA (%s)", txserver.EmissionsPoolAddress) +func (r *E2ERunner) FundEmissionsPool() error { + r.Logger.Print("⚙️ funding the emissions pool on ZetaChain with 20M ZETA (%s)", txserver.EmissionsPoolAddress) - return runner.ZetaTxServer.FundEmissionsPool(e2eutils.FungibleAdminName, EmissionsPoolFunding) + return r.ZetaTxServer.FundEmissionsPool(e2eutils.FungibleAdminName, EmissionsPoolFunding) } diff --git a/e2e/runner/zeta.go b/e2e/runner/zeta.go index 104fb4900f..726f3f5cb6 100644 --- a/e2e/runner/zeta.go +++ b/e2e/runner/zeta.go @@ -1,11 +1,11 @@ package runner import ( - "fmt" "math/big" ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" zetaconnectoreth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.eth.sol" connectorzevm "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zetaconnectorzevm.sol" @@ -14,103 +14,77 @@ import ( ) // WaitForTxReceiptOnZEVM waits for a tx receipt on ZEVM -func (runner *E2ERunner) WaitForTxReceiptOnZEVM(tx *ethtypes.Transaction) { - defer func() { - runner.Unlock() - }() - runner.Lock() - - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) - if receipt.Status != 1 { - panic("tx failed") - } +func (r *E2ERunner) WaitForTxReceiptOnZEVM(tx *ethtypes.Transaction) { + r.Lock() + defer r.Unlock() + + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt) } // WaitForMinedCCTX waits for a cctx to be mined from a tx -func (runner *E2ERunner) WaitForMinedCCTX(txHash ethcommon.Hash) { - defer func() { - runner.Unlock() - }() - runner.Lock() +func (r *E2ERunner) WaitForMinedCCTX(txHash ethcommon.Hash) { + r.Lock() + defer r.Unlock() cctx := utils.WaitCctxMinedByInboundHash( - runner.Ctx, + r.Ctx, txHash.Hex(), - runner.CctxClient, - runner.Logger, - runner.CctxTimeout, + r.CctxClient, + r.Logger, + r.CctxTimeout, ) - if cctx.CctxStatus.Status != types.CctxStatus_OutboundMined { - panic(fmt.Sprintf("expected cctx status to be mined; got %s, message: %s", - cctx.CctxStatus.Status.String(), - cctx.CctxStatus.StatusMessage), - ) - } + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_OutboundMined) } // WaitForMinedCCTXFromIndex waits for a cctx to be mined from its index -func (runner *E2ERunner) WaitForMinedCCTXFromIndex(index string) { - defer func() { - runner.Unlock() - }() - runner.Lock() - - cctx := utils.WaitCCTXMinedByIndex(runner.Ctx, index, runner.CctxClient, runner.Logger, runner.CctxTimeout) - if cctx.CctxStatus.Status != types.CctxStatus_OutboundMined { - panic(fmt.Sprintf("expected cctx status to be mined; got %s, message: %s", - cctx.CctxStatus.Status.String(), - cctx.CctxStatus.StatusMessage), - ) - } +func (r *E2ERunner) WaitForMinedCCTXFromIndex(index string) { + r.Lock() + defer r.Unlock() + + cctx := utils.WaitCCTXMinedByIndex(r.Ctx, index, r.CctxClient, r.Logger, r.CctxTimeout) + utils.RequireCCTXStatus(r, cctx, types.CctxStatus_OutboundMined) } // SendZetaOnEvm sends ZETA to an address on EVM // this allows the ZETA contract deployer to funds other accounts on EVM -func (runner *E2ERunner) SendZetaOnEvm(address ethcommon.Address, zetaAmount int64) *ethtypes.Transaction { +func (r *E2ERunner) SendZetaOnEvm(address ethcommon.Address, zetaAmount int64) *ethtypes.Transaction { // the deployer might be sending ZETA in different goroutines - defer func() { - runner.Unlock() - }() - runner.Lock() + r.Lock() + defer r.Unlock() amount := big.NewInt(1e18) amount = amount.Mul(amount, big.NewInt(zetaAmount)) - tx, err := runner.ZetaEth.Transfer(runner.EVMAuth, address, amount) - if err != nil { - panic(err) - } + tx, err := r.ZetaEth.Transfer(r.EVMAuth, address, amount) + require.NoError(r, err) + return tx } // DepositZeta deposits ZETA on ZetaChain from the ZETA smart contract on EVM -func (runner *E2ERunner) DepositZeta() ethcommon.Hash { +func (r *E2ERunner) DepositZeta() ethcommon.Hash { amount := big.NewInt(1e18) amount = amount.Mul(amount, big.NewInt(100)) // 100 Zeta - return runner.DepositZetaWithAmount(runner.DeployerAddress, amount) + return r.DepositZetaWithAmount(r.DeployerAddress, amount) } // DepositZetaWithAmount deposits ZETA on ZetaChain from the ZETA smart contract on EVM with the specified amount -func (runner *E2ERunner) DepositZetaWithAmount(to ethcommon.Address, amount *big.Int) ethcommon.Hash { - tx, err := runner.ZetaEth.Approve(runner.EVMAuth, runner.ConnectorEthAddr, amount) - if err != nil { - panic(err) - } - runner.Logger.Info("Approve tx hash: %s", tx.Hash().Hex()) +func (r *E2ERunner) DepositZetaWithAmount(to ethcommon.Address, amount *big.Int) ethcommon.Hash { + tx, err := r.ZetaEth.Approve(r.EVMAuth, r.ConnectorEthAddr, amount) + require.NoError(r, err) - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, tx, runner.Logger, runner.ReceiptTimeout) - runner.Logger.EVMReceipt(*receipt, "approve") - if receipt.Status != 1 { - panic("approve tx failed") - } + r.Logger.Info("Approve tx hash: %s", tx.Hash().Hex()) + + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.Logger.EVMReceipt(*receipt, "approve") + r.requireTxSuccessful(receipt, "approve tx failed") // query the chain ID using zevm client - zetaChainID, err := runner.ZEVMClient.ChainID(runner.Ctx) - if err != nil { - panic(err) - } + zetaChainID, err := r.ZEVMClient.ChainID(r.Ctx) + require.NoError(r, err) - tx, err = runner.ConnectorEth.Send(runner.EVMAuth, zetaconnectoreth.ZetaInterfacesSendInput{ + tx, err = r.ConnectorEth.Send(r.EVMAuth, zetaconnectoreth.ZetaInterfacesSendInput{ // TODO: allow user to specify destination chain id // https://github.com/zeta-chain/node-private/issues/41 DestinationChainId: zetaChainID, @@ -120,27 +94,24 @@ func (runner *E2ERunner) DepositZetaWithAmount(to ethcommon.Address, amount *big ZetaValueAndGas: amount, ZetaParams: nil, }) - if err != nil { - panic(err) - } - runner.Logger.Info("Send tx hash: %s", tx.Hash().Hex()) + require.NoError(r, err) - receipt = utils.MustWaitForTxReceipt(runner.Ctx, runner.EVMClient, tx, runner.Logger, runner.ReceiptTimeout) - runner.Logger.EVMReceipt(*receipt, "send") - if receipt.Status != 1 { - panic(fmt.Sprintf("expected tx receipt status to be 1; got %d", receipt.Status)) - } + r.Logger.Info("Send tx hash: %s", tx.Hash().Hex()) - runner.Logger.Info(" Logs:") + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.Logger.EVMReceipt(*receipt, "send") + r.requireTxSuccessful(receipt, "send tx failed") + + r.Logger.Info(" Logs:") for _, log := range receipt.Logs { - sentLog, err := runner.ConnectorEth.ParseZetaSent(*log) + sentLog, err := r.ConnectorEth.ParseZetaSent(*log) if err == nil { - runner.Logger.Info(" Connector: %s", runner.ConnectorEthAddr.String()) - runner.Logger.Info(" Dest Addr: %s", ethcommon.BytesToAddress(sentLog.DestinationAddress).Hex()) - runner.Logger.Info(" Dest Chain: %d", sentLog.DestinationChainId) - runner.Logger.Info(" Dest Gas: %d", sentLog.DestinationGasLimit) - runner.Logger.Info(" Zeta Value: %d", sentLog.ZetaValueAndGas) - runner.Logger.Info(" Block Num: %d", log.BlockNumber) + r.Logger.Info(" Connector: %s", r.ConnectorEthAddr.String()) + r.Logger.Info(" Dest Addr: %s", ethcommon.BytesToAddress(sentLog.DestinationAddress).Hex()) + r.Logger.Info(" Dest Chain: %d", sentLog.DestinationChainId) + r.Logger.Info(" Dest Gas: %d", sentLog.DestinationGasLimit) + r.Logger.Info(" Zeta Value: %d", sentLog.ZetaValueAndGas) + r.Logger.Info(" Block Num: %d", log.BlockNumber) } } @@ -148,71 +119,59 @@ func (runner *E2ERunner) DepositZetaWithAmount(to ethcommon.Address, amount *big } // DepositAndApproveWZeta deposits and approves WZETA on ZetaChain from the ZETA smart contract on ZEVM -func (runner *E2ERunner) DepositAndApproveWZeta(amount *big.Int) { - runner.ZEVMAuth.Value = amount - tx, err := runner.WZeta.Deposit(runner.ZEVMAuth) - if err != nil { - panic(err) - } - runner.ZEVMAuth.Value = big.NewInt(0) - runner.Logger.Info("wzeta deposit tx hash: %s", tx.Hash().Hex()) +func (r *E2ERunner) DepositAndApproveWZeta(amount *big.Int) { + r.ZEVMAuth.Value = amount + tx, err := r.WZeta.Deposit(r.ZEVMAuth) + require.NoError(r, err) - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) - runner.Logger.EVMReceipt(*receipt, "wzeta deposit") - if receipt.Status == 0 { - panic("deposit failed") - } + r.ZEVMAuth.Value = big.NewInt(0) + r.Logger.Info("wzeta deposit tx hash: %s", tx.Hash().Hex()) - tx, err = runner.WZeta.Approve(runner.ZEVMAuth, runner.ConnectorZEVMAddr, amount) - if err != nil { - panic(err) - } - runner.Logger.Info("wzeta approve tx hash: %s", tx.Hash().Hex()) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + r.Logger.EVMReceipt(*receipt, "wzeta deposit") + r.requireTxSuccessful(receipt, "deposit failed") - receipt = utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) - runner.Logger.EVMReceipt(*receipt, "wzeta approve") - if receipt.Status == 0 { - panic(fmt.Sprintf("approve failed, logs: %+v", receipt.Logs)) - } + tx, err = r.WZeta.Approve(r.ZEVMAuth, r.ConnectorZEVMAddr, amount) + require.NoError(r, err) + + r.Logger.Info("wzeta approve tx hash: %s", tx.Hash().Hex()) + + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + r.Logger.EVMReceipt(*receipt, "wzeta approve") + r.requireTxSuccessful(receipt, "approve failed, logs: %+v", receipt.Logs) } // WithdrawZeta withdraws ZETA from ZetaChain to the ZETA smart contract on EVM // waitReceipt specifies whether to wait for the tx receipt and check if the tx was successful -func (runner *E2ERunner) WithdrawZeta(amount *big.Int, waitReceipt bool) *ethtypes.Transaction { - chainID, err := runner.EVMClient.ChainID(runner.Ctx) - if err != nil { - panic(err) - } +func (r *E2ERunner) WithdrawZeta(amount *big.Int, waitReceipt bool) *ethtypes.Transaction { + chainID, err := r.EVMClient.ChainID(r.Ctx) + require.NoError(r, err) - tx, err := runner.ConnectorZEVM.Send(runner.ZEVMAuth, connectorzevm.ZetaInterfacesSendInput{ + tx, err := r.ConnectorZEVM.Send(r.ZEVMAuth, connectorzevm.ZetaInterfacesSendInput{ DestinationChainId: chainID, - DestinationAddress: runner.DeployerAddress.Bytes(), + DestinationAddress: r.DeployerAddress.Bytes(), DestinationGasLimit: big.NewInt(400_000), Message: nil, ZetaValueAndGas: amount, ZetaParams: nil, }) - if err != nil { - panic(err) - } - runner.Logger.Info("send tx hash: %s", tx.Hash().Hex()) + require.NoError(r, err) - if waitReceipt { - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) - runner.Logger.EVMReceipt(*receipt, "send") - if receipt.Status == 0 { - panic(fmt.Sprintf("send failed, logs: %+v", receipt.Logs)) + r.Logger.Info("send tx hash: %s", tx.Hash().Hex()) - } + if waitReceipt { + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + r.Logger.EVMReceipt(*receipt, "send") + r.requireTxSuccessful(receipt, "send failed, logs: %+v", receipt.Logs) - runner.Logger.Info(" Logs:") + r.Logger.Info(" Logs:") for _, log := range receipt.Logs { - sentLog, err := runner.ConnectorZEVM.ParseZetaSent(*log) + sentLog, err := r.ConnectorZEVM.ParseZetaSent(*log) if err == nil { - runner.Logger.Info(" Dest Addr: %s", ethcommon.BytesToAddress(sentLog.DestinationAddress).Hex()) - runner.Logger.Info(" Dest Chain: %d", sentLog.DestinationChainId) - runner.Logger.Info(" Dest Gas: %d", sentLog.DestinationGasLimit) - runner.Logger.Info(" Zeta Value: %d", sentLog.ZetaValueAndGas) + r.Logger.Info(" Dest Addr: %s", ethcommon.BytesToAddress(sentLog.DestinationAddress).Hex()) + r.Logger.Info(" Dest Chain: %d", sentLog.DestinationChainId) + r.Logger.Info(" Dest Gas: %d", sentLog.DestinationGasLimit) + r.Logger.Info(" Zeta Value: %d", sentLog.ZetaValueAndGas) } } } @@ -221,40 +180,37 @@ func (runner *E2ERunner) WithdrawZeta(amount *big.Int, waitReceipt bool) *ethtyp } // WithdrawEther withdraws Ether from ZetaChain to the ZETA smart contract on EVM -func (runner *E2ERunner) WithdrawEther(amount *big.Int) *ethtypes.Transaction { +func (r *E2ERunner) WithdrawEther(amount *big.Int) *ethtypes.Transaction { // withdraw - tx, err := runner.ETHZRC20.Withdraw(runner.ZEVMAuth, runner.DeployerAddress.Bytes(), amount) - if err != nil { - panic(err) - } - runner.Logger.EVMTransaction(*tx, "withdraw") + tx, err := r.ETHZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), amount) + require.NoError(r, err) - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) - if receipt.Status == 0 { - panic("withdraw failed") - } - runner.Logger.EVMReceipt(*receipt, "withdraw") - runner.Logger.ZRC20Withdrawal(runner.ETHZRC20, *receipt, "withdraw") + r.Logger.EVMTransaction(*tx, "withdraw") + + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt, "withdraw failed") + + r.Logger.EVMReceipt(*receipt, "withdraw") + r.Logger.ZRC20Withdrawal(r.ETHZRC20, *receipt, "withdraw") return tx } // WithdrawERC20 withdraws an ERC20 token from ZetaChain to the ZETA smart contract on EVM -func (runner *E2ERunner) WithdrawERC20(amount *big.Int) *ethtypes.Transaction { - tx, err := runner.ERC20ZRC20.Withdraw(runner.ZEVMAuth, runner.DeployerAddress.Bytes(), amount) - if err != nil { - panic(err) - } - runner.Logger.EVMTransaction(*tx, "withdraw") +func (r *E2ERunner) WithdrawERC20(amount *big.Int) *ethtypes.Transaction { + tx, err := r.ERC20ZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), amount) + require.NoError(r, err) + + r.Logger.EVMTransaction(*tx, "withdraw") - receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) - runner.Logger.Info("Receipt txhash %s status %d", receipt.TxHash, receipt.Status) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + r.Logger.Info("Receipt txhash %s status %d", receipt.TxHash, receipt.Status) for _, log := range receipt.Logs { - event, err := runner.ERC20ZRC20.ParseWithdrawal(*log) + event, err := r.ERC20ZRC20.ParseWithdrawal(*log) if err != nil { continue } - runner.Logger.Info( + r.Logger.Info( " logs: from %s, to %x, value %d, gasfee %d", event.From.Hex(), event.To, diff --git a/e2e/utils/evm.go b/e2e/utils/evm.go index fc6792d617..45b2a55890 100644 --- a/e2e/utils/evm.go +++ b/e2e/utils/evm.go @@ -11,6 +11,7 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/require" ) const ( @@ -34,24 +35,23 @@ func CheckNonce( } // MustWaitForTxReceipt waits until a broadcasted tx to be mined and return its receipt -// timeout and panic after 30s. func MustWaitForTxReceipt( ctx context.Context, client *ethclient.Client, tx *ethtypes.Transaction, logger infoLogger, - receiptTimeout time.Duration, + timeout time.Duration, ) *ethtypes.Receipt { - timeout := DefaultReceiptTimeout - if receiptTimeout != 0 { - timeout = receiptTimeout + if timeout == 0 { + timeout = DefaultReceiptTimeout } + t := TestingFromContext(ctx) + start := time.Now() for i := 0; ; i++ { - if time.Since(start) > timeout { - panic("waiting tx receipt timeout") - } + require.False(t, time.Since(start) > timeout, "waiting tx receipt timeout") + receipt, err := client.TransactionReceipt(ctx, tx.Hash()) if err != nil { if !errors.Is(err, ethereum.NotFound) && i%10 == 0 { diff --git a/e2e/utils/require.go b/e2e/utils/require.go new file mode 100644 index 0000000000..ffedb62e59 --- /dev/null +++ b/e2e/utils/require.go @@ -0,0 +1,47 @@ +package utils + +import ( + "fmt" + + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" + + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +// RequireCCTXStatus checks if the cctx status is equal to the expected status +func RequireCCTXStatus( + t require.TestingT, + cctx *crosschaintypes.CrossChainTx, + expected crosschaintypes.CctxStatus, + msgAndArgs ...any, +) { + msg := fmt.Sprintf("cctx status is not %q", expected.String()) + + require.NotNil(t, cctx.CctxStatus) + require.Equal(t, expected, cctx.CctxStatus.Status, msg+errSuffix(msgAndArgs...)) +} + +// RequireTxSuccessful checks if the receipt status is successful. +// Currently, it accepts eth receipt, but we can make this more generic by using type assertion. +func RequireTxSuccessful(t require.TestingT, receipt *ethtypes.Receipt, msgAndArgs ...any) { + msg := "receipt status is not successful" + require.Equal(t, ethtypes.ReceiptStatusSuccessful, receipt.Status, msg+errSuffix(msgAndArgs...)) +} + +// RequiredTxFailed checks if the receipt status is failed. +// Currently, it accepts eth receipt, but we can make this more generic by using type assertion. +func RequiredTxFailed(t require.TestingT, receipt *ethtypes.Receipt, msgAndArgs ...any) { + msg := "receipt status is not successful" + require.Equal(t, ethtypes.ReceiptStatusFailed, receipt.Status, msg+errSuffix(msgAndArgs...)) +} + +func errSuffix(msgAndArgs ...any) string { + if len(msgAndArgs) == 0 { + return "" + } + + template := "; " + msgAndArgs[0].(string) + + return fmt.Sprintf(template, msgAndArgs[1:]) +} diff --git a/e2e/utils/utils.go b/e2e/utils/utils.go index bfa3d509b3..5bc451c606 100644 --- a/e2e/utils/utils.go +++ b/e2e/utils/utils.go @@ -1,10 +1,12 @@ package utils import ( + "context" "encoding/hex" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" + "github.com/stretchr/testify/require" ) // ScriptPKToAddress is a hex string for P2WPKH script @@ -26,3 +28,20 @@ type infoLogger interface { type NoopLogger struct{} func (nl NoopLogger) Info(_ string, _ ...interface{}) {} + +type testingKey struct{} + +// WithTesting allows to store a testing.T instance in the context +func WithTesting(ctx context.Context, t require.TestingT) context.Context { + return context.WithValue(ctx, testingKey{}, t) +} + +// TestingFromContext extracts require.TestingT from the context or panics. +func TestingFromContext(ctx context.Context) require.TestingT { + t, ok := ctx.Value(testingKey{}).(require.TestingT) + if !ok { + panic("context missing require.TestingT key") + } + + return t +} diff --git a/e2e/utils/zetacore.go b/e2e/utils/zetacore.go index a641ea9518..cbba05de75 100644 --- a/e2e/utils/zetacore.go +++ b/e2e/utils/zetacore.go @@ -2,11 +2,10 @@ package utils import ( "context" - "fmt" "time" rpchttp "github.com/cometbft/cometbft/rpc/client/http" - coretypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/pkg/errors" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -26,14 +25,14 @@ const ( func WaitCctxMinedByInboundHash( ctx context.Context, inboundHash string, - cctxClient crosschaintypes.QueryClient, + client crosschaintypes.QueryClient, logger infoLogger, - cctxTimeout time.Duration, + timeout time.Duration, ) *crosschaintypes.CrossChainTx { - cctxs := WaitCctxsMinedByInboundHash(ctx, inboundHash, cctxClient, 1, logger, cctxTimeout) - if len(cctxs) == 0 { - panic(fmt.Sprintf("cctx not found, inboundHash: %s", inboundHash)) - } + t := TestingFromContext(ctx) + cctxs := WaitCctxsMinedByInboundHash(ctx, inboundHash, client, 1, logger, timeout) + require.NotEmpty(t, cctxs, "cctx not found, inboundHash: %s", inboundHash) + return cctxs[len(cctxs)-1] } @@ -41,41 +40,35 @@ func WaitCctxMinedByInboundHash( func WaitCctxsMinedByInboundHash( ctx context.Context, inboundHash string, - cctxClient crosschaintypes.QueryClient, + client crosschaintypes.QueryClient, cctxsCount int, logger infoLogger, - cctxTimeout time.Duration, + timeout time.Duration, ) []*crosschaintypes.CrossChainTx { - startTime := time.Now() - - timeout := DefaultCctxTimeout - if cctxTimeout != 0 { - timeout = cctxTimeout + if timeout == 0 { + timeout = DefaultCctxTimeout } + t := TestingFromContext(ctx) + + startTime := time.Now() + in := &crosschaintypes.QueryInboundHashToCctxDataRequest{InboundHash: inboundHash} + // fetch cctxs by inboundHash for i := 0; ; i++ { // declare cctxs here so we can print the last fetched one if we reach timeout var cctxs []*crosschaintypes.CrossChainTx - if time.Since(startTime) > timeout { - cctxMessage := "" - if len(cctxs) > 0 { - cctxMessage = fmt.Sprintf(", last cctx: %v", cctxs[0].String()) - } + timedOut := time.Since(startTime) > timeout + require.False(t, timedOut, "waiting cctx timeout, cctx not mined, inbound hash: %s", inboundHash) - panic(fmt.Sprintf("waiting cctx timeout, cctx not mined, inboundHash: %s%s", inboundHash, cctxMessage)) - } time.Sleep(1 * time.Second) // We use InTxHashToCctxData instead of InboundTrackerAllByChain to able to run these tests with the previous version // for the update tests // TODO: replace with InboundHashToCctxData once removed // https://github.com/zeta-chain/node/issues/2200 - res, err := cctxClient.InTxHashToCctxData(ctx, &crosschaintypes.QueryInboundHashToCctxDataRequest{ - InboundHash: inboundHash, - }) - + res, err := client.InTxHashToCctxData(ctx, in) if err != nil { // prevent spamming logs if i%10 == 0 { @@ -126,30 +119,27 @@ func WaitCctxsMinedByInboundHash( func WaitCCTXMinedByIndex( ctx context.Context, cctxIndex string, - cctxClient crosschaintypes.QueryClient, + client crosschaintypes.QueryClient, logger infoLogger, - cctxTimeout time.Duration, + timeout time.Duration, ) *crosschaintypes.CrossChainTx { - startTime := time.Now() - - timeout := DefaultCctxTimeout - if cctxTimeout != 0 { - timeout = cctxTimeout + if timeout == 0 { + timeout = DefaultCctxTimeout } + t := TestingFromContext(ctx) + startTime := time.Now() + in := &crosschaintypes.QueryGetCctxRequest{Index: cctxIndex} + for i := 0; ; i++ { - if time.Since(startTime) > timeout { - panic(fmt.Sprintf( - "waiting cctx timeout, cctx not mined, cctx: %s", - cctxIndex, - )) + require.False(t, time.Since(startTime) > timeout, "waiting cctx timeout, cctx not mined, cctx: %s", cctxIndex) + + if i > 0 { + time.Sleep(1 * time.Second) } - time.Sleep(1 * time.Second) // fetch cctx by index - res, err := cctxClient.Cctx(ctx, &crosschaintypes.QueryGetCctxRequest{ - Index: cctxIndex, - }) + res, err := client.Cctx(ctx, in) if err != nil { // prevent spamming logs if i%10 == 0 { @@ -157,6 +147,7 @@ func WaitCCTXMinedByIndex( } continue } + cctx := res.CrossChainTx if !IsTerminalStatus(cctx.CctxStatus.Status) { // prevent spamming logs @@ -259,26 +250,32 @@ func IsTerminalStatus(status crosschaintypes.CctxStatus) bool { // WaitForBlockHeight waits until the block height reaches the given height func WaitForBlockHeight( ctx context.Context, - height int64, + desiredHeight int64, rpcURL string, logger infoLogger, -) { +) error { // initialize rpc and check status rpc, err := rpchttp.New(rpcURL, "/websocket") if err != nil { - panic(err) + return errors.Wrap(err, "unable to create rpc client") } - status := &coretypes.ResultStatus{} - for i := 0; status.SyncInfo.LatestBlockHeight < height; i++ { - status, err = rpc.Status(ctx) + + var currentHeight int64 + for i := 0; currentHeight < desiredHeight; i++ { + s, err := rpc.Status(ctx) if err != nil { - panic(err) + return errors.Wrap(err, "unable to get status") } + + currentHeight = s.SyncInfo.LatestBlockHeight + time.Sleep(1 * time.Second) // prevent spamming logs if i%10 == 0 { - logger.Info("waiting for block: %d, current height: %d\n", height, status.SyncInfo.LatestBlockHeight) + logger.Info("waiting for block: %d, current height: %d\n", desiredHeight, currentHeight) } } + + return nil } diff --git a/testutil/helpers.go b/testutil/helpers.go new file mode 100644 index 0000000000..dc49a0b024 --- /dev/null +++ b/testutil/helpers.go @@ -0,0 +1,38 @@ +package testutil + +import ( + "fmt" + "os" + "strings" + + "github.com/stretchr/testify/assert" +) + +const helpersFile = "testutil/helpers.go" + +// Must a helper that terminates the program if the error is not nil. +func Must[T any](v T, err error) T { + NoError(err) + return v +} + +// NoError terminates the program if the error is not nil. +func NoError(err error) { + if err != nil { + exit(err) + } +} + +func exit(err error) { + fmt.Printf("Unable to continue execution: %s.\nStacktrace:\n", err) + + for _, line := range assert.CallerInfo() { + if strings.Contains(line, helpersFile) { + continue + } + + fmt.Println(" ", line) + } + + os.Exit(1) +} From 91886bafef52a2449279195d496797118494a041 Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:08:58 +0200 Subject: [PATCH 02/23] feat(fmt): Improve & speedup code formatting (#2375) * Improve & speed up code formatting * Fix golangcli-lint config (make it up to date) * Apply code style fixes * Update changelog --- .github/workflows/publish-release.yml | 5 +-- .github/workflows/sast-linters.yml | 5 +-- .golangci.yml | 37 +++++++++++++------ Makefile | 12 ++---- app/app.go | 1 - app/export.go | 1 - changelog.md | 1 + cmd/zetaclientd/debug.go | 1 - cmd/zetaclientd/keygen_tss.go | 1 - cmd/zetaclientd/main.go | 1 - cmd/zetaclientd/p2p_diagnostics.go | 2 - cmd/zetaclientd/utils.go | 1 - cmd/zetacored/add_observer_list.go | 2 - cmd/zetacored/main.go | 1 - cmd/zetacored/parse_genesis.go | 1 - cmd/zetatool/filterdeposit/evm.go | 1 - contrib/rpctest/main.go | 2 - ...test_message_passing_evm_to_zevm_revert.go | 1 - e2e/e2etests/test_rate_limiter.go | 1 - e2e/runner/report.go | 1 - e2e/txserver/zeta_tx_server.go | 1 - pkg/chains/address_taproot.go | 1 - pkg/proofs/ethereum/proof.go | 1 - scripts/fmt-golines.sh | 10 ----- scripts/fmt-imports.sh | 10 ----- scripts/fmt.sh | 26 +++++++++++++ testutil/keeper/crosschain.go | 1 - testutil/network/genesis_state.go | 1 - testutil/sample/crosschain.go | 1 - testutil/sample/lightclient.go | 1 - .../client/cli/tx_add_authorization.go | 1 - x/crosschain/client/cli/cli_tss.go | 2 - x/crosschain/client/cli/cli_zeta_height.go | 1 - x/crosschain/client/querytests/suite.go | 1 - x/crosschain/keeper/events.go | 2 - .../keeper/msg_server_refund_aborted_tx.go | 2 - x/crosschain/keeper/msg_server_update_tss.go | 1 - x/crosschain/migrations/v2/migrate.go | 1 - x/crosschain/migrations/v3/migrate.go | 1 - x/crosschain/migrations/v4/migrate.go | 1 - x/crosschain/migrations/v5/migrate.go | 3 -- x/crosschain/module.go | 1 - x/crosschain/types/status.go | 1 - .../client/cli/query_get_emmisons_factors.go | 1 - x/emissions/client/cli/query_list_balances.go | 1 - .../client/cli/tx_update_contract_bytecode.go | 1 - x/fungible/genesis.go | 1 - .../cli/tx_disable_verification_flags.go | 1 - .../cli/tx_enable_verification_flags.go | 1 - .../grpc_query_header_enabled_chains.go | 1 - .../message_disable_verification_flags.go | 1 - x/observer/client/cli/query_blame.go | 1 - x/observer/client/cli/query_chain_params.go | 1 - .../client/cli/query_get_tss_address.go | 2 - x/observer/client/cli/query_observers.go | 1 - .../client/cli/query_show_observer_count.go | 1 - x/observer/client/cli/tx_add_observer.go | 1 - .../client/cli/tx_disable_cctx_flags.go | 1 - x/observer/client/cli/tx_enable_cctx_flags.go | 1 - .../client/cli/tx_update_chain_params.go | 1 - .../cli/tx_update_gas_price_increase_flags.go | 1 - x/observer/client/cli/tx_update_observer.go | 1 - x/observer/client/cli/tx_vote_tss.go | 1 - x/observer/client/querytests/suite.go | 1 - x/observer/genesis.go | 1 - x/observer/keeper/grpc_query_observer.go | 1 - x/observer/keeper/hooks.go | 1 - x/observer/keeper/keeper.go | 1 - x/observer/keeper/msg_server_vote_tss.go | 1 - x/observer/keeper/nonce_to_cctx.go | 2 - x/observer/keeper/observer_set.go | 1 - x/observer/keeper/tss.go | 1 - x/observer/types/ballot.go | 1 - x/observer/types/keys.go | 1 - .../chains/bitcoin/observer/outbound.go | 1 - zetaclient/chains/evm/observer/observer.go | 1 - zetaclient/chains/evm/signer/outbound_data.go | 1 - .../supplychecker/zeta_supply_checker.go | 1 - zetaclient/zetacore/client.go | 1 - 79 files changed, 59 insertions(+), 128 deletions(-) delete mode 100644 scripts/fmt-golines.sh delete mode 100644 scripts/fmt-imports.sh create mode 100755 scripts/fmt.sh diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index a396f4d71d..e96bb39e46 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -113,11 +113,10 @@ jobs: - name: Run golangci-lint if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v6 with: - version: v1.54 + version: v1.59 skip-cache: true - args: --out-format=json - name: Mark Job Complete Skipped if: ${{ github.event.inputs.skip_checks == 'true' }} diff --git a/.github/workflows/sast-linters.yml b/.github/workflows/sast-linters.yml index 3b8381e19d..2372ff5264 100644 --- a/.github/workflows/sast-linters.yml +++ b/.github/workflows/sast-linters.yml @@ -69,11 +69,10 @@ jobs: go-version: '1.20' - name: Run golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v6 with: - version: v1.54 + version: v1.59 skip-cache: true - args: --out-format=json nosec_alert: runs-on: ubuntu-22.04 diff --git a/.golangci.yml b/.golangci.yml index f393d5880f..c9567f4b3b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,8 @@ +run: + go: '1.20' # as in go.mod + timeout: 5m + tests: false # exclude test from linting + linters: disable-all: true enable: @@ -18,24 +23,32 @@ linters: - bodyclose - unconvert - unused + - gci + - gofmt + - whitespace + linters-settings: gocyclo: min-complexity: 11 errcheck: - ignore: fmt:.*,io/ioutil:^Read.*,github.com/spf13/cobra:MarkFlagRequired,github.com/spf13/viper:BindPFlag - golint: - min-confidence: 1.1 + exclude-functions: + - fmt:.* + - io/ioutil:^Read.*, + - github.com/spf13/cobra:MarkFlagRequired + - github.com/spf13/viper:BindPFlag exhaustive: check-generated: false - exhaustivestruct: - check-generated: false + gci: + # Gci controls Go package import order and makes it always deterministic + # https://golangci-lint.run/usage/linters/#gci + sections: + - standard + - default + - prefix(github.com/zeta-chain/zetacore) + skip-generated: true + issues: + exclude-generated: strict exclude: - composite -run: - tests: false - deadline: 15m - timeout: 5m - skip-files: - - ".*\\.pb\\.go$" - + exclude-dirs: [ ".git", ".github" ] \ No newline at end of file diff --git a/Makefile b/Makefile index 0520f1f319..360e071485 100644 --- a/Makefile +++ b/Makefile @@ -145,14 +145,8 @@ gosec: ### Formatting ### ############################################################################### -fmt-import: - @bash ./scripts/fmt-imports.sh -@PHONY: fmt-import - -fmt-golines: - @echo "--> Formatting Go lines" - @bash ./scripts/fmt-golines.sh -.PHONY: fmt-golines +fmt: + @bash ./scripts/fmt.sh ############################################################################### ### Generation commands ### @@ -199,7 +193,7 @@ mocks: .PHONY: mocks # generate also includes Go code formatting -generate: proto-gen openapi specs typescript docs-zetacored mocks fmt-import fmt-golines +generate: proto-gen openapi specs typescript docs-zetacored mocks fmt .PHONY: generate ############################################################################### diff --git a/app/app.go b/app/app.go index 0688ca75db..f5d0abd7e9 100644 --- a/app/app.go +++ b/app/app.go @@ -316,7 +316,6 @@ func New( appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *App { - appCodec := encodingConfig.Codec cdc := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry diff --git a/app/export.go b/app/export.go index d75de64514..1f1ae26a96 100644 --- a/app/export.go +++ b/app/export.go @@ -17,7 +17,6 @@ import ( func (app *App) ExportAppStateAndValidators( forZeroHeight bool, jailAllowedAddrs []string, modulesToExport []string, ) (servertypes.ExportedApp, error) { - // as if they could withdraw from the start of the next block ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) diff --git a/changelog.md b/changelog.md index bf1a778f93..f7a819e383 100644 --- a/changelog.md +++ b/changelog.md @@ -51,6 +51,7 @@ * [2340](https://github.com/zeta-chain/node/pull/2340) - add ValidateInbound method for cctx orchestrator * [2344](https://github.com/zeta-chain/node/pull/2344) - group common data of EVM/Bitcoin signer and observer using base structs * [2357](https://github.com/zeta-chain/node/pull/2357) - integrate base Signer structure into EVM/Bitcoin Signer +* [2375](https://github.com/zeta-chain/node/pull/2375) - improve & speedup code formatting ### Tests diff --git a/cmd/zetaclientd/debug.go b/cmd/zetaclientd/debug.go index 4e10b24c25..4ba2f01516 100644 --- a/cmd/zetaclientd/debug.go +++ b/cmd/zetaclientd/debug.go @@ -187,7 +187,6 @@ func DebugCmd() *cobra.Command { if err != nil { return err } - } fmt.Println("BallotIdentifier : ", ballotIdentifier) diff --git a/cmd/zetaclientd/keygen_tss.go b/cmd/zetaclientd/keygen_tss.go index 0e74d878ca..007ce9ec8c 100644 --- a/cmd/zetaclientd/keygen_tss.go +++ b/cmd/zetaclientd/keygen_tss.go @@ -203,7 +203,6 @@ func SetTSSPubKey(tss *mc.TSS, logger zerolog.Logger) error { } logger.Info().Msgf("TSS address in hex: %s", tss.EVMAddress().Hex()) return nil - } func TestTSS(tss *mc.TSS, logger zerolog.Logger) error { keygenLogger := logger.With().Str("module", "test-keygen").Logger() diff --git a/cmd/zetaclientd/main.go b/cmd/zetaclientd/main.go index 99aaf55c10..b0b8ffb0e1 100644 --- a/cmd/zetaclientd/main.go +++ b/cmd/zetaclientd/main.go @@ -42,5 +42,4 @@ func SetupConfigForTest() { }) rand.Seed(time.Now().UnixNano()) - } diff --git a/cmd/zetaclientd/p2p_diagnostics.go b/cmd/zetaclientd/p2p_diagnostics.go index 9816c16eab..330f520013 100644 --- a/cmd/zetaclientd/p2p_diagnostics.go +++ b/cmd/zetaclientd/p2p_diagnostics.go @@ -32,7 +32,6 @@ func RunDiagnostics( hotkeyPk cryptotypes.PrivKey, cfg config.Config, ) error { - startLogger.Warn().Msg("P2P Diagnostic mode enabled") startLogger.Warn().Msgf("seed peer: %s", peers) priKey := secp256k1.PrivKey(hotkeyPk.Bytes()[:32]) @@ -46,7 +45,6 @@ func RunDiagnostics( var s *metrics.TelemetryServer if len(peers) == 0 { startLogger.Warn().Msg("No seed peer specified; assuming I'm the host") - } p2pPriKey, err := crypto.UnmarshalSecp256k1PrivateKey(priKey[:]) if err != nil { diff --git a/cmd/zetaclientd/utils.go b/cmd/zetaclientd/utils.go index 64db1c3efa..43caf04c11 100644 --- a/cmd/zetaclientd/utils.go +++ b/cmd/zetaclientd/utils.go @@ -140,7 +140,6 @@ func CreateChainObserverMap( co, err := btcobserver.NewObserver(appContext, btcChain, zetacoreClient, tss, dbpath, logger, btcConfig, ts) if err != nil { logger.Std.Error().Err(err).Msgf("NewObserver error for bitcoin chain %s", btcChain.String()) - } else { observerMap[btcChain.ChainId] = co } diff --git a/cmd/zetacored/add_observer_list.go b/cmd/zetacored/add_observer_list.go index fd614efbef..e2dd16a5b5 100644 --- a/cmd/zetacored/add_observer_list.go +++ b/cmd/zetacored/add_observer_list.go @@ -104,7 +104,6 @@ func AddObserverListCmd() *cobra.Command { ObserverBalance := sdk.NewCoins(sdk.NewCoin(config.BaseDenom, observerTokens)) // Generate the grant authorizations and created observer list for chain for _, info := range observerInfo { - if isValidatorOnly(info.IsObserver) { balances = append(balances, banktypes.Balance{ Address: info.ObserverAddress, @@ -403,7 +402,6 @@ func addStakingGrants(grants []authz.GrantAuthorization, info ObserverInfoReader }) return grants - } func AddGenesisAccount( diff --git a/cmd/zetacored/main.go b/cmd/zetacored/main.go index b00e3dd337..69fa673548 100644 --- a/cmd/zetacored/main.go +++ b/cmd/zetacored/main.go @@ -18,7 +18,6 @@ func main() { rootCmd, _ := NewRootCmd() if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil { - switch e := err.(type) { case server.ErrorCode: os.Exit(e.Code) diff --git a/cmd/zetacored/parse_genesis.go b/cmd/zetacored/parse_genesis.go index ec0a9bd313..8f177ee7ef 100644 --- a/cmd/zetacored/parse_genesis.go +++ b/cmd/zetacored/parse_genesis.go @@ -129,7 +129,6 @@ func ImportDataIntoFile( cdc codec.Codec, modifyEnabled bool, ) error { - appState, err := genutiltypes.GenesisStateFromGenDoc(*genDoc) if err != nil { return err diff --git a/cmd/zetatool/filterdeposit/evm.go b/cmd/zetatool/filterdeposit/evm.go index dadaeb4377..f2cea39b99 100644 --- a/cmd/zetatool/filterdeposit/evm.go +++ b/cmd/zetatool/filterdeposit/evm.go @@ -119,7 +119,6 @@ func GetHashListSegment( endBlock uint64, tssAddress string, cfg *config.Config) ([]Deposit, error) { - deposits := make([]Deposit, 0) connectorAddress := common.HexToAddress(cfg.ConnectorAddress) connectorContract, err := zetaconnector.NewZetaConnectorNonEth(connectorAddress, client) diff --git a/contrib/rpctest/main.go b/contrib/rpctest/main.go index 50d55468ba..a9cc1fb405 100644 --- a/contrib/rpctest/main.go +++ b/contrib/rpctest/main.go @@ -252,9 +252,7 @@ func main() { fmt.Printf(" receipt block number: %d\n", receipt.BlockNumber) fmt.Printf(" receipt transaction index: %d\n", receipt.TransactionIndex) fmt.Printf(" receipt contract address: %s\n", receipt.ContractAddress.Hex()) - } - } type EthClient struct { diff --git a/e2e/e2etests/test_message_passing_evm_to_zevm_revert.go b/e2e/e2etests/test_message_passing_evm_to_zevm_revert.go index b99ea8513f..99a49fba56 100644 --- a/e2e/e2etests/test_message_passing_evm_to_zevm_revert.go +++ b/e2e/e2etests/test_message_passing_evm_to_zevm_revert.go @@ -105,5 +105,4 @@ func TestMessagePassingEVMtoZEVMRevert(r *runner.E2ERunner, args []string) { previousBalanceAndAmountEVM.String(), newBalanceEVM.String(), ) - } diff --git a/e2e/e2etests/test_rate_limiter.go b/e2e/e2etests/test_rate_limiter.go index 8b88dc28aa..446d49a6b2 100644 --- a/e2e/e2etests/test_rate_limiter.go +++ b/e2e/e2etests/test_rate_limiter.go @@ -92,7 +92,6 @@ func createAndWaitWithdraws(r *runner.E2ERunner, withdrawType withdrawType, with // Perform RateLimiterWithdrawNumber withdraws to log time for completion txs := make([]*ethtypes.Transaction, rateLimiterWithdrawNumber) for i := 0; i < rateLimiterWithdrawNumber; i++ { - // create a new withdraw depending on the type switch withdrawType { case withdrawTypeZETA: diff --git a/e2e/runner/report.go b/e2e/runner/report.go index 82bb263856..d80024e0dd 100644 --- a/e2e/runner/report.go +++ b/e2e/runner/report.go @@ -126,5 +126,4 @@ func (r *E2ERunner) PrintNetworkReport(nr NetworkReport) { r.Logger.Print("Block Height: %d", nr.Height) r.Logger.Print("CCTX Processed: %d", nr.CctxCount) r.Logger.Print("Emissions Pool Balance: %sZETA", nr.EmissionsPoolBalance.Quo(sdkmath.NewIntFromUint64(1e18))) - } diff --git a/e2e/txserver/zeta_tx_server.go b/e2e/txserver/zeta_tx_server.go index fb2c403ada..b6f19a5807 100644 --- a/e2e/txserver/zeta_tx_server.go +++ b/e2e/txserver/zeta_tx_server.go @@ -156,7 +156,6 @@ func (zts ZetaTxServer) GetAccountAddressFromName(name string) (string, error) { // GetAllAccountAddress returns all account addresses func (zts ZetaTxServer) GetAllAccountAddress() []string { return zts.address - } // GetAccountMnemonic returns the account name from the given index diff --git a/pkg/chains/address_taproot.go b/pkg/chains/address_taproot.go index 1d927e2f9d..4ff270da7d 100644 --- a/pkg/chains/address_taproot.go +++ b/pkg/chains/address_taproot.go @@ -29,7 +29,6 @@ var _ btcutil.Address = &AddressTaproot{} // NewAddressTaproot returns a new AddressTaproot. func NewAddressTaproot(witnessProg []byte, net *chaincfg.Params) (*AddressTaproot, error) { - return newAddressTaproot(net.Bech32HRPSegwit, witnessProg) } diff --git a/pkg/proofs/ethereum/proof.go b/pkg/proofs/ethereum/proof.go index 6d457bc444..b09919f971 100644 --- a/pkg/proofs/ethereum/proof.go +++ b/pkg/proofs/ethereum/proof.go @@ -75,7 +75,6 @@ func (m *Proof) Delete(key []byte) error { func (m *Proof) Has(key []byte) (bool, error) { for i := 0; i < len(m.Keys); i++ { if bytes.Equal(m.Keys[i], key) { - return true, nil } } diff --git a/scripts/fmt-golines.sh b/scripts/fmt-golines.sh deleted file mode 100644 index a24b264d81..0000000000 --- a/scripts/fmt-golines.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -# Install golines -go install github.com/segmentio/golines@v0.12.2 - -# Run golines in Cosmos modules and ZetaClient codebase -find . -type f -name '*.go' -exec golines -w --max-len=120 {} + > /dev/null 2>&1 - -# Print a message to indicate completion -echo "Go source code lines formatted." \ No newline at end of file diff --git a/scripts/fmt-imports.sh b/scripts/fmt-imports.sh deleted file mode 100644 index 6e9df43948..0000000000 --- a/scripts/fmt-imports.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -# Install goimports-revise -go install github.com/incu6us/goimports-reviser/v3@v3.6.4 - -# Run goimports-revise on all Go files -find . -name '*.go' -exec goimports-reviser -project-name github.com/zeta-chain/zetacore -file-path {} \; > /dev/null 2>&1 - -# Print a message to indicate completion -echo "Go imports formatted." \ No newline at end of file diff --git a/scripts/fmt.sh b/scripts/fmt.sh new file mode 100755 index 0000000000..7d6ef5eb9f --- /dev/null +++ b/scripts/fmt.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Exit on any error +set -e + +if ! command -v golangci-lint &> /dev/null +then + echo "golangci-lint is not found, installing..." + go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.1 +fi + +if ! command -v golines &> /dev/null +then + echo "golines could not be found, installing..." + go install github.com/segmentio/golines@v0.12.2 +fi + +# Fix long lines +echo "Fixing long lines..." +golines -w --max-len=120 --ignore-generated --ignored-dirs=".git" --base-formatter="gofmt" . + +# Gofmt, fix & order imports, remove whitespaces +echo "Formatting code..." +golangci-lint run --enable-only 'gci' --enable-only 'gofmt' --enable-only 'whitespace' --fix + +echo "Code is formatted" diff --git a/testutil/keeper/crosschain.go b/testutil/keeper/crosschain.go index aec1ac7838..d2b1bc1d5b 100644 --- a/testutil/keeper/crosschain.go +++ b/testutil/keeper/crosschain.go @@ -293,7 +293,6 @@ func MockGetRevertGasLimitForERC20( }, true).Once() m.On("QueryGasLimit", mock.Anything, mock.Anything). Return(big.NewInt(returnVal), nil).Once() - } func MockPayGasAndUpdateCCTX( diff --git a/testutil/network/genesis_state.go b/testutil/network/genesis_state.go index 18f464ccb7..7f0bb2003c 100644 --- a/testutil/network/genesis_state.go +++ b/testutil/network/genesis_state.go @@ -28,7 +28,6 @@ func SetupZetaGenesisState( observerList []string, setupChainNonces bool, ) { - // Cross-chain genesis state var crossChainGenesis types.GenesisState require.NoError(t, codec.UnmarshalJSON(genesisState[types.ModuleName], &crossChainGenesis)) diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 7fc6678580..38d490af62 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -308,7 +308,6 @@ func GetValidZrc20WithdrawToETH(t *testing.T) (receipt ethtypes.Receipt) { err := json.Unmarshal([]byte(block), &receipt) require.NoError(t, err) return - } // receiver is bc1qysd4sp9q8my59ul9wsf5rvs9p387hf8vfwatzu diff --git a/testutil/sample/lightclient.go b/testutil/sample/lightclient.go index 70aa55b51a..bbb0fc1d9b 100644 --- a/testutil/sample/lightclient.go +++ b/testutil/sample/lightclient.go @@ -49,7 +49,6 @@ func HeaderSupportedChains() []lightclienttypes.HeaderSupportedChain { func BlockHeaderVerification() lightclienttypes.BlockHeaderVerification { return lightclienttypes.BlockHeaderVerification{HeaderSupportedChains: HeaderSupportedChains()} - } // Proof generates a proof and block header diff --git a/x/authority/client/cli/tx_add_authorization.go b/x/authority/client/cli/tx_add_authorization.go index 5658d24e91..d1329801a3 100644 --- a/x/authority/client/cli/tx_add_authorization.go +++ b/x/authority/client/cli/tx_add_authorization.go @@ -57,5 +57,4 @@ func GetPolicyType(policyTypeString string) (types.PolicyType, error) { default: return types.PolicyType_groupEmpty, fmt.Errorf("invalid policy type value: %d", policyType) } - } diff --git a/x/crosschain/client/cli/cli_tss.go b/x/crosschain/client/cli/cli_tss.go index c24733431f..f1391b9658 100644 --- a/x/crosschain/client/cli/cli_tss.go +++ b/x/crosschain/client/cli/cli_tss.go @@ -19,7 +19,6 @@ func CmdUpdateTss() *cobra.Command { Short: "Create a new TSSVoter", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - argsPubkey, err := cast.ToStringE(args[0]) if err != nil { return err @@ -45,7 +44,6 @@ func CmdMigrateTssFunds() *cobra.Command { Short: "Migrate TSS funds to the latest TSS address", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - argsChainID, err := strconv.ParseInt(args[0], 10, 64) if err != nil { return err diff --git a/x/crosschain/client/cli/cli_zeta_height.go b/x/crosschain/client/cli/cli_zeta_height.go index a2b0f1ea51..7d1f96c8ee 100644 --- a/x/crosschain/client/cli/cli_zeta_height.go +++ b/x/crosschain/client/cli/cli_zeta_height.go @@ -14,7 +14,6 @@ func CmdLastZetaHeight() *cobra.Command { Short: "Query last Zeta Height", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) error { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/crosschain/client/querytests/suite.go b/x/crosschain/client/querytests/suite.go index ca42b9b4ec..d9354b6d18 100644 --- a/x/crosschain/client/querytests/suite.go +++ b/x/crosschain/client/querytests/suite.go @@ -52,7 +52,6 @@ func (s *CliTestSuite) SetupSuite() { s.network = net _, err = s.network.WaitForHeight(1) s.Require().NoError(err) - } func (s *CliTestSuite) TearDownSuite() { diff --git a/x/crosschain/keeper/events.go b/x/crosschain/keeper/events.go index 1bff85d750..c503835f14 100644 --- a/x/crosschain/keeper/events.go +++ b/x/crosschain/keeper/events.go @@ -56,7 +56,6 @@ func EmitZetaWithdrawCreated(ctx sdk.Context, cctx types.CrossChainTx) { if err != nil { ctx.Logger().Error("Error emitting ZetaWithdrawCreated :", err) } - } func EmitOutboundSuccess(ctx sdk.Context, valueReceived string, oldStatus string, newStatus string, cctxIndex string) { @@ -70,7 +69,6 @@ func EmitOutboundSuccess(ctx sdk.Context, valueReceived string, oldStatus string if err != nil { ctx.Logger().Error("Error emitting MsgVoteOutbound :", err) } - } func EmitOutboundFailure(ctx sdk.Context, valueReceived string, oldStatus string, newStatus string, cctxIndex string) { diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index 1efd3227ec..201b507af6 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -22,7 +22,6 @@ func (k msgServer) RefundAbortedCCTX( goCtx context.Context, msg *types.MsgRefundAbortedCCTX, ) (*types.MsgRefundAbortedCCTXResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) // check if authorized @@ -99,5 +98,4 @@ func GetRefundAddress(refundAddress string) (ethcommon.Address, error) { return ethcommon.Address{}, errorsmod.Wrap(types.ErrInvalidAddress, "invalid refund address") } return ethRefundAddress, nil - } diff --git a/x/crosschain/keeper/msg_server_update_tss.go b/x/crosschain/keeper/msg_server_update_tss.go index 672d64e462..56052b6671 100644 --- a/x/crosschain/keeper/msg_server_update_tss.go +++ b/x/crosschain/keeper/msg_server_update_tss.go @@ -60,7 +60,6 @@ func (k msgServer) UpdateTssAddress( migratorTx.CctxStatus.Status.String(), ) } - } k.GetObserverKeeper().SetTssAndUpdateNonce(ctx, tss) diff --git a/x/crosschain/migrations/v2/migrate.go b/x/crosschain/migrations/v2/migrate.go index 67f6ae709e..4fad2501bb 100644 --- a/x/crosschain/migrations/v2/migrate.go +++ b/x/crosschain/migrations/v2/migrate.go @@ -19,7 +19,6 @@ func MigrateStore( crossChainStoreKey storetypes.StoreKey, cdc codec.BinaryCodec, ) error { - // Using New Types from observer module as the structure is the same var nodeAccounts []observerTypes.NodeAccount var crosschainFlags observerTypes.CrosschainFlags diff --git a/x/crosschain/migrations/v3/migrate.go b/x/crosschain/migrations/v3/migrate.go index cbe11eef98..a6ec4f293b 100644 --- a/x/crosschain/migrations/v3/migrate.go +++ b/x/crosschain/migrations/v3/migrate.go @@ -19,7 +19,6 @@ func MigrateStore( crossChainStoreKey storetypes.StoreKey, cdc codec.BinaryCodec, ) error { - // Fetch existing TSS existingTss := observertypes.TSS{} store := prefix.NewStore(ctx.KVStore(crossChainStoreKey), types.KeyPrefix(observertypes.TSSKey)) diff --git a/x/crosschain/migrations/v4/migrate.go b/x/crosschain/migrations/v4/migrate.go index 0be2ca2f08..367e9c54eb 100644 --- a/x/crosschain/migrations/v4/migrate.go +++ b/x/crosschain/migrations/v4/migrate.go @@ -130,7 +130,6 @@ func MoveNonceToObserverModule( for _, n := range nonceToCcTx { observerKeeper.SetNonceToCctx(ctx, n) } - } func MoveTssToObserverModule(ctx sdk.Context, diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go index 58d33629da..fcb42dc4d0 100644 --- a/x/crosschain/migrations/v5/migrate.go +++ b/x/crosschain/migrations/v5/migrate.go @@ -94,7 +94,6 @@ func SetZetaAccounting( abortedAmountZeta := sdkmath.ZeroUint() for _, cctx := range ccctxList { if cctx.CctxStatus.Status == types.CctxStatus_Aborted { - switch cctx.InboundParams.CoinType { case coin.CoinType_ERC20: { @@ -124,7 +123,6 @@ func SetZetaAccounting( abortedValue := GetAbortedAmount(cctx) abortedAmountZeta = abortedAmountZeta.Add(abortedValue) cctx.CctxStatus.IsAbortRefunded = false - } case coin.CoinType_Gas: { @@ -134,7 +132,6 @@ func SetZetaAccounting( } crosschainKeeper.SetCrossChainTx(ctx, cctx) } - } crosschainKeeper.SetZetaAccounting(ctx, types.ZetaAccounting{AbortedZetaAmount: abortedAmountZeta}) diff --git a/x/crosschain/module.go b/x/crosschain/module.go index 01bb84fc82..59f6bdfb11 100644 --- a/x/crosschain/module.go +++ b/x/crosschain/module.go @@ -136,7 +136,6 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err := cfg.RegisterMigration(types.ModuleName, 4, m.Migrate4to5); err != nil { panic(err) } - } // RegisterInvariants registers the crosschain module's invariants. diff --git a/x/crosschain/types/status.go b/x/crosschain/types/status.go index ded81edeec..320209ae78 100644 --- a/x/crosschain/types/status.go +++ b/x/crosschain/types/status.go @@ -31,7 +31,6 @@ func (m *Status) ChangeStatus(newStatus CctxStatus, msg string) { return } m.Status = newStatus - } //nolint:typecheck func (m *Status) ValidateTransition(newStatus CctxStatus) bool { diff --git a/x/emissions/client/cli/query_get_emmisons_factors.go b/x/emissions/client/cli/query_get_emmisons_factors.go index c98ec7c6af..ef19623975 100644 --- a/x/emissions/client/cli/query_get_emmisons_factors.go +++ b/x/emissions/client/cli/query_get_emmisons_factors.go @@ -14,7 +14,6 @@ func CmdGetEmmisonsFactors() *cobra.Command { Short: "Query GetEmmisonsFactors", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/emissions/client/cli/query_list_balances.go b/x/emissions/client/cli/query_list_balances.go index 3e40965d87..d16b0191dc 100644 --- a/x/emissions/client/cli/query_list_balances.go +++ b/x/emissions/client/cli/query_list_balances.go @@ -14,7 +14,6 @@ func CmdListPoolAddresses() *cobra.Command { Short: "Query list-pool-addresses", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/fungible/client/cli/tx_update_contract_bytecode.go b/x/fungible/client/cli/tx_update_contract_bytecode.go index 334cd12a68..2b2077792c 100644 --- a/x/fungible/client/cli/tx_update_contract_bytecode.go +++ b/x/fungible/client/cli/tx_update_contract_bytecode.go @@ -15,7 +15,6 @@ func CmdUpdateContractBytecode() *cobra.Command { Short: "Broadcast message UpdateContractBytecode", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/fungible/genesis.go b/x/fungible/genesis.go index ba8a3d0153..be5d6f7555 100644 --- a/x/fungible/genesis.go +++ b/x/fungible/genesis.go @@ -18,7 +18,6 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) if genState.SystemContract != nil { k.SetSystemContract(ctx, *genState.SystemContract) } - } // ExportGenesis returns the fungible module's exported genesis. diff --git a/x/lightclient/client/cli/tx_disable_verification_flags.go b/x/lightclient/client/cli/tx_disable_verification_flags.go index 4d86dee552..41ba1203a6 100644 --- a/x/lightclient/client/cli/tx_disable_verification_flags.go +++ b/x/lightclient/client/cli/tx_disable_verification_flags.go @@ -24,7 +24,6 @@ func CmdDisableVerificationFlags() *cobra.Command { `, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/lightclient/client/cli/tx_enable_verification_flags.go b/x/lightclient/client/cli/tx_enable_verification_flags.go index cf896fd2be..d8866c7400 100644 --- a/x/lightclient/client/cli/tx_enable_verification_flags.go +++ b/x/lightclient/client/cli/tx_enable_verification_flags.go @@ -24,7 +24,6 @@ func CmdEnableVerificationFlags() *cobra.Command { `, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/lightclient/keeper/grpc_query_header_enabled_chains.go b/x/lightclient/keeper/grpc_query_header_enabled_chains.go index 8a9700cc03..7408923ad8 100644 --- a/x/lightclient/keeper/grpc_query_header_enabled_chains.go +++ b/x/lightclient/keeper/grpc_query_header_enabled_chains.go @@ -51,5 +51,4 @@ func (k Keeper) HeaderEnabledChains( } return &types.QueryHeaderEnabledChainsResponse{HeaderEnabledChains: val.GetHeaderEnabledChains()}, nil - } diff --git a/x/lightclient/types/message_disable_verification_flags.go b/x/lightclient/types/message_disable_verification_flags.go index e051a7d4b7..5ee2964aa7 100644 --- a/x/lightclient/types/message_disable_verification_flags.go +++ b/x/lightclient/types/message_disable_verification_flags.go @@ -19,7 +19,6 @@ func NewMsgDisableHeaderVerification(creator string, chainIDs []int64) *MsgDisab Creator: creator, ChainIdList: chainIDs, } - } func (msg *MsgDisableHeaderVerification) Route() string { diff --git a/x/observer/client/cli/query_blame.go b/x/observer/client/cli/query_blame.go index ded997d35c..9d173f0a00 100644 --- a/x/observer/client/cli/query_blame.go +++ b/x/observer/client/cli/query_blame.go @@ -49,7 +49,6 @@ func CmdGetAllBlameRecords() *cobra.Command { Short: "Query AllBlameRecords", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/query_chain_params.go b/x/observer/client/cli/query_chain_params.go index b4126b5c76..3652dbf411 100644 --- a/x/observer/client/cli/query_chain_params.go +++ b/x/observer/client/cli/query_chain_params.go @@ -48,7 +48,6 @@ func CmdGetChainParams() *cobra.Command { Short: "Query GetChainParams", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/query_get_tss_address.go b/x/observer/client/cli/query_get_tss_address.go index f663ca43df..8e9b92d8bb 100644 --- a/x/observer/client/cli/query_get_tss_address.go +++ b/x/observer/client/cli/query_get_tss_address.go @@ -16,7 +16,6 @@ func CmdGetTssAddress() *cobra.Command { Short: "Query current tss address", Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err @@ -51,7 +50,6 @@ func CmdGetTssAddressByFinalizedZetaHeight() *cobra.Command { Short: "Query tss address by finalized zeta height (for historical tss addresses)", Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/query_observers.go b/x/observer/client/cli/query_observers.go index 6bdc34616c..721a0b12a6 100644 --- a/x/observer/client/cli/query_observers.go +++ b/x/observer/client/cli/query_observers.go @@ -14,7 +14,6 @@ func CmdObserverSet() *cobra.Command { Short: "Query observer set", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/query_show_observer_count.go b/x/observer/client/cli/query_show_observer_count.go index 43c7feb7a6..0f5f6039b0 100644 --- a/x/observer/client/cli/query_show_observer_count.go +++ b/x/observer/client/cli/query_show_observer_count.go @@ -14,7 +14,6 @@ func CmdShowObserverCount() *cobra.Command { Short: "Query show-observer-count", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/tx_add_observer.go b/x/observer/client/cli/tx_add_observer.go index 3c18fbcca5..b55606c1d1 100644 --- a/x/observer/client/cli/tx_add_observer.go +++ b/x/observer/client/cli/tx_add_observer.go @@ -18,7 +18,6 @@ func CmdAddObserver() *cobra.Command { Short: "Broadcast message add-observer", Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/tx_disable_cctx_flags.go b/x/observer/client/cli/tx_disable_cctx_flags.go index 53cdf923bf..be88aada31 100644 --- a/x/observer/client/cli/tx_disable_cctx_flags.go +++ b/x/observer/client/cli/tx_disable_cctx_flags.go @@ -17,7 +17,6 @@ func CmdDisableCCTX() *cobra.Command { Short: "Disable inbound and outbound for CCTX", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/tx_enable_cctx_flags.go b/x/observer/client/cli/tx_enable_cctx_flags.go index c21016e258..d4371118bd 100644 --- a/x/observer/client/cli/tx_enable_cctx_flags.go +++ b/x/observer/client/cli/tx_enable_cctx_flags.go @@ -17,7 +17,6 @@ func CmdEnableCCTX() *cobra.Command { Short: "Enable inbound and outbound for CCTX", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/tx_update_chain_params.go b/x/observer/client/cli/tx_update_chain_params.go index 81e5cac7a1..d677801c6a 100644 --- a/x/observer/client/cli/tx_update_chain_params.go +++ b/x/observer/client/cli/tx_update_chain_params.go @@ -19,7 +19,6 @@ func CmdUpdateChainParams() *cobra.Command { Short: "Broadcast message updateChainParams", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { - argChainParams := args[0] clientCtx, err := client.GetClientTxContext(cmd) diff --git a/x/observer/client/cli/tx_update_gas_price_increase_flags.go b/x/observer/client/cli/tx_update_gas_price_increase_flags.go index e2cc0a5685..5569104bcf 100644 --- a/x/observer/client/cli/tx_update_gas_price_increase_flags.go +++ b/x/observer/client/cli/tx_update_gas_price_increase_flags.go @@ -18,7 +18,6 @@ func CmdUpdateGasPriceIncreaseFlags() *cobra.Command { Short: "Update the gas price increase flags", Args: cobra.ExactArgs(5), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/tx_update_observer.go b/x/observer/client/cli/tx_update_observer.go index abc8c72e51..c04cfa2664 100644 --- a/x/observer/client/cli/tx_update_observer.go +++ b/x/observer/client/cli/tx_update_observer.go @@ -19,7 +19,6 @@ func CmdUpdateObserver() *cobra.Command { Short: "Broadcast message add-observer", Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err diff --git a/x/observer/client/cli/tx_vote_tss.go b/x/observer/client/cli/tx_vote_tss.go index 088ec36fcf..ce6591c749 100644 --- a/x/observer/client/cli/tx_vote_tss.go +++ b/x/observer/client/cli/tx_vote_tss.go @@ -19,7 +19,6 @@ func CmdVoteTSS() *cobra.Command { Short: "Vote for a new TSS creation", Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { - argsPubkey, err := cast.ToStringE(args[0]) if err != nil { return err diff --git a/x/observer/client/querytests/suite.go b/x/observer/client/querytests/suite.go index 8fc7063676..c0a0710c5b 100644 --- a/x/observer/client/querytests/suite.go +++ b/x/observer/client/querytests/suite.go @@ -51,7 +51,6 @@ func (s *CliTestSuite) SetupSuite() { s.network = net _, err = s.network.WaitForHeight(1) s.Require().NoError(err) - } func (s *CliTestSuite) TearDownSuite() { diff --git a/x/observer/genesis.go b/x/observer/genesis.go index 9a8a3bcee1..d39a771535 100644 --- a/x/observer/genesis.go +++ b/x/observer/genesis.go @@ -130,7 +130,6 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) for _, elem := range genState.NonceToCctx { k.SetNonceToCctx(ctx, elem) } - } // ExportGenesis returns the observer module's exported genesis. diff --git a/x/observer/keeper/grpc_query_observer.go b/x/observer/keeper/grpc_query_observer.go index 181ba163f8..5ae55ab30a 100644 --- a/x/observer/keeper/grpc_query_observer.go +++ b/x/observer/keeper/grpc_query_observer.go @@ -46,5 +46,4 @@ func (k Keeper) ObserverSet( return &types.QueryObserverSetResponse{ Observers: observerSet.ObserverList, }, nil - } diff --git a/x/observer/keeper/hooks.go b/x/observer/keeper/hooks.go index 7e11cae282..afe6b9eb91 100644 --- a/x/observer/keeper/hooks.go +++ b/x/observer/keeper/hooks.go @@ -37,7 +37,6 @@ func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, } func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) error { - err := h.k.CleanSlashedValidator(ctx, valAddr, fraction) if err != nil { return err diff --git a/x/observer/keeper/keeper.go b/x/observer/keeper/keeper.go index 1019fc1002..1b26fd3af3 100644 --- a/x/observer/keeper/keeper.go +++ b/x/observer/keeper/keeper.go @@ -48,7 +48,6 @@ func NewKeeper( lightclientKeeper: lightclientKeeper, authority: authority, } - } func (k Keeper) GetSlashingKeeper() types.SlashingKeeper { diff --git a/x/observer/keeper/msg_server_vote_tss.go b/x/observer/keeper/msg_server_vote_tss.go index 065bfe68f2..ae40c41444 100644 --- a/x/observer/keeper/msg_server_vote_tss.go +++ b/x/observer/keeper/msg_server_vote_tss.go @@ -51,7 +51,6 @@ func (k msgServer) VoteTSS(goCtx context.Context, msg *types.MsgVoteTSS) (*types index := msg.Digest() ballot, found := k.GetBallot(ctx, index) if !found { - // if ballot does not exist, create a new ballot var voterList []string diff --git a/x/observer/keeper/nonce_to_cctx.go b/x/observer/keeper/nonce_to_cctx.go index 057f4b1b4b..8042a6df28 100644 --- a/x/observer/keeper/nonce_to_cctx.go +++ b/x/observer/keeper/nonce_to_cctx.go @@ -51,9 +51,7 @@ func (k Keeper) GetAllNonceToCctx(ctx sdk.Context) (list []types.NonceToCctx) { if err == nil { list = append(list, val) } - } return - } diff --git a/x/observer/keeper/observer_set.go b/x/observer/keeper/observer_set.go index deeae5395b..c8a22e0e0f 100644 --- a/x/observer/keeper/observer_set.go +++ b/x/observer/keeper/observer_set.go @@ -34,7 +34,6 @@ func (k Keeper) IsAddressPartOfObserverSet(ctx sdk.Context, address string) bool } } return false - } func (k Keeper) AddObserverToSet(ctx sdk.Context, address string) { diff --git a/x/observer/keeper/tss.go b/x/observer/keeper/tss.go index 55915d55d2..1d885a68cf 100644 --- a/x/observer/keeper/tss.go +++ b/x/observer/keeper/tss.go @@ -45,7 +45,6 @@ func (k Keeper) GetHistoricalTssByFinalizedHeight(ctx sdk.Context, finalizedZeta return types.TSS{}, false } return tss, true - } // GetTSS returns the current tss information diff --git a/x/observer/types/ballot.go b/x/observer/types/ballot.go index 2ddab67ec6..6c04963cf9 100644 --- a/x/observer/types/ballot.go +++ b/x/observer/types/ballot.go @@ -62,7 +62,6 @@ func (m Ballot) IsFinalizingVote() (Ballot, bool) { if vote == VoteType_FailureObservation { failure = failure.Add(sdk.OneDec()) } - } if failure.IsPositive() { if failure.Quo(total).GTE(m.BallotThreshold) { diff --git a/x/observer/types/keys.go b/x/observer/types/keys.go index eb05d34142..40b088686c 100644 --- a/x/observer/types/keys.go +++ b/x/observer/types/keys.go @@ -34,7 +34,6 @@ func GetMinObserverDelegation() (sdkmath.Int, bool) { func GetMinObserverDelegationDec() (sdk.Dec, error) { return sdk.NewDecFromStr(MinObserverDelegation) - } func KeyPrefix(p string) []byte { diff --git a/zetaclient/chains/bitcoin/observer/outbound.go b/zetaclient/chains/bitcoin/observer/outbound.go index a17d46883f..47d026c11a 100644 --- a/zetaclient/chains/bitcoin/observer/outbound.go +++ b/zetaclient/chains/bitcoin/observer/outbound.go @@ -328,7 +328,6 @@ func (ob *Observer) refreshPendingNonce() { } func (ob *Observer) getOutboundIDByNonce(nonce uint64, test bool) (string, error) { - // There are 2 types of txids an observer can trust // 1. The ones had been verified and saved by observer self. // 2. The ones had been finalized in zetacore based on majority vote. diff --git a/zetaclient/chains/evm/observer/observer.go b/zetaclient/chains/evm/observer/observer.go index 99db258f5a..0b3c02113c 100644 --- a/zetaclient/chains/evm/observer/observer.go +++ b/zetaclient/chains/evm/observer/observer.go @@ -481,7 +481,6 @@ func (ob *Observer) WatchGasPrice() { } func (ob *Observer) PostGasPrice() error { - // GAS PRICE gasPrice, err := ob.evmClient.SuggestGasPrice(context.TODO()) if err != nil { diff --git a/zetaclient/chains/evm/signer/outbound_data.go b/zetaclient/chains/evm/signer/outbound_data.go index d12ecb118c..070c73597e 100644 --- a/zetaclient/chains/evm/signer/outbound_data.go +++ b/zetaclient/chains/evm/signer/outbound_data.go @@ -71,7 +71,6 @@ func (txData *OutboundData) SetupGas( client interfaces.EVMRPCClient, chain *chains.Chain, ) error { - txData.gasLimit = cctx.GetCurrentOutboundParam().GasLimit if txData.gasLimit < MinGasLimit { txData.gasLimit = MinGasLimit diff --git a/zetaclient/supplychecker/zeta_supply_checker.go b/zetaclient/supplychecker/zeta_supply_checker.go index f975c7eb88..3984b740ab 100644 --- a/zetaclient/supplychecker/zeta_supply_checker.go +++ b/zetaclient/supplychecker/zeta_supply_checker.go @@ -113,7 +113,6 @@ func (zs *ZetaSupplyChecker) Stop() { } func (zs *ZetaSupplyChecker) CheckZetaTokenSupply() error { - externalChainTotalSupply := sdkmath.ZeroInt() for _, chain := range zs.externalEvmChain { externalEvmChainParams, ok := zs.coreContext.GetEVMChainParams(chain.ChainId) diff --git a/zetaclient/zetacore/client.go b/zetaclient/zetacore/client.go index d64fd56db1..3b85296fe1 100644 --- a/zetaclient/zetacore/client.go +++ b/zetaclient/zetacore/client.go @@ -57,7 +57,6 @@ func NewClient( hsmMode bool, telemetry *metrics.TelemetryServer, ) (*Client, error) { - // main module logger logger := log.With().Str("module", "ZetacoreClient").Logger() cfg := config.ClientConfiguration{ From 562a53432a096c0bac083331539a66edff0c937c Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Mon, 24 Jun 2024 17:06:22 +0200 Subject: [PATCH 03/23] chore: initialize coderabbit config to focus review on code (#2374) --- .coderabbit.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000000..381e9d9fc4 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,20 @@ +reviews: + path_filters: + - "**/*.pb.go" + - "**/*.pb.gw.go" + path_instructions: + - path: '**/*.go' + instructions: >- + Review the Go code, point out issues relative to principles of clean + code, expressiveness, and performance. + - path: '**/*.proto' + instructions: >- + Review the Protobuf definitions, point out issues relative to + compatibility, and expressiveness. + - path: '**/*.sh' + instructions: >- + Review the shell scripts, point out issues relative to security, + performance, and maintainability. + auto_review: + base_branches: + - develop \ No newline at end of file From 3eb36cde5f6de77d9386490d08d7a08bcfe4c634 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Mon, 24 Jun 2024 09:57:38 -0700 Subject: [PATCH 04/23] refactor(localnet): reduce number of docker compose files (#2365) * refactor(localnet): reduce number of docker compose files * add ZETACORED_START_PERIOD and allow user to set E2E_ARGS * fix upgrade tests * fix upgrade-test height * rebase for start-e2e-import-mainnet-test * always use make stop-localnet * newlines and readme --- .github/workflows/build.yml | 6 +-- .github/workflows/execute_advanced_tests.yaml | 12 ++---- .github/workflows/publish-release.yml | 3 +- Makefile | 32 +++++++++++---- ...n.yml => docker-compose-additionalevm.yml} | 11 ++---- .../localnet/docker-compose-import-data.yml | 30 -------------- .../localnet/docker-compose-monitoring.yml | 2 - .../localnet/docker-compose-performance.yml | 9 ----- .../localnet/docker-compose-setup-only.yml | 9 ----- ...resstest.yml => docker-compose-stress.yml} | 39 ++++++------------- .../localnet/docker-compose-upgrade-light.yml | 11 ------ contrib/localnet/docker-compose-upgrade.yml | 14 ++----- contrib/localnet/docker-compose.yml | 16 +++++--- .../localnet/orchestrator/start-zetae2e.sh | 25 ++++++------ contrib/localnet/scripts/import-data.sh | 6 +-- .../scripts/start-upgrade-orchestrator.sh | 2 - contrib/localnet/scripts/start-zetaclientd.sh | 4 +- contrib/localnet/scripts/start-zetacored.sh | 12 +----- docs/development/LOCAL_TESTING.md | 19 +++++---- 19 files changed, 94 insertions(+), 168 deletions(-) rename contrib/localnet/{docker-compose-admin.yml => docker-compose-additionalevm.yml} (66%) delete mode 100644 contrib/localnet/docker-compose-import-data.yml delete mode 100644 contrib/localnet/docker-compose-performance.yml delete mode 100644 contrib/localnet/docker-compose-setup-only.yml rename contrib/localnet/{docker-compose-stresstest.yml => docker-compose-stress.yml} (70%) delete mode 100644 contrib/localnet/docker-compose-upgrade-light.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4fdd5c2149..fc58eb6c56 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -152,8 +152,7 @@ jobs: - name: Full Log Dump On Failure if: failure() run: | - cd contrib/localnet - docker compose logs + make stop-localnet - name: Notify Slack on Failure if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/develop' @@ -167,8 +166,7 @@ jobs: - name: Stop Private Network if: always() run: | - cd contrib/localnet/ - docker compose down + make stop-localnet - name: Clean Up Workspace if: always() diff --git a/.github/workflows/execute_advanced_tests.yaml b/.github/workflows/execute_advanced_tests.yaml index e42d08e9d6..0af6d13a48 100644 --- a/.github/workflows/execute_advanced_tests.yaml +++ b/.github/workflows/execute_advanced_tests.yaml @@ -50,8 +50,7 @@ jobs: - name: Full Log Dump On Failure if: failure() run: | - cd contrib/localnet - docker compose logs + make stop-localnet - name: Notify Slack on Failure if: failure() && github.event_name == 'schedule' @@ -82,8 +81,7 @@ jobs: - name: Full Log Dump On Failure if: failure() run: | - cd contrib/localnet - docker compose logs + make stop-localnet - name: Notify Slack on Failure if: failure() && github.event_name == 'schedule' @@ -114,8 +112,7 @@ jobs: - name: Full Log Dump On Failure if: failure() run: | - cd contrib/localnet - docker compose logs + make stop-localnet e2e-performance-test: if: ${{ github.event.inputs.e2e-performance-test == 'true' }} @@ -137,5 +134,4 @@ jobs: - name: Full Log Dump On Failure if: failure() run: | - cd contrib/localnet - docker compose logs \ No newline at end of file + make stop-localnet diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index e96bb39e46..89a4b1f688 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -339,8 +339,7 @@ jobs: - name: Stop Private Network if: ${{ always() && github.event.inputs.skip_checks != 'true' }} run: | - cd contrib/localnet/ - docker compose down + make stop-localnet - name: Clean Up Workspace if: always() diff --git a/Makefile b/Makefile index 360e071485..75834d690d 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,14 @@ HSM_BUILD_FLAGS := -tags pebbledb,ledger,hsm_test export DOCKER_BUILDKIT := 1 +# parameters for localnet docker compose files +# set defaults to empty to prevent docker warning +export LOCALNET_MODE +export E2E_ARGS := $(E2E_ARGS) +export UPGRADE_HEIGHT +export ZETACORED_IMPORT_GENESIS_DATA +export ZETACORED_START_PERIOD := 30s + clean: clean-binaries clean-dir clean-test-dir clean-coverage clean-binaries: @@ -217,15 +225,17 @@ start-e2e-test: zetanode start-e2e-admin-test: zetanode @echo "--> Starting e2e admin test" - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-admin.yml up -d + export E2E_ARGS="--skip-regular --test-admin" && \ + cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-additionalevm.yml up -d start-e2e-performance-test: zetanode @echo "--> Starting e2e performance test" - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-performance.yml up -d + export E2E_ARGS="--test-performance" && \ + cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml up -d start-stress-test: zetanode @echo "--> Starting stress test" - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-stresstest.yml up -d + cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-stress.yml up -d #TODO: replace OLD_VERSION with v16 tag once its available zetanode-upgrade: zetanode @@ -236,24 +246,30 @@ zetanode-upgrade: zetanode start-upgrade-test: zetanode-upgrade @echo "--> Starting upgrade test" + export LOCALNET_MODE=upgrade && \ + export UPGRADE_HEIGHT=225 && \ cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-upgrade.yml up -d start-upgrade-test-light: zetanode-upgrade @echo "--> Starting light upgrade test (no ZetaChain state populating before upgrade)" - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-upgrade.yml -f docker-compose-upgrade-light.yml up -d + export LOCALNET_MODE=upgrade && \ + export UPGRADE_HEIGHT=90 && \ + cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-upgrade.yml up -d start-localnet: zetanode start-localnet-skip-build start-localnet-skip-build: @echo "--> Starting localnet" - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-setup-only.yml up -d + export LOCALNET_MODE=setup-only && \ + cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml up -d -stop-localnet: start-e2e-import-mainnet-test: zetanode @echo "--> Starting e2e import-data test" - cd contrib/localnet/ && ./scripts/import-data.sh mainnet && $(DOCKER) compose -f docker-compose.yml -f docker-compose-import-data.yml up -d + export ZETACORED_IMPORT_GENESIS_DATA=true && \ + export ZETACORED_START_PERIOD=10m && \ + cd contrib/localnet/ && ./scripts/import-data.sh mainnet && $(DOCKER) compose -f docker-compose.yml up -d -stop-test: +stop-localnet: cd contrib/localnet/ && $(DOCKER) compose down --remove-orphans ############################################################################### diff --git a/contrib/localnet/docker-compose-admin.yml b/contrib/localnet/docker-compose-additionalevm.yml similarity index 66% rename from contrib/localnet/docker-compose-admin.yml rename to contrib/localnet/docker-compose-additionalevm.yml index 19a478100e..208a8e30e9 100644 --- a/contrib/localnet/docker-compose-admin.yml +++ b/contrib/localnet/docker-compose-additionalevm.yml @@ -1,13 +1,8 @@ -version: "3" - # This docker-compose file overrides the orchestrator service to specify the flag to test the admin functions # and skip the regular tests # it also adds another local Ethereum network to test EVM chain migration and use the additional-evm flag services: - orchestrator: - entrypoint: ["/work/start-zetae2e.sh", "local --skip-regular --test-admin"] - eth2: build: context: ./anvil @@ -21,7 +16,9 @@ services: ipv4_address: 172.20.0.102 zetaclient0: - entrypoint: [ "/root/start-zetaclientd.sh", "additional-evm" ] + environment: + - ADDITIONAL_EVM=true zetaclient1: - entrypoint: [ "/root/start-zetaclientd.sh", "additional-evm" ] + environment: + - ADDITIONAL_EVM=true diff --git a/contrib/localnet/docker-compose-import-data.yml b/contrib/localnet/docker-compose-import-data.yml deleted file mode 100644 index 19f4068ad5..0000000000 --- a/contrib/localnet/docker-compose-import-data.yml +++ /dev/null @@ -1,30 +0,0 @@ -version: "3" - -# This docker-compose file configures the localnet environment -# it contains the following services: -# - ZetaChain with 2 nodes (zetacore0, zetacore1) -# - A observer set with 2 clients (zetaclient0, zetaclient1) -# - An Ethereum node (eth) -# - A Bitcoin node (bitcoin) -# - A Rosetta API (rosetta) -# - An orchestrator to manage interaction with the localnet (orchestrator) -services: - rosetta: - entrypoint: ["/root/start-rosetta.sh"] - - zetacore0: - entrypoint: ["/root/start-zetacored.sh", "2","import-data"] - volumes: - - ~/genesis_export/:/root/genesis_data - - zetacore1: - entrypoint: ["/root/start-zetacored.sh", "2","import-data"] - - zetaclient0: - entrypoint: ["/root/start-zetaclientd.sh"] - - zetaclient1: - entrypoint: ["/root/start-zetaclientd.sh"] - - orchestrator: - entrypoint: ["/work/start-zetae2e.sh", "local"] \ No newline at end of file diff --git a/contrib/localnet/docker-compose-monitoring.yml b/contrib/localnet/docker-compose-monitoring.yml index ad66f828ec..9f11bd5575 100644 --- a/contrib/localnet/docker-compose-monitoring.yml +++ b/contrib/localnet/docker-compose-monitoring.yml @@ -1,5 +1,3 @@ -version: '3' - services: grafana: image: grafana/grafana:latest diff --git a/contrib/localnet/docker-compose-performance.yml b/contrib/localnet/docker-compose-performance.yml deleted file mode 100644 index 0374d42030..0000000000 --- a/contrib/localnet/docker-compose-performance.yml +++ /dev/null @@ -1,9 +0,0 @@ -version: "3" - -# This docker-compose file overrides the orchestrator service to specify the flag to test performance of cctxs -# and skip the regular tests - -services: - orchestrator: - entrypoint: ["/work/start-zetae2e.sh", "local --test-performance"] - diff --git a/contrib/localnet/docker-compose-setup-only.yml b/contrib/localnet/docker-compose-setup-only.yml deleted file mode 100644 index 11761ad817..0000000000 --- a/contrib/localnet/docker-compose-setup-only.yml +++ /dev/null @@ -1,9 +0,0 @@ -version: "3" - -# This docker-compose file overrides the orcherstrator service to use the setup only option -# It is used to setup the localnet environment without running tests - -services: - orchestrator: - entrypoint: ["/work/start-zetae2e.sh", "local --setup-only"] - diff --git a/contrib/localnet/docker-compose-stresstest.yml b/contrib/localnet/docker-compose-stress.yml similarity index 70% rename from contrib/localnet/docker-compose-stresstest.yml rename to contrib/localnet/docker-compose-stress.yml index 38df1133f3..fb11f01b5c 100644 --- a/contrib/localnet/docker-compose-stresstest.yml +++ b/contrib/localnet/docker-compose-stress.yml @@ -1,23 +1,19 @@ -version: "3" - # This docker-compose redefine the services: # - ZetaChain with 4 nodes to test performance # - ZetaChain observer set with 4 clients to test performance -# - Orchestrator call stress commands services: zetacore0: - entrypoint: ["/root/start-zetacored.sh", "4"] + environment: + - ZETACORED_REPLICAS=4 zetacore1: - entrypoint: ["/root/start-zetacored.sh", "4"] + environment: + - ZETACORED_REPLICAS=4 zetacore2: image: zetanode:latest container_name: zetacore2 - build: - context: ../../. - dockerfile: Dockerfile-localnet hostname: zetacore2 networks: mynetwork: @@ -26,6 +22,7 @@ services: environment: - HOTKEY_BACKEND=file - HOTKEY_PASSWORD=password # test purposes only + - ZETACORED_REPLICAS=4 zetacore3: image: zetanode:latest @@ -41,21 +38,11 @@ services: environment: - HOTKEY_BACKEND=file - HOTKEY_PASSWORD=password # test purposes only - - zetaclient0: - ports: - - "8123:8123" - entrypoint: /root/start-zetaclientd.sh - - zetaclient1: - entrypoint: /root/start-zetaclientd.sh + - ZETACORED_REPLICAS=4 zetaclient2: image: zetanode:latest container_name: zetaclient2 - build: - context: ../../. - dockerfile: Dockerfile-localnet hostname: zetaclient2 networks: mynetwork: @@ -65,13 +52,13 @@ services: - ETHDEV_ENDPOINT=http://eth:8545 - HOTKEY_BACKEND=file - HOTKEY_PASSWORD=password # test purposes only + volumes: + - ssh:/root/.ssh + - preparams:/root/preparams zetaclient3: image: zetanode:latest container_name: zetaclient3 - build: - context: ../../. - dockerfile: Dockerfile-localnet hostname: zetaclient3 networks: mynetwork: @@ -81,8 +68,6 @@ services: - ETHDEV_ENDPOINT=http://eth:8545 - HOTKEY_BACKEND=file - HOTKEY_PASSWORD=password # test purposes only - - orchestrator: - build: - dockerfile: contrib/localnet/orchestrator/Dockerfile.fastbuild - entrypoint: ["/work/start-zetae2e.sh", "stress"] \ No newline at end of file + volumes: + - ssh:/root/.ssh + - preparams:/root/preparams diff --git a/contrib/localnet/docker-compose-upgrade-light.yml b/contrib/localnet/docker-compose-upgrade-light.yml deleted file mode 100644 index 8e3cb098c1..0000000000 --- a/contrib/localnet/docker-compose-upgrade-light.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: "3" - -# This docker-compose is similar to the docker-compose-upgrade.yml, but it uses a smaller height option for the upgrade (90) -# By using 90, the orchestrator will automatically run setup only for the first e2e test execution. - -services: - orchestrator: - entrypoint: ["/work/start-zetae2e.sh", "local", "upgrade", "90"] - - upgrade-orchestrator: - entrypoint: ["/root/start-upgrade-orchestrator.sh", "90"] \ No newline at end of file diff --git a/contrib/localnet/docker-compose-upgrade.yml b/contrib/localnet/docker-compose-upgrade.yml index a7497db980..c6ae72941a 100644 --- a/contrib/localnet/docker-compose-upgrade.yml +++ b/contrib/localnet/docker-compose-upgrade.yml @@ -1,5 +1,3 @@ -version: "3" - # This docker-compose redefine the services: # - ZetaChain with 2 nodes (zetacore0, zetacore1) using the upgrade option for cosmovisor # - ZetaChain observer set with 2 clients (zetaclient0, zetaclient1) using the background option @@ -13,17 +11,11 @@ services: image: zetanode:old zetaclient0: - entrypoint: ["/root/start-zetaclientd.sh"] image: zetanode:old zetaclient1: - entrypoint: ["/root/start-zetaclientd.sh"] image: zetanode:old - orchestrator: - entrypoint: ["/work/start-zetae2e.sh", "local", "upgrade"] - image: orchestrator - upgrade-host: image: zetanode:latest container_name: upgrade-host @@ -40,12 +32,14 @@ services: image: zetanode:old container_name: upgrade-orchestrator hostname: upgrade-orchestrator - entrypoint: ["/root/start-upgrade-orchestrator.sh", "225"] + entrypoint: ["/root/start-upgrade-orchestrator.sh"] networks: mynetwork: ipv4_address: 172.20.0.251 depends_on: - zetacore0 - upgrade-host + environment: + - UPGRADE_HEIGHT=${UPGRADE_HEIGHT} volumes: - - ssh:/root/.ssh \ No newline at end of file + - ssh:/root/.ssh diff --git a/contrib/localnet/docker-compose.yml b/contrib/localnet/docker-compose.yml index f176c30f00..1a59202d0d 100644 --- a/contrib/localnet/docker-compose.yml +++ b/contrib/localnet/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3" - # This docker-compose file configures the localnet environment # it contains the following services: # - ZetaChain with 2 nodes (zetacore0, zetacore1) @@ -46,17 +44,20 @@ services: interval: 30s timeout: 10s retries: 3 - start_period: 30s + start_period: ${ZETACORED_START_PERIOD} start_interval: 1s networks: mynetwork: ipv4_address: 172.20.0.11 - entrypoint: ["/root/start-zetacored.sh", "2"] + entrypoint: ["/root/start-zetacored.sh"] environment: - HOTKEY_BACKEND=file - HOTKEY_PASSWORD=password # test purposes only + - ZETACORED_REPLICAS=2 + - ZETACORED_IMPORT_GENESIS_DATA=${ZETACORED_IMPORT_GENESIS_DATA} volumes: - ssh:/root/.ssh + - ~/.zetacored/genesis_data:/root/genesis_data zetacore1: image: zetanode:latest @@ -65,10 +66,11 @@ services: networks: mynetwork: ipv4_address: 172.20.0.12 - entrypoint: ["/root/start-zetacored.sh", "2"] + entrypoint: ["/root/start-zetacored.sh"] environment: - HOTKEY_BACKEND=file - HOTKEY_PASSWORD=password # test purposes only + - ZETACORED_REPLICAS=2 volumes: - ssh:/root/.ssh @@ -146,6 +148,10 @@ services: mynetwork: ipv4_address: 172.20.0.2 entrypoint: ["/work/start-zetae2e.sh", "local"] + environment: + - LOCALNET_MODE=${LOCALNET_MODE} + - E2E_ARGS=${E2E_ARGS} + - UPGRADE_HEIGHT=${UPGRADE_HEIGHT} volumes: - ssh:/root/.ssh volumes: diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index 8dcb4ea271..791f0a6074 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -5,9 +5,6 @@ # A second optional argument can be passed and can have the following value: # upgrade: run the local e2e once, then restart zetaclientd at upgrade height and run the local e2e again -ZETAE2E_CMD=$1 -OPTION=$2 - get_zetacored_version() { retries=10 node_info="" @@ -78,15 +75,15 @@ geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xF421292cb0d3c97b90E ### Run zetae2e command depending on the option passed -if [ "$OPTION" == "upgrade" ]; then +if [ "$LOCALNET_MODE" == "upgrade" ]; then # Run the e2e tests, then restart zetaclientd at upgrade height and run the e2e tests again - # Fetch the height of the upgrade, default is 225, if arg3 is passed, use that value - UPGRADE_HEIGHT=${3:-225} + # set upgrade height to 225 by default + UPGRADE_HEIGHT=${UPGRADE_HEIGHT:=225} if [[ ! -f deployed.yml ]]; then - zetae2e "$ZETAE2E_CMD" --setup-only --config-out deployed.yml --skip-header-proof + zetae2e local $E2E_ARGS --setup-only --config-out deployed.yml --skip-header-proof if [ $? -ne 0 ]; then echo "e2e setup failed" exit 1 @@ -100,7 +97,7 @@ if [ "$OPTION" == "upgrade" ]; then echo "running E2E command to setup the networks and populate the state..." # Use light flag to ensure tests can complete before the upgrade height - zetae2e "$ZETAE2E_CMD" --skip-setup --config deployed.yml --light --skip-header-proof + zetae2e local $E2E_ARGS --skip-setup --config deployed.yml --light --skip-header-proof if [ $? -ne 0 ]; then echo "first e2e failed" exit 1 @@ -142,9 +139,9 @@ if [ "$OPTION" == "upgrade" ]; then # When the upgrade height is greater than 100 for upgrade test, the Bitcoin tests have been run once, therefore the Bitcoin wallet is already set up # Use light flag to skip advanced tests if [ "$UPGRADE_HEIGHT" -lt 100 ]; then - zetae2e $ZETAE2E_CMD --skip-setup --config deployed.yml --light --skip-header-proof + zetae2e local $E2E_ARGS --skip-setup --config deployed.yml --light --skip-header-proof else - zetae2e $ZETAE2E_CMD --skip-setup --config deployed.yml --skip-bitcoin-setup --light --skip-header-proof + zetae2e local $E2E_ARGS --skip-setup --config deployed.yml --skip-bitcoin-setup --light --skip-header-proof fi ZETAE2E_EXIT_CODE=$? @@ -162,7 +159,7 @@ else echo "running e2e setup..." if [[ ! -f deployed.yml ]]; then - zetae2e $ZETAE2E_CMD --setup-only --config-out deployed.yml + zetae2e local $E2E_ARGS --setup-only --config-out deployed.yml if [ $? -ne 0 ]; then echo "e2e setup failed" exit 1 @@ -171,9 +168,13 @@ else echo "skipping e2e setup because it has already been completed" fi + if [ "$LOCALNET_MODE" == "setup-only" ]; then + exit 0 + fi + echo "running e2e tests..." - zetae2e $ZETAE2E_CMD --skip-setup --config deployed.yml + zetae2e local $E2E_ARGS --skip-setup --config deployed.yml ZETAE2E_EXIT_CODE=$? # if e2e passed, exit with 0, otherwise exit with 1 diff --git a/contrib/localnet/scripts/import-data.sh b/contrib/localnet/scripts/import-data.sh index d71d5c3656..5236bfe166 100644 --- a/contrib/localnet/scripts/import-data.sh +++ b/contrib/localnet/scripts/import-data.sh @@ -7,9 +7,9 @@ fi NETWORK=$1 echo "NETWORK: ${NETWORK}" -rm -rf ~/genesis_export/ -mkdir ~/genesis_export/ +rm -rf ~/.zetacored/genesis_data +mkdir ~/.zetacored/genesis_data echo "Download Latest State Export" LATEST_EXPORT_URL=$(curl https://snapshots.zetachain.com/latest-state-export | jq -r ."${NETWORK}") echo "LATEST EXPORT URL: ${LATEST_EXPORT_URL}" -wget -q ${LATEST_EXPORT_URL} -O ~/genesis_export/exported-genesis.json \ No newline at end of file +wget -q ${LATEST_EXPORT_URL} -O ~/.zetacored/genesis_data/exported-genesis.json diff --git a/contrib/localnet/scripts/start-upgrade-orchestrator.sh b/contrib/localnet/scripts/start-upgrade-orchestrator.sh index a2e8ec68fd..f68009db9a 100755 --- a/contrib/localnet/scripts/start-upgrade-orchestrator.sh +++ b/contrib/localnet/scripts/start-upgrade-orchestrator.sh @@ -1,7 +1,5 @@ #!/bin/bash -UPGRADE_HEIGHT=$1 - CHAINID="athens_101-1" UPGRADE_AUTHORITY_ACCOUNT="zeta10d07y265gmmuvt4z0w9aw880jnsr700jvxasvr" diff --git a/contrib/localnet/scripts/start-zetaclientd.sh b/contrib/localnet/scripts/start-zetaclientd.sh index 1b018de4ef..a849891275 100755 --- a/contrib/localnet/scripts/start-zetaclientd.sh +++ b/contrib/localnet/scripts/start-zetaclientd.sh @@ -63,7 +63,7 @@ then # check if the option is additional-evm # in this case, the additional evm is represented with the sepolia chain, we set manually the eth2 endpoint to the sepolia chain (11155111 -> http://eth2:8545) # in /root/.zetacored/config/zetaclient_config.json - if [ "$OPTION" == "additional-evm" ]; then + if [[ -n $ADDITIONAL_EVM ]]; then set_sepolia_endpoint fi fi @@ -82,7 +82,7 @@ then # check if the option is additional-evm # in this case, the additional evm is represented with the sepolia chain, we set manually the eth2 endpoint to the sepolia chain (11155111 -> http://eth2:8545) # in /root/.zetacored/config/zetaclient_config.json - if [ "$OPTION" == "additional-evm" ]; then + if [[ -n $ADDITIONAL_EVM ]]; then set_sepolia_endpoint fi fi diff --git a/contrib/localnet/scripts/start-zetacored.sh b/contrib/localnet/scripts/start-zetacored.sh index d390b99083..dd8509847f 100755 --- a/contrib/localnet/scripts/start-zetacored.sh +++ b/contrib/localnet/scripts/start-zetacored.sh @@ -67,14 +67,6 @@ add_v17_message_authorizations() { ' $json_file > temp.json && mv temp.json $json_file } -if [ $# -lt 1 ] -then - echo "Usage: genesis.sh [option]" - exit 1 -fi -NUMOFNODES=$1 -OPTION=$2 - # create keys CHAINID="athens_101-1" KEYRING="test" @@ -96,7 +88,7 @@ export UNSAFE_SKIP_BACKUP=true # generate node list START=1 # shellcheck disable=SC2100 -END=$((NUMOFNODES - 1)) +END=$((ZETACORED_REPLICAS - 1)) NODELIST=() for i in $(eval echo "{$START..$END}") do @@ -257,7 +249,7 @@ then scp $NODE:~/.zetacored/config/gentx/* ~/.zetacored/config/gentx/z2gentx/ done - if [[ "$OPTION" == "import-data" || "$OPTION" == "import-data-upgrade" ]]; then + if [[ -n "$ZETACORED_IMPORT_GENESIS_DATA" ]]; then echo "Importing data" zetacored parse-genesis-file /root/genesis_data/exported-genesis.json fi diff --git a/docs/development/LOCAL_TESTING.md b/docs/development/LOCAL_TESTING.md index d28c44638e..3472daca89 100644 --- a/docs/development/LOCAL_TESTING.md +++ b/docs/development/LOCAL_TESTING.md @@ -27,6 +27,17 @@ Now we have built all the docker images, we can run the e2e test with make comma make start-e2e-test ``` +This uses `docker compose` to start the localnet and run standard e2e tests inside the orchestrator container. There are several parameters that the `Makefile` can provide to `docker compose` via environment variables: + +- `LOCALNET_MODE` + - `setup-only`: only setup the localnet, do not run the e2e tests + - `upgrade`: run the upgrade tests + - unset: run the e2e tests +- `E2E_ARGS`: arguments to provide to the `zetae2e local` command +- `UPGRADE_HEIGHT`: block height to upgrade at when `LOCALNET_MODE=upgrade` +- `ZETACORED_IMPORT_GENESIS_DATA`: path to genesis data to import before starting zetacored +- `ZETACORED_START_PERIOD`: duration to tolerate `zetacored` health check failures during startup + #### Run admin functions e2e tests We define e2e tests allowing to test admin functionalities (emergency network pause for example). @@ -42,13 +53,7 @@ make start-e2e-admin-test Upgrade tests run the E2E tests with an older version, upgrade the nodes to the new version, and run the E2E tests again. This allows testing the upgrade process with a populated state. -Before running the upgrade tests, the versions must be specified in `Dockefile-upgrade`: - -```dockerfile -ARG OLD_VERSION=v{old_major_version}.{old_minor_version}.{old_patch_version} -ENV NEW_VERSION=v{new_major_version} -``` -The new version must match the version specified in `app/setup_handlers.go` +Before running the upgrade tests, the old version must be specified the Makefile. NOTE: We only specify the major version for `NEW_VERSION` since we use major version only for chain upgrade. Semver is needed for `OLD_VERSION` because we use this value to fetch the release tag from the GitHub repository. From 3a96ba6ca0342d24734373e99b260f3a195a2a4d Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Mon, 24 Jun 2024 20:55:13 +0200 Subject: [PATCH 05/23] fix: use correct name for rate limiter flag query (#2367) * fix: use correct name for rate limiter flag query * make generate * Update x/crosschain/client/cli/query_rate_limiter_flags.go Co-authored-by: Tanmay * make generate --------- Co-authored-by: Tanmay --- docs/cli/zetacored/zetacored_query_crosschain.md | 2 +- ...> zetacored_query_crosschain_show-rate-limiter-flags.md} | 6 +++--- x/crosschain/client/cli/query_rate_limiter_flags.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename docs/cli/zetacored/{zetacored_query_crosschain_update_rate_limit_flags.md => zetacored_query_crosschain_show-rate-limiter-flags.md} (86%) diff --git a/docs/cli/zetacored/zetacored_query_crosschain.md b/docs/cli/zetacored/zetacored_query_crosschain.md index 595a065ea5..6ee04cc8d2 100644 --- a/docs/cli/zetacored/zetacored_query_crosschain.md +++ b/docs/cli/zetacored/zetacored_query_crosschain.md @@ -41,5 +41,5 @@ zetacored query crosschain [flags] * [zetacored query crosschain show-gas-price](zetacored_query_crosschain_show-gas-price.md) - shows a gasPrice * [zetacored query crosschain show-inbound-hash-to-cctx](zetacored_query_crosschain_show-inbound-hash-to-cctx.md) - shows a inboundHashToCctx * [zetacored query crosschain show-outbound-tracker](zetacored_query_crosschain_show-outbound-tracker.md) - shows an outbound tracker -* [zetacored query crosschain update_rate_limit_flags](zetacored_query_crosschain_update_rate_limit_flags.md) - shows the rate limiter flags +* [zetacored query crosschain show-rate-limiter-flags](zetacored_query_crosschain_show-rate-limiter-flags.md) - shows the rate limiter flags diff --git a/docs/cli/zetacored/zetacored_query_crosschain_update_rate_limit_flags.md b/docs/cli/zetacored/zetacored_query_crosschain_show-rate-limiter-flags.md similarity index 86% rename from docs/cli/zetacored/zetacored_query_crosschain_update_rate_limit_flags.md rename to docs/cli/zetacored/zetacored_query_crosschain_show-rate-limiter-flags.md index 6dcc3b12a4..abbf7042bb 100644 --- a/docs/cli/zetacored/zetacored_query_crosschain_update_rate_limit_flags.md +++ b/docs/cli/zetacored/zetacored_query_crosschain_show-rate-limiter-flags.md @@ -1,9 +1,9 @@ -# query crosschain update_rate_limit_flags +# query crosschain show-rate-limiter-flags shows the rate limiter flags ``` -zetacored query crosschain update_rate_limit_flags [flags] +zetacored query crosschain show-rate-limiter-flags [flags] ``` ### Options @@ -12,7 +12,7 @@ zetacored query crosschain update_rate_limit_flags [flags] --grpc-addr string the gRPC endpoint to use for this chain --grpc-insecure allow gRPC over insecure channels, if not TLS the server must use TLS --height int Use a specific height to query state at (this can error if the node is pruning state) - -h, --help help for update_rate_limit_flags + -h, --help help for show-rate-limiter-flags --node string [host]:[port] to Tendermint RPC interface for this chain -o, --output string Output format (text|json) ``` diff --git a/x/crosschain/client/cli/query_rate_limiter_flags.go b/x/crosschain/client/cli/query_rate_limiter_flags.go index ad4177295e..bdd8fd0558 100644 --- a/x/crosschain/client/cli/query_rate_limiter_flags.go +++ b/x/crosschain/client/cli/query_rate_limiter_flags.go @@ -12,7 +12,7 @@ import ( func CmdShowUpdateRateLimiterFlags() *cobra.Command { cmd := &cobra.Command{ - Use: "update_rate_limit_flags", + Use: "show-rate-limiter-flags", Short: "shows the rate limiter flags", RunE: func(cmd *cobra.Command, _ []string) error { clientCtx := client.GetClientContextFromCmd(cmd) From a1af6298e4b9c923dbac1371275b9816118281ae Mon Sep 17 00:00:00 2001 From: Christopher Fuka <97121270+CryptoFewka@users.noreply.github.com> Date: Mon, 24 Jun 2024 15:31:44 -0500 Subject: [PATCH 06/23] ci: Update sast-linters.yml (#2377) * Update sast-linters.yml - Exclude .github/workflows/sast-linters.yml from gosec nosec use scanning * Update sast-linters.yml * Update changelog.md * Update sast-linters.yml Also ignore changelog.md --- .github/workflows/sast-linters.yml | 13 +++++++++---- changelog.md | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/sast-linters.yml b/.github/workflows/sast-linters.yml index 2372ff5264..79b308d2df 100644 --- a/.github/workflows/sast-linters.yml +++ b/.github/workflows/sast-linters.yml @@ -104,7 +104,14 @@ jobs: echo "Changed files: ${{ steps.changed-files.outputs.all_changed_files }}" for file in ${{ steps.changed-files.outputs.all_changed_files }}; do - if git diff ${{ github.event.pull_request.base.sha }} $file | grep -q nosec; then + # Skip this workflow file + if [ "$file" == ".github/workflows/sast-linters.yml" ] || [ "$file" == "changelog.md" ]; then + echo "Skipping nosec check for $file" + continue + fi + + # Only consider additions of "nosec", marked by '+' + if git diff ${{ github.event.pull_request.base.sha }} $file | grep -q '^+.*nosec'; then echo "nosec detected in $file" nosec_list+=("$file,") nosec_detected=1 @@ -118,6 +125,7 @@ jobs: echo "nosec_files=$nosec_list_string" >> $GITHUB_ENV echo "nosec_detected=$nosec_detected" >> $GITHUB_ENV + - name: Report nosec uses uses: mshick/add-pr-comment@v2 if: env.nosec_detected == 1 @@ -149,6 +157,3 @@ jobs: run: | DIFF=$(git diff ${{ github.event.pull_request.base.sha }}) echo "$DIFF" | grep -P '#nosec(?!(\sG\d{3}))(?![^\s\t])([\s\t]*|$)' && echo "nosec without specified rule found!" && exit 1 || exit 0 - - - \ No newline at end of file diff --git a/changelog.md b/changelog.md index f7a819e383..9d439de407 100644 --- a/changelog.md +++ b/changelog.md @@ -92,6 +92,7 @@ * [2191](https://github.com/zeta-chain/node/pull/2191) - Fixed conditional logic for the docker build step for non release builds to not overwrite the github tag * [2192](https://github.com/zeta-chain/node/pull/2192) - Added release status checker and updater pipeline that will update release statuses when they go live on network * [2335](https://github.com/zeta-chain/node/pull/2335) - ci: updated the artillery report to publish to artillery cloud +* [2377](https://github.com/zeta-chain/node/pull/2377) - ci: adjusted sast-linters.yml to not scan itself, nor alert on removal of nosec. ## v17.0.0 @@ -531,4 +532,4 @@ Getting the correct TSS address for Bitcoin now requires proviidng the Bitcoin c ### CI * [1218](https://github.com/zeta-chain/node/pull/1218) - cross-compile release binaries and simplify PR testings -* [1302](https://github.com/zeta-chain/node/pull/1302) - add mainnet builds to goreleaser \ No newline at end of file +* [1302](https://github.com/zeta-chain/node/pull/1302) - add mainnet builds to goreleaser From 852897fdca9b497190d225e77994b516cc77dbb0 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 24 Jun 2024 17:59:30 -0400 Subject: [PATCH 07/23] feat: add migration for authorization list (#2366) * add migration for authorization list * add changelog * add forced migration to fix upgrade tests * make fmt --------- Co-authored-by: Alex Gartner --- Makefile | 2 +- app/setup_handlers.go | 2 ++ changelog.md | 1 + x/authority/keeper/migrator.go | 24 +++++++++++++++++ x/authority/migrations/v2/migrate.go | 21 +++++++++++++++ x/authority/migrations/v2/migrate_test.go | 28 ++++++++++++++++++++ x/authority/module.go | 6 ++++- x/authority/types/authorization_list_test.go | 5 ++++ 8 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 x/authority/keeper/migrator.go create mode 100644 x/authority/migrations/v2/migrate.go create mode 100644 x/authority/migrations/v2/migrate_test.go diff --git a/Makefile b/Makefile index 75834d690d..858efad24a 100644 --- a/Makefile +++ b/Makefile @@ -240,7 +240,7 @@ start-stress-test: zetanode #TODO: replace OLD_VERSION with v16 tag once its available zetanode-upgrade: zetanode @echo "Building zetanode-upgrade" - $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime --build-arg OLD_VERSION='release/v16' . + $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime --build-arg OLD_VERSION='release/v17' . $(DOCKER) build -t orchestrator -f contrib/localnet/orchestrator/Dockerfile.fastbuild . .PHONY: zetanode-upgrade diff --git a/app/setup_handlers.go b/app/setup_handlers.go index 7fe7bc1f8f..df6ef31c9b 100644 --- a/app/setup_handlers.go +++ b/app/setup_handlers.go @@ -24,6 +24,7 @@ import ( "golang.org/x/exp/slices" "github.com/zeta-chain/zetacore/pkg/constant" + authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" emissionstypes "github.com/zeta-chain/zetacore/x/emissions/types" ibccrosschaintypes "github.com/zeta-chain/zetacore/x/ibccrosschain/types" ) @@ -66,6 +67,7 @@ func SetupHandlers(app *App) { govtypes.ModuleName, crisistypes.ModuleName, emissionstypes.ModuleName, + authoritytypes.ModuleName, } allUpgrades := upgradeTracker{ upgrades: []upgradeTrackerItem{ diff --git a/changelog.md b/changelog.md index 9d439de407..70116d7939 100644 --- a/changelog.md +++ b/changelog.md @@ -28,6 +28,7 @@ * [2319](https://github.com/zeta-chain/node/pull/2319) - use `CheckAuthorization` function in all messages * [2325](https://github.com/zeta-chain/node/pull/2325) - revert telemetry server changes * [2339](https://github.com/zeta-chain/node/pull/2339) - add binaries related question to syncing issue form +* [2366](https://github.com/zeta-chain/node/pull/2366) - add migration script for adding authorizations table ### Refactor diff --git a/x/authority/keeper/migrator.go b/x/authority/keeper/migrator.go new file mode 100644 index 0000000000..9edf014b1d --- /dev/null +++ b/x/authority/keeper/migrator.go @@ -0,0 +1,24 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + v2 "github.com/zeta-chain/zetacore/x/authority/migrations/v2" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + authorityKeeper Keeper +} + +// NewMigrator returns a new Migrator for the authority module. +func NewMigrator(keeper Keeper) Migrator { + return Migrator{ + authorityKeeper: keeper, + } +} + +// Migrate1to2 migrates the authority store from consensus version 1 to 2 +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return v2.MigrateStore(ctx, m.authorityKeeper) +} diff --git a/x/authority/migrations/v2/migrate.go b/x/authority/migrations/v2/migrate.go new file mode 100644 index 0000000000..5b9bbd3d83 --- /dev/null +++ b/x/authority/migrations/v2/migrate.go @@ -0,0 +1,21 @@ +package v2 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/zeta-chain/zetacore/x/authority/types" +) + +type authorityKeeper interface { + SetAuthorizationList(ctx sdk.Context, list types.AuthorizationList) +} + +// MigrateStore migrates the authority module state from the consensus version 1 to 2 +func MigrateStore( + ctx sdk.Context, + keeper authorityKeeper, +) error { + ctx.Logger().Info("Migrating authority store from version 1 to 2") + keeper.SetAuthorizationList(ctx, types.DefaultAuthorizationsList()) + return nil +} diff --git a/x/authority/migrations/v2/migrate_test.go b/x/authority/migrations/v2/migrate_test.go new file mode 100644 index 0000000000..d8cbdbf6fe --- /dev/null +++ b/x/authority/migrations/v2/migrate_test.go @@ -0,0 +1,28 @@ +package v2_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + v2 "github.com/zeta-chain/zetacore/x/authority/migrations/v2" + "github.com/zeta-chain/zetacore/x/authority/types" +) + +func TestMigrateStore(t *testing.T) { + t.Run("Set authorization list", func(t *testing.T) { + k, ctx := keepertest.AuthorityKeeper(t) + + list, found := k.GetAuthorizationList(ctx) + require.False(t, found) + require.Equal(t, types.AuthorizationList{}, list) + + err := v2.MigrateStore(ctx, *k) + require.NoError(t, err) + + list, found = k.GetAuthorizationList(ctx) + require.True(t, found) + require.Equal(t, types.DefaultAuthorizationsList(), list) + }) +} diff --git a/x/authority/module.go b/x/authority/module.go index f92da86e37..696c9c1edb 100644 --- a/x/authority/module.go +++ b/x/authority/module.go @@ -122,6 +122,10 @@ func (am AppModule) Name() string { func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + m := keeper.NewMigrator(am.keeper) + if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { + panic(err) + } } // RegisterInvariants registers the authority module's invariants. @@ -146,7 +150,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 1 } +func (AppModule) ConsensusVersion() uint64 { return 2 } // BeginBlock executes all ABCI BeginBlock logic respective to the authority module. func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} diff --git a/x/authority/types/authorization_list_test.go b/x/authority/types/authorization_list_test.go index ee301c92d6..4a1cf701e8 100644 --- a/x/authority/types/authorization_list_test.go +++ b/x/authority/types/authorization_list_test.go @@ -209,6 +209,11 @@ func TestAuthorizationList_Validate(t *testing.T) { authorizations types.AuthorizationList expectedError error }{ + { + name: "validate default authorizations list", + authorizations: types.DefaultAuthorizationsList(), + expectedError: nil, + }, { name: "validate successfully", authorizations: types.AuthorizationList{Authorizations: []types.Authorization{ From 3f32bd0fe950e1eea9125d488f5688b83cc22e96 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Tue, 25 Jun 2024 11:30:23 -0500 Subject: [PATCH 08/23] refactor: integrated base Observer structure into existing EVM/BTC observers (#2359) * save local new files to remote * initiated base observer * move base to chains folder * moved logger to base package * added base signer and logger * added changelog entry * integrated base signer into evm/bitcoin; integrated base observer into evm * integrated base observer to evm and bitcoin chain * added changelog entry * cherry pick base Signer structure integration * updated PR number in changelog * updated PR number in changelog * cherry picked the integration of base Observer * moved pure RPC methods to rpc package * moved Mutex to base Observer struct * type check on cached block, header * update changelog PR number and added unit test for Stop() method * replace magic numbers with constants * updated method name in logging * Move sqlite-mem db to testutils * Add base signer's Lock & Unlock --------- Co-authored-by: Dmitry --- changelog.md | 1 + cmd/zetaclientd/debug.go | 9 +- cmd/zetaclientd/utils.go | 59 +- testutil/sample/crypto.go | 6 + zetaclient/chains/base/observer.go | 149 +++-- zetaclient/chains/base/observer_test.go | 275 ++++---- zetaclient/chains/base/signer.go | 14 +- zetaclient/chains/base/signer_test.go | 4 - zetaclient/chains/bitcoin/observer/inbound.go | 86 +-- .../chains/bitcoin/observer/inbound_test.go | 53 +- .../chains/bitcoin/observer/observer.go | 586 +++++++----------- .../chains/bitcoin/observer/observer_test.go | 320 +++++++++- .../chains/bitcoin/observer/outbound.go | 90 +-- .../chains/bitcoin/observer/outbound_test.go | 85 +-- zetaclient/chains/bitcoin/rpc/rpc.go | 109 ++++ .../live_test.go => rpc/rpc_live_test.go} | 76 ++- zetaclient/chains/bitcoin/signer/signer.go | 24 +- zetaclient/chains/evm/observer/inbound.go | 210 ++++--- .../chains/evm/observer/inbound_test.go | 60 +- zetaclient/chains/evm/observer/observer.go | 474 +++++--------- .../chains/evm/observer/observer_test.go | 357 +++++++++-- zetaclient/chains/evm/observer/outbound.go | 62 +- .../chains/evm/observer/outbound_test.go | 53 +- .../chains/evm/signer/outbound_data_test.go | 2 +- zetaclient/chains/evm/signer/signer.go | 44 +- zetaclient/chains/evm/signer/signer_test.go | 44 +- .../supplychecker/zeta_supply_checker.go | 2 +- zetaclient/testutils/constant.go | 3 + zetaclient/testutils/mocks/btc_rpc.go | 39 +- zetaclient/testutils/mocks/evm_rpc.go | 8 +- 30 files changed, 1946 insertions(+), 1358 deletions(-) create mode 100644 zetaclient/chains/bitcoin/rpc/rpc.go rename zetaclient/chains/bitcoin/{observer/live_test.go => rpc/rpc_live_test.go} (90%) diff --git a/changelog.md b/changelog.md index 70116d7939..373c0bafb3 100644 --- a/changelog.md +++ b/changelog.md @@ -52,6 +52,7 @@ * [2340](https://github.com/zeta-chain/node/pull/2340) - add ValidateInbound method for cctx orchestrator * [2344](https://github.com/zeta-chain/node/pull/2344) - group common data of EVM/Bitcoin signer and observer using base structs * [2357](https://github.com/zeta-chain/node/pull/2357) - integrate base Signer structure into EVM/Bitcoin Signer +* [2359](https://github.com/zeta-chain/node/pull/2359) - integrate base Observer structure into EVM/Bitcoin Observer * [2375](https://github.com/zeta-chain/node/pull/2375) - improve & speedup code formatting ### Tests diff --git a/cmd/zetaclientd/debug.go b/cmd/zetaclientd/debug.go index 4ba2f01516..8aaeb6384e 100644 --- a/cmd/zetaclientd/debug.go +++ b/cmd/zetaclientd/debug.go @@ -5,7 +5,6 @@ import ( "fmt" "strconv" "strings" - "sync" "github.com/btcsuite/btcd/rpcclient" sdk "github.com/cosmos/cosmos-sdk/types" @@ -86,9 +85,7 @@ func DebugCmd() *cobra.Command { // get ballot identifier according to the chain type if chains.IsEVMChain(chain.ChainId) { - evmObserver := evmobserver.Observer{ - Mu: &sync.Mutex{}, - } + evmObserver := evmobserver.Observer{} evmObserver.WithZetacoreClient(client) var ethRPC *ethrpc.EthRPC var client *ethclient.Client @@ -164,9 +161,7 @@ func DebugCmd() *cobra.Command { } fmt.Println("CoinType : ", coinType) } else if chains.IsBitcoinChain(chain.ChainId) { - btcObserver := btcobserver.Observer{ - Mu: &sync.Mutex{}, - } + btcObserver := btcobserver.Observer{} btcObserver.WithZetacoreClient(client) btcObserver.WithChain(*chains.GetChainFromChainID(chainID)) connCfg := &rpcclient.ConnConfig{ diff --git a/cmd/zetaclientd/utils.go b/cmd/zetaclientd/utils.go index 43caf04c11..99dd26c487 100644 --- a/cmd/zetaclientd/utils.go +++ b/cmd/zetaclientd/utils.go @@ -1,12 +1,16 @@ package main import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" "github.com/zeta-chain/zetacore/zetaclient/authz" "github.com/zeta-chain/zetacore/zetaclient/chains/base" btcobserver "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/observer" + btcrpc "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/rpc" btcsigner "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/signer" evmobserver "github.com/zeta-chain/zetacore/zetaclient/chains/evm/observer" evmsigner "github.com/zeta-chain/zetacore/zetaclient/chains/evm/signer" @@ -116,32 +120,75 @@ func CreateChainObserverMap( logger base.Logger, ts *metrics.TelemetryServer, ) (map[int64]interfaces.ChainObserver, error) { + zetacoreContext := appContext.ZetacoreContext() observerMap := make(map[int64]interfaces.ChainObserver) // EVM observers for _, evmConfig := range appContext.Config().GetAllEVMConfigs() { if evmConfig.Chain.IsZetaChain() { continue } - _, found := appContext.ZetacoreContext().GetEVMChainParams(evmConfig.Chain.ChainId) + chainParams, found := zetacoreContext.GetEVMChainParams(evmConfig.Chain.ChainId) if !found { logger.Std.Error().Msgf("ChainParam not found for chain %s", evmConfig.Chain.String()) continue } - co, err := evmobserver.NewObserver(appContext, zetacoreClient, tss, dbpath, logger, evmConfig, ts) + + // create EVM client + evmClient, err := ethclient.Dial(evmConfig.Endpoint) + if err != nil { + logger.Std.Error().Err(err).Msgf("error dailing endpoint %s", evmConfig.Endpoint) + continue + } + + // create EVM chain observer + observer, err := evmobserver.NewObserver( + evmConfig, + evmClient, + *chainParams, + zetacoreContext, + zetacoreClient, + tss, + dbpath, + logger, + ts, + ) if err != nil { logger.Std.Error().Err(err).Msgf("NewObserver error for evm chain %s", evmConfig.Chain.String()) continue } - observerMap[evmConfig.Chain.ChainId] = co + observerMap[evmConfig.Chain.ChainId] = observer } + // BTC observer + _, chainParams, found := zetacoreContext.GetBTCChainParams() + if !found { + return nil, fmt.Errorf("bitcoin chains params not found") + } + + // create BTC chain observer btcChain, btcConfig, enabled := appContext.GetBTCChainAndConfig() if enabled { - co, err := btcobserver.NewObserver(appContext, btcChain, zetacoreClient, tss, dbpath, logger, btcConfig, ts) + btcClient, err := btcrpc.NewRPCClient(btcConfig) if err != nil { - logger.Std.Error().Err(err).Msgf("NewObserver error for bitcoin chain %s", btcChain.String()) + logger.Std.Error().Err(err).Msgf("error creating rpc client for bitcoin chain %s", btcChain.String()) } else { - observerMap[btcChain.ChainId] = co + // create BTC chain observer + observer, err := btcobserver.NewObserver( + btcChain, + btcClient, + *chainParams, + zetacoreContext, + zetacoreClient, + tss, + dbpath, + logger, + ts, + ) + if err != nil { + logger.Std.Error().Err(err).Msgf("NewObserver error for bitcoin chain %s", btcChain.String()) + } else { + observerMap[btcChain.ChainId] = observer + } } } diff --git a/testutil/sample/crypto.go b/testutil/sample/crypto.go index 153f1a2a80..a5b62d7154 100644 --- a/testutil/sample/crypto.go +++ b/testutil/sample/crypto.go @@ -7,6 +7,7 @@ import ( "strconv" "testing" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/cometbft/cometbft/crypto/secp256k1" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -60,6 +61,11 @@ func Hash() ethcommon.Hash { return EthAddress().Hash() } +// BtcHash returns a sample btc hash +func BtcHash() chainhash.Hash { + return chainhash.Hash(Hash()) +} + // PubKey returns a sample account PubKey func PubKey(r *rand.Rand) cryptotypes.PubKey { seed := []byte(strconv.Itoa(r.Int())) diff --git a/zetaclient/chains/base/observer.go b/zetaclient/chains/base/observer.go index 905775b2b2..1f3fc2d0ca 100644 --- a/zetaclient/chains/base/observer.go +++ b/zetaclient/chains/base/observer.go @@ -4,6 +4,8 @@ import ( "fmt" "os" "strconv" + "strings" + "sync" "sync/atomic" lru "github.com/hashicorp/golang-lru" @@ -11,6 +13,7 @@ import ( "github.com/rs/zerolog" "gorm.io/driver/sqlite" "gorm.io/gorm" + "gorm.io/gorm/logger" "github.com/zeta-chain/zetacore/pkg/chains" observertypes "github.com/zeta-chain/zetacore/x/observer/types" @@ -28,9 +31,9 @@ const ( // Cached blocks can be used to get block information and verify transactions DefaultBlockCacheSize = 1000 - // DefaultHeadersCacheSize is the default number of headers that the observer will keep in cache for performance (without RPC calls) + // DefaultHeaderCacheSize is the default number of headers that the observer will keep in cache for performance (without RPC calls) // Cached headers can be used to get header information - DefaultHeadersCacheSize = 1000 + DefaultHeaderCacheSize = 1000 ) // Observer is the base structure for chain observers, grouping the common logic for each chain observer client. @@ -72,6 +75,10 @@ type Observer struct { // logger contains the loggers used by observer logger ObserverLogger + // mu protects fields from concurrent access + // Note: base observer simply provides the mutex. It's the sub-struct's responsibility to use it to be thread-safe + mu *sync.Mutex + // stop is the channel to signal the observer to stop stop chan struct{} } @@ -84,8 +91,7 @@ func NewObserver( zetacoreClient interfaces.ZetacoreClient, tss interfaces.TSSSigner, blockCacheSize int, - headersCacheSize int, - dbPath string, + headerCacheSize int, ts *metrics.TelemetryServer, logger Logger, ) (*Observer, error) { @@ -98,6 +104,7 @@ func NewObserver( lastBlock: 0, lastBlockScanned: 0, ts: ts, + mu: &sync.Mutex{}, stop: make(chan struct{}), } @@ -112,20 +119,29 @@ func NewObserver( } // create header cache - ob.headerCache, err = lru.New(headersCacheSize) + ob.headerCache, err = lru.New(headerCacheSize) if err != nil { return nil, errors.Wrap(err, "error creating header cache") } - // open database - err = ob.OpenDB(dbPath) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("error opening observer db for chain: %s", chain.ChainName)) - } - return &ob, nil } +// Stop notifies all goroutines to stop and closes the database. +func (ob *Observer) Stop() { + ob.logger.Chain.Info().Msgf("observer is stopping for chain %d", ob.Chain().ChainId) + close(ob.stop) + + // close database + if ob.db != nil { + err := ob.CloseDB() + if err != nil { + ob.Logger().Chain.Error().Err(err).Msgf("CloseDB failed for chain %d", ob.Chain().ChainId) + } + } + ob.Logger().Chain.Info().Msgf("observer stopped for chain %d", ob.Chain().ChainId) +} + // Chain returns the chain for the observer. func (ob *Observer) Chain() chains.Chain { return ob.chain @@ -232,9 +248,20 @@ func (ob *Observer) DB() *gorm.DB { return ob.db } +// WithTelemetryServer attaches a new telemetry server to the observer. +func (ob *Observer) WithTelemetryServer(ts *metrics.TelemetryServer) *Observer { + ob.ts = ts + return ob +} + +// TelemetryServer returns the telemetry server for the observer. +func (ob *Observer) TelemetryServer() *metrics.TelemetryServer { + return ob.ts +} + // Logger returns the logger for the observer. -func (ob *Observer) Logger() ObserverLogger { - return ob.logger +func (ob *Observer) Logger() *ObserverLogger { + return &ob.logger } // WithLogger attaches a new logger to the observer. @@ -251,45 +278,69 @@ func (ob *Observer) WithLogger(logger Logger) *Observer { return ob } -// Stop returns the stop channel for the observer. -func (ob *Observer) Stop() chan struct{} { +// Mu returns the mutex for the observer. +func (ob *Observer) Mu() *sync.Mutex { + return ob.mu +} + +// StopChannel returns the stop channel for the observer. +func (ob *Observer) StopChannel() chan struct{} { return ob.stop } // OpenDB open sql database in the given path. -func (ob *Observer) OpenDB(dbPath string) error { - if dbPath != "" { - // create db path if not exist - if _, err := os.Stat(dbPath); os.IsNotExist(err) { - err := os.MkdirAll(dbPath, os.ModePerm) - if err != nil { - return errors.Wrap(err, "error creating db path") - } - } - - // open db by chain name - chainName := ob.chain.ChainName.String() - path := fmt.Sprintf("%s/%s", dbPath, chainName) - db, err := gorm.Open(sqlite.Open(path), &gorm.Config{}) +func (ob *Observer) OpenDB(dbPath string, dbName string) error { + // create db path if not exist + if _, err := os.Stat(dbPath); os.IsNotExist(err) { + err := os.MkdirAll(dbPath, os.ModePerm) if err != nil { - return errors.Wrap(err, "error opening db") + return errors.Wrapf(err, "error creating db path: %s", dbPath) } + } - // migrate db - err = db.AutoMigrate(&clienttypes.ReceiptSQLType{}, - &clienttypes.TransactionSQLType{}, - &clienttypes.LastBlockSQLType{}) - if err != nil { - return errors.Wrap(err, "error migrating db") - } - ob.db = db + // use custom dbName or chain name if not provided + if dbName == "" { + dbName = ob.chain.ChainName.String() + } + path := fmt.Sprintf("%s/%s", dbPath, dbName) + + // use memory db if specified + if strings.Contains(dbPath, ":memory:") { + path = dbPath + } + + // open db + db, err := gorm.Open(sqlite.Open(path), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)}) + if err != nil { + return errors.Wrap(err, "error opening db") + } + + // migrate db + err = db.AutoMigrate(&clienttypes.LastBlockSQLType{}) + if err != nil { + return errors.Wrap(err, "error migrating db") + } + ob.db = db + + return nil +} + +// CloseDB close the database. +func (ob *Observer) CloseDB() error { + dbInst, err := ob.db.DB() + if err != nil { + return fmt.Errorf("error getting database instance: %w", err) + } + err = dbInst.Close() + if err != nil { + return fmt.Errorf("error closing database: %w", err) } return nil } // LoadLastBlockScanned loads last scanned block from environment variable or from database. // The last scanned block is the height from which the observer should continue scanning. -func (ob *Observer) LoadLastBlockScanned(logger zerolog.Logger) (fromLatest bool, err error) { +func (ob *Observer) LoadLastBlockScanned(logger zerolog.Logger) error { // get environment variable envvar := EnvVarLatestBlockByChain(ob.chain) scanFromBlock := os.Getenv(envvar) @@ -299,27 +350,33 @@ func (ob *Observer) LoadLastBlockScanned(logger zerolog.Logger) (fromLatest bool logger.Info(). Msgf("LoadLastBlockScanned: envvar %s is set; scan from block %s", envvar, scanFromBlock) if scanFromBlock == EnvVarLatestBlock { - return true, nil + return nil } blockNumber, err := strconv.ParseUint(scanFromBlock, 10, 64) if err != nil { - return false, err + return err } ob.WithLastBlockScanned(blockNumber) - return false, nil + return nil } // load from DB otherwise. If not found, start from latest block blockNumber, err := ob.ReadLastBlockScannedFromDB() if err != nil { - logger.Info().Msgf("LoadLastBlockScanned: chain %d starts scanning from latest block", ob.chain.ChainId) - return true, nil + logger.Info().Msgf("LoadLastBlockScanned: last scanned block not found in db for chain %d", ob.chain.ChainId) + return nil } ob.WithLastBlockScanned(blockNumber) logger.Info(). Msgf("LoadLastBlockScanned: chain %d starts scanning from block %d", ob.chain.ChainId, ob.LastBlockScanned()) - return false, nil + return nil +} + +// SaveLastBlockScanned saves the last scanned block to memory and database. +func (ob *Observer) SaveLastBlockScanned(blockNumber uint64) error { + ob.WithLastBlockScanned(blockNumber) + return ob.WriteLastBlockScannedToDB(blockNumber) } // WriteLastBlockScannedToDB saves the last scanned block to the database. @@ -339,5 +396,5 @@ func (ob *Observer) ReadLastBlockScannedFromDB() (uint64, error) { // EnvVarLatestBlock returns the environment variable for the latest block by chain. func EnvVarLatestBlockByChain(chain chains.Chain) string { - return chain.ChainName.String() + "_SCAN_FROM" + return fmt.Sprintf("CHAIN_%d_SCAN_FROM", chain.ChainId) } diff --git a/zetaclient/chains/base/observer_test.go b/zetaclient/chains/base/observer_test.go index 6972478190..a04a48fcc3 100644 --- a/zetaclient/chains/base/observer_test.go +++ b/zetaclient/chains/base/observer_test.go @@ -7,6 +7,7 @@ import ( lru "github.com/hashicorp/golang-lru" "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/zetaclient/testutils" "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/testutil/sample" @@ -15,11 +16,12 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" "github.com/zeta-chain/zetacore/zetaclient/config" "github.com/zeta-chain/zetacore/zetaclient/context" + "github.com/zeta-chain/zetacore/zetaclient/metrics" "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" ) // createObserver creates a new observer for testing -func createObserver(t *testing.T, dbPath string) *base.Observer { +func createObserver(t *testing.T) *base.Observer { // constructor parameters chain := chains.Ethereum chainParams := *sample.ChainParams(chain.ChainId) @@ -36,8 +38,7 @@ func createObserver(t *testing.T, dbPath string) *base.Observer { zetacoreClient, tss, base.DefaultBlockCacheSize, - base.DefaultHeadersCacheSize, - dbPath, + base.DefaultHeaderCacheSize, nil, logger, ) @@ -54,73 +55,55 @@ func TestNewObserver(t *testing.T) { zetacoreClient := mocks.NewMockZetacoreClient() tss := mocks.NewTSSMainnet() blockCacheSize := base.DefaultBlockCacheSize - headersCacheSize := base.DefaultHeadersCacheSize - dbPath := sample.CreateTempDir(t) + headersCacheSize := base.DefaultHeaderCacheSize // test cases tests := []struct { - name string - chain chains.Chain - chainParams observertypes.ChainParams - zetacoreContext *context.ZetacoreContext - zetacoreClient interfaces.ZetacoreClient - tss interfaces.TSSSigner - blockCacheSize int - headersCacheSize int - dbPath string - fail bool - message string + name string + chain chains.Chain + chainParams observertypes.ChainParams + zetacoreContext *context.ZetacoreContext + zetacoreClient interfaces.ZetacoreClient + tss interfaces.TSSSigner + blockCacheSize int + headerCacheSize int + fail bool + message string }{ { - name: "should be able to create new observer", - chain: chain, - chainParams: chainParams, - zetacoreContext: zetacoreContext, - zetacoreClient: zetacoreClient, - tss: tss, - blockCacheSize: blockCacheSize, - headersCacheSize: headersCacheSize, - dbPath: dbPath, - fail: false, - }, - { - name: "should return error on invalid block cache size", - chain: chain, - chainParams: chainParams, - zetacoreContext: zetacoreContext, - zetacoreClient: zetacoreClient, - tss: tss, - blockCacheSize: 0, - headersCacheSize: headersCacheSize, - dbPath: dbPath, - fail: true, - message: "error creating block cache", + name: "should be able to create new observer", + chain: chain, + chainParams: chainParams, + zetacoreContext: zetacoreContext, + zetacoreClient: zetacoreClient, + tss: tss, + blockCacheSize: blockCacheSize, + headerCacheSize: headersCacheSize, + fail: false, }, { - name: "should return error on invalid header cache size", - chain: chain, - chainParams: chainParams, - zetacoreContext: zetacoreContext, - zetacoreClient: zetacoreClient, - tss: tss, - blockCacheSize: blockCacheSize, - headersCacheSize: 0, - dbPath: dbPath, - fail: true, - message: "error creating header cache", + name: "should return error on invalid block cache size", + chain: chain, + chainParams: chainParams, + zetacoreContext: zetacoreContext, + zetacoreClient: zetacoreClient, + tss: tss, + blockCacheSize: 0, + headerCacheSize: headersCacheSize, + fail: true, + message: "error creating block cache", }, { - name: "should return error on invalid db path", - chain: chain, - chainParams: chainParams, - zetacoreContext: zetacoreContext, - zetacoreClient: zetacoreClient, - tss: tss, - blockCacheSize: blockCacheSize, - headersCacheSize: headersCacheSize, - dbPath: "/invalid/123db", - fail: true, - message: "error opening observer db", + name: "should return error on invalid header cache size", + chain: chain, + chainParams: chainParams, + zetacoreContext: zetacoreContext, + zetacoreClient: zetacoreClient, + tss: tss, + blockCacheSize: blockCacheSize, + headerCacheSize: 0, + fail: true, + message: "error creating header cache", }, } @@ -134,8 +117,7 @@ func TestNewObserver(t *testing.T) { tt.zetacoreClient, tt.tss, tt.blockCacheSize, - tt.headersCacheSize, - tt.dbPath, + tt.headerCacheSize, nil, base.DefaultLogger(), ) @@ -151,11 +133,20 @@ func TestNewObserver(t *testing.T) { } } -func TestObserverGetterAndSetter(t *testing.T) { - dbPath := sample.CreateTempDir(t) +func TestStop(t *testing.T) { + t.Run("should be able to stop observer", func(t *testing.T) { + // create observer and initialize db + ob := createObserver(t) + ob.OpenDB(sample.CreateTempDir(t), "") + + // stop observer + ob.Stop() + }) +} +func TestObserverGetterAndSetter(t *testing.T) { t.Run("should be able to update chain", func(t *testing.T) { - ob := createObserver(t, dbPath) + ob := createObserver(t) // update chain newChain := chains.BscMainnet @@ -163,7 +154,7 @@ func TestObserverGetterAndSetter(t *testing.T) { require.Equal(t, newChain, ob.Chain()) }) t.Run("should be able to update chain params", func(t *testing.T) { - ob := createObserver(t, dbPath) + ob := createObserver(t) // update chain params newChainParams := *sample.ChainParams(chains.BscMainnet.ChainId) @@ -171,7 +162,7 @@ func TestObserverGetterAndSetter(t *testing.T) { require.True(t, observertypes.ChainParamsEqual(newChainParams, ob.ChainParams())) }) t.Run("should be able to update zetacore context", func(t *testing.T) { - ob := createObserver(t, dbPath) + ob := createObserver(t) // update zetacore context newZetacoreContext := context.NewZetacoreContext(config.NewConfig()) @@ -179,7 +170,7 @@ func TestObserverGetterAndSetter(t *testing.T) { require.Equal(t, newZetacoreContext, ob.ZetacoreContext()) }) t.Run("should be able to update zetacore client", func(t *testing.T) { - ob := createObserver(t, dbPath) + ob := createObserver(t) // update zetacore client newZetacoreClient := mocks.NewMockZetacoreClient() @@ -187,7 +178,7 @@ func TestObserverGetterAndSetter(t *testing.T) { require.Equal(t, newZetacoreClient, ob.ZetacoreClient()) }) t.Run("should be able to update tss", func(t *testing.T) { - ob := createObserver(t, dbPath) + ob := createObserver(t) // update tss newTSS := mocks.NewTSSAthens3() @@ -195,7 +186,7 @@ func TestObserverGetterAndSetter(t *testing.T) { require.Equal(t, newTSS, ob.TSS()) }) t.Run("should be able to update last block", func(t *testing.T) { - ob := createObserver(t, dbPath) + ob := createObserver(t) // update last block newLastBlock := uint64(100) @@ -203,7 +194,7 @@ func TestObserverGetterAndSetter(t *testing.T) { require.Equal(t, newLastBlock, ob.LastBlock()) }) t.Run("should be able to update last block scanned", func(t *testing.T) { - ob := createObserver(t, dbPath) + ob := createObserver(t) // update last block scanned newLastBlockScanned := uint64(100) @@ -211,7 +202,7 @@ func TestObserverGetterAndSetter(t *testing.T) { require.Equal(t, newLastBlockScanned, ob.LastBlockScanned()) }) t.Run("should be able to replace block cache", func(t *testing.T) { - ob := createObserver(t, dbPath) + ob := createObserver(t) // update block cache newBlockCache, err := lru.New(200) @@ -220,8 +211,8 @@ func TestObserverGetterAndSetter(t *testing.T) { ob = ob.WithBlockCache(newBlockCache) require.Equal(t, newBlockCache, ob.BlockCache()) }) - t.Run("should be able to replace headers cache", func(t *testing.T) { - ob := createObserver(t, dbPath) + t.Run("should be able to replace header cache", func(t *testing.T) { + ob := createObserver(t) // update headers cache newHeadersCache, err := lru.New(200) @@ -231,13 +222,24 @@ func TestObserverGetterAndSetter(t *testing.T) { require.Equal(t, newHeadersCache, ob.HeaderCache()) }) t.Run("should be able to get database", func(t *testing.T) { - ob := createObserver(t, dbPath) + // create observer and open db + dbPath := sample.CreateTempDir(t) + ob := createObserver(t) + ob.OpenDB(dbPath, "") db := ob.DB() require.NotNil(t, db) }) + t.Run("should be able to update telemetry server", func(t *testing.T) { + ob := createObserver(t) + + // update telemetry server + newServer := metrics.NewTelemetryServer() + ob = ob.WithTelemetryServer(newServer) + require.Equal(t, newServer, ob.TelemetryServer()) + }) t.Run("should be able to get logger", func(t *testing.T) { - ob := createObserver(t, dbPath) + ob := createObserver(t) logger := ob.Logger() // should be able to print log @@ -250,16 +252,30 @@ func TestObserverGetterAndSetter(t *testing.T) { }) } -func TestOpenDB(t *testing.T) { +func TestOpenCloseDB(t *testing.T) { dbPath := sample.CreateTempDir(t) - ob := createObserver(t, dbPath) + ob := createObserver(t) + + t.Run("should be able to open/close db", func(t *testing.T) { + // open db + err := ob.OpenDB(dbPath, "") + require.NoError(t, err) - t.Run("should be able to open db", func(t *testing.T) { - err := ob.OpenDB(dbPath) + // close db + err = ob.CloseDB() + require.NoError(t, err) + }) + t.Run("should use memory db if specified", func(t *testing.T) { + // open db with memory + err := ob.OpenDB(testutils.SQLiteMemory, "") + require.NoError(t, err) + + // close db + err = ob.CloseDB() require.NoError(t, err) }) t.Run("should return error on invalid db path", func(t *testing.T) { - err := ob.OpenDB("/invalid/123db") + err := ob.OpenDB("/invalid/123db", "") require.ErrorContains(t, err, "error creating db path") }) } @@ -269,71 +285,116 @@ func TestLoadLastBlockScanned(t *testing.T) { envvar := base.EnvVarLatestBlockByChain(chain) t.Run("should be able to load last block scanned", func(t *testing.T) { - // create db and write 100 as last block scanned + // create observer and open db dbPath := sample.CreateTempDir(t) - ob := createObserver(t, dbPath) + ob := createObserver(t) + err := ob.OpenDB(dbPath, "") + require.NoError(t, err) + + // create db and write 100 as last block scanned ob.WriteLastBlockScannedToDB(100) // read last block scanned - fromLatest, err := ob.LoadLastBlockScanned(log.Logger) + err = ob.LoadLastBlockScanned(log.Logger) require.NoError(t, err) require.EqualValues(t, 100, ob.LastBlockScanned()) - require.False(t, fromLatest) }) - t.Run("should use latest block if last block scanned not found", func(t *testing.T) { - // create empty db + t.Run("latest block scanned should be 0 if not found in db", func(t *testing.T) { + // create observer and open db dbPath := sample.CreateTempDir(t) - ob := createObserver(t, dbPath) + ob := createObserver(t) + err := ob.OpenDB(dbPath, "") + require.NoError(t, err) // read last block scanned - fromLatest, err := ob.LoadLastBlockScanned(log.Logger) + err = ob.LoadLastBlockScanned(log.Logger) require.NoError(t, err) - require.True(t, fromLatest) + require.EqualValues(t, 0, ob.LastBlockScanned()) }) t.Run("should overwrite last block scanned if env var is set", func(t *testing.T) { - // create db and write 100 as last block scanned + // create observer and open db dbPath := sample.CreateTempDir(t) - ob := createObserver(t, dbPath) + ob := createObserver(t) + err := ob.OpenDB(dbPath, "") + require.NoError(t, err) + + // create db and write 100 as last block scanned ob.WriteLastBlockScannedToDB(100) // set env var os.Setenv(envvar, "101") // read last block scanned - fromLatest, err := ob.LoadLastBlockScanned(log.Logger) + err = ob.LoadLastBlockScanned(log.Logger) require.NoError(t, err) require.EqualValues(t, 101, ob.LastBlockScanned()) - require.False(t, fromLatest) + }) + t.Run("last block scanned should remain 0 if env var is set to latest", func(t *testing.T) { + // create observer and open db + dbPath := sample.CreateTempDir(t) + ob := createObserver(t) + err := ob.OpenDB(dbPath, "") + require.NoError(t, err) + + // create db and write 100 as last block scanned + ob.WriteLastBlockScannedToDB(100) // set env var to 'latest' os.Setenv(envvar, base.EnvVarLatestBlock) - // read last block scanned - fromLatest, err = ob.LoadLastBlockScanned(log.Logger) + // last block scanned should remain 0 + err = ob.LoadLastBlockScanned(log.Logger) require.NoError(t, err) - require.True(t, fromLatest) + require.EqualValues(t, 0, ob.LastBlockScanned()) }) t.Run("should return error on invalid env var", func(t *testing.T) { - // create db and write 100 as last block scanned + // create observer and open db dbPath := sample.CreateTempDir(t) - ob := createObserver(t, dbPath) + ob := createObserver(t) + err := ob.OpenDB(dbPath, "") + require.NoError(t, err) // set invalid env var os.Setenv(envvar, "invalid") // read last block scanned - fromLatest, err := ob.LoadLastBlockScanned(log.Logger) + err = ob.LoadLastBlockScanned(log.Logger) require.Error(t, err) - require.False(t, fromLatest) + }) +} + +func TestSaveLastBlockScanned(t *testing.T) { + t.Run("should be able to save last block scanned", func(t *testing.T) { + // create observer and open db + dbPath := sample.CreateTempDir(t) + ob := createObserver(t) + err := ob.OpenDB(dbPath, "") + require.NoError(t, err) + + // save 100 as last block scanned + err = ob.SaveLastBlockScanned(100) + require.NoError(t, err) + + // check last block scanned in memory + require.EqualValues(t, 100, ob.LastBlockScanned()) + + // read last block scanned from db + lastBlockScanned, err := ob.ReadLastBlockScannedFromDB() + require.NoError(t, err) + require.EqualValues(t, 100, lastBlockScanned) }) } func TestReadWriteLastBlockScannedToDB(t *testing.T) { t.Run("should be able to write and read last block scanned to db", func(t *testing.T) { - // create db and write 100 as last block scanned + // create observer and open db dbPath := sample.CreateTempDir(t) - ob := createObserver(t, dbPath) - err := ob.WriteLastBlockScannedToDB(100) + ob := createObserver(t) + err := ob.OpenDB(dbPath, "") + require.NoError(t, err) + + // write last block scanned + err = ob.WriteLastBlockScannedToDB(100) require.NoError(t, err) lastBlockScanned, err := ob.ReadLastBlockScannedFromDB() @@ -343,7 +404,9 @@ func TestReadWriteLastBlockScannedToDB(t *testing.T) { t.Run("should return error when last block scanned not found in db", func(t *testing.T) { // create empty db dbPath := sample.CreateTempDir(t) - ob := createObserver(t, dbPath) + ob := createObserver(t) + err := ob.OpenDB(dbPath, "") + require.NoError(t, err) lastScannedBlock, err := ob.ReadLastBlockScannedFromDB() require.Error(t, err) diff --git a/zetaclient/chains/base/signer.go b/zetaclient/chains/base/signer.go index a33f116e48..bc5ad7934f 100644 --- a/zetaclient/chains/base/signer.go +++ b/zetaclient/chains/base/signer.go @@ -29,7 +29,7 @@ type Signer struct { // mu protects fields from concurrent access // Note: base signer simply provides the mutex. It's the sub-struct's responsibility to use it to be thread-safe - mu *sync.Mutex + mu sync.Mutex } // NewSigner creates a new base signer @@ -49,7 +49,6 @@ func NewSigner( Std: logger.Std.With().Int64("chain", chain.ChainId).Str("module", "signer").Logger(), Compliance: logger.Compliance, }, - mu: &sync.Mutex{}, } } @@ -102,7 +101,12 @@ func (s *Signer) Logger() *Logger { return &s.logger } -// Mu returns the mutex for the signer -func (s *Signer) Mu() *sync.Mutex { - return s.mu +// Lock locks the signer +func (s *Signer) Lock() { + s.mu.Lock() +} + +// Unlock unlocks the signer +func (s *Signer) Unlock() { + s.mu.Unlock() } diff --git a/zetaclient/chains/base/signer_test.go b/zetaclient/chains/base/signer_test.go index 3de1d18d4a..960c508d6e 100644 --- a/zetaclient/chains/base/signer_test.go +++ b/zetaclient/chains/base/signer_test.go @@ -71,8 +71,4 @@ func TestSignerGetterAndSetter(t *testing.T) { logger.Std.Info().Msg("print standard log") logger.Compliance.Info().Msg("print compliance log") }) - t.Run("should be able to get mutex", func(t *testing.T) { - signer := createSigner(t) - require.NotNil(t, signer.Mu()) - }) } diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index 54c5294745..2438411b5b 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -25,7 +25,7 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/zetacore" ) -// WatchInbound watches Bitcoin chain for incoming txs and post votes to zetacore +// WatchInbound watches Bitcoin chain for inbounds on a ticker func (ob *Observer) WatchInbound() { ticker, err := types.NewDynamicTicker("Bitcoin_WatchInbound", ob.GetChainParams().InboundTicker) if err != nil { @@ -34,15 +34,15 @@ func (ob *Observer) WatchInbound() { } defer ticker.Stop() - ob.logger.Inbound.Info().Msgf("WatchInbound started for chain %d", ob.chain.ChainId) + ob.logger.Inbound.Info().Msgf("WatchInbound started for chain %d", ob.Chain().ChainId) sampledLogger := ob.logger.Inbound.Sample(&zerolog.BasicSampler{N: 10}) for { select { case <-ticker.C(): - if !context.IsInboundObservationEnabled(ob.coreContext, ob.GetChainParams()) { + if !context.IsInboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { sampledLogger.Info(). - Msgf("WatchInbound: inbound observation is disabled for chain %d", ob.chain.ChainId) + Msgf("WatchInbound: inbound observation is disabled for chain %d", ob.Chain().ChainId) continue } err := ob.ObserveInbound() @@ -50,47 +50,49 @@ func (ob *Observer) WatchInbound() { ob.logger.Inbound.Error().Err(err).Msg("WatchInbound error observing in tx") } ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.logger.Inbound) - case <-ob.stop: - ob.logger.Inbound.Info().Msgf("WatchInbound stopped for chain %d", ob.chain.ChainId) + case <-ob.StopChannel(): + ob.logger.Inbound.Info().Msgf("WatchInbound stopped for chain %d", ob.Chain().ChainId) return } } } +// ObserveInbound observes the Bitcoin chain for inbounds and post votes to zetacore func (ob *Observer) ObserveInbound() error { // get and update latest block height - cnt, err := ob.rpcClient.GetBlockCount() + cnt, err := ob.btcClient.GetBlockCount() if err != nil { return fmt.Errorf("observeInboundBTC: error getting block number: %s", err) } if cnt < 0 { return fmt.Errorf("observeInboundBTC: block number is negative: %d", cnt) } - if cnt < ob.GetLastBlockHeight() { + // #nosec G701 checked positive + lastBlock := uint64(cnt) + if lastBlock < ob.LastBlock() { return fmt.Errorf( "observeInboundBTC: block number should not decrease: current %d last %d", cnt, - ob.GetLastBlockHeight(), + ob.LastBlock(), ) } - ob.SetLastBlockHeight(cnt) + ob.WithLastBlock(lastBlock) // skip if current height is too low - // #nosec G701 always in range - confirmedBlockNum := cnt - int64(ob.GetChainParams().ConfirmationCount) - if confirmedBlockNum < 0 { + if lastBlock < ob.GetChainParams().ConfirmationCount { return fmt.Errorf("observeInboundBTC: skipping observer, current block number %d is too low", cnt) } // skip if no new block is confirmed - lastScanned := ob.GetLastBlockHeightScanned() - if lastScanned >= confirmedBlockNum { + lastScanned := ob.LastBlockScanned() + if lastScanned >= lastBlock-ob.GetChainParams().ConfirmationCount { return nil } // query incoming gas asset to TSS address blockNumber := lastScanned + 1 - res, err := ob.GetBlockByNumberCached(blockNumber) + // #nosec G701 always in range + res, err := ob.GetBlockByNumberCached(int64(blockNumber)) if err != nil { ob.logger.Inbound.Error().Err(err).Msgf("observeInboundBTC: error getting bitcoin block %d", blockNumber) return err @@ -103,9 +105,10 @@ func (ob *Observer) ObserveInbound() error { // https://github.com/zeta-chain/node/issues/1847 // TODO: move this logic in its own routine // https://github.com/zeta-chain/node/issues/2204 - blockHeaderVerification, found := ob.coreContext.GetBlockHeaderEnabledChains(ob.chain.ChainId) + blockHeaderVerification, found := ob.ZetacoreContext().GetBlockHeaderEnabledChains(ob.Chain().ChainId) if found && blockHeaderVerification.Enabled { - err = ob.postBlockHeader(blockNumber) + // #nosec G701 always in range + err = ob.postBlockHeader(int64(blockNumber)) if err != nil { ob.logger.Inbound.Warn().Err(err).Msgf("observeInboundBTC: error posting block header %d", blockNumber) } @@ -113,14 +116,14 @@ func (ob *Observer) ObserveInbound() error { if len(res.Block.Tx) > 1 { // get depositor fee - depositorFee := bitcoin.CalcDepositorFee(res.Block, ob.chain.ChainId, ob.netParams, ob.logger.Inbound) + depositorFee := bitcoin.CalcDepositorFee(res.Block, ob.Chain().ChainId, ob.netParams, ob.logger.Inbound) // filter incoming txs to TSS address - tssAddress := ob.Tss.BTCAddress() + tssAddress := ob.TSS().BTCAddress() // #nosec G701 always positive inbounds, err := FilterAndParseIncomingTx( - ob.rpcClient, + ob.btcClient, res.Block.Tx, uint64(res.Block.Height), tssAddress, @@ -139,7 +142,7 @@ func (ob *Observer) ObserveInbound() error { for _, inbound := range inbounds { msg := ob.GetInboundVoteMessageFromBtcEvent(inbound) if msg != nil { - zetaHash, ballot, err := ob.zetacoreClient.PostVoteInbound( + zetaHash, ballot, err := ob.ZetacoreClient().PostVoteInbound( zetacore.PostVoteInboundGasLimit, zetacore.PostVoteInboundExecutionGasLimit, msg, @@ -157,11 +160,8 @@ func (ob *Observer) ObserveInbound() error { } } - // Save LastBlockHeight - ob.SetLastBlockHeightScanned(blockNumber) - - // #nosec G701 always positive - if err := ob.db.Save(types.ToLastBlockSQLType(uint64(blockNumber))).Error; err != nil { + // save last scanned block to both memory and db + if err := ob.SaveLastBlockScanned(blockNumber); err != nil { ob.logger.Inbound.Error(). Err(err). Msgf("observeInboundBTC: error writing last scanned block %d to db", blockNumber) @@ -182,18 +182,18 @@ func (ob *Observer) WatchInboundTracker() { for { select { case <-ticker.C(): - if !context.IsInboundObservationEnabled(ob.coreContext, ob.GetChainParams()) { + if !context.IsInboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { continue } err := ob.ProcessInboundTrackers() if err != nil { ob.logger.Inbound.Error(). Err(err). - Msgf("error observing inbound tracker for chain %d", ob.chain.ChainId) + Msgf("error observing inbound tracker for chain %d", ob.Chain().ChainId) } ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.logger.Inbound) - case <-ob.stop: - ob.logger.Inbound.Info().Msgf("WatchInboundTracker stopped for chain %d", ob.chain.ChainId) + case <-ob.StopChannel(): + ob.logger.Inbound.Info().Msgf("WatchInboundTracker stopped for chain %d", ob.Chain().ChainId) return } } @@ -201,7 +201,7 @@ func (ob *Observer) WatchInboundTracker() { // ProcessInboundTrackers processes inbound trackers func (ob *Observer) ProcessInboundTrackers() error { - trackers, err := ob.zetacoreClient.GetInboundTrackersForChain(ob.chain.ChainId) + trackers, err := ob.ZetacoreClient().GetInboundTrackersForChain(ob.Chain().ChainId) if err != nil { return err } @@ -214,7 +214,7 @@ func (ob *Observer) ProcessInboundTrackers() error { return err } ob.logger.Inbound.Info(). - Msgf("Vote submitted for inbound Tracker, Chain : %s,Ballot Identifier : %s, coin-type %s", ob.chain.ChainName, ballotIdentifier, coin.CoinType_Gas.String()) + Msgf("Vote submitted for inbound Tracker, Chain : %s,Ballot Identifier : %s, coin-type %s", ob.Chain().ChainName, ballotIdentifier, coin.CoinType_Gas.String()) } return nil @@ -227,7 +227,7 @@ func (ob *Observer) CheckReceiptForBtcTxHash(txHash string, vote bool) (string, return "", err } - tx, err := ob.rpcClient.GetRawTransactionVerbose(hash) + tx, err := ob.btcClient.GetRawTransactionVerbose(hash) if err != nil { return "", err } @@ -237,7 +237,7 @@ func (ob *Observer) CheckReceiptForBtcTxHash(txHash string, vote bool) (string, return "", err } - blockVb, err := ob.rpcClient.GetBlockVerboseTx(blockHash) + blockVb, err := ob.btcClient.GetBlockVerboseTx(blockHash) if err != nil { return "", err } @@ -246,15 +246,15 @@ func (ob *Observer) CheckReceiptForBtcTxHash(txHash string, vote bool) (string, return "", fmt.Errorf("block %d has no transactions", blockVb.Height) } - depositorFee := bitcoin.CalcDepositorFee(blockVb, ob.chain.ChainId, ob.netParams, ob.logger.Inbound) - tss, err := ob.zetacoreClient.GetBtcTssAddress(ob.chain.ChainId) + depositorFee := bitcoin.CalcDepositorFee(blockVb, ob.Chain().ChainId, ob.netParams, ob.logger.Inbound) + tss, err := ob.ZetacoreClient().GetBtcTssAddress(ob.Chain().ChainId) if err != nil { return "", err } // #nosec G701 always positive event, err := GetBtcEvent( - ob.rpcClient, + ob.btcClient, *tx, tss, uint64(blockVb.Height), @@ -279,7 +279,7 @@ func (ob *Observer) CheckReceiptForBtcTxHash(txHash string, vote bool) (string, return msg.Digest(), nil } - zetaHash, ballot, err := ob.zetacoreClient.PostVoteInbound( + zetaHash, ballot, err := ob.ZetacoreClient().PostVoteInbound( zetacore.PostVoteInboundGasLimit, zetacore.PostVoteInboundExecutionGasLimit, msg, @@ -343,10 +343,10 @@ func (ob *Observer) GetInboundVoteMessageFromBtcEvent(inbound *BTCInboundEvent) return zetacore.GetInboundVoteMessage( inbound.FromAddress, - ob.chain.ChainId, + ob.Chain().ChainId, inbound.FromAddress, inbound.FromAddress, - ob.zetacoreClient.Chain().ChainId, + ob.ZetacoreClient().Chain().ChainId, cosmosmath.NewUintFromBigInt(amountInt), message, inbound.TxHash, @@ -354,7 +354,7 @@ func (ob *Observer) GetInboundVoteMessageFromBtcEvent(inbound *BTCInboundEvent) 0, coin.CoinType_Gas, "", - ob.zetacoreClient.GetKeys().GetOperatorAddress().String(), + ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), 0, ) } @@ -368,7 +368,7 @@ func (ob *Observer) DoesInboundContainsRestrictedAddress(inTx *BTCInboundEvent) } if config.ContainRestrictedAddress(inTx.FromAddress, receiver) { compliance.PrintComplianceLog(ob.logger.Inbound, ob.logger.Compliance, - false, ob.chain.ChainId, inTx.TxHash, inTx.FromAddress, receiver, "BTC") + false, ob.Chain().ChainId, inTx.TxHash, inTx.FromAddress, receiver, "BTC") return true } return false diff --git a/zetaclient/chains/bitcoin/observer/inbound_test.go b/zetaclient/chains/bitcoin/observer/inbound_test.go index b67b7d7b50..63042e8b85 100644 --- a/zetaclient/chains/bitcoin/observer/inbound_test.go +++ b/zetaclient/chains/bitcoin/observer/inbound_test.go @@ -1,4 +1,4 @@ -package observer +package observer_test import ( "bytes" @@ -18,6 +18,7 @@ import ( "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin" + "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/observer" clientcommon "github.com/zeta-chain/zetacore/zetaclient/common" "github.com/zeta-chain/zetacore/zetaclient/testutils" "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" @@ -198,7 +199,7 @@ func TestGetSenderAddressByVin(t *testing.T) { // get sender address txVin := btcjson.Vin{Txid: txHash, Vout: 2} - sender, err := GetSenderAddressByVin(rpcClient, txVin, net) + sender, err := observer.GetSenderAddressByVin(rpcClient, txVin, net) require.NoError(t, err) require.Equal(t, "bc1px3peqcd60hk7wqyqk36697u9hzugq0pd5lzvney93yzzrqy4fkpq6cj7m3", sender) }) @@ -210,7 +211,7 @@ func TestGetSenderAddressByVin(t *testing.T) { // get sender address txVin := btcjson.Vin{Txid: txHash, Vout: 0} - sender, err := GetSenderAddressByVin(rpcClient, txVin, net) + sender, err := observer.GetSenderAddressByVin(rpcClient, txVin, net) require.NoError(t, err) require.Equal(t, "bc1q79kmcyc706d6nh7tpzhnn8lzp76rp0tepph3hqwrhacqfcy4lwxqft0ppq", sender) }) @@ -222,7 +223,7 @@ func TestGetSenderAddressByVin(t *testing.T) { // get sender address txVin := btcjson.Vin{Txid: txHash, Vout: 2} - sender, err := GetSenderAddressByVin(rpcClient, txVin, net) + sender, err := observer.GetSenderAddressByVin(rpcClient, txVin, net) require.NoError(t, err) require.Equal(t, "bc1q68kxnq52ahz5vd6c8czevsawu0ux9nfrzzrh6e", sender) }) @@ -234,7 +235,7 @@ func TestGetSenderAddressByVin(t *testing.T) { // get sender address txVin := btcjson.Vin{Txid: txHash, Vout: 0} - sender, err := GetSenderAddressByVin(rpcClient, txVin, net) + sender, err := observer.GetSenderAddressByVin(rpcClient, txVin, net) require.NoError(t, err) require.Equal(t, "3MqRRSP76qxdVD9K4cfFnVtSLVwaaAjm3t", sender) }) @@ -246,7 +247,7 @@ func TestGetSenderAddressByVin(t *testing.T) { // get sender address txVin := btcjson.Vin{Txid: txHash, Vout: 1} - sender, err := GetSenderAddressByVin(rpcClient, txVin, net) + sender, err := observer.GetSenderAddressByVin(rpcClient, txVin, net) require.NoError(t, err) require.Equal(t, "1ESQp1WQi7fzSpzCNs2oBTqaUBmNjLQLoV", sender) }) @@ -272,7 +273,7 @@ func TestGetSenderAddressByVin(t *testing.T) { // get sender address txVin := btcjson.Vin{Txid: txHash, Vout: 1} - sender, err := GetSenderAddressByVin(rpcClient, txVin, net) + sender, err := observer.GetSenderAddressByVin(rpcClient, txVin, net) require.NoError(t, err) require.Empty(t, sender) }) @@ -288,7 +289,7 @@ func TestGetSenderAddressByVinErrors(t *testing.T) { rpcClient := mocks.NewMockBTCRPCClient() // use invalid tx hash txVin := btcjson.Vin{Txid: "invalid tx hash", Vout: 2} - sender, err := GetSenderAddressByVin(rpcClient, txVin, net) + sender, err := observer.GetSenderAddressByVin(rpcClient, txVin, net) require.Error(t, err) require.Empty(t, sender) }) @@ -296,7 +297,7 @@ func TestGetSenderAddressByVinErrors(t *testing.T) { // create mock rpc client without preloaded tx rpcClient := mocks.NewMockBTCRPCClient() txVin := btcjson.Vin{Txid: txHash, Vout: 2} - sender, err := GetSenderAddressByVin(rpcClient, txVin, net) + sender, err := observer.GetSenderAddressByVin(rpcClient, txVin, net) require.ErrorContains(t, err, "error getting raw transaction") require.Empty(t, sender) }) @@ -305,7 +306,7 @@ func TestGetSenderAddressByVinErrors(t *testing.T) { rpcClient := createRPCClientAndLoadTx(t, chain.ChainId, txHash) // invalid output index txVin := btcjson.Vin{Txid: txHash, Vout: 3} - sender, err := GetSenderAddressByVin(rpcClient, txVin, net) + sender, err := observer.GetSenderAddressByVin(rpcClient, txVin, net) require.ErrorContains(t, err, "out of range") require.Empty(t, sender) }) @@ -328,7 +329,7 @@ func TestGetBtcEvent(t *testing.T) { // expected result memo, err := hex.DecodeString(tx.Vout[1].ScriptPubKey.Hex[4:]) require.NoError(t, err) - eventExpected := &BTCInboundEvent{ + eventExpected := &observer.BTCInboundEvent{ FromAddress: "bc1q68kxnq52ahz5vd6c8czevsawu0ux9nfrzzrh6e", ToAddress: tssAddress, Value: tx.Vout[0].Value - depositorFee, // 7008 sataoshis @@ -347,7 +348,7 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := createRPCClientAndLoadTx(t, chain.ChainId, preHash) // get BTC event - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -362,7 +363,7 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := createRPCClientAndLoadTx(t, chain.ChainId, preHash) // get BTC event - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -377,7 +378,7 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := createRPCClientAndLoadTx(t, chain.ChainId, preHash) // get BTC event - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -392,7 +393,7 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := createRPCClientAndLoadTx(t, chain.ChainId, preHash) // get BTC event - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -407,7 +408,7 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := createRPCClientAndLoadTx(t, chain.ChainId, preHash) // get BTC event - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -418,7 +419,7 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewMockBTCRPCClient() - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Nil(t, event) }) @@ -429,13 +430,13 @@ func TestGetBtcEvent(t *testing.T) { // modify the tx to have Vout[0] a P2SH output tx.Vout[0].ScriptPubKey.Hex = strings.Replace(tx.Vout[0].ScriptPubKey.Hex, "0014", "a914", 1) - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Nil(t, event) // append 1 byte to script to make it longer than 22 bytes tx.Vout[0].ScriptPubKey.Hex = tx.Vout[0].ScriptPubKey.Hex + "00" - event, err = GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err = observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Nil(t, event) }) @@ -446,7 +447,7 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewMockBTCRPCClient() - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Nil(t, event) }) @@ -457,7 +458,7 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewMockBTCRPCClient() - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Nil(t, event) }) @@ -468,7 +469,7 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewMockBTCRPCClient() - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Nil(t, event) }) @@ -479,7 +480,7 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewMockBTCRPCClient() - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.NoError(t, err) require.Nil(t, event) }) @@ -502,7 +503,7 @@ func TestGetBtcEventErrors(t *testing.T) { // get BTC event rpcClient := mocks.NewMockBTCRPCClient() - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.Error(t, err) require.Nil(t, event) }) @@ -513,7 +514,7 @@ func TestGetBtcEventErrors(t *testing.T) { // get BTC event rpcClient := mocks.NewMockBTCRPCClient() - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.Error(t, err) require.Nil(t, event) }) @@ -523,7 +524,7 @@ func TestGetBtcEventErrors(t *testing.T) { rpcClient := mocks.NewMockBTCRPCClient() // get BTC event - event, err := GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) require.Error(t, err) require.Nil(t, event) }) diff --git a/zetaclient/chains/bitcoin/observer/observer.go b/zetaclient/chains/bitcoin/observer/observer.go index 6b93ba12cd..5d6e308dfe 100644 --- a/zetaclient/chains/bitcoin/observer/observer.go +++ b/zetaclient/chains/bitcoin/observer/observer.go @@ -6,24 +6,16 @@ import ( "fmt" "math" "math/big" - "os" "sort" - "sync" - "sync/atomic" "time" "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" - lru "github.com/hashicorp/golang-lru" "github.com/pkg/errors" "github.com/rs/zerolog" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/logger" "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/proofs" @@ -31,47 +23,34 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/chains/base" "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin" "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" - "github.com/zeta-chain/zetacore/zetaclient/config" "github.com/zeta-chain/zetacore/zetaclient/context" "github.com/zeta-chain/zetacore/zetaclient/metrics" clienttypes "github.com/zeta-chain/zetacore/zetaclient/types" - "github.com/zeta-chain/zetacore/zetaclient/zetacore" ) const ( // btcBlocksPerDay represents Bitcoin blocks per days for LRU block cache size btcBlocksPerDay = 144 - // bigValueSats contains the threshold to determine a big value in Bitcoin represents 2 BTC - bigValueSats = 200000000 + // RegnetStartBlock is the hardcoded start block for regnet + RegnetStartBlock = 100 - // bigValueConfirmationCount represents the number of confirmation necessary for bigger values: 6 confirmations - bigValueConfirmationCount = 6 + // BigValueSats contains the threshold to determine a big value in Bitcoin represents 2 BTC + BigValueSats = 200000000 + + // BigValueConfirmationCount represents the number of confirmation necessary for bigger values: 6 confirmations + BigValueConfirmationCount = 6 ) var _ interfaces.ChainObserver = &Observer{} // Logger contains list of loggers used by Bitcoin chain observer -// TODO: Merge this logger with the one in evm -// https://github.com/zeta-chain/node/issues/2022 type Logger struct { - // Chain is the parent logger for the chain - Chain zerolog.Logger - - // Inbound is the logger for incoming transactions - Inbound zerolog.Logger // The logger for incoming transactions - - // Outbound is the logger for outgoing transactions - Outbound zerolog.Logger // The logger for outgoing transactions + // base.Logger contains a list of base observer loggers + base.ObserverLogger // UTXOs is the logger for UTXOs management - UTXOs zerolog.Logger // The logger for UTXOs management - - // GasPrice is the logger for gas price - GasPrice zerolog.Logger // The logger for gas price - - // Compliance is the logger for compliance checks - Compliance zerolog.Logger // The logger for compliance checks + UTXOs zerolog.Logger } // BTCInboundEvent represents an incoming transaction event @@ -98,23 +77,20 @@ type BTCBlockNHeader struct { // Observer is the Bitcoin chain observer type Observer struct { - BlockCache *lru.Cache + // base.Observer implements the base chain observer + base.Observer + + // netParams contains the Bitcoin network parameters + netParams *chaincfg.Params - // Mu is lock for all the maps, utxos and core params - Mu *sync.Mutex + // btcClient is the Bitcoin RPC client that interacts with the Bitcoin node + btcClient interfaces.BTCRPCClient - Tss interfaces.TSSSigner + // pendingNonce is the outbound artificial pending nonce + pendingNonce uint64 - chain chains.Chain - netParams *chaincfg.Params - rpcClient interfaces.BTCRPCClient - zetacoreClient interfaces.ZetacoreClient - lastBlock int64 - lastBlockScanned int64 - pendingNonce uint64 - utxos []btcjson.ListUnspentResult - params observertypes.ChainParams - coreContext *context.ZetacoreContext + // utxos contains the UTXOs owned by the TSS address + utxos []btcjson.ListUnspentResult // includedTxHashes indexes included tx with tx hash includedTxHashes map[string]bool @@ -125,157 +101,116 @@ type Observer struct { // broadcastedTx indexes the outbound hash with the outbound tx identifier broadcastedTx map[string]string - db *gorm.DB - stop chan struct{} + // logger contains the loggers used by the bitcoin observer logger Logger - ts *metrics.TelemetryServer } // NewObserver returns a new Bitcoin chain observer func NewObserver( - appcontext *context.AppContext, chain chains.Chain, + btcClient interfaces.BTCRPCClient, + chainParams observertypes.ChainParams, + zetacoreContext *context.ZetacoreContext, zetacoreClient interfaces.ZetacoreClient, tss interfaces.TSSSigner, dbpath string, logger base.Logger, - btcCfg config.BTCConfig, ts *metrics.TelemetryServer, ) (*Observer, error) { - // initialize the observer - ob := Observer{ - ts: ts, - } - ob.stop = make(chan struct{}) - ob.chain = chain - - // get the bitcoin network params - netParams, err := chains.BitcoinNetParamsFromChainID(ob.chain.ChainId) - if err != nil { - return nil, fmt.Errorf("error getting net params for chain %d: %s", ob.chain.ChainId, err) - } - ob.netParams = netParams - - ob.Mu = &sync.Mutex{} - - chainLogger := logger.Std.With().Str("chain", chain.ChainName.String()).Logger() - ob.logger = Logger{ - Chain: chainLogger, - Inbound: chainLogger.With().Str("module", "WatchInbound").Logger(), - Outbound: chainLogger.With().Str("module", "WatchOutbound").Logger(), - UTXOs: chainLogger.With().Str("module", "WatchUTXOs").Logger(), - GasPrice: chainLogger.With().Str("module", "WatchGasPrice").Logger(), - Compliance: logger.Compliance, - } - - ob.zetacoreClient = zetacoreClient - ob.Tss = tss - ob.coreContext = appcontext.ZetacoreContext() - ob.includedTxHashes = make(map[string]bool) - ob.includedTxResults = make(map[string]*btcjson.GetTransactionResult) - ob.broadcastedTx = make(map[string]string) - - // set the Bitcoin chain params - _, chainParams, found := appcontext.ZetacoreContext().GetBTCChainParams() - if !found { - return nil, fmt.Errorf("btc chains params not initialized") - } - ob.params = *chainParams - - // create the RPC client - ob.logger.Chain.Info().Msgf("Chain %s endpoint %s", ob.chain.String(), btcCfg.RPCHost) - connCfg := &rpcclient.ConnConfig{ - Host: btcCfg.RPCHost, - User: btcCfg.RPCUsername, - Pass: btcCfg.RPCPassword, - HTTPPostMode: true, - DisableTLS: true, - Params: btcCfg.RPCParams, - } - rpcClient, err := rpcclient.New(connCfg, nil) + // create base observer + baseObserver, err := base.NewObserver( + chain, + chainParams, + zetacoreContext, + zetacoreClient, + tss, + btcBlocksPerDay, + base.DefaultHeaderCacheSize, + ts, + logger, + ) if err != nil { - return nil, fmt.Errorf("error creating rpc client: %s", err) + return nil, err } - // try connection - ob.rpcClient = rpcClient - err = rpcClient.Ping() + // get the bitcoin network params + netParams, err := chains.BitcoinNetParamsFromChainID(chain.ChainId) if err != nil { - return nil, fmt.Errorf("error ping the bitcoin server: %s", err) + return nil, fmt.Errorf("error getting net params for chain %d: %s", chain.ChainId, err) } - ob.BlockCache, err = lru.New(btcBlocksPerDay) - if err != nil { - ob.logger.Chain.Error().Err(err).Msg("failed to create bitcoin block cache") - return nil, err + // create bitcoin observer + ob := &Observer{ + Observer: *baseObserver, + netParams: netParams, + btcClient: btcClient, + pendingNonce: 0, + utxos: []btcjson.ListUnspentResult{}, + includedTxHashes: make(map[string]bool), + includedTxResults: make(map[string]*btcjson.GetTransactionResult), + broadcastedTx: make(map[string]string), + logger: Logger{ + ObserverLogger: *baseObserver.Logger(), + UTXOs: baseObserver.Logger().Chain.With().Str("module", "utxos").Logger(), + }, } // load btc chain observer DB - err = ob.loadDB(dbpath) + err = ob.LoadDB(dbpath) if err != nil { return nil, err } - return &ob, nil -} - -func (ob *Observer) WithZetacoreClient(client *zetacore.Client) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.zetacoreClient = client -} - -func (ob *Observer) WithLogger(logger zerolog.Logger) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.logger = Logger{ - Chain: logger, - Inbound: logger.With().Str("module", "WatchInbound").Logger(), - Outbound: logger.With().Str("module", "WatchOutbound").Logger(), - UTXOs: logger.With().Str("module", "WatchUTXOs").Logger(), - GasPrice: logger.With().Str("module", "WatchGasPrice").Logger(), - } -} - -func (ob *Observer) WithBtcClient(client *rpcclient.Client) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.rpcClient = client + return ob, nil } -func (ob *Observer) WithChain(chain chains.Chain) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.chain = chain +// BtcClient returns the btc client +func (ob *Observer) BtcClient() interfaces.BTCRPCClient { + return ob.btcClient } -func (ob *Observer) Chain() chains.Chain { - ob.Mu.Lock() - defer ob.Mu.Unlock() - return ob.chain +// WithBtcClient attaches a new btc client to the observer +func (ob *Observer) WithBtcClient(client interfaces.BTCRPCClient) { + ob.btcClient = client } +// SetChainParams sets the chain params for the observer +// Note: chain params is accessed concurrently func (ob *Observer) SetChainParams(params observertypes.ChainParams) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.params = params + ob.Mu().Lock() + defer ob.Mu().Unlock() + ob.WithChainParams(params) } +// GetChainParams returns the chain params for the observer +// Note: chain params is accessed concurrently func (ob *Observer) GetChainParams() observertypes.ChainParams { - ob.Mu.Lock() - defer ob.Mu.Unlock() - return ob.params + ob.Mu().Lock() + defer ob.Mu().Unlock() + return ob.ChainParams() } // Start starts the Go routine to observe the Bitcoin chain func (ob *Observer) Start() { - ob.logger.Chain.Info().Msgf("Bitcoin client is starting") - go ob.WatchInbound() // watch bitcoin chain for incoming txs and post votes to zetacore - go ob.WatchOutbound() // watch bitcoin chain for outgoing txs status - go ob.WatchUTXOs() // watch bitcoin chain for UTXOs owned by the TSS address - go ob.WatchGasPrice() // watch bitcoin chain for gas rate and post to zetacore - go ob.WatchInboundTracker() // watch zetacore for bitcoin inbound trackers - go ob.WatchRPCStatus() // watch the RPC status of the bitcoin chain + ob.Logger().Chain.Info().Msgf("observer is starting for chain %d", ob.Chain().ChainId) + + // watch bitcoin chain for incoming txs and post votes to zetacore + go ob.WatchInbound() + + // watch bitcoin chain for outgoing txs status + go ob.WatchOutbound() + + // watch bitcoin chain for UTXOs owned by the TSS address + go ob.WatchUTXOs() + + // watch bitcoin chain for gas rate and post to zetacore + go ob.WatchGasPrice() + + // watch zetacore for bitcoin inbound trackers + go ob.WatchInboundTracker() + + // watch the RPC status of the bitcoin chain + go ob.WatchRPCStatus() } // WatchRPCStatus watches the RPC status of the Bitcoin chain @@ -290,19 +225,19 @@ func (ob *Observer) WatchRPCStatus() { continue } - bn, err := ob.rpcClient.GetBlockCount() + bn, err := ob.btcClient.GetBlockCount() if err != nil { ob.logger.Chain.Error().Err(err).Msg("RPC status check: RPC down? ") continue } - hash, err := ob.rpcClient.GetBlockHash(bn) + hash, err := ob.btcClient.GetBlockHash(bn) if err != nil { ob.logger.Chain.Error().Err(err).Msg("RPC status check: RPC down? ") continue } - header, err := ob.rpcClient.GetBlockHeader(hash) + header, err := ob.btcClient.GetBlockHeader(hash) if err != nil { ob.logger.Chain.Error().Err(err).Msg("RPC status check: RPC down? ") continue @@ -315,8 +250,8 @@ func (ob *Observer) WatchRPCStatus() { continue } - tssAddr := ob.Tss.BTCAddressWitnessPubkeyHash() - res, err := ob.rpcClient.ListUnspentMinMaxAddresses(0, 1000000, []btcutil.Address{tssAddr}) + tssAddr := ob.TSS().BTCAddressWitnessPubkeyHash() + res, err := ob.btcClient.ListUnspentMinMaxAddresses(0, 1000000, []btcutil.Address{tssAddr}) if err != nil { ob.logger.Chain.Error(). Err(err). @@ -334,56 +269,27 @@ func (ob *Observer) WatchRPCStatus() { ob.logger.Chain.Info(). Msgf("[OK] RPC status check: latest block number %d, timestamp %s (%.fs ago), tss addr %s, #utxos: %d", bn, blockTime, elapsedSeconds, tssAddr, len(res)) - case <-ob.stop: + case <-ob.StopChannel(): return } } } -func (ob *Observer) Stop() { - ob.logger.Chain.Info().Msgf("ob %s is stopping", ob.chain.String()) - close(ob.stop) // this notifies all goroutines to stop - ob.logger.Chain.Info().Msgf("%s observer stopped", ob.chain.String()) -} - -func (ob *Observer) SetLastBlockHeight(height int64) { - atomic.StoreInt64(&ob.lastBlock, height) -} - -func (ob *Observer) GetLastBlockHeight() int64 { - return atomic.LoadInt64(&ob.lastBlock) -} - -func (ob *Observer) SetLastBlockHeightScanned(height int64) { - atomic.StoreInt64(&ob.lastBlockScanned, height) - // #nosec G701 checked as positive - ob.ts.SetLastScannedBlockNumber(ob.chain, uint64(height)) -} - -func (ob *Observer) GetLastBlockHeightScanned() int64 { - return atomic.LoadInt64(&ob.lastBlockScanned) -} - +// GetPendingNonce returns the artificial pending nonce +// Note: pending nonce is accessed concurrently func (ob *Observer) GetPendingNonce() uint64 { - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() return ob.pendingNonce } -// GetBaseGasPrice ... -// TODO: implement -// https://github.com/zeta-chain/node/issues/868 -func (ob *Observer) GetBaseGasPrice() *big.Int { - return big.NewInt(0) -} - // ConfirmationsThreshold returns number of required Bitcoin confirmations depending on sent BTC amount. func (ob *Observer) ConfirmationsThreshold(amount *big.Int) int64 { - if amount.Cmp(big.NewInt(bigValueSats)) >= 0 { - return bigValueConfirmationCount + if amount.Cmp(big.NewInt(BigValueSats)) >= 0 { + return BigValueConfirmationCount } - if bigValueConfirmationCount < ob.GetChainParams().ConfirmationCount { - return bigValueConfirmationCount + if BigValueConfirmationCount < ob.GetChainParams().ConfirmationCount { + return BigValueConfirmationCount } // #nosec G701 always in range @@ -395,7 +301,7 @@ func (ob *Observer) WatchGasPrice() { // report gas price right away as the ticker takes time to kick in err := ob.PostGasPrice() if err != nil { - ob.logger.GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.chain.ChainId) + ob.logger.GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.Chain().ChainId) } // start gas price ticker @@ -405,7 +311,7 @@ func (ob *Observer) WatchGasPrice() { return } ob.logger.GasPrice.Info().Msgf("WatchGasPrice started for chain %d with interval %d", - ob.chain.ChainId, ob.GetChainParams().GasPriceTicker) + ob.Chain().ChainId, ob.GetChainParams().GasPriceTicker) defer ticker.Stop() for { @@ -416,25 +322,27 @@ func (ob *Observer) WatchGasPrice() { } err := ob.PostGasPrice() if err != nil { - ob.logger.GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.chain.ChainId) + ob.logger.GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.Chain().ChainId) } ticker.UpdateInterval(ob.GetChainParams().GasPriceTicker, ob.logger.GasPrice) - case <-ob.stop: - ob.logger.GasPrice.Info().Msgf("WatchGasPrice stopped for chain %d", ob.chain.ChainId) + case <-ob.StopChannel(): + ob.logger.GasPrice.Info().Msgf("WatchGasPrice stopped for chain %d", ob.Chain().ChainId) return } } } +// PostGasPrice posts gas price to zetacore func (ob *Observer) PostGasPrice() error { - if ob.chain.ChainId == 18444 { //bitcoin regtest; hardcode here since this RPC is not available on regtest - blockNumber, err := ob.rpcClient.GetBlockCount() + // hardcode gas price here since this RPC is not available on regtest + if chains.IsBitcoinRegnet(ob.Chain().ChainId) { + blockNumber, err := ob.btcClient.GetBlockCount() if err != nil { return err } // #nosec G701 always in range - _, err = ob.zetacoreClient.PostGasPrice(ob.chain, 1, "100", uint64(blockNumber)) + _, err = ob.ZetacoreClient().PostGasPrice(ob.Chain(), 1, "100", uint64(blockNumber)) if err != nil { ob.logger.GasPrice.Err(err).Msg("PostGasPrice:") return err @@ -443,7 +351,7 @@ func (ob *Observer) PostGasPrice() error { } // EstimateSmartFee returns the fees per kilobyte (BTC/kb) targeting given block confirmation - feeResult, err := ob.rpcClient.EstimateSmartFee(1, &btcjson.EstimateModeEconomical) + feeResult, err := ob.btcClient.EstimateSmartFee(1, &btcjson.EstimateModeEconomical) if err != nil { return err } @@ -455,13 +363,13 @@ func (ob *Observer) PostGasPrice() error { } feeRatePerByte := bitcoin.FeeRateToSatPerByte(*feeResult.FeeRate) - blockNumber, err := ob.rpcClient.GetBlockCount() + blockNumber, err := ob.btcClient.GetBlockCount() if err != nil { return err } // #nosec G701 always positive - _, err = ob.zetacoreClient.PostGasPrice(ob.chain, feeRatePerByte.Uint64(), "100", uint64(blockNumber)) + _, err = ob.ZetacoreClient().PostGasPrice(ob.Chain(), feeRatePerByte.Uint64(), "100", uint64(blockNumber)) if err != nil { ob.logger.GasPrice.Err(err).Msg("PostGasPrice:") return err @@ -532,13 +440,14 @@ func (ob *Observer) WatchUTXOs() { ob.logger.UTXOs.Error().Err(err).Msg("error fetching btc utxos") } ticker.UpdateInterval(ob.GetChainParams().WatchUtxoTicker, ob.logger.UTXOs) - case <-ob.stop: - ob.logger.UTXOs.Info().Msgf("WatchUTXOs stopped for chain %d", ob.chain.ChainId) + case <-ob.StopChannel(): + ob.logger.UTXOs.Info().Msgf("WatchUTXOs stopped for chain %d", ob.Chain().ChainId) return } } } +// FetchUTXOs fetches TSS-owned UTXOs from the Bitcoin node func (ob *Observer) FetchUTXOs() error { defer func() { if err := recover(); err != nil { @@ -550,19 +459,19 @@ func (ob *Observer) FetchUTXOs() error { ob.refreshPendingNonce() // get the current block height. - bh, err := ob.rpcClient.GetBlockCount() + bh, err := ob.btcClient.GetBlockCount() if err != nil { return fmt.Errorf("btc: error getting block height : %v", err) } maxConfirmations := int(bh) // List all unspent UTXOs (160ms) - tssAddr := ob.Tss.BTCAddress() - address, err := chains.DecodeBtcAddress(tssAddr, ob.chain.ChainId) + tssAddr := ob.TSS().BTCAddress() + address, err := chains.DecodeBtcAddress(tssAddr, ob.Chain().ChainId) if err != nil { return fmt.Errorf("btc: error decoding wallet address (%s) : %s", tssAddr, err.Error()) } - utxos, err := ob.rpcClient.ListUnspentMinMaxAddresses(0, maxConfirmations, []btcutil.Address{address}) + utxos, err := ob.btcClient.ListUnspentMinMaxAddresses(0, maxConfirmations, []btcutil.Address{address}) if err != nil { return err } @@ -594,22 +503,22 @@ func (ob *Observer) FetchUTXOs() error { utxosFiltered = append(utxosFiltered, utxo) } - ob.Mu.Lock() - ob.ts.SetNumberOfUTXOs(len(utxosFiltered)) + ob.Mu().Lock() + ob.TelemetryServer().SetNumberOfUTXOs(len(utxosFiltered)) ob.utxos = utxosFiltered - ob.Mu.Unlock() + ob.Mu().Unlock() return nil } // SaveBroadcastedTx saves successfully broadcasted transaction func (ob *Observer) SaveBroadcastedTx(txHash string, nonce uint64) { outboundID := ob.GetTxID(nonce) - ob.Mu.Lock() + ob.Mu().Lock() ob.broadcastedTx[outboundID] = txHash - ob.Mu.Unlock() + ob.Mu().Unlock() broadcastEntry := clienttypes.ToOutboundHashSQLType(txHash, outboundID) - if err := ob.db.Save(&broadcastEntry).Error; err != nil { + if err := ob.DB().Save(&broadcastEntry).Error; err != nil { ob.logger.Outbound.Error(). Err(err). Msgf("SaveBroadcastedTx: error saving broadcasted txHash %s for outbound %s", txHash, outboundID) @@ -617,150 +526,111 @@ func (ob *Observer) SaveBroadcastedTx(txHash string, nonce uint64) { ob.logger.Outbound.Info().Msgf("SaveBroadcastedTx: saved broadcasted txHash %s for outbound %s", txHash, outboundID) } -// GetTxResultByHash gets the transaction result by hash -func GetTxResultByHash( - rpcClient interfaces.BTCRPCClient, - txID string, -) (*chainhash.Hash, *btcjson.GetTransactionResult, error) { - hash, err := chainhash.NewHashFromStr(txID) - if err != nil { - return nil, nil, errors.Wrapf(err, "GetTxResultByHash: error NewHashFromStr: %s", txID) +// GetBlockByNumberCached gets cached block (and header) by block number +func (ob *Observer) GetBlockByNumberCached(blockNumber int64) (*BTCBlockNHeader, error) { + if result, ok := ob.BlockCache().Get(blockNumber); ok { + if block, ok := result.(*BTCBlockNHeader); ok { + return block, nil + } + return nil, errors.New("cached value is not of type *BTCBlockNHeader") } - // The Bitcoin node has to be configured to watch TSS address - txResult, err := rpcClient.GetTransaction(hash) + // Get the block hash + hash, err := ob.btcClient.GetBlockHash(blockNumber) if err != nil { - return nil, nil, errors.Wrapf(err, "GetTxResultByHash: error GetTransaction %s", hash.String()) + return nil, err } - return hash, txResult, nil -} - -// GetBlockHeightByHash gets the block height by block hash -func GetBlockHeightByHash( - rpcClient interfaces.BTCRPCClient, - hash string, -) (int64, error) { - // decode the block hash - var blockHash chainhash.Hash - err := chainhash.Decode(&blockHash, hash) + // Get the block header + header, err := ob.btcClient.GetBlockHeader(hash) if err != nil { - return 0, errors.Wrapf(err, "GetBlockHeightByHash: error decoding block hash %s", hash) + return nil, err } - - // get block by hash - block, err := rpcClient.GetBlockVerbose(&blockHash) + // Get the block with verbose transactions + block, err := ob.btcClient.GetBlockVerboseTx(hash) if err != nil { - return 0, errors.Wrapf(err, "GetBlockHeightByHash: error GetBlockVerbose %s", hash) + return nil, err + } + blockNheader := &BTCBlockNHeader{ + Header: header, + Block: block, } - return block.Height, nil + ob.BlockCache().Add(blockNumber, blockNheader) + ob.BlockCache().Add(hash, blockNheader) + return blockNheader, nil } -// GetRawTxResult gets the raw tx result -func GetRawTxResult( - rpcClient interfaces.BTCRPCClient, - hash *chainhash.Hash, - res *btcjson.GetTransactionResult, -) (btcjson.TxRawResult, error) { - if res.Confirmations == 0 { // for pending tx, we query the raw tx directly - rawResult, err := rpcClient.GetRawTransactionVerbose(hash) // for pending tx, we query the raw tx - if err != nil { - return btcjson.TxRawResult{}, errors.Wrapf( - err, - "getRawTxResult: error GetRawTransactionVerbose %s", - res.TxID, - ) - } - return *rawResult, nil - } else if res.Confirmations > 0 { // for confirmed tx, we query the block - blkHash, err := chainhash.NewHashFromStr(res.BlockHash) - if err != nil { - return btcjson.TxRawResult{}, errors.Wrapf(err, "getRawTxResult: error NewHashFromStr for block hash %s", res.BlockHash) - } - block, err := rpcClient.GetBlockVerboseTx(blkHash) - if err != nil { - return btcjson.TxRawResult{}, errors.Wrapf(err, "getRawTxResult: error GetBlockVerboseTx %s", res.BlockHash) - } - if res.BlockIndex < 0 || res.BlockIndex >= int64(len(block.Tx)) { - return btcjson.TxRawResult{}, errors.Wrapf(err, "getRawTxResult: invalid outbound with invalid block index, TxID %s, BlockIndex %d", res.TxID, res.BlockIndex) - } - return block.Tx[res.BlockIndex], nil +// LoadDB open sql database and load data into Bitcoin observer +func (ob *Observer) LoadDB(dbPath string) error { + if dbPath == "" { + return errors.New("empty db path") } - // res.Confirmations < 0 (meaning not included) - return btcjson.TxRawResult{}, fmt.Errorf("getRawTxResult: tx %s not included yet", hash) -} - -func (ob *Observer) BuildBroadcastedTxMap() error { - var broadcastedTransactions []clienttypes.OutboundHashSQLType - if err := ob.db.Find(&broadcastedTransactions).Error; err != nil { - ob.logger.Chain.Error().Err(err).Msg("error iterating over db") - return err + // open database, the custom dbName is used here for backward compatibility + err := ob.OpenDB(dbPath, "btc_chain_client") + if err != nil { + return errors.Wrapf(err, "error OpenDB for chain %d", ob.Chain().ChainId) } - for _, entry := range broadcastedTransactions { - ob.broadcastedTx[entry.Key] = entry.Hash + + // run auto migration + // transaction result table is used nowhere but we still run migration in case they are needed in future + err = ob.DB().AutoMigrate( + &clienttypes.TransactionResultSQLType{}, + &clienttypes.OutboundHashSQLType{}, + ) + if err != nil { + return errors.Wrapf(err, "error AutoMigrate for chain %d", ob.Chain().ChainId) } - return nil -} -// LoadLastScannedBlock loads last scanned block from database -// The last scanned block is the height from which the observer should continue scanning for inbound transactions -func (ob *Observer) LoadLastScannedBlock() error { - // Get the latest block number from node - bn, err := ob.rpcClient.GetBlockCount() + // load last scanned block + err = ob.LoadLastBlockScanned() if err != nil { return err } - if bn < 0 { - return fmt.Errorf("LoadLastScannedBlock: negative block number %d", bn) + + // load broadcasted transactions + err = ob.LoadBroadcastedTxMap() + return err +} + +// LoadLastBlockScanned loads the last scanned block from the database +func (ob *Observer) LoadLastBlockScanned() error { + err := ob.Observer.LoadLastBlockScanned(ob.Logger().Chain) + if err != nil { + return errors.Wrapf(err, "error LoadLastBlockScanned for chain %d", ob.Chain().ChainId) } - //Load persisted block number - var lastBlockNum clienttypes.LastBlockSQLType - if err := ob.db.First(&lastBlockNum, clienttypes.LastBlockNumID).Error; err != nil { - ob.logger.Chain.Info().Msg("LoadLastScannedBlock: last scanned block not found in DB, scan from latest") - ob.SetLastBlockHeightScanned(bn) - } else { - // #nosec G701 always in range - lastBN := int64(lastBlockNum.Num) - ob.SetLastBlockHeightScanned(lastBN) + // observer will scan from the last block when 'lastBlockScanned == 0', this happens when: + // 1. environment variable is set explicitly to "latest" + // 2. environment variable is empty and last scanned block is not found in DB + if ob.LastBlockScanned() == 0 { + blockNumber, err := ob.btcClient.GetBlockCount() + if err != nil { + return errors.Wrapf(err, "error GetBlockCount for chain %d", ob.Chain().ChainId) + } + // #nosec G701 always positive + ob.WithLastBlockScanned(uint64(blockNumber)) } - // bitcoin regtest starts from block 100 - if chains.IsBitcoinRegnet(ob.chain.ChainId) { - ob.SetLastBlockHeightScanned(100) + // bitcoin regtest starts from hardcoded block 100 + if chains.IsBitcoinRegnet(ob.Chain().ChainId) { + ob.WithLastBlockScanned(RegnetStartBlock) } - ob.logger.Chain.Info(). - Msgf("LoadLastScannedBlock: chain %d starts scanning from block %d", ob.chain.ChainId, ob.GetLastBlockHeightScanned()) + ob.Logger().Chain.Info().Msgf("chain %d starts scanning from block %d", ob.Chain().ChainId, ob.LastBlockScanned()) return nil } -func (ob *Observer) GetBlockByNumberCached(blockNumber int64) (*BTCBlockNHeader, error) { - if result, ok := ob.BlockCache.Get(blockNumber); ok { - return result.(*BTCBlockNHeader), nil - } - // Get the block hash - hash, err := ob.rpcClient.GetBlockHash(blockNumber) - if err != nil { - return nil, err - } - // Get the block header - header, err := ob.rpcClient.GetBlockHeader(hash) - if err != nil { - return nil, err - } - // Get the block with verbose transactions - block, err := ob.rpcClient.GetBlockVerboseTx(hash) - if err != nil { - return nil, err +// LoadBroadcastedTxMap loads broadcasted transactions from the database +func (ob *Observer) LoadBroadcastedTxMap() error { + var broadcastedTransactions []clienttypes.OutboundHashSQLType + if err := ob.DB().Find(&broadcastedTransactions).Error; err != nil { + ob.logger.Chain.Error().Err(err).Msgf("error iterating over db for chain %d", ob.Chain().ChainId) + return err } - blockNheader := &BTCBlockNHeader{ - Header: header, - Block: block, + for _, entry := range broadcastedTransactions { + ob.broadcastedTx[entry.Key] = entry.Hash } - ob.BlockCache.Add(blockNumber, blockNheader) - ob.BlockCache.Add(hash, blockNheader) - return blockNheader, nil + return nil } // isTssTransaction checks if a given transaction was sent by TSS itself. @@ -774,7 +644,7 @@ func (ob *Observer) isTssTransaction(txid string) bool { func (ob *Observer) postBlockHeader(tip int64) error { ob.logger.Inbound.Info().Msgf("postBlockHeader: tip %d", tip) bn := tip - res, err := ob.zetacoreClient.GetBlockHeaderChainState(ob.chain.ChainId) + res, err := ob.ZetacoreClient().GetBlockHeaderChainState(ob.Chain().ChainId) if err == nil && res.ChainState != nil && res.ChainState.EarliestHeight > 0 { bn = res.ChainState.LatestHeight + 1 } @@ -793,8 +663,8 @@ func (ob *Observer) postBlockHeader(tip int64) error { return err } blockHash := res2.Header.BlockHash() - _, err = ob.zetacoreClient.PostVoteBlockHeader( - ob.chain.ChainId, + _, err = ob.ZetacoreClient().PostVoteBlockHeader( + ob.Chain().ChainId, blockHash[:], res2.Block.Height, proofs.NewBitcoinHeader(headerBuf.Bytes()), @@ -805,37 +675,3 @@ func (ob *Observer) postBlockHeader(tip int64) error { } return err } - -func (ob *Observer) loadDB(dbpath string) error { - if _, err := os.Stat(dbpath); os.IsNotExist(err) { - err := os.MkdirAll(dbpath, os.ModePerm) - if err != nil { - return err - } - } - path := fmt.Sprintf("%s/btc_chain_client", dbpath) - db, err := gorm.Open(sqlite.Open(path), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)}) - if err != nil { - ob.logger.Chain.Error().Err(err).Msgf("failed to open observer database for %s", ob.chain.ChainName.String()) - return err - } - ob.db = db - - err = db.AutoMigrate(&clienttypes.TransactionResultSQLType{}, - &clienttypes.OutboundHashSQLType{}, - &clienttypes.LastBlockSQLType{}) - if err != nil { - return err - } - - // Load last scanned block - err = ob.LoadLastScannedBlock() - if err != nil { - return err - } - - //Load broadcasted transactions - err = ob.BuildBroadcastedTxMap() - - return err -} diff --git a/zetaclient/chains/bitcoin/observer/observer_test.go b/zetaclient/chains/bitcoin/observer/observer_test.go index 2d2494dd16..c79209e3fc 100644 --- a/zetaclient/chains/bitcoin/observer/observer_test.go +++ b/zetaclient/chains/bitcoin/observer/observer_test.go @@ -1,13 +1,17 @@ -package observer +package observer_test import ( + "fmt" "math/big" + "os" "strconv" - "sync" "testing" "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/wire" + lru "github.com/hashicorp/golang-lru" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/zetaclient/testutils" "gorm.io/driver/sqlite" "gorm.io/gorm" @@ -15,18 +19,14 @@ import ( "github.com/zeta-chain/zetacore/testutil/sample" observertypes "github.com/zeta-chain/zetacore/x/observer/types" "github.com/zeta-chain/zetacore/zetaclient/chains/base" - "github.com/zeta-chain/zetacore/zetaclient/config" + "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/observer" + "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" "github.com/zeta-chain/zetacore/zetaclient/context" "github.com/zeta-chain/zetacore/zetaclient/metrics" "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" clienttypes "github.com/zeta-chain/zetacore/zetaclient/types" ) -const ( - // tempSQLiteDbPath is the temporary SQLite database used for testing - tempSQLiteDbPath = "file::memory:?cache=shared" -) - var ( // the relative path to the testdata directory TestDataDir = "../../../" @@ -36,7 +36,7 @@ var ( func setupDBTxResults(t *testing.T) (*gorm.DB, map[string]btcjson.GetTransactionResult) { submittedTx := map[string]btcjson.GetTransactionResult{} - db, err := gorm.Open(sqlite.Open(tempSQLiteDbPath), &gorm.Config{}) + db, err := gorm.Open(sqlite.Open(testutils.SQLiteMemory), &gorm.Config{}) require.NoError(t, err) err = db.AutoMigrate(&clienttypes.TransactionResultSQLType{}) @@ -67,26 +67,286 @@ func setupDBTxResults(t *testing.T) (*gorm.DB, map[string]btcjson.GetTransaction return db, submittedTx } -func TestNewBitcoinObserver(t *testing.T) { - t.Run("should return error because zetacore doesn't update zetacore context", func(t *testing.T) { - cfg := config.NewConfig() - coreContext := context.NewZetacoreContext(cfg) - appContext := context.NewAppContext(coreContext, cfg) - chain := chains.BitcoinMainnet - zetacoreClient := mocks.NewMockZetacoreClient() - tss := mocks.NewMockTSS(chains.BitcoinTestnet, sample.EthAddress().String(), "") - logger := base.Logger{} - btcCfg := cfg.BitcoinConfig - ts := metrics.NewTelemetryServer() - - client, err := NewObserver(appContext, chain, zetacoreClient, tss, tempSQLiteDbPath, logger, btcCfg, ts) - require.ErrorContains(t, err, "btc chains params not initialized") - require.Nil(t, client) +// MockBTCObserver creates a mock Bitcoin observer for testing +func MockBTCObserver( + t *testing.T, + chain chains.Chain, + params observertypes.ChainParams, + btcClient interfaces.BTCRPCClient, + dbpath string, +) *observer.Observer { + // use default mock btc client if not provided + if btcClient == nil { + btcClient = mocks.NewMockBTCRPCClient().WithBlockCount(100) + } + + // use memory db if dbpath is empty + if dbpath == "" { + dbpath = "file::memory:?cache=shared" + } + + // create observer + ob, err := observer.NewObserver( + chain, + btcClient, + params, + nil, + nil, + nil, + dbpath, + base.Logger{}, + nil, + ) + require.NoError(t, err) + + return ob +} + +func Test_NewObserver(t *testing.T) { + // use Bitcoin mainnet chain for testing + chain := chains.BitcoinMainnet + params := mocks.MockChainParams(chain.ChainId, 10) + + // test cases + tests := []struct { + name string + chain chains.Chain + btcClient interfaces.BTCRPCClient + chainParams observertypes.ChainParams + coreContext *context.ZetacoreContext + coreClient interfaces.ZetacoreClient + tss interfaces.TSSSigner + dbpath string + logger base.Logger + ts *metrics.TelemetryServer + fail bool + message string + }{ + { + name: "should be able to create observer", + chain: chain, + btcClient: mocks.NewMockBTCRPCClient().WithBlockCount(100), + chainParams: params, + coreContext: nil, + coreClient: nil, + tss: mocks.NewTSSMainnet(), + dbpath: sample.CreateTempDir(t), + logger: base.Logger{}, + ts: nil, + fail: false, + }, + { + name: "should fail if net params is not found", + chain: chains.Chain{ChainId: 111}, // invalid chain id + btcClient: mocks.NewMockBTCRPCClient().WithBlockCount(100), + chainParams: params, + coreContext: nil, + coreClient: nil, + tss: mocks.NewTSSMainnet(), + dbpath: sample.CreateTempDir(t), + logger: base.Logger{}, + ts: nil, + fail: true, + message: "error getting net params", + }, + { + name: "should fail on invalid dbpath", + chain: chain, + chainParams: params, + coreContext: nil, + coreClient: nil, + btcClient: mocks.NewMockBTCRPCClient().WithBlockCount(100), + tss: mocks.NewTSSMainnet(), + dbpath: "/invalid/dbpath", // invalid dbpath + logger: base.Logger{}, + ts: nil, + fail: true, + message: "error creating db path", + }, + } + + // run tests + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // create observer + ob, err := observer.NewObserver( + tt.chain, + tt.btcClient, + tt.chainParams, + tt.coreContext, + tt.coreClient, + tt.tss, + tt.dbpath, + tt.logger, + tt.ts, + ) + + // check result + if tt.fail { + require.ErrorContains(t, err, tt.message) + require.Nil(t, ob) + } else { + require.NoError(t, err) + require.NotNil(t, ob) + } + }) + } +} + +func Test_BlockCache(t *testing.T) { + t.Run("should add and get block from cache", func(t *testing.T) { + // create observer + ob := &observer.Observer{} + blockCache, err := lru.New(100) + require.NoError(t, err) + ob.WithBlockCache(blockCache) + + // create mock btc client + btcClient := mocks.NewMockBTCRPCClient() + ob.WithBtcClient(btcClient) + + // feed block hash, header and block to btc client + hash := sample.BtcHash() + header := &wire.BlockHeader{Version: 1} + block := &btcjson.GetBlockVerboseTxResult{Version: 1} + btcClient.WithBlockHash(&hash) + btcClient.WithBlockHeader(header) + btcClient.WithBlockVerboseTx(block) + + // get block and header from observer, fallback to btc client + result, err := ob.GetBlockByNumberCached(100) + require.NoError(t, err) + require.EqualValues(t, header, result.Header) + require.EqualValues(t, block, result.Block) + + // get block header from cache + result, err = ob.GetBlockByNumberCached(100) + require.NoError(t, err) + require.EqualValues(t, header, result.Header) + require.EqualValues(t, block, result.Block) + }) + t.Run("should fail if stored type is not BlockNHeader", func(t *testing.T) { + // create observer + ob := &observer.Observer{} + blockCache, err := lru.New(100) + require.NoError(t, err) + ob.WithBlockCache(blockCache) + + // add a string to cache + blockNumber := int64(100) + blockCache.Add(blockNumber, "a string value") + + // get result from cache + result, err := ob.GetBlockByNumberCached(blockNumber) + require.ErrorContains(t, err, "cached value is not of type *BTCBlockNHeader") + require.Nil(t, result) + }) +} + +func Test_LoadDB(t *testing.T) { + // use Bitcoin mainnet chain for testing + chain := chains.BitcoinMainnet + params := mocks.MockChainParams(chain.ChainId, 10) + + // create mock btc client, tss and test dbpath + btcClient := mocks.NewMockBTCRPCClient().WithBlockCount(100) + tss := mocks.NewTSSMainnet() + + // create observer + dbpath := sample.CreateTempDir(t) + ob, err := observer.NewObserver(chain, btcClient, params, nil, nil, tss, dbpath, base.Logger{}, nil) + require.NoError(t, err) + + t.Run("should load db successfully", func(t *testing.T) { + err := ob.LoadDB(dbpath) + require.NoError(t, err) + require.EqualValues(t, 100, ob.LastBlockScanned()) + }) + t.Run("should fail on invalid dbpath", func(t *testing.T) { + // load db with empty dbpath + err := ob.LoadDB("") + require.ErrorContains(t, err, "empty db path") + + // load db with invalid dbpath + err = ob.LoadDB("/invalid/dbpath") + require.ErrorContains(t, err, "error OpenDB") + }) + t.Run("should fail on invalid env var", func(t *testing.T) { + // set invalid environment variable + envvar := base.EnvVarLatestBlockByChain(chain) + os.Setenv(envvar, "invalid") + defer os.Unsetenv(envvar) + + // load db + err := ob.LoadDB(dbpath) + require.ErrorContains(t, err, "error LoadLastBlockScanned") + }) +} + +func Test_LoadLastBlockScanned(t *testing.T) { + // use Bitcoin mainnet chain for testing + chain := chains.BitcoinMainnet + params := mocks.MockChainParams(chain.ChainId, 10) + + // create observer using mock btc client + btcClient := mocks.NewMockBTCRPCClient().WithBlockCount(200) + dbpath := sample.CreateTempDir(t) + + t.Run("should load last block scanned", func(t *testing.T) { + // create observer and write 199 as last block scanned + ob := MockBTCObserver(t, chain, params, btcClient, dbpath) + ob.WriteLastBlockScannedToDB(199) + + // load last block scanned + err := ob.LoadLastBlockScanned() + require.NoError(t, err) + require.EqualValues(t, 199, ob.LastBlockScanned()) + }) + t.Run("should fail on invalid env var", func(t *testing.T) { + // create observer + ob := MockBTCObserver(t, chain, params, btcClient, dbpath) + + // set invalid environment variable + envvar := base.EnvVarLatestBlockByChain(chain) + os.Setenv(envvar, "invalid") + defer os.Unsetenv(envvar) + + // load last block scanned + err := ob.LoadLastBlockScanned() + require.ErrorContains(t, err, "error LoadLastBlockScanned") + }) + t.Run("should fail on RPC error", func(t *testing.T) { + // create observer on separate path, as we need to reset last block scanned + otherPath := sample.CreateTempDir(t) + obOther := MockBTCObserver(t, chain, params, btcClient, otherPath) + + // reset last block scanned to 0 so that it will be loaded from RPC + obOther.WithLastBlockScanned(0) + + // set RPC error + btcClient.WithError(fmt.Errorf("error RPC")) + + // load last block scanned + err := obOther.LoadLastBlockScanned() + require.ErrorContains(t, err, "error RPC") + }) + t.Run("should use hardcode block 100 for regtest", func(t *testing.T) { + // use regtest chain + regtest := chains.BitcoinRegtest + obRegnet := MockBTCObserver(t, regtest, params, btcClient, dbpath) + + // load last block scanned + err := obRegnet.LoadLastBlockScanned() + require.NoError(t, err) + require.EqualValues(t, observer.RegnetStartBlock, obRegnet.LastBlockScanned()) }) } func TestConfirmationThreshold(t *testing.T) { - ob := &Observer{Mu: &sync.Mutex{}} + chain := chains.BitcoinMainnet + params := mocks.MockChainParams(chain.ChainId, 10) + ob := MockBTCObserver(t, chain, params, nil, "") + t.Run("should return confirmations in chain param", func(t *testing.T) { ob.SetChainParams(observertypes.ChainParams{ConfirmationCount: 3}) require.Equal(t, int64(3), ob.ConfirmationsThreshold(big.NewInt(1000))) @@ -94,12 +354,16 @@ func TestConfirmationThreshold(t *testing.T) { t.Run("should return big value confirmations", func(t *testing.T) { ob.SetChainParams(observertypes.ChainParams{ConfirmationCount: 3}) - require.Equal(t, int64(bigValueConfirmationCount), ob.ConfirmationsThreshold(big.NewInt(bigValueSats))) + require.Equal( + t, + int64(observer.BigValueConfirmationCount), + ob.ConfirmationsThreshold(big.NewInt(observer.BigValueSats)), + ) }) t.Run("big value confirmations is the upper cap", func(t *testing.T) { - ob.SetChainParams(observertypes.ChainParams{ConfirmationCount: bigValueConfirmationCount + 1}) - require.Equal(t, int64(bigValueConfirmationCount), ob.ConfirmationsThreshold(big.NewInt(1000))) + ob.SetChainParams(observertypes.ChainParams{ConfirmationCount: observer.BigValueConfirmationCount + 1}) + require.Equal(t, int64(observer.BigValueConfirmationCount), ob.ConfirmationsThreshold(big.NewInt(1000))) }) } diff --git a/zetaclient/chains/bitcoin/observer/outbound.go b/zetaclient/chains/bitcoin/observer/outbound.go index 47d026c11a..5bf20c8e7d 100644 --- a/zetaclient/chains/bitcoin/observer/outbound.go +++ b/zetaclient/chains/bitcoin/observer/outbound.go @@ -13,6 +13,7 @@ import ( "github.com/zeta-chain/zetacore/pkg/coin" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin" + "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/rpc" "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" "github.com/zeta-chain/zetacore/zetaclient/compliance" "github.com/zeta-chain/zetacore/zetaclient/context" @@ -21,8 +22,8 @@ import ( // GetTxID returns a unique id for outbound tx func (ob *Observer) GetTxID(nonce uint64) string { - tssAddr := ob.Tss.BTCAddress() - return fmt.Sprintf("%d-%s-%d", ob.chain.ChainId, tssAddr, nonce) + tssAddr := ob.TSS().BTCAddress() + return fmt.Sprintf("%d-%s-%d", ob.Chain().ChainId, tssAddr, nonce) } // WatchOutbound watches Bitcoin chain for outgoing txs status @@ -34,32 +35,33 @@ func (ob *Observer) WatchOutbound() { } defer ticker.Stop() - ob.logger.Outbound.Info().Msgf("WatchInbound started for chain %d", ob.chain.ChainId) + chainID := ob.Chain().ChainId + ob.logger.Outbound.Info().Msgf("WatchOutbound started for chain %d", chainID) sampledLogger := ob.logger.Outbound.Sample(&zerolog.BasicSampler{N: 10}) for { select { case <-ticker.C(): - if !context.IsOutboundObservationEnabled(ob.coreContext, ob.GetChainParams()) { + if !context.IsOutboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { sampledLogger.Info(). - Msgf("WatchOutbound: outbound observation is disabled for chain %d", ob.chain.ChainId) + Msgf("WatchOutbound: outbound observation is disabled for chain %d", chainID) continue } - trackers, err := ob.zetacoreClient.GetAllOutboundTrackerByChain(ob.chain.ChainId, interfaces.Ascending) + trackers, err := ob.ZetacoreClient().GetAllOutboundTrackerByChain(chainID, interfaces.Ascending) if err != nil { ob.logger.Outbound.Error(). Err(err). - Msgf("WatchOutbound: error GetAllOutboundTrackerByChain for chain %d", ob.chain.ChainId) + Msgf("WatchOutbound: error GetAllOutboundTrackerByChain for chain %d", chainID) continue } for _, tracker := range trackers { // get original cctx parameters outboundID := ob.GetTxID(tracker.Nonce) - cctx, err := ob.zetacoreClient.GetCctxByNonce(ob.chain.ChainId, tracker.Nonce) + cctx, err := ob.ZetacoreClient().GetCctxByNonce(chainID, tracker.Nonce) if err != nil { ob.logger.Outbound.Info(). Err(err). - Msgf("WatchOutbound: can't find cctx for chain %d nonce %d", ob.chain.ChainId, tracker.Nonce) + Msgf("WatchOutbound: can't find cctx for chain %d nonce %d", chainID, tracker.Nonce) break } @@ -85,10 +87,10 @@ func (ob *Observer) WatchOutbound() { txCount++ txResult = result ob.logger.Outbound.Info(). - Msgf("WatchOutbound: included outbound %s for chain %d nonce %d", txHash.TxHash, ob.chain.ChainId, tracker.Nonce) + Msgf("WatchOutbound: included outbound %s for chain %d nonce %d", txHash.TxHash, chainID, tracker.Nonce) if txCount > 1 { ob.logger.Outbound.Error().Msgf( - "WatchOutbound: checkIncludedTx passed, txCount %d chain %d nonce %d result %v", txCount, ob.chain.ChainId, tracker.Nonce, result) + "WatchOutbound: checkIncludedTx passed, txCount %d chain %d nonce %d result %v", txCount, chainID, tracker.Nonce, result) } } } @@ -97,12 +99,12 @@ func (ob *Observer) WatchOutbound() { ob.setIncludedTx(tracker.Nonce, txResult) } else if txCount > 1 { ob.removeIncludedTx(tracker.Nonce) // we can't tell which txHash is true, so we remove all (if any) to be safe - ob.logger.Outbound.Error().Msgf("WatchOutbound: included multiple (%d) outbound for chain %d nonce %d", txCount, ob.chain.ChainId, tracker.Nonce) + ob.logger.Outbound.Error().Msgf("WatchOutbound: included multiple (%d) outbound for chain %d nonce %d", txCount, chainID, tracker.Nonce) } } ticker.UpdateInterval(ob.GetChainParams().OutboundTicker, ob.logger.Outbound) - case <-ob.stop: - ob.logger.Outbound.Info().Msgf("WatchOutbound stopped for chain %d", ob.chain.ChainId) + case <-ob.StopChannel(): + ob.logger.Outbound.Info().Msgf("WatchOutbound stopped for chain %d", chainID) return } } @@ -118,10 +120,10 @@ func (ob *Observer) IsOutboundProcessed(cctx *crosschaintypes.CrossChainTx, logg outboundID := ob.GetTxID(nonce) logger.Info().Msgf("IsOutboundProcessed %s", outboundID) - ob.Mu.Lock() + ob.Mu().Lock() txnHash, broadcasted := ob.broadcastedTx[outboundID] res, included := ob.includedTxResults[outboundID] - ob.Mu.Unlock() + ob.Mu().Unlock() if !included { if !broadcasted { @@ -162,7 +164,7 @@ func (ob *Observer) IsOutboundProcessed(cctx *crosschaintypes.CrossChainTx, logg } // Get outbound block height - blockHeight, err := GetBlockHeightByHash(ob.rpcClient, res.BlockHash) + blockHeight, err := rpc.GetBlockHeightByHash(ob.btcClient, res.BlockHash) if err != nil { return true, false, errors.Wrapf( err, @@ -172,7 +174,7 @@ func (ob *Observer) IsOutboundProcessed(cctx *crosschaintypes.CrossChainTx, logg } logger.Debug().Msgf("Bitcoin outbound confirmed: txid %s, amount %s\n", res.TxID, amountInSat.String()) - zetaHash, ballot, err := ob.zetacoreClient.PostVoteOutbound( + zetaHash, ballot, err := ob.ZetacoreClient().PostVoteOutbound( sendHash, res.TxID, // #nosec G701 always positive @@ -182,7 +184,7 @@ func (ob *Observer) IsOutboundProcessed(cctx *crosschaintypes.CrossChainTx, logg 0, // gas limit not used with Bitcoin amountInSat, chains.ReceiveStatus_success, - ob.chain, + ob.Chain(), nonce, coin.CoinType_Gas, ) @@ -221,16 +223,16 @@ func (ob *Observer) SelectUTXOs( idx := -1 if nonce == 0 { // for nonce = 0; make exception; no need to include nonce-mark utxo - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() } else { // for nonce > 0; we proceed only when we see the nonce-mark utxo preTxid, err := ob.getOutboundIDByNonce(nonce-1, test) if err != nil { return nil, 0, 0, 0, err } - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() idx, err = ob.findNonceMarkUTXO(nonce-1, preTxid) if err != nil { return nil, 0, 0, 0, err @@ -299,15 +301,15 @@ func (ob *Observer) SelectUTXOs( // 2. The tracker is missing in zetacore. func (ob *Observer) refreshPendingNonce() { // get pending nonces from zetacore - p, err := ob.zetacoreClient.GetPendingNoncesByChain(ob.chain.ChainId) + p, err := ob.ZetacoreClient().GetPendingNoncesByChain(ob.Chain().ChainId) if err != nil { ob.logger.Chain.Error().Err(err).Msg("refreshPendingNonce: error getting pending nonces") } // increase pending nonce if lagged behind - ob.Mu.Lock() + ob.Mu().Lock() pendingNonce := ob.pendingNonce - ob.Mu.Unlock() + ob.Mu().Unlock() // #nosec G701 always non-negative nonceLow := uint64(p.NonceLow) @@ -319,8 +321,8 @@ func (ob *Observer) refreshPendingNonce() { } // set 'NonceLow' as the new pending nonce - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() ob.pendingNonce = nonceLow ob.logger.Chain.Info(). Msgf("refreshPendingNonce: increase pending nonce to %d with txid %s", ob.pendingNonce, txid) @@ -335,7 +337,7 @@ func (ob *Observer) getOutboundIDByNonce(nonce uint64, test bool) (string, error return res.TxID, nil } if !test { // if not unit test, get cctx from zetacore - send, err := ob.zetacoreClient.GetCctxByNonce(ob.chain.ChainId, nonce) + send, err := ob.ZetacoreClient().GetCctxByNonce(ob.Chain().ChainId, nonce) if err != nil { return "", errors.Wrapf(err, "getOutboundIDByNonce: error getting cctx for nonce %d", nonce) } @@ -344,7 +346,7 @@ func (ob *Observer) getOutboundIDByNonce(nonce uint64, test bool) (string, error return "", fmt.Errorf("getOutboundIDByNonce: cannot find outbound txid for nonce %d", nonce) } // make sure it's a real Bitcoin txid - _, getTxResult, err := GetTxResultByHash(ob.rpcClient, txid) + _, getTxResult, err := rpc.GetTxResultByHash(ob.btcClient, txid) if err != nil { return "", errors.Wrapf( err, @@ -362,7 +364,7 @@ func (ob *Observer) getOutboundIDByNonce(nonce uint64, test bool) (string, error } func (ob *Observer) findNonceMarkUTXO(nonce uint64, txid string) (int, error) { - tssAddress := ob.Tss.BTCAddressWitnessPubkeyHash().EncodeAddress() + tssAddress := ob.TSS().BTCAddressWitnessPubkeyHash().EncodeAddress() amount := chains.NonceMarkAmount(nonce) for i, utxo := range ob.utxos { sats, err := bitcoin.GetSatoshis(utxo.Amount) @@ -385,7 +387,7 @@ func (ob *Observer) checkIncludedTx( txHash string, ) (*btcjson.GetTransactionResult, bool) { outboundID := ob.GetTxID(cctx.GetCurrentOutboundParam().TssNonce) - hash, getTxResult, err := GetTxResultByHash(ob.rpcClient, txHash) + hash, getTxResult, err := rpc.GetTxResultByHash(ob.btcClient, txHash) if err != nil { ob.logger.Outbound.Error().Err(err).Msgf("checkIncludedTx: error GetTxResultByHash: %s", txHash) return nil, false @@ -415,8 +417,8 @@ func (ob *Observer) setIncludedTx(nonce uint64, getTxResult *btcjson.GetTransact txHash := getTxResult.TxID outboundID := ob.GetTxID(nonce) - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() res, found := ob.includedTxResults[outboundID] if !found { // not found. @@ -441,15 +443,15 @@ func (ob *Observer) setIncludedTx(nonce uint64, getTxResult *btcjson.GetTransact // getIncludedTx gets the receipt and transaction from memory func (ob *Observer) getIncludedTx(nonce uint64) *btcjson.GetTransactionResult { - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() return ob.includedTxResults[ob.GetTxID(nonce)] } // removeIncludedTx removes included tx from memory func (ob *Observer) removeIncludedTx(nonce uint64) { - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() txResult, found := ob.includedTxResults[ob.GetTxID(nonce)] if found { delete(ob.includedTxHashes, txResult.TxID) @@ -469,7 +471,7 @@ func (ob *Observer) checkTssOutboundResult( ) error { params := cctx.GetCurrentOutboundParam() nonce := params.TssNonce - rawResult, err := GetRawTxResult(ob.rpcClient, hash, res) + rawResult, err := rpc.GetRawTxResult(ob.btcClient, hash, res) if err != nil { return errors.Wrapf(err, "checkTssOutboundResult: error GetRawTxResultByHash %s", hash.String()) } @@ -506,7 +508,7 @@ func (ob *Observer) checkTSSVin(vins []btcjson.Vin, nonce uint64) error { if nonce > 0 && len(vins) <= 1 { return fmt.Errorf("checkTSSVin: len(vins) <= 1") } - pubKeyTss := hex.EncodeToString(ob.Tss.PubKeyCompressedBytes()) + pubKeyTss := hex.EncodeToString(ob.TSS().PubKeyCompressedBytes()) for i, vin := range vins { // The length of the Witness should be always 2 for SegWit inputs. if len(vin.Witness) != 2 { @@ -546,7 +548,7 @@ func (ob *Observer) checkTSSVout(params *crosschaintypes.OutboundParams, vouts [ } nonce := params.TssNonce - tssAddress := ob.Tss.BTCAddress() + tssAddress := ob.TSS().BTCAddress() for _, vout := range vouts { // decode receiver and amount from vout receiverExpected := tssAddress @@ -554,7 +556,7 @@ func (ob *Observer) checkTSSVout(params *crosschaintypes.OutboundParams, vouts [ // the 2nd output is the payment to recipient receiverExpected = params.Receiver } - receiverVout, amount, err := bitcoin.DecodeTSSVout(vout, receiverExpected, ob.chain) + receiverVout, amount, err := bitcoin.DecodeTSSVout(vout, receiverExpected, ob.Chain()) if err != nil { return err } @@ -605,10 +607,10 @@ func (ob *Observer) checkTSSVoutCancelled(params *crosschaintypes.OutboundParams } nonce := params.TssNonce - tssAddress := ob.Tss.BTCAddress() + tssAddress := ob.TSS().BTCAddress() for _, vout := range vouts { // decode receiver and amount from vout - receiverVout, amount, err := bitcoin.DecodeTSSVout(vout, tssAddress, ob.chain) + receiverVout, amount, err := bitcoin.DecodeTSSVout(vout, tssAddress, ob.Chain()) if err != nil { return errors.Wrap(err, "checkTSSVoutCancelled: error decoding P2WPKH vout") } diff --git a/zetaclient/chains/bitcoin/observer/outbound_test.go b/zetaclient/chains/bitcoin/observer/outbound_test.go index bad0997c0c..0aaeb7b600 100644 --- a/zetaclient/chains/bitcoin/observer/outbound_test.go +++ b/zetaclient/chains/bitcoin/observer/outbound_test.go @@ -3,7 +3,6 @@ package observer import ( "math" "sort" - "sync" "testing" "github.com/btcsuite/btcd/btcjson" @@ -11,22 +10,27 @@ import ( "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/pkg/chains" - "github.com/zeta-chain/zetacore/zetaclient/config" - "github.com/zeta-chain/zetacore/zetaclient/context" + "github.com/zeta-chain/zetacore/zetaclient/chains/base" "github.com/zeta-chain/zetacore/zetaclient/testutils" "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" ) -func MockBTCObserverMainnet() *Observer { - cfg := config.NewConfig() - coreContext := context.NewZetacoreContext(cfg) +// the relative path to the testdata directory +var TestDataDir = "../../../" - return &Observer{ - chain: chains.BitcoinMainnet, - zetacoreClient: mocks.NewMockZetacoreClient(), - Tss: mocks.NewTSSMainnet(), - coreContext: coreContext, - } +// MockBTCObserverMainnet creates a mock Bitcoin mainnet observer for testing +func MockBTCObserverMainnet(t *testing.T) *Observer { + // setup mock arguments + chain := chains.BitcoinMainnet + btcClient := mocks.NewMockBTCRPCClient().WithBlockCount(100) + params := mocks.MockChainParams(chain.ChainId, 10) + tss := mocks.NewTSSMainnet() + + // create Bitcoin observer + ob, err := NewObserver(chain, btcClient, params, nil, nil, tss, testutils.SQLiteMemory, base.Logger{}, nil) + require.NoError(t, err) + + return ob } // helper function to create a test Bitcoin observer @@ -37,26 +41,27 @@ func createObserverWithPrivateKey(t *testing.T) *Observer { tss := &mocks.TSS{ PrivKey: privateKey, } - return &Observer{ - Tss: tss, - Mu: &sync.Mutex{}, - includedTxResults: make(map[string]*btcjson.GetTransactionResult), - } + + // create Bitcoin observer with mock tss + ob := MockBTCObserverMainnet(t) + ob.WithTSS(tss) + + return ob } // helper function to create a test Bitcoin observer with UTXOs func createObserverWithUTXOs(t *testing.T) *Observer { // Create Bitcoin observer - client := createObserverWithPrivateKey(t) - tssAddress := client.Tss.BTCAddressWitnessPubkeyHash().EncodeAddress() + ob := createObserverWithPrivateKey(t) + tssAddress := ob.TSS().BTCAddressWitnessPubkeyHash().EncodeAddress() // Create 10 dummy UTXOs (22.44 BTC in total) - client.utxos = make([]btcjson.ListUnspentResult, 0, 10) + ob.utxos = make([]btcjson.ListUnspentResult, 0, 10) amounts := []float64{0.01, 0.12, 0.18, 0.24, 0.5, 1.26, 2.97, 3.28, 5.16, 8.72} for _, amount := range amounts { - client.utxos = append(client.utxos, btcjson.ListUnspentResult{Address: tssAddress, Amount: amount}) + ob.utxos = append(ob.utxos, btcjson.ListUnspentResult{Address: tssAddress, Amount: amount}) } - return client + return ob } func mineTxNSetNonceMark(ob *Observer, nonce uint64, txid string, preMarkIndex int) { @@ -65,7 +70,7 @@ func mineTxNSetNonceMark(ob *Observer, nonce uint64, txid string, preMarkIndex i ob.includedTxResults[outboundID] = &btcjson.GetTransactionResult{TxID: txid} // Set nonce mark - tssAddress := ob.Tss.BTCAddressWitnessPubkeyHash().EncodeAddress() + tssAddress := ob.TSS().BTCAddressWitnessPubkeyHash().EncodeAddress() nonceMark := btcjson.ListUnspentResult{ TxID: txid, Address: tssAddress, @@ -90,22 +95,22 @@ func TestCheckTSSVout(t *testing.T) { nonce := uint64(148) // create mainnet mock client - btcClient := MockBTCObserverMainnet() + ob := MockBTCObserverMainnet(t) t.Run("valid TSS vout should pass", func(t *testing.T) { rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, TestDataDir, chainID, nonce) params := cctx.GetCurrentOutboundParam() - err := btcClient.checkTSSVout(params, rawResult.Vout) + err := ob.checkTSSVout(params, rawResult.Vout) require.NoError(t, err) }) t.Run("should fail if vout length < 2 or > 3", func(t *testing.T) { _, cctx := testutils.LoadBTCTxRawResultNCctx(t, TestDataDir, chainID, nonce) params := cctx.GetCurrentOutboundParam() - err := btcClient.checkTSSVout(params, []btcjson.Vout{{}}) + err := ob.checkTSSVout(params, []btcjson.Vout{{}}) require.ErrorContains(t, err, "invalid number of vouts") - err = btcClient.checkTSSVout(params, []btcjson.Vout{{}, {}, {}, {}}) + err = ob.checkTSSVout(params, []btcjson.Vout{{}, {}, {}, {}}) require.ErrorContains(t, err, "invalid number of vouts") }) t.Run("should fail on invalid TSS vout", func(t *testing.T) { @@ -114,7 +119,7 @@ func TestCheckTSSVout(t *testing.T) { // invalid TSS vout rawResult.Vout[0].ScriptPubKey.Hex = "invalid script" - err := btcClient.checkTSSVout(params, rawResult.Vout) + err := ob.checkTSSVout(params, rawResult.Vout) require.Error(t, err) }) t.Run("should fail if vout 0 is not to the TSS address", func(t *testing.T) { @@ -123,7 +128,7 @@ func TestCheckTSSVout(t *testing.T) { // not TSS address, bc1qh297vdt8xq6df5xae9z8gzd4jsu9a392mp0dus rawResult.Vout[0].ScriptPubKey.Hex = "0014ba8be635673034d4d0ddc9447409b594385ec4aa" - err := btcClient.checkTSSVout(params, rawResult.Vout) + err := ob.checkTSSVout(params, rawResult.Vout) require.ErrorContains(t, err, "not match TSS address") }) t.Run("should fail if vout 0 not match nonce mark", func(t *testing.T) { @@ -132,7 +137,7 @@ func TestCheckTSSVout(t *testing.T) { // not match nonce mark rawResult.Vout[0].Value = 0.00000147 - err := btcClient.checkTSSVout(params, rawResult.Vout) + err := ob.checkTSSVout(params, rawResult.Vout) require.ErrorContains(t, err, "not match nonce-mark amount") }) t.Run("should fail if vout 1 is not to the receiver address", func(t *testing.T) { @@ -141,7 +146,7 @@ func TestCheckTSSVout(t *testing.T) { // not receiver address, bc1qh297vdt8xq6df5xae9z8gzd4jsu9a392mp0dus rawResult.Vout[1].ScriptPubKey.Hex = "0014ba8be635673034d4d0ddc9447409b594385ec4aa" - err := btcClient.checkTSSVout(params, rawResult.Vout) + err := ob.checkTSSVout(params, rawResult.Vout) require.ErrorContains(t, err, "not match params receiver") }) t.Run("should fail if vout 1 not match payment amount", func(t *testing.T) { @@ -150,7 +155,7 @@ func TestCheckTSSVout(t *testing.T) { // not match payment amount rawResult.Vout[1].Value = 0.00011000 - err := btcClient.checkTSSVout(params, rawResult.Vout) + err := ob.checkTSSVout(params, rawResult.Vout) require.ErrorContains(t, err, "not match params amount") }) t.Run("should fail if vout 2 is not to the TSS address", func(t *testing.T) { @@ -159,7 +164,7 @@ func TestCheckTSSVout(t *testing.T) { // not TSS address, bc1qh297vdt8xq6df5xae9z8gzd4jsu9a392mp0dus rawResult.Vout[2].ScriptPubKey.Hex = "0014ba8be635673034d4d0ddc9447409b594385ec4aa" - err := btcClient.checkTSSVout(params, rawResult.Vout) + err := ob.checkTSSVout(params, rawResult.Vout) require.ErrorContains(t, err, "not match TSS address") }) } @@ -172,7 +177,7 @@ func TestCheckTSSVoutCancelled(t *testing.T) { nonce := uint64(148) // create mainnet mock client - btcClient := MockBTCObserverMainnet() + ob := MockBTCObserverMainnet(t) t.Run("valid TSS vout should pass", func(t *testing.T) { // remove change vout to simulate cancelled tx @@ -181,17 +186,17 @@ func TestCheckTSSVoutCancelled(t *testing.T) { rawResult.Vout = rawResult.Vout[:2] params := cctx.GetCurrentOutboundParam() - err := btcClient.checkTSSVoutCancelled(params, rawResult.Vout) + err := ob.checkTSSVoutCancelled(params, rawResult.Vout) require.NoError(t, err) }) t.Run("should fail if vout length < 1 or > 2", func(t *testing.T) { _, cctx := testutils.LoadBTCTxRawResultNCctx(t, TestDataDir, chainID, nonce) params := cctx.GetCurrentOutboundParam() - err := btcClient.checkTSSVoutCancelled(params, []btcjson.Vout{}) + err := ob.checkTSSVoutCancelled(params, []btcjson.Vout{}) require.ErrorContains(t, err, "invalid number of vouts") - err = btcClient.checkTSSVoutCancelled(params, []btcjson.Vout{{}, {}, {}}) + err = ob.checkTSSVoutCancelled(params, []btcjson.Vout{{}, {}, {}}) require.ErrorContains(t, err, "invalid number of vouts") }) t.Run("should fail if vout 0 is not to the TSS address", func(t *testing.T) { @@ -203,7 +208,7 @@ func TestCheckTSSVoutCancelled(t *testing.T) { // not TSS address, bc1qh297vdt8xq6df5xae9z8gzd4jsu9a392mp0dus rawResult.Vout[0].ScriptPubKey.Hex = "0014ba8be635673034d4d0ddc9447409b594385ec4aa" - err := btcClient.checkTSSVoutCancelled(params, rawResult.Vout) + err := ob.checkTSSVoutCancelled(params, rawResult.Vout) require.ErrorContains(t, err, "not match TSS address") }) t.Run("should fail if vout 0 not match nonce mark", func(t *testing.T) { @@ -215,7 +220,7 @@ func TestCheckTSSVoutCancelled(t *testing.T) { // not match nonce mark rawResult.Vout[0].Value = 0.00000147 - err := btcClient.checkTSSVoutCancelled(params, rawResult.Vout) + err := ob.checkTSSVoutCancelled(params, rawResult.Vout) require.ErrorContains(t, err, "not match nonce-mark amount") }) t.Run("should fail if vout 1 is not to the TSS address", func(t *testing.T) { @@ -228,7 +233,7 @@ func TestCheckTSSVoutCancelled(t *testing.T) { // not TSS address, bc1qh297vdt8xq6df5xae9z8gzd4jsu9a392mp0dus rawResult.Vout[1].ScriptPubKey.Hex = "0014ba8be635673034d4d0ddc9447409b594385ec4aa" - err := btcClient.checkTSSVoutCancelled(params, rawResult.Vout) + err := ob.checkTSSVoutCancelled(params, rawResult.Vout) require.ErrorContains(t, err, "not match TSS address") }) } diff --git a/zetaclient/chains/bitcoin/rpc/rpc.go b/zetaclient/chains/bitcoin/rpc/rpc.go new file mode 100644 index 0000000000..32144d77f2 --- /dev/null +++ b/zetaclient/chains/bitcoin/rpc/rpc.go @@ -0,0 +1,109 @@ +package rpc + +import ( + "fmt" + + "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/rpcclient" + "github.com/pkg/errors" + + "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" + "github.com/zeta-chain/zetacore/zetaclient/config" +) + +// NewRPCClient creates a new RPC client by the given config. +func NewRPCClient(btcConfig config.BTCConfig) (*rpcclient.Client, error) { + connCfg := &rpcclient.ConnConfig{ + Host: btcConfig.RPCHost, + User: btcConfig.RPCUsername, + Pass: btcConfig.RPCPassword, + HTTPPostMode: true, + DisableTLS: true, + Params: btcConfig.RPCParams, + } + + rpcClient, err := rpcclient.New(connCfg, nil) + if err != nil { + return nil, fmt.Errorf("error creating rpc client: %s", err) + } + + err = rpcClient.Ping() + if err != nil { + return nil, fmt.Errorf("error ping the bitcoin server: %s", err) + } + return rpcClient, nil +} + +// GetTxResultByHash gets the transaction result by hash +func GetTxResultByHash( + rpcClient interfaces.BTCRPCClient, + txID string, +) (*chainhash.Hash, *btcjson.GetTransactionResult, error) { + hash, err := chainhash.NewHashFromStr(txID) + if err != nil { + return nil, nil, errors.Wrapf(err, "GetTxResultByHash: error NewHashFromStr: %s", txID) + } + + // The Bitcoin node has to be configured to watch TSS address + txResult, err := rpcClient.GetTransaction(hash) + if err != nil { + return nil, nil, errors.Wrapf(err, "GetTxResultByHash: error GetTransaction %s", hash.String()) + } + return hash, txResult, nil +} + +// GetBlockHeightByHash gets the block height by block hash +func GetBlockHeightByHash( + rpcClient interfaces.BTCRPCClient, + hash string, +) (int64, error) { + // decode the block hash + var blockHash chainhash.Hash + err := chainhash.Decode(&blockHash, hash) + if err != nil { + return 0, errors.Wrapf(err, "GetBlockHeightByHash: error decoding block hash %s", hash) + } + + // get block by hash + block, err := rpcClient.GetBlockVerbose(&blockHash) + if err != nil { + return 0, errors.Wrapf(err, "GetBlockHeightByHash: error GetBlockVerbose %s", hash) + } + return block.Height, nil +} + +// GetRawTxResult gets the raw tx result +func GetRawTxResult( + rpcClient interfaces.BTCRPCClient, + hash *chainhash.Hash, + res *btcjson.GetTransactionResult, +) (btcjson.TxRawResult, error) { + if res.Confirmations == 0 { // for pending tx, we query the raw tx directly + rawResult, err := rpcClient.GetRawTransactionVerbose(hash) // for pending tx, we query the raw tx + if err != nil { + return btcjson.TxRawResult{}, errors.Wrapf( + err, + "GetRawTxResult: error GetRawTransactionVerbose %s", + res.TxID, + ) + } + return *rawResult, nil + } else if res.Confirmations > 0 { // for confirmed tx, we query the block + blkHash, err := chainhash.NewHashFromStr(res.BlockHash) + if err != nil { + return btcjson.TxRawResult{}, errors.Wrapf(err, "GetRawTxResult: error NewHashFromStr for block hash %s", res.BlockHash) + } + block, err := rpcClient.GetBlockVerboseTx(blkHash) + if err != nil { + return btcjson.TxRawResult{}, errors.Wrapf(err, "GetRawTxResult: error GetBlockVerboseTx %s", res.BlockHash) + } + if res.BlockIndex < 0 || res.BlockIndex >= int64(len(block.Tx)) { + return btcjson.TxRawResult{}, errors.Wrapf(err, "GetRawTxResult: invalid outbound with invalid block index, TxID %s, BlockIndex %d", res.TxID, res.BlockIndex) + } + return block.Tx[res.BlockIndex], nil + } + + // res.Confirmations < 0 (meaning not included) + return btcjson.TxRawResult{}, fmt.Errorf("GetRawTxResult: tx %s not included yet", hash) +} diff --git a/zetaclient/chains/bitcoin/observer/live_test.go b/zetaclient/chains/bitcoin/rpc/rpc_live_test.go similarity index 90% rename from zetaclient/chains/bitcoin/observer/live_test.go rename to zetaclient/chains/bitcoin/rpc/rpc_live_test.go index dd1053f620..97a373f94d 100644 --- a/zetaclient/chains/bitcoin/observer/live_test.go +++ b/zetaclient/chains/bitcoin/rpc/rpc_live_test.go @@ -1,4 +1,4 @@ -package observer +package rpc_test import ( "context" @@ -23,8 +23,9 @@ import ( "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/zetaclient/chains/base" "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin" + "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/observer" + "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/rpc" "github.com/zeta-chain/zetacore/zetaclient/config" - clientcontext "github.com/zeta-chain/zetacore/zetaclient/context" "github.com/zeta-chain/zetacore/zetaclient/testutils" "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" ) @@ -47,34 +48,39 @@ func (suite *BitcoinObserverTestSuite) SetupTest() { tss := &mocks.TSS{ PrivKey: privateKey, } - appContext := clientcontext.NewAppContext(&clientcontext.ZetacoreContext{}, config.Config{}) - client, err := NewObserver(appContext, chains.BitcoinRegtest, nil, tss, tempSQLiteDbPath, - base.DefaultLogger(), config.BTCConfig{}, nil) + + // create mock arguments for constructor + chain := chains.BitcoinMainnet + params := mocks.MockChainParams(chain.ChainId, 10) + btcClient := mocks.NewMockBTCRPCClient() + + // create observer + ob, err := observer.NewObserver(chain, btcClient, params, nil, nil, tss, testutils.SQLiteMemory, + base.DefaultLogger(), nil) suite.Require().NoError(err) + suite.Require().NotNil(ob) suite.rpcClient, err = getRPCClient(18332) suite.Require().NoError(err) skBytes, err := hex.DecodeString(skHex) suite.Require().NoError(err) suite.T().Logf("skBytes: %d", len(skBytes)) - btc := client.rpcClient - - _, err = btc.CreateWallet("e2e") + _, err = btcClient.CreateWallet("e2e") suite.Require().NoError(err) - addr, err := btc.GetNewAddress("test") + addr, err := btcClient.GetNewAddress("test") suite.Require().NoError(err) suite.T().Logf("deployer address: %s", addr) //err = btc.ImportPrivKey(privkeyWIF) //suite.Require().NoError(err) - btc.GenerateToAddress(101, addr, nil) + btcClient.GenerateToAddress(101, addr, nil) suite.Require().NoError(err) - bal, err := btc.GetBalance("*") + bal, err := btcClient.GetBalance("*") suite.Require().NoError(err) suite.T().Logf("balance: %f", bal.ToBTC()) - utxo, err := btc.ListUnspent() + utxo, err := btcClient.ListUnspent() suite.Require().NoError(err) suite.T().Logf("utxo: %d", len(utxo)) for _, u := range utxo { @@ -153,7 +159,7 @@ func (suite *BitcoinObserverTestSuite) Test1() { suite.T().Logf("block confirmation %d", block.Confirmations) suite.T().Logf("block txs len %d", len(block.Tx)) - inbounds, err := FilterAndParseIncomingTx( + inbounds, err := observer.FilterAndParseIncomingTx( suite.rpcClient, block.Tx, uint64(block.Height), @@ -190,7 +196,7 @@ func (suite *BitcoinObserverTestSuite) Test2() { suite.T().Logf("block height %d", block.Height) suite.T().Logf("block txs len %d", len(block.Tx)) - inbounds, err := FilterAndParseIncomingTx( + inbounds, err := observer.FilterAndParseIncomingTx( suite.rpcClient, block.Tx, uint64(block.Height), @@ -203,26 +209,11 @@ func (suite *BitcoinObserverTestSuite) Test2() { suite.Require().Equal(0, len(inbounds)) } -func (suite *BitcoinObserverTestSuite) Test3() { - client := suite.rpcClient - res, err := client.EstimateSmartFee(1, &btcjson.EstimateModeConservative) - suite.Require().NoError(err) - suite.T().Logf("fee: %f", *res.FeeRate) - suite.T().Logf("blocks: %d", res.Blocks) - suite.T().Logf("errors: %s", res.Errors) - gasPrice := big.NewFloat(0) - gasPriceU64, _ := gasPrice.Mul(big.NewFloat(*res.FeeRate), big.NewFloat(1e8)).Uint64() - suite.T().Logf("gas price: %d", gasPriceU64) - - bn, err := client.GetBlockCount() - suite.Require().NoError(err) - suite.T().Logf("block number %d", bn) -} - // TestBitcoinObserverLive is a phony test to run each live test individually func TestBitcoinObserverLive(t *testing.T) { // suite.Run(t, new(BitcoinClientTestSuite)) + // LiveTestNewRPCClient(t) // LiveTestGetBlockHeightByHash(t) // LiveTestBitcoinFeeRate(t) // LiveTestAvgFeeRateMainnetMempoolSpace(t) @@ -230,6 +221,25 @@ func TestBitcoinObserverLive(t *testing.T) { // LiveTestGetSenderByVin(t) } +// LiveTestNewRPCClient creates a new Bitcoin RPC client +func LiveTestNewRPCClient(t *testing.T) { + btcConfig := config.BTCConfig{ + RPCUsername: "user", + RPCPassword: "pass", + RPCHost: "bitcoin.rpc.zetachain.com/6315704c-49bc-4649-8b9d-e9278a1dfeb3", + RPCParams: "mainnet", + } + + // create Bitcoin RPC client + client, err := rpc.NewRPCClient(btcConfig) + require.NoError(t, err) + + // get block count + bn, err := client.GetBlockCount() + require.NoError(t, err) + require.Greater(t, bn, int64(0)) +} + // LiveTestGetBlockHeightByHash queries Bitcoin block height by hash func LiveTestGetBlockHeightByHash(t *testing.T) { // setup Bitcoin client @@ -242,11 +252,11 @@ func LiveTestGetBlockHeightByHash(t *testing.T) { invalidHash := "invalidhash" // get block by invalid hash - _, err = GetBlockHeightByHash(client, invalidHash) + _, err = rpc.GetBlockHeightByHash(client, invalidHash) require.ErrorContains(t, err, "error decoding block hash") // get block height by block hash - height, err := GetBlockHeightByHash(client, hash) + height, err := rpc.GetBlockHeightByHash(client, hash) require.NoError(t, err) require.Equal(t, expectedHeight, height) } @@ -460,7 +470,7 @@ BLOCKLOOP: Txid: mpvin.TxID, Vout: mpvin.Vout, } - senderAddr, err := GetSenderAddressByVin(client, vin, net) + senderAddr, err := observer.GetSenderAddressByVin(client, vin, net) if err != nil { fmt.Printf("error GetSenderAddressByVin for block %d, tx %s vout %d: %s\n", bn, vin.Txid, vin.Vout, err) time.Sleep(3 * time.Second) diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index d39b8a8f9d..6ad9bfc2a6 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -5,7 +5,6 @@ import ( "encoding/hex" "fmt" "math/big" - "math/rand" "time" "github.com/btcsuite/btcd/btcec" @@ -37,14 +36,19 @@ const ( // the rank below (or equal to) which we consolidate UTXOs consolidationRank = 10 + + // broadcastBackoff is the initial backoff duration for retrying broadcast + broadcastBackoff = 1000 * time.Millisecond + + // broadcastRetries is the maximum number of retries for broadcasting a transaction + broadcastRetries = 5 ) var _ interfaces.ChainSigner = &Signer{} // Signer deals with signing BTC transactions and implements the ChainSigner interface type Signer struct { - // base.Signer implements the base chain signer - base.Signer + *base.Signer // client is the RPC client to interact with the Bitcoin chain client interfaces.BTCRPCClient @@ -76,7 +80,7 @@ func NewSigner( } return &Signer{ - Signer: *baseSigner, + Signer: baseSigner, client: client, }, nil } @@ -422,17 +426,17 @@ func (signer *Signer) TryProcessOutbound( outboundHash := tx.TxHash().String() logger.Info(). Msgf("on chain %s nonce %d, outboundHash %s signer %s", chain.ChainName, outboundTssNonce, outboundHash, signerAddress) - // TODO: pick a few broadcasters. - //if len(signers) == 0 || myid == signers[send.OutboundParams.Broadcaster] || myid == signers[int(send.OutboundParams.Broadcaster+1)%len(signers)] { - // retry loop: 1s, 2s, 4s, 8s, 16s in case of RPC error - for i := 0; i < 5; i++ { - // #nosec G404 randomness is not a security issue here - time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond) //random delay to avoid sychronized broadcast + + // try broacasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error + backOff := broadcastBackoff + for i := 0; i < broadcastRetries; i++ { + time.Sleep(backOff) err := signer.Broadcast(tx) if err != nil { logger.Warn(). Err(err). Msgf("broadcasting tx %s to chain %s: nonce %d, retry %d", outboundHash, chain.ChainName, outboundTssNonce, i) + backOff *= 2 continue } logger.Info(). diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index 1e261c4d0a..41ada01375 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -36,33 +36,33 @@ import ( // WatchInbound watches evm chain for incoming txs and post votes to zetacore func (ob *Observer) WatchInbound() { ticker, err := clienttypes.NewDynamicTicker( - fmt.Sprintf("EVM_WatchInbound_%d", ob.chain.ChainId), + fmt.Sprintf("EVM_WatchInbound_%d", ob.Chain().ChainId), ob.GetChainParams().InboundTicker, ) if err != nil { - ob.logger.Inbound.Error().Err(err).Msg("error creating ticker") + ob.Logger().Inbound.Error().Err(err).Msg("error creating ticker") return } defer ticker.Stop() - ob.logger.Inbound.Info().Msgf("WatchInbound started for chain %d", ob.chain.ChainId) - sampledLogger := ob.logger.Inbound.Sample(&zerolog.BasicSampler{N: 10}) + ob.Logger().Inbound.Info().Msgf("WatchInbound started for chain %d", ob.Chain().ChainId) + sampledLogger := ob.Logger().Inbound.Sample(&zerolog.BasicSampler{N: 10}) for { select { case <-ticker.C(): - if !clientcontext.IsInboundObservationEnabled(ob.coreContext, ob.GetChainParams()) { + if !clientcontext.IsInboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { sampledLogger.Info(). - Msgf("WatchInbound: inbound observation is disabled for chain %d", ob.chain.ChainId) + Msgf("WatchInbound: inbound observation is disabled for chain %d", ob.Chain().ChainId) continue } err := ob.ObserveInbound(sampledLogger) if err != nil { - ob.logger.Inbound.Err(err).Msg("WatchInbound: observeInbound error") + ob.Logger().Inbound.Err(err).Msg("WatchInbound: observeInbound error") } - ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.logger.Inbound) - case <-ob.stop: - ob.logger.Inbound.Info().Msgf("WatchInbound stopped for chain %d", ob.chain.ChainId) + ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.Logger().Inbound) + case <-ob.StopChannel(): + ob.Logger().Inbound.Info().Msgf("WatchInbound stopped for chain %d", ob.Chain().ChainId) return } } @@ -72,29 +72,29 @@ func (ob *Observer) WatchInbound() { // If it was, it tries to broadcast the confirmation vote. If this zeta client has previously broadcast the vote, the tx would be rejected func (ob *Observer) WatchInboundTracker() { ticker, err := clienttypes.NewDynamicTicker( - fmt.Sprintf("EVM_WatchInboundTracker_%d", ob.chain.ChainId), + fmt.Sprintf("EVM_WatchInboundTracker_%d", ob.Chain().ChainId), ob.GetChainParams().InboundTicker, ) if err != nil { - ob.logger.Inbound.Err(err).Msg("error creating ticker") + ob.Logger().Inbound.Err(err).Msg("error creating ticker") return } defer ticker.Stop() - ob.logger.Inbound.Info().Msgf("Inbound tracker watcher started for chain %d", ob.chain.ChainId) + ob.Logger().Inbound.Info().Msgf("Inbound tracker watcher started for chain %d", ob.Chain().ChainId) for { select { case <-ticker.C(): - if !clientcontext.IsInboundObservationEnabled(ob.coreContext, ob.GetChainParams()) { + if !clientcontext.IsInboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { continue } err := ob.ProcessInboundTrackers() if err != nil { - ob.logger.Inbound.Err(err).Msg("ProcessInboundTrackers error") + ob.Logger().Inbound.Err(err).Msg("ProcessInboundTrackers error") } - ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.logger.Inbound) - case <-ob.stop: - ob.logger.Inbound.Info().Msgf("WatchInboundTracker stopped for chain %d", ob.chain.ChainId) + ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.Logger().Inbound) + case <-ob.StopChannel(): + ob.Logger().Inbound.Info().Msgf("WatchInboundTracker stopped for chain %d", ob.Chain().ChainId) return } } @@ -102,7 +102,7 @@ func (ob *Observer) WatchInboundTracker() { // ProcessInboundTrackers processes inbound trackers from zetacore func (ob *Observer) ProcessInboundTrackers() error { - trackers, err := ob.zetacoreClient.GetInboundTrackersForChain(ob.chain.ChainId) + trackers, err := ob.ZetacoreClient().GetInboundTrackersForChain(ob.Chain().ChainId) if err != nil { return err } @@ -114,15 +114,20 @@ func (ob *Observer) ProcessInboundTrackers() error { err, "error getting transaction for inbound %s chain %d", tracker.TxHash, - ob.chain.ChainId, + ob.Chain().ChainId, ) } receipt, err := ob.evmClient.TransactionReceipt(context.Background(), ethcommon.HexToHash(tracker.TxHash)) if err != nil { - return errors.Wrapf(err, "error getting receipt for inbound %s chain %d", tracker.TxHash, ob.chain.ChainId) + return errors.Wrapf( + err, + "error getting receipt for inbound %s chain %d", + tracker.TxHash, + ob.Chain().ChainId, + ) } - ob.logger.Inbound.Info().Msgf("checking tracker for inbound %s chain %d", tracker.TxHash, ob.chain.ChainId) + ob.Logger().Inbound.Info().Msgf("checking tracker for inbound %s chain %d", tracker.TxHash, ob.Chain().ChainId) // check and vote on inbound tx switch tracker.CoinType { @@ -137,11 +142,11 @@ func (ob *Observer) ProcessInboundTrackers() error { "unknown coin type %s for inbound %s chain %d", tracker.CoinType, tx.Hash, - ob.chain.ChainId, + ob.Chain().ChainId, ) } if err != nil { - return errors.Wrapf(err, "error checking and voting for inbound %s chain %d", tx.Hash, ob.chain.ChainId) + return errors.Wrapf(err, "error checking and voting for inbound %s chain %d", tx.Hash, ob.Chain().ChainId) } } return nil @@ -153,17 +158,17 @@ func (ob *Observer) ObserveInbound(sampledLogger zerolog.Logger) error { if err != nil { return err } - if blockNumber < ob.GetLastBlockHeight() { + if blockNumber < ob.LastBlock() { return fmt.Errorf( "observeInbound: block number should not decrease: current %d last %d", blockNumber, - ob.GetLastBlockHeight(), + ob.LastBlock(), ) } - ob.SetLastBlockHeight(blockNumber) + ob.WithLastBlock(blockNumber) // increment prom counter - metrics.GetBlockByNumberPerChain.WithLabelValues(ob.chain.ChainName.String()).Inc() + metrics.GetBlockByNumberPerChain.WithLabelValues(ob.Chain().ChainName.String()).Inc() // skip if current height is too low if blockNumber < ob.GetChainParams().ConfirmationCount { @@ -172,10 +177,10 @@ func (ob *Observer) ObserveInbound(sampledLogger zerolog.Logger) error { confirmedBlockNum := blockNumber - ob.GetChainParams().ConfirmationCount // skip if no new block is confirmed - lastScanned := ob.GetLastBlockHeightScanned() + lastScanned := ob.LastBlockScanned() if lastScanned >= confirmedBlockNum { sampledLogger.Debug(). - Msgf("observeInbound: skipping observer, no new block is produced for chain %d", ob.chain.ChainId) + Msgf("observeInbound: skipping observer, no new block is produced for chain %d", ob.Chain().ChainId) return nil } @@ -205,12 +210,11 @@ func (ob *Observer) ObserveInbound(sampledLogger zerolog.Logger) error { if lastScannedLowest > lastScanned { sampledLogger.Info(). Msgf("observeInbound: lasstScanned heights for chain %d ZetaSent %d ERC20Deposited %d TssRecvd %d", - ob.chain.ChainId, lastScannedZetaSent, lastScannedDeposited, lastScannedTssRecvd) - ob.SetLastBlockHeightScanned(lastScannedLowest) - if err := ob.db.Save(clienttypes.ToLastBlockSQLType(lastScannedLowest)).Error; err != nil { - ob.logger.Inbound.Error(). + ob.Chain().ChainId, lastScannedZetaSent, lastScannedDeposited, lastScannedTssRecvd) + if err := ob.SaveLastBlockScanned(lastScannedLowest); err != nil { + ob.Logger().Inbound.Error(). Err(err). - Msgf("observeInbound: error writing lastScannedLowest %d to db", lastScannedLowest) + Msgf("observeInbound: error saving lastScannedLowest %d to db", lastScannedLowest) } } return nil @@ -222,7 +226,7 @@ func (ob *Observer) ObserveZetaSent(startBlock, toBlock uint64) uint64 { // filter ZetaSent logs addrConnector, connector, err := ob.GetConnectorContract() if err != nil { - ob.logger.Chain.Warn().Err(err).Msgf("ObserveZetaSent: GetConnectorContract error:") + ob.Logger().Chain.Warn().Err(err).Msgf("ObserveZetaSent: GetConnectorContract error:") return startBlock - 1 // lastScanned } iter, err := connector.FilterZetaSent(&bind.FilterOpts{ @@ -231,8 +235,8 @@ func (ob *Observer) ObserveZetaSent(startBlock, toBlock uint64) uint64 { Context: context.TODO(), }, []ethcommon.Address{}, []*big.Int{}) if err != nil { - ob.logger.Chain.Warn().Err(err).Msgf( - "ObserveZetaSent: FilterZetaSent error from block %d to %d for chain %d", startBlock, toBlock, ob.chain.ChainId) + ob.Logger().Chain.Warn().Err(err).Msgf( + "ObserveZetaSent: FilterZetaSent error from block %d to %d for chain %d", startBlock, toBlock, ob.Chain().ChainId) return startBlock - 1 // lastScanned } @@ -245,10 +249,10 @@ func (ob *Observer) ObserveZetaSent(startBlock, toBlock uint64) uint64 { events = append(events, iter.Event) continue } - ob.logger.Inbound.Warn(). + ob.Logger().Inbound.Warn(). Err(err). Msgf("ObserveZetaSent: invalid ZetaSent event in tx %s on chain %d at height %d", - iter.Event.Raw.TxHash.Hex(), ob.chain.ChainId, iter.Event.Raw.BlockNumber) + iter.Event.Raw.TxHash.Hex(), ob.Chain().ChainId, iter.Event.Raw.BlockNumber) } sort.SliceStable(events, func(i, j int) bool { if events[i].Raw.BlockNumber == events[j].Raw.BlockNumber { @@ -261,7 +265,7 @@ func (ob *Observer) ObserveZetaSent(startBlock, toBlock uint64) uint64 { }) // increment prom counter - metrics.GetFilterLogsPerChain.WithLabelValues(ob.chain.ChainName.String()).Inc() + metrics.GetFilterLogsPerChain.WithLabelValues(ob.Chain().ChainName.String()).Inc() // post to zetacore beingScanned := uint64(0) @@ -273,7 +277,7 @@ func (ob *Observer) ObserveZetaSent(startBlock, toBlock uint64) uint64 { } // guard against multiple events in the same tx if guard[event.Raw.TxHash.Hex()] { - ob.logger.Inbound.Warn(). + ob.Logger().Inbound.Warn(). Msgf("ObserveZetaSent: multiple remote call events detected in tx %s", event.Raw.TxHash) continue } @@ -301,7 +305,7 @@ func (ob *Observer) ObserveERC20Deposited(startBlock, toBlock uint64) uint64 { // filter ERC20CustodyDeposited logs addrCustody, erc20custodyContract, err := ob.GetERC20CustodyContract() if err != nil { - ob.logger.Inbound.Warn().Err(err).Msgf("ObserveERC20Deposited: GetERC20CustodyContract error:") + ob.Logger().Inbound.Warn().Err(err).Msgf("ObserveERC20Deposited: GetERC20CustodyContract error:") return startBlock - 1 // lastScanned } @@ -311,8 +315,8 @@ func (ob *Observer) ObserveERC20Deposited(startBlock, toBlock uint64) uint64 { Context: context.TODO(), }, []ethcommon.Address{}) if err != nil { - ob.logger.Inbound.Warn().Err(err).Msgf( - "ObserveERC20Deposited: FilterDeposited error from block %d to %d for chain %d", startBlock, toBlock, ob.chain.ChainId) + ob.Logger().Inbound.Warn().Err(err).Msgf( + "ObserveERC20Deposited: FilterDeposited error from block %d to %d for chain %d", startBlock, toBlock, ob.Chain().ChainId) return startBlock - 1 // lastScanned } @@ -325,10 +329,10 @@ func (ob *Observer) ObserveERC20Deposited(startBlock, toBlock uint64) uint64 { events = append(events, iter.Event) continue } - ob.logger.Inbound.Warn(). + ob.Logger().Inbound.Warn(). Err(err). Msgf("ObserveERC20Deposited: invalid Deposited event in tx %s on chain %d at height %d", - iter.Event.Raw.TxHash.Hex(), ob.chain.ChainId, iter.Event.Raw.BlockNumber) + iter.Event.Raw.TxHash.Hex(), ob.Chain().ChainId, iter.Event.Raw.BlockNumber) } sort.SliceStable(events, func(i, j int) bool { if events[i].Raw.BlockNumber == events[j].Raw.BlockNumber { @@ -341,7 +345,7 @@ func (ob *Observer) ObserveERC20Deposited(startBlock, toBlock uint64) uint64 { }) // increment prom counter - metrics.GetFilterLogsPerChain.WithLabelValues(ob.chain.ChainName.String()).Inc() + metrics.GetFilterLogsPerChain.WithLabelValues(ob.Chain().ChainName.String()).Inc() // post to zeatcore guard := make(map[string]bool) @@ -353,15 +357,15 @@ func (ob *Observer) ObserveERC20Deposited(startBlock, toBlock uint64) uint64 { } tx, _, err := ob.TransactionByHash(event.Raw.TxHash.Hex()) if err != nil { - ob.logger.Inbound.Error().Err(err).Msgf( - "ObserveERC20Deposited: error getting transaction for inbound %s chain %d", event.Raw.TxHash, ob.chain.ChainId) + ob.Logger().Inbound.Error().Err(err).Msgf( + "ObserveERC20Deposited: error getting transaction for inbound %s chain %d", event.Raw.TxHash, ob.Chain().ChainId) return beingScanned - 1 // we have to re-scan from this block next time } sender := ethcommon.HexToAddress(tx.From) // guard against multiple events in the same tx if guard[event.Raw.TxHash.Hex()] { - ob.logger.Inbound.Warn(). + ob.Logger().Inbound.Warn(). Msgf("ObserveERC20Deposited: multiple remote call events detected in tx %s", event.Raw.TxHash) continue } @@ -387,23 +391,23 @@ func (ob *Observer) ObserverTSSReceive(startBlock, toBlock uint64) uint64 { // post new block header (if any) to zetacore and ignore error // TODO: consider having a independent ticker(from TSS scaning) for posting block headers // https://github.com/zeta-chain/node/issues/1847 - blockHeaderVerification, found := ob.coreContext.GetBlockHeaderEnabledChains(ob.chain.ChainId) + blockHeaderVerification, found := ob.ZetacoreContext().GetBlockHeaderEnabledChains(ob.Chain().ChainId) if found && blockHeaderVerification.Enabled { // post block header for supported chains // TODO: move this logic in its own routine // https://github.com/zeta-chain/node/issues/2204 err := ob.postBlockHeader(toBlock) if err != nil { - ob.logger.Inbound.Error().Err(err).Msg("error posting block header") + ob.Logger().Inbound.Error().Err(err).Msg("error posting block header") } } // observe TSS received gas token in block 'bn' err := ob.ObserveTSSReceiveInBlock(bn) if err != nil { - ob.logger.Inbound.Error(). + ob.Logger().Inbound.Error(). Err(err). - Msgf("ObserverTSSReceive: error observing TSS received token in block %d for chain %d", bn, ob.chain.ChainId) + Msgf("ObserverTSSReceive: error observing TSS received token in block %d for chain %d", bn, ob.Chain().ChainId) return bn - 1 // we have to re-scan from this block next time } } @@ -418,7 +422,7 @@ func (ob *Observer) CheckAndVoteInboundTokenZeta( vote bool, ) (string, error) { // check confirmations - if confirmed := ob.HasEnoughConfirmations(receipt, ob.GetLastBlockHeight()); !confirmed { + if confirmed := ob.HasEnoughConfirmations(receipt, ob.LastBlock()); !confirmed { return "", fmt.Errorf( "inbound %s has not been confirmed yet: receipt block %d", tx.Hash, @@ -442,7 +446,7 @@ func (ob *Observer) CheckAndVoteInboundTokenZeta( if err == nil { msg = ob.BuildInboundVoteMsgForZetaSentEvent(event) } else { - ob.logger.Inbound.Error().Err(err).Msgf("CheckEvmTxLog error on inbound %s chain %d", tx.Hash, ob.chain.ChainId) + ob.Logger().Inbound.Error().Err(err).Msgf("CheckEvmTxLog error on inbound %s chain %d", tx.Hash, ob.Chain().ChainId) return "", err } break // only one event is allowed per tx @@ -450,7 +454,7 @@ func (ob *Observer) CheckAndVoteInboundTokenZeta( } if msg == nil { // no event, restricted tx, etc. - ob.logger.Inbound.Info().Msgf("no ZetaSent event found for inbound %s chain %d", tx.Hash, ob.chain.ChainId) + ob.Logger().Inbound.Info().Msgf("no ZetaSent event found for inbound %s chain %d", tx.Hash, ob.Chain().ChainId) return "", nil } if vote { @@ -467,7 +471,7 @@ func (ob *Observer) CheckAndVoteInboundTokenERC20( vote bool, ) (string, error) { // check confirmations - if confirmed := ob.HasEnoughConfirmations(receipt, ob.GetLastBlockHeight()); !confirmed { + if confirmed := ob.HasEnoughConfirmations(receipt, ob.LastBlock()); !confirmed { return "", fmt.Errorf( "inbound %s has not been confirmed yet: receipt block %d", tx.Hash, @@ -492,7 +496,7 @@ func (ob *Observer) CheckAndVoteInboundTokenERC20( if err == nil { msg = ob.BuildInboundVoteMsgForDepositedEvent(zetaDeposited, sender) } else { - ob.logger.Inbound.Error().Err(err).Msgf("CheckEvmTxLog error on inbound %s chain %d", tx.Hash, ob.chain.ChainId) + ob.Logger().Inbound.Error().Err(err).Msgf("CheckEvmTxLog error on inbound %s chain %d", tx.Hash, ob.Chain().ChainId) return "", err } break // only one event is allowed per tx @@ -500,7 +504,7 @@ func (ob *Observer) CheckAndVoteInboundTokenERC20( } if msg == nil { // no event, donation, restricted tx, etc. - ob.logger.Inbound.Info().Msgf("no Deposited event found for inbound %s chain %d", tx.Hash, ob.chain.ChainId) + ob.Logger().Inbound.Info().Msgf("no Deposited event found for inbound %s chain %d", tx.Hash, ob.Chain().ChainId) return "", nil } if vote { @@ -517,7 +521,7 @@ func (ob *Observer) CheckAndVoteInboundTokenGas( vote bool, ) (string, error) { // check confirmations - if confirmed := ob.HasEnoughConfirmations(receipt, ob.GetLastBlockHeight()); !confirmed { + if confirmed := ob.HasEnoughConfirmations(receipt, ob.LastBlock()); !confirmed { return "", fmt.Errorf( "inbound %s has not been confirmed yet: receipt block %d", tx.Hash, @@ -526,7 +530,7 @@ func (ob *Observer) CheckAndVoteInboundTokenGas( } // checks receiver and tx status - if ethcommon.HexToAddress(tx.To) != ob.Tss.EVMAddress() { + if ethcommon.HexToAddress(tx.To) != ob.TSS().EVMAddress() { return "", fmt.Errorf("tx.To %s is not TSS address", tx.To) } if receipt.Status != ethtypes.ReceiptStatusSuccessful { @@ -538,7 +542,7 @@ func (ob *Observer) CheckAndVoteInboundTokenGas( msg := ob.BuildInboundVoteMsgForTokenSentToTSS(tx, sender, receipt.BlockNumber.Uint64()) if msg == nil { // donation, restricted tx, etc. - ob.logger.Inbound.Info().Msgf("no vote message built for inbound %s chain %d", tx.Hash, ob.chain.ChainId) + ob.Logger().Inbound.Info().Msgf("no vote message built for inbound %s chain %d", tx.Hash, ob.Chain().ChainId) return "", nil } if vote { @@ -555,16 +559,16 @@ func (ob *Observer) PostVoteInbound( retryGasLimit uint64, ) (string, error) { txHash := msg.InboundHash - chainID := ob.chain.ChainId - zetaHash, ballot, err := ob.zetacoreClient.PostVoteInbound(zetacore.PostVoteInboundGasLimit, retryGasLimit, msg) + chainID := ob.Chain().ChainId + zetaHash, ballot, err := ob.ZetacoreClient().PostVoteInbound(zetacore.PostVoteInboundGasLimit, retryGasLimit, msg) if err != nil { - ob.logger.Inbound.Err(err). + ob.Logger().Inbound.Err(err). Msgf("inbound detected: error posting vote for chain %d token %s inbound %s", chainID, coinType, txHash) return "", err } else if zetaHash != "" { - ob.logger.Inbound.Info().Msgf("inbound detected: chain %d token %s inbound %s vote %s ballot %s", chainID, coinType, txHash, zetaHash, ballot) + ob.Logger().Inbound.Info().Msgf("inbound detected: chain %d token %s inbound %s vote %s ballot %s", chainID, coinType, txHash, zetaHash, ballot) } else { - ob.logger.Inbound.Info().Msgf("inbound detected: chain %d token %s inbound %s already voted on ballot %s", chainID, coinType, txHash, ballot) + ob.Logger().Inbound.Info().Msgf("inbound detected: chain %d token %s inbound %s already voted on ballot %s", chainID, coinType, txHash, ballot) } return ballot, err @@ -589,10 +593,10 @@ func (ob *Observer) BuildInboundVoteMsgForDepositedEvent( } if config.ContainRestrictedAddress(sender.Hex(), clienttypes.BytesToEthHex(event.Recipient), maybeReceiver) { compliance.PrintComplianceLog( - ob.logger.Inbound, - ob.logger.Compliance, + ob.Logger().Inbound, + ob.Logger().Compliance, false, - ob.chain.ChainId, + ob.Chain().ChainId, event.Raw.TxHash.Hex(), sender.Hex(), clienttypes.BytesToEthHex(event.Recipient), @@ -603,21 +607,22 @@ func (ob *Observer) BuildInboundVoteMsgForDepositedEvent( // donation check if bytes.Equal(event.Message, []byte(constant.DonationMessage)) { - ob.logger.Inbound.Info(). - Msgf("thank you rich folk for your donation! tx %s chain %d", event.Raw.TxHash.Hex(), ob.chain.ChainId) + ob.Logger().Inbound.Info(). + Msgf("thank you rich folk for your donation! tx %s chain %d", event.Raw.TxHash.Hex(), ob.Chain().ChainId) return nil } message := hex.EncodeToString(event.Message) - ob.logger.Inbound.Info(). + ob.Logger().Inbound.Info(). Msgf("ERC20CustodyDeposited inbound detected on chain %d tx %s block %d from %s value %s message %s", - ob.chain.ChainId, event.Raw.TxHash.Hex(), event.Raw.BlockNumber, sender.Hex(), event.Amount.String(), message) + ob.Chain(). + ChainId, event.Raw.TxHash.Hex(), event.Raw.BlockNumber, sender.Hex(), event.Amount.String(), message) return zetacore.GetInboundVoteMessage( sender.Hex(), - ob.chain.ChainId, + ob.Chain().ChainId, "", clienttypes.BytesToEthHex(event.Recipient), - ob.zetacoreClient.Chain().ChainId, + ob.ZetacoreClient().Chain().ChainId, sdkmath.NewUintFromBigInt(event.Amount), hex.EncodeToString(event.Message), event.Raw.TxHash.Hex(), @@ -625,7 +630,7 @@ func (ob *Observer) BuildInboundVoteMsgForDepositedEvent( 1_500_000, coin.CoinType_ERC20, event.Asset.String(), - ob.zetacoreClient.GetKeys().GetOperatorAddress().String(), + ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), event.Raw.Index, ) } @@ -636,7 +641,7 @@ func (ob *Observer) BuildInboundVoteMsgForZetaSentEvent( ) *types.MsgVoteInbound { destChain := chains.GetChainFromChainID(event.DestinationChainId.Int64()) if destChain == nil { - ob.logger.Inbound.Warn().Msgf("chain id not supported %d", event.DestinationChainId.Int64()) + ob.Logger().Inbound.Warn().Msgf("chain id not supported %d", event.DestinationChainId.Int64()) return nil } destAddr := clienttypes.BytesToEthHex(event.DestinationAddress) @@ -644,32 +649,33 @@ func (ob *Observer) BuildInboundVoteMsgForZetaSentEvent( // compliance check sender := event.ZetaTxSenderAddress.Hex() if config.ContainRestrictedAddress(sender, destAddr, event.SourceTxOriginAddress.Hex()) { - compliance.PrintComplianceLog(ob.logger.Inbound, ob.logger.Compliance, - false, ob.chain.ChainId, event.Raw.TxHash.Hex(), sender, destAddr, "Zeta") + compliance.PrintComplianceLog(ob.Logger().Inbound, ob.Logger().Compliance, + false, ob.Chain().ChainId, event.Raw.TxHash.Hex(), sender, destAddr, "Zeta") return nil } if !destChain.IsZetaChain() { - paramsDest, found := ob.coreContext.GetEVMChainParams(destChain.ChainId) + paramsDest, found := ob.ZetacoreContext().GetEVMChainParams(destChain.ChainId) if !found { - ob.logger.Inbound.Warn(). + ob.Logger().Inbound.Warn(). Msgf("chain id not present in EVMChainParams %d", event.DestinationChainId.Int64()) return nil } if strings.EqualFold(destAddr, paramsDest.ZetaTokenContractAddress) { - ob.logger.Inbound.Warn(). + ob.Logger().Inbound.Warn(). Msgf("potential attack attempt: %s destination address is ZETA token contract address %s", destChain, destAddr) return nil } } message := base64.StdEncoding.EncodeToString(event.Message) - ob.logger.Inbound.Info().Msgf("ZetaSent inbound detected on chain %d tx %s block %d from %s value %s message %s", - ob.chain.ChainId, event.Raw.TxHash.Hex(), event.Raw.BlockNumber, sender, event.ZetaValueAndGas.String(), message) + ob.Logger().Inbound.Info().Msgf("ZetaSent inbound detected on chain %d tx %s block %d from %s value %s message %s", + ob.Chain(). + ChainId, event.Raw.TxHash.Hex(), event.Raw.BlockNumber, sender, event.ZetaValueAndGas.String(), message) return zetacore.GetInboundVoteMessage( sender, - ob.chain.ChainId, + ob.Chain().ChainId, event.SourceTxOriginAddress.Hex(), destAddr, destChain.ChainId, @@ -680,7 +686,7 @@ func (ob *Observer) BuildInboundVoteMsgForZetaSentEvent( event.DestinationGasLimit.Uint64(), coin.CoinType_Zeta, "", - ob.zetacoreClient.GetKeys().GetOperatorAddress().String(), + ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), event.Raw.Index, ) } @@ -700,8 +706,8 @@ func (ob *Observer) BuildInboundVoteMsgForTokenSentToTSS( maybeReceiver = parsedAddress.Hex() } if config.ContainRestrictedAddress(sender.Hex(), maybeReceiver) { - compliance.PrintComplianceLog(ob.logger.Inbound, ob.logger.Compliance, - false, ob.chain.ChainId, tx.Hash, sender.Hex(), sender.Hex(), "Gas") + compliance.PrintComplianceLog(ob.Logger().Inbound, ob.Logger().Compliance, + false, ob.Chain().ChainId, tx.Hash, sender.Hex(), sender.Hex(), "Gas") return nil } @@ -709,19 +715,19 @@ func (ob *Observer) BuildInboundVoteMsgForTokenSentToTSS( // #nosec G703 err is already checked data, _ := hex.DecodeString(message) if bytes.Equal(data, []byte(constant.DonationMessage)) { - ob.logger.Inbound.Info(). - Msgf("thank you rich folk for your donation! tx %s chain %d", tx.Hash, ob.chain.ChainId) + ob.Logger().Inbound.Info(). + Msgf("thank you rich folk for your donation! tx %s chain %d", tx.Hash, ob.Chain().ChainId) return nil } - ob.logger.Inbound.Info().Msgf("TSS inbound detected on chain %d tx %s block %d from %s value %s message %s", - ob.chain.ChainId, tx.Hash, blockNumber, sender.Hex(), tx.Value.String(), message) + ob.Logger().Inbound.Info().Msgf("TSS inbound detected on chain %d tx %s block %d from %s value %s message %s", + ob.Chain().ChainId, tx.Hash, blockNumber, sender.Hex(), tx.Value.String(), message) return zetacore.GetInboundVoteMessage( sender.Hex(), - ob.chain.ChainId, + ob.Chain().ChainId, sender.Hex(), sender.Hex(), - ob.zetacoreClient.Chain().ChainId, + ob.ZetacoreClient().Chain().ChainId, sdkmath.NewUintFromBigInt(&tx.Value), message, tx.Hash, @@ -729,7 +735,7 @@ func (ob *Observer) BuildInboundVoteMsgForTokenSentToTSS( 90_000, coin.CoinType_Gas, "", - ob.zetacoreClient.GetKeys().GetOperatorAddress().String(), + ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), 0, // not a smart contract call ) } @@ -738,15 +744,15 @@ func (ob *Observer) BuildInboundVoteMsgForTokenSentToTSS( func (ob *Observer) ObserveTSSReceiveInBlock(blockNumber uint64) error { block, err := ob.GetBlockByNumberCached(blockNumber) if err != nil { - return errors.Wrapf(err, "error getting block %d for chain %d", blockNumber, ob.chain.ChainId) + return errors.Wrapf(err, "error getting block %d for chain %d", blockNumber, ob.Chain().ChainId) } for i := range block.Transactions { tx := block.Transactions[i] - if ethcommon.HexToAddress(tx.To) == ob.Tss.EVMAddress() { + if ethcommon.HexToAddress(tx.To) == ob.TSS().EVMAddress() { receipt, err := ob.evmClient.TransactionReceipt(context.Background(), ethcommon.HexToHash(tx.Hash)) if err != nil { - return errors.Wrapf(err, "error getting receipt for inbound %s chain %d", tx.Hash, ob.chain.ChainId) + return errors.Wrapf(err, "error getting receipt for inbound %s chain %d", tx.Hash, ob.Chain().ChainId) } _, err = ob.CheckAndVoteInboundTokenGas(&tx, receipt, true) @@ -755,7 +761,7 @@ func (ob *Observer) ObserveTSSReceiveInBlock(blockNumber uint64) error { err, "error checking and voting inbound gas asset for inbound %s chain %d", tx.Hash, - ob.chain.ChainId, + ob.Chain().ChainId, ) } } diff --git a/zetaclient/chains/evm/observer/inbound_test.go b/zetaclient/chains/evm/observer/inbound_test.go index 906634e1ad..bb8930f4ca 100644 --- a/zetaclient/chains/evm/observer/inbound_test.go +++ b/zetaclient/chains/evm/observer/inbound_test.go @@ -40,7 +40,7 @@ func Test_CheckAndVoteInboundTokenZeta(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) ballot, err := ob.CheckAndVoteInboundTokenZeta(tx, receipt, false) require.NoError(t, err) require.Equal(t, cctx.InboundParams.BallotIndex, ballot) @@ -56,7 +56,7 @@ func Test_CheckAndVoteInboundTokenZeta(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - 1 - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) _, err := ob.CheckAndVoteInboundTokenZeta(tx, receipt, false) require.ErrorContains(t, err, "not been confirmed") }) @@ -72,7 +72,7 @@ func Test_CheckAndVoteInboundTokenZeta(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) ballot, err := ob.CheckAndVoteInboundTokenZeta(tx, receipt, true) require.NoError(t, err) require.Equal(t, "", ballot) @@ -89,7 +89,17 @@ func Test_CheckAndVoteInboundTokenZeta(t *testing.T) { lastBlock := receipt.BlockNumber.Uint64() + confirmation chainID = 56 // use BSC chain connector - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, mocks.MockChainParams(chainID, confirmation)) + ob := MockEVMObserver( + t, + chain, + nil, + nil, + nil, + nil, + memDBPath, + lastBlock, + mocks.MockChainParams(chainID, confirmation), + ) _, err := ob.CheckAndVoteInboundTokenZeta(tx, receipt, true) require.ErrorContains(t, err, "emitter address mismatch") }) @@ -115,7 +125,7 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) ballot, err := ob.CheckAndVoteInboundTokenERC20(tx, receipt, false) require.NoError(t, err) require.Equal(t, cctx.InboundParams.BallotIndex, ballot) @@ -131,7 +141,7 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - 1 - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) _, err := ob.CheckAndVoteInboundTokenERC20(tx, receipt, false) require.ErrorContains(t, err, "not been confirmed") }) @@ -147,7 +157,7 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) ballot, err := ob.CheckAndVoteInboundTokenERC20(tx, receipt, true) require.NoError(t, err) require.Equal(t, "", ballot) @@ -164,7 +174,17 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) { lastBlock := receipt.BlockNumber.Uint64() + confirmation chainID = 56 // use BSC chain ERC20 custody - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, mocks.MockChainParams(chainID, confirmation)) + ob := MockEVMObserver( + t, + chain, + nil, + nil, + nil, + nil, + memDBPath, + lastBlock, + mocks.MockChainParams(chainID, confirmation), + ) _, err := ob.CheckAndVoteInboundTokenERC20(tx, receipt, true) require.ErrorContains(t, err, "emitter address mismatch") }) @@ -190,7 +210,7 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) ballot, err := ob.CheckAndVoteInboundTokenGas(tx, receipt, false) require.NoError(t, err) require.Equal(t, cctx.InboundParams.BallotIndex, ballot) @@ -200,7 +220,7 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - 1 - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) _, err := ob.CheckAndVoteInboundTokenGas(tx, receipt, false) require.ErrorContains(t, err, "not been confirmed") }) @@ -210,7 +230,7 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) ballot, err := ob.CheckAndVoteInboundTokenGas(tx, receipt, false) require.ErrorContains(t, err, "not TSS address") require.Equal(t, "", ballot) @@ -221,7 +241,7 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) ballot, err := ob.CheckAndVoteInboundTokenGas(tx, receipt, false) require.ErrorContains(t, err, "not a successful tx") require.Equal(t, "", ballot) @@ -232,7 +252,7 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, lastBlock, chainParam) ballot, err := ob.CheckAndVoteInboundTokenGas(tx, receipt, false) require.NoError(t, err) require.Equal(t, "", ballot) @@ -249,7 +269,7 @@ func Test_BuildInboundVoteMsgForZetaSentEvent(t *testing.T) { cctx := testutils.LoadCctxByInbound(t, chainID, coin.CoinType_Zeta, inboundHash) // parse ZetaSent event - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(1, 1)) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, 1, mocks.MockChainParams(1, 1)) connector := mocks.MockConnectorNonEth(t, chainID) event := testutils.ParseReceiptZetaSent(receipt, connector) @@ -296,7 +316,7 @@ func Test_BuildInboundVoteMsgForDepositedEvent(t *testing.T) { cctx := testutils.LoadCctxByInbound(t, chainID, coin.CoinType_ERC20, inboundHash) // parse Deposited event - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(1, 1)) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, 1, mocks.MockChainParams(1, 1)) custody := mocks.MockERC20Custody(t, chainID) event := testutils.ParseReceiptERC20Deposited(receipt, custody) sender := ethcommon.HexToAddress(tx.From) @@ -354,7 +374,7 @@ func Test_BuildInboundVoteMsgForTokenSentToTSS(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(txDonation)) // create test compliance config - ob := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(1, 1)) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, 1, mocks.MockChainParams(1, 1)) cfg := config.Config{ ComplianceConfig: config.ComplianceConfig{}, } @@ -424,7 +444,7 @@ func Test_ObserveTSSReceiveInBlock(t *testing.T) { lastBlock := receipt.BlockNumber.Uint64() + confirmation t.Run("should observe TSS receive in block", func(t *testing.T) { - ob := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, memDBPath, lastBlock, chainParam) // feed archived block and receipt evmJSONRPC.WithBlock(block) @@ -433,20 +453,20 @@ func Test_ObserveTSSReceiveInBlock(t *testing.T) { require.NoError(t, err) }) t.Run("should not observe on error getting block", func(t *testing.T) { - ob := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, memDBPath, lastBlock, chainParam) err := ob.ObserveTSSReceiveInBlock(blockNumber) // error getting block is expected because the mock JSONRPC contains no block require.ErrorContains(t, err, "error getting block") }) t.Run("should not observe on error getting receipt", func(t *testing.T) { - ob := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, memDBPath, lastBlock, chainParam) evmJSONRPC.WithBlock(block) err := ob.ObserveTSSReceiveInBlock(blockNumber) // error getting block is expected because the mock evmClient contains no receipt require.ErrorContains(t, err, "error getting receipt") }) t.Run("should not observe on error posting vote", func(t *testing.T) { - ob := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, lastBlock, chainParam) + ob := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, memDBPath, lastBlock, chainParam) // feed archived block and pause zetacore client evmJSONRPC.WithBlock(block) diff --git a/zetaclient/chains/evm/observer/observer.go b/zetaclient/chains/evm/observer/observer.go index 0b3c02113c..3db0538870 100644 --- a/zetaclient/chains/evm/observer/observer.go +++ b/zetaclient/chains/evm/observer/observer.go @@ -5,29 +5,19 @@ import ( "fmt" "math" "math/big" - "os" - "strconv" "strings" - "sync" - "sync/atomic" "time" ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rlp" - lru "github.com/hashicorp/golang-lru" "github.com/onrik/ethrpc" "github.com/pkg/errors" - "github.com/rs/zerolog" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zeta.non-eth.sol" zetaconnectoreth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.eth.sol" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.non-eth.sol" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/proofs" observertypes "github.com/zeta-chain/zetacore/x/observer/types" "github.com/zeta-chain/zetacore/zetaclient/chains/base" @@ -39,225 +29,124 @@ import ( clienttypes "github.com/zeta-chain/zetacore/zetaclient/types" ) -// Logger is the logger for evm chains -// TODO: Merge this logger with the one in bitcoin -// https://github.com/zeta-chain/node/issues/2022 -type Logger struct { - // Chain is the parent logger for the chain - Chain zerolog.Logger +var _ interfaces.ChainObserver = &Observer{} - // Inbound is the logger for incoming transactions - Inbound zerolog.Logger +// Observer is the observer for evm chains +type Observer struct { + // base.Observer implements the base chain observer + base.Observer - // Outbound is the logger for outgoing transactions - Outbound zerolog.Logger + // evmClient is the EVM client for the observed chain + evmClient interfaces.EVMRPCClient - // GasPrice is the logger for gas prices - GasPrice zerolog.Logger + // evmJSONRPC is the EVM JSON RPC client for the observed chain + evmJSONRPC interfaces.EVMJSONRPCClient - // Compliance is the logger for compliance checks - Compliance zerolog.Logger -} + // outboundPendingTransactions is the map to index pending transactions by hash + outboundPendingTransactions map[string]*ethtypes.Transaction -var _ interfaces.ChainObserver = &Observer{} + // outboundConfirmedReceipts is the map to index confirmed receipts by hash + outboundConfirmedReceipts map[string]*ethtypes.Receipt -// Observer is the observer for evm chains -type Observer struct { - Tss interfaces.TSSSigner - - Mu *sync.Mutex - - chain chains.Chain - evmClient interfaces.EVMRPCClient - evmJSONRPC interfaces.EVMJSONRPCClient - zetacoreClient interfaces.ZetacoreClient - lastBlockScanned uint64 - lastBlock uint64 - db *gorm.DB - outboundPendingTransactions map[string]*ethtypes.Transaction - outboundConfirmedReceipts map[string]*ethtypes.Receipt + // outboundConfirmedTransactions is the map to index confirmed transactions by hash outboundConfirmedTransactions map[string]*ethtypes.Transaction - stop chan struct{} - logger Logger - coreContext *clientcontext.ZetacoreContext - chainParams observertypes.ChainParams - ts *metrics.TelemetryServer - - blockCache *lru.Cache - headerCache *lru.Cache } // NewObserver returns a new EVM chain observer func NewObserver( - appContext *clientcontext.AppContext, + evmCfg config.EVMConfig, + evmClient interfaces.EVMRPCClient, + chainParams observertypes.ChainParams, + zetacoreContext *clientcontext.ZetacoreContext, zetacoreClient interfaces.ZetacoreClient, tss interfaces.TSSSigner, dbpath string, logger base.Logger, - evmCfg config.EVMConfig, ts *metrics.TelemetryServer, ) (*Observer, error) { - ob := Observer{ - ts: ts, - } - - chainLogger := logger.Std.With().Str("chain", evmCfg.Chain.ChainName.String()).Logger() - ob.logger = Logger{ - Chain: chainLogger, - Inbound: chainLogger.With().Str("module", "WatchInbound").Logger(), - Outbound: chainLogger.With().Str("module", "WatchOutbound").Logger(), - GasPrice: chainLogger.With().Str("module", "WatchGasPrice").Logger(), - Compliance: logger.Compliance, - } - - ob.coreContext = appContext.ZetacoreContext() - chainParams, found := ob.coreContext.GetEVMChainParams(evmCfg.Chain.ChainId) - if !found { - return nil, fmt.Errorf("evm chains params not initialized for chain %d", evmCfg.Chain.ChainId) - } - - ob.chainParams = *chainParams - ob.stop = make(chan struct{}) - ob.chain = evmCfg.Chain - ob.Mu = &sync.Mutex{} - ob.zetacoreClient = zetacoreClient - ob.Tss = tss - ob.outboundPendingTransactions = make(map[string]*ethtypes.Transaction) - ob.outboundConfirmedReceipts = make(map[string]*ethtypes.Receipt) - ob.outboundConfirmedTransactions = make(map[string]*ethtypes.Transaction) - - ob.logger.Chain.Info().Msgf("Chain %s endpoint %s", ob.chain.ChainName.String(), evmCfg.Endpoint) - client, err := ethclient.Dial(evmCfg.Endpoint) - if err != nil { - ob.logger.Chain.Error().Err(err).Msg("eth Client Dial") - return nil, err - } - - ob.evmClient = client - ob.evmJSONRPC = ethrpc.NewEthRPC(evmCfg.Endpoint) - - // create block header and block caches - ob.blockCache, err = lru.New(1000) + // create base observer + baseObserver, err := base.NewObserver( + evmCfg.Chain, + chainParams, + zetacoreContext, + zetacoreClient, + tss, + base.DefaultBlockCacheSize, + base.DefaultHeaderCacheSize, + ts, + logger, + ) if err != nil { - ob.logger.Chain.Error().Err(err).Msg("failed to create block cache") return nil, err } - ob.headerCache, err = lru.New(1000) - if err != nil { - ob.logger.Chain.Error().Err(err).Msg("failed to create header cache") - return nil, err + // create evm observer + ob := &Observer{ + Observer: *baseObserver, + evmClient: evmClient, + evmJSONRPC: ethrpc.NewEthRPC(evmCfg.Endpoint), + outboundPendingTransactions: make(map[string]*ethtypes.Transaction), + outboundConfirmedReceipts: make(map[string]*ethtypes.Receipt), + outboundConfirmedTransactions: make(map[string]*ethtypes.Transaction), } - err = ob.LoadDB(dbpath, ob.chain) + // open database and load data + err = ob.LoadDB(dbpath) if err != nil { return nil, err } - ob.logger.Chain.Info().Msgf("%s: start scanning from block %d", ob.chain.String(), ob.GetLastBlockHeightScanned()) - - return &ob, nil -} - -// WithChain attaches a new chain to the observer -func (ob *Observer) WithChain(chain chains.Chain) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.chain = chain -} - -// WithLogger attaches a new logger to the observer -func (ob *Observer) WithLogger(logger zerolog.Logger) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.logger = Logger{ - Chain: logger, - Inbound: logger.With().Str("module", "WatchInbound").Logger(), - Outbound: logger.With().Str("module", "WatchOutbound").Logger(), - GasPrice: logger.With().Str("module", "WatchGasPrice").Logger(), - } + return ob, nil } // WithEvmClient attaches a new evm client to the observer func (ob *Observer) WithEvmClient(client interfaces.EVMRPCClient) { - ob.Mu.Lock() - defer ob.Mu.Unlock() ob.evmClient = client } // WithEvmJSONRPC attaches a new evm json rpc client to the observer func (ob *Observer) WithEvmJSONRPC(client interfaces.EVMJSONRPCClient) { - ob.Mu.Lock() - defer ob.Mu.Unlock() ob.evmJSONRPC = client } -// WithZetacoreClient attaches a new client to interact with zetacore to the observer -func (ob *Observer) WithZetacoreClient(client interfaces.ZetacoreClient) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.zetacoreClient = client -} - -// WithBlockCache attaches a new block cache to the observer -func (ob *Observer) WithBlockCache(cache *lru.Cache) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.blockCache = cache -} - -// Chain returns the chain for the observer -func (ob *Observer) Chain() chains.Chain { - ob.Mu.Lock() - defer ob.Mu.Unlock() - return ob.chain -} - // SetChainParams sets the chain params for the observer +// Note: chain params is accessed concurrently func (ob *Observer) SetChainParams(params observertypes.ChainParams) { - ob.Mu.Lock() - defer ob.Mu.Unlock() - ob.chainParams = params + ob.Mu().Lock() + defer ob.Mu().Unlock() + ob.WithChainParams(params) } // GetChainParams returns the chain params for the observer +// Note: chain params is accessed concurrently func (ob *Observer) GetChainParams() observertypes.ChainParams { - ob.Mu.Lock() - defer ob.Mu.Unlock() - return ob.chainParams + ob.Mu().Lock() + defer ob.Mu().Unlock() + return ob.ChainParams() } +// GetConnectorContract returns the non-Eth connector address and binder func (ob *Observer) GetConnectorContract() (ethcommon.Address, *zetaconnector.ZetaConnectorNonEth, error) { addr := ethcommon.HexToAddress(ob.GetChainParams().ConnectorContractAddress) - contract, err := FetchConnectorContract(addr, ob.evmClient) + contract, err := zetaconnector.NewZetaConnectorNonEth(addr, ob.evmClient) return addr, contract, err } +// GetConnectorContractEth returns the Eth connector address and binder func (ob *Observer) GetConnectorContractEth() (ethcommon.Address, *zetaconnectoreth.ZetaConnectorEth, error) { addr := ethcommon.HexToAddress(ob.GetChainParams().ConnectorContractAddress) contract, err := FetchConnectorContractEth(addr, ob.evmClient) return addr, contract, err } -func (ob *Observer) GetZetaTokenNonEthContract() (ethcommon.Address, *zeta.ZetaNonEth, error) { - addr := ethcommon.HexToAddress(ob.GetChainParams().ZetaTokenContractAddress) - contract, err := FetchZetaZetaNonEthTokenContract(addr, ob.evmClient) - return addr, contract, err -} - +// GetERC20CustodyContract returns ERC20Custody contract address and binder func (ob *Observer) GetERC20CustodyContract() (ethcommon.Address, *erc20custody.ERC20Custody, error) { addr := ethcommon.HexToAddress(ob.GetChainParams().Erc20CustodyContractAddress) - contract, err := FetchERC20CustodyContract(addr, ob.evmClient) + contract, err := erc20custody.NewERC20Custody(addr, ob.evmClient) return addr, contract, err } -func FetchConnectorContract( - addr ethcommon.Address, - client interfaces.EVMRPCClient, -) (*zetaconnector.ZetaConnectorNonEth, error) { - return zetaconnector.NewZetaConnectorNonEth(addr, client) -} - +// FetchConnectorContractEth returns the Eth connector address and binder func FetchConnectorContractEth( addr ethcommon.Address, client interfaces.EVMRPCClient, @@ -265,22 +154,18 @@ func FetchConnectorContractEth( return zetaconnectoreth.NewZetaConnectorEth(addr, client) } -func FetchZetaZetaNonEthTokenContract( +// FetchZetaTokenContract returns the non-Eth ZETA token binder +func FetchZetaTokenContract( addr ethcommon.Address, client interfaces.EVMRPCClient, ) (*zeta.ZetaNonEth, error) { return zeta.NewZetaNonEth(addr, client) } -func FetchERC20CustodyContract( - addr ethcommon.Address, - client interfaces.EVMRPCClient, -) (*erc20custody.ERC20Custody, error) { - return erc20custody.NewERC20Custody(addr, client) -} - // Start all observation routines for the evm chain func (ob *Observer) Start() { + ob.Logger().Chain.Info().Msgf("observer is starting for chain %d", ob.Chain().ChainId) + // watch evm chain for incoming txs and post votes to zetacore go ob.WatchInbound() @@ -299,7 +184,7 @@ func (ob *Observer) Start() { // WatchRPCStatus watches the RPC status of the evm chain func (ob *Observer) WatchRPCStatus() { - ob.logger.Chain.Info().Msgf("Starting RPC status check for chain %s", ob.chain.String()) + ob.Logger().Chain.Info().Msgf("Starting RPC status check for chain %d", ob.Chain().ChainId) ticker := time.NewTicker(60 * time.Second) for { select { @@ -309,70 +194,53 @@ func (ob *Observer) WatchRPCStatus() { } bn, err := ob.evmClient.BlockNumber(context.Background()) if err != nil { - ob.logger.Chain.Error().Err(err).Msg("RPC Status Check error: RPC down?") + ob.Logger().Chain.Error().Err(err).Msg("RPC Status Check error: RPC down?") continue } gasPrice, err := ob.evmClient.SuggestGasPrice(context.Background()) if err != nil { - ob.logger.Chain.Error().Err(err).Msg("RPC Status Check error: RPC down?") + ob.Logger().Chain.Error().Err(err).Msg("RPC Status Check error: RPC down?") continue } header, err := ob.evmClient.HeaderByNumber(context.Background(), new(big.Int).SetUint64(bn)) if err != nil { - ob.logger.Chain.Error().Err(err).Msg("RPC Status Check error: RPC down?") + ob.Logger().Chain.Error().Err(err).Msg("RPC Status Check error: RPC down?") continue } // #nosec G701 always in range blockTime := time.Unix(int64(header.Time), 0).UTC() elapsedSeconds := time.Since(blockTime).Seconds() if elapsedSeconds > 100 { - ob.logger.Chain.Warn(). + ob.Logger().Chain.Warn(). Msgf("RPC Status Check warning: RPC stale or chain stuck (check explorer)? Latest block %d timestamp is %.0fs ago", bn, elapsedSeconds) continue } - ob.logger.Chain.Info(). + ob.Logger().Chain.Info(). Msgf("[OK] RPC status: latest block num %d, timestamp %s ( %.0fs ago), suggested gas price %d", header.Number, blockTime.String(), elapsedSeconds, gasPrice.Uint64()) - case <-ob.stop: + case <-ob.StopChannel(): return } } } -func (ob *Observer) Stop() { - ob.logger.Chain.Info().Msgf("ob %s is stopping", ob.chain.String()) - close(ob.stop) // this notifies all goroutines to stop - - ob.logger.Chain.Info().Msg("closing ob.db") - dbInst, err := ob.db.DB() - if err != nil { - ob.logger.Chain.Info().Msg("error getting database instance") - } - err = dbInst.Close() - if err != nil { - ob.logger.Chain.Error().Err(err).Msg("error closing database") - } - - ob.logger.Chain.Info().Msgf("%s observer stopped", ob.chain.String()) -} - // SetPendingTx sets the pending transaction in memory func (ob *Observer) SetPendingTx(nonce uint64, transaction *ethtypes.Transaction) { - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() ob.outboundPendingTransactions[ob.GetTxID(nonce)] = transaction } // GetPendingTx gets the pending transaction from memory func (ob *Observer) GetPendingTx(nonce uint64) *ethtypes.Transaction { - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() return ob.outboundPendingTransactions[ob.GetTxID(nonce)] } // SetTxNReceipt sets the receipt and transaction in memory func (ob *Observer) SetTxNReceipt(nonce uint64, receipt *ethtypes.Receipt, transaction *ethtypes.Transaction) { - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() delete(ob.outboundPendingTransactions, ob.GetTxID(nonce)) // remove pending transaction, if any ob.outboundConfirmedReceipts[ob.GetTxID(nonce)] = receipt ob.outboundConfirmedTransactions[ob.GetTxID(nonce)] = transaction @@ -380,8 +248,8 @@ func (ob *Observer) SetTxNReceipt(nonce uint64, receipt *ethtypes.Receipt, trans // GetTxNReceipt gets the receipt and transaction from memory func (ob *Observer) GetTxNReceipt(nonce uint64) (*ethtypes.Receipt, *ethtypes.Transaction) { - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() receipt := ob.outboundConfirmedReceipts[ob.GetTxID(nonce)] transaction := ob.outboundConfirmedTransactions[ob.GetTxID(nonce)] return receipt, transaction @@ -389,8 +257,8 @@ func (ob *Observer) GetTxNReceipt(nonce uint64) (*ethtypes.Receipt, *ethtypes.Tr // IsTxConfirmed returns true if there is a confirmed tx for 'nonce' func (ob *Observer) IsTxConfirmed(nonce uint64) bool { - ob.Mu.Lock() - defer ob.Mu.Unlock() + ob.Mu().Lock() + defer ob.Mu().Unlock() return ob.outboundConfirmedReceipts[ob.GetTxID(nonce)] != nil && ob.outboundConfirmedTransactions[ob.GetTxID(nonce)] != nil } @@ -419,47 +287,25 @@ func (ob *Observer) CheckTxInclusion(tx *ethtypes.Transaction, receipt *ethtypes return nil } -// SetLastBlockHeightScanned set last block height scanned (not necessarily caught up with external block; could be slow/paused) -func (ob *Observer) SetLastBlockHeightScanned(height uint64) { - atomic.StoreUint64(&ob.lastBlockScanned, height) - ob.ts.SetLastScannedBlockNumber(ob.chain, height) -} - -// GetLastBlockHeightScanned get last block height scanned (not necessarily caught up with external block; could be slow/paused) -func (ob *Observer) GetLastBlockHeightScanned() uint64 { - height := atomic.LoadUint64(&ob.lastBlockScanned) - return height -} - -// SetLastBlockHeight set external last block height -func (ob *Observer) SetLastBlockHeight(height uint64) { - atomic.StoreUint64(&ob.lastBlock, height) -} - -// GetLastBlockHeight get external last block height -func (ob *Observer) GetLastBlockHeight() uint64 { - return atomic.LoadUint64(&ob.lastBlock) -} - // WatchGasPrice watches evm chain for gas prices and post to zetacore func (ob *Observer) WatchGasPrice() { // report gas price right away as the ticker takes time to kick in err := ob.PostGasPrice() if err != nil { - ob.logger.GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.chain.ChainId) + ob.Logger().GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.Chain().ChainId) } // start gas price ticker ticker, err := clienttypes.NewDynamicTicker( - fmt.Sprintf("EVM_WatchGasPrice_%d", ob.chain.ChainId), + fmt.Sprintf("EVM_WatchGasPrice_%d", ob.Chain().ChainId), ob.GetChainParams().GasPriceTicker, ) if err != nil { - ob.logger.GasPrice.Error().Err(err).Msg("NewDynamicTicker error") + ob.Logger().GasPrice.Error().Err(err).Msg("NewDynamicTicker error") return } - ob.logger.GasPrice.Info().Msgf("WatchGasPrice started for chain %d with interval %d", - ob.chain.ChainId, ob.GetChainParams().GasPriceTicker) + ob.Logger().GasPrice.Info().Msgf("WatchGasPrice started for chain %d with interval %d", + ob.Chain().ChainId, ob.GetChainParams().GasPriceTicker) defer ticker.Stop() for { @@ -470,11 +316,11 @@ func (ob *Observer) WatchGasPrice() { } err = ob.PostGasPrice() if err != nil { - ob.logger.GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.chain.ChainId) + ob.Logger().GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.Chain().ChainId) } - ticker.UpdateInterval(ob.GetChainParams().GasPriceTicker, ob.logger.GasPrice) - case <-ob.stop: - ob.logger.GasPrice.Info().Msg("WatchGasPrice stopped") + ticker.UpdateInterval(ob.GetChainParams().GasPriceTicker, ob.Logger().GasPrice) + case <-ob.StopChannel(): + ob.Logger().GasPrice.Info().Msg("WatchGasPrice stopped") return } } @@ -484,21 +330,21 @@ func (ob *Observer) PostGasPrice() error { // GAS PRICE gasPrice, err := ob.evmClient.SuggestGasPrice(context.TODO()) if err != nil { - ob.logger.GasPrice.Err(err).Msg("Err SuggestGasPrice:") + ob.Logger().GasPrice.Err(err).Msg("Err SuggestGasPrice:") return err } blockNum, err := ob.evmClient.BlockNumber(context.TODO()) if err != nil { - ob.logger.GasPrice.Err(err).Msg("Err Fetching Most recent Block : ") + ob.Logger().GasPrice.Err(err).Msg("Err Fetching Most recent Block : ") return err } // SUPPLY supply := "100" // lockedAmount on ETH, totalSupply on other chains - zetaHash, err := ob.zetacoreClient.PostGasPrice(ob.chain, gasPrice.Uint64(), supply, blockNum) + zetaHash, err := ob.ZetacoreClient().PostGasPrice(ob.Chain(), gasPrice.Uint64(), supply, blockNum) if err != nil { - ob.logger.GasPrice.Err(err).Msg("PostGasPrice to zetacore failed") + ob.Logger().GasPrice.Err(err).Msg("PostGasPrice to zetacore failed") return err } _ = zetaHash @@ -520,22 +366,28 @@ func (ob *Observer) TransactionByHash(txHash string) (*ethrpc.Transaction, bool, } func (ob *Observer) GetBlockHeaderCached(blockNumber uint64) (*ethtypes.Header, error) { - if header, ok := ob.headerCache.Get(blockNumber); ok { - return header.(*ethtypes.Header), nil + if result, ok := ob.HeaderCache().Get(blockNumber); ok { + if header, ok := result.(*ethtypes.Header); ok { + return header, nil + } + return nil, errors.New("cached value is not of type *ethtypes.Header") } header, err := ob.evmClient.HeaderByNumber(context.Background(), new(big.Int).SetUint64(blockNumber)) if err != nil { return nil, err } - ob.headerCache.Add(blockNumber, header) + ob.HeaderCache().Add(blockNumber, header) return header, nil } // GetBlockByNumberCached get block by number from cache // returns block, ethrpc.Block, isFallback, isSkip, error func (ob *Observer) GetBlockByNumberCached(blockNumber uint64) (*ethrpc.Block, error) { - if block, ok := ob.blockCache.Get(blockNumber); ok { - return block.(*ethrpc.Block), nil + if result, ok := ob.BlockCache().Get(blockNumber); ok { + if block, ok := result.(*ethrpc.Block); ok { + return block, nil + } + return nil, errors.New("cached value is not of type *ethrpc.Block") } if blockNumber > math.MaxInt32 { return nil, fmt.Errorf("block number %d is too large", blockNumber) @@ -545,13 +397,13 @@ func (ob *Observer) GetBlockByNumberCached(blockNumber uint64) (*ethrpc.Block, e if err != nil { return nil, err } - ob.blockCache.Add(blockNumber, block) + ob.BlockCache().Add(blockNumber, block) return block, nil } // RemoveCachedBlock remove block from cache func (ob *Observer) RemoveCachedBlock(blockNumber uint64) { - ob.blockCache.Remove(blockNumber) + ob.BlockCache().Remove(blockNumber) } // BlockByNumber query block by number via JSON-RPC @@ -569,92 +421,60 @@ func (ob *Observer) BlockByNumber(blockNumber int) (*ethrpc.Block, error) { return block, nil } -// LoadLastScannedBlock loads last scanned block from specified height or from database -// The last scanned block is the height from which the observer should continue scanning for inbound transactions -func (ob *Observer) LoadLastScannedBlock() error { - // get environment variable - envvar := ob.chain.ChainName.String() + "_SCAN_FROM" - scanFromBlock := os.Getenv(envvar) - - // load from environment variable if set - if scanFromBlock != "" { - ob.logger.Chain.Info(). - Msgf("LoadLastScannedBlock: envvar %s is set; scan from block %s", envvar, scanFromBlock) - if scanFromBlock == base.EnvVarLatestBlock { - header, err := ob.evmClient.HeaderByNumber(context.Background(), nil) - if err != nil { - return err - } - ob.SetLastBlockHeightScanned(header.Number.Uint64()) - } else { - scanFromBlockInt, err := strconv.ParseUint(scanFromBlock, 10, 64) - if err != nil { - return err - } - ob.SetLastBlockHeightScanned(scanFromBlockInt) - } - } else { - // load from DB otherwise - var lastBlock clienttypes.LastBlockSQLType - if err := ob.db.First(&lastBlock, clienttypes.LastBlockNumID).Error; err != nil { - ob.logger.Chain.Info().Msg("LoadLastScannedBlock: last scanned block not found in DB, scan from latest") - header, err := ob.evmClient.HeaderByNumber(context.Background(), nil) - if err != nil { - return err - } - ob.SetLastBlockHeightScanned(header.Number.Uint64()) - if dbc := ob.db.Save(clienttypes.ToLastBlockSQLType(ob.GetLastBlockHeightScanned())); dbc.Error != nil { - ob.logger.Chain.Error().Err(dbc.Error).Msgf("LoadLastScannedBlock: error writing last scanned block %d to DB", ob.GetLastBlockHeightScanned()) - } - } else { - ob.SetLastBlockHeightScanned(lastBlock.Num) - } +// LoadDB open sql database and load data into EVM observer +func (ob *Observer) LoadDB(dbPath string) error { + if dbPath == "" { + return errors.New("empty db path") } - ob.logger.Chain.Info(). - Msgf("LoadLastScannedBlock: chain %d starts scanning from block %d", ob.chain.ChainId, ob.GetLastBlockHeightScanned()) - return nil -} + // open database + err := ob.OpenDB(dbPath, "") + if err != nil { + return errors.Wrapf(err, "error OpenDB for chain %d", ob.Chain().ChainId) + } -// LoadDB open sql database and load data into EVM observer -func (ob *Observer) LoadDB(dbPath string, chain chains.Chain) error { - if dbPath != "" { - if _, err := os.Stat(dbPath); os.IsNotExist(err) { - err := os.MkdirAll(dbPath, os.ModePerm) - if err != nil { - return err - } - } - path := fmt.Sprintf("%s/%s", dbPath, chain.ChainName.String()) //Use "file::memory:?cache=shared" for temp db - db, err := gorm.Open(sqlite.Open(path), &gorm.Config{}) - if err != nil { - ob.logger.Chain.Error(). - Err(err). - Msgf("failed to open observer database for %s", ob.chain.ChainName.String()) - return err - } + // run auto migration + // transaction and receipt tables are used nowhere but we still run migration in case they are needed in future + err = ob.DB().AutoMigrate( + &clienttypes.ReceiptSQLType{}, + &clienttypes.TransactionSQLType{}, + ) + if err != nil { + return errors.Wrapf(err, "error AutoMigrate for chain %d", ob.Chain().ChainId) + } - err = db.AutoMigrate(&clienttypes.ReceiptSQLType{}, - &clienttypes.TransactionSQLType{}, - &clienttypes.LastBlockSQLType{}) - if err != nil { - ob.logger.Chain.Error().Err(err).Msg("error migrating db") - return err - } + // load last block scanned + err = ob.LoadLastBlockScanned() - ob.db = db - err = ob.LoadLastScannedBlock() + return err +} + +// LoadLastBlockScanned loads the last scanned block from the database +func (ob *Observer) LoadLastBlockScanned() error { + err := ob.Observer.LoadLastBlockScanned(ob.Logger().Chain) + if err != nil { + return errors.Wrapf(err, "error LoadLastBlockScanned for chain %d", ob.Chain().ChainId) + } + + // observer will scan from the last block when 'lastBlockScanned == 0', this happens when: + // 1. environment variable is set explicitly to "latest" + // 2. environment variable is empty and last scanned block is not found in DB + if ob.LastBlockScanned() == 0 { + blockNumber, err := ob.evmClient.BlockNumber(context.Background()) if err != nil { - return err + return errors.Wrapf(err, "error BlockNumber for chain %d", ob.Chain().ChainId) } + ob.WithLastBlockScanned(blockNumber) } + ob.Logger().Chain.Info().Msgf("chain %d starts scanning from block %d", ob.Chain().ChainId, ob.LastBlockScanned()) + return nil } func (ob *Observer) postBlockHeader(tip uint64) error { bn := tip - res, err := ob.zetacoreClient.GetBlockHeaderChainState(ob.chain.ChainId) + res, err := ob.ZetacoreClient().GetBlockHeaderChainState(ob.Chain().ChainId) if err == nil && res.ChainState != nil && res.ChainState.EarliestHeight > 0 { // #nosec G701 always positive bn = uint64(res.ChainState.LatestHeight) + 1 // the next header to post @@ -666,23 +486,23 @@ func (ob *Observer) postBlockHeader(tip uint64) error { header, err := ob.GetBlockHeaderCached(bn) if err != nil { - ob.logger.Inbound.Error().Err(err).Msgf("postBlockHeader: error getting block: %d", bn) + ob.Logger().Inbound.Error().Err(err).Msgf("postBlockHeader: error getting block: %d", bn) return err } headerRLP, err := rlp.EncodeToBytes(header) if err != nil { - ob.logger.Inbound.Error().Err(err).Msgf("postBlockHeader: error encoding block header: %d", bn) + ob.Logger().Inbound.Error().Err(err).Msgf("postBlockHeader: error encoding block header: %d", bn) return err } - _, err = ob.zetacoreClient.PostVoteBlockHeader( - ob.chain.ChainId, + _, err = ob.ZetacoreClient().PostVoteBlockHeader( + ob.Chain().ChainId, header.Hash().Bytes(), header.Number.Int64(), proofs.NewEthereumHeader(headerRLP), ) if err != nil { - ob.logger.Inbound.Error().Err(err).Msgf("postBlockHeader: error posting block header: %d", bn) + ob.Logger().Inbound.Error().Err(err).Msgf("postBlockHeader: error posting block header: %d", bn) return err } return nil diff --git a/zetaclient/chains/evm/observer/observer_test.go b/zetaclient/chains/evm/observer/observer_test.go index 0601c083f2..f149d1bae2 100644 --- a/zetaclient/chains/evm/observer/observer_test.go +++ b/zetaclient/chains/evm/observer/observer_test.go @@ -1,10 +1,13 @@ package observer_test import ( - "sync" + "fmt" + "math/big" + "os" "testing" "cosmossdk.io/math" + ethtypes "github.com/ethereum/go-ethereum/core/types" lru "github.com/hashicorp/golang-lru" "github.com/onrik/ethrpc" "github.com/rs/zerolog" @@ -21,6 +24,7 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/config" "github.com/zeta-chain/zetacore/zetaclient/context" "github.com/zeta-chain/zetacore/zetaclient/keys" + "github.com/zeta-chain/zetacore/zetaclient/metrics" "github.com/zeta-chain/zetacore/zetaclient/testutils" "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" ) @@ -28,17 +32,24 @@ import ( // the relative path to the testdata directory var TestDataDir = "../../../" -// getAppContext creates an app context for unit tests -func getAppContext( +// getZetacoreContext creates a zetacore context for unit tests +func getZetacoreContext( evmChain chains.Chain, + endpoint string, evmChainParams *observertypes.ChainParams, -) (*context.AppContext, config.EVMConfig) { +) (*context.ZetacoreContext, config.EVMConfig) { + // use default endpoint if not provided + if endpoint == "" { + endpoint = "http://localhost:8545" + } + // create config cfg := config.NewConfig() cfg.EVMChainConfigs[evmChain.ChainId] = config.EVMConfig{ Chain: evmChain, - Endpoint: "http://localhost:8545", + Endpoint: endpoint, } + // create zetacore context coreCtx := context.NewZetacoreContext(cfg) evmChainParamsMap := make(map[int64]*observertypes.ChainParams) @@ -57,8 +68,7 @@ func getAppContext( zerolog.Logger{}, ) // create app context - appCtx := context.NewAppContext(coreCtx, cfg) - return appCtx, cfg.EVMChainConfigs[evmChain.ChainId] + return coreCtx, cfg.EVMChainConfigs[evmChain.ChainId] } // MockEVMObserver creates a mock ChainObserver with custom chain, TSS, params etc @@ -69,8 +79,15 @@ func MockEVMObserver( evmJSONRPC interfaces.EVMJSONRPCClient, zetacoreClient interfaces.ZetacoreClient, tss interfaces.TSSSigner, + dbpath string, lastBlock uint64, - params observertypes.ChainParams) *observer.Observer { + params observertypes.ChainParams, +) *observer.Observer { + // use default mock evm client if not provided + if evmClient == nil { + evmClient = mocks.NewMockEvmClient().WithBlockNumber(1000) + } + // use default mock zetacore client if not provided if zetacoreClient == nil { zetacoreClient = mocks.NewMockZetacoreClient().WithKeys(&keys.Keys{}) @@ -79,44 +96,310 @@ func MockEVMObserver( if tss == nil { tss = mocks.NewTSSMainnet() } - // create app context - appCtx, evmCfg := getAppContext(chain, ¶ms) + // create zetacore context + coreCtx, evmCfg := getZetacoreContext(chain, "", ¶ms) - // create chain observer - client, err := observer.NewObserver(appCtx, zetacoreClient, tss, "", base.Logger{}, evmCfg, nil) + // create observer + ob, err := observer.NewObserver(evmCfg, evmClient, params, coreCtx, zetacoreClient, tss, dbpath, base.Logger{}, nil) require.NoError(t, err) - client.WithEvmClient(evmClient) - client.WithEvmJSONRPC(evmJSONRPC) - client.SetLastBlockHeight(lastBlock) + ob.WithEvmJSONRPC(evmJSONRPC) + ob.WithLastBlock(lastBlock) - return client + return ob } -func Test_BlockCache(t *testing.T) { - // create client - blockCache, err := lru.New(1000) - require.NoError(t, err) - ob := &observer.Observer{Mu: &sync.Mutex{}} - ob.WithBlockCache(blockCache) +func Test_NewObserver(t *testing.T) { + // use Ethereum chain for testing + chain := chains.Ethereum + params := mocks.MockChainParams(chain.ChainId, 10) + + // test cases + tests := []struct { + name string + evmCfg config.EVMConfig + chainParams observertypes.ChainParams + evmClient interfaces.EVMRPCClient + tss interfaces.TSSSigner + dbpath string + logger base.Logger + ts *metrics.TelemetryServer + fail bool + message string + }{ + { + name: "should be able to create observer", + evmCfg: config.EVMConfig{ + Chain: chain, + Endpoint: "http://localhost:8545", + }, + chainParams: params, + evmClient: mocks.NewMockEvmClient().WithBlockNumber(1000), + tss: mocks.NewTSSMainnet(), + dbpath: sample.CreateTempDir(t), + logger: base.Logger{}, + ts: nil, + fail: false, + }, + { + name: "should fail on invalid dbpath", + evmCfg: config.EVMConfig{ + Chain: chain, + Endpoint: "http://localhost:8545", + }, + chainParams: params, + evmClient: mocks.NewMockEvmClient().WithBlockNumber(1000), + tss: mocks.NewTSSMainnet(), + dbpath: "/invalid/dbpath", // invalid dbpath + logger: base.Logger{}, + ts: nil, + fail: true, + message: "error creating db path", + }, + { + name: "should fail if RPC call fails", + evmCfg: config.EVMConfig{ + Chain: chain, + Endpoint: "http://localhost:8545", + }, + chainParams: params, + evmClient: mocks.NewMockEvmClient().WithError(fmt.Errorf("error RPC")), + tss: mocks.NewTSSMainnet(), + dbpath: sample.CreateTempDir(t), + logger: base.Logger{}, + ts: nil, + fail: true, + message: "error RPC", + }, + } + + // run tests + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // create zetacore context, client and tss + zetacoreCtx, _ := getZetacoreContext(tt.evmCfg.Chain, tt.evmCfg.Endpoint, ¶ms) + zetacoreClient := mocks.NewMockZetacoreClient().WithKeys(&keys.Keys{}) - // delete non-existing block should not panic - blockNumber := uint64(10388180) - ob.RemoveCachedBlock(blockNumber) + // create observer + ob, err := observer.NewObserver( + tt.evmCfg, + tt.evmClient, + tt.chainParams, + zetacoreCtx, + zetacoreClient, + tt.tss, + tt.dbpath, + tt.logger, + tt.ts, + ) - // add a block - block := ðrpc.Block{ - // #nosec G701 always in range - Number: int(blockNumber), + // check result + if tt.fail { + require.ErrorContains(t, err, tt.message) + require.Nil(t, ob) + } else { + require.NoError(t, err) + require.NotNil(t, ob) + } + }) } - blockCache.Add(blockNumber, block) - ob.WithBlockCache(blockCache) +} - // block should be in cache - _, err = ob.GetBlockByNumberCached(blockNumber) - require.NoError(t, err) +func Test_LoadDB(t *testing.T) { + // use Ethereum chain for testing + chain := chains.Ethereum + params := mocks.MockChainParams(chain.ChainId, 10) + dbpath := sample.CreateTempDir(t) + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, dbpath, 1, params) + + t.Run("should load db successfully", func(t *testing.T) { + err := ob.LoadDB(dbpath) + require.NoError(t, err) + require.EqualValues(t, 1000, ob.LastBlockScanned()) + }) + t.Run("should fail on invalid dbpath", func(t *testing.T) { + // load db with empty dbpath + err := ob.LoadDB("") + require.ErrorContains(t, err, "empty db path") + + // load db with invalid dbpath + err = ob.LoadDB("/invalid/dbpath") + require.ErrorContains(t, err, "error OpenDB") + }) + t.Run("should fail on invalid env var", func(t *testing.T) { + // set invalid environment variable + envvar := base.EnvVarLatestBlockByChain(chain) + os.Setenv(envvar, "invalid") + defer os.Unsetenv(envvar) + + // load db + err := ob.LoadDB(dbpath) + require.ErrorContains(t, err, "error LoadLastBlockScanned") + }) + t.Run("should fail on RPC error", func(t *testing.T) { + // create observer + tempClient := mocks.NewMockEvmClient() + ob := MockEVMObserver(t, chain, tempClient, nil, nil, nil, dbpath, 1, params) + + // set RPC error + tempClient.WithError(fmt.Errorf("error RPC")) + + // load db + err := ob.LoadDB(dbpath) + require.ErrorContains(t, err, "error RPC") + }) +} + +func Test_LoadLastBlockScanned(t *testing.T) { + // use Ethereum chain for testing + chain := chains.Ethereum + params := mocks.MockChainParams(chain.ChainId, 10) + + // create observer using mock evm client + evmClient := mocks.NewMockEvmClient().WithBlockNumber(100) + dbpath := sample.CreateTempDir(t) + ob := MockEVMObserver(t, chain, evmClient, nil, nil, nil, dbpath, 1, params) + + t.Run("should load last block scanned", func(t *testing.T) { + // create db and write 123 as last block scanned + ob.WriteLastBlockScannedToDB(123) + + // load last block scanned + err := ob.LoadLastBlockScanned() + require.NoError(t, err) + require.EqualValues(t, 123, ob.LastBlockScanned()) + }) + t.Run("should fail on invalid env var", func(t *testing.T) { + // set invalid environment variable + envvar := base.EnvVarLatestBlockByChain(chain) + os.Setenv(envvar, "invalid") + defer os.Unsetenv(envvar) + + // load last block scanned + err := ob.LoadLastBlockScanned() + require.ErrorContains(t, err, "error LoadLastBlockScanned") + }) + t.Run("should fail on RPC error", func(t *testing.T) { + // create observer on separate path, as we need to reset last block scanned + otherPath := sample.CreateTempDir(t) + obOther := MockEVMObserver(t, chain, evmClient, nil, nil, nil, otherPath, 1, params) + + // reset last block scanned to 0 so that it will be loaded from RPC + obOther.WithLastBlockScanned(0) + + // set RPC error + evmClient.WithError(fmt.Errorf("error RPC")) - // delete the block should not panic - ob.RemoveCachedBlock(blockNumber) + // load last block scanned + err := obOther.LoadLastBlockScanned() + require.ErrorContains(t, err, "error RPC") + }) +} + +func Test_BlockCache(t *testing.T) { + t.Run("should get block from cache", func(t *testing.T) { + // create observer + ob := &observer.Observer{} + blockCache, err := lru.New(100) + require.NoError(t, err) + ob.WithBlockCache(blockCache) + + // create mock evm client + JSONRPC := mocks.NewMockJSONRPCClient() + ob.WithEvmJSONRPC(JSONRPC) + + // feed block to JSON rpc client + block := ðrpc.Block{Number: 100} + JSONRPC.WithBlock(block) + + // get block header from observer, fallback to JSON RPC + result, err := ob.GetBlockByNumberCached(uint64(100)) + require.NoError(t, err) + require.EqualValues(t, block, result) + + // get block header from cache + result, err = ob.GetBlockByNumberCached(uint64(100)) + require.NoError(t, err) + require.EqualValues(t, block, result) + }) + t.Run("should fail if stored type is not block", func(t *testing.T) { + // create observer + ob := &observer.Observer{} + blockCache, err := lru.New(100) + require.NoError(t, err) + ob.WithBlockCache(blockCache) + + // add a string to cache + blockNumber := uint64(100) + blockCache.Add(blockNumber, "a string value") + + // get result header from cache + result, err := ob.GetBlockByNumberCached(blockNumber) + require.ErrorContains(t, err, "cached value is not of type *ethrpc.Block") + require.Nil(t, result) + }) + t.Run("should be able to remove block from cache", func(t *testing.T) { + // create observer + ob := &observer.Observer{} + blockCache, err := lru.New(100) + require.NoError(t, err) + ob.WithBlockCache(blockCache) + + // delete non-existing block should not panic + blockNumber := uint64(123) + ob.RemoveCachedBlock(blockNumber) + + // add a block + block := ðrpc.Block{Number: 123} + blockCache.Add(blockNumber, block) + ob.WithBlockCache(blockCache) + + // block should be in cache + result, err := ob.GetBlockByNumberCached(blockNumber) + require.NoError(t, err) + require.EqualValues(t, block, result) + + // delete the block should not panic + ob.RemoveCachedBlock(blockNumber) + }) +} + +func Test_HeaderCache(t *testing.T) { + t.Run("should get block header from cache", func(t *testing.T) { + // create observer + ob := &observer.Observer{} + headerCache, err := lru.New(100) + require.NoError(t, err) + ob.WithHeaderCache(headerCache) + + // create mock evm client + evmClient := mocks.NewMockEvmClient() + ob.WithEvmClient(evmClient) + + // feed block header to evm client + header := ðtypes.Header{Number: big.NewInt(100)} + evmClient.WithHeader(header) + + // get block header from observer + resHeader, err := ob.GetBlockHeaderCached(uint64(100)) + require.NoError(t, err) + require.EqualValues(t, header, resHeader) + }) + t.Run("should fail if stored type is not block header", func(t *testing.T) { + // create observer + ob := &observer.Observer{} + headerCache, err := lru.New(100) + require.NoError(t, err) + ob.WithHeaderCache(headerCache) + + // add a string to cache + blockNumber := uint64(100) + headerCache.Add(blockNumber, "a string value") + + // get block header from cache + header, err := ob.GetBlockHeaderCached(blockNumber) + require.ErrorContains(t, err, "cached value is not of type *ethtypes.Header") + require.Nil(t, header) + }) } func Test_CheckTxInclusion(t *testing.T) { @@ -135,7 +418,7 @@ func Test_CheckTxInclusion(t *testing.T) { // create client blockCache, err := lru.New(1000) require.NoError(t, err) - ob := &observer.Observer{Mu: &sync.Mutex{}} + ob := &observer.Observer{} // save block to cache blockCache.Add(blockNumber, block) diff --git a/zetaclient/chains/evm/observer/outbound.go b/zetaclient/chains/evm/observer/outbound.go index 8dda7ac034..9c3bd1c66b 100644 --- a/zetaclient/chains/evm/observer/outbound.go +++ b/zetaclient/chains/evm/observer/outbound.go @@ -29,33 +29,33 @@ import ( // GetTxID returns a unique id for outbound tx func (ob *Observer) GetTxID(nonce uint64) string { - tssAddr := ob.Tss.EVMAddress().String() - return fmt.Sprintf("%d-%s-%d", ob.chain.ChainId, tssAddr, nonce) + tssAddr := ob.TSS().EVMAddress().String() + return fmt.Sprintf("%d-%s-%d", ob.Chain().ChainId, tssAddr, nonce) } // WatchOutbound watches evm chain for outgoing txs status func (ob *Observer) WatchOutbound() { ticker, err := clienttypes.NewDynamicTicker( - fmt.Sprintf("EVM_WatchOutbound_%d", ob.chain.ChainId), + fmt.Sprintf("EVM_WatchOutbound_%d", ob.Chain().ChainId), ob.GetChainParams().OutboundTicker, ) if err != nil { - ob.logger.Outbound.Error().Err(err).Msg("error creating ticker") + ob.Logger().Outbound.Error().Err(err).Msg("error creating ticker") return } - ob.logger.Outbound.Info().Msgf("WatchOutbound started for chain %d", ob.chain.ChainId) - sampledLogger := ob.logger.Outbound.Sample(&zerolog.BasicSampler{N: 10}) + ob.Logger().Outbound.Info().Msgf("WatchOutbound started for chain %d", ob.Chain().ChainId) + sampledLogger := ob.Logger().Outbound.Sample(&zerolog.BasicSampler{N: 10}) defer ticker.Stop() for { select { case <-ticker.C(): - if !clientcontext.IsOutboundObservationEnabled(ob.coreContext, ob.GetChainParams()) { + if !clientcontext.IsOutboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { sampledLogger.Info(). - Msgf("WatchOutbound: outbound observation is disabled for chain %d", ob.chain.ChainId) + Msgf("WatchOutbound: outbound observation is disabled for chain %d", ob.Chain().ChainId) continue } - trackers, err := ob.zetacoreClient.GetAllOutboundTrackerByChain(ob.chain.ChainId, interfaces.Ascending) + trackers, err := ob.ZetacoreClient().GetAllOutboundTrackerByChain(ob.Chain().ChainId, interfaces.Ascending) if err != nil { continue } @@ -72,23 +72,23 @@ func (ob *Observer) WatchOutbound() { txCount++ outboundReceipt = receipt outbound = tx - ob.logger.Outbound.Info(). - Msgf("WatchOutbound: confirmed outbound %s for chain %d nonce %d", txHash.TxHash, ob.chain.ChainId, nonceInt) + ob.Logger().Outbound.Info(). + Msgf("WatchOutbound: confirmed outbound %s for chain %d nonce %d", txHash.TxHash, ob.Chain().ChainId, nonceInt) if txCount > 1 { - ob.logger.Outbound.Error().Msgf( - "WatchOutbound: checkConfirmedTx passed, txCount %d chain %d nonce %d receipt %v transaction %v", txCount, ob.chain.ChainId, nonceInt, outboundReceipt, outbound) + ob.Logger().Outbound.Error().Msgf( + "WatchOutbound: checkConfirmedTx passed, txCount %d chain %d nonce %d receipt %v transaction %v", txCount, ob.Chain().ChainId, nonceInt, outboundReceipt, outbound) } } } if txCount == 1 { // should be only one txHash confirmed for each nonce. ob.SetTxNReceipt(nonceInt, outboundReceipt, outbound) } else if txCount > 1 { // should not happen. We can't tell which txHash is true. It might happen (e.g. glitchy/hacked endpoint) - ob.logger.Outbound.Error().Msgf("WatchOutbound: confirmed multiple (%d) outbound for chain %d nonce %d", txCount, ob.chain.ChainId, nonceInt) + ob.Logger().Outbound.Error().Msgf("WatchOutbound: confirmed multiple (%d) outbound for chain %d nonce %d", txCount, ob.Chain().ChainId, nonceInt) } } - ticker.UpdateInterval(ob.GetChainParams().OutboundTicker, ob.logger.Outbound) - case <-ob.stop: - ob.logger.Outbound.Info().Msg("WatchOutbound: stopped") + ticker.UpdateInterval(ob.GetChainParams().OutboundTicker, ob.Logger().Outbound) + case <-ob.StopChannel(): + ob.Logger().Outbound.Info().Msg("WatchOutbound: stopped") return } } @@ -105,8 +105,8 @@ func (ob *Observer) PostVoteOutbound( cointype coin.CoinType, logger zerolog.Logger, ) { - chainID := ob.chain.ChainId - zetaTxHash, ballot, err := ob.zetacoreClient.PostVoteOutbound( + chainID := ob.Chain().ChainId + zetaTxHash, ballot, err := ob.ZetacoreClient().PostVoteOutbound( cctxIndex, receipt.TxHash.Hex(), receipt.BlockNumber.Uint64(), @@ -115,7 +115,7 @@ func (ob *Observer) PostVoteOutbound( transaction.Gas(), receiveValue, receiveStatus, - ob.chain, + ob.Chain(), nonce, cointype, ) @@ -137,17 +137,17 @@ func (ob *Observer) IsOutboundProcessed(cctx *crosschaintypes.CrossChainTx, logg return false, false, nil } receipt, transaction := ob.GetTxNReceipt(nonce) - sendID := fmt.Sprintf("%d-%d", ob.chain.ChainId, nonce) + sendID := fmt.Sprintf("%d-%d", ob.Chain().ChainId, nonce) logger = logger.With().Str("sendID", sendID).Logger() // get connector and erce20Custody contracts connectorAddr, connector, err := ob.GetConnectorContract() if err != nil { - return false, false, errors.Wrapf(err, "error getting zeta connector for chain %d", ob.chain.ChainId) + return false, false, errors.Wrapf(err, "error getting zeta connector for chain %d", ob.Chain().ChainId) } custodyAddr, custody, err := ob.GetERC20CustodyContract() if err != nil { - return false, false, errors.Wrapf(err, "error getting erc20 custody for chain %d", ob.chain.ChainId) + return false, false, errors.Wrapf(err, "error getting erc20 custody for chain %d", ob.Chain().ChainId) } // define a few common variables @@ -181,7 +181,7 @@ func (ob *Observer) IsOutboundProcessed(cctx *crosschaintypes.CrossChainTx, logg if err != nil { logger.Error(). Err(err). - Msgf("IsOutboundProcessed: error parsing outbound event for chain %d txhash %s", ob.chain.ChainId, receipt.TxHash) + Msgf("IsOutboundProcessed: error parsing outbound event for chain %d txhash %s", ob.Chain().ChainId, receipt.TxHash) return false, false, err } @@ -346,7 +346,7 @@ func (ob *Observer) checkConfirmedTx(txHash string, nonce uint64) (*ethtypes.Rec if err != nil { log.Error(). Err(err). - Msgf("confirmTxByHash: error getting transaction for outbound %s chain %d", txHash, ob.chain.ChainId) + Msgf("confirmTxByHash: error getting transaction for outbound %s chain %d", txHash, ob.Chain().ChainId) return nil, nil, false } if transaction == nil { // should not happen @@ -355,17 +355,17 @@ func (ob *Observer) checkConfirmedTx(txHash string, nonce uint64) (*ethtypes.Rec } // check tx sender and nonce - signer := ethtypes.NewLondonSigner(big.NewInt(ob.chain.ChainId)) + signer := ethtypes.NewLondonSigner(big.NewInt(ob.Chain().ChainId)) from, err := signer.Sender(transaction) if err != nil { log.Error(). Err(err). - Msgf("confirmTxByHash: local recovery of sender address failed for outbound %s chain %d", transaction.Hash().Hex(), ob.chain.ChainId) + Msgf("confirmTxByHash: local recovery of sender address failed for outbound %s chain %d", transaction.Hash().Hex(), ob.Chain().ChainId) return nil, nil, false } - if from != ob.Tss.EVMAddress() { // must be TSS address + if from != ob.TSS().EVMAddress() { // must be TSS address log.Error().Msgf("confirmTxByHash: sender %s for outbound %s chain %d is not TSS address %s", - from.Hex(), transaction.Hash().Hex(), ob.chain.ChainId, ob.Tss.EVMAddress().Hex()) + from.Hex(), transaction.Hash().Hex(), ob.Chain().ChainId, ob.TSS().EVMAddress().Hex()) return nil, nil, false } if transaction.Nonce() != nonce { // must match cctx nonce @@ -394,10 +394,10 @@ func (ob *Observer) checkConfirmedTx(txHash string, nonce uint64) (*ethtypes.Rec } // check confirmations - if !ob.HasEnoughConfirmations(receipt, ob.GetLastBlockHeight()) { + if !ob.HasEnoughConfirmations(receipt, ob.LastBlock()) { log.Debug(). Msgf("confirmTxByHash: txHash %s nonce %d included but not confirmed: receipt block %d, current block %d", - txHash, nonce, receipt.BlockNumber, ob.GetLastBlockHeight()) + txHash, nonce, receipt.BlockNumber, ob.LastBlock()) return nil, nil, false } diff --git a/zetaclient/chains/evm/observer/outbound_test.go b/zetaclient/chains/evm/observer/outbound_test.go index e0806d6086..72023d8f57 100644 --- a/zetaclient/chains/evm/observer/outbound_test.go +++ b/zetaclient/chains/evm/observer/outbound_test.go @@ -19,6 +19,8 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" ) +const memDBPath = testutils.SQLiteMemory + // getContractsByChainID is a helper func to get contracts and addresses by chainID func getContractsByChainID( t *testing.T, @@ -57,11 +59,12 @@ func Test_IsOutboundProcessed(t *testing.T) { ) t.Run("should post vote and return true if outbound is processed", func(t *testing.T) { - // create evm client and set outbound and receipt - client := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) - client.SetTxNReceipt(nonce, receipt, outbound) + // create evm observer and set outbound and receipt + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, 1, chainParam) + ob.SetTxNReceipt(nonce, receipt, outbound) + // post outbound vote - isIncluded, isConfirmed, err := client.IsOutboundProcessed(cctx, zerolog.Logger{}) + isIncluded, isConfirmed, err := ob.IsOutboundProcessed(cctx, zerolog.Logger{}) require.NoError(t, err) require.True(t, isIncluded) require.True(t, isConfirmed) @@ -73,9 +76,9 @@ func Test_IsOutboundProcessed(t *testing.T) { cctx := testutils.LoadCctxByNonce(t, chainID, nonce) cctx.InboundParams.Sender = sample.EthAddress().Hex() - // create evm client and set outbound and receipt - client := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) - client.SetTxNReceipt(nonce, receipt, outbound) + // create evm observer and set outbound and receipt + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, 1, chainParam) + ob.SetTxNReceipt(nonce, receipt, outbound) // modify compliance config to restrict sender address cfg := config.Config{ @@ -85,29 +88,29 @@ func Test_IsOutboundProcessed(t *testing.T) { config.LoadComplianceConfig(cfg) // post outbound vote - isIncluded, isConfirmed, err := client.IsOutboundProcessed(cctx, zerolog.Logger{}) + isIncluded, isConfirmed, err := ob.IsOutboundProcessed(cctx, zerolog.Logger{}) require.NoError(t, err) require.True(t, isIncluded) require.True(t, isConfirmed) }) t.Run("should return false if outbound is not confirmed", func(t *testing.T) { - // create evm client and DO NOT set outbound as confirmed - client := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) - isIncluded, isConfirmed, err := client.IsOutboundProcessed(cctx, zerolog.Logger{}) + // create evm observer and DO NOT set outbound as confirmed + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, 1, chainParam) + isIncluded, isConfirmed, err := ob.IsOutboundProcessed(cctx, zerolog.Logger{}) require.NoError(t, err) require.False(t, isIncluded) require.False(t, isConfirmed) }) t.Run("should fail if unable to parse ZetaReceived event", func(t *testing.T) { - // create evm client and set outbound and receipt - client := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) - client.SetTxNReceipt(nonce, receipt, outbound) + // create evm observer and set outbound and receipt + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, 1, chainParam) + ob.SetTxNReceipt(nonce, receipt, outbound) // set connector contract address to an arbitrary address to make event parsing fail - chainParamsNew := client.GetChainParams() + chainParamsNew := ob.GetChainParams() chainParamsNew.ConnectorContractAddress = sample.EthAddress().Hex() - client.SetChainParams(chainParamsNew) - isIncluded, isConfirmed, err := client.IsOutboundProcessed(cctx, zerolog.Logger{}) + ob.SetChainParams(chainParamsNew) + isIncluded, isConfirmed, err := ob.IsOutboundProcessed(cctx, zerolog.Logger{}) require.Error(t, err) require.False(t, isIncluded) require.False(t, isConfirmed) @@ -147,15 +150,15 @@ func Test_IsOutboundProcessed_ContractError(t *testing.T) { ) t.Run("should fail if unable to get connector/custody contract", func(t *testing.T) { - // create evm client and set outbound and receipt - client := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) - client.SetTxNReceipt(nonce, receipt, outbound) + // create evm observer and set outbound and receipt + ob := MockEVMObserver(t, chain, nil, nil, nil, nil, memDBPath, 1, chainParam) + ob.SetTxNReceipt(nonce, receipt, outbound) abiConnector := zetaconnector.ZetaConnectorNonEthMetaData.ABI abiCustody := erc20custody.ERC20CustodyMetaData.ABI // set invalid connector ABI zetaconnector.ZetaConnectorNonEthMetaData.ABI = "invalid abi" - isIncluded, isConfirmed, err := client.IsOutboundProcessed(cctx, zerolog.Logger{}) + isIncluded, isConfirmed, err := ob.IsOutboundProcessed(cctx, zerolog.Logger{}) zetaconnector.ZetaConnectorNonEthMetaData.ABI = abiConnector // reset connector ABI require.ErrorContains(t, err, "error getting zeta connector") require.False(t, isIncluded) @@ -163,7 +166,7 @@ func Test_IsOutboundProcessed_ContractError(t *testing.T) { // set invalid custody ABI erc20custody.ERC20CustodyMetaData.ABI = "invalid abi" - isIncluded, isConfirmed, err = client.IsOutboundProcessed(cctx, zerolog.Logger{}) + isIncluded, isConfirmed, err = ob.IsOutboundProcessed(cctx, zerolog.Logger{}) require.ErrorContains(t, err, "error getting erc20 custody") require.False(t, isIncluded) require.False(t, isConfirmed) @@ -193,8 +196,8 @@ func Test_PostVoteOutbound(t *testing.T) { // create evm client using mock zetacore client and post outbound vote zetacoreClient := mocks.NewMockZetacoreClient() - client := MockEVMObserver(t, chain, nil, nil, zetacoreClient, nil, 1, observertypes.ChainParams{}) - client.PostVoteOutbound( + ob := MockEVMObserver(t, chain, nil, nil, zetacoreClient, nil, memDBPath, 1, observertypes.ChainParams{}) + ob.PostVoteOutbound( cctx.Index, receipt, outbound, @@ -207,7 +210,7 @@ func Test_PostVoteOutbound(t *testing.T) { // pause the mock zetacore client to simulate error posting vote zetacoreClient.Pause() - client.PostVoteOutbound( + ob.PostVoteOutbound( cctx.Index, receipt, outbound, diff --git a/zetaclient/chains/evm/signer/outbound_data_test.go b/zetaclient/chains/evm/signer/outbound_data_test.go index fbb4d5ef88..d7df5a33d1 100644 --- a/zetaclient/chains/evm/signer/outbound_data_test.go +++ b/zetaclient/chains/evm/signer/outbound_data_test.go @@ -70,7 +70,7 @@ func TestSigner_NewOutboundData(t *testing.T) { evmSigner, err := getNewEvmSigner(nil) require.NoError(t, err) - mockObserver, err := getNewEvmChainObserver(nil) + mockObserver, err := getNewEvmChainObserver(t, nil) require.NoError(t, err) t.Run("NewOutboundData success", func(t *testing.T) { diff --git a/zetaclient/chains/evm/signer/signer.go b/zetaclient/chains/evm/signer/signer.go index 4fa29a015b..d50b214b03 100644 --- a/zetaclient/chains/evm/signer/signer.go +++ b/zetaclient/chains/evm/signer/signer.go @@ -37,6 +37,14 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/zetacore" ) +const ( + // broadcastBackoff is the initial backoff duration for retrying broadcast + broadcastBackoff = 1000 * time.Millisecond + + // broadcastRetries is the maximum number of retries for broadcasting a transaction + broadcastRetries = 5 +) + var ( _ interfaces.ChainSigner = &Signer{} @@ -46,8 +54,7 @@ var ( // Signer deals with the signing EVM transactions and implements the ChainSigner interface type Signer struct { - // base.Signer implements the base chain signer - base.Signer + *base.Signer // client is the EVM RPC client to interact with the EVM chain client interfaces.EVMRPCClient @@ -104,7 +111,7 @@ func NewSigner( } return &Signer{ - Signer: *baseSigner, + Signer: baseSigner, client: client, ethSigner: ethSigner, zetaConnectorABI: connectorABI, @@ -117,29 +124,29 @@ func NewSigner( // SetZetaConnectorAddress sets the zeta connector address func (signer *Signer) SetZetaConnectorAddress(addr ethcommon.Address) { - signer.Mu().Lock() - defer signer.Mu().Unlock() + signer.Lock() + defer signer.Unlock() signer.zetaConnectorAddress = addr } // SetERC20CustodyAddress sets the erc20 custody address func (signer *Signer) SetERC20CustodyAddress(addr ethcommon.Address) { - signer.Mu().Lock() - defer signer.Mu().Unlock() + signer.Lock() + defer signer.Unlock() signer.er20CustodyAddress = addr } // GetZetaConnectorAddress returns the zeta connector address func (signer *Signer) GetZetaConnectorAddress() ethcommon.Address { - signer.Mu().Lock() - defer signer.Mu().Unlock() + signer.Lock() + defer signer.Unlock() return signer.zetaConnectorAddress } // GetERC20CustodyAddress returns the erc20 custody address func (signer *Signer) GetERC20CustodyAddress() ethcommon.Address { - signer.Mu().Lock() - defer signer.Mu().Unlock() + signer.Lock() + defer signer.Unlock() return signer.er20CustodyAddress } @@ -527,7 +534,8 @@ func (signer *Signer) BroadcastOutbound( logger zerolog.Logger, myID sdk.AccAddress, zetacoreClient interfaces.ZetacoreClient, - txData *OutboundData) { + txData *OutboundData, +) { // Get destination chain for logging toChain := chains.GetChainFromChainID(txData.toChainID.Int64()) if tx == nil { @@ -539,8 +547,8 @@ func (signer *Signer) BroadcastOutbound( outboundHash := tx.Hash().Hex() // try broacasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error - backOff := 1000 * time.Millisecond - for i := 0; i < 5; i++ { + backOff := broadcastBackoff + for i := 0; i < broadcastRetries; i++ { time.Sleep(backOff) err := signer.Broadcast(tx) if err != nil { @@ -689,8 +697,8 @@ func (signer *Signer) reportToOutboundTracker( logger zerolog.Logger, ) { // skip if already being reported - signer.Mu().Lock() - defer signer.Mu().Unlock() + signer.Lock() + defer signer.Unlock() if _, found := signer.outboundHashBeingReported[outboundHash]; found { logger.Info(). Msgf("reportToOutboundTracker: outboundHash %s for chain %d nonce %d is being reported", outboundHash, chainID, nonce) @@ -701,9 +709,9 @@ func (signer *Signer) reportToOutboundTracker( // report to outbound tracker with goroutine go func() { defer func() { - signer.Mu().Lock() + signer.Lock() delete(signer.outboundHashBeingReported, outboundHash) - signer.Mu().Unlock() + signer.Unlock() }() // try monitoring tx inclusion status for 10 minutes diff --git a/zetaclient/chains/evm/signer/signer_test.go b/zetaclient/chains/evm/signer/signer_test.go index 410ea5adf3..ea27152b97 100644 --- a/zetaclient/chains/evm/signer/signer_test.go +++ b/zetaclient/chains/evm/signer/signer_test.go @@ -59,22 +59,34 @@ func getNewEvmSigner(tss interfaces.TSSSigner) (*Signer, error) { } // getNewEvmChainObserver creates a new EVM chain observer for testing -func getNewEvmChainObserver(tss interfaces.TSSSigner) (*observer.Observer, error) { +func getNewEvmChainObserver(t *testing.T, tss interfaces.TSSSigner) (*observer.Observer, error) { // use default mock TSS if not provided if tss == nil { tss = mocks.NewTSSMainnet() } - - logger := base.Logger{} - ts := &metrics.TelemetryServer{} cfg := config.NewConfig() + // prepare mock arguments to create observer evmcfg := config.EVMConfig{Chain: chains.BscMainnet, Endpoint: "http://localhost:8545"} + evmClient := mocks.NewMockEvmClient().WithBlockNumber(1000) + params := mocks.MockChainParams(evmcfg.Chain.ChainId, 10) cfg.EVMChainConfigs[chains.BscMainnet.ChainId] = evmcfg coreCTX := context.NewZetacoreContext(cfg) - appCTX := context.NewAppContext(coreCTX, cfg) + dbpath := sample.CreateTempDir(t) + logger := base.Logger{} + ts := &metrics.TelemetryServer{} - return observer.NewObserver(appCTX, mocks.NewMockZetacoreClient(), tss, "", logger, evmcfg, ts) + return observer.NewObserver( + evmcfg, + evmClient, + params, + coreCTX, + mocks.NewMockZetacoreClient(), + tss, + dbpath, + logger, + ts, + ) } func getNewOutboundProcessor() *outboundprocessor.Processor { @@ -145,7 +157,7 @@ func TestSigner_TryProcessOutbound(t *testing.T) { require.NoError(t, err) cctx := getCCTX(t) processor := getNewOutboundProcessor() - mockObserver, err := getNewEvmChainObserver(nil) + mockObserver, err := getNewEvmChainObserver(t, nil) require.NoError(t, err) // Test with mock client that has keys @@ -166,7 +178,7 @@ func TestSigner_SignOutbound(t *testing.T) { // Setup txData struct cctx := getCCTX(t) - mockObserver, err := getNewEvmChainObserver(tss) + mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) @@ -200,7 +212,7 @@ func TestSigner_SignRevertTx(t *testing.T) { // Setup txData struct cctx := getCCTX(t) - mockObserver, err := getNewEvmChainObserver(tss) + mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) @@ -238,7 +250,7 @@ func TestSigner_SignCancelTx(t *testing.T) { // Setup txData struct cctx := getCCTX(t) - mockObserver, err := getNewEvmChainObserver(tss) + mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) @@ -276,7 +288,7 @@ func TestSigner_SignWithdrawTx(t *testing.T) { // Setup txData struct cctx := getCCTX(t) - mockObserver, err := getNewEvmChainObserver(tss) + mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) @@ -312,7 +324,7 @@ func TestSigner_SignCommandTx(t *testing.T) { // Setup txData struct cctx := getCCTX(t) - mockObserver, err := getNewEvmChainObserver(nil) + mockObserver, err := getNewEvmChainObserver(t, nil) require.NoError(t, err) txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) @@ -357,7 +369,7 @@ func TestSigner_SignERC20WithdrawTx(t *testing.T) { // Setup txData struct cctx := getCCTX(t) - mockObserver, err := getNewEvmChainObserver(tss) + mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) @@ -395,7 +407,7 @@ func TestSigner_BroadcastOutbound(t *testing.T) { // Setup txData struct cctx := getCCTX(t) - mockObserver, err := getNewEvmChainObserver(nil) + mockObserver, err := getNewEvmChainObserver(t, nil) require.NoError(t, err) txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) @@ -445,7 +457,7 @@ func TestSigner_SignWhitelistERC20Cmd(t *testing.T) { // Setup txData struct cctx := getCCTX(t) - mockObserver, err := getNewEvmChainObserver(tss) + mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) @@ -488,7 +500,7 @@ func TestSigner_SignMigrateTssFundsCmd(t *testing.T) { // Setup txData struct cctx := getCCTX(t) - mockObserver, err := getNewEvmChainObserver(tss) + mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) diff --git a/zetaclient/supplychecker/zeta_supply_checker.go b/zetaclient/supplychecker/zeta_supply_checker.go index 3984b740ab..952c0df16f 100644 --- a/zetaclient/supplychecker/zeta_supply_checker.go +++ b/zetaclient/supplychecker/zeta_supply_checker.go @@ -122,7 +122,7 @@ func (zs *ZetaSupplyChecker) CheckZetaTokenSupply() error { zetaTokenAddressString := externalEvmChainParams.ZetaTokenContractAddress zetaTokenAddress := ethcommon.HexToAddress(zetaTokenAddressString) - zetatokenNonEth, err := observer.FetchZetaZetaNonEthTokenContract(zetaTokenAddress, zs.evmClient[chain.ChainId]) + zetatokenNonEth, err := observer.FetchZetaTokenContract(zetaTokenAddress, zs.evmClient[chain.ChainId]) if err != nil { return err } diff --git a/zetaclient/testutils/constant.go b/zetaclient/testutils/constant.go index ad8302577d..3d4f6e2a03 100644 --- a/zetaclient/testutils/constant.go +++ b/zetaclient/testutils/constant.go @@ -27,6 +27,9 @@ const ( EventZetaReverted = "ZetaReverted" EventERC20Deposit = "Deposited" EventERC20Withdraw = "Withdrawn" + + // SQLiteMemory is a SQLite in-memory database connection string. + SQLiteMemory = "file::memory:?cache=shared" ) // ConnectorAddresses contains constants ERC20 connector addresses for testing diff --git a/zetaclient/testutils/mocks/btc_rpc.go b/zetaclient/testutils/mocks/btc_rpc.go index 01d286d31a..6809de664a 100644 --- a/zetaclient/testutils/mocks/btc_rpc.go +++ b/zetaclient/testutils/mocks/btc_rpc.go @@ -17,9 +17,12 @@ var _ interfaces.BTCRPCClient = &MockBTCRPCClient{} // MockBTCRPCClient is a mock implementation of the BTCRPCClient interface type MockBTCRPCClient struct { - err error - blockCount int64 - Txs []*btcutil.Tx + err error + blockCount int64 + blockHash *chainhash.Hash + blockHeader *wire.BlockHeader + blockVerboseTx *btcjson.GetBlockVerboseTxResult + Txs []*btcutil.Tx } // NewMockBTCRPCClient creates a new mock BTC RPC client @@ -108,7 +111,10 @@ func (c *MockBTCRPCClient) GetBlockCount() (int64, error) { } func (c *MockBTCRPCClient) GetBlockHash(_ int64) (*chainhash.Hash, error) { - return nil, errors.New("not implemented") + if c.err != nil { + return nil, c.err + } + return c.blockHash, nil } func (c *MockBTCRPCClient) GetBlockVerbose(_ *chainhash.Hash) (*btcjson.GetBlockVerboseResult, error) { @@ -116,11 +122,17 @@ func (c *MockBTCRPCClient) GetBlockVerbose(_ *chainhash.Hash) (*btcjson.GetBlock } func (c *MockBTCRPCClient) GetBlockVerboseTx(_ *chainhash.Hash) (*btcjson.GetBlockVerboseTxResult, error) { - return nil, errors.New("not implemented") + if c.err != nil { + return nil, c.err + } + return c.blockVerboseTx, nil } func (c *MockBTCRPCClient) GetBlockHeader(_ *chainhash.Hash) (*wire.BlockHeader, error) { - return nil, errors.New("not implemented") + if c.err != nil { + return nil, c.err + } + return c.blockHeader, nil } // ---------------------------------------------------------------------------- @@ -137,6 +149,21 @@ func (c *MockBTCRPCClient) WithBlockCount(blkCnt int64) *MockBTCRPCClient { return c } +func (c *MockBTCRPCClient) WithBlockHash(hash *chainhash.Hash) *MockBTCRPCClient { + c.blockHash = hash + return c +} + +func (c *MockBTCRPCClient) WithBlockHeader(header *wire.BlockHeader) *MockBTCRPCClient { + c.blockHeader = header + return c +} + +func (c *MockBTCRPCClient) WithBlockVerboseTx(block *btcjson.GetBlockVerboseTxResult) *MockBTCRPCClient { + c.blockVerboseTx = block + return c +} + func (c *MockBTCRPCClient) WithRawTransaction(tx *btcutil.Tx) *MockBTCRPCClient { c.Txs = append(c.Txs, tx) return c diff --git a/zetaclient/testutils/mocks/evm_rpc.go b/zetaclient/testutils/mocks/evm_rpc.go index fa40357592..e6daff0f13 100644 --- a/zetaclient/testutils/mocks/evm_rpc.go +++ b/zetaclient/testutils/mocks/evm_rpc.go @@ -33,6 +33,7 @@ var _ interfaces.EVMRPCClient = &MockEvmClient{} type MockEvmClient struct { err error blockNumber uint64 + header *ethtypes.Header Receipts []*ethtypes.Receipt } @@ -70,7 +71,7 @@ func (e *MockEvmClient) HeaderByNumber(_ context.Context, _ *big.Int) (*ethtypes if e.err != nil { return nil, e.err } - return ðtypes.Header{}, nil + return e.header, nil } func (e *MockEvmClient) PendingCodeAt(_ context.Context, _ ethcommon.Address) ([]byte, error) { @@ -189,6 +190,11 @@ func (e *MockEvmClient) WithBlockNumber(blockNumber uint64) *MockEvmClient { return e } +func (e *MockEvmClient) WithHeader(header *ethtypes.Header) *MockEvmClient { + e.header = header + return e +} + func (e *MockEvmClient) WithReceipt(receipt *ethtypes.Receipt) *MockEvmClient { e.Receipts = append(e.Receipts, receipt) return e From a97bf1302f3e9671d2d762e2c282ce02d258bc54 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 26 Jun 2024 14:44:56 +0100 Subject: [PATCH 09/23] fix: add tx input and gas in rpc methods for synthetic txs (#2382) --- changelog.md | 1 + rpc/backend/backend_suite_test.go | 1 + rpc/backend/tx_info_test.go | 3 +++ rpc/types/events.go | 4 +++- rpc/types/utils.go | 2 +- 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 373c0bafb3..8b386c85ec 100644 --- a/changelog.md +++ b/changelog.md @@ -83,6 +83,7 @@ * [2256](https://github.com/zeta-chain/node/pull/2256) - fix rate limiter falsely included reverted non-withdraw cctxs * [2327](https://github.com/zeta-chain/node/pull/2327) - partially cherry picked the fix to Bitcoin outbound dust amount * [2362](https://github.com/zeta-chain/node/pull/2362) - set 1000 satoshis as minimum BTC amount that can be withdrawn from zEVM +* [2382](https://github.com/zeta-chain/node/pull/2382) - add tx input and gas in rpc methods for synthetic eth txs ### CI diff --git a/rpc/backend/backend_suite_test.go b/rpc/backend/backend_suite_test.go index 1abd882fd2..21744e87e3 100644 --- a/rpc/backend/backend_suite_test.go +++ b/rpc/backend/backend_suite_test.go @@ -155,6 +155,7 @@ func (suite *BackendTestSuite) buildSyntheticTxResult(txHash string) ([]byte, ab {Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{ {Key: "ethereumTxHash", Value: txHash}, {Key: "txIndex", Value: "8888"}, + {Key: "txData", Value: "0x1234"}, {Key: "amount", Value: "1000"}, {Key: "txGasUsed", Value: "21000"}, {Key: "txHash", Value: ""}, diff --git a/rpc/backend/tx_info_test.go b/rpc/backend/tx_info_test.go index c76a26ead8..0ceb0160a6 100644 --- a/rpc/backend/tx_info_test.go +++ b/rpc/backend/tx_info_test.go @@ -56,6 +56,9 @@ func (suite *BackendTestSuite) TestGetSyntheticTransactionByHash() { suite.Require().Equal(uint64(88), txType) suite.Require().Equal(int64(7001), res.ChainID.ToInt().Int64()) suite.Require().Equal(int64(1000), res.Value.ToInt().Int64()) + gas, _ := hexutil.DecodeUint64(res.Gas.String()) + suite.Require().Equal(uint64(21000), gas) + suite.Require().Equal("0x1234", res.Input.String()) suite.Require().Nil(res.V) suite.Require().Nil(res.R) suite.Require().Nil(res.S) diff --git a/rpc/types/events.go b/rpc/types/events.go index 4a265f2c6d..f43270fae3 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -169,7 +169,8 @@ func ParseTxResult(result *abci.ResponseDeliverTx, tx sdk.Tx) (*ParsedTxs, error } // some old versions miss some events, fill it with tx result - if len(p.Txs) == 1 { + // txs with type CosmosEVMTxType will always emit GasUsed in events so no need to override for those + if len(p.Txs) == 1 && p.Txs[0].Type != CosmosEVMTxType { // #nosec G701 always positive p.Txs[0].GasUsed = uint64(result.GasUsed) } @@ -240,6 +241,7 @@ func ParseTxIndexerResult( Type: parsedTx.Type, Recipient: parsedTx.Recipient, Sender: parsedTx.Sender, + GasUsed: parsedTx.GasUsed, Data: parsedTx.Data, Nonce: parsedTx.Nonce, }, nil diff --git a/rpc/types/utils.go b/rpc/types/utils.go index dfda689557..7ba3c998da 100644 --- a/rpc/types/utils.go +++ b/rpc/types/utils.go @@ -252,7 +252,7 @@ func NewRPCTransactionFromIncompleteMsg( Gas: hexutil.Uint64(txAdditional.GasUsed), GasPrice: (*hexutil.Big)(baseFee), Hash: common.HexToHash(msg.Hash), - Input: []byte{}, + Input: txAdditional.Data, Nonce: hexutil.Uint64(txAdditional.Nonce), // TODO: get nonce for "from" from ethermint To: to, Value: (*hexutil.Big)(txAdditional.Value), From f2ac8f66d5202035a6f002c510b5b0e4460a9376 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 26 Jun 2024 11:06:50 -0400 Subject: [PATCH 10/23] feat: add queries for tss funds migrator info (#2372) --- changelog.md | 1 + .../cli/zetacored/zetacored_query_observer.md | 2 + ..._query_observer_list-tss-funds-migrator.md | 40 + ..._query_observer_show-tss-funds-migrator.md | 40 + docs/openapi/openapi.swagger.yaml | 57 + proto/zetachain/zetacore/observer/query.proto | 25 + .../zetachain/zetacore/observer/query_pb.d.ts | 92 ++ x/observer/client/cli/query.go | 2 + .../client/cli/query_tss_fund_migrator.go | 70 ++ .../grpc_query_tss_funds_migrator_info.go | 51 + .../grpc_query_tss_funds_migrator_test.go | 104 ++ x/observer/types/query.pb.go | 1112 ++++++++++++++--- x/observer/types/query.pb.gw.go | 148 +++ 13 files changed, 1544 insertions(+), 200 deletions(-) create mode 100644 docs/cli/zetacored/zetacored_query_observer_list-tss-funds-migrator.md create mode 100644 docs/cli/zetacored/zetacored_query_observer_show-tss-funds-migrator.md create mode 100644 x/observer/client/cli/query_tss_fund_migrator.go create mode 100644 x/observer/keeper/grpc_query_tss_funds_migrator_info.go create mode 100644 x/observer/keeper/grpc_query_tss_funds_migrator_test.go diff --git a/changelog.md b/changelog.md index 8b386c85ec..3d0194dc28 100644 --- a/changelog.md +++ b/changelog.md @@ -29,6 +29,7 @@ * [2325](https://github.com/zeta-chain/node/pull/2325) - revert telemetry server changes * [2339](https://github.com/zeta-chain/node/pull/2339) - add binaries related question to syncing issue form * [2366](https://github.com/zeta-chain/node/pull/2366) - add migration script for adding authorizations table +* [2372](https://github.com/zeta-chain/node/pull/2372) - add queries for tss fund migration info ### Refactor diff --git a/docs/cli/zetacored/zetacored_query_observer.md b/docs/cli/zetacored/zetacored_query_observer.md index 42d0ffe777..e19f4cbecb 100644 --- a/docs/cli/zetacored/zetacored_query_observer.md +++ b/docs/cli/zetacored/zetacored_query_observer.md @@ -36,6 +36,7 @@ zetacored query observer [flags] * [zetacored query observer list-node-account](zetacored_query_observer_list-node-account.md) - list all NodeAccount * [zetacored query observer list-observer-set](zetacored_query_observer_list-observer-set.md) - Query observer set * [zetacored query observer list-pending-nonces](zetacored_query_observer_list-pending-nonces.md) - shows a chainNonces +* [zetacored query observer list-tss-funds-migrator](zetacored_query_observer_list-tss-funds-migrator.md) - list all tss funds migrators * [zetacored query observer list-tss-history](zetacored_query_observer_list-tss-history.md) - show historical list of TSS * [zetacored query observer show-ballot](zetacored_query_observer_show-ballot.md) - Query BallotByIdentifier * [zetacored query observer show-blame](zetacored_query_observer_show-blame.md) - Query BlameByIdentifier @@ -46,4 +47,5 @@ zetacored query observer [flags] * [zetacored query observer show-node-account](zetacored_query_observer_show-node-account.md) - shows a NodeAccount * [zetacored query observer show-observer-count](zetacored_query_observer_show-observer-count.md) - Query show-observer-count * [zetacored query observer show-tss](zetacored_query_observer_show-tss.md) - shows a TSS +* [zetacored query observer show-tss-funds-migrator](zetacored_query_observer_show-tss-funds-migrator.md) - show the tss funds migrator for a chain diff --git a/docs/cli/zetacored/zetacored_query_observer_list-tss-funds-migrator.md b/docs/cli/zetacored/zetacored_query_observer_list-tss-funds-migrator.md new file mode 100644 index 0000000000..0eca411dae --- /dev/null +++ b/docs/cli/zetacored/zetacored_query_observer_list-tss-funds-migrator.md @@ -0,0 +1,40 @@ +# query observer list-tss-funds-migrator + +list all tss funds migrators + +``` +zetacored query observer list-tss-funds-migrator [flags] +``` + +### Options + +``` + --count-total count total number of records in list-tss-funds-migrator to query for + --grpc-addr string the gRPC endpoint to use for this chain + --grpc-insecure allow gRPC over insecure channels, if not TLS the server must use TLS + --height int Use a specific height to query state at (this can error if the node is pruning state) + -h, --help help for list-tss-funds-migrator + --limit uint pagination limit of list-tss-funds-migrator to query for (default 100) + --node string [host]:[port] to Tendermint RPC interface for this chain + --offset uint pagination offset of list-tss-funds-migrator to query for + -o, --output string Output format (text|json) + --page uint pagination page of list-tss-funds-migrator to query for. This sets offset to a multiple of limit (default 1) + --page-key string pagination page-key of list-tss-funds-migrator to query for + --reverse results are sorted in descending order +``` + +### Options inherited from parent commands + +``` + --chain-id string The network chain ID + --home string directory for config and data + --log_format string The logging format (json|plain) + --log_level string The logging level (trace|debug|info|warn|error|fatal|panic) + --log_no_color Disable colored logs + --trace print out full stack trace on errors +``` + +### SEE ALSO + +* [zetacored query observer](zetacored_query_observer.md) - Querying commands for the observer module + diff --git a/docs/cli/zetacored/zetacored_query_observer_show-tss-funds-migrator.md b/docs/cli/zetacored/zetacored_query_observer_show-tss-funds-migrator.md new file mode 100644 index 0000000000..c307953301 --- /dev/null +++ b/docs/cli/zetacored/zetacored_query_observer_show-tss-funds-migrator.md @@ -0,0 +1,40 @@ +# query observer show-tss-funds-migrator + +show the tss funds migrator for a chain + +``` +zetacored query observer show-tss-funds-migrator [chain-id] [flags] +``` + +### Options + +``` + --count-total count total number of records in show-tss-funds-migrator [chain-id] to query for + --grpc-addr string the gRPC endpoint to use for this chain + --grpc-insecure allow gRPC over insecure channels, if not TLS the server must use TLS + --height int Use a specific height to query state at (this can error if the node is pruning state) + -h, --help help for show-tss-funds-migrator + --limit uint pagination limit of show-tss-funds-migrator [chain-id] to query for (default 100) + --node string [host]:[port] to Tendermint RPC interface for this chain + --offset uint pagination offset of show-tss-funds-migrator [chain-id] to query for + -o, --output string Output format (text|json) + --page uint pagination page of show-tss-funds-migrator [chain-id] to query for. This sets offset to a multiple of limit (default 1) + --page-key string pagination page-key of show-tss-funds-migrator [chain-id] to query for + --reverse results are sorted in descending order +``` + +### Options inherited from parent commands + +``` + --chain-id string The network chain ID + --home string directory for config and data + --log_format string The logging format (json|plain) + --log_level string The logging level (trace|debug|info|warn|error|fatal|panic) + --log_no_color Disable colored logs + --trace print out full stack trace on errors +``` + +### SEE ALSO + +* [zetacored query observer](zetacored_query_observer.md) - Querying commands for the observer module + diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index dc72d0bf6b..987feb13d4 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -30252,6 +30252,42 @@ paths: format: int64 tags: - Query + /zeta-chain/observer/getAllTssFundsMigrators: + get: + summary: Queries all TssFundMigratorInfo + operationId: Query_TssFundsMigratorInfoAll + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/observerQueryTssFundsMigratorInfoAllResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + tags: + - Query + /zeta-chain/observer/getTssFundsMigrator: + get: + summary: Queries the TssFundMigratorInfo for a specific chain + operationId: Query_TssFundsMigratorInfo + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/observerQueryTssFundsMigratorInfoResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + parameters: + - name: chain_id + in: query + required: false + type: string + format: int64 + tags: + - Query /zeta-chain/observer/has_voted/{ballot_identifier}/{voter_address}: get: summary: Query if a voter has voted for a ballot @@ -58111,6 +58147,19 @@ definitions: items: type: object $ref: '#/definitions/chainsChain' + observerQueryTssFundsMigratorInfoAllResponse: + type: object + properties: + tss_funds_migrators: + type: array + items: + type: object + $ref: '#/definitions/observerTssFundMigratorInfo' + observerQueryTssFundsMigratorInfoResponse: + type: object + properties: + tss_funds_migrator: + $ref: '#/definitions/observerTssFundMigratorInfo' observerQueryTssHistoryResponse: type: object properties: @@ -58140,6 +58189,14 @@ definitions: keyGenZetaHeight: type: string format: int64 + observerTssFundMigratorInfo: + type: object + properties: + chain_id: + type: string + format: int64 + migration_cctx_index: + type: string observerVoteType: type: string enum: diff --git a/proto/zetachain/zetacore/observer/query.proto b/proto/zetachain/zetacore/observer/query.proto index ef06616b2e..799bc1efb9 100644 --- a/proto/zetachain/zetacore/observer/query.proto +++ b/proto/zetachain/zetacore/observer/query.proto @@ -16,6 +16,7 @@ import "zetachain/zetacore/observer/pending_nonces.proto"; import "zetachain/zetacore/observer/tss.proto"; import "zetachain/zetacore/pkg/chains/chains.proto"; import "zetachain/zetacore/pkg/proofs/proofs.proto"; +import "zetachain/zetacore/observer/tss_funds_migrator.proto"; option go_package = "github.com/zeta-chain/zetacore/x/observer/types"; @@ -150,6 +151,30 @@ service Query { returns (QueryAllChainNoncesResponse) { option (google.api.http).get = "/zeta-chain/observer/chainNonces"; } + // Queries the TssFundMigratorInfo for a specific chain + rpc TssFundsMigratorInfo(QueryTssFundsMigratorInfoRequest) + returns (QueryTssFundsMigratorInfoResponse) { + option (google.api.http).get = "/zeta-chain/observer/getTssFundsMigrator"; + } + + // Queries all TssFundMigratorInfo + rpc TssFundsMigratorInfoAll(QueryTssFundsMigratorInfoAllRequest) + returns (QueryTssFundsMigratorInfoAllResponse) { + option (google.api.http).get = + "/zeta-chain/observer/getAllTssFundsMigrators"; + } +} + +message QueryTssFundsMigratorInfoAllRequest {} + +message QueryTssFundsMigratorInfoAllResponse { + repeated TssFundMigratorInfo tss_funds_migrators = 1 + [ (gogoproto.nullable) = false ]; +} + +message QueryTssFundsMigratorInfoRequest { int64 chain_id = 1; } +message QueryTssFundsMigratorInfoResponse { + TssFundMigratorInfo tss_funds_migrator = 1 [ (gogoproto.nullable) = false ]; } message QueryGetChainNoncesRequest { string index = 1; } diff --git a/typescript/zetachain/zetacore/observer/query_pb.d.ts b/typescript/zetachain/zetacore/observer/query_pb.d.ts index 5c4f8c71d0..41873827e5 100644 --- a/typescript/zetachain/zetacore/observer/query_pb.d.ts +++ b/typescript/zetachain/zetacore/observer/query_pb.d.ts @@ -5,6 +5,7 @@ import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; import { Message, proto3 } from "@bufbuild/protobuf"; +import type { TssFundMigratorInfo } from "./tss_funds_migrator_pb.js"; import type { ChainNonces } from "./chain_nonces_pb.js"; import type { PageRequest, PageResponse } from "../../../cosmos/base/query/v1beta1/pagination_pb.js"; import type { PendingNonces } from "./pending_nonces_pb.js"; @@ -18,6 +19,97 @@ import type { CrosschainFlags } from "./crosschain_flags_pb.js"; import type { Keygen } from "./keygen_pb.js"; import type { Blame } from "./blame_pb.js"; +/** + * @generated from message zetachain.zetacore.observer.QueryTssFundsMigratorInfoAllRequest + */ +export declare class QueryTssFundsMigratorInfoAllRequest extends Message { + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.observer.QueryTssFundsMigratorInfoAllRequest"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): QueryTssFundsMigratorInfoAllRequest; + + static fromJson(jsonValue: JsonValue, options?: Partial): QueryTssFundsMigratorInfoAllRequest; + + static fromJsonString(jsonString: string, options?: Partial): QueryTssFundsMigratorInfoAllRequest; + + static equals(a: QueryTssFundsMigratorInfoAllRequest | PlainMessage | undefined, b: QueryTssFundsMigratorInfoAllRequest | PlainMessage | undefined): boolean; +} + +/** + * @generated from message zetachain.zetacore.observer.QueryTssFundsMigratorInfoAllResponse + */ +export declare class QueryTssFundsMigratorInfoAllResponse extends Message { + /** + * @generated from field: repeated zetachain.zetacore.observer.TssFundMigratorInfo tss_funds_migrators = 1; + */ + tssFundsMigrators: TssFundMigratorInfo[]; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.observer.QueryTssFundsMigratorInfoAllResponse"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): QueryTssFundsMigratorInfoAllResponse; + + static fromJson(jsonValue: JsonValue, options?: Partial): QueryTssFundsMigratorInfoAllResponse; + + static fromJsonString(jsonString: string, options?: Partial): QueryTssFundsMigratorInfoAllResponse; + + static equals(a: QueryTssFundsMigratorInfoAllResponse | PlainMessage | undefined, b: QueryTssFundsMigratorInfoAllResponse | PlainMessage | undefined): boolean; +} + +/** + * @generated from message zetachain.zetacore.observer.QueryTssFundsMigratorInfoRequest + */ +export declare class QueryTssFundsMigratorInfoRequest extends Message { + /** + * @generated from field: int64 chain_id = 1; + */ + chainId: bigint; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.observer.QueryTssFundsMigratorInfoRequest"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): QueryTssFundsMigratorInfoRequest; + + static fromJson(jsonValue: JsonValue, options?: Partial): QueryTssFundsMigratorInfoRequest; + + static fromJsonString(jsonString: string, options?: Partial): QueryTssFundsMigratorInfoRequest; + + static equals(a: QueryTssFundsMigratorInfoRequest | PlainMessage | undefined, b: QueryTssFundsMigratorInfoRequest | PlainMessage | undefined): boolean; +} + +/** + * @generated from message zetachain.zetacore.observer.QueryTssFundsMigratorInfoResponse + */ +export declare class QueryTssFundsMigratorInfoResponse extends Message { + /** + * @generated from field: zetachain.zetacore.observer.TssFundMigratorInfo tss_funds_migrator = 1; + */ + tssFundsMigrator?: TssFundMigratorInfo; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.observer.QueryTssFundsMigratorInfoResponse"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): QueryTssFundsMigratorInfoResponse; + + static fromJson(jsonValue: JsonValue, options?: Partial): QueryTssFundsMigratorInfoResponse; + + static fromJsonString(jsonString: string, options?: Partial): QueryTssFundsMigratorInfoResponse; + + static equals(a: QueryTssFundsMigratorInfoResponse | PlainMessage | undefined, b: QueryTssFundsMigratorInfoResponse | PlainMessage | undefined): boolean; +} + /** * @generated from message zetachain.zetacore.observer.QueryGetChainNoncesRequest */ diff --git a/x/observer/client/cli/query.go b/x/observer/client/cli/query.go index 84b9c6c6e6..39f43847a7 100644 --- a/x/observer/client/cli/query.go +++ b/x/observer/client/cli/query.go @@ -41,6 +41,8 @@ func GetQueryCmd(_ string) *cobra.Command { CmdListChainNonces(), CmdShowChainNonces(), CmdListPendingNonces(), + CmdGetAllTssFundsMigrator(), + CmdGetTssFundsMigrator(), ) return cmd diff --git a/x/observer/client/cli/query_tss_fund_migrator.go b/x/observer/client/cli/query_tss_fund_migrator.go new file mode 100644 index 0000000000..a5483fde51 --- /dev/null +++ b/x/observer/client/cli/query_tss_fund_migrator.go @@ -0,0 +1,70 @@ +package cli + +import ( + "context" + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + + "github.com/zeta-chain/zetacore/x/observer/types" +) + +func CmdGetTssFundsMigrator() *cobra.Command { + cmd := &cobra.Command{ + Use: "show-tss-funds-migrator [chain-id]", + Short: "show the tss funds migrator for a chain", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + chainID, err := strconv.ParseInt(args[0], 10, 64) + if err != nil { + return err + } + params := &types.QueryTssFundsMigratorInfoRequest{ + ChainId: chainID, + } + + res, err := queryClient.TssFundsMigratorInfo(context.Background(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddPaginationFlagsToCmd(cmd, cmd.Use) + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func CmdGetAllTssFundsMigrator() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-tss-funds-migrator", + Short: "list all tss funds migrators", + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryTssFundsMigratorInfoAllRequest{} + + res, err := queryClient.TssFundsMigratorInfoAll(context.Background(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddPaginationFlagsToCmd(cmd, cmd.Use) + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/observer/keeper/grpc_query_tss_funds_migrator_info.go b/x/observer/keeper/grpc_query_tss_funds_migrator_info.go new file mode 100644 index 0000000000..7a2ab7e357 --- /dev/null +++ b/x/observer/keeper/grpc_query_tss_funds_migrator_info.go @@ -0,0 +1,51 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/zeta-chain/zetacore/pkg/chains" + "github.com/zeta-chain/zetacore/x/observer/types" +) + +// TssFundsMigratorInfo queries a tss fund migrator info +func (k Keeper) TssFundsMigratorInfo( + goCtx context.Context, + req *types.QueryTssFundsMigratorInfoRequest, +) (*types.QueryTssFundsMigratorInfoResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + if chains.GetChainFromChainID(req.ChainId) == nil { + return nil, status.Error(codes.InvalidArgument, "invalid chain id") + } + + fm, found := k.GetFundMigrator(ctx, req.ChainId) + if !found { + return nil, status.Error(codes.NotFound, "tss fund migrator not found") + } + return &types.QueryTssFundsMigratorInfoResponse{ + TssFundsMigrator: fm, + }, nil +} + +// TssFundsMigratorInfoAll queries all tss fund migrator info for all chains +func (k Keeper) TssFundsMigratorInfoAll( + goCtx context.Context, + request *types.QueryTssFundsMigratorInfoAllRequest, +) (*types.QueryTssFundsMigratorInfoAllResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + migrators := k.GetAllTssFundMigrators(ctx) + + return &types.QueryTssFundsMigratorInfoAllResponse{TssFundsMigrators: migrators}, nil +} diff --git a/x/observer/keeper/grpc_query_tss_funds_migrator_test.go b/x/observer/keeper/grpc_query_tss_funds_migrator_test.go new file mode 100644 index 0000000000..3882079f5d --- /dev/null +++ b/x/observer/keeper/grpc_query_tss_funds_migrator_test.go @@ -0,0 +1,104 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/zeta-chain/zetacore/pkg/chains" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/observer/types" +) + +func TestKeeper_TssFundsMigratorInfo(t *testing.T) { + t.Run("should error if req is nil", func(t *testing.T) { + k, ctx, _, _ := keepertest.ObserverKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + + res, err := k.TssFundsMigratorInfo(wctx, nil) + require.ErrorContains(t, err, "invalid request") + require.Nil(t, res) + }) + + t.Run("should error if chain id is invalid", func(t *testing.T) { + k, ctx, _, _ := keepertest.ObserverKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + + res, err := k.TssFundsMigratorInfo(wctx, &types.QueryTssFundsMigratorInfoRequest{ + ChainId: 0, + }) + require.ErrorContains(t, err, "invalid chain id") + require.Nil(t, res) + }) + + t.Run("should error if not found", func(t *testing.T) { + k, ctx, _, _ := keepertest.ObserverKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + + res, err := k.TssFundsMigratorInfo(wctx, &types.QueryTssFundsMigratorInfoRequest{ + ChainId: chains.Ethereum.ChainId, + }) + require.ErrorContains(t, err, "tss fund migrator not found") + require.Nil(t, res) + }) + + t.Run("should return if found", func(t *testing.T) { + k, ctx, _, _ := keepertest.ObserverKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + chainId := chains.Ethereum.ChainId + + fm := types.TssFundMigratorInfo{ + ChainId: chainId, + MigrationCctxIndex: sample.ZetaIndex(t), + } + k.SetFundMigrator(ctx, fm) + + res, err := k.TssFundsMigratorInfo(wctx, &types.QueryTssFundsMigratorInfoRequest{ + ChainId: chainId, + }) + require.NoError(t, err) + require.Equal(t, fm, res.TssFundsMigrator) + }) +} + +func TestKeeper_TssFundsMigratorInfoAll(t *testing.T) { + t.Run("should error if req is nil", func(t *testing.T) { + k, ctx, _, _ := keepertest.ObserverKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + + res, err := k.TssFundsMigratorInfoAll(wctx, nil) + require.ErrorContains(t, err, "invalid request") + require.Nil(t, res) + }) + + t.Run("should return empty list if not found", func(t *testing.T) { + k, ctx, _, _ := keepertest.ObserverKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + + res, err := k.TssFundsMigratorInfoAll(wctx, &types.QueryTssFundsMigratorInfoAllRequest{}) + require.NoError(t, err) + require.Equal(t, 0, len(res.TssFundsMigrators)) + }) + + t.Run("should return list of infos if found", func(t *testing.T) { + k, ctx, _, _ := keepertest.ObserverKeeper(t) + wctx := sdk.WrapSDKContext(ctx) + + migrators := make([]types.TssFundMigratorInfo, 3) + for i := 0; i < 3; i++ { + fm := types.TssFundMigratorInfo{ + ChainId: int64(i), + MigrationCctxIndex: sample.ZetaIndex(t), + } + k.SetFundMigrator(ctx, fm) + migrators[i] = fm + } + + res, err := k.TssFundsMigratorInfoAll(wctx, &types.QueryTssFundsMigratorInfoAllRequest{}) + require.NoError(t, err) + require.Equal(t, 3, len(res.TssFundsMigrators)) + require.ElementsMatch(t, migrators, res.TssFundsMigrators) + }) +} diff --git a/x/observer/types/query.pb.go b/x/observer/types/query.pb.go index 1c7b0178cc..38d676df2b 100644 --- a/x/observer/types/query.pb.go +++ b/x/observer/types/query.pb.go @@ -32,6 +32,174 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +type QueryTssFundsMigratorInfoAllRequest struct { +} + +func (m *QueryTssFundsMigratorInfoAllRequest) Reset() { *m = QueryTssFundsMigratorInfoAllRequest{} } +func (m *QueryTssFundsMigratorInfoAllRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTssFundsMigratorInfoAllRequest) ProtoMessage() {} +func (*QueryTssFundsMigratorInfoAllRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_25b2aa420449a0c0, []int{0} +} +func (m *QueryTssFundsMigratorInfoAllRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTssFundsMigratorInfoAllRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTssFundsMigratorInfoAllRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTssFundsMigratorInfoAllRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTssFundsMigratorInfoAllRequest.Merge(m, src) +} +func (m *QueryTssFundsMigratorInfoAllRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTssFundsMigratorInfoAllRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTssFundsMigratorInfoAllRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTssFundsMigratorInfoAllRequest proto.InternalMessageInfo + +type QueryTssFundsMigratorInfoAllResponse struct { + TssFundsMigrators []TssFundMigratorInfo `protobuf:"bytes,1,rep,name=tss_funds_migrators,json=tssFundsMigrators,proto3" json:"tss_funds_migrators"` +} + +func (m *QueryTssFundsMigratorInfoAllResponse) Reset() { *m = QueryTssFundsMigratorInfoAllResponse{} } +func (m *QueryTssFundsMigratorInfoAllResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTssFundsMigratorInfoAllResponse) ProtoMessage() {} +func (*QueryTssFundsMigratorInfoAllResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_25b2aa420449a0c0, []int{1} +} +func (m *QueryTssFundsMigratorInfoAllResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTssFundsMigratorInfoAllResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTssFundsMigratorInfoAllResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTssFundsMigratorInfoAllResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTssFundsMigratorInfoAllResponse.Merge(m, src) +} +func (m *QueryTssFundsMigratorInfoAllResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTssFundsMigratorInfoAllResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTssFundsMigratorInfoAllResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTssFundsMigratorInfoAllResponse proto.InternalMessageInfo + +func (m *QueryTssFundsMigratorInfoAllResponse) GetTssFundsMigrators() []TssFundMigratorInfo { + if m != nil { + return m.TssFundsMigrators + } + return nil +} + +type QueryTssFundsMigratorInfoRequest struct { + ChainId int64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` +} + +func (m *QueryTssFundsMigratorInfoRequest) Reset() { *m = QueryTssFundsMigratorInfoRequest{} } +func (m *QueryTssFundsMigratorInfoRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTssFundsMigratorInfoRequest) ProtoMessage() {} +func (*QueryTssFundsMigratorInfoRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_25b2aa420449a0c0, []int{2} +} +func (m *QueryTssFundsMigratorInfoRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTssFundsMigratorInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTssFundsMigratorInfoRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTssFundsMigratorInfoRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTssFundsMigratorInfoRequest.Merge(m, src) +} +func (m *QueryTssFundsMigratorInfoRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTssFundsMigratorInfoRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTssFundsMigratorInfoRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTssFundsMigratorInfoRequest proto.InternalMessageInfo + +func (m *QueryTssFundsMigratorInfoRequest) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +type QueryTssFundsMigratorInfoResponse struct { + TssFundsMigrator TssFundMigratorInfo `protobuf:"bytes,1,opt,name=tss_funds_migrator,json=tssFundsMigrator,proto3" json:"tss_funds_migrator"` +} + +func (m *QueryTssFundsMigratorInfoResponse) Reset() { *m = QueryTssFundsMigratorInfoResponse{} } +func (m *QueryTssFundsMigratorInfoResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTssFundsMigratorInfoResponse) ProtoMessage() {} +func (*QueryTssFundsMigratorInfoResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_25b2aa420449a0c0, []int{3} +} +func (m *QueryTssFundsMigratorInfoResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTssFundsMigratorInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTssFundsMigratorInfoResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTssFundsMigratorInfoResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTssFundsMigratorInfoResponse.Merge(m, src) +} +func (m *QueryTssFundsMigratorInfoResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTssFundsMigratorInfoResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTssFundsMigratorInfoResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTssFundsMigratorInfoResponse proto.InternalMessageInfo + +func (m *QueryTssFundsMigratorInfoResponse) GetTssFundsMigrator() TssFundMigratorInfo { + if m != nil { + return m.TssFundsMigrator + } + return TssFundMigratorInfo{} +} + type QueryGetChainNoncesRequest struct { Index string `protobuf:"bytes,1,opt,name=index,proto3" json:"index,omitempty"` } @@ -40,7 +208,7 @@ func (m *QueryGetChainNoncesRequest) Reset() { *m = QueryGetChainNoncesR func (m *QueryGetChainNoncesRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetChainNoncesRequest) ProtoMessage() {} func (*QueryGetChainNoncesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{0} + return fileDescriptor_25b2aa420449a0c0, []int{4} } func (m *QueryGetChainNoncesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -84,7 +252,7 @@ func (m *QueryGetChainNoncesResponse) Reset() { *m = QueryGetChainNonces func (m *QueryGetChainNoncesResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetChainNoncesResponse) ProtoMessage() {} func (*QueryGetChainNoncesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{1} + return fileDescriptor_25b2aa420449a0c0, []int{5} } func (m *QueryGetChainNoncesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -128,7 +296,7 @@ func (m *QueryAllChainNoncesRequest) Reset() { *m = QueryAllChainNoncesR func (m *QueryAllChainNoncesRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllChainNoncesRequest) ProtoMessage() {} func (*QueryAllChainNoncesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{2} + return fileDescriptor_25b2aa420449a0c0, []int{6} } func (m *QueryAllChainNoncesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -173,7 +341,7 @@ func (m *QueryAllChainNoncesResponse) Reset() { *m = QueryAllChainNonces func (m *QueryAllChainNoncesResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllChainNoncesResponse) ProtoMessage() {} func (*QueryAllChainNoncesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{3} + return fileDescriptor_25b2aa420449a0c0, []int{7} } func (m *QueryAllChainNoncesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -224,7 +392,7 @@ func (m *QueryAllPendingNoncesRequest) Reset() { *m = QueryAllPendingNon func (m *QueryAllPendingNoncesRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllPendingNoncesRequest) ProtoMessage() {} func (*QueryAllPendingNoncesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{4} + return fileDescriptor_25b2aa420449a0c0, []int{8} } func (m *QueryAllPendingNoncesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -269,7 +437,7 @@ func (m *QueryAllPendingNoncesResponse) Reset() { *m = QueryAllPendingNo func (m *QueryAllPendingNoncesResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllPendingNoncesResponse) ProtoMessage() {} func (*QueryAllPendingNoncesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{5} + return fileDescriptor_25b2aa420449a0c0, []int{9} } func (m *QueryAllPendingNoncesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -320,7 +488,7 @@ func (m *QueryPendingNoncesByChainRequest) Reset() { *m = QueryPendingNo func (m *QueryPendingNoncesByChainRequest) String() string { return proto.CompactTextString(m) } func (*QueryPendingNoncesByChainRequest) ProtoMessage() {} func (*QueryPendingNoncesByChainRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{6} + return fileDescriptor_25b2aa420449a0c0, []int{10} } func (m *QueryPendingNoncesByChainRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -364,7 +532,7 @@ func (m *QueryPendingNoncesByChainResponse) Reset() { *m = QueryPendingN func (m *QueryPendingNoncesByChainResponse) String() string { return proto.CompactTextString(m) } func (*QueryPendingNoncesByChainResponse) ProtoMessage() {} func (*QueryPendingNoncesByChainResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{7} + return fileDescriptor_25b2aa420449a0c0, []int{11} } func (m *QueryPendingNoncesByChainResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -407,7 +575,7 @@ func (m *QueryGetTSSRequest) Reset() { *m = QueryGetTSSRequest{} } func (m *QueryGetTSSRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetTSSRequest) ProtoMessage() {} func (*QueryGetTSSRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{8} + return fileDescriptor_25b2aa420449a0c0, []int{12} } func (m *QueryGetTSSRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -444,7 +612,7 @@ func (m *QueryGetTSSResponse) Reset() { *m = QueryGetTSSResponse{} } func (m *QueryGetTSSResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetTSSResponse) ProtoMessage() {} func (*QueryGetTSSResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{9} + return fileDescriptor_25b2aa420449a0c0, []int{13} } func (m *QueryGetTSSResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -488,7 +656,7 @@ func (m *QueryGetTssAddressRequest) Reset() { *m = QueryGetTssAddressReq func (m *QueryGetTssAddressRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetTssAddressRequest) ProtoMessage() {} func (*QueryGetTssAddressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{10} + return fileDescriptor_25b2aa420449a0c0, []int{14} } func (m *QueryGetTssAddressRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -533,7 +701,7 @@ func (m *QueryGetTssAddressResponse) Reset() { *m = QueryGetTssAddressRe func (m *QueryGetTssAddressResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetTssAddressResponse) ProtoMessage() {} func (*QueryGetTssAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{11} + return fileDescriptor_25b2aa420449a0c0, []int{15} } func (m *QueryGetTssAddressResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -589,7 +757,7 @@ func (m *QueryGetTssAddressByFinalizedHeightRequest) String() string { } func (*QueryGetTssAddressByFinalizedHeightRequest) ProtoMessage() {} func (*QueryGetTssAddressByFinalizedHeightRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{12} + return fileDescriptor_25b2aa420449a0c0, []int{16} } func (m *QueryGetTssAddressByFinalizedHeightRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -645,7 +813,7 @@ func (m *QueryGetTssAddressByFinalizedHeightResponse) String() string { } func (*QueryGetTssAddressByFinalizedHeightResponse) ProtoMessage() {} func (*QueryGetTssAddressByFinalizedHeightResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{13} + return fileDescriptor_25b2aa420449a0c0, []int{17} } func (m *QueryGetTssAddressByFinalizedHeightResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -696,7 +864,7 @@ func (m *QueryTssHistoryRequest) Reset() { *m = QueryTssHistoryRequest{} func (m *QueryTssHistoryRequest) String() string { return proto.CompactTextString(m) } func (*QueryTssHistoryRequest) ProtoMessage() {} func (*QueryTssHistoryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{14} + return fileDescriptor_25b2aa420449a0c0, []int{18} } func (m *QueryTssHistoryRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -741,7 +909,7 @@ func (m *QueryTssHistoryResponse) Reset() { *m = QueryTssHistoryResponse func (m *QueryTssHistoryResponse) String() string { return proto.CompactTextString(m) } func (*QueryTssHistoryResponse) ProtoMessage() {} func (*QueryTssHistoryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{15} + return fileDescriptor_25b2aa420449a0c0, []int{19} } func (m *QueryTssHistoryResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -793,7 +961,7 @@ func (m *QueryHasVotedRequest) Reset() { *m = QueryHasVotedRequest{} } func (m *QueryHasVotedRequest) String() string { return proto.CompactTextString(m) } func (*QueryHasVotedRequest) ProtoMessage() {} func (*QueryHasVotedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{16} + return fileDescriptor_25b2aa420449a0c0, []int{20} } func (m *QueryHasVotedRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -844,7 +1012,7 @@ func (m *QueryHasVotedResponse) Reset() { *m = QueryHasVotedResponse{} } func (m *QueryHasVotedResponse) String() string { return proto.CompactTextString(m) } func (*QueryHasVotedResponse) ProtoMessage() {} func (*QueryHasVotedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{17} + return fileDescriptor_25b2aa420449a0c0, []int{21} } func (m *QueryHasVotedResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -888,7 +1056,7 @@ func (m *QueryBallotByIdentifierRequest) Reset() { *m = QueryBallotByIde func (m *QueryBallotByIdentifierRequest) String() string { return proto.CompactTextString(m) } func (*QueryBallotByIdentifierRequest) ProtoMessage() {} func (*QueryBallotByIdentifierRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{18} + return fileDescriptor_25b2aa420449a0c0, []int{22} } func (m *QueryBallotByIdentifierRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -933,7 +1101,7 @@ func (m *VoterList) Reset() { *m = VoterList{} } func (m *VoterList) String() string { return proto.CompactTextString(m) } func (*VoterList) ProtoMessage() {} func (*VoterList) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{19} + return fileDescriptor_25b2aa420449a0c0, []int{23} } func (m *VoterList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -987,7 +1155,7 @@ func (m *QueryBallotByIdentifierResponse) Reset() { *m = QueryBallotById func (m *QueryBallotByIdentifierResponse) String() string { return proto.CompactTextString(m) } func (*QueryBallotByIdentifierResponse) ProtoMessage() {} func (*QueryBallotByIdentifierResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{20} + return fileDescriptor_25b2aa420449a0c0, []int{24} } func (m *QueryBallotByIdentifierResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1051,7 +1219,7 @@ func (m *QueryObserverSet) Reset() { *m = QueryObserverSet{} } func (m *QueryObserverSet) String() string { return proto.CompactTextString(m) } func (*QueryObserverSet) ProtoMessage() {} func (*QueryObserverSet) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{21} + return fileDescriptor_25b2aa420449a0c0, []int{25} } func (m *QueryObserverSet) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1088,7 +1256,7 @@ func (m *QueryObserverSetResponse) Reset() { *m = QueryObserverSetRespon func (m *QueryObserverSetResponse) String() string { return proto.CompactTextString(m) } func (*QueryObserverSetResponse) ProtoMessage() {} func (*QueryObserverSetResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{22} + return fileDescriptor_25b2aa420449a0c0, []int{26} } func (m *QueryObserverSetResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1131,7 +1299,7 @@ func (m *QuerySupportedChains) Reset() { *m = QuerySupportedChains{} } func (m *QuerySupportedChains) String() string { return proto.CompactTextString(m) } func (*QuerySupportedChains) ProtoMessage() {} func (*QuerySupportedChains) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{23} + return fileDescriptor_25b2aa420449a0c0, []int{27} } func (m *QuerySupportedChains) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1168,7 +1336,7 @@ func (m *QuerySupportedChainsResponse) Reset() { *m = QuerySupportedChai func (m *QuerySupportedChainsResponse) String() string { return proto.CompactTextString(m) } func (*QuerySupportedChainsResponse) ProtoMessage() {} func (*QuerySupportedChainsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{24} + return fileDescriptor_25b2aa420449a0c0, []int{28} } func (m *QuerySupportedChainsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1212,7 +1380,7 @@ func (m *QueryGetChainParamsForChainRequest) Reset() { *m = QueryGetChai func (m *QueryGetChainParamsForChainRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetChainParamsForChainRequest) ProtoMessage() {} func (*QueryGetChainParamsForChainRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{25} + return fileDescriptor_25b2aa420449a0c0, []int{29} } func (m *QueryGetChainParamsForChainRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1256,7 +1424,7 @@ func (m *QueryGetChainParamsForChainResponse) Reset() { *m = QueryGetCha func (m *QueryGetChainParamsForChainResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetChainParamsForChainResponse) ProtoMessage() {} func (*QueryGetChainParamsForChainResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{26} + return fileDescriptor_25b2aa420449a0c0, []int{30} } func (m *QueryGetChainParamsForChainResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1299,7 +1467,7 @@ func (m *QueryGetChainParamsRequest) Reset() { *m = QueryGetChainParamsR func (m *QueryGetChainParamsRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetChainParamsRequest) ProtoMessage() {} func (*QueryGetChainParamsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{27} + return fileDescriptor_25b2aa420449a0c0, []int{31} } func (m *QueryGetChainParamsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1336,7 +1504,7 @@ func (m *QueryGetChainParamsResponse) Reset() { *m = QueryGetChainParams func (m *QueryGetChainParamsResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetChainParamsResponse) ProtoMessage() {} func (*QueryGetChainParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{28} + return fileDescriptor_25b2aa420449a0c0, []int{32} } func (m *QueryGetChainParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1380,7 +1548,7 @@ func (m *QueryGetNodeAccountRequest) Reset() { *m = QueryGetNodeAccountR func (m *QueryGetNodeAccountRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetNodeAccountRequest) ProtoMessage() {} func (*QueryGetNodeAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{29} + return fileDescriptor_25b2aa420449a0c0, []int{33} } func (m *QueryGetNodeAccountRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1424,7 +1592,7 @@ func (m *QueryGetNodeAccountResponse) Reset() { *m = QueryGetNodeAccount func (m *QueryGetNodeAccountResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetNodeAccountResponse) ProtoMessage() {} func (*QueryGetNodeAccountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{30} + return fileDescriptor_25b2aa420449a0c0, []int{34} } func (m *QueryGetNodeAccountResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1468,7 +1636,7 @@ func (m *QueryAllNodeAccountRequest) Reset() { *m = QueryAllNodeAccountR func (m *QueryAllNodeAccountRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllNodeAccountRequest) ProtoMessage() {} func (*QueryAllNodeAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{31} + return fileDescriptor_25b2aa420449a0c0, []int{35} } func (m *QueryAllNodeAccountRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1513,7 +1681,7 @@ func (m *QueryAllNodeAccountResponse) Reset() { *m = QueryAllNodeAccount func (m *QueryAllNodeAccountResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllNodeAccountResponse) ProtoMessage() {} func (*QueryAllNodeAccountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{32} + return fileDescriptor_25b2aa420449a0c0, []int{36} } func (m *QueryAllNodeAccountResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1563,7 +1731,7 @@ func (m *QueryGetCrosschainFlagsRequest) Reset() { *m = QueryGetCrosscha func (m *QueryGetCrosschainFlagsRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetCrosschainFlagsRequest) ProtoMessage() {} func (*QueryGetCrosschainFlagsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{33} + return fileDescriptor_25b2aa420449a0c0, []int{37} } func (m *QueryGetCrosschainFlagsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1600,7 +1768,7 @@ func (m *QueryGetCrosschainFlagsResponse) Reset() { *m = QueryGetCrossch func (m *QueryGetCrosschainFlagsResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetCrosschainFlagsResponse) ProtoMessage() {} func (*QueryGetCrosschainFlagsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{34} + return fileDescriptor_25b2aa420449a0c0, []int{38} } func (m *QueryGetCrosschainFlagsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1643,7 +1811,7 @@ func (m *QueryGetKeygenRequest) Reset() { *m = QueryGetKeygenRequest{} } func (m *QueryGetKeygenRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetKeygenRequest) ProtoMessage() {} func (*QueryGetKeygenRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{35} + return fileDescriptor_25b2aa420449a0c0, []int{39} } func (m *QueryGetKeygenRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1680,7 +1848,7 @@ func (m *QueryGetKeygenResponse) Reset() { *m = QueryGetKeygenResponse{} func (m *QueryGetKeygenResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetKeygenResponse) ProtoMessage() {} func (*QueryGetKeygenResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{36} + return fileDescriptor_25b2aa420449a0c0, []int{40} } func (m *QueryGetKeygenResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1723,7 +1891,7 @@ func (m *QueryShowObserverCountRequest) Reset() { *m = QueryShowObserver func (m *QueryShowObserverCountRequest) String() string { return proto.CompactTextString(m) } func (*QueryShowObserverCountRequest) ProtoMessage() {} func (*QueryShowObserverCountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{37} + return fileDescriptor_25b2aa420449a0c0, []int{41} } func (m *QueryShowObserverCountRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1760,7 +1928,7 @@ func (m *QueryShowObserverCountResponse) Reset() { *m = QueryShowObserve func (m *QueryShowObserverCountResponse) String() string { return proto.CompactTextString(m) } func (*QueryShowObserverCountResponse) ProtoMessage() {} func (*QueryShowObserverCountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{38} + return fileDescriptor_25b2aa420449a0c0, []int{42} } func (m *QueryShowObserverCountResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1804,7 +1972,7 @@ func (m *QueryBlameByIdentifierRequest) Reset() { *m = QueryBlameByIdent func (m *QueryBlameByIdentifierRequest) String() string { return proto.CompactTextString(m) } func (*QueryBlameByIdentifierRequest) ProtoMessage() {} func (*QueryBlameByIdentifierRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{39} + return fileDescriptor_25b2aa420449a0c0, []int{43} } func (m *QueryBlameByIdentifierRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1848,7 +2016,7 @@ func (m *QueryBlameByIdentifierResponse) Reset() { *m = QueryBlameByIden func (m *QueryBlameByIdentifierResponse) String() string { return proto.CompactTextString(m) } func (*QueryBlameByIdentifierResponse) ProtoMessage() {} func (*QueryBlameByIdentifierResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{40} + return fileDescriptor_25b2aa420449a0c0, []int{44} } func (m *QueryBlameByIdentifierResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1892,7 +2060,7 @@ func (m *QueryAllBlameRecordsRequest) Reset() { *m = QueryAllBlameRecord func (m *QueryAllBlameRecordsRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllBlameRecordsRequest) ProtoMessage() {} func (*QueryAllBlameRecordsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{41} + return fileDescriptor_25b2aa420449a0c0, []int{45} } func (m *QueryAllBlameRecordsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1937,7 +2105,7 @@ func (m *QueryAllBlameRecordsResponse) Reset() { *m = QueryAllBlameRecor func (m *QueryAllBlameRecordsResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllBlameRecordsResponse) ProtoMessage() {} func (*QueryAllBlameRecordsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{42} + return fileDescriptor_25b2aa420449a0c0, []int{46} } func (m *QueryAllBlameRecordsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1989,7 +2157,7 @@ func (m *QueryBlameByChainAndNonceRequest) Reset() { *m = QueryBlameByCh func (m *QueryBlameByChainAndNonceRequest) String() string { return proto.CompactTextString(m) } func (*QueryBlameByChainAndNonceRequest) ProtoMessage() {} func (*QueryBlameByChainAndNonceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{43} + return fileDescriptor_25b2aa420449a0c0, []int{47} } func (m *QueryBlameByChainAndNonceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2040,7 +2208,7 @@ func (m *QueryBlameByChainAndNonceResponse) Reset() { *m = QueryBlameByC func (m *QueryBlameByChainAndNonceResponse) String() string { return proto.CompactTextString(m) } func (*QueryBlameByChainAndNonceResponse) ProtoMessage() {} func (*QueryBlameByChainAndNonceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_25b2aa420449a0c0, []int{44} + return fileDescriptor_25b2aa420449a0c0, []int{48} } func (m *QueryBlameByChainAndNonceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2077,6 +2245,10 @@ func (m *QueryBlameByChainAndNonceResponse) GetBlameInfo() []*Blame { } func init() { + proto.RegisterType((*QueryTssFundsMigratorInfoAllRequest)(nil), "zetachain.zetacore.observer.QueryTssFundsMigratorInfoAllRequest") + proto.RegisterType((*QueryTssFundsMigratorInfoAllResponse)(nil), "zetachain.zetacore.observer.QueryTssFundsMigratorInfoAllResponse") + proto.RegisterType((*QueryTssFundsMigratorInfoRequest)(nil), "zetachain.zetacore.observer.QueryTssFundsMigratorInfoRequest") + proto.RegisterType((*QueryTssFundsMigratorInfoResponse)(nil), "zetachain.zetacore.observer.QueryTssFundsMigratorInfoResponse") proto.RegisterType((*QueryGetChainNoncesRequest)(nil), "zetachain.zetacore.observer.QueryGetChainNoncesRequest") proto.RegisterType((*QueryGetChainNoncesResponse)(nil), "zetachain.zetacore.observer.QueryGetChainNoncesResponse") proto.RegisterType((*QueryAllChainNoncesRequest)(nil), "zetachain.zetacore.observer.QueryAllChainNoncesRequest") @@ -2129,140 +2301,150 @@ func init() { } var fileDescriptor_25b2aa420449a0c0 = []byte{ - // 2128 bytes of a gzipped FileDescriptorProto + // 2284 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x5a, 0xcf, 0x6f, 0x1b, 0xc7, - 0x15, 0xf6, 0x4a, 0x89, 0x22, 0x3d, 0xd9, 0x92, 0x3c, 0x96, 0x1d, 0x87, 0x76, 0x64, 0x79, 0x65, - 0xc7, 0xb2, 0x62, 0x73, 0x6d, 0x3a, 0xa9, 0x7f, 0xc7, 0x16, 0xdd, 0x58, 0xb2, 0x93, 0xda, 0x0e, - 0xa9, 0x36, 0x80, 0x91, 0x96, 0x5d, 0x92, 0x43, 0x72, 0xeb, 0xd5, 0x0e, 0xb3, 0x33, 0x72, 0xc2, - 0xa8, 0x02, 0x8a, 0x1e, 0x73, 0x2a, 0x50, 0xa0, 0xbd, 0x15, 0xbd, 0xf4, 0x58, 0xa0, 0x08, 0x50, - 0xb4, 0x40, 0xd1, 0x43, 0x4e, 0xcd, 0xa1, 0x87, 0x14, 0x05, 0x8a, 0x9e, 0xda, 0xc0, 0xee, 0xff, - 0xd1, 0x62, 0x67, 0xde, 0x92, 0xbb, 0xcb, 0xe5, 0x72, 0x28, 0xab, 0x27, 0xee, 0xce, 0xbe, 0xf7, - 0xe6, 0xfb, 0xde, 0xce, 0xcc, 0xfb, 0x66, 0x87, 0x70, 0xe6, 0x33, 0x2a, 0xec, 0x5a, 0xcb, 0x76, - 0x3c, 0x4b, 0x5e, 0x31, 0x9f, 0x5a, 0xac, 0xca, 0xa9, 0xff, 0x94, 0xfa, 0xd6, 0xc7, 0x5b, 0xd4, - 0xef, 0xe4, 0xdb, 0x3e, 0x13, 0x8c, 0x1c, 0xeb, 0x1a, 0xe6, 0x43, 0xc3, 0x7c, 0x68, 0x98, 0x5b, - 0xa9, 0x31, 0xbe, 0xc9, 0xb8, 0x55, 0xb5, 0x39, 0x55, 0x5e, 0xd6, 0xd3, 0x8b, 0x55, 0x2a, 0xec, - 0x8b, 0x56, 0xdb, 0x6e, 0x3a, 0x9e, 0x2d, 0x1c, 0xe6, 0xa9, 0x40, 0xb9, 0xf9, 0x26, 0x6b, 0x32, - 0x79, 0x69, 0x05, 0x57, 0xd8, 0x7a, 0xbc, 0xc9, 0x58, 0xd3, 0xa5, 0x96, 0xdd, 0x76, 0x2c, 0xdb, - 0xf3, 0x98, 0x90, 0x2e, 0x1c, 0x9f, 0x2e, 0x67, 0xa1, 0xac, 0xda, 0xae, 0xcb, 0x04, 0x5a, 0x66, - 0xf2, 0xa9, 0xba, 0xf6, 0x26, 0x45, 0xc3, 0x7c, 0x96, 0xa1, 0x6c, 0xaf, 0x78, 0xcc, 0xab, 0xd1, - 0x10, 0x42, 0x21, 0xd3, 0xde, 0x67, 0x9c, 0x2b, 0xa7, 0x86, 0x6b, 0x37, 0xb5, 0x60, 0x3f, 0xa1, - 0x9d, 0x26, 0xf5, 0x74, 0xd0, 0x78, 0xac, 0x4e, 0x2b, 0x76, 0xad, 0xc6, 0xb6, 0xbc, 0x90, 0xe6, - 0x4a, 0x96, 0x7d, 0x78, 0xa1, 0x83, 0xa2, 0x6d, 0xfb, 0xf6, 0x66, 0x88, 0xf7, 0x42, 0xa6, 0x25, - 0xf5, 0xea, 0x8e, 0xd7, 0x8c, 0x67, 0xe5, 0x74, 0x96, 0x87, 0xe0, 0x3c, 0x03, 0x6e, 0xfb, 0x49, - 0x53, 0xe5, 0x99, 0xe3, 0xcf, 0x10, 0xdb, 0xb6, 0xcf, 0x58, 0x83, 0xe3, 0x8f, 0xb2, 0x35, 0x0b, - 0x90, 0xfb, 0x20, 0x18, 0x6d, 0x6b, 0x54, 0xdc, 0x09, 0x3c, 0x1e, 0x48, 0x6c, 0x25, 0xfa, 0xf1, - 0x16, 0xe5, 0x82, 0xcc, 0xc3, 0xcb, 0x8e, 0x57, 0xa7, 0x9f, 0x1e, 0x35, 0x16, 0x8d, 0xe5, 0xa9, - 0x92, 0xba, 0x31, 0x19, 0x1c, 0x4b, 0xf5, 0xe1, 0x6d, 0xe6, 0x71, 0x4a, 0x1e, 0xc1, 0x74, 0xa4, - 0x59, 0xba, 0x4e, 0x17, 0x96, 0xf3, 0x19, 0xa3, 0x3f, 0x1f, 0xb1, 0x2f, 0xbe, 0xf4, 0xd5, 0xbf, - 0x4e, 0xec, 0x2b, 0x45, 0x43, 0x98, 0x75, 0x04, 0xb9, 0xea, 0xba, 0x29, 0x20, 0xef, 0x02, 0xf4, - 0xa6, 0x08, 0x76, 0xf7, 0x46, 0x5e, 0xcd, 0xa7, 0x7c, 0x30, 0x9f, 0xf2, 0x6a, 0x16, 0xe2, 0x7c, - 0xca, 0x3f, 0xb2, 0x9b, 0x14, 0x7d, 0x4b, 0x11, 0x4f, 0xf3, 0x8f, 0x06, 0xf2, 0x4a, 0x76, 0x33, - 0x88, 0xd7, 0xf8, 0x0b, 0xf2, 0x22, 0x6b, 0x31, 0xe4, 0x63, 0x12, 0xf9, 0x99, 0xa1, 0xc8, 0x15, - 0x9c, 0x18, 0xf4, 0x06, 0x1c, 0x0f, 0x91, 0x3f, 0x52, 0x83, 0xec, 0xff, 0x93, 0xa2, 0x2f, 0x0d, - 0x78, 0x7d, 0x40, 0x47, 0x98, 0xa4, 0x0f, 0x61, 0x26, 0x3e, 0xcc, 0x31, 0x4f, 0x2b, 0x99, 0x79, - 0x8a, 0xc5, 0xc2, 0x4c, 0x1d, 0x68, 0x47, 0x1b, 0xf7, 0x2e, 0x57, 0x37, 0x61, 0x51, 0x52, 0x88, - 0xf7, 0xd9, 0x91, 0xef, 0x25, 0xcc, 0xd7, 0x6b, 0x30, 0xa9, 0xd6, 0x22, 0xa7, 0x2e, 0xb3, 0x35, - 0x5e, 0x7a, 0x45, 0xde, 0xdf, 0xab, 0x9b, 0x3f, 0x86, 0x93, 0x19, 0xee, 0x19, 0x59, 0x30, 0xf6, - 0x20, 0x0b, 0xe6, 0x3c, 0x90, 0x70, 0xea, 0x6d, 0x94, 0xcb, 0x08, 0xd7, 0x7c, 0x08, 0x87, 0x62, - 0xad, 0x88, 0xe2, 0x0a, 0x8c, 0x6f, 0x94, 0xcb, 0xd8, 0xf5, 0x62, 0x66, 0xd7, 0x1b, 0xe5, 0x32, - 0x76, 0x18, 0xb8, 0x98, 0xef, 0xc2, 0x6b, 0xdd, 0x80, 0x9c, 0xaf, 0xd6, 0xeb, 0x3e, 0xe5, 0xdd, - 0xc1, 0xb4, 0x0c, 0x73, 0x55, 0x47, 0xd4, 0x98, 0xe3, 0x55, 0xba, 0x49, 0x1a, 0x93, 0x49, 0x9a, - 0xc1, 0xf6, 0x3b, 0x98, 0xab, 0xdb, 0xbd, 0xc5, 0x25, 0x1a, 0x06, 0xe1, 0xcd, 0xc1, 0x38, 0x15, - 0x2d, 0x5c, 0x5a, 0x82, 0xcb, 0xa0, 0xa5, 0x2a, 0x6a, 0x32, 0xd8, 0x54, 0x29, 0xb8, 0x34, 0x3f, - 0x37, 0x60, 0xa5, 0x3f, 0x44, 0xb1, 0x73, 0xd7, 0xf1, 0x6c, 0xd7, 0xf9, 0x8c, 0xd6, 0xd7, 0xa9, - 0xd3, 0x6c, 0x89, 0x10, 0x5a, 0x01, 0x0e, 0x37, 0xc2, 0x27, 0x95, 0x80, 0x65, 0xa5, 0x25, 0x9f, - 0xe3, 0x4b, 0x3c, 0xd4, 0x7d, 0xf8, 0x98, 0x0a, 0x5b, 0xb9, 0x8e, 0x40, 0xe7, 0x03, 0x78, 0x53, - 0x0b, 0xcb, 0x08, 0xfc, 0x7e, 0x08, 0x47, 0x64, 0xc8, 0x0d, 0xce, 0xd7, 0x1d, 0x2e, 0x98, 0xdf, - 0xd9, 0xeb, 0x29, 0xfb, 0x1b, 0x03, 0x5e, 0xed, 0xeb, 0x02, 0x11, 0xae, 0xc2, 0xa4, 0xe0, 0xbc, - 0xe2, 0x3a, 0x5c, 0xe0, 0x34, 0xd5, 0x1d, 0x25, 0xaf, 0x08, 0xce, 0xdf, 0x77, 0xb8, 0xd8, 0xbb, - 0x69, 0xd9, 0x82, 0x79, 0x09, 0x73, 0xdd, 0xe6, 0xdf, 0x63, 0x82, 0xd6, 0xc3, 0x3c, 0xbc, 0x09, - 0x07, 0x95, 0x3c, 0xa9, 0x38, 0x75, 0xea, 0x09, 0xa7, 0xe1, 0x50, 0x1f, 0x73, 0x3a, 0xa7, 0x1e, - 0xdc, 0xeb, 0xb6, 0x93, 0x25, 0x38, 0xf0, 0x94, 0x09, 0xea, 0x57, 0x6c, 0xf5, 0x72, 0x30, 0xd5, - 0xfb, 0x65, 0x23, 0xbe, 0x30, 0xf3, 0x2d, 0x38, 0x9c, 0xe8, 0x09, 0xd3, 0x71, 0x0c, 0xa6, 0x5a, - 0x36, 0xaf, 0x04, 0xc6, 0x6a, 0xda, 0x4f, 0x96, 0x26, 0x5b, 0x68, 0x64, 0x7e, 0x07, 0x16, 0xa4, - 0x57, 0x51, 0xf6, 0x59, 0xec, 0xf4, 0x7a, 0xdd, 0x0d, 0x52, 0x53, 0xc0, 0x54, 0x10, 0xd7, 0x97, - 0x49, 0xec, 0x83, 0x6d, 0xf4, 0xc3, 0x26, 0x45, 0x98, 0x0a, 0xee, 0x2b, 0xa2, 0xd3, 0xa6, 0x92, - 0xd7, 0x4c, 0xe1, 0x74, 0xe6, 0xdb, 0x0a, 0xe2, 0x6f, 0x74, 0xda, 0xb4, 0x34, 0xf9, 0x14, 0xaf, - 0xcc, 0x3f, 0x8c, 0xc1, 0x89, 0x81, 0x2c, 0x30, 0x0b, 0x23, 0x25, 0xfc, 0x1d, 0x98, 0x90, 0x20, - 0x83, 0x4c, 0x8f, 0xcb, 0x11, 0x3a, 0x0c, 0x91, 0x64, 0x5c, 0x42, 0x2f, 0xf2, 0x21, 0xcc, 0xa9, - 0xa7, 0x72, 0x10, 0x28, 0x6e, 0xe3, 0x92, 0xdb, 0xb9, 0xcc, 0x48, 0x0f, 0x7b, 0x4e, 0x92, 0xe2, - 0x2c, 0x8b, 0x37, 0x90, 0x07, 0x70, 0x00, 0x59, 0x70, 0x61, 0x8b, 0x2d, 0x7e, 0xf4, 0x25, 0x19, - 0xf5, 0x6c, 0x66, 0x54, 0x95, 0x95, 0xb2, 0x74, 0x28, 0xed, 0xaf, 0x46, 0xee, 0x4c, 0x02, 0x73, - 0x32, 0x71, 0x0f, 0xd1, 0xb6, 0x4c, 0x85, 0x79, 0x05, 0x8e, 0x26, 0xdb, 0xba, 0x59, 0x3c, 0x0e, - 0x53, 0x61, 0x58, 0x55, 0x02, 0xa7, 0x4a, 0xbd, 0x06, 0xf3, 0x08, 0x0e, 0xf6, 0xf2, 0x56, 0xbb, - 0xcd, 0x7c, 0x41, 0xeb, 0x72, 0x89, 0xe1, 0xe6, 0x47, 0x58, 0xc7, 0x13, 0xed, 0xdd, 0xa8, 0x37, - 0x60, 0x42, 0x29, 0x3d, 0x9c, 0xae, 0xa7, 0xd2, 0xe8, 0xb4, 0x9f, 0x34, 0xf3, 0xa8, 0x07, 0x55, - 0x55, 0x42, 0x1f, 0xf3, 0x16, 0x98, 0x31, 0xdd, 0xf6, 0x48, 0x2a, 0xd7, 0xbb, 0xcc, 0xd7, 0xad, - 0x7d, 0x3e, 0x2c, 0x65, 0x06, 0x40, 0x94, 0xef, 0xc1, 0x7e, 0x15, 0x41, 0x49, 0x63, 0x7d, 0x05, - 0xa8, 0xe2, 0x95, 0xa6, 0x6b, 0xbd, 0x1b, 0xf3, 0x78, 0x42, 0xa0, 0xa2, 0x0d, 0x56, 0x3e, 0x2f, - 0x21, 0x45, 0xc3, 0xa7, 0x88, 0xe4, 0x61, 0x2a, 0x92, 0x73, 0xba, 0x48, 0xe4, 0x50, 0x8d, 0xa1, - 0x89, 0xc8, 0xe5, 0x07, 0xac, 0x4e, 0x57, 0xd5, 0x96, 0x22, 0x5b, 0x2e, 0xff, 0xa8, 0x87, 0x31, - 0xe6, 0xd3, 0xcb, 0x56, 0x74, 0x7b, 0xa2, 0x95, 0xad, 0x68, 0x9c, 0x69, 0xaf, 0x77, 0x13, 0x55, - 0xca, 0x29, 0xf8, 0xf6, 0xaa, 0xa6, 0x7c, 0x11, 0x51, 0xca, 0x69, 0x94, 0xee, 0xc3, 0x74, 0xa4, - 0x59, 0x4b, 0x29, 0xc7, 0x18, 0x45, 0x6e, 0xf6, 0xae, 0xc0, 0x2c, 0xe2, 0x02, 0x1e, 0x0c, 0x95, - 0xee, 0x66, 0xf3, 0x6e, 0xb0, 0xd7, 0x0c, 0x07, 0xd3, 0x4f, 0x0c, 0x5c, 0x1d, 0xd3, 0x4c, 0x90, - 0xda, 0xf7, 0x61, 0x2e, 0xb9, 0x55, 0xd5, 0x1b, 0x55, 0xf1, 0x78, 0x58, 0x46, 0x67, 0x6b, 0xf1, - 0x66, 0xf3, 0x55, 0xac, 0x4d, 0x6b, 0x54, 0xbc, 0x27, 0x77, 0xb7, 0x21, 0xb6, 0xef, 0xa2, 0x50, - 0x88, 0x3c, 0x40, 0x44, 0xd7, 0x61, 0x42, 0x6d, 0x84, 0x11, 0xc7, 0x52, 0x26, 0x0e, 0x74, 0x46, - 0x17, 0xf3, 0x04, 0xea, 0xf9, 0x72, 0x8b, 0x7d, 0x12, 0x2e, 0x63, 0x77, 0x22, 0x43, 0x26, 0xc8, - 0xc9, 0xc2, 0x20, 0x0b, 0x04, 0xf0, 0x03, 0x38, 0xe4, 0xda, 0x5c, 0x54, 0xc2, 0x3e, 0x2a, 0xd1, - 0x71, 0x9c, 0xcf, 0x44, 0xf3, 0xbe, 0xcd, 0x45, 0x3c, 0xe8, 0x41, 0x37, 0xd9, 0x64, 0xde, 0x47, - 0x8c, 0x45, 0xd7, 0xde, 0xa4, 0x69, 0x85, 0xf7, 0x2c, 0xcc, 0xc9, 0xef, 0x12, 0xfd, 0x05, 0x6b, - 0x56, 0xb6, 0x47, 0xca, 0x6e, 0x2d, 0xac, 0xe2, 0xfd, 0xb1, 0xba, 0x9a, 0x08, 0x30, 0x98, 0xd7, - 0x60, 0x48, 0xc2, 0xcc, 0xae, 0x1a, 0x81, 0x79, 0x69, 0x4a, 0x75, 0xe5, 0x35, 0x98, 0x49, 0x7b, - 0xb3, 0x43, 0x3d, 0xa3, 0x35, 0xe6, 0xd7, 0xf7, 0x7c, 0x33, 0xf6, 0x3b, 0xa3, 0xb7, 0xeb, 0x8b, - 0xf7, 0x83, 0x54, 0xd6, 0x12, 0x54, 0xc6, 0xf5, 0xa8, 0xe0, 0xd8, 0xec, 0x11, 0xda, 0xbb, 0x39, - 0x58, 0xc6, 0xbd, 0x17, 0xa6, 0x5f, 0x2e, 0xb5, 0xab, 0x5e, 0x5d, 0x6e, 0x6e, 0x86, 0xd7, 0x9f, - 0x60, 0x7d, 0x95, 0xdb, 0x29, 0xd4, 0xe7, 0xea, 0xc6, 0x6c, 0xe0, 0x8e, 0x2c, 0x3d, 0xe8, 0x80, - 0xd7, 0x3a, 0x3e, 0xf2, 0x6b, 0x2d, 0xfc, 0x77, 0x11, 0x5e, 0x96, 0x1d, 0x91, 0x3f, 0x1b, 0x30, - 0x19, 0xaa, 0x47, 0x72, 0x31, 0x33, 0x4a, 0x9a, 0xa6, 0xcd, 0x15, 0x46, 0x71, 0x51, 0x04, 0xcc, - 0xfb, 0x3f, 0xfd, 0xfb, 0x7f, 0x7e, 0x3e, 0xf6, 0x6d, 0x52, 0x94, 0xdf, 0x74, 0xce, 0xab, 0xcf, - 0x3b, 0xdd, 0x0f, 0x45, 0x5d, 0xdd, 0x6a, 0x6d, 0xf7, 0x89, 0xb7, 0x1d, 0x6b, 0x3b, 0xa6, 0x2e, - 0x77, 0xc8, 0x3f, 0x0c, 0x20, 0xfd, 0x0a, 0x90, 0x5c, 0x1f, 0x0e, 0x6b, 0xa0, 0xfa, 0xcd, 0xdd, - 0xd8, 0x9d, 0x33, 0xb2, 0x7b, 0x57, 0xb2, 0xbb, 0x45, 0x6e, 0xa6, 0xb2, 0x43, 0x4a, 0xd5, 0x4e, - 0x84, 0x55, 0x1a, 0x51, 0xf2, 0x2b, 0x03, 0xa6, 0x23, 0x6a, 0x8c, 0x9c, 0x1f, 0x0e, 0x2a, 0x62, - 0x9e, 0x7b, 0x7b, 0x24, 0xf3, 0x2e, 0xf8, 0xb3, 0x12, 0xfc, 0x12, 0x39, 0x99, 0x0a, 0xbe, 0xbb, - 0x2c, 0x72, 0x2a, 0xc8, 0x6f, 0x0d, 0x98, 0x4d, 0x88, 0x3b, 0x9d, 0x01, 0x94, 0x70, 0xc9, 0x5d, - 0x1d, 0xd9, 0xa5, 0x0b, 0xf6, 0x9c, 0x04, 0xfb, 0x06, 0x39, 0x95, 0x0a, 0x96, 0x27, 0xb0, 0xfd, - 0xdb, 0x80, 0x23, 0xe9, 0x6a, 0x8f, 0xdc, 0x1a, 0x8e, 0x21, 0x53, 0x68, 0xe6, 0x6e, 0xef, 0x3e, - 0x00, 0x72, 0x29, 0x4a, 0x2e, 0x37, 0xc8, 0xb5, 0x54, 0x2e, 0x4d, 0x2a, 0x2a, 0x51, 0xf5, 0x57, - 0x69, 0x30, 0x5f, 0x35, 0x58, 0xdb, 0xe1, 0x0a, 0xb3, 0x43, 0xbe, 0x30, 0x60, 0x26, 0xde, 0x0d, - 0xb9, 0x3c, 0x2a, 0xb0, 0x90, 0xd1, 0x95, 0xd1, 0x1d, 0x91, 0xc9, 0x79, 0xc9, 0xe4, 0x0c, 0x39, - 0xad, 0xc5, 0x24, 0x00, 0x1d, 0x13, 0x49, 0x7a, 0x88, 0xfb, 0x15, 0xa1, 0x26, 0xe2, 0x14, 0x8d, - 0x67, 0x5e, 0x90, 0x88, 0x57, 0xc8, 0x72, 0x2a, 0xe2, 0x88, 0x26, 0xb5, 0xb6, 0xa5, 0x0c, 0xde, - 0x09, 0xc6, 0xfe, 0x4c, 0x24, 0xd2, 0xaa, 0xeb, 0xea, 0xe0, 0x4e, 0x55, 0xb2, 0x3a, 0xb8, 0xd3, - 0xb5, 0xa9, 0xb9, 0x2c, 0x71, 0x9b, 0x64, 0x71, 0x18, 0x6e, 0xf2, 0x27, 0x03, 0x66, 0x13, 0xb2, - 0x4d, 0x67, 0x89, 0x1c, 0xa8, 0x2f, 0x75, 0x96, 0xc8, 0xc1, 0xca, 0x73, 0xc8, 0x10, 0x49, 0x8a, - 0x52, 0xf2, 0x0b, 0x03, 0x26, 0x94, 0xd8, 0x23, 0x05, 0xad, 0x7e, 0x63, 0x7a, 0x33, 0x77, 0x69, - 0x24, 0x1f, 0x84, 0xb8, 0x24, 0x21, 0xbe, 0x4e, 0x8e, 0xa5, 0x42, 0x54, 0x92, 0x93, 0xfc, 0xc5, - 0x80, 0x83, 0x7d, 0x62, 0x92, 0x5c, 0xd3, 0x58, 0xd1, 0x06, 0x68, 0xd4, 0xdc, 0xf5, 0x5d, 0xf9, - 0x22, 0xe6, 0xab, 0x12, 0xf3, 0x25, 0x72, 0x31, 0x8a, 0xb9, 0xff, 0x24, 0x86, 0xb7, 0xd8, 0x27, - 0x09, 0x85, 0x4b, 0xfe, 0x66, 0xc0, 0xc1, 0x3e, 0x21, 0xa9, 0xc3, 0x64, 0x90, 0x92, 0xd5, 0x61, - 0x32, 0x50, 0xb9, 0x9a, 0x77, 0x24, 0x93, 0x9b, 0xe4, 0x7a, 0x7a, 0x0d, 0x95, 0xea, 0x27, 0x59, - 0x42, 0x13, 0xb2, 0x79, 0x27, 0x90, 0x36, 0x64, 0x8d, 0x8a, 0x84, 0xa4, 0x24, 0x7a, 0xf3, 0x2d, - 0x45, 0xed, 0xea, 0x94, 0xaa, 0x01, 0xfa, 0xd5, 0x2c, 0x48, 0x42, 0xe7, 0xc8, 0xca, 0xc0, 0x45, - 0xd1, 0x76, 0xdd, 0x8a, 0xe2, 0xe0, 0x23, 0xd0, 0x6f, 0x0c, 0x38, 0x2c, 0x83, 0xf1, 0x84, 0x12, - 0x24, 0x37, 0xb5, 0x73, 0x9b, 0x26, 0x4b, 0x73, 0xef, 0xec, 0xd6, 0x1d, 0xc9, 0xac, 0x4b, 0x32, - 0x45, 0x72, 0x3b, 0xfb, 0xed, 0xa8, 0x29, 0x6c, 0x7b, 0x75, 0x75, 0x70, 0x10, 0xa9, 0x54, 0xd6, - 0xb6, 0x6c, 0xd9, 0x21, 0x5f, 0x1a, 0x70, 0x20, 0xf6, 0x09, 0x9a, 0x7c, 0x4b, 0x6b, 0xb2, 0xf6, - 0x7d, 0xc9, 0xcf, 0x5d, 0x1e, 0xd9, 0x0f, 0xc9, 0xdc, 0x92, 0x64, 0xae, 0x92, 0xcb, 0x03, 0xdf, - 0x8c, 0xe0, 0x3c, 0xd4, 0x9b, 0xd6, 0x76, 0xf2, 0xfb, 0xfa, 0x0e, 0xf9, 0xe5, 0x18, 0x2c, 0x64, - 0x7f, 0x46, 0x27, 0x6b, 0x23, 0x82, 0x1b, 0x74, 0x28, 0x90, 0x5b, 0x7f, 0xf1, 0x40, 0x48, 0xbb, - 0x2a, 0x69, 0x7f, 0x44, 0x1e, 0xeb, 0xd0, 0xae, 0xb4, 0xe4, 0xd7, 0x76, 0xa7, 0x66, 0xbb, 0xd6, - 0x76, 0xea, 0xa9, 0xc4, 0x4e, 0x5a, 0x66, 0x3e, 0x37, 0xe4, 0xa9, 0x0d, 0xb1, 0xf4, 0x50, 0x77, - 0x0f, 0x81, 0x72, 0x17, 0xf4, 0x1d, 0x90, 0xce, 0xa2, 0xa4, 0x93, 0x23, 0x47, 0x53, 0xe9, 0x04, - 0x20, 0x7e, 0x6d, 0x00, 0xf4, 0xce, 0x0d, 0x88, 0x46, 0x51, 0xe8, 0x3b, 0xc8, 0xc8, 0xbd, 0x35, - 0x9a, 0x13, 0x62, 0x3b, 0x23, 0xb1, 0x9d, 0x24, 0x27, 0x52, 0xb1, 0x89, 0x1e, 0xa6, 0xdf, 0x1b, - 0x30, 0x17, 0x3b, 0x38, 0x0b, 0x74, 0x85, 0xde, 0xa2, 0x93, 0x76, 0x54, 0x9a, 0xbb, 0xb6, 0x1b, - 0x57, 0x04, 0xbd, 0x22, 0x41, 0x9f, 0x22, 0x66, 0x2a, 0xe8, 0xf8, 0x79, 0xe6, 0x5f, 0x0d, 0x98, - 0x4f, 0x3b, 0x43, 0xd4, 0x59, 0xa7, 0x32, 0x8e, 0x2e, 0x75, 0xd6, 0xa9, 0xac, 0xa3, 0x4b, 0xf3, - 0x6d, 0xc9, 0xc1, 0x22, 0xe7, 0x87, 0x73, 0x48, 0xc8, 0xe8, 0xd8, 0xd1, 0xf6, 0x08, 0x1a, 0x3a, - 0x9e, 0xff, 0x2b, 0xa3, 0x3b, 0x6a, 0x29, 0xd2, 0x5a, 0xcf, 0x23, 0xa6, 0x48, 0x23, 0x91, 0xf4, - 0x15, 0xe9, 0xee, 0x70, 0xa7, 0xff, 0xaf, 0x60, 0x88, 0x22, 0x8d, 0xe0, 0x2e, 0xde, 0xfb, 0xea, - 0xd9, 0x82, 0xf1, 0xf5, 0xb3, 0x05, 0xe3, 0x9b, 0x67, 0x0b, 0xc6, 0xcf, 0x9e, 0x2f, 0xec, 0xfb, - 0xfa, 0xf9, 0xc2, 0xbe, 0x7f, 0x3e, 0x5f, 0xd8, 0xf7, 0xd8, 0x6a, 0x3a, 0xa2, 0xb5, 0x55, 0xcd, - 0xd7, 0xd8, 0x66, 0xaa, 0x8e, 0xf9, 0x34, 0x32, 0x77, 0x3a, 0x6d, 0xca, 0xab, 0x13, 0xf2, 0xef, - 0x1f, 0x97, 0xfe, 0x17, 0x00, 0x00, 0xff, 0xff, 0x19, 0xf9, 0xb3, 0x69, 0xbe, 0x24, 0x00, 0x00, + 0x15, 0xf6, 0x4a, 0x89, 0x22, 0x8d, 0x6c, 0xfd, 0x18, 0xcb, 0xb6, 0x42, 0x3b, 0xb2, 0x3c, 0x92, + 0x63, 0x59, 0x91, 0xb9, 0xb6, 0xec, 0xd4, 0xbf, 0x63, 0x8b, 0x6e, 0x24, 0xd9, 0x49, 0x6c, 0x87, + 0x74, 0x1b, 0xc0, 0x48, 0xcb, 0x2e, 0xc9, 0x21, 0xb9, 0xf5, 0x6a, 0x87, 0xd9, 0x19, 0x39, 0x61, + 0x54, 0x01, 0x45, 0x6f, 0xcd, 0xa1, 0x28, 0x50, 0xa0, 0xbd, 0x15, 0xb9, 0xf4, 0x58, 0xa0, 0x08, + 0x50, 0xb4, 0x40, 0xd1, 0x43, 0x4e, 0xcd, 0xa1, 0x87, 0x14, 0x2d, 0x8a, 0x9e, 0xda, 0xc0, 0xee, + 0x1f, 0x52, 0xec, 0xcc, 0x5b, 0x72, 0x77, 0xb9, 0xbb, 0x1c, 0xca, 0xea, 0x89, 0xdc, 0xd9, 0x79, + 0x6f, 0xbe, 0xef, 0xed, 0xcc, 0x7b, 0xdf, 0xce, 0x2c, 0x3a, 0xf3, 0x29, 0x15, 0x56, 0xb5, 0x69, + 0xd9, 0xae, 0x29, 0xff, 0x31, 0x8f, 0x9a, 0xac, 0xc2, 0xa9, 0xf7, 0x94, 0x7a, 0xe6, 0x47, 0xdb, + 0xd4, 0x6b, 0xe7, 0x5b, 0x1e, 0x13, 0x0c, 0x1f, 0xef, 0x74, 0xcc, 0x07, 0x1d, 0xf3, 0x41, 0xc7, + 0xdc, 0x72, 0x95, 0xf1, 0x2d, 0xc6, 0xcd, 0x8a, 0xc5, 0xa9, 0xb2, 0x32, 0x9f, 0x5e, 0xa8, 0x50, + 0x61, 0x5d, 0x30, 0x5b, 0x56, 0xc3, 0x76, 0x2d, 0x61, 0x33, 0x57, 0x39, 0xca, 0xcd, 0x34, 0x58, + 0x83, 0xc9, 0xbf, 0xa6, 0xff, 0x0f, 0x5a, 0x4f, 0x34, 0x18, 0x6b, 0x38, 0xd4, 0xb4, 0x5a, 0xb6, + 0x69, 0xb9, 0x2e, 0x13, 0xd2, 0x84, 0xc3, 0xdd, 0xa5, 0x2c, 0x94, 0x15, 0xcb, 0x71, 0x98, 0x80, + 0x9e, 0x99, 0x7c, 0x2a, 0x8e, 0xb5, 0x45, 0xa1, 0x63, 0x3e, 0xab, 0xa3, 0x6c, 0x2f, 0xbb, 0xcc, + 0xad, 0xd2, 0x00, 0xc2, 0x6a, 0x66, 0x7f, 0x8f, 0x71, 0xae, 0x8c, 0xea, 0x8e, 0xd5, 0xd0, 0x82, + 0xfd, 0x84, 0xb6, 0x1b, 0xd4, 0xd5, 0x41, 0xe3, 0xb2, 0x1a, 0x2d, 0x5b, 0xd5, 0x2a, 0xdb, 0x76, + 0x03, 0x9a, 0xcb, 0x59, 0xfd, 0x83, 0x3f, 0x3a, 0x28, 0x5a, 0x96, 0x67, 0x6d, 0x05, 0x78, 0xcf, + 0x67, 0xf6, 0xa4, 0x6e, 0xcd, 0x76, 0x1b, 0xd1, 0xa8, 0x9c, 0xce, 0xb2, 0x10, 0x9c, 0x67, 0xc0, + 0x6d, 0x3d, 0x69, 0xa8, 0x38, 0x73, 0xf8, 0xe9, 0xd3, 0xb7, 0xe5, 0x31, 0x56, 0xe7, 0xf0, 0x03, + 0x7d, 0x2f, 0xf5, 0x19, 0xbe, 0x5c, 0xdf, 0x76, 0x6b, 0xbc, 0xbc, 0x65, 0x37, 0x3c, 0x4b, 0x30, + 0x08, 0x08, 0x39, 0x8d, 0x16, 0xde, 0xf7, 0xe7, 0xe8, 0x23, 0xce, 0xd7, 0xfd, 0xfb, 0xef, 0xc1, + 0xed, 0xbb, 0x6e, 0x9d, 0xad, 0x39, 0x4e, 0x91, 0x7e, 0xb4, 0x4d, 0xb9, 0x20, 0x3f, 0x33, 0xd0, + 0x62, 0x76, 0x3f, 0xde, 0x62, 0x2e, 0xa7, 0xb8, 0x8e, 0x0e, 0xf7, 0x8e, 0xc5, 0x67, 0x8d, 0xf9, + 0xe1, 0xa5, 0xf1, 0xd5, 0xf3, 0xf9, 0x8c, 0x85, 0x93, 0x07, 0xd7, 0x61, 0xcf, 0x85, 0x97, 0xbe, + 0xfa, 0xf7, 0xc9, 0x03, 0xc5, 0x69, 0x11, 0x1b, 0x95, 0x93, 0x9b, 0x68, 0x3e, 0x15, 0x0f, 0x80, + 0xc6, 0xaf, 0xa2, 0x51, 0x35, 0x0f, 0xed, 0xda, 0xac, 0x31, 0x6f, 0x2c, 0x0d, 0x17, 0x5f, 0x91, + 0xd7, 0x77, 0x6b, 0xe4, 0xa7, 0x06, 0x3a, 0x95, 0x61, 0x0f, 0x64, 0x6a, 0x08, 0xf7, 0x92, 0x91, + 0xae, 0xf6, 0xce, 0x65, 0x2a, 0xce, 0x85, 0xac, 0xa2, 0x9c, 0x84, 0xb2, 0x41, 0xc5, 0x1d, 0xdf, + 0xdd, 0x7d, 0x39, 0xa9, 0x02, 0x12, 0x33, 0xe8, 0x65, 0xdb, 0xad, 0xd1, 0x4f, 0xe4, 0xb0, 0x63, + 0x45, 0x75, 0x41, 0x18, 0x3a, 0x9e, 0x68, 0x03, 0xc0, 0x1f, 0xa2, 0xf1, 0x50, 0x33, 0x20, 0x5e, + 0xca, 0x44, 0x1c, 0xea, 0x0f, 0x48, 0xc3, 0x2e, 0x48, 0x0d, 0x40, 0xae, 0x39, 0x4e, 0x02, 0xc8, + 0x75, 0x84, 0xba, 0xb9, 0x0d, 0x86, 0x7b, 0x3d, 0xaf, 0x12, 0x61, 0xde, 0x4f, 0x84, 0x79, 0x95, + 0x3e, 0x21, 0x11, 0xe6, 0x1f, 0x5a, 0x0d, 0x0a, 0xb6, 0xc5, 0x90, 0x25, 0xf9, 0xa3, 0x01, 0xbc, + 0xe2, 0xc3, 0xa4, 0xf1, 0x1a, 0x7e, 0x41, 0x5e, 0x78, 0x23, 0x82, 0x7c, 0x48, 0x22, 0x3f, 0xd3, + 0x17, 0xb9, 0x82, 0x13, 0x81, 0x5e, 0x47, 0x27, 0x02, 0xe4, 0x0f, 0x55, 0x76, 0xf8, 0xff, 0x84, + 0xe8, 0x4b, 0x03, 0xbd, 0x96, 0x32, 0x10, 0x04, 0xe9, 0x03, 0x34, 0x11, 0xcd, 0x4f, 0x10, 0xa7, + 0xe5, 0xcc, 0x38, 0x45, 0x7c, 0x41, 0xa4, 0x0e, 0xb5, 0xc2, 0x8d, 0xfb, 0x17, 0xab, 0x60, 0xf1, + 0x46, 0xc7, 0x6c, 0xcb, 0xe7, 0xa2, 0xb1, 0x78, 0x7f, 0x04, 0x6b, 0x37, 0xd9, 0x3c, 0x23, 0x0a, + 0xc6, 0x3e, 0x44, 0x81, 0xcc, 0x20, 0x1c, 0x2c, 0xbd, 0x47, 0xa5, 0x52, 0x90, 0x20, 0x1f, 0xa0, + 0xc3, 0x91, 0x56, 0x40, 0x71, 0x05, 0x0d, 0x3f, 0x2a, 0x95, 0x60, 0xe8, 0xf9, 0xec, 0x94, 0x51, + 0x2a, 0xc1, 0x80, 0xbe, 0x09, 0x79, 0x1b, 0xbd, 0xda, 0x71, 0xc8, 0xf9, 0x5a, 0xad, 0xe6, 0x51, + 0xde, 0x99, 0x4c, 0x4b, 0x68, 0xaa, 0x62, 0x8b, 0x2a, 0xb3, 0xdd, 0x72, 0x27, 0x48, 0x43, 0x32, + 0x48, 0x13, 0xd0, 0x7e, 0x07, 0x62, 0x75, 0xbb, 0x9b, 0x5c, 0xc2, 0x6e, 0x00, 0xde, 0x14, 0x1a, + 0xa6, 0xa2, 0x09, 0xa9, 0xc5, 0xff, 0xeb, 0xb7, 0x54, 0x44, 0x55, 0x3a, 0x1b, 0x2b, 0xfa, 0x7f, + 0xc9, 0x67, 0x06, 0x5a, 0xee, 0x75, 0x51, 0x68, 0xaf, 0xdb, 0xae, 0xe5, 0xd8, 0x9f, 0xd2, 0xda, + 0x26, 0xb5, 0x1b, 0x4d, 0x11, 0x40, 0x5b, 0x45, 0x47, 0xea, 0xc1, 0x9d, 0xb2, 0xcf, 0xb2, 0xdc, + 0x94, 0xf7, 0xe1, 0x21, 0x1e, 0xee, 0xdc, 0x7c, 0x4c, 0x85, 0xa5, 0x4c, 0x07, 0xa0, 0xf3, 0x3e, + 0x7a, 0x43, 0x0b, 0xcb, 0x00, 0xfc, 0x7e, 0x80, 0x8e, 0x06, 0x95, 0x60, 0xd3, 0xe6, 0x82, 0x79, + 0xed, 0xfd, 0x5e, 0xb2, 0xbf, 0x31, 0xd0, 0xb1, 0x9e, 0x21, 0x00, 0xe1, 0x1a, 0x1a, 0xf5, 0x4b, + 0x8c, 0x63, 0x73, 0x01, 0xcb, 0x54, 0x77, 0x96, 0xbc, 0x22, 0x38, 0x7f, 0xd7, 0xe6, 0x62, 0xff, + 0x96, 0x65, 0x13, 0xcd, 0x48, 0x98, 0x9b, 0x16, 0xff, 0x2e, 0x13, 0xb4, 0x16, 0xc4, 0xe1, 0x0d, + 0x34, 0xad, 0x74, 0x65, 0xd9, 0xae, 0x51, 0x57, 0xd8, 0x75, 0x9b, 0x7a, 0x10, 0xd3, 0x29, 0x75, + 0xe3, 0x6e, 0xa7, 0x1d, 0x2f, 0xa0, 0x43, 0x4f, 0x99, 0xa0, 0x5e, 0xd9, 0x52, 0x0f, 0x07, 0x42, + 0x7d, 0x50, 0x36, 0xc2, 0x03, 0x23, 0x97, 0xd0, 0x91, 0xd8, 0x48, 0x10, 0x8e, 0xe3, 0x68, 0xac, + 0x69, 0xf1, 0xb2, 0xdf, 0x59, 0x2d, 0xfb, 0xd1, 0xe2, 0x68, 0x13, 0x3a, 0x91, 0xf7, 0xd0, 0x9c, + 0xb4, 0x2a, 0xc8, 0x31, 0x0b, 0xed, 0xee, 0xa8, 0x7b, 0x41, 0x4a, 0x04, 0x1a, 0xf3, 0xfd, 0x7a, + 0x32, 0x88, 0x3d, 0xb0, 0x8d, 0x5e, 0xd8, 0xb8, 0x80, 0xc6, 0xfc, 0xeb, 0xb2, 0x68, 0xb7, 0xa8, + 0xe4, 0x35, 0xb1, 0x7a, 0x3a, 0xf3, 0x69, 0xf9, 0xfe, 0x1f, 0xb5, 0x5b, 0xb4, 0x38, 0xfa, 0x14, + 0xfe, 0x91, 0x3f, 0x0c, 0xa1, 0x93, 0xa9, 0x2c, 0x20, 0x0a, 0x03, 0x05, 0xfc, 0x2d, 0x34, 0x22, + 0x41, 0xfa, 0x91, 0x1e, 0x96, 0x33, 0xb4, 0x1f, 0x22, 0xc9, 0xb8, 0x08, 0x56, 0xf8, 0x03, 0x34, + 0xa5, 0xee, 0xca, 0x49, 0xa0, 0xb8, 0x0d, 0x4b, 0x6e, 0x2b, 0x99, 0x9e, 0x1e, 0x74, 0x8d, 0x24, + 0xc5, 0x49, 0x16, 0x6d, 0xc0, 0xf7, 0xd1, 0x21, 0x60, 0xc1, 0x85, 0x25, 0xb6, 0xf9, 0xec, 0x4b, + 0xd2, 0xeb, 0xd9, 0x4c, 0xaf, 0x2a, 0x2a, 0x25, 0x69, 0x50, 0x3c, 0x58, 0x09, 0x5d, 0x11, 0x8c, + 0xa6, 0x64, 0xe0, 0x1e, 0x40, 0xdf, 0x12, 0x15, 0xe4, 0x0a, 0x9a, 0x8d, 0xb7, 0x75, 0xa2, 0x78, + 0x02, 0x8d, 0x05, 0x6e, 0x55, 0x09, 0x1c, 0x2b, 0x76, 0x1b, 0xc8, 0x51, 0x98, 0xec, 0xa5, 0xed, + 0x56, 0x8b, 0x79, 0x82, 0xd6, 0x64, 0x8a, 0xe1, 0xe4, 0x43, 0xa8, 0xe3, 0xb1, 0xf6, 0x8e, 0xd7, + 0x1b, 0x68, 0x44, 0x49, 0x74, 0x58, 0xae, 0x8b, 0x49, 0x74, 0x5a, 0x4f, 0x1a, 0x79, 0x10, 0xf2, + 0xaa, 0x2a, 0x81, 0x0d, 0xb9, 0x85, 0x48, 0x44, 0xb7, 0x3d, 0x94, 0xaf, 0x1c, 0xeb, 0xcc, 0xd3, + 0xad, 0x7d, 0x1e, 0xe8, 0xf5, 0x34, 0x07, 0x80, 0xf2, 0x1d, 0x74, 0x50, 0x79, 0x50, 0xef, 0x34, + 0xfa, 0x0a, 0x50, 0xf9, 0x2b, 0x8e, 0x57, 0xbb, 0x17, 0xe4, 0x44, 0x4c, 0xa0, 0x42, 0x1f, 0xa8, + 0x7c, 0x6e, 0x4c, 0x8a, 0x06, 0x77, 0x01, 0xc9, 0x83, 0x44, 0x24, 0x2b, 0xba, 0x48, 0xe4, 0x54, + 0x8d, 0xa0, 0x09, 0xc9, 0xe5, 0xfb, 0xac, 0x46, 0xd7, 0xd4, 0xbb, 0x60, 0xb6, 0x5c, 0xfe, 0x61, + 0x17, 0x63, 0xc4, 0xa6, 0x1b, 0xad, 0xf0, 0x7b, 0xa5, 0x56, 0xb4, 0xc2, 0x7e, 0xc6, 0xdd, 0xee, + 0x45, 0x58, 0x29, 0x27, 0xe0, 0xdb, 0xaf, 0x9a, 0xf2, 0x45, 0x48, 0x29, 0x27, 0x51, 0xba, 0x87, + 0xc6, 0x43, 0xcd, 0x5a, 0x4a, 0x39, 0xc2, 0x28, 0x74, 0xb1, 0x7f, 0x05, 0x66, 0x1e, 0x12, 0xb8, + 0x3f, 0x55, 0x3a, 0xbb, 0x04, 0xeb, 0x8e, 0xd5, 0xe8, 0x4c, 0xa6, 0x1f, 0x1b, 0x90, 0x1d, 0x93, + 0xba, 0x00, 0xb5, 0xef, 0xa1, 0xa9, 0xf8, 0x1e, 0x83, 0xde, 0xac, 0x8a, 0xfa, 0x83, 0x32, 0x3a, + 0x59, 0x8d, 0x36, 0x93, 0x63, 0x50, 0x9b, 0x36, 0xa8, 0x78, 0x47, 0x6e, 0x4b, 0x04, 0xd8, 0xbe, + 0x03, 0x42, 0x21, 0x74, 0x03, 0x10, 0x5d, 0x47, 0x23, 0x6a, 0x07, 0x03, 0x70, 0x2c, 0x64, 0xe2, + 0x00, 0x63, 0x30, 0x21, 0x27, 0x41, 0xcf, 0x97, 0x9a, 0xec, 0xe3, 0x20, 0x8d, 0xdd, 0x09, 0x4d, + 0x19, 0x3f, 0x26, 0x73, 0x69, 0x3d, 0x00, 0xc0, 0xf7, 0xd1, 0x61, 0xc7, 0xe2, 0xa2, 0x1c, 0x8c, + 0x51, 0x0e, 0xcf, 0xe3, 0x7c, 0x26, 0x9a, 0x77, 0x2d, 0x2e, 0xa2, 0x4e, 0xa7, 0x9d, 0x78, 0x13, + 0xb9, 0x07, 0x18, 0x0b, 0x8e, 0xb5, 0x45, 0x93, 0x0a, 0xef, 0x59, 0x34, 0x25, 0x37, 0x94, 0x7a, + 0x0b, 0xd6, 0xa4, 0x6c, 0x0f, 0x95, 0xdd, 0x6a, 0x50, 0xc5, 0x7b, 0x7d, 0x75, 0x34, 0x11, 0x02, + 0x67, 0x6e, 0x9d, 0x01, 0x09, 0x92, 0x5d, 0x35, 0xfc, 0xee, 0xc5, 0x31, 0x35, 0x94, 0x5b, 0x67, + 0x84, 0x76, 0x57, 0x87, 0xba, 0x47, 0xab, 0xcc, 0xab, 0xed, 0xfb, 0xcb, 0xd8, 0xef, 0x8c, 0xee, + 0x5b, 0x5f, 0x74, 0x1c, 0xa0, 0xb2, 0x11, 0xa3, 0x32, 0xac, 0x47, 0x05, 0xe6, 0x66, 0x97, 0xd0, + 0xfe, 0xad, 0xc1, 0x12, 0xbc, 0x7b, 0x41, 0xf8, 0x65, 0xaa, 0x5d, 0x73, 0x6b, 0xf2, 0xe5, 0xa6, + 0x7f, 0xfd, 0xf1, 0xf3, 0xab, 0x7c, 0x9d, 0x02, 0x7d, 0xae, 0x2e, 0x48, 0x1d, 0xde, 0xc8, 0x92, + 0x9d, 0xa6, 0x3c, 0xd6, 0xe1, 0x81, 0x1f, 0xeb, 0xea, 0xe7, 0x8b, 0xe8, 0x65, 0x39, 0x10, 0xfe, + 0xb3, 0x81, 0x46, 0x03, 0xf5, 0x88, 0x2f, 0x64, 0x7a, 0x49, 0xd2, 0xb4, 0xb9, 0xd5, 0x41, 0x4c, + 0x14, 0x01, 0x72, 0xef, 0x27, 0x7f, 0xff, 0xef, 0x2f, 0x86, 0xbe, 0x8d, 0x0b, 0x72, 0x83, 0xed, + 0x9c, 0xda, 0x6b, 0xeb, 0x6c, 0xb1, 0x75, 0x74, 0xab, 0xb9, 0xd3, 0x23, 0xde, 0x76, 0xcd, 0x9d, + 0x88, 0xba, 0xdc, 0xc5, 0xff, 0x34, 0x10, 0xee, 0x55, 0x80, 0xf8, 0x7a, 0x7f, 0x58, 0xa9, 0xea, + 0x37, 0x77, 0x63, 0x6f, 0xc6, 0xc0, 0xee, 0x6d, 0xc9, 0xee, 0x16, 0xbe, 0x99, 0xc8, 0x0e, 0x28, + 0x55, 0xda, 0x21, 0x56, 0x49, 0x44, 0xf1, 0xaf, 0x0d, 0x34, 0x1e, 0x52, 0x63, 0xf8, 0x5c, 0x7f, + 0x50, 0xa1, 0xee, 0xb9, 0x37, 0x07, 0xea, 0xde, 0x01, 0x7f, 0x56, 0x82, 0x5f, 0xc0, 0xa7, 0x12, + 0xc1, 0x77, 0xd2, 0x22, 0xa7, 0x02, 0xff, 0xd6, 0x40, 0x93, 0x31, 0x71, 0xa7, 0x33, 0x81, 0x62, + 0x26, 0xb9, 0xab, 0x03, 0x9b, 0x74, 0xc0, 0xae, 0x48, 0xb0, 0xaf, 0xe3, 0xc5, 0x44, 0xb0, 0x3c, + 0x86, 0xed, 0x3f, 0x06, 0x3a, 0x9a, 0xac, 0xf6, 0xf0, 0xad, 0xfe, 0x18, 0x32, 0x85, 0x66, 0xee, + 0xf6, 0xde, 0x1d, 0x00, 0x97, 0x82, 0xe4, 0x72, 0x03, 0x5f, 0x4b, 0xe4, 0xd2, 0xa0, 0xa2, 0x1c, + 0x56, 0x7f, 0xe5, 0x3a, 0xf3, 0x54, 0x83, 0xb9, 0x13, 0x64, 0x98, 0x5d, 0xfc, 0x85, 0x81, 0x26, + 0xa2, 0xc3, 0xe0, 0xcb, 0x83, 0x02, 0x0b, 0x18, 0x5d, 0x19, 0xdc, 0x10, 0x98, 0x9c, 0x93, 0x4c, + 0xce, 0xe0, 0xd3, 0x5a, 0x4c, 0x7c, 0xd0, 0x11, 0x91, 0xa4, 0x87, 0xb8, 0x57, 0x11, 0x6a, 0x22, + 0x4e, 0xd0, 0x78, 0xe4, 0xbc, 0x44, 0xbc, 0x8c, 0x97, 0x12, 0x11, 0x87, 0x34, 0xa9, 0xb9, 0x23, + 0x65, 0xf0, 0xae, 0x3f, 0xf7, 0x27, 0x42, 0x9e, 0xd6, 0x1c, 0x47, 0x07, 0x77, 0xa2, 0x92, 0xd5, + 0xc1, 0x9d, 0xac, 0x4d, 0xc9, 0x92, 0xc4, 0x4d, 0xf0, 0x7c, 0x3f, 0xdc, 0xf8, 0x4f, 0x06, 0x9a, + 0x8c, 0xc9, 0x36, 0x9d, 0x14, 0x99, 0xaa, 0x2f, 0x75, 0x52, 0x64, 0xba, 0xf2, 0xec, 0x33, 0x45, + 0xe2, 0xa2, 0x14, 0xff, 0xd2, 0x40, 0x23, 0x4a, 0xec, 0xe1, 0x55, 0xad, 0x71, 0x23, 0x7a, 0x33, + 0x77, 0x71, 0x20, 0x1b, 0x80, 0xb8, 0x20, 0x21, 0xbe, 0x86, 0x8f, 0x27, 0x42, 0x54, 0x92, 0x13, + 0xff, 0xc5, 0x40, 0xd3, 0x3d, 0x62, 0x12, 0x5f, 0xd3, 0xc8, 0x68, 0x29, 0x1a, 0x35, 0x77, 0x7d, + 0x4f, 0xb6, 0x80, 0xf9, 0xaa, 0xc4, 0x7c, 0x11, 0x5f, 0x08, 0x63, 0xee, 0x3d, 0xc3, 0xe2, 0x4d, + 0xf6, 0x71, 0x4c, 0xe1, 0xe2, 0xbf, 0x19, 0x68, 0xba, 0x47, 0x48, 0xea, 0x30, 0x49, 0x53, 0xb2, + 0x3a, 0x4c, 0x52, 0x95, 0x2b, 0xb9, 0x23, 0x99, 0xdc, 0xc4, 0xd7, 0x93, 0x6b, 0xa8, 0x54, 0x3f, + 0xf1, 0x12, 0x1a, 0x93, 0xcd, 0xbb, 0xbe, 0xb4, 0xc1, 0x1b, 0x54, 0xc4, 0x24, 0x25, 0xd6, 0x5b, + 0x6f, 0x09, 0x6a, 0x57, 0xa7, 0x54, 0xa5, 0xe8, 0x57, 0xb2, 0x2a, 0x09, 0xad, 0xe0, 0xe5, 0xd4, + 0xa4, 0x68, 0x39, 0x4e, 0x59, 0x71, 0xf0, 0x00, 0xe8, 0x37, 0x06, 0x3a, 0x22, 0x9d, 0xf1, 0x98, + 0x12, 0xc4, 0x37, 0xb5, 0x63, 0x9b, 0x24, 0x4b, 0x73, 0x6f, 0xed, 0xd5, 0x1c, 0xc8, 0x6c, 0x4a, + 0x32, 0x05, 0x7c, 0x3b, 0xfb, 0xe9, 0xa8, 0x25, 0x6c, 0xb9, 0x35, 0x75, 0x70, 0x10, 0xaa, 0x54, + 0xe6, 0x8e, 0x6c, 0xd9, 0xc5, 0x5f, 0x1a, 0xe8, 0x50, 0x64, 0x0b, 0x1a, 0x7f, 0x4b, 0x6b, 0xb1, + 0xf6, 0xec, 0xe4, 0xe7, 0x2e, 0x0f, 0x6c, 0x07, 0x64, 0x6e, 0x49, 0x32, 0x57, 0xf1, 0xe5, 0xd4, + 0x27, 0x23, 0x38, 0x0f, 0xf4, 0xa6, 0xb9, 0x13, 0xdf, 0x5f, 0xdf, 0xc5, 0xbf, 0x1a, 0x42, 0x73, + 0xd9, 0xdb, 0xe8, 0x78, 0x63, 0x40, 0x70, 0x69, 0x87, 0x02, 0xb9, 0xcd, 0x17, 0x77, 0x04, 0xb4, + 0x2b, 0x92, 0xf6, 0x87, 0xf8, 0xb1, 0x0e, 0xed, 0x72, 0x53, 0xee, 0xb6, 0xdb, 0x55, 0xcb, 0x31, + 0x77, 0x12, 0x4f, 0x25, 0x76, 0x93, 0x22, 0xf3, 0x99, 0x21, 0x4f, 0x6d, 0xb0, 0xa9, 0x87, 0xba, + 0x73, 0x08, 0x94, 0x3b, 0xaf, 0x6f, 0x00, 0x74, 0xe6, 0x25, 0x9d, 0x1c, 0x9e, 0x4d, 0xa4, 0xe3, + 0x83, 0xf8, 0xdc, 0x40, 0xa8, 0x7b, 0x6e, 0x80, 0x35, 0x8a, 0x42, 0xcf, 0x41, 0x46, 0xee, 0xd2, + 0x60, 0x46, 0x80, 0xed, 0x8c, 0xc4, 0x76, 0x0a, 0x9f, 0x4c, 0xc4, 0x26, 0xba, 0x98, 0x7e, 0x6f, + 0xa0, 0xa9, 0xc8, 0xc1, 0x99, 0xaf, 0x2b, 0xf4, 0x92, 0x4e, 0xd2, 0x51, 0x69, 0xee, 0xda, 0x5e, + 0x4c, 0x01, 0xf4, 0xb2, 0x04, 0xbd, 0x88, 0x49, 0x22, 0xe8, 0xe8, 0x79, 0xe6, 0x5f, 0x0d, 0x34, + 0x93, 0x74, 0x86, 0xa8, 0x93, 0xa7, 0x32, 0x8e, 0x2e, 0x75, 0xf2, 0x54, 0xd6, 0xd1, 0x25, 0x79, + 0x53, 0x72, 0x30, 0xf1, 0xb9, 0xfe, 0x1c, 0x62, 0x32, 0x3a, 0x72, 0xb4, 0x3d, 0x80, 0x86, 0x8e, + 0xc6, 0xff, 0xca, 0xe0, 0x86, 0x5a, 0x8a, 0xb4, 0xda, 0xb5, 0x88, 0x28, 0xd2, 0x90, 0x27, 0x7d, + 0x45, 0xba, 0x37, 0xdc, 0xc9, 0xdf, 0x15, 0xf4, 0x51, 0xa4, 0x21, 0xdc, 0xbe, 0x74, 0x9a, 0x49, + 0xfa, 0x66, 0x44, 0x67, 0xce, 0x64, 0x7c, 0xab, 0xa2, 0x33, 0x67, 0xb2, 0x3e, 0x55, 0xe9, 0x13, + 0xf9, 0x86, 0x4c, 0xae, 0x11, 0x6b, 0xfc, 0x0f, 0x03, 0x1d, 0x4b, 0xf9, 0x9a, 0x07, 0xdf, 0xde, + 0x1b, 0x9a, 0xee, 0x07, 0x43, 0xb9, 0xb5, 0x17, 0xf0, 0x00, 0x94, 0x2e, 0x49, 0x4a, 0x79, 0xbc, + 0x92, 0x46, 0x69, 0xcd, 0x71, 0xe2, 0x3e, 0x78, 0xe1, 0xee, 0x57, 0xcf, 0xe6, 0x8c, 0xaf, 0x9f, + 0xcd, 0x19, 0xdf, 0x3c, 0x9b, 0x33, 0x7e, 0xfe, 0x7c, 0xee, 0xc0, 0xd7, 0xcf, 0xe7, 0x0e, 0xfc, + 0xeb, 0xf9, 0xdc, 0x81, 0xc7, 0x66, 0xc3, 0x16, 0xcd, 0xed, 0x4a, 0xbe, 0xca, 0xb6, 0x12, 0x85, + 0xe6, 0x27, 0xa1, 0xe4, 0xd6, 0x6e, 0x51, 0x5e, 0x19, 0x91, 0x9f, 0x48, 0x5d, 0xfc, 0x5f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xc1, 0xd9, 0x00, 0xc6, 0x18, 0x28, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2315,6 +2497,10 @@ type QueryClient interface { ChainNonces(ctx context.Context, in *QueryGetChainNoncesRequest, opts ...grpc.CallOption) (*QueryGetChainNoncesResponse, error) // Queries a list of chainNonces items. ChainNoncesAll(ctx context.Context, in *QueryAllChainNoncesRequest, opts ...grpc.CallOption) (*QueryAllChainNoncesResponse, error) + // Queries the TssFundMigratorInfo for a specific chain + TssFundsMigratorInfo(ctx context.Context, in *QueryTssFundsMigratorInfoRequest, opts ...grpc.CallOption) (*QueryTssFundsMigratorInfoResponse, error) + // Queries all TssFundMigratorInfo + TssFundsMigratorInfoAll(ctx context.Context, in *QueryTssFundsMigratorInfoAllRequest, opts ...grpc.CallOption) (*QueryTssFundsMigratorInfoAllResponse, error) } type queryClient struct { @@ -2523,6 +2709,24 @@ func (c *queryClient) ChainNoncesAll(ctx context.Context, in *QueryAllChainNonce return out, nil } +func (c *queryClient) TssFundsMigratorInfo(ctx context.Context, in *QueryTssFundsMigratorInfoRequest, opts ...grpc.CallOption) (*QueryTssFundsMigratorInfoResponse, error) { + out := new(QueryTssFundsMigratorInfoResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.observer.Query/TssFundsMigratorInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) TssFundsMigratorInfoAll(ctx context.Context, in *QueryTssFundsMigratorInfoAllRequest, opts ...grpc.CallOption) (*QueryTssFundsMigratorInfoAllResponse, error) { + out := new(QueryTssFundsMigratorInfoAllResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.observer.Query/TssFundsMigratorInfoAll", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Query if a voter has voted for a ballot @@ -2563,6 +2767,10 @@ type QueryServer interface { ChainNonces(context.Context, *QueryGetChainNoncesRequest) (*QueryGetChainNoncesResponse, error) // Queries a list of chainNonces items. ChainNoncesAll(context.Context, *QueryAllChainNoncesRequest) (*QueryAllChainNoncesResponse, error) + // Queries the TssFundMigratorInfo for a specific chain + TssFundsMigratorInfo(context.Context, *QueryTssFundsMigratorInfoRequest) (*QueryTssFundsMigratorInfoResponse, error) + // Queries all TssFundMigratorInfo + TssFundsMigratorInfoAll(context.Context, *QueryTssFundsMigratorInfoAllRequest) (*QueryTssFundsMigratorInfoAllResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -2635,6 +2843,12 @@ func (*UnimplementedQueryServer) ChainNonces(ctx context.Context, req *QueryGetC func (*UnimplementedQueryServer) ChainNoncesAll(ctx context.Context, req *QueryAllChainNoncesRequest) (*QueryAllChainNoncesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ChainNoncesAll not implemented") } +func (*UnimplementedQueryServer) TssFundsMigratorInfo(ctx context.Context, req *QueryTssFundsMigratorInfoRequest) (*QueryTssFundsMigratorInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TssFundsMigratorInfo not implemented") +} +func (*UnimplementedQueryServer) TssFundsMigratorInfoAll(ctx context.Context, req *QueryTssFundsMigratorInfoAllRequest) (*QueryTssFundsMigratorInfoAllResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TssFundsMigratorInfoAll not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -3036,6 +3250,42 @@ func _Query_ChainNoncesAll_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _Query_TssFundsMigratorInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTssFundsMigratorInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TssFundsMigratorInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.observer.Query/TssFundsMigratorInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TssFundsMigratorInfo(ctx, req.(*QueryTssFundsMigratorInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_TssFundsMigratorInfoAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTssFundsMigratorInfoAllRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TssFundsMigratorInfoAll(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.observer.Query/TssFundsMigratorInfoAll", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TssFundsMigratorInfoAll(ctx, req.(*QueryTssFundsMigratorInfoAllRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "zetachain.zetacore.observer.Query", HandlerType: (*QueryServer)(nil), @@ -3128,12 +3378,20 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "ChainNoncesAll", Handler: _Query_ChainNoncesAll_Handler, }, + { + MethodName: "TssFundsMigratorInfo", + Handler: _Query_TssFundsMigratorInfo_Handler, + }, + { + MethodName: "TssFundsMigratorInfoAll", + Handler: _Query_TssFundsMigratorInfoAll_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "zetachain/zetacore/observer/query.proto", } -func (m *QueryGetChainNoncesRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryTssFundsMigratorInfoAllRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -3143,27 +3401,20 @@ func (m *QueryGetChainNoncesRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryGetChainNoncesRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryTssFundsMigratorInfoAllRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryGetChainNoncesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryTssFundsMigratorInfoAllRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Index) > 0 { - i -= len(m.Index) - copy(dAtA[i:], m.Index) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Index))) - i-- - dAtA[i] = 0xa - } return len(dAtA) - i, nil } -func (m *QueryGetChainNoncesResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryTssFundsMigratorInfoAllResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -3173,25 +3424,153 @@ func (m *QueryGetChainNoncesResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryGetChainNoncesResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryTssFundsMigratorInfoAllResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryGetChainNoncesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryTssFundsMigratorInfoAllResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - { - size, err := m.ChainNonces.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- + if len(m.TssFundsMigrators) > 0 { + for iNdEx := len(m.TssFundsMigrators) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TssFundsMigrators[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryTssFundsMigratorInfoRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryTssFundsMigratorInfoRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTssFundsMigratorInfoRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ChainId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryTssFundsMigratorInfoResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryTssFundsMigratorInfoResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTssFundsMigratorInfoResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.TssFundsMigrator.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryGetChainNoncesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryGetChainNoncesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryGetChainNoncesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Index) > 0 { + i -= len(m.Index) + copy(dAtA[i:], m.Index) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Index))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryGetChainNoncesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryGetChainNoncesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryGetChainNoncesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.ChainNonces.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -4676,6 +5055,53 @@ func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *QueryTssFundsMigratorInfoAllRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryTssFundsMigratorInfoAllResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TssFundsMigrators) > 0 { + for _, e := range m.TssFundsMigrators { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryTssFundsMigratorInfoRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainId != 0 { + n += 1 + sovQuery(uint64(m.ChainId)) + } + return n +} + +func (m *QueryTssFundsMigratorInfoResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.TssFundsMigrator.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + func (m *QueryGetChainNoncesRequest) Size() (n int) { if m == nil { return 0 @@ -5294,6 +5720,292 @@ func sovQuery(x uint64) (n int) { func sozQuery(x uint64) (n int) { return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (m *QueryTssFundsMigratorInfoAllRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTssFundsMigratorInfoAllRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTssFundsMigratorInfoAllRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTssFundsMigratorInfoAllResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTssFundsMigratorInfoAllResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTssFundsMigratorInfoAllResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TssFundsMigrators", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TssFundsMigrators = append(m.TssFundsMigrators, TssFundMigratorInfo{}) + if err := m.TssFundsMigrators[len(m.TssFundsMigrators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTssFundsMigratorInfoRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTssFundsMigratorInfoRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTssFundsMigratorInfoRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTssFundsMigratorInfoResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTssFundsMigratorInfoResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTssFundsMigratorInfoResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TssFundsMigrator", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TssFundsMigrator.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *QueryGetChainNoncesRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/observer/types/query.pb.gw.go b/x/observer/types/query.pb.gw.go index fc62c63354..0c1295a13f 100644 --- a/x/observer/types/query.pb.gw.go +++ b/x/observer/types/query.pb.gw.go @@ -945,6 +945,60 @@ func local_request_Query_ChainNoncesAll_0(ctx context.Context, marshaler runtime } +var ( + filter_Query_TssFundsMigratorInfo_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_TssFundsMigratorInfo_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTssFundsMigratorInfoRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TssFundsMigratorInfo_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.TssFundsMigratorInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TssFundsMigratorInfo_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTssFundsMigratorInfoRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TssFundsMigratorInfo_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.TssFundsMigratorInfo(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_TssFundsMigratorInfoAll_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTssFundsMigratorInfoAllRequest + var metadata runtime.ServerMetadata + + msg, err := client.TssFundsMigratorInfoAll(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TssFundsMigratorInfoAll_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTssFundsMigratorInfoAllRequest + var metadata runtime.ServerMetadata + + msg, err := server.TssFundsMigratorInfoAll(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -1457,6 +1511,52 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_TssFundsMigratorInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_TssFundsMigratorInfo_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TssFundsMigratorInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TssFundsMigratorInfoAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_TssFundsMigratorInfoAll_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TssFundsMigratorInfoAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1938,6 +2038,46 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_TssFundsMigratorInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_TssFundsMigratorInfo_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TssFundsMigratorInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TssFundsMigratorInfoAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_TssFundsMigratorInfoAll_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TssFundsMigratorInfoAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1985,6 +2125,10 @@ var ( pattern_Query_ChainNonces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"zeta-chain", "observer", "chainNonces", "index"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_ChainNoncesAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "observer", "chainNonces"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_TssFundsMigratorInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "observer", "getTssFundsMigrator"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_TssFundsMigratorInfoAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "observer", "getAllTssFundsMigrators"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -2031,4 +2175,8 @@ var ( forward_Query_ChainNonces_0 = runtime.ForwardResponseMessage forward_Query_ChainNoncesAll_0 = runtime.ForwardResponseMessage + + forward_Query_TssFundsMigratorInfo_0 = runtime.ForwardResponseMessage + + forward_Query_TssFundsMigratorInfoAll_0 = runtime.ForwardResponseMessage ) From 57457fdecb9ba5893923b1e97f75c6025e4f733f Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Wed, 26 Jun 2024 19:35:51 +0200 Subject: [PATCH 11/23] docs(`zetaclient`): add more function and package documentation (#2321) * bitcoin * add revamp todos * evm * config * keys and metrics * orchestrator and tss * zetacore package * add package headers * changelog entry * Update zetaclient/chains/bitcoin/observer/observer.go Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> * Update zetaclient/chains/bitcoin/observer/observer.go Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> * Update zetaclient/chains/bitcoin/observer/observer.go Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> * apply some comments * Apply suggestions from code review Co-authored-by: Tanmay * add one comment * add some fixes --------- Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Co-authored-by: Tanmay --- changelog.md | 4 ++ zetaclient/authz/authz_signer.go | 8 +++ zetaclient/authz/authz_signer_test.go | 2 + zetaclient/chains/bitcoin/observer/inbound.go | 9 ++++ .../chains/bitcoin/observer/observer.go | 16 +++++- .../chains/bitcoin/observer/outbound.go | 8 +++ zetaclient/chains/bitcoin/signer/signer.go | 5 ++ zetaclient/chains/bitcoin/utils.go | 5 ++ zetaclient/chains/evm/observer/inbound.go | 4 ++ zetaclient/chains/evm/observer/observer.go | 15 ++++++ zetaclient/chains/evm/observer/outbound.go | 3 ++ zetaclient/chains/evm/signer/signer.go | 14 ++++++ zetaclient/chains/interfaces/interfaces.go | 2 +- zetaclient/compliance/compliance.go | 1 + zetaclient/config/config.go | 7 +++ zetaclient/config/config_chain.go | 12 +++++ zetaclient/config/types.go | 19 ++++++- zetaclient/context/app_context.go | 3 ++ zetaclient/context/zetacore_context.go | 5 ++ zetaclient/hsm/hsm_signer.go | 3 ++ zetaclient/keys/keys.go | 7 ++- zetaclient/metrics/metrics.go | 18 +++++++ zetaclient/metrics/telemetry.go | 4 ++ zetaclient/orchestrator/orchestrator.go | 11 +++- .../outboundprocessor/outbound_processor.go | 9 ++++ zetaclient/ratelimiter/rate_limiter.go | 1 + zetaclient/supplychecker/logger.go | 1 + zetaclient/supplychecker/validate.go | 1 + .../supplychecker/zeta_supply_checker.go | 8 +++ zetaclient/testutils/mempool_client.go | 6 +++ zetaclient/testutils/mocks/zetacore_client.go | 7 --- zetaclient/testutils/testdata.go | 2 + zetaclient/tss/tss_signer.go | 25 ++++++++++ zetaclient/types/dynamic_ticker.go | 5 ++ zetaclient/types/ethish.go | 1 + zetaclient/types/sql_evm.go | 7 +++ zetaclient/zetacore/broadcast.go | 3 +- zetaclient/zetacore/client.go | 5 ++ zetaclient/zetacore/query.go | 50 ++++++++++++++----- zetaclient/zetacore/query_test.go | 24 --------- zetaclient/zetacore/tx.go | 18 +++++++ 41 files changed, 306 insertions(+), 52 deletions(-) diff --git a/changelog.md b/changelog.md index 3d0194dc28..db3d2475f4 100644 --- a/changelog.md +++ b/changelog.md @@ -98,6 +98,10 @@ * [2335](https://github.com/zeta-chain/node/pull/2335) - ci: updated the artillery report to publish to artillery cloud * [2377](https://github.com/zeta-chain/node/pull/2377) - ci: adjusted sast-linters.yml to not scan itself, nor alert on removal of nosec. +### Documentation + +* [2321](https://github.com/zeta-chain/node/pull/2321) - improve documentation for ZetaClient functions and packages + ## v17.0.0 ### Fixes diff --git a/zetaclient/authz/authz_signer.go b/zetaclient/authz/authz_signer.go index 5f1221f9a9..7f9dc4d471 100644 --- a/zetaclient/authz/authz_signer.go +++ b/zetaclient/authz/authz_signer.go @@ -1,3 +1,5 @@ +// Package authz provides a signer object for transactions using grants +// grants are used to allow a hotkey to sign transactions on behalf of the observers package authz import ( @@ -7,18 +9,22 @@ import ( crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) +// Signer represents a signer for a grantee key type Signer struct { KeyType authz.KeyType GranterAddress string GranteeAddress sdk.AccAddress } +// String returns a string representation of a Signer func (a Signer) String() string { return a.KeyType.String() + " " + a.GranterAddress + " " + a.GranteeAddress.String() } +// signers is a map of all the signers for the different tx types var signers map[string]Signer +// init initializes the signers map with all the crosschain tx types using the ZetaClientGranteeKey func init() { signersList := make(map[string]Signer) for _, tx := range crosschaintypes.GetAllAuthzZetaclientTxTypes() { @@ -27,6 +33,7 @@ func init() { signers = signersList } +// SetupAuthZSignerList sets the granter and grantee for all the signers func SetupAuthZSignerList(granter string, grantee sdk.AccAddress) { for k, v := range signers { v.GranterAddress = granter @@ -35,6 +42,7 @@ func SetupAuthZSignerList(granter string, grantee sdk.AccAddress) { } } +// GetSigner returns the signer for a given msgURL func GetSigner(msgURL string) Signer { return signers[msgURL] } diff --git a/zetaclient/authz/authz_signer_test.go b/zetaclient/authz/authz_signer_test.go index 00a25722c4..1cc70b3116 100644 --- a/zetaclient/authz/authz_signer_test.go +++ b/zetaclient/authz/authz_signer_test.go @@ -1 +1,3 @@ package authz_test + +// NOTE: test file currently created empty to add the package in the test coverage scope diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index 2438411b5b..037fd11cd1 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -26,6 +26,8 @@ import ( ) // WatchInbound watches Bitcoin chain for inbounds on a ticker +// It starts a ticker and run ObserveInbound +// TODO(revamp): move all ticker related methods in the same file func (ob *Observer) WatchInbound() { ticker, err := types.NewDynamicTicker("Bitcoin_WatchInbound", ob.GetChainParams().InboundTicker) if err != nil { @@ -37,6 +39,7 @@ func (ob *Observer) WatchInbound() { ob.logger.Inbound.Info().Msgf("WatchInbound started for chain %d", ob.Chain().ChainId) sampledLogger := ob.logger.Inbound.Sample(&zerolog.BasicSampler{N: 10}) + // ticker loop for { select { case <-ticker.C(): @@ -58,6 +61,7 @@ func (ob *Observer) WatchInbound() { } // ObserveInbound observes the Bitcoin chain for inbounds and post votes to zetacore +// TODO(revamp): simplify this function into smaller functions func (ob *Observer) ObserveInbound() error { // get and update latest block height cnt, err := ob.btcClient.GetBlockCount() @@ -171,6 +175,7 @@ func (ob *Observer) ObserveInbound() error { } // WatchInboundTracker watches zetacore for bitcoin inbound trackers +// TODO(revamp): move all ticker related methods in the same file func (ob *Observer) WatchInboundTracker() { ticker, err := types.NewDynamicTicker("Bitcoin_WatchInboundTracker", ob.GetChainParams().InboundTicker) if err != nil { @@ -200,6 +205,7 @@ func (ob *Observer) WatchInboundTracker() { } // ProcessInboundTrackers processes inbound trackers +// TODO(revamp): move inbound tracker logic in a specific file func (ob *Observer) ProcessInboundTrackers() error { trackers, err := ob.ZetacoreClient().GetInboundTrackersForChain(ob.Chain().ChainId) if err != nil { @@ -328,6 +334,7 @@ func FilterAndParseIncomingTx( return inbounds, nil } +// GetInboundVoteMessageFromBtcEvent converts a BTCInboundEvent to a MsgVoteInbound to enable voting on the inbound on zetacore func (ob *Observer) GetInboundVoteMessageFromBtcEvent(inbound *BTCInboundEvent) *crosschaintypes.MsgVoteInbound { ob.logger.Inbound.Debug().Msgf("Processing inbound: %s", inbound.TxHash) amount := big.NewFloat(inbound.Value) @@ -360,6 +367,7 @@ func (ob *Observer) GetInboundVoteMessageFromBtcEvent(inbound *BTCInboundEvent) } // DoesInboundContainsRestrictedAddress returns true if the inbound contains restricted addresses +// TODO(revamp): move all compliance related functions in a specific file func (ob *Observer) DoesInboundContainsRestrictedAddress(inTx *BTCInboundEvent) bool { receiver := "" parsedAddress, _, err := chains.ParseAddressAndData(hex.EncodeToString(inTx.MemoBytes)) @@ -376,6 +384,7 @@ func (ob *Observer) DoesInboundContainsRestrictedAddress(inTx *BTCInboundEvent) // GetBtcEvent either returns a valid BTCInboundEvent or nil // Note: the caller should retry the tx on error (e.g., GetSenderAddressByVin failed) +// TODO(revamp): simplify this function func GetBtcEvent( rpcClient interfaces.BTCRPCClient, tx btcjson.TxRawResult, diff --git a/zetaclient/chains/bitcoin/observer/observer.go b/zetaclient/chains/bitcoin/observer/observer.go index 5d6e308dfe..11ccc5460a 100644 --- a/zetaclient/chains/bitcoin/observer/observer.go +++ b/zetaclient/chains/bitcoin/observer/observer.go @@ -1,3 +1,4 @@ +// Package observer implements the Bitcoin chain observer package observer import ( @@ -54,6 +55,7 @@ type Logger struct { } // BTCInboundEvent represents an incoming transaction event +// TODO(revamp): Move to inbound type BTCInboundEvent struct { // FromAddress is the first input address FromAddress string @@ -69,7 +71,7 @@ type BTCInboundEvent struct { TxHash string } -// BTCOutboundEvent contains bitcoin block and the header +// BTCBlockNHeader contains bitcoin block and the header type BTCBlockNHeader struct { Header *wire.BlockHeader Block *btcjson.GetBlockVerboseTxResult @@ -190,7 +192,7 @@ func (ob *Observer) GetChainParams() observertypes.ChainParams { return ob.ChainParams() } -// Start starts the Go routine to observe the Bitcoin chain +// Start starts the Go routine processes to observe the Bitcoin chain func (ob *Observer) Start() { ob.Logger().Chain.Info().Msgf("observer is starting for chain %d", ob.Chain().ChainId) @@ -214,6 +216,8 @@ func (ob *Observer) Start() { } // WatchRPCStatus watches the RPC status of the Bitcoin chain +// TODO(revamp): move ticker related functions to a specific file +// TODO(revamp): move inner logic in a separate function func (ob *Observer) WatchRPCStatus() { ob.logger.Chain.Info().Msgf("RPCStatus is starting") ticker := time.NewTicker(60 * time.Second) @@ -297,6 +301,8 @@ func (ob *Observer) ConfirmationsThreshold(amount *big.Int) int64 { } // WatchGasPrice watches Bitcoin chain for gas rate and post to zetacore +// TODO(revamp): move ticker related functions to a specific file +// TODO(revamp): move inner logic in a separate function func (ob *Observer) WatchGasPrice() { // report gas price right away as the ticker takes time to kick in err := ob.PostGasPrice() @@ -333,6 +339,7 @@ func (ob *Observer) WatchGasPrice() { } // PostGasPrice posts gas price to zetacore +// TODO(revamp): move to gas price file func (ob *Observer) PostGasPrice() error { // hardcode gas price here since this RPC is not available on regtest if chains.IsBitcoinRegnet(ob.Chain().ChainId) { @@ -379,6 +386,7 @@ func (ob *Observer) PostGasPrice() error { } // GetSenderAddressByVin get the sender address from the previous transaction +// TODO(revamp): move in upper package to separate file (e.g., rpc.go) func GetSenderAddressByVin(rpcClient interfaces.BTCRPCClient, vin btcjson.Vin, net *chaincfg.Params) (string, error) { // query previous raw transaction by txid // GetTransaction requires reconfiguring the bitcoin node (txindex=1), so we use GetRawTransaction instead @@ -421,6 +429,7 @@ func GetSenderAddressByVin(rpcClient interfaces.BTCRPCClient, vin btcjson.Vin, n } // WatchUTXOs watches bitcoin chain for UTXOs owned by the TSS address +// TODO(revamp): move ticker related functions to a specific file func (ob *Observer) WatchUTXOs() { ticker, err := clienttypes.NewDynamicTicker("Bitcoin_WatchUTXOs", ob.GetChainParams().WatchUtxoTicker) if err != nil { @@ -448,6 +457,7 @@ func (ob *Observer) WatchUTXOs() { } // FetchUTXOs fetches TSS-owned UTXOs from the Bitcoin node +// TODO(revamp): move to UTXO file func (ob *Observer) FetchUTXOs() error { defer func() { if err := recover(); err != nil { @@ -511,6 +521,7 @@ func (ob *Observer) FetchUTXOs() error { } // SaveBroadcastedTx saves successfully broadcasted transaction +// TODO(revamp): move to db file func (ob *Observer) SaveBroadcastedTx(txHash string, nonce uint64) { outboundID := ob.GetTxID(nonce) ob.Mu().Lock() @@ -641,6 +652,7 @@ func (ob *Observer) isTssTransaction(txid string) bool { } // postBlockHeader posts block header to zetacore +// TODO(revamp): move to block header file func (ob *Observer) postBlockHeader(tip int64) error { ob.logger.Inbound.Info().Msgf("postBlockHeader: tip %d", tip) bn := tip diff --git a/zetaclient/chains/bitcoin/observer/outbound.go b/zetaclient/chains/bitcoin/observer/outbound.go index 5bf20c8e7d..5f4684f50f 100644 --- a/zetaclient/chains/bitcoin/observer/outbound.go +++ b/zetaclient/chains/bitcoin/observer/outbound.go @@ -27,6 +27,8 @@ func (ob *Observer) GetTxID(nonce uint64) string { } // WatchOutbound watches Bitcoin chain for outgoing txs status +// TODO(revamp): move ticker functions to a specific file +// TODO(revamp): move into a separate package func (ob *Observer) WatchOutbound() { ticker, err := types.NewDynamicTicker("Bitcoin_WatchOutbound", ob.GetChainParams().OutboundTicker) if err != nil { @@ -111,6 +113,7 @@ func (ob *Observer) WatchOutbound() { } // IsOutboundProcessed returns isIncluded(or inMempool), isConfirmed, Error +// TODO(revamp): rename as it vote the outbound and doesn't only check if outbound is processed func (ob *Observer) IsOutboundProcessed(cctx *crosschaintypes.CrossChainTx, logger zerolog.Logger) (bool, bool, error) { params := *cctx.GetCurrentOutboundParam() sendHash := cctx.Index @@ -213,6 +216,8 @@ func (ob *Observer) IsOutboundProcessed(cctx *crosschaintypes.CrossChainTx, logg // - the total value of the selected UTXOs. // - the number of consolidated UTXOs. // - the total value of the consolidated UTXOs. +// +// TODO(revamp): move to utxo file func (ob *Observer) SelectUTXOs( amount float64, utxosToSpend uint16, @@ -329,6 +334,8 @@ func (ob *Observer) refreshPendingNonce() { } } +// getOutboundIDByNonce gets the outbound ID from the nonce of the outbound transaction +// test is true for unit test only func (ob *Observer) getOutboundIDByNonce(nonce uint64, test bool) (string, error) { // There are 2 types of txids an observer can trust // 1. The ones had been verified and saved by observer self. @@ -363,6 +370,7 @@ func (ob *Observer) getOutboundIDByNonce(nonce uint64, test bool) (string, error return "", fmt.Errorf("getOutboundIDByNonce: cannot find outbound txid for nonce %d", nonce) } +// findNonceMarkUTXO finds the nonce-mark UTXO in the list of UTXOs. func (ob *Observer) findNonceMarkUTXO(nonce uint64, txid string) (int, error) { tssAddress := ob.TSS().BTCAddressWitnessPubkeyHash().EncodeAddress() amount := chains.NonceMarkAmount(nonce) diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index 6ad9bfc2a6..eae11a68ce 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -1,3 +1,4 @@ +// Package signer implements the ChainSigner interface for BTC package signer import ( @@ -168,6 +169,7 @@ func (signer *Signer) AddWithdrawTxOutputs( } // SignWithdrawTx receives utxos sorted by value, amount in BTC, feeRate in BTC per Kb +// TODO(revamp): simplify the function func (signer *Signer) SignWithdrawTx( to btcutil.Address, amount float64, @@ -291,6 +293,7 @@ func (signer *Signer) SignWithdrawTx( return tx, nil } +// Broadcast sends the signed transaction to the network func (signer *Signer) Broadcast(signedTx *wire.MsgTx) error { fmt.Printf("BTCSigner: Broadcasting: %s\n", signedTx.TxHash().String()) @@ -311,6 +314,8 @@ func (signer *Signer) Broadcast(signedTx *wire.MsgTx) error { return nil } +// TryProcessOutbound signs and broadcasts a BTC transaction from a new outbound +// TODO(revamp): simplify the function func (signer *Signer) TryProcessOutbound( cctx *types.CrossChainTx, outboundProcessor *outboundprocessor.Processor, diff --git a/zetaclient/chains/bitcoin/utils.go b/zetaclient/chains/bitcoin/utils.go index fe2bb2481b..8c37e01fad 100644 --- a/zetaclient/chains/bitcoin/utils.go +++ b/zetaclient/chains/bitcoin/utils.go @@ -8,6 +8,9 @@ import ( "github.com/pkg/errors" ) +// TODO(revamp): Remove utils.go and move the functions to the appropriate files + +// PrettyPrintStruct returns a pretty-printed string representation of a struct func PrettyPrintStruct(val interface{}) (string, error) { prettyStruct, err := json.MarshalIndent( val, @@ -20,6 +23,7 @@ func PrettyPrintStruct(val interface{}) (string, error) { return string(prettyStruct), nil } +// GetSatoshis converts a bitcoin amount to satoshis func GetSatoshis(btc float64) (int64, error) { // The amount is only considered invalid if it cannot be represented // as an integer type. This may happen if f is NaN or +-Infinity. @@ -39,6 +43,7 @@ func GetSatoshis(btc float64) (int64, error) { return round(btc * btcutil.SatoshiPerBitcoin), nil } +// round rounds a float64 to the nearest integer func round(f float64) int64 { if f < 0 { // #nosec G701 always in range diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index 41ada01375..40844ddbd7 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -34,6 +34,7 @@ import ( ) // WatchInbound watches evm chain for incoming txs and post votes to zetacore +// TODO(revamp): move ticker function to a separate file func (ob *Observer) WatchInbound() { ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("EVM_WatchInbound_%d", ob.Chain().ChainId), @@ -70,6 +71,7 @@ func (ob *Observer) WatchInbound() { // WatchInboundTracker gets a list of Inbound tracker suggestions from zeta-core at each tick and tries to check if the in-tx was confirmed. // If it was, it tries to broadcast the confirmation vote. If this zeta client has previously broadcast the vote, the tx would be rejected +// TODO(revamp): move inbound tracker function to a separate file func (ob *Observer) WatchInboundTracker() { ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("EVM_WatchInboundTracker_%d", ob.Chain().ChainId), @@ -101,6 +103,7 @@ func (ob *Observer) WatchInboundTracker() { } // ProcessInboundTrackers processes inbound trackers from zetacore +// TODO(revamp): move inbound tracker function to a separate file func (ob *Observer) ProcessInboundTrackers() error { trackers, err := ob.ZetacoreClient().GetInboundTrackersForChain(ob.Chain().ChainId) if err != nil { @@ -152,6 +155,7 @@ func (ob *Observer) ProcessInboundTrackers() error { return nil } +// ObserveInbound observes the evm chain for inbounds and posts votes to zetacore func (ob *Observer) ObserveInbound(sampledLogger zerolog.Logger) error { // get and update latest block height blockNumber, err := ob.evmClient.BlockNumber(context.Background()) diff --git a/zetaclient/chains/evm/observer/observer.go b/zetaclient/chains/evm/observer/observer.go index 3db0538870..0a33603196 100644 --- a/zetaclient/chains/evm/observer/observer.go +++ b/zetaclient/chains/evm/observer/observer.go @@ -1,3 +1,4 @@ +// Package observer implements the EVM chain observer package observer import ( @@ -147,6 +148,7 @@ func (ob *Observer) GetERC20CustodyContract() (ethcommon.Address, *erc20custody. } // FetchConnectorContractEth returns the Eth connector address and binder +// TODO(revamp): move this to a contract package func FetchConnectorContractEth( addr ethcommon.Address, client interfaces.EVMRPCClient, @@ -155,6 +157,7 @@ func FetchConnectorContractEth( } // FetchZetaTokenContract returns the non-Eth ZETA token binder +// TODO(revamp): move this to a contract package func FetchZetaTokenContract( addr ethcommon.Address, client interfaces.EVMRPCClient, @@ -183,6 +186,8 @@ func (ob *Observer) Start() { } // WatchRPCStatus watches the RPC status of the evm chain +// TODO(revamp): move ticker to ticker file +// TODO(revamp): move inner logic to a separate function func (ob *Observer) WatchRPCStatus() { ob.Logger().Chain.Info().Msgf("Starting RPC status check for chain %d", ob.Chain().ChainId) ticker := time.NewTicker(60 * time.Second) @@ -288,6 +293,8 @@ func (ob *Observer) CheckTxInclusion(tx *ethtypes.Transaction, receipt *ethtypes } // WatchGasPrice watches evm chain for gas prices and post to zetacore +// TODO(revamp): move ticker to ticker file +// TODO(revamp): move inner logic to a separate function func (ob *Observer) WatchGasPrice() { // report gas price right away as the ticker takes time to kick in err := ob.PostGasPrice() @@ -326,6 +333,8 @@ func (ob *Observer) WatchGasPrice() { } } +// PostGasPrice posts gas price to zetacore +// TODO(revamp): move to gas price file func (ob *Observer) PostGasPrice() error { // GAS PRICE gasPrice, err := ob.evmClient.SuggestGasPrice(context.TODO()) @@ -353,6 +362,7 @@ func (ob *Observer) PostGasPrice() error { } // TransactionByHash query transaction by hash via JSON-RPC +// TODO(revamp): update this method as a pure RPC method that takes two parameters (jsonRPC, and txHash) and move to upper package to file rpc.go func (ob *Observer) TransactionByHash(txHash string) (*ethrpc.Transaction, bool, error) { tx, err := ob.evmJSONRPC.EthGetTransactionByHash(txHash) if err != nil { @@ -365,6 +375,7 @@ func (ob *Observer) TransactionByHash(txHash string) (*ethrpc.Transaction, bool, return tx, tx.BlockNumber == nil, nil } +// GetBlockHeaderCached get block header by number from cache func (ob *Observer) GetBlockHeaderCached(blockNumber uint64) (*ethtypes.Header, error) { if result, ok := ob.HeaderCache().Get(blockNumber); ok { if header, ok := result.(*ethtypes.Header); ok { @@ -422,6 +433,7 @@ func (ob *Observer) BlockByNumber(blockNumber int) (*ethrpc.Block, error) { } // LoadDB open sql database and load data into EVM observer +// TODO(revamp): move to a db file func (ob *Observer) LoadDB(dbPath string) error { if dbPath == "" { return errors.New("empty db path") @@ -450,6 +462,7 @@ func (ob *Observer) LoadDB(dbPath string) error { } // LoadLastBlockScanned loads the last scanned block from the database +// TODO(revamp): move to a db file func (ob *Observer) LoadLastBlockScanned() error { err := ob.Observer.LoadLastBlockScanned(ob.Logger().Chain) if err != nil { @@ -471,6 +484,8 @@ func (ob *Observer) LoadLastBlockScanned() error { return nil } +// postBlockHeader posts the block header to zetacore +// TODO(revamp): move to a block header file func (ob *Observer) postBlockHeader(tip uint64) error { bn := tip diff --git a/zetaclient/chains/evm/observer/outbound.go b/zetaclient/chains/evm/observer/outbound.go index 9c3bd1c66b..2f3d3c136f 100644 --- a/zetaclient/chains/evm/observer/outbound.go +++ b/zetaclient/chains/evm/observer/outbound.go @@ -34,6 +34,8 @@ func (ob *Observer) GetTxID(nonce uint64) string { } // WatchOutbound watches evm chain for outgoing txs status +// TODO(revamp): move ticker function to ticker file +// TODO(revamp): move inner logic to a separate function func (ob *Observer) WatchOutbound() { ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("EVM_WatchOutbound_%d", ob.Chain().ChainId), @@ -130,6 +132,7 @@ func (ob *Observer) PostVoteOutbound( // IsOutboundProcessed checks outbound status and returns (isIncluded, isConfirmed, error) // It also posts vote to zetacore if the tx is confirmed +// TODO(revamp): rename as it also vote the outbound func (ob *Observer) IsOutboundProcessed(cctx *crosschaintypes.CrossChainTx, logger zerolog.Logger) (bool, bool, error) { // skip if outbound is not confirmed nonce := cctx.GetCurrentOutboundParam().TssNonce diff --git a/zetaclient/chains/evm/signer/signer.go b/zetaclient/chains/evm/signer/signer.go index d50b214b03..3ea7852766 100644 --- a/zetaclient/chains/evm/signer/signer.go +++ b/zetaclient/chains/evm/signer/signer.go @@ -1,3 +1,4 @@ +// Package signer implements the ChainSigner interface for EVM chains package signer import ( @@ -329,6 +330,7 @@ func (signer *Signer) SignCommandTx(txData *OutboundData, cmd string, params str // TryProcessOutbound - signer interface implementation // This function will attempt to build and sign an evm transaction using the TSS signer. // It will then broadcast the signed transaction to the outbound chain. +// TODO(revamp): simplify function func (signer *Signer) TryProcessOutbound( cctx *types.CrossChainTx, outboundProc *outboundprocessor.Processor, @@ -618,14 +620,19 @@ func (signer *Signer) GetReportedTxList() *map[string]bool { return &signer.outboundHashBeingReported } +// EvmClient returns the EVM RPC client func (signer *Signer) EvmClient() interfaces.EVMRPCClient { return signer.client } +// EvmSigner returns the EVM signer object for the signer func (signer *Signer) EvmSigner() ethtypes.Signer { + // TODO(revamp): rename field into evmSigner return signer.ethSigner } +// IsSenderZetaChain checks if the sender chain is ZetaChain +// TODO(revamp): move to another package more general for cctx functions func IsSenderZetaChain( cctx *types.CrossChainTx, zetacoreClient interfaces.ZetacoreClient, @@ -635,6 +642,7 @@ func IsSenderZetaChain( cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound && flags.IsOutboundEnabled } +// ErrorMsg returns a error message for SignOutbound failure with cctx data func ErrorMsg(cctx *types.CrossChainTx) string { return fmt.Sprintf( "signer SignOutbound error: nonce %d chain %d", @@ -643,6 +651,8 @@ func ErrorMsg(cctx *types.CrossChainTx) string { ) } +// SignWhitelistERC20Cmd signs a whitelist command for ERC20 token +// TODO(revamp): move the cmd in a specific file func (signer *Signer) SignWhitelistERC20Cmd(txData *OutboundData, params string) (*ethtypes.Transaction, error) { outboundParams := txData.outboundParams erc20 := ethcommon.HexToAddress(params) @@ -672,6 +682,8 @@ func (signer *Signer) SignWhitelistERC20Cmd(txData *OutboundData, params string) return tx, nil } +// SignMigrateTssFundsCmd signs a migrate TSS funds command +// TODO(revamp): move the cmd in a specific file func (signer *Signer) SignMigrateTssFundsCmd(txData *OutboundData) (*ethtypes.Transaction, error) { tx, _, _, err := signer.Sign( nil, @@ -689,6 +701,7 @@ func (signer *Signer) SignMigrateTssFundsCmd(txData *OutboundData) (*ethtypes.Tr } // reportToOutboundTracker reports outboundHash to tracker only when tx receipt is available +// TODO(revamp): move outbound tracker function to a outbound tracker file func (signer *Signer) reportToOutboundTracker( zetacoreClient interfaces.ZetacoreClient, chainID int64, @@ -821,6 +834,7 @@ func getEVMRPC(endpoint string) (interfaces.EVMRPCClient, ethtypes.Signer, error return client, ethSigner, nil } +// roundUpToNearestGwei rounds up the gas price to the nearest Gwei func roundUpToNearestGwei(gasPrice *big.Int) *big.Int { oneGwei := big.NewInt(1_000_000_000) // 1 Gwei mod := new(big.Int) diff --git a/zetaclient/chains/interfaces/interfaces.go b/zetaclient/chains/interfaces/interfaces.go index 1ef94ec8de..2272ef1dfe 100644 --- a/zetaclient/chains/interfaces/interfaces.go +++ b/zetaclient/chains/interfaces/interfaces.go @@ -1,3 +1,4 @@ +// Package interfaces provides interfaces for clients and signers for the chain to interact with package interfaces import ( @@ -96,7 +97,6 @@ type ZetacoreClient interface { GetKeys() keyinterfaces.ObserverKeys GetKeyGen() (*observertypes.Keygen, error) GetBlockHeight() (int64, error) - GetLastBlockHeightByChain(chain chains.Chain) (*crosschaintypes.LastBlockHeight, error) ListPendingCctx(chainID int64) ([]*crosschaintypes.CrossChainTx, uint64, error) ListPendingCctxWithinRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, int64, string, bool, error) GetRateLimiterInput(window int64) (crosschaintypes.QueryRateLimiterInputResponse, error) diff --git a/zetaclient/compliance/compliance.go b/zetaclient/compliance/compliance.go index e085b6954b..849d56742b 100644 --- a/zetaclient/compliance/compliance.go +++ b/zetaclient/compliance/compliance.go @@ -1,3 +1,4 @@ +// Package compliance provides functions to check for compliance of cross-chain transactions package compliance import ( diff --git a/zetaclient/config/config.go b/zetaclient/config/config.go index 7dcf1b00f3..6efd149628 100644 --- a/zetaclient/config/config.go +++ b/zetaclient/config/config.go @@ -1,3 +1,4 @@ +// Package config provides functions to load and save ZetaClient config package config import ( @@ -11,7 +12,10 @@ import ( // restrictedAddressBook is a map of restricted addresses var restrictedAddressBook = map[string]bool{} +// filename is config file name for ZetaClient const filename string = "zetaclient_config.json" + +// folder is the folder name for ZetaClient config const folder string = "config" // Save saves ZetaClient config @@ -78,10 +82,12 @@ func Load(path string) (Config, error) { return cfg, nil } +// LoadComplianceConfig loads compliance data (restricted addresses) from config func LoadComplianceConfig(cfg Config) { restrictedAddressBook = cfg.GetRestrictedAddressBook() } +// GetPath returns the absolute path of the input path func GetPath(inputPath string) string { path := strings.Split(inputPath, "/") if len(path) > 0 { @@ -94,6 +100,7 @@ func GetPath(inputPath string) string { return filepath.Join(path...) } } + return inputPath } diff --git a/zetaclient/config/config_chain.go b/zetaclient/config/config_chain.go index 12c889f6af..5c2ed1d077 100644 --- a/zetaclient/config/config_chain.go +++ b/zetaclient/config/config_chain.go @@ -7,20 +7,29 @@ const ( ) const ( + // ConnectorAbiString is the ABI of the connector contract + // TODO(revamp): we should be able to use info from Go binding ConnectorAbiString = ` [{"inputs":[{"internalType":"address","name":"_zetaTokenAddress","type":"address"},{"internalType":"address","name":"_tssAddress","type":"address"},{"internalType":"address","name":"_tssAddressUpdater","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"originSenderAddress","type":"bytes"},{"indexed":true,"internalType":"uint256","name":"originChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"destinationAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"zetaAmount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":true,"internalType":"bytes32","name":"internalSendHash","type":"bytes32"}],"name":"ZetaReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"originSenderAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"originChainId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"destinationAddress","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"zetaAmount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":true,"internalType":"bytes32","name":"internalSendHash","type":"bytes32"}],"name":"ZetaReverted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"originSenderAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"destinationAddress","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"zetaAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasLimit","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"zetaParams","type":"bytes"}],"name":"ZetaSent","type":"event"},{"inputs":[],"name":"getLockedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"originSenderAddress","type":"bytes"},{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"uint256","name":"zetaAmount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"bytes32","name":"internalSendHash","type":"bytes32"}],"name":"onReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"originSenderAddress","type":"address"},{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"bytes","name":"destinationAddress","type":"bytes"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"uint256","name":"zetaAmount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"bytes32","name":"internalSendHash","type":"bytes32"}],"name":"onRevert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceTssAddressUpdater","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"bytes","name":"destinationAddress","type":"bytes"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"uint256","name":"zetaAmount","type":"uint256"},{"internalType":"bytes","name":"zetaParams","type":"bytes"}],"internalType":"struct ZetaInterfaces.SendInput","name":"input","type":"tuple"}],"name":"send","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tssAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tssAddressUpdater","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tssAddress","type":"address"}],"name":"updateTssAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"zetaToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]` + + // ERC20CustodyAbiString is the ABI of the erc20 custodu contract + // TODO(revamp): we should be able to use info from Go binding ERC20CustodyAbiString = ` [{"inputs":[{"internalType":"address","name":"_TSSAddress","type":"address"},{"internalType":"address","name":"_TSSAddressUpdater","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidTSSUpdater","type":"error"},{"inputs":[],"name":"IsPaused","type":"error"},{"inputs":[],"name":"NotPaused","type":"error"},{"inputs":[],"name":"NotWhitelisted","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"recipient","type":"bytes"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"}],"name":"Unwhitelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"}],"name":"Whitelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"TSSAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TSSAddressUpdater","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"recipient","type":"bytes"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceTSSAddressUpdater","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"unwhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"updateTSSAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"whitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]` ) +// GetConnectorABI returns the ABI of the connector contract func GetConnectorABI() string { return ConnectorAbiString } +// GetERC20CustodyABI returns the ABI of the erc20 custody contract func GetERC20CustodyABI() string { return ERC20CustodyAbiString } +// New returns a new config +// It is initialize with default chain configs func New() Config { return Config{ EVMChainConfigs: evmChainsConfigs, @@ -28,6 +37,7 @@ func New() Config { } } +// bitcoinConfigRegnet contains Bitcoin config for regnet var bitcoinConfigRegnet = BTCConfig{ RPCUsername: "smoketest", // smoketest is the previous name for E2E test, we keep this name for compatibility between client versions in upgrade test RPCPassword: "123", @@ -35,6 +45,8 @@ var bitcoinConfigRegnet = BTCConfig{ RPCParams: "regtest", } +// evmChainsConfigs contains EVM chain configs +// it contains list of EVM chains with empty endpoint except for localnet var evmChainsConfigs = map[int64]EVMConfig{ chains.Ethereum.ChainId: { Chain: chains.Ethereum, diff --git a/zetaclient/config/types.go b/zetaclient/config/types.go index b14cc8191b..96cdf24a4c 100644 --- a/zetaclient/config/types.go +++ b/zetaclient/config/types.go @@ -12,9 +12,14 @@ import ( type KeyringBackend string const ( + // KeyringBackendUndefined is undefined keyring backend KeyringBackendUndefined KeyringBackend = "" - KeyringBackendTest KeyringBackend = "test" - KeyringBackendFile KeyringBackend = "file" + + // KeyringBackendTest is the test Cosmos keyring backend + KeyringBackendTest KeyringBackend = "test" + + // KeyringBackendFile is the file Cosmos keyring backend + KeyringBackendFile KeyringBackend = "file" ) // ClientConfiguration is a subset of zetaclient config that is used by zetacore client @@ -27,11 +32,13 @@ type ClientConfiguration struct { HsmMode bool `json:"hsm_mode"` } +// EVMConfig is the config for EVM chain type EVMConfig struct { Chain chains.Chain Endpoint string } +// BTCConfig is the config for Bitcoin chain type BTCConfig struct { // the following are rpcclient ConnConfig fields RPCUsername string @@ -40,6 +47,7 @@ type BTCConfig struct { RPCParams string // "regtest", "mainnet", "testnet3" } +// ComplianceConfig is the config for compliance type ComplianceConfig struct { LogPath string `json:"LogPath"` RestrictedAddresses []string `json:"RestrictedAddresses"` @@ -78,6 +86,8 @@ type Config struct { ComplianceConfig ComplianceConfig `json:"ComplianceConfig"` } +// NewConfig returns a new Config with initialize EVM chain mapping and a new mutex +// TODO(revamp): consolidate with New function func NewConfig() Config { return Config{ cfgLock: &sync.RWMutex{}, @@ -85,6 +95,7 @@ func NewConfig() Config { } } +// GetEVMConfig returns the EVM config for the given chain ID func (c Config) GetEVMConfig(chainID int64) (EVMConfig, bool) { c.cfgLock.RLock() defer c.cfgLock.RUnlock() @@ -92,6 +103,7 @@ func (c Config) GetEVMConfig(chainID int64) (EVMConfig, bool) { return evmCfg, found } +// GetAllEVMConfigs returns a map of all EVM configs func (c Config) GetAllEVMConfigs() map[int64]EVMConfig { c.cfgLock.RLock() defer c.cfgLock.RUnlock() @@ -104,6 +116,7 @@ func (c Config) GetAllEVMConfigs() map[int64]EVMConfig { return copied } +// GetBTCConfig returns the BTC config func (c Config) GetBTCConfig() (BTCConfig, bool) { c.cfgLock.RLock() defer c.cfgLock.RUnlock() @@ -111,6 +124,7 @@ func (c Config) GetBTCConfig() (BTCConfig, bool) { return c.BitcoinConfig, c.BitcoinConfig != (BTCConfig{}) } +// String returns the string representation of the config func (c Config) String() string { s, err := json.MarshalIndent(c, "", "\t") if err != nil { @@ -131,6 +145,7 @@ func (c Config) GetRestrictedAddressBook() map[string]bool { return restrictedAddresses } +// GetKeyringBackend returns the keyring backend func (c *Config) GetKeyringBackend() KeyringBackend { c.cfgLock.RLock() defer c.cfgLock.RUnlock() diff --git a/zetaclient/context/app_context.go b/zetaclient/context/app_context.go index d47cd925e8..ffdfa05604 100644 --- a/zetaclient/context/app_context.go +++ b/zetaclient/context/app_context.go @@ -1,3 +1,4 @@ +// Package context provides global app context for ZetaClient package context import ( @@ -22,10 +23,12 @@ func NewAppContext( } } +// Config returns the config of the app func (a AppContext) Config() config.Config { return a.config } +// ZetacoreContext returns the context for ZetaChain func (a AppContext) ZetacoreContext() *ZetacoreContext { return a.coreContext } diff --git a/zetaclient/context/zetacore_context.go b/zetaclient/context/zetacore_context.go index 73ad83ff29..17d4cc5c3d 100644 --- a/zetaclient/context/zetacore_context.go +++ b/zetaclient/context/zetacore_context.go @@ -52,6 +52,7 @@ func NewZetacoreContext(cfg config.Config) *ZetacoreContext { } } +// GetKeygen returns the current keygen func (c *ZetacoreContext) GetKeygen() observertypes.Keygen { c.coreContextLock.RLock() defer c.coreContextLock.RUnlock() @@ -69,6 +70,7 @@ func (c *ZetacoreContext) GetKeygen() observertypes.Keygen { } } +// GetCurrentTssPubkey returns the current tss pubkey func (c *ZetacoreContext) GetCurrentTssPubkey() string { c.coreContextLock.RLock() defer c.coreContextLock.RUnlock() @@ -99,6 +101,7 @@ func (c *ZetacoreContext) GetEnabledExternalChains() []chains.Chain { return externalChains } +// GetEVMChainParams returns chain params for a specific EVM chain func (c *ZetacoreContext) GetEVMChainParams(chainID int64) (*observertypes.ChainParams, bool) { c.coreContextLock.RLock() defer c.coreContextLock.RUnlock() @@ -107,6 +110,7 @@ func (c *ZetacoreContext) GetEVMChainParams(chainID int64) (*observertypes.Chain return evmChainParams, found } +// GetAllEVMChainParams returns all chain params for EVM chains func (c *ZetacoreContext) GetAllEVMChainParams() map[int64]*observertypes.ChainParams { c.coreContextLock.RLock() defer c.coreContextLock.RUnlock() @@ -137,6 +141,7 @@ func (c *ZetacoreContext) GetBTCChainParams() (chains.Chain, *observertypes.Chai return *chain, c.bitcoinChainParams, true } +// GetCrossChainFlags returns crosschain flags func (c *ZetacoreContext) GetCrossChainFlags() observertypes.CrosschainFlags { c.coreContextLock.RLock() defer c.coreContextLock.RUnlock() diff --git a/zetaclient/hsm/hsm_signer.go b/zetaclient/hsm/hsm_signer.go index a6d513a353..7d11952716 100644 --- a/zetaclient/hsm/hsm_signer.go +++ b/zetaclient/hsm/hsm_signer.go @@ -1,3 +1,5 @@ +// Package hsm is used to interact with chains with a HSM +// it is currently not used package hsm import ( @@ -158,6 +160,7 @@ func SignWithHSM( return txBuilder.SetSignatures(prevSignatures...) } +// GetPKCS11Config returns the PKCS11 configuration from the environment variables func GetPKCS11Config() (config *crypto11.Config, err error) { config = &crypto11.Config{} config.Path = os.Getenv(hsmPath) diff --git a/zetaclient/keys/keys.go b/zetaclient/keys/keys.go index 3532c12233..0fdef6c204 100644 --- a/zetaclient/keys/keys.go +++ b/zetaclient/keys/keys.go @@ -23,8 +23,11 @@ import ( ) var ( + // ErrBech32ifyPubKey is an error when Bech32ifyPubKey fails ErrBech32ifyPubKey = errors.New("Bech32ifyPubKey fail in main") - ErrNewPubKey = errors.New("NewPubKey error from string") + + // ErrNewPubKey is an error when NewPubKey fails + ErrNewPubKey = errors.New("NewPubKey error from string") ) var _ interfaces.ObserverKeys = &Keys{} @@ -52,6 +55,7 @@ func NewKeysWithKeybase( } } +// GetGranteeKeyName return the grantee name func GetGranteeKeyName(signerName string) string { return signerName } @@ -110,6 +114,7 @@ func (k *Keys) GetSignerInfo() *ckeys.Record { return info } +// GetOperatorAddress return the operator address func (k *Keys) GetOperatorAddress() sdk.AccAddress { return k.OperatorAddress } diff --git a/zetaclient/metrics/metrics.go b/zetaclient/metrics/metrics.go index 1170d16f68..1da10d10e8 100644 --- a/zetaclient/metrics/metrics.go +++ b/zetaclient/metrics/metrics.go @@ -1,3 +1,4 @@ +// Package metrics provides metrics functionalities for the zetaclient package metrics import ( @@ -11,79 +12,93 @@ import ( "github.com/rs/zerolog/log" ) +// Metrics is a struct that contains the http server for metrics type Metrics struct { s *http.Server } +// ZetaClientNamespace is the namespace for the metrics const ZetaClientNamespace = "zetaclient" var ( + // PendingTxsPerChain is a gauge that contains the number of pending transactions per chain PendingTxsPerChain = promauto.NewGaugeVec(prometheus.GaugeOpts{ Namespace: ZetaClientNamespace, Name: "pending_txs_total", Help: "Number of pending transactions per chain", }, []string{"chain"}) + // GetFilterLogsPerChain is a counter that contains the number of getLogs per chain GetFilterLogsPerChain = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: ZetaClientNamespace, Name: "rpc_getFilterLogs_count", Help: "Count of getLogs per chain", }, []string{"chain"}) + // GetBlockByNumberPerChain is a counter that contains the number of getBlockByNumber per chain GetBlockByNumberPerChain = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: ZetaClientNamespace, Name: "rpc_getBlockByNumber_count", Help: "Count of getLogs per chain", }, []string{"chain"}) + // TssNodeBlamePerPubKey is a counter that contains the number of tss node blame per pubkey TssNodeBlamePerPubKey = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: ZetaClientNamespace, Name: "tss_node_blame_count", Help: "Tss node blame counter per pubkey", }, []string{"pubkey"}) + // HotKeyBurnRate is a gauge that contains the fee burn rate of the hotkey HotKeyBurnRate = promauto.NewGauge(prometheus.GaugeOpts{ Namespace: ZetaClientNamespace, Name: "hotkey_burn_rate", Help: "Fee burn rate of the hotkey", }) + // NumberOfUTXO is a gauge that contains the number of UTXOs NumberOfUTXO = promauto.NewGauge(prometheus.GaugeOpts{ Namespace: ZetaClientNamespace, Name: "utxo_number", Help: "Number of UTXOs", }) + // LastScannedBlockNumber is a gauge that contains the last scanned block number per chain LastScannedBlockNumber = promauto.NewGaugeVec(prometheus.GaugeOpts{ Namespace: ZetaClientNamespace, Name: "last_scanned_block_number", Help: "Last scanned block number per chain", }, []string{"chain"}) + // LastCoreBlockNumber is a gauge that contains the last core block number LastCoreBlockNumber = promauto.NewGauge(prometheus.GaugeOpts{ Namespace: ZetaClientNamespace, Name: "last_core_block_number", Help: "Last core block number", }) + // Info is a gauge that contains information about the zetaclient environment Info = promauto.NewGaugeVec(prometheus.GaugeOpts{ Namespace: ZetaClientNamespace, Name: "info", Help: "Information about Zetaclient environment", }, []string{"version"}) + // LastStartTime is a gauge that contains the start time in Unix time LastStartTime = promauto.NewGauge(prometheus.GaugeOpts{ Namespace: ZetaClientNamespace, Name: "last_start_timestamp_seconds", Help: "Start time in Unix time", }) + // NumActiveMsgSigns is a gauge that contains the number of concurrent key signs NumActiveMsgSigns = promauto.NewGauge(prometheus.GaugeOpts{ Namespace: ZetaClientNamespace, Name: "num_active_message_signs", Help: "Number of concurrent key signs", }) + // PercentageOfRateReached is a gauge that contains the percentage of the rate limiter rate reached PercentageOfRateReached = promauto.NewGauge(prometheus.GaugeOpts{ Namespace: ZetaClientNamespace, Name: "percentage_of_rate_reached", @@ -91,6 +106,7 @@ var ( }) ) +// NewMetrics creates a new Metrics instance func NewMetrics() (*Metrics, error) { handler := promhttp.InstrumentMetricHandler( prometheus.DefaultRegisterer, @@ -111,6 +127,7 @@ func NewMetrics() (*Metrics, error) { }, nil } +// Start starts the metrics server func (m *Metrics) Start() { log.Info().Msg("metrics server starting") go func() { @@ -120,6 +137,7 @@ func (m *Metrics) Start() { }() } +// Stop stops the metrics server func (m *Metrics) Stop() error { ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) defer cancel() diff --git a/zetaclient/metrics/telemetry.go b/zetaclient/metrics/telemetry.go index f49c1bf7b1..ebf62d887c 100644 --- a/zetaclient/metrics/telemetry.go +++ b/zetaclient/metrics/telemetry.go @@ -176,10 +176,12 @@ func (t *TelemetryServer) Stop() error { return err } +// pingHandler returns a 200 OK response func (t *TelemetryServer) pingHandler(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) } +// p2pHandler returns the p2p id func (t *TelemetryServer) p2pHandler(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) t.mu.Lock() @@ -187,6 +189,7 @@ func (t *TelemetryServer) p2pHandler(w http.ResponseWriter, _ *http.Request) { fmt.Fprintf(w, "%s", t.p2pid) } +// ipHandler returns the ip address func (t *TelemetryServer) ipHandler(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) t.mu.Lock() @@ -248,6 +251,7 @@ func (t *TelemetryServer) hotKeyFeeBurnRate(w http.ResponseWriter, _ *http.Reque fmt.Fprintf(w, "%v", t.HotKeyBurnRate.GetBurnRate()) } +// logMiddleware logs the incoming HTTP request func logMiddleware() mux.MiddlewareFunc { return func(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/zetaclient/orchestrator/orchestrator.go b/zetaclient/orchestrator/orchestrator.go index 1407557d3e..2c5ea2d2de 100644 --- a/zetaclient/orchestrator/orchestrator.go +++ b/zetaclient/orchestrator/orchestrator.go @@ -1,3 +1,4 @@ +// Package orchestrator provides the orchestrator for orchestrating cross-chain transactions package orchestrator import ( @@ -32,6 +33,8 @@ const ( loggerSamplingRate = 10 ) +// Log is a struct that contains the logger +// TODO(revamp): rename to logger type Log struct { Std zerolog.Logger Sampled zerolog.Logger @@ -42,8 +45,10 @@ type Orchestrator struct { // zetacore client zetacoreClient interfaces.ZetacoreClient - // chain signers and observers - signerMap map[int64]interfaces.ChainSigner + // signerMap contains the chain signers indexed by chainID + signerMap map[int64]interfaces.ChainSigner + + // observerMap contains the chain observers indexed by chainID observerMap map[int64]interfaces.ChainObserver // outbound processor @@ -94,6 +99,7 @@ func NewOrchestrator( return &oc } +// MonitorCore starts the orchestrator for CCTXs func (oc *Orchestrator) MonitorCore(appContext *context.AppContext) error { signerAddress, err := oc.zetacoreClient.GetKeys().GetAddress() if err != nil { @@ -231,6 +237,7 @@ func (oc *Orchestrator) GetPendingCctxsWithinRatelimit( } // StartCctxScheduler schedules keysigns for cctxs on each ZetaChain block (the ticker) +// TODO(revamp): make this function simpler func (oc *Orchestrator) StartCctxScheduler(appContext *context.AppContext) { observeTicker := time.NewTicker(3 * time.Second) var lastBlockNum int64 diff --git a/zetaclient/outboundprocessor/outbound_processor.go b/zetaclient/outboundprocessor/outbound_processor.go index feb4caafa7..75a9a6a19f 100644 --- a/zetaclient/outboundprocessor/outbound_processor.go +++ b/zetaclient/outboundprocessor/outbound_processor.go @@ -1,3 +1,4 @@ +// Package outboundprocessor provides functionalities to track outbound processing package outboundprocessor import ( @@ -8,6 +9,9 @@ import ( "github.com/rs/zerolog" ) +// Processor is a struct that contains data about outbound being processed +// TODO(revamp): rename this struct as it is not used to process outbound but track their processing +// We can also consider removing it once we refactor chain client to contains common logic to sign outbounds type Processor struct { outboundStartTime map[string]time.Time outboundEndTime map[string]time.Time @@ -17,6 +21,7 @@ type Processor struct { numActiveProcessor int64 } +// NewProcessor creates a new Processor func NewProcessor(logger zerolog.Logger) *Processor { return &Processor{ outboundStartTime: make(map[string]time.Time), @@ -28,6 +33,7 @@ func NewProcessor(logger zerolog.Logger) *Processor { } } +// StartTryProcess register a new outbound ID to track func (p *Processor) StartTryProcess(outboundID string) { p.mu.Lock() defer p.mu.Unlock() @@ -37,6 +43,7 @@ func (p *Processor) StartTryProcess(outboundID string) { p.Logger.Info().Msgf("StartTryProcess %s, numActiveProcessor %d", outboundID, p.numActiveProcessor) } +// EndTryProcess remove the outbound ID from tracking func (p *Processor) EndTryProcess(outboundID string) { p.mu.Lock() defer p.mu.Unlock() @@ -47,6 +54,7 @@ func (p *Processor) EndTryProcess(outboundID string) { Msgf("EndTryProcess %s, numActiveProcessor %d, time elapsed %s", outboundID, p.numActiveProcessor, time.Since(p.outboundStartTime[outboundID])) } +// IsOutboundActive checks if the outbound ID is being processed func (p *Processor) IsOutboundActive(outboundID string) bool { p.mu.Lock() defer p.mu.Unlock() @@ -54,6 +62,7 @@ func (p *Processor) IsOutboundActive(outboundID string) bool { return found } +// TimeInTryProcess returns the time elapsed since the outbound ID is being processed func (p *Processor) TimeInTryProcess(outboundID string) time.Duration { p.mu.Lock() defer p.mu.Unlock() diff --git a/zetaclient/ratelimiter/rate_limiter.go b/zetaclient/ratelimiter/rate_limiter.go index 0ddb3b378b..e3c69898fa 100644 --- a/zetaclient/ratelimiter/rate_limiter.go +++ b/zetaclient/ratelimiter/rate_limiter.go @@ -1,3 +1,4 @@ +// Package ratelimiter provides functionalities for rate limiting the cross-chain transactions package ratelimiter import ( diff --git a/zetaclient/supplychecker/logger.go b/zetaclient/supplychecker/logger.go index 223e43eab8..89da0300d6 100644 --- a/zetaclient/supplychecker/logger.go +++ b/zetaclient/supplychecker/logger.go @@ -21,6 +21,7 @@ type ZetaSupplyCheckLogs struct { SupplyCheckSuccess bool `json:"supply_check_success"` } +// LogOutput logs the output of the ZetaSupplyChecker func (z ZetaSupplyCheckLogs) LogOutput() { output, err := bitcoin.PrettyPrintStruct(z) if err != nil { diff --git a/zetaclient/supplychecker/validate.go b/zetaclient/supplychecker/validate.go index d70bda8c34..f9e4dbaf79 100644 --- a/zetaclient/supplychecker/validate.go +++ b/zetaclient/supplychecker/validate.go @@ -5,6 +5,7 @@ import ( "github.com/rs/zerolog" ) +// ValidateZetaSupply validates the zeta supply from the checked values func ValidateZetaSupply( logger zerolog.Logger, abortedTxAmounts, zetaInTransit, genesisAmounts, externalChainTotalSupply, zetaTokenSupplyOnNode, ethLockedAmount sdkmath.Int, diff --git a/zetaclient/supplychecker/zeta_supply_checker.go b/zetaclient/supplychecker/zeta_supply_checker.go index 952c0df16f..10ad1d5db1 100644 --- a/zetaclient/supplychecker/zeta_supply_checker.go +++ b/zetaclient/supplychecker/zeta_supply_checker.go @@ -1,3 +1,5 @@ +// Package supplychecker provides functionalities to check the total supply of Zeta tokens +// Currently not used in the codebase package supplychecker import ( @@ -92,6 +94,7 @@ func NewZetaSupplyChecker( return zetaSupplyChecker, nil } +// Start starts the ZetaSupplyChecker func (zs *ZetaSupplyChecker) Start() { defer zs.ticker.Stop() for { @@ -107,11 +110,13 @@ func (zs *ZetaSupplyChecker) Start() { } } +// Stop stops the ZetaSupplyChecker func (zs *ZetaSupplyChecker) Stop() { zs.logger.Info().Msgf("ZetaSupplyChecker is stopping") close(zs.stop) } +// CheckZetaTokenSupply checks the total supply of Zeta tokens func (zs *ZetaSupplyChecker) CheckZetaTokenSupply() error { externalChainTotalSupply := sdkmath.ZeroInt() for _, chain := range zs.externalEvmChain { @@ -193,6 +198,7 @@ func (zs *ZetaSupplyChecker) CheckZetaTokenSupply() error { return nil } +// AbortedTxAmount returns the amount of Zeta tokens in aborted transactions func (zs *ZetaSupplyChecker) AbortedTxAmount() (sdkmath.Int, error) { amount, err := zs.zetaClient.GetAbortedZetaAmount() if err != nil { @@ -205,6 +211,7 @@ func (zs *ZetaSupplyChecker) AbortedTxAmount() (sdkmath.Int, error) { return amountInt, nil } +// GetAmountOfZetaInTransit returns the amount of Zeta tokens in transit func (zs *ZetaSupplyChecker) GetAmountOfZetaInTransit() (sdkmath.Int, error) { chainsToCheck := make([]chains.Chain, len(zs.externalEvmChain)+1) chainsToCheck = append(append(chainsToCheck, zs.externalEvmChain...), zs.ethereumChain) @@ -222,6 +229,7 @@ func (zs *ZetaSupplyChecker) GetAmountOfZetaInTransit() (sdkmath.Int, error) { return amountInt, nil } +// GetPendingCCTXInTransit returns the pending CCTX in transit func (zs *ZetaSupplyChecker) GetPendingCCTXInTransit(receivingChains []chains.Chain) []*types.CrossChainTx { cctxInTransit := make([]*types.CrossChainTx, 0) for _, chain := range receivingChains { diff --git a/zetaclient/testutils/mempool_client.go b/zetaclient/testutils/mempool_client.go index 03c79120dc..a49ff45e78 100644 --- a/zetaclient/testutils/mempool_client.go +++ b/zetaclient/testutils/mempool_client.go @@ -15,6 +15,7 @@ const ( APIURLBlockTxsTestnet = "https://mempool.space/testnet/api/block/%s/txs" ) +// MempoolBlock represents a block in the mempool type MempoolBlock struct { ID string `json:"id"` Height int `json:"height"` @@ -32,6 +33,7 @@ type MempoolBlock struct { Extras BlockExtra `json:"extras"` } +// Vin represents a Bitcoin transaction input type Vin struct { TxID string `json:"txid"` Vout uint32 `json:"vout"` @@ -47,6 +49,7 @@ type Vin struct { Sequence uint32 `json:"sequence"` } +// Vout represents a Bitcoin transaction output type Vout struct { Scriptpubkey string `json:"scriptpubkey"` ScriptpubkeyAsm string `json:"scriptpubkey_asm"` @@ -54,6 +57,7 @@ type Vout struct { Value int64 `json:"value"` } +// MempoolTx represents a transaction in the mempool type MempoolTx struct { TxID string `json:"txid"` Version int `json:"version"` @@ -65,6 +69,7 @@ type MempoolTx struct { Fee int `json:"fee"` } +// BlockExtra represents extra information about a block type BlockExtra struct { TotalFees int `json:"totalFees"` MedianFee float64 `json:"medianFee"` @@ -105,6 +110,7 @@ type BlockExtra struct { ExpectedWeight int `json:"expectedWeight"` } +// Get makes a GET request to the given path and decodes the response func Get(ctx context.Context, path string, v interface{}) error { req, err := http.NewRequest("GET", path, nil) if err != nil { diff --git a/zetaclient/testutils/mocks/zetacore_client.go b/zetaclient/testutils/mocks/zetacore_client.go index 953d8ce287..2f413a8764 100644 --- a/zetaclient/testutils/mocks/zetacore_client.go +++ b/zetaclient/testutils/mocks/zetacore_client.go @@ -145,13 +145,6 @@ func (m *MockZetacoreClient) GetBlockHeight() (int64, error) { return 0, nil } -func (m *MockZetacoreClient) GetLastBlockHeightByChain(_ chains.Chain) (*crosschaintypes.LastBlockHeight, error) { - if m.paused { - return nil, errors.New(ErrMsgPaused) - } - return &crosschaintypes.LastBlockHeight{}, nil -} - func (m *MockZetacoreClient) GetRateLimiterInput(_ int64) (crosschaintypes.QueryRateLimiterInputResponse, error) { if m.paused { return crosschaintypes.QueryRateLimiterInputResponse{}, errors.New(ErrMsgPaused) diff --git a/zetaclient/testutils/testdata.go b/zetaclient/testutils/testdata.go index fc028bf0ec..620eb16b17 100644 --- a/zetaclient/testutils/testdata.go +++ b/zetaclient/testutils/testdata.go @@ -48,6 +48,8 @@ func LoadObjectFromJSONFile(t *testing.T, obj interface{}, filename string) { require.NoError(t, err) } +// ComplianceConfigTest returns a test compliance config +// TODO(revamp): move to sample package func ComplianceConfigTest() config.ComplianceConfig { return config.ComplianceConfig{ RestrictedAddresses: []string{RestrictedEVMAddressTest, RestrictedBtcAddressTest}, diff --git a/zetaclient/tss/tss_signer.go b/zetaclient/tss/tss_signer.go index 8fdd0384ee..08d48833db 100644 --- a/zetaclient/tss/tss_signer.go +++ b/zetaclient/tss/tss_signer.go @@ -1,3 +1,4 @@ +// Package tss provides the TSS signer functionalities for the zetaclient to sign transactions on external chains package tss import ( @@ -37,15 +38,18 @@ import ( ) const ( + // envFlagPostBlame is the environment flag to enable posting blame data to core envFlagPostBlame = "POST_BLAME" ) +// Key is a struct that holds the public key, bech32 pubkey, and address for the TSS type Key struct { PubkeyInBytes []byte PubkeyInBech32 string AddressInHex string } +// NewTSSKey creates a new TSS key func NewTSSKey(pk string) (*Key, error) { TSSKey := &Key{ PubkeyInBech32: pk, @@ -141,6 +145,8 @@ func NewTSS( return &newTss, nil } +// SetupTSSServer creates a new TSS server +// TODO(revamp): move to TSS server file func SetupTSSServer( peer p2p.AddrList, privkey tmcrypto.PrivKey, @@ -207,6 +213,7 @@ func SetupTSSServer( return tssServer, nil } +// Pubkey returns the current pubkey func (tss *TSS) Pubkey() []byte { return tss.Keys[tss.CurrentPubkey].PubkeyInBytes } @@ -404,6 +411,7 @@ func (tss *TSS) SignBatch(digests [][]byte, height uint64, nonce uint64, chainID return sigBytes, nil } +// Validate validates the TSS func (tss *TSS) Validate() error { evmAddress := tss.EVMAddress() blankAddress := ethcommon.Address{} @@ -419,6 +427,7 @@ func (tss *TSS) Validate() error { return nil } +// EVMAddress generates an EVM address from pubkey func (tss *TSS) EVMAddress() ethcommon.Address { addr, err := GetTssAddrEVM(tss.CurrentPubkey) if err != nil { @@ -438,6 +447,7 @@ func (tss *TSS) BTCAddress() string { return addr } +// BTCAddressWitnessPubkeyHash generates a bech32 p2wpkh address from pubkey func (tss *TSS) BTCAddressWitnessPubkeyHash() *btcutil.AddressWitnessPubKeyHash { addrWPKH, err := getKeyAddrBTCWitnessPubkeyHash(tss.CurrentPubkey, tss.BitcoinChainID) if err != nil { @@ -447,6 +457,7 @@ func (tss *TSS) BTCAddressWitnessPubkeyHash() *btcutil.AddressWitnessPubKeyHash return addrWPKH } +// PubKeyCompressedBytes returns the compressed bytes of the current pubkey func (tss *TSS) PubKeyCompressedBytes() []byte { pubk, err := cosmos.GetPubKeyFromBech32(cosmos.Bech32PubKeyTypeAccPub, tss.CurrentPubkey) if err != nil { @@ -466,6 +477,7 @@ func (tss *TSS) InsertPubKey(pk string) error { return nil } +// VerifyKeysharesForPubkeys verifies the keyshares present on the node. It checks whether the node has TSS key shares for the TSS ceremonies it was part of. func (tss *TSS) VerifyKeysharesForPubkeys(tssList []observertypes.TSS, granteePubKey32 string) error { for _, t := range tssList { if wasNodePartOfTss(granteePubKey32, t.TssParticipantList) { @@ -477,6 +489,7 @@ func (tss *TSS) VerifyKeysharesForPubkeys(tssList []observertypes.TSS, granteePu return nil } +// LoadTssFilesFromDirectory loads the TSS files at the directory specified by the `tssPath` func (tss *TSS) LoadTssFilesFromDirectory(tssPath string) error { files, err := os.ReadDir(tssPath) if err != nil { @@ -528,6 +541,7 @@ func (tss *TSS) LoadTssFilesFromDirectory(tssPath string) error { return nil } +// GetTssAddrBTC generates a bech32 p2wpkh address from pubkey func GetTssAddrBTC(tssPubkey string, bitcoinChainID int64) (string, error) { addrWPKH, err := getKeyAddrBTCWitnessPubkeyHash(tssPubkey, bitcoinChainID) if err != nil { @@ -538,6 +552,7 @@ func GetTssAddrBTC(tssPubkey string, bitcoinChainID int64) (string, error) { return addrWPKH.EncodeAddress(), nil } +// GetTssAddrEVM generates an EVM address from pubkey func GetTssAddrEVM(tssPubkey string) (ethcommon.Address, error) { var keyAddr ethcommon.Address pubk, err := cosmos.GetPubKeyFromBech32(cosmos.Bech32PubKeyTypeAccPub, tssPubkey) @@ -558,6 +573,9 @@ func GetTssAddrEVM(tssPubkey string) (ethcommon.Address, error) { return keyAddr, nil } +// TestKeysign tests the keysign +// it is called when a new TSS is generated to ensure the network works as expected +// TODO(revamp): move to a test package func TestKeysign(tssPubkey string, tssServer *tss.TssServer) error { log.Info().Msg("trying keysign...") data := []byte("hello meta") @@ -594,11 +612,14 @@ func TestKeysign(tssPubkey string, tssServer *tss.TssServer) error { return fmt.Errorf("verify signature fail") } +// IsEnvFlagEnabled checks if the environment flag is enabled func IsEnvFlagEnabled(flag string) bool { value := os.Getenv(flag) return value == "true" || value == "1" } +// verifySignature verifies the signature +// TODO(revamp): move to a test package func verifySignature(tssPubkey string, signature []keysign.Signature, H []byte) bool { if len(signature) == 0 { log.Warn().Msg("verify_signature: empty signature array") @@ -640,12 +661,15 @@ func verifySignature(tssPubkey string, signature []keysign.Signature, H []byte) return bytes.Equal(pubkey.Bytes(), compressedPubkey) } +// combineDigests combines the digests func combineDigests(digestList []string) []byte { digestConcat := strings.Join(digestList[:], "") digestBytes := chainhash.DoubleHashH([]byte(digestConcat)) return digestBytes.CloneBytes() } +// wasNodePartOfTss checks if the node was part of the TSS +// it checks whether a pubkey is part of the list used to generate the TSS , Every TSS generated on the network has its own list of associated public keys func wasNodePartOfTss(granteePubKey32 string, granteeList []string) bool { for _, grantee := range granteeList { if granteePubKey32 == grantee { @@ -655,6 +679,7 @@ func wasNodePartOfTss(granteePubKey32 string, granteeList []string) bool { return false } +// getKeyAddrBTCWitnessPubkeyHash generates a bech32 p2wpkh address from pubkey func getKeyAddrBTCWitnessPubkeyHash(tssPubkey string, chainID int64) (*btcutil.AddressWitnessPubKeyHash, error) { pubk, err := cosmos.GetPubKeyFromBech32(cosmos.Bech32PubKeyTypeAccPub, tssPubkey) if err != nil { diff --git a/zetaclient/types/dynamic_ticker.go b/zetaclient/types/dynamic_ticker.go index 49434e03ea..103bfffb94 100644 --- a/zetaclient/types/dynamic_ticker.go +++ b/zetaclient/types/dynamic_ticker.go @@ -7,12 +7,14 @@ import ( "github.com/rs/zerolog" ) +// DynamicTicker is a ticker that can have its interval updated type DynamicTicker struct { name string interval uint64 impl *time.Ticker } +// NewDynamicTicker creates a new DynamicTicker func NewDynamicTicker(name string, interval uint64) (*DynamicTicker, error) { if interval <= 0 { return nil, fmt.Errorf("non-positive ticker interval %d for %s", interval, name) @@ -25,10 +27,12 @@ func NewDynamicTicker(name string, interval uint64) (*DynamicTicker, error) { }, nil } +// C returns the channel of the ticker func (t *DynamicTicker) C() <-chan time.Time { return t.impl.C } +// UpdateInterval updates the interval of the ticker func (t *DynamicTicker) UpdateInterval(newInterval uint64, logger zerolog.Logger) { if newInterval > 0 && t.interval != newInterval { t.impl.Stop() @@ -39,6 +43,7 @@ func (t *DynamicTicker) UpdateInterval(newInterval uint64, logger zerolog.Logger } } +// Stop stops the ticker func (t *DynamicTicker) Stop() { t.impl.Stop() } diff --git a/zetaclient/types/ethish.go b/zetaclient/types/ethish.go index fd3a40af6d..6935a22141 100644 --- a/zetaclient/types/ethish.go +++ b/zetaclient/types/ethish.go @@ -4,6 +4,7 @@ import ( "encoding/hex" ) +// EthHexToBytes converts an Ethereum hex string to bytes func BytesToEthHex(b []byte) string { return "0x" + hex.EncodeToString(b) } diff --git a/zetaclient/types/sql_evm.go b/zetaclient/types/sql_evm.go index c551fda503..398a968a60 100644 --- a/zetaclient/types/sql_evm.go +++ b/zetaclient/types/sql_evm.go @@ -71,6 +71,7 @@ type LastBlockSQLType struct { // Type translation functions: +// ToReceiptDBType : Converts an Ethereum receipt to a ReceiptDB type func ToReceiptDBType(receipt *ethtypes.Receipt) (ReceiptDB, error) { logs, err := json.Marshal(receipt.Logs) if err != nil { @@ -92,6 +93,7 @@ func ToReceiptDBType(receipt *ethtypes.Receipt) (ReceiptDB, error) { }, nil } +// FromReceiptDBType : Converts a ReceiptDB type to an Ethereum receipt func FromReceiptDBType(receipt ReceiptDB) (*ethtypes.Receipt, error) { res := ðtypes.Receipt{ Type: receipt.Type, @@ -111,6 +113,7 @@ func FromReceiptDBType(receipt ReceiptDB) (*ethtypes.Receipt, error) { return res, err } +// ToReceiptSQLType : Converts an Ethereum receipt to a ReceiptSQLType func ToReceiptSQLType(receipt *ethtypes.Receipt, index string) (*ReceiptSQLType, error) { r, err := ToReceiptDBType(receipt) if err != nil { @@ -122,6 +125,7 @@ func ToReceiptSQLType(receipt *ethtypes.Receipt, index string) (*ReceiptSQLType, }, nil } +// ToTransactionDBType : Converts an Ethereum transaction to a TransactionDB type func ToTransactionDBType(transaction *ethtypes.Transaction) (TransactionDB, error) { data, err := transaction.MarshalBinary() if err != nil { @@ -137,12 +141,14 @@ func ToTransactionDBType(transaction *ethtypes.Transaction) (TransactionDB, erro }, nil } +// FromTransactionDBType : Converts a TransactionDB type to an Ethereum transaction func FromTransactionDBType(transaction TransactionDB) (*ethtypes.Transaction, error) { res := ðtypes.Transaction{} err := res.UnmarshalBinary(transaction.TransactionData) return res, err } +// ToTransactionSQLType : Converts an Ethereum transaction to a TransactionSQLType func ToTransactionSQLType(transaction *ethtypes.Transaction, index string) (*TransactionSQLType, error) { trans, err := ToTransactionDBType(transaction) if err != nil { @@ -154,6 +160,7 @@ func ToTransactionSQLType(transaction *ethtypes.Transaction, index string) (*Tra }, nil } +// ToLastBlockSQLType : Converts a last block number to a LastBlockSQLType func ToLastBlockSQLType(lastBlock uint64) *LastBlockSQLType { return &LastBlockSQLType{ Model: gorm.Model{ID: LastBlockNumID}, diff --git a/zetaclient/zetacore/broadcast.go b/zetaclient/zetacore/broadcast.go index 82a011c6ba..6c1b475476 100644 --- a/zetaclient/zetacore/broadcast.go +++ b/zetaclient/zetacore/broadcast.go @@ -50,7 +50,7 @@ func BroadcastToZetaCore( return client.Broadcast(gasLimit, authzWrappedMsg, authzSigner) } -// Broadcast Broadcasts tx to metachain. Returns txHash and error +// Broadcast Broadcasts tx to ZetaChain. Returns txHash and error func (c *Client) Broadcast(gaslimit uint64, authzWrappedMsg sdktypes.Msg, authzSigner authz.Signer) (string, error) { c.broadcastLock.Lock() defer c.broadcastLock.Unlock() @@ -204,6 +204,7 @@ func (c *Client) GetContext() (client.Context, error) { return ctx, nil } +// SignTx signs a tx with the given name func (c *Client) SignTx( txf clienttx.Factory, name string, diff --git a/zetaclient/zetacore/client.go b/zetaclient/zetacore/client.go index 3b85296fe1..4443316a4a 100644 --- a/zetaclient/zetacore/client.go +++ b/zetaclient/zetacore/client.go @@ -1,3 +1,4 @@ +// Package zetacore provides functionalities for interacting with ZetaChain package zetacore import ( @@ -283,14 +284,18 @@ func (c *Client) UpdateZetacoreContext( return nil } +// Pause pauses the client func (c *Client) Pause() { <-c.pause } +// Unpause unpauses the client func (c *Client) Unpause() { c.pause <- struct{}{} } +// EnableMockSDKClient enables the mock cosmos sdk client +// TODO(revamp): move this to a test package func (c *Client) EnableMockSDKClient(client rpcclient.Client) { c.mockSDKClient = client c.enableMockSDKClient = true diff --git a/zetaclient/zetacore/query.go b/zetaclient/zetacore/query.go index b68ea37f8b..e90be274ff 100644 --- a/zetaclient/zetacore/query.go +++ b/zetaclient/zetacore/query.go @@ -25,6 +25,7 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" ) +// GetCrosschainFlags returns the crosschain flags func (c *Client) GetCrosschainFlags() (observertypes.CrosschainFlags, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.CrosschainFlags(context.Background(), &observertypes.QueryGetCrosschainFlagsRequest{}) @@ -34,6 +35,7 @@ func (c *Client) GetCrosschainFlags() (observertypes.CrosschainFlags, error) { return resp.CrosschainFlags, nil } +// GetBlockHeaderEnabledChains returns the enabled chains for block headers func (c *Client) GetBlockHeaderEnabledChains() ([]lightclienttypes.HeaderSupportedChain, error) { client := lightclienttypes.NewQueryClient(c.grpcConn) resp, err := client.HeaderEnabledChains(context.Background(), &lightclienttypes.QueryHeaderEnabledChainsRequest{}) @@ -43,6 +45,7 @@ func (c *Client) GetBlockHeaderEnabledChains() ([]lightclienttypes.HeaderSupport return resp.HeaderEnabledChains, nil } +// GetRateLimiterFlags returns the rate limiter flags func (c *Client) GetRateLimiterFlags() (crosschaintypes.RateLimiterFlags, error) { client := crosschaintypes.NewQueryClient(c.grpcConn) resp, err := client.RateLimiterFlags(context.Background(), &crosschaintypes.QueryRateLimiterFlagsRequest{}) @@ -52,6 +55,7 @@ func (c *Client) GetRateLimiterFlags() (crosschaintypes.RateLimiterFlags, error) return resp.RateLimiterFlags, nil } +// GetChainParamsForChainID returns the chain params for a given chain ID func (c *Client) GetChainParamsForChainID(externalChainID int64) (*observertypes.ChainParams, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.GetChainParamsForChain( @@ -64,6 +68,7 @@ func (c *Client) GetChainParamsForChainID(externalChainID int64) (*observertypes return resp.ChainParams, nil } +// GetChainParams returns all the chain params func (c *Client) GetChainParams() ([]*observertypes.ChainParams, error) { client := observertypes.NewQueryClient(c.grpcConn) var err error @@ -79,6 +84,7 @@ func (c *Client) GetChainParams() ([]*observertypes.ChainParams, error) { return nil, fmt.Errorf("failed to get chain params | err %s", err.Error()) } +// GetUpgradePlan returns the current upgrade plan func (c *Client) GetUpgradePlan() (*upgradetypes.Plan, error) { client := upgradetypes.NewQueryClient(c.grpcConn) @@ -89,6 +95,7 @@ func (c *Client) GetUpgradePlan() (*upgradetypes.Plan, error) { return resp.Plan, nil } +// GetAllCctx returns all cross chain transactions func (c *Client) GetAllCctx() ([]*crosschaintypes.CrossChainTx, error) { client := crosschaintypes.NewQueryClient(c.grpcConn) resp, err := client.CctxAll(context.Background(), &crosschaintypes.QueryAllCctxRequest{}) @@ -98,6 +105,7 @@ func (c *Client) GetAllCctx() ([]*crosschaintypes.CrossChainTx, error) { return resp.CrossChainTx, nil } +// GetCctxByHash returns a cross chain transaction by hash func (c *Client) GetCctxByHash(sendHash string) (*crosschaintypes.CrossChainTx, error) { client := crosschaintypes.NewQueryClient(c.grpcConn) resp, err := client.Cctx(context.Background(), &crosschaintypes.QueryGetCctxRequest{Index: sendHash}) @@ -107,6 +115,7 @@ func (c *Client) GetCctxByHash(sendHash string) (*crosschaintypes.CrossChainTx, return resp.CrossChainTx, nil } +// GetCctxByNonce returns a cross chain transaction by nonce func (c *Client) GetCctxByNonce(chainID int64, nonce uint64) (*crosschaintypes.CrossChainTx, error) { client := crosschaintypes.NewQueryClient(c.grpcConn) resp, err := client.CctxByNonce(context.Background(), &crosschaintypes.QueryGetCctxByNonceRequest{ @@ -119,6 +128,7 @@ func (c *Client) GetCctxByNonce(chainID int64, nonce uint64) (*crosschaintypes.C return resp.CrossChainTx, nil } +// GetObserverList returns the list of observers func (c *Client) GetObserverList() ([]string, error) { var err error client := observertypes.NewQueryClient(c.grpcConn) @@ -185,6 +195,7 @@ func (c *Client) ListPendingCctxWithinRatelimit() ([]*crosschaintypes.CrossChain return resp.CrossChainTx, resp.TotalPending, resp.CurrentWithdrawWindow, resp.CurrentWithdrawRate, resp.RateLimitExceeded, nil } +// GetAbortedZetaAmount returns the amount of zeta that has been aborted func (c *Client) GetAbortedZetaAmount() (string, error) { client := crosschaintypes.NewQueryClient(c.grpcConn) resp, err := client.ZetaAccounting(context.Background(), &crosschaintypes.QueryZetaAccountingRequest{}) @@ -194,6 +205,7 @@ func (c *Client) GetAbortedZetaAmount() (string, error) { return resp.AbortedZetaAmount, nil } +// GetGenesisSupply returns the genesis supply func (c *Client) GetGenesisSupply() (sdkmath.Int, error) { tmURL := fmt.Sprintf("http://%s", c.cfg.ChainRPC) s, err := tmhttp.New(tmURL, "/websocket") @@ -212,6 +224,7 @@ func (c *Client) GetGenesisSupply() (sdkmath.Int, error) { return bankstate.Supply.AmountOf(config.BaseDenom), nil } +// GetZetaTokenSupplyOnNode returns the zeta token supply on the node func (c *Client) GetZetaTokenSupplyOnNode() (sdkmath.Int, error) { client := banktypes.NewQueryClient(c.grpcConn) resp, err := client.SupplyOf(context.Background(), &banktypes.QuerySupplyOfRequest{Denom: config.BaseDenom}) @@ -221,6 +234,7 @@ func (c *Client) GetZetaTokenSupplyOnNode() (sdkmath.Int, error) { return resp.GetAmount().Amount, nil } +// GetLastBlockHeight returns the last block height func (c *Client) GetLastBlockHeight() ([]*crosschaintypes.LastBlockHeight, error) { client := crosschaintypes.NewQueryClient(c.grpcConn) resp, err := client.LastBlockHeightAll(context.Background(), &crosschaintypes.QueryAllLastBlockHeightRequest{}) @@ -231,6 +245,7 @@ func (c *Client) GetLastBlockHeight() ([]*crosschaintypes.LastBlockHeight, error return resp.LastBlockHeight, nil } +// GetLatestZetaBlock returns the latest zeta block func (c *Client) GetLatestZetaBlock() (*tmservice.Block, error) { client := tmservice.NewServiceClient(c.grpcConn) res, err := client.GetLatestBlock(context.Background(), &tmservice.GetLatestBlockRequest{}) @@ -240,6 +255,7 @@ func (c *Client) GetLatestZetaBlock() (*tmservice.Block, error) { return res.SdkBlock, nil } +// GetNodeInfo returns the node info func (c *Client) GetNodeInfo() (*tmservice.GetNodeInfoResponse, error) { var err error @@ -254,18 +270,7 @@ func (c *Client) GetNodeInfo() (*tmservice.GetNodeInfoResponse, error) { return nil, err } -func (c *Client) GetLastBlockHeightByChain(chain chains.Chain) (*crosschaintypes.LastBlockHeight, error) { - client := crosschaintypes.NewQueryClient(c.grpcConn) - resp, err := client.LastBlockHeight( - context.Background(), - &crosschaintypes.QueryGetLastBlockHeightRequest{Index: chain.ChainName.String()}, - ) - if err != nil { - return nil, err - } - return resp.LastBlockHeight, nil -} - +// GetBlockHeight returns the zetachain block height func (c *Client) GetBlockHeight() (int64, error) { client := crosschaintypes.NewQueryClient(c.grpcConn) resp, err := client.LastZetaHeight(context.Background(), &crosschaintypes.QueryLastZetaHeightRequest{}) @@ -275,6 +280,7 @@ func (c *Client) GetBlockHeight() (int64, error) { return resp.Height, nil } +// GetBaseGasPrice returns the base gas price func (c *Client) GetBaseGasPrice() (int64, error) { client := feemarkettypes.NewQueryClient(c.grpcConn) resp, err := client.Params(context.Background(), &feemarkettypes.QueryParamsRequest{}) @@ -287,6 +293,7 @@ func (c *Client) GetBaseGasPrice() (int64, error) { return resp.Params.BaseFee.Int64(), nil } +// GetBallotByID returns a ballot by ID func (c *Client) GetBallotByID(id string) (*observertypes.QueryBallotByIdentifierResponse, error) { client := observertypes.NewQueryClient(c.grpcConn) return client.BallotByIdentifier(context.Background(), &observertypes.QueryBallotByIdentifierRequest{ @@ -294,6 +301,7 @@ func (c *Client) GetBallotByID(id string) (*observertypes.QueryBallotByIdentifie }) } +// GetNonceByChain returns the nonce by chain func (c *Client) GetNonceByChain(chain chains.Chain) (observertypes.ChainNonces, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.ChainNonces( @@ -306,6 +314,7 @@ func (c *Client) GetNonceByChain(chain chains.Chain) (observertypes.ChainNonces, return resp.ChainNonces, nil } +// GetAllNodeAccounts returns all node accounts func (c *Client) GetAllNodeAccounts() ([]*observertypes.NodeAccount, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.NodeAccountAll(context.Background(), &observertypes.QueryAllNodeAccountRequest{}) @@ -316,6 +325,7 @@ func (c *Client) GetAllNodeAccounts() ([]*observertypes.NodeAccount, error) { return resp.NodeAccount, nil } +// GetKeyGen returns the keygen func (c *Client) GetKeyGen() (*observertypes.Keygen, error) { var err error client := observertypes.NewQueryClient(c.grpcConn) @@ -330,6 +340,7 @@ func (c *Client) GetKeyGen() (*observertypes.Keygen, error) { return nil, fmt.Errorf("failed to get keygen | err %s", err.Error()) } +// GetBallot returns a ballot by ID func (c *Client) GetBallot(ballotIdentifier string) (*observertypes.QueryBallotByIdentifierResponse, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.BallotByIdentifier(context.Background(), &observertypes.QueryBallotByIdentifierRequest{ @@ -341,6 +352,7 @@ func (c *Client) GetBallot(ballotIdentifier string) (*observertypes.QueryBallotB return resp, nil } +// GetInboundTrackersForChain returns the inbound trackers for a chain func (c *Client) GetInboundTrackersForChain(chainID int64) ([]crosschaintypes.InboundTracker, error) { client := crosschaintypes.NewQueryClient(c.grpcConn) resp, err := client.InboundTrackerAllByChain( @@ -353,6 +365,7 @@ func (c *Client) GetInboundTrackersForChain(chainID int64) ([]crosschaintypes.In return resp.InboundTracker, nil } +// GetCurrentTss returns the current TSS func (c *Client) GetCurrentTss() (observertypes.TSS, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.TSS(context.Background(), &observertypes.QueryGetTSSRequest{}) @@ -362,6 +375,8 @@ func (c *Client) GetCurrentTss() (observertypes.TSS, error) { return resp.TSS, nil } +// GetEthTssAddress returns the ETH TSS address +// TODO(revamp): rename to EVM func (c *Client) GetEthTssAddress() (string, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.GetTssAddress(context.Background(), &observertypes.QueryGetTssAddressRequest{}) @@ -371,6 +386,7 @@ func (c *Client) GetEthTssAddress() (string, error) { return resp.Eth, nil } +// GetBtcTssAddress returns the BTC TSS address func (c *Client) GetBtcTssAddress(chainID int64) (string, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.GetTssAddress(context.Background(), &observertypes.QueryGetTssAddressRequest{ @@ -382,6 +398,7 @@ func (c *Client) GetBtcTssAddress(chainID int64) (string, error) { return resp.Btc, nil } +// GetTssHistory returns the TSS history func (c *Client) GetTssHistory() ([]observertypes.TSS, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.TssHistory(context.Background(), &observertypes.QueryTssHistoryRequest{}) @@ -391,6 +408,7 @@ func (c *Client) GetTssHistory() ([]observertypes.TSS, error) { return resp.TssList, nil } +// GetOutboundTracker returns the outbound tracker for a chain and nonce func (c *Client) GetOutboundTracker(chain chains.Chain, nonce uint64) (*crosschaintypes.OutboundTracker, error) { client := crosschaintypes.NewQueryClient(c.grpcConn) resp, err := client.OutboundTracker(context.Background(), &crosschaintypes.QueryGetOutboundTrackerRequest{ @@ -403,6 +421,7 @@ func (c *Client) GetOutboundTracker(chain chains.Chain, nonce uint64) (*crosscha return &resp.OutboundTracker, nil } +// GetAllOutboundTrackerByChain returns all outbound trackers for a chain func (c *Client) GetAllOutboundTrackerByChain( chainID int64, order interfaces.Order, @@ -437,6 +456,7 @@ func (c *Client) GetAllOutboundTrackerByChain( return resp.OutboundTracker, nil } +// GetPendingNoncesByChain returns the pending nonces for a chain and current tss address func (c *Client) GetPendingNoncesByChain(chainID int64) (observertypes.PendingNonces, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.PendingNoncesByChain( @@ -449,6 +469,7 @@ func (c *Client) GetPendingNoncesByChain(chainID int64) (observertypes.PendingNo return resp.PendingNonces, nil } +// GetBlockHeaderChainState returns the block header chain state func (c *Client) GetBlockHeaderChainState(chainID int64) (lightclienttypes.QueryGetChainStateResponse, error) { client := lightclienttypes.NewQueryClient(c.grpcConn) resp, err := client.ChainState(context.Background(), &lightclienttypes.QueryGetChainStateRequest{ChainId: chainID}) @@ -458,6 +479,7 @@ func (c *Client) GetBlockHeaderChainState(chainID int64) (lightclienttypes.Query return *resp, nil } +// GetSupportedChains returns the supported chains func (c *Client) GetSupportedChains() ([]*chains.Chain, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.SupportedChains(context.Background(), &observertypes.QuerySupportedChains{}) @@ -467,6 +489,7 @@ func (c *Client) GetSupportedChains() ([]*chains.Chain, error) { return resp.GetChains(), nil } +// GetPendingNonces returns the pending nonces func (c *Client) GetPendingNonces() (*observertypes.QueryAllPendingNoncesResponse, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.PendingNoncesAll(context.Background(), &observertypes.QueryAllPendingNoncesRequest{}) @@ -476,6 +499,7 @@ func (c *Client) GetPendingNonces() (*observertypes.QueryAllPendingNoncesRespons return resp, nil } +// Prove returns whether a proof is valid func (c *Client) Prove( blockHash string, txHash string, @@ -497,6 +521,7 @@ func (c *Client) Prove( return resp.Valid, nil } +// HasVoted returns whether an observer has voted func (c *Client) HasVoted(ballotIndex string, voterAddress string) (bool, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.HasVoted(context.Background(), &observertypes.QueryHasVotedRequest{ @@ -509,6 +534,7 @@ func (c *Client) HasVoted(ballotIndex string, voterAddress string) (bool, error) return resp.HasVoted, nil } +// GetZetaHotKeyBalance returns the zeta hot key balance func (c *Client) GetZetaHotKeyBalance() (sdkmath.Int, error) { client := banktypes.NewQueryClient(c.grpcConn) address, err := c.keys.GetAddress() diff --git a/zetaclient/zetacore/query_test.go b/zetaclient/zetacore/query_test.go index 05d52fc088..70898b8e11 100644 --- a/zetaclient/zetacore/query_test.go +++ b/zetaclient/zetacore/query_test.go @@ -461,30 +461,6 @@ func TestZetacore_GetNodeInfo(t *testing.T) { require.Equal(t, expectedOutput, *resp) } -func TestZetacore_GetLastBlockHeightByChain(t *testing.T) { - index := chains.BscMainnet - expectedOutput := crosschainTypes.QueryGetLastBlockHeightResponse{ - LastBlockHeight: &crosschainTypes.LastBlockHeight{ - Index: index.ChainName.String(), - Chain: "7000", - LastOutboundHeight: 2134123, - LastInboundHeight: 1234333, - }, - } - input := crosschainTypes.QueryGetLastBlockHeightRequest{Index: index.ChainName.String()} - method := "/zetachain.zetacore.crosschain.Query/LastBlockHeight" - server := setupMockServer(t, crosschainTypes.RegisterQueryServer, method, input, expectedOutput) - server.Serve() - defer closeMockServer(t, server) - - client, err := setupZetacoreClient() - require.NoError(t, err) - - resp, err := client.GetLastBlockHeightByChain(index) - require.NoError(t, err) - require.Equal(t, expectedOutput.LastBlockHeight, resp) -} - func TestZetacore_GetZetaBlockHeight(t *testing.T) { expectedOutput := crosschainTypes.QueryLastZetaHeightResponse{Height: 12345} input := crosschainTypes.QueryLastZetaHeightRequest{} diff --git a/zetaclient/zetacore/tx.go b/zetaclient/zetacore/tx.go index 798654856f..0a28336b04 100644 --- a/zetaclient/zetacore/tx.go +++ b/zetaclient/zetacore/tx.go @@ -24,6 +24,7 @@ import ( ) // GetInboundVoteMessage returns a new MsgVoteInbound +// TODO(revamp): move to a different file func GetInboundVoteMessage( sender string, senderChain int64, @@ -69,6 +70,8 @@ func GasPriceMultiplier(chainID int64) (float64, error) { return 0, fmt.Errorf("cannot get gas price multiplier for unknown chain %d", chainID) } +// WrapMessageWithAuthz wraps a message with an authz message +// used since a hotkey is used to broadcast the transactions, instead of the operator func (c *Client) WrapMessageWithAuthz(msg sdk.Msg) (sdk.Msg, clientauthz.Signer, error) { msgURL := sdk.MsgTypeURL(msg) @@ -82,6 +85,8 @@ func (c *Client) WrapMessageWithAuthz(msg sdk.Msg) (sdk.Msg, clientauthz.Signer, return &authzMessage, authzSigner, nil } +// PostGasPrice posts a gas price vote +// TODO(revamp): rename to PostVoteGasPrice func (c *Client) PostGasPrice(chain chains.Chain, gasPrice uint64, supply string, blockNum uint64) (string, error) { // apply gas price multiplier for the chain multiplier, err := GasPriceMultiplier(chain.ChainId) @@ -110,6 +115,8 @@ func (c *Client) PostGasPrice(chain chains.Chain, gasPrice uint64, supply string return "", fmt.Errorf("post gasprice failed after %d retries", DefaultRetryInterval) } +// AddOutboundTracker adds an outbound tracker +// TODO(revamp): rename to PostAddOutboundTracker func (c *Client) AddOutboundTracker( chainID int64, nonce uint64, @@ -143,6 +150,8 @@ func (c *Client) AddOutboundTracker( return zetaTxHash, nil } +// SetTSS sends message to vote tss +// TODO(revamp): rename to PostVoteTSS func (c *Client) SetTSS(tssPubkey string, keyGenZetaHeight int64, status chains.ReceiveStatus) (string, error) { signerAddress := c.keys.GetOperatorAddress().String() msg := observertypes.NewMsgVoteTSS(signerAddress, tssPubkey, keyGenZetaHeight, status) @@ -166,6 +175,8 @@ func (c *Client) SetTSS(tssPubkey string, keyGenZetaHeight int64, status chains. } // ZetacoreContextUpdater is a polling goroutine that checks and updates zetacore context at every height +// TODO(revamp): move to a different file +// TODO(revamp): rename to UpdateZetacoreContext func (c *Client) ZetacoreContextUpdater(appContext *appcontext.AppContext) { c.logger.Info().Msg("ZetacoreContextUpdater started") ticker := time.NewTicker(time.Duration(appContext.Config().ConfigUpdateTicker) * time.Second) @@ -185,6 +196,8 @@ func (c *Client) ZetacoreContextUpdater(appContext *appcontext.AppContext) { } } +// PostBlameData posts blame data message to zetacore +// TODO(revamp): rename to PostVoteBlame func (c *Client) PostBlameData(blame *blame.Blame, chainID int64, index string) (string, error) { signerAddress := c.keys.GetOperatorAddress().String() zetaBlame := observertypes.Blame{ @@ -212,6 +225,7 @@ func (c *Client) PostBlameData(blame *blame.Blame, chainID int64, index string) return "", fmt.Errorf("post blame data failed after %d retries", DefaultRetryCount) } +// PostVoteBlockHeader posts a vote on an observed block header func (c *Client) PostVoteBlockHeader( chainID int64, blockHash []byte, @@ -280,6 +294,7 @@ func (c *Client) PostVoteInbound(gasLimit, retryGasLimit uint64, msg *types.MsgV // MonitorVoteInboundResult monitors the result of a vote inbound tx // retryGasLimit is the gas limit used to resend the tx if it fails because of insufficient gas // if retryGasLimit is 0, the tx is not resent +// TODO(revamp): move to a monitor file func (c *Client) MonitorVoteInboundResult(zetaTxHash string, retryGasLimit uint64, msg *types.MsgVoteInbound) { var lastErr error @@ -330,6 +345,7 @@ func (c *Client) MonitorVoteInboundResult(zetaTxHash string, retryGasLimit uint6 } // PostVoteOutbound posts a vote on an observed outbound tx +// TODO(revamp): rename and move to a different file func (c *Client) PostVoteOutbound( cctxIndex string, outboundHash string, @@ -372,6 +388,7 @@ func (c *Client) PostVoteOutbound( } // PostVoteOutboundFromMsg posts a vote on an observed outbound tx from a MsgVoteOutbound +// TODO(revamp): rename to PostVoteOutbound func (c *Client) PostVoteOutboundFromMsg( gasLimit, retryGasLimit uint64, msg *types.MsgVoteOutbound, @@ -412,6 +429,7 @@ func (c *Client) PostVoteOutboundFromMsg( // MonitorVoteOutboundResult monitors the result of a vote outbound tx // retryGasLimit is the gas limit used to resend the tx if it fails because of insufficient gas // if retryGasLimit is 0, the tx is not resent +// TODO(revamp): move to a monitor file func (c *Client) MonitorVoteOutboundResult(zetaTxHash string, retryGasLimit uint64, msg *types.MsgVoteOutbound) { var lastErr error From 47d835a51ec509616e84ec1886385bd2b2c42059 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 26 Jun 2024 16:13:52 -0400 Subject: [PATCH 12/23] test: add stateful upgrade test (#2364) --- .github/workflows/execute_advanced_tests.yaml | 90 ++++++++++++++++++- .github/workflows/publish-release.yml | 33 ++++++- Makefile | 49 ++++++---- changelog.md | 1 + cmd/zetacored/parse_genesis.go | 2 +- contrib/localnet/docker-compose-upgrade.yml | 1 + contrib/localnet/docker-compose.yml | 3 + contrib/localnet/scripts/import-data.sh | 2 +- .../scripts/start-upgrade-orchestrator.sh | 2 +- contrib/localnet/scripts/start-zetacored.sh | 4 +- .../zetacored/zetacored_parse-genesis-file.md | 2 +- e2e/txserver/zeta_tx_server.go | 4 +- 12 files changed, 165 insertions(+), 28 deletions(-) mode change 100644 => 100755 contrib/localnet/scripts/import-data.sh diff --git a/.github/workflows/execute_advanced_tests.yaml b/.github/workflows/execute_advanced_tests.yaml index 0af6d13a48..77d6a2b6bd 100644 --- a/.github/workflows/execute_advanced_tests.yaml +++ b/.github/workflows/execute_advanced_tests.yaml @@ -11,6 +11,10 @@ on: type: boolean required: false default: false + e2e-stateful-upgrade-test: + type: boolean + required: false + default: false e2e-performance-test: type: boolean required: false @@ -19,6 +23,10 @@ on: type: boolean required: false default: false + e2e-stateful-data-test: + type: boolean + required: false + default: false debug: type: boolean required: false @@ -63,7 +71,7 @@ jobs: e2e-upgrade-test: if: ${{ github.event.inputs.e2e-upgrade-test == 'true' || github.event_name == 'schedule' }} - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: buildjet-16vcpu-ubuntu-2204 timeout-minutes: 120 steps: - name: "Checkout Code" @@ -92,6 +100,37 @@ jobs: env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_CI_ALERTS }} + e2e-stateful-upgrade-test: + if: ${{ github.event.inputs.e2e-stateful-upgrade-test == 'true' || github.event_name == 'schedule' }} + runs-on: buildjet-16vcpu-ubuntu-2204 + timeout-minutes: 120 + steps: + - name: "Checkout Code" + uses: actions/checkout@v4 + + - name: Start Test + run: make start-upgrade-import-mainnet-test + + - name: Watch Test + run: | + container_id=$(docker ps --filter "ancestor=orchestrator:latest" --format "{{.ID}}") + docker logs -f "${container_id}" & + exit $(docker wait "${container_id}") + + - name: Full Log Dump On Failure + if: failure() + run: | + make stop-localnet + + - name: Notify Slack on Failure + if: failure() && github.event_name == 'schedule' + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,message,commit,author,action,eventName,ref,workflow,job,took + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_CI_ALERTS }} + e2e-upgrade-test-light: if: ${{ github.event.inputs.e2e-upgrade-test-light == 'true' }} runs-on: buildjet-4vcpu-ubuntu-2204 @@ -114,6 +153,15 @@ jobs: run: | make stop-localnet + - name: Notify Slack on Failure + if: failure() && github.event_name == 'schedule' + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,message,commit,author,action,eventName,ref,workflow,job,took + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_CI_ALERTS }} + e2e-performance-test: if: ${{ github.event.inputs.e2e-performance-test == 'true' }} runs-on: buildjet-4vcpu-ubuntu-2204 @@ -135,3 +183,43 @@ jobs: if: failure() run: | make stop-localnet + + - name: Notify Slack on Failure + if: failure() && github.event_name == 'schedule' + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,message,commit,author,action,eventName,ref,workflow,job,took + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_CI_ALERTS }} + + e2e-stateful-data-test: + if: ${{ github.event.inputs.e2e-stateful-data-test == 'true' || github.event_name == 'schedule' }} + runs-on: buildjet-16vcpu-ubuntu-2204 + timeout-minutes: 120 + steps: + - name: "Checkout Code" + uses: actions/checkout@v4 + + - name: Start Test + run: make start-e2e-import-mainnet-test + + - name: Watch Test + run: | + container_id=$(docker ps --filter "ancestor=orchestrator:latest" --format "{{.ID}}") + docker logs -f "${container_id}" & + exit $(docker wait "${container_id}") + + - name: Full Log Dump On Failure + if: failure() + run: | + make stop-localnet + + - name: Notify Slack on Failure + if: failure() && github.event_name == 'schedule' + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,message,commit,author,action,eventName,ref,workflow,job,took + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_CI_ALERTS }} \ No newline at end of file diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 89a4b1f688..7eded17252 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -367,6 +367,8 @@ jobs: shell: bash run: | make start-e2e-admin-test + container_id=$(docker ps --filter "ancestor=orchestrator:latest" --format "{{.ID}}") + docker logs -f "${container_id}" & exit $(docker wait "${container_id}") - name: Mark Job Complete Skipped if: ${{ github.event.inputs.skip_checks == 'true' }} @@ -377,7 +379,7 @@ jobs: e2e-upgrade-test: needs: - check_branch - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: buildjet-16vcpu-ubuntu-2204 timeout-minutes: 120 steps: - name: "Checkout Code" @@ -388,7 +390,33 @@ jobs: if: ${{ github.event.inputs.skip_checks != 'true' }} shell: bash run: | - make start-upgrade-test + make start-upgrade-import-mainnet-test + container_id=$(docker ps --filter "ancestor=orchestrator:latest" --format "{{.ID}}") + docker logs -f "${container_id}" & exit $(docker wait "${container_id}") + + - name: Mark Job Complete Skipped + if: ${{ github.event.inputs.skip_checks == 'true' }} + shell: bash + run: | + echo "continue" + + e2e-stateful-data-test: + needs: + - check_branch + runs-on: buildjet-16vcpu-ubuntu-2204 + timeout-minutes: 120 + steps: + - name: "Checkout Code" + if: ${{ github.event.inputs.skip_checks != 'true' }} + uses: actions/checkout@v3 + + - name: Execute stateful-data-test + if: ${{ github.event.inputs.skip_checks != 'true' }} + shell: bash + run: | + make start-e2e-import-mainnet-test + container_id=$(docker ps --filter "ancestor=orchestrator:latest" --format "{{.ID}}") + docker logs -f "${container_id}" & exit $(docker wait "${container_id}") - name: Mark Job Complete Skipped if: ${{ github.event.inputs.skip_checks == 'true' }} @@ -407,6 +435,7 @@ jobs: - smoke-test - build-test - e2e-admin-tests + - e2e-stateful-data-test - e2e-upgrade-test - check_branch runs-on: ubuntu-22.04 diff --git a/Makefile b/Makefile index 858efad24a..509cb40fd7 100644 --- a/Makefile +++ b/Makefile @@ -204,8 +204,22 @@ mocks: generate: proto-gen openapi specs typescript docs-zetacored mocks fmt .PHONY: generate + ############################################################################### -### E2E tests and localnet ### +### Localnet ### +############################################################################### +start-localnet: zetanode start-localnet-skip-build + +start-localnet-skip-build: + @echo "--> Starting localnet" + export LOCALNET_MODE=setup-only && \ + cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml up -d + +stop-localnet: + cd contrib/localnet/ && $(DOCKER) compose down --remove-orphans + +############################################################################### +### E2E tests ### ############################################################################### zetanode: @@ -233,11 +247,21 @@ start-e2e-performance-test: zetanode export E2E_ARGS="--test-performance" && \ cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml up -d +start-e2e-import-mainnet-test: zetanode + @echo "--> Starting e2e import-data test" + export ZETACORED_IMPORT_GENESIS_DATA=true && \ + export ZETACORED_START_PERIOD=15m && \ + cd contrib/localnet/ && ./scripts/import-data.sh mainnet && $(DOCKER) compose -f docker-compose.yml up -d + start-stress-test: zetanode @echo "--> Starting stress test" cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-stress.yml up -d -#TODO: replace OLD_VERSION with v16 tag once its available +############################################################################### +### Upgrade Tests ### +############################################################################### + + zetanode-upgrade: zetanode @echo "Building zetanode-upgrade" $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime --build-arg OLD_VERSION='release/v17' . @@ -256,22 +280,13 @@ start-upgrade-test-light: zetanode-upgrade export UPGRADE_HEIGHT=90 && \ cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-upgrade.yml up -d -start-localnet: zetanode start-localnet-skip-build - -start-localnet-skip-build: - @echo "--> Starting localnet" - export LOCALNET_MODE=setup-only && \ - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml up -d - -start-e2e-import-mainnet-test: zetanode - @echo "--> Starting e2e import-data test" +start-upgrade-import-mainnet-test: zetanode-upgrade + @echo "--> Starting import-data upgrade test" + export LOCALNET_MODE=upgrade && \ export ZETACORED_IMPORT_GENESIS_DATA=true && \ - export ZETACORED_START_PERIOD=10m && \ - cd contrib/localnet/ && ./scripts/import-data.sh mainnet && $(DOCKER) compose -f docker-compose.yml up -d - -stop-localnet: - cd contrib/localnet/ && $(DOCKER) compose down --remove-orphans - + export ZETACORED_START_PERIOD=15m && \ + export UPGRADE_HEIGHT=225 && \ + cd contrib/localnet/ && ./scripts/import-data.sh mainnet && $(DOCKER) compose -f docker-compose.yml -f docker-compose-upgrade.yml up -d ############################################################################### ### Monitoring ### ############################################################################### diff --git a/changelog.md b/changelog.md index db3d2475f4..1a7d568bd3 100644 --- a/changelog.md +++ b/changelog.md @@ -68,6 +68,7 @@ * [2329](https://github.com/zeta-chain/node/pull/2329) - fix TODOs in rpc unit tests * [2342](https://github.com/zeta-chain/node/pull/2342) - extend rpc unit tests with testing extension to include synthetic ethereum txs * [2299](https://github.com/zeta-chain/node/pull/2299) - add `zetae2e` command to deploy test contracts +* [2364](https://github.com/zeta-chain/node/pull/2364) - add stateful upgrade test * [2360](https://github.com/zeta-chain/node/pull/2360) - add stateful e2e tests. * [2349](https://github.com/zeta-chain/node/pull/2349) - add TestBitcoinDepositRefund and WithdrawBitcoinMultipleTimes E2E tests * [2368](https://github.com/zeta-chain/node/pull/2368) - eliminate panic usage across testing suite diff --git a/cmd/zetacored/parse_genesis.go b/cmd/zetacored/parse_genesis.go index 8f177ee7ef..b671519d11 100644 --- a/cmd/zetacored/parse_genesis.go +++ b/cmd/zetacored/parse_genesis.go @@ -119,7 +119,7 @@ func CmdParseGenesisFile() *cobra.Command { return nil }, } - cmd.PersistentFlags().Bool("modify", false, "Modify the genesis file before importing") + cmd.PersistentFlags().Bool("modify", false, "modify the genesis file before importing") return cmd } diff --git a/contrib/localnet/docker-compose-upgrade.yml b/contrib/localnet/docker-compose-upgrade.yml index c6ae72941a..badd7db8e5 100644 --- a/contrib/localnet/docker-compose-upgrade.yml +++ b/contrib/localnet/docker-compose-upgrade.yml @@ -1,3 +1,4 @@ +version: "3" # This docker-compose redefine the services: # - ZetaChain with 2 nodes (zetacore0, zetacore1) using the upgrade option for cosmovisor # - ZetaChain observer set with 2 clients (zetaclient0, zetaclient1) using the background option diff --git a/contrib/localnet/docker-compose.yml b/contrib/localnet/docker-compose.yml index 1a59202d0d..e73a946c04 100644 --- a/contrib/localnet/docker-compose.yml +++ b/contrib/localnet/docker-compose.yml @@ -18,6 +18,9 @@ services: image: zetanode:latest container_name: rosetta hostname: rosetta + depends_on: + zetacore0: + condition: service_healthy ports: - "8080:8080" networks: diff --git a/contrib/localnet/scripts/import-data.sh b/contrib/localnet/scripts/import-data.sh old mode 100644 new mode 100755 index 5236bfe166..52b18945fd --- a/contrib/localnet/scripts/import-data.sh +++ b/contrib/localnet/scripts/import-data.sh @@ -8,7 +8,7 @@ fi NETWORK=$1 echo "NETWORK: ${NETWORK}" rm -rf ~/.zetacored/genesis_data -mkdir ~/.zetacored/genesis_data +mkdir -p ~/.zetacored/genesis_data echo "Download Latest State Export" LATEST_EXPORT_URL=$(curl https://snapshots.zetachain.com/latest-state-export | jq -r ."${NETWORK}") echo "LATEST EXPORT URL: ${LATEST_EXPORT_URL}" diff --git a/contrib/localnet/scripts/start-upgrade-orchestrator.sh b/contrib/localnet/scripts/start-upgrade-orchestrator.sh index f68009db9a..0bc93b7aec 100755 --- a/contrib/localnet/scripts/start-upgrade-orchestrator.sh +++ b/contrib/localnet/scripts/start-upgrade-orchestrator.sh @@ -63,7 +63,7 @@ cat > upgrade.json < $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json cat $HOME/.zetacored/config/genesis.json | jq '.app_state["evm"]["params"]["evm_denom"]="azeta"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json cat $HOME/.zetacored/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="500000000"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json - cat $HOME/.zetacored/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="100s"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json cat $HOME/.zetacored/config/genesis.json | jq '.app_state["feemarket"]["params"]["min_gas_price"]="10000000000.0000"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json # set governance parameters in new params module for sdk v0.47+ @@ -249,10 +248,13 @@ then scp $NODE:~/.zetacored/config/gentx/* ~/.zetacored/config/gentx/z2gentx/ done +# TODO : USE --modify flag to modify the genesis file when v18 is released if [[ -n "$ZETACORED_IMPORT_GENESIS_DATA" ]]; then echo "Importing data" zetacored parse-genesis-file /root/genesis_data/exported-genesis.json fi +# Update governance voting period to 100s , to ignore the voting period imported from mainnet. + cat $HOME/.zetacored/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="100s"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json # 4. Collect all the gentx files in zetacore0 and create the final genesis.json zetacored collect-gentxs diff --git a/docs/cli/zetacored/zetacored_parse-genesis-file.md b/docs/cli/zetacored/zetacored_parse-genesis-file.md index a7b66ebb73..b67b875d53 100644 --- a/docs/cli/zetacored/zetacored_parse-genesis-file.md +++ b/docs/cli/zetacored/zetacored_parse-genesis-file.md @@ -10,7 +10,7 @@ zetacored parse-genesis-file [import-genesis-file] [optional-genesis-file] [flag ``` -h, --help help for parse-genesis-file - --modify Modify the genesis file before importing + --modify modify the genesis file before importing ``` ### Options inherited from parent commands diff --git a/e2e/txserver/zeta_tx_server.go b/e2e/txserver/zeta_tx_server.go index b6f19a5807..5c4c5e80af 100644 --- a/e2e/txserver/zeta_tx_server.go +++ b/e2e/txserver/zeta_tx_server.go @@ -118,7 +118,7 @@ func NewZetaTxServer(rpcAddr string, names []string, privateKeys []string, chain txFactory: txf, name: names, address: addresses, - blockTimeout: 1 * time.Minute, + blockTimeout: 2 * time.Minute, }, nil } @@ -199,7 +199,6 @@ func (zts ZetaTxServer) BroadcastTx(account string, msg sdktypes.Msg) (*sdktypes if err != nil { return nil, err } - return broadcastWithBlockTimeout(zts, txBytes) } @@ -270,7 +269,6 @@ func (zts ZetaTxServer) EnableHeaderVerification(account string, chainIDList []i addr.String(), chainIDList, )) - return err } From 98c63b92cd3ef20d90afdb8093a7b24adb84ad03 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Thu, 27 Jun 2024 09:39:17 -0700 Subject: [PATCH 13/23] refactor(e2e): move addresses and private keys to config (#2308) * refactor(e2e): move all addresses and private keys to config * localnet config and inject into orchestrator * zetacored from config * generate keys in init * fmt * docs * more lint fixes * s/deployer/default_account/ * trim prefix --- Dockerfile-localnet | 3 +- cmd/zetae2e/README.md | 8 +- cmd/zetae2e/balances.go | 12 +- cmd/zetae2e/bitcoin_address.go | 12 +- cmd/zetae2e/config/clients.go | 17 +- cmd/zetae2e/config/config.go | 42 ++-- cmd/zetae2e/config/config_test.go | 40 +++ cmd/zetae2e/config/contracts.go | 125 +++++----- cmd/zetae2e/config/example.yml | 4 +- cmd/zetae2e/config/local.yml | 5 +- cmd/zetae2e/config/localnet.yml | 51 ++++ cmd/zetae2e/init.go | 13 +- cmd/zetae2e/local/accounts.go | 44 ---- cmd/zetae2e/local/admin.go | 8 +- cmd/zetae2e/local/bitcoin.go | 6 +- cmd/zetae2e/local/config.go | 8 +- cmd/zetae2e/local/erc20.go | 6 +- cmd/zetae2e/local/ethereum.go | 3 +- cmd/zetae2e/local/local.go | 5 +- cmd/zetae2e/local/misc.go | 6 +- cmd/zetae2e/local/performance.go | 6 +- cmd/zetae2e/local/test_runner.go | 8 +- cmd/zetae2e/local/zeta.go | 6 +- cmd/zetae2e/local/zevm_mp.go | 6 +- cmd/zetae2e/run.go | 10 +- cmd/zetae2e/setup_bitcoin.go | 11 +- cmd/zetae2e/show_tss.go | 12 +- cmd/zetae2e/stress.go | 32 +-- .../orchestrator/Dockerfile.fastbuild | 3 +- .../localnet/orchestrator/start-zetae2e.sh | 50 ++-- contrib/localnet/scripts/start-zetacored.sh | 27 +- e2e/config/config.go | 230 ++++++++++++++++-- e2e/config/config_test.go | 39 +++ e2e/e2etests/test_context_upgrade.go | 2 +- e2e/e2etests/test_crosschain_swap.go | 8 +- e2e/e2etests/test_erc20_deposit.go | 2 +- e2e/e2etests/test_erc20_deposit_refund.go | 16 +- e2e/e2etests/test_erc20_multiple_deposits.go | 6 +- e2e/e2etests/test_erc20_multiple_withdraws.go | 4 +- e2e/e2etests/test_eth_deposit_call.go | 7 +- .../test_eth_deposit_liquidity_cap.go | 8 +- e2e/e2etests/test_eth_deposit_refund.go | 7 +- .../test_message_passing_external_chains.go | 2 +- ...age_passing_external_chains_revert_fail.go | 2 +- e2e/e2etests/test_migrate_chain_support.go | 19 +- e2e/e2etests/test_rate_limiter.go | 2 +- e2e/e2etests/test_stress_eth_withdraw.go | 2 +- e2e/e2etests/test_update_bytecode_zrc20.go | 8 +- e2e/e2etests/test_zeta_deposit.go | 2 +- .../test_zeta_withdraw_bitcoin_revert.go | 2 +- e2e/e2etests/test_zrc20_swap.go | 8 +- e2e/runner/balances.go | 18 +- e2e/runner/bitcoin.go | 4 +- e2e/runner/evm.go | 7 +- e2e/runner/runner.go | 15 +- e2e/runner/setup_bitcoin.go | 4 +- e2e/runner/setup_evm.go | 18 +- e2e/runner/zeta.go | 8 +- 58 files changed, 631 insertions(+), 408 deletions(-) create mode 100644 cmd/zetae2e/config/config_test.go create mode 100644 cmd/zetae2e/config/localnet.yml delete mode 100644 cmd/zetae2e/local/accounts.go create mode 100644 e2e/config/config_test.go diff --git a/Dockerfile-localnet b/Dockerfile-localnet index bacf8c19a4..1ed82c6b98 100644 --- a/Dockerfile-localnet +++ b/Dockerfile-localnet @@ -28,7 +28,7 @@ RUN go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@v1.5.0 FROM golang:1.20.14-bookworm AS base-runtime RUN apt update && \ - apt install -yq jq curl tmux python3 openssh-server iputils-ping iproute2 && \ + apt install -yq jq yq curl tmux python3 openssh-server iputils-ping iproute2 && \ rm -rf /var/lib/apt/lists/* RUN ssh-keygen -A && \ @@ -46,6 +46,7 @@ ENV PATH /root/.zetacored/cosmovisor/current/bin/:/root/.zetaclientd/upgrades/cu COPY contrib/localnet/scripts /root COPY contrib/localnet/ssh_config /etc/ssh/ssh_config.d/localnet.conf COPY contrib/localnet/zetacored /root/zetacored +COPY cmd/zetae2e/config/localnet.yml /root/config.yml RUN chmod 755 /root/*.sh && \ chmod 644 /etc/ssh/ssh_config.d/localnet.conf diff --git a/cmd/zetae2e/README.md b/cmd/zetae2e/README.md index c57863e7cf..bdc043f7d2 100644 --- a/cmd/zetae2e/README.md +++ b/cmd/zetae2e/README.md @@ -24,9 +24,9 @@ This is an example of config for interaction with Athens3: ```go zeta_chain_id: "athens_7001-1" -accounts: +default_account: evm_address: "" - evm_priv_key: "" + private_key: "" rpcs: zevm: ", generally using port 8545" evm: ", generally using port 8545" @@ -101,9 +101,9 @@ Testing a gas token requires the following values to be defined in the config: ```go zeta_chain_id -accounts: +default_account: evm_address - evm_priv_key + private_key rpcs: zevm evm diff --git a/cmd/zetae2e/balances.go b/cmd/zetae2e/balances.go index bf1b543227..13df89430a 100644 --- a/cmd/zetae2e/balances.go +++ b/cmd/zetae2e/balances.go @@ -2,9 +2,7 @@ package main import ( "context" - "errors" - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/fatih/color" "github.com/spf13/cobra" @@ -54,21 +52,13 @@ func runBalances(cmd *cobra.Command, args []string) error { // initialize context ctx, cancel := context.WithCancel(context.Background()) - // get EVM address from config - evmAddr := conf.Accounts.EVMAddress - if !ethcommon.IsHexAddress(evmAddr) { - cancel() - return errors.New("invalid EVM address") - } - // initialize deployer runner with config r, err := zetae2econfig.RunnerFromConfig( ctx, "e2e", cancel, conf, - ethcommon.HexToAddress(evmAddr), - conf.Accounts.EVMPrivKey, + conf.DefaultAccount, logger, ) if err != nil { diff --git a/cmd/zetae2e/bitcoin_address.go b/cmd/zetae2e/bitcoin_address.go index 63eb26d386..6c9c5c3f4a 100644 --- a/cmd/zetae2e/bitcoin_address.go +++ b/cmd/zetae2e/bitcoin_address.go @@ -2,9 +2,7 @@ package main import ( "context" - "errors" - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/fatih/color" "github.com/spf13/cobra" @@ -54,21 +52,13 @@ func runBitcoinAddress(cmd *cobra.Command, args []string) error { // initialize context ctx, cancel := context.WithCancel(context.Background()) - // get EVM address from config - evmAddr := conf.Accounts.EVMAddress - if !ethcommon.IsHexAddress(evmAddr) { - cancel() - return errors.New("invalid EVM address") - } - // initialize deployer runner with config r, err := zetae2econfig.RunnerFromConfig( ctx, "e2e", cancel, conf, - ethcommon.HexToAddress(evmAddr), - conf.Accounts.EVMPrivKey, + conf.DefaultAccount, logger, ) if err != nil { diff --git a/cmd/zetae2e/config/clients.go b/cmd/zetae2e/config/clients.go index ae56eaa9dd..8c6bb37106 100644 --- a/cmd/zetae2e/config/clients.go +++ b/cmd/zetae2e/config/clients.go @@ -8,7 +8,6 @@ import ( 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/crypto" "github.com/ethereum/go-ethereum/ethclient" "google.golang.org/grpc" @@ -20,7 +19,7 @@ import ( ) // getClientsFromConfig get clients from config -func getClientsFromConfig(ctx context.Context, conf config.Config, evmPrivKey string) ( +func getClientsFromConfig(ctx context.Context, conf config.Config, account config.Account) ( *rpcclient.Client, *ethclient.Client, *bind.TransactOpts, @@ -38,7 +37,7 @@ func getClientsFromConfig(ctx context.Context, conf config.Config, evmPrivKey st if err != nil { return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("failed to get btc client: %w", err) } - evmClient, evmAuth, err := getEVMClient(ctx, conf.RPCs.EVM, evmPrivKey) + evmClient, evmAuth, err := getEVMClient(ctx, conf.RPCs.EVM, account) if err != nil { return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("failed to get evm client: %w", err) } @@ -48,7 +47,7 @@ func getClientsFromConfig(ctx context.Context, conf config.Config, evmPrivKey st if err != nil { return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("failed to get zeta clients: %w", err) } - zevmClient, zevmAuth, err := getEVMClient(ctx, conf.RPCs.Zevm, evmPrivKey) + zevmClient, zevmAuth, err := getEVMClient(ctx, conf.RPCs.Zevm, account) if err != nil { return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("failed to get zevm client: %w", err) } @@ -91,7 +90,11 @@ func getBtcClient(rpcConf config.BitcoinRPC) (*rpcclient.Client, error) { } // getEVMClient get evm client -func getEVMClient(ctx context.Context, rpc, privKey string) (*ethclient.Client, *bind.TransactOpts, error) { +func getEVMClient( + ctx context.Context, + rpc string, + account config.Account, +) (*ethclient.Client, *bind.TransactOpts, error) { evmClient, err := ethclient.Dial(rpc) if err != nil { return nil, nil, fmt.Errorf("failed to dial evm client: %w", err) @@ -101,11 +104,11 @@ func getEVMClient(ctx context.Context, rpc, privKey string) (*ethclient.Client, if err != nil { return nil, nil, fmt.Errorf("failed to get chain id: %w", err) } - deployerPrivkey, err := crypto.HexToECDSA(privKey) + privKey, err := account.PrivateKey() if err != nil { return nil, nil, fmt.Errorf("failed to get deployer privkey: %w", err) } - evmAuth, err := bind.NewKeyedTransactorWithChainID(deployerPrivkey, chainid) + evmAuth, err := bind.NewKeyedTransactorWithChainID(privKey, chainid) if err != nil { return nil, nil, fmt.Errorf("failed to get keyed transactor: %w", err) } diff --git a/cmd/zetae2e/config/config.go b/cmd/zetae2e/config/config.go index 7918a9a9ae..a0aedef1a6 100644 --- a/cmd/zetae2e/config/config.go +++ b/cmd/zetae2e/config/config.go @@ -4,8 +4,6 @@ import ( "context" "fmt" - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/zeta-chain/zetacore/e2e/config" "github.com/zeta-chain/zetacore/e2e/runner" ) @@ -16,8 +14,7 @@ func RunnerFromConfig( name string, ctxCancel context.CancelFunc, conf config.Config, - evmUserAddr ethcommon.Address, - evmUserPrivKey string, + account config.Account, logger *runner.Logger, opts ...runner.E2ERunnerOption, ) (*runner.E2ERunner, error) { @@ -33,7 +30,7 @@ func RunnerFromConfig( lightClient, zevmClient, zevmAuth, - err := getClientsFromConfig(ctx, conf, evmUserPrivKey) + err := getClientsFromConfig(ctx, conf, account) if err != nil { return nil, fmt.Errorf("failed to get clients from config: %w", err) } @@ -43,8 +40,7 @@ func RunnerFromConfig( ctx, name, ctxCancel, - evmUserAddr, - evmUserPrivKey, + account, evmClient, zevmClient, cctxClient, @@ -79,23 +75,23 @@ func RunnerFromConfig( // ExportContractsFromRunner export contracts from the runner to config using a source config func ExportContractsFromRunner(r *runner.E2ERunner, conf config.Config) config.Config { // copy contracts from deployer runner - conf.Contracts.EVM.ZetaEthAddress = r.ZetaEthAddr.Hex() - conf.Contracts.EVM.ConnectorEthAddr = r.ConnectorEthAddr.Hex() - conf.Contracts.EVM.CustodyAddr = r.ERC20CustodyAddr.Hex() - conf.Contracts.EVM.ERC20 = r.ERC20Addr.Hex() - conf.Contracts.EVM.TestDappAddr = r.EvmTestDAppAddr.Hex() + conf.Contracts.EVM.ZetaEthAddr = config.DoubleQuotedString(r.ZetaEthAddr.Hex()) + conf.Contracts.EVM.ConnectorEthAddr = config.DoubleQuotedString(r.ConnectorEthAddr.Hex()) + conf.Contracts.EVM.CustodyAddr = config.DoubleQuotedString(r.ERC20CustodyAddr.Hex()) + conf.Contracts.EVM.ERC20 = config.DoubleQuotedString(r.ERC20Addr.Hex()) + conf.Contracts.EVM.TestDappAddr = config.DoubleQuotedString(r.EvmTestDAppAddr.Hex()) - conf.Contracts.ZEVM.SystemContractAddr = r.SystemContractAddr.Hex() - conf.Contracts.ZEVM.ETHZRC20Addr = r.ETHZRC20Addr.Hex() - conf.Contracts.ZEVM.ERC20ZRC20Addr = r.ERC20ZRC20Addr.Hex() - conf.Contracts.ZEVM.BTCZRC20Addr = r.BTCZRC20Addr.Hex() - conf.Contracts.ZEVM.UniswapFactoryAddr = r.UniswapV2FactoryAddr.Hex() - conf.Contracts.ZEVM.UniswapRouterAddr = r.UniswapV2RouterAddr.Hex() - conf.Contracts.ZEVM.ConnectorZEVMAddr = r.ConnectorZEVMAddr.Hex() - conf.Contracts.ZEVM.WZetaAddr = r.WZetaAddr.Hex() - conf.Contracts.ZEVM.ZEVMSwapAppAddr = r.ZEVMSwapAppAddr.Hex() - conf.Contracts.ZEVM.ContextAppAddr = r.ContextAppAddr.Hex() - conf.Contracts.ZEVM.TestDappAddr = r.ZevmTestDAppAddr.Hex() + conf.Contracts.ZEVM.SystemContractAddr = config.DoubleQuotedString(r.SystemContractAddr.Hex()) + conf.Contracts.ZEVM.ETHZRC20Addr = config.DoubleQuotedString(r.ETHZRC20Addr.Hex()) + conf.Contracts.ZEVM.ERC20ZRC20Addr = config.DoubleQuotedString(r.ERC20ZRC20Addr.Hex()) + conf.Contracts.ZEVM.BTCZRC20Addr = config.DoubleQuotedString(r.BTCZRC20Addr.Hex()) + conf.Contracts.ZEVM.UniswapFactoryAddr = config.DoubleQuotedString(r.UniswapV2FactoryAddr.Hex()) + conf.Contracts.ZEVM.UniswapRouterAddr = config.DoubleQuotedString(r.UniswapV2RouterAddr.Hex()) + conf.Contracts.ZEVM.ConnectorZEVMAddr = config.DoubleQuotedString(r.ConnectorZEVMAddr.Hex()) + conf.Contracts.ZEVM.WZetaAddr = config.DoubleQuotedString(r.WZetaAddr.Hex()) + conf.Contracts.ZEVM.ZEVMSwapAppAddr = config.DoubleQuotedString(r.ZEVMSwapAppAddr.Hex()) + conf.Contracts.ZEVM.ContextAppAddr = config.DoubleQuotedString(r.ContextAppAddr.Hex()) + conf.Contracts.ZEVM.TestDappAddr = config.DoubleQuotedString(r.ZevmTestDAppAddr.Hex()) return conf } diff --git a/cmd/zetae2e/config/config_test.go b/cmd/zetae2e/config/config_test.go new file mode 100644 index 0000000000..f8eb98a01e --- /dev/null +++ b/cmd/zetae2e/config/config_test.go @@ -0,0 +1,40 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/zeta-chain/zetacore/e2e/config" +) + +func TestReadConfig(t *testing.T) { + tests := []struct { + name string + filePath string + expectNoError bool + expectNotEmpty bool + }{ + { + name: "ReadLocalnetConfig", + filePath: "localnet.yml", + expectNoError: true, + expectNotEmpty: true, + }, + { + name: "ReadLocalConfig", + filePath: "local.yml", + expectNoError: true, + expectNotEmpty: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + conf, err := config.ReadConfig(tt.filePath) + require.NoError(t, err) + require.NotEmpty(t, conf.DefaultAccount.RawEVMAddress) + require.NotEmpty(t, conf.DefaultAccount.RawPrivateKey) + }) + } +} diff --git a/cmd/zetae2e/config/contracts.go b/cmd/zetae2e/config/contracts.go index a47b39ef4e..110038298a 100644 --- a/cmd/zetae2e/config/contracts.go +++ b/cmd/zetae2e/config/contracts.go @@ -3,7 +3,6 @@ package config import ( "fmt" - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol" zetaeth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zeta.eth.sol" zetaconnectoreth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.eth.sol" @@ -26,169 +25,173 @@ func setContractsFromConfig(r *runner.E2ERunner, conf config.Config) error { var err error // set EVM contracts - if c := conf.Contracts.EVM.ZetaEthAddress; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ZetaEthAddress: %s", c) + if c := conf.Contracts.EVM.ZetaEthAddr; c != "" { + r.ZetaEthAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid ZetaEthAddr: %w", err) } - r.ZetaEthAddr = ethcommon.HexToAddress(c) r.ZetaEth, err = zetaeth.NewZetaEth(r.ZetaEthAddr, r.EVMClient) if err != nil { return err } } + if c := conf.Contracts.EVM.ConnectorEthAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ConnectorEthAddr: %s", c) + r.ConnectorEthAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid ConnectorEthAddr: %w", err) } - r.ConnectorEthAddr = ethcommon.HexToAddress(c) r.ConnectorEth, err = zetaconnectoreth.NewZetaConnectorEth(r.ConnectorEthAddr, r.EVMClient) if err != nil { return err } } + if c := conf.Contracts.EVM.CustodyAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid CustodyAddr: %s", c) + r.ERC20CustodyAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid CustodyAddr: %w", err) } - r.ERC20CustodyAddr = ethcommon.HexToAddress(c) r.ERC20Custody, err = erc20custody.NewERC20Custody(r.ERC20CustodyAddr, r.EVMClient) if err != nil { return err } } + if c := conf.Contracts.EVM.ERC20; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ERC20: %s", c) + r.ERC20Addr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid ERC20: %w", err) } - r.ERC20Addr = ethcommon.HexToAddress(c) r.ERC20, err = erc20.NewERC20(r.ERC20Addr, r.EVMClient) if err != nil { return err } } - // set Zevm contracts + // set ZEVM contracts if c := conf.Contracts.ZEVM.SystemContractAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid SystemContractAddr: %s", c) + r.SystemContractAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid SystemContractAddr: %w", err) } - r.SystemContractAddr = ethcommon.HexToAddress(c) r.SystemContract, err = systemcontract.NewSystemContract(r.SystemContractAddr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.ETHZRC20Addr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ETHZRC20Addr: %s", c) + r.ETHZRC20Addr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid ETHZRC20Addr: %w", err) } - r.ETHZRC20Addr = ethcommon.HexToAddress(c) r.ETHZRC20, err = zrc20.NewZRC20(r.ETHZRC20Addr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.ERC20ZRC20Addr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ERC20ZRC20Addr: %s", c) + r.ERC20ZRC20Addr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid ERC20ZRC20Addr: %w", err) } - r.ERC20ZRC20Addr = ethcommon.HexToAddress(c) r.ERC20ZRC20, err = zrc20.NewZRC20(r.ERC20ZRC20Addr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.BTCZRC20Addr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid BTCZRC20Addr: %s", c) - } - r.BTCZRC20Addr = ethcommon.HexToAddress(c) - r.BTCZRC20, err = zrc20.NewZRC20(r.BTCZRC20Addr, r.ZEVMClient) + r.BTCZRC20Addr, err = c.AsEVMAddress() if err != nil { - return err - } - } - if c := conf.Contracts.ZEVM.ERC20ZRC20Addr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ERC20ZRC20Addr: %s", c) + return fmt.Errorf("invalid BTCZRC20Addr: %w", err) } - r.ERC20ZRC20Addr = ethcommon.HexToAddress(c) - r.ERC20ZRC20, err = zrc20.NewZRC20(r.ERC20ZRC20Addr, r.ZEVMClient) + r.BTCZRC20, err = zrc20.NewZRC20(r.BTCZRC20Addr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.UniswapFactoryAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid UniswapFactoryAddr: %s", c) + r.UniswapV2FactoryAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid UniswapFactoryAddr: %w", err) } - r.UniswapV2FactoryAddr = ethcommon.HexToAddress(c) r.UniswapV2Factory, err = uniswapv2factory.NewUniswapV2Factory(r.UniswapV2FactoryAddr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.UniswapRouterAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid UniswapRouterAddr: %s", c) + r.UniswapV2RouterAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid UniswapRouterAddr: %w", err) } - r.UniswapV2RouterAddr = ethcommon.HexToAddress(c) r.UniswapV2Router, err = uniswapv2router.NewUniswapV2Router02(r.UniswapV2RouterAddr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.ConnectorZEVMAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ConnectorZEVMAddr: %s", c) + r.ConnectorZEVMAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid ConnectorZEVMAddr: %w", err) } - r.ConnectorZEVMAddr = ethcommon.HexToAddress(c) r.ConnectorZEVM, err = connectorzevm.NewZetaConnectorZEVM(r.ConnectorZEVMAddr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.WZetaAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid WZetaAddr: %s", c) + r.WZetaAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid WZetaAddr: %w", err) } - r.WZetaAddr = ethcommon.HexToAddress(c) r.WZeta, err = wzeta.NewWETH9(r.WZetaAddr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.ZEVMSwapAppAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ZEVMSwapAppAddr: %s", c) + r.ZEVMSwapAppAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid ZEVMSwapAppAddr: %w", err) } - r.ZEVMSwapAppAddr = ethcommon.HexToAddress(c) r.ZEVMSwapApp, err = zevmswap.NewZEVMSwapApp(r.ZEVMSwapAppAddr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.ContextAppAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ContextAppAddr: %s", c) + r.ContextAppAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid ContextAppAddr: %w", err) } - r.ContextAppAddr = ethcommon.HexToAddress(c) r.ContextApp, err = contextapp.NewContextApp(r.ContextAppAddr, r.ZEVMClient) if err != nil { return err } } + if c := conf.Contracts.ZEVM.TestDappAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid ZevmTestDappAddr: %s", c) + r.ZevmTestDAppAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid ZevmTestDappAddr: %w", err) } - r.ZevmTestDAppAddr = ethcommon.HexToAddress(c) } + if c := conf.Contracts.EVM.TestDappAddr; c != "" { - if !ethcommon.IsHexAddress(c) { - return fmt.Errorf("invalid EvmTestDappAddr: %s", c) + r.EvmTestDAppAddr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid EvmTestDappAddr: %w", err) } - r.EvmTestDAppAddr = ethcommon.HexToAddress(c) } return nil diff --git a/cmd/zetae2e/config/example.yml b/cmd/zetae2e/config/example.yml index be692b9d4c..21cdd6de36 100644 --- a/cmd/zetae2e/config/example.yml +++ b/cmd/zetae2e/config/example.yml @@ -1,7 +1,7 @@ zeta_chain_id: "athens_7001-1" -accounts: +default_account: evm_address: "" - evm_priv_key: "" + private_key: "" rpcs: zevm: ", generally using port 8545" evm: ", generally using port 8545" diff --git a/cmd/zetae2e/config/local.yml b/cmd/zetae2e/config/local.yml index ae2638ace7..ee5e171ccc 100644 --- a/cmd/zetae2e/config/local.yml +++ b/cmd/zetae2e/config/local.yml @@ -1,7 +1,8 @@ zeta_chain_id: "athens_7001-1" -accounts: +default_account: + bech32_address: zeta1uhznv7uzyjq84s3q056suc8pkme85lkvhrz3dd evm_address: "0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC" - evm_priv_key: "d87baf7bf6dc560a252596678c12e41f7d1682837f05b29d411bc3f78ae2c263" + private_key: "d87baf7bf6dc560a252596678c12e41f7d1682837f05b29d411bc3f78ae2c263" rpcs: zevm: "http://0.0.0.0:9545" evm: "http://0.0.0.0:8545" diff --git a/cmd/zetae2e/config/localnet.yml b/cmd/zetae2e/config/localnet.yml new file mode 100644 index 0000000000..abb780db39 --- /dev/null +++ b/cmd/zetae2e/config/localnet.yml @@ -0,0 +1,51 @@ +zeta_chain_id: "athens_101-1" +default_account: + bech32_address: "zeta1uhznv7uzyjq84s3q056suc8pkme85lkvhrz3dd" + evm_address: "0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC" + private_key: "d87baf7bf6dc560a252596678c12e41f7d1682837f05b29d411bc3f78ae2c263" +additional_accounts: + user_erc20: + bech32_address: "zeta1datate7xmwm4uk032f9rmcu0cwy7ch7kg6y6zv" + evm_address: "0x6F57D5E7c6DBb75e59F1524a3dE38Fc389ec5Fd6" + private_key: "fda3be1b1517bdf48615bdadacc1e6463d2865868dc8077d2cdcfa4709a16894" + user_zeta_test: + bech32_address: "zeta1tnp0hvsq4y5mxuhrq9h3jfwulxywpq0ads0rer" + evm_address: "0x5cC2fBb200A929B372e3016F1925DcF988E081fd" + private_key: "729a6cdc5c925242e7df92fdeeb94dadbf2d0b9950d4db8f034ab27a3b114ba7" + user_zevm_mp_test: + bech32_address: "zeta13t3zjxvwec7g38q8mdjga37rpes9zkfvv7tkn2" + evm_address: "0x8Ae229198eCE3c889C07DB648Ec7C30E6051592c" + private_key: "105460aebf71b10bfdb710ef5aa6d2932ee6ff6fc317ac9c24e0979903b10a5d" + user_bitcoin: + bech32_address: "zeta19q7czqysah6qg0n4y3l2a08gfzqxydla492v80" + evm_address: "0x283d810090EdF4043E75247eAeBcE848806237fD" + private_key: "7bb523963ee2c78570fb6113d886a4184d42565e8847f1cb639f5f5e2ef5b37a" + user_ether: + bech32_address: "zeta134rakuus43xn63yucgxhn88ywj8ewcv6ezn2ga" + evm_address: "0x8D47Db7390AC4D3D449Cc20D799ce4748F97619A" + private_key: "098e74a1c2261fa3c1b8cfca8ef2b4ff96c73ce36710d208d1f6535aef42545d" + user_misc: + bech32_address: "zeta1jqfx6qhyrj0t9ggvl3p64vaax3s9y0xldt020w" + evm_address: "0x90126d02E41c9eB2a10cfc43aAb3BD3460523Cdf" + private_key: "853c0945b8035a501b1161df65a17a0a20fc848bda8975a8b4e9222cc6f84cd4" + user_admin: + bech32_address: "zeta17w0adeg64ky0daxwd2ugyuneellmjgnx4e483s" + evm_address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + private_key: "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + user_fungible_admin: + bech32_address: "zeta1svzuz982w09vf2y08xsh8qplj36phyz466krj3" + evm_address: "0x8305C114Ea73cAc4A88f39A173803F94741b9055" + private_key: "d88d09a7d6849c15a36eb6931f9dd616091a63e9849a2cc86f309ba11fb8fec5" +rpcs: + zevm: "http://zetacore0:8545" + evm: "http://eth:8545" + bitcoin: + host: "bitcoin:18443" + user: "smoketest" + pass: "123" + http_post_mode: true + disable_tls: true + params: regnet + zetacore_grpc: "zetacore0:9090" + zetacore_rpc: "http://zetacore0:26657" +# contracts will be populated on first run \ No newline at end of file diff --git a/cmd/zetae2e/init.go b/cmd/zetae2e/init.go index b35f42ff97..742b3ebd96 100644 --- a/cmd/zetae2e/init.go +++ b/cmd/zetae2e/init.go @@ -16,7 +16,7 @@ func NewInitCmd() *cobra.Command { var InitCmd = &cobra.Command{ Use: "init", Short: "initialize config file for e2e tests", - Run: initConfig, + RunE: initConfig, } InitCmd.Flags().StringVar(&initConf.RPCs.EVM, "ethURL", "http://eth:8545", "--ethURL http://eth:8545") @@ -33,9 +33,14 @@ func NewInitCmd() *cobra.Command { return InitCmd } -func initConfig(_ *cobra.Command, _ []string) { - err := config.WriteConfig(configFile, initConf) +func initConfig(_ *cobra.Command, _ []string) error { + err := initConf.GenerateKeys() if err != nil { - fmt.Printf("error writing config file: %s", err.Error()) + return fmt.Errorf("generating keys: %w", err) } + err = config.WriteConfig(configFile, initConf) + if err != nil { + return fmt.Errorf("writing config: %w", err) + } + return nil } diff --git a/cmd/zetae2e/local/accounts.go b/cmd/zetae2e/local/accounts.go deleted file mode 100644 index 16ab7d97a4..0000000000 --- a/cmd/zetae2e/local/accounts.go +++ /dev/null @@ -1,44 +0,0 @@ -package local - -import ( - ethcommon "github.com/ethereum/go-ethereum/common" -) - -var ( - // DeployerAddress is the address of the account for deploying networks - DeployerAddress = ethcommon.HexToAddress("0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC") - DeployerPrivateKey = "d87baf7bf6dc560a252596678c12e41f7d1682837f05b29d411bc3f78ae2c263" // #nosec G101 - used for testing - - // UserERC20Address is the address of the account for testing ERC20 - UserERC20Address = ethcommon.HexToAddress("0x6F57D5E7c6DBb75e59F1524a3dE38Fc389ec5Fd6") - UserERC20PrivateKey = "fda3be1b1517bdf48615bdadacc1e6463d2865868dc8077d2cdcfa4709a16894" // #nosec G101 - used for testing - - // UserZetaTestAddress is the address of the account for testing Zeta transfers - UserZetaTestAddress = ethcommon.HexToAddress("0x5cC2fBb200A929B372e3016F1925DcF988E081fd") - UserZetaTestPrivateKey = "729a6cdc5c925242e7df92fdeeb94dadbf2d0b9950d4db8f034ab27a3b114ba7" // #nosec G101 - used for testing - - // UserZEVMMPTestAddress is the address of the account for testing ZEVM Message Passing - UserZEVMMPTestAddress = ethcommon.HexToAddress("0x8Ae229198eCE3c889C07DB648Ec7C30E6051592c") - UserZEVMMPTestPrivateKey = "105460aebf71b10bfdb710ef5aa6d2932ee6ff6fc317ac9c24e0979903b10a5d" // #nosec G101 - used for testing - - // UserBitcoinAddress is the address of the account for testing Bitcoin - UserBitcoinAddress = ethcommon.HexToAddress("0x283d810090EdF4043E75247eAeBcE848806237fD") - UserBitcoinPrivateKey = "7bb523963ee2c78570fb6113d886a4184d42565e8847f1cb639f5f5e2ef5b37a" // #nosec G101 - used for testing - - // UserEtherAddress is the address of the account for testing Ether - UserEtherAddress = ethcommon.HexToAddress("0x8D47Db7390AC4D3D449Cc20D799ce4748F97619A") - UserEtherPrivateKey = "098e74a1c2261fa3c1b8cfca8ef2b4ff96c73ce36710d208d1f6535aef42545d" // #nosec G101 - used for testing - - // UserMiscAddress is the address of the account for miscellaneous tests - UserMiscAddress = ethcommon.HexToAddress("0x90126d02E41c9eB2a10cfc43aAb3BD3460523Cdf") - UserMiscPrivateKey = "853c0945b8035a501b1161df65a17a0a20fc848bda8975a8b4e9222cc6f84cd4" // #nosec G101 - used for testing - - // UserAdminAddress is the address of the account for testing admin function features - // NOTE: this is the default account using Anvil - UserAdminAddress = ethcommon.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") - UserAdminPrivateKey = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" // #nosec G101 - used for testing - - // FungibleAdminAddress is the address of the account for testing the fungible admin functions - UserFungibleAdminAddress = ethcommon.HexToAddress("0x8305C114Ea73cAc4A88f39A173803F94741b9055") - UserFungibleAdminPrivateKey = "d88d09a7d6849c15a36eb6931f9dd616091a63e9849a2cc86f309ba11fb8fec5" // #nosec G101 - used for testing -) diff --git a/cmd/zetae2e/local/admin.go b/cmd/zetae2e/local/admin.go index 63cff6fe23..bc76aeeedc 100644 --- a/cmd/zetae2e/local/admin.go +++ b/cmd/zetae2e/local/admin.go @@ -19,13 +19,13 @@ func adminTestRoutine( testNames ...string, ) func() error { return func() (err error) { + account := conf.AdditionalAccounts.UserAdmin // initialize runner for erc20 advanced test adminRunner, err := initTestRunner( "admin", conf, deployerRunner, - UserAdminAddress, - UserAdminPrivateKey, + account, runner.NewLogger(verbose, color.FgHiGreen, "admin"), runner.WithZetaTxServer(deployerRunner.ZetaTxServer), ) @@ -38,8 +38,8 @@ func adminTestRoutine( // funding the account // we transfer around the total supply of Zeta to the admin for the chain migration test - txZetaSend := deployerRunner.SendZetaOnEvm(UserAdminAddress, 20_500_000_000) - txERC20Send := deployerRunner.SendERC20OnEvm(UserAdminAddress, 1000) + txZetaSend := deployerRunner.SendZetaOnEvm(account.EVMAddress(), 20_500_000_000) + txERC20Send := deployerRunner.SendERC20OnEvm(account.EVMAddress(), 1000) adminRunner.WaitForTxReceiptOnEvm(txZetaSend) adminRunner.WaitForTxReceiptOnEvm(txERC20Send) diff --git a/cmd/zetae2e/local/bitcoin.go b/cmd/zetae2e/local/bitcoin.go index cfb0501a8c..05098fd5a9 100644 --- a/cmd/zetae2e/local/bitcoin.go +++ b/cmd/zetae2e/local/bitcoin.go @@ -21,13 +21,13 @@ func bitcoinTestRoutine( testNames ...string, ) func() error { return func() (err error) { + account := conf.AdditionalAccounts.UserBitcoin // initialize runner for bitcoin test bitcoinRunner, err := initTestRunner( "bitcoin", conf, deployerRunner, - UserBitcoinAddress, - UserBitcoinPrivateKey, + account, runner.NewLogger(verbose, color.FgYellow, "bitcoin"), ) if err != nil { @@ -38,7 +38,7 @@ func bitcoinTestRoutine( startTime := time.Now() // funding the account - txERC20Send := deployerRunner.SendERC20OnEvm(UserBitcoinAddress, 1000) + txERC20Send := deployerRunner.SendERC20OnEvm(account.EVMAddress(), 1000) bitcoinRunner.WaitForTxReceiptOnEvm(txERC20Send) // depositing the necessary tokens on ZetaChain diff --git a/cmd/zetae2e/local/config.go b/cmd/zetae2e/local/config.go index 98ece83ac0..8788024b7d 100644 --- a/cmd/zetae2e/local/config.go +++ b/cmd/zetae2e/local/config.go @@ -1,6 +1,7 @@ package local import ( + "fmt" "path/filepath" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,12 +15,7 @@ import ( func GetConfig(cmd *cobra.Command) (config.Config, error) { configFile, err := cmd.Flags().GetString(FlagConfigFile) if err != nil { - return config.Config{}, err - } - - // use default config if no config file is specified - if configFile == "" { - return config.DefaultConfig(), nil + return config.Config{}, fmt.Errorf("--config is a required parameter") } configFile, err = filepath.Abs(configFile) diff --git a/cmd/zetae2e/local/erc20.go b/cmd/zetae2e/local/erc20.go index fe0fa8bb8a..8b0d21e564 100644 --- a/cmd/zetae2e/local/erc20.go +++ b/cmd/zetae2e/local/erc20.go @@ -19,13 +19,13 @@ func erc20TestRoutine( testNames ...string, ) func() error { return func() (err error) { + account := conf.AdditionalAccounts.UserERC20 // initialize runner for erc20 test erc20Runner, err := initTestRunner( "erc20", conf, deployerRunner, - UserERC20Address, - UserERC20PrivateKey, + account, runner.NewLogger(verbose, color.FgGreen, "erc20"), runner.WithZetaTxServer(deployerRunner.ZetaTxServer), ) @@ -37,7 +37,7 @@ func erc20TestRoutine( startTime := time.Now() // funding the account - txERC20Send := deployerRunner.SendERC20OnEvm(UserERC20Address, 10) + txERC20Send := deployerRunner.SendERC20OnEvm(account.EVMAddress(), 10) erc20Runner.WaitForTxReceiptOnEvm(txERC20Send) // depositing the necessary tokens on ZetaChain diff --git a/cmd/zetae2e/local/ethereum.go b/cmd/zetae2e/local/ethereum.go index fa9e7754e2..ae2eebc268 100644 --- a/cmd/zetae2e/local/ethereum.go +++ b/cmd/zetae2e/local/ethereum.go @@ -25,8 +25,7 @@ func ethereumTestRoutine( "ether", conf, deployerRunner, - UserEtherAddress, - UserEtherPrivateKey, + conf.AdditionalAccounts.UserEther, runner.NewLogger(verbose, color.FgMagenta, "ether"), ) if err != nil { diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index bd9dd654a2..7e00f9ba5b 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -127,7 +127,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { zetaTxServer, err := txserver.NewZetaTxServer( conf.RPCs.ZetaCoreRPC, []string{utils.FungibleAdminName}, - []string{UserFungibleAdminPrivateKey}, + []string{conf.AdditionalAccounts.UserFungibleAdmin.RawPrivateKey.String()}, conf.ZetaChainID, ) noError(err) @@ -138,8 +138,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { "deployer", cancel, conf, - DeployerAddress, - DeployerPrivateKey, + conf.DefaultAccount, logger, runner.WithZetaTxServer(zetaTxServer), ) diff --git a/cmd/zetae2e/local/misc.go b/cmd/zetae2e/local/misc.go index 65467ec9e5..a27c93c932 100644 --- a/cmd/zetae2e/local/misc.go +++ b/cmd/zetae2e/local/misc.go @@ -19,13 +19,13 @@ func miscTestRoutine( testNames ...string, ) func() error { return func() (err error) { + account := conf.AdditionalAccounts.UserMisc // initialize runner for misc test miscRunner, err := initTestRunner( "misc", conf, deployerRunner, - UserMiscAddress, - UserMiscPrivateKey, + account, runner.NewLogger(verbose, color.FgCyan, "misc"), ) if err != nil { @@ -36,7 +36,7 @@ func miscTestRoutine( startTime := time.Now() // funding the account - txZetaSend := deployerRunner.SendZetaOnEvm(UserMiscAddress, 1000) + txZetaSend := deployerRunner.SendZetaOnEvm(account.EVMAddress(), 1000) miscRunner.WaitForTxReceiptOnEvm(txZetaSend) // depositing the necessary tokens on ZetaChain diff --git a/cmd/zetae2e/local/performance.go b/cmd/zetae2e/local/performance.go index 7d289c4e90..4039084550 100644 --- a/cmd/zetae2e/local/performance.go +++ b/cmd/zetae2e/local/performance.go @@ -27,8 +27,7 @@ func ethereumDepositPerformanceRoutine( "ether", conf, deployerRunner, - UserERC20Address, - UserERC20PrivateKey, + conf.AdditionalAccounts.UserERC20, runner.NewLogger(verbose, color.FgHiMagenta, "perf_eth_deposit"), ) if err != nil { @@ -69,8 +68,7 @@ func ethereumWithdrawPerformanceRoutine( "ether", conf, deployerRunner, - UserEtherAddress, - UserEtherPrivateKey, + conf.AdditionalAccounts.UserEther, runner.NewLogger(verbose, color.FgHiBlue, "perf_eth_withdraw"), ) if err != nil { diff --git a/cmd/zetae2e/local/test_runner.go b/cmd/zetae2e/local/test_runner.go index f2fe0ae811..198260c05c 100644 --- a/cmd/zetae2e/local/test_runner.go +++ b/cmd/zetae2e/local/test_runner.go @@ -1,8 +1,6 @@ package local import ( - ethcommon "github.com/ethereum/go-ethereum/common" - zetae2econfig "github.com/zeta-chain/zetacore/cmd/zetae2e/config" "github.com/zeta-chain/zetacore/e2e/config" "github.com/zeta-chain/zetacore/e2e/runner" @@ -14,8 +12,7 @@ func initTestRunner( name string, conf config.Config, deployerRunner *runner.E2ERunner, - userAddress ethcommon.Address, - userPrivKey string, + account config.Account, logger *runner.Logger, opts ...runner.E2ERunnerOption, ) (*runner.E2ERunner, error) { @@ -25,8 +22,7 @@ func initTestRunner( name, deployerRunner.CtxCancel, conf, - userAddress, - userPrivKey, + account, logger, opts..., ) diff --git a/cmd/zetae2e/local/zeta.go b/cmd/zetae2e/local/zeta.go index 6f5039b63f..3fdb4f48cc 100644 --- a/cmd/zetae2e/local/zeta.go +++ b/cmd/zetae2e/local/zeta.go @@ -19,13 +19,13 @@ func zetaTestRoutine( testNames ...string, ) func() error { return func() (err error) { + account := conf.AdditionalAccounts.UserZetaTest // initialize runner for zeta test zetaRunner, err := initTestRunner( "zeta", conf, deployerRunner, - UserZetaTestAddress, - UserZetaTestPrivateKey, + account, runner.NewLogger(verbose, color.FgBlue, "zeta"), ) if err != nil { @@ -36,7 +36,7 @@ func zetaTestRoutine( startTime := time.Now() // funding the account - txZetaSend := deployerRunner.SendZetaOnEvm(UserZetaTestAddress, 1000) + txZetaSend := deployerRunner.SendZetaOnEvm(account.EVMAddress(), 1000) zetaRunner.WaitForTxReceiptOnEvm(txZetaSend) // depositing the necessary tokens on ZetaChain diff --git a/cmd/zetae2e/local/zevm_mp.go b/cmd/zetae2e/local/zevm_mp.go index f95fa24390..bc97c45e29 100644 --- a/cmd/zetae2e/local/zevm_mp.go +++ b/cmd/zetae2e/local/zevm_mp.go @@ -19,13 +19,13 @@ func zevmMPTestRoutine( testNames ...string, ) func() error { return func() (err error) { + account := conf.AdditionalAccounts.UserZEVMMPTest // initialize runner for zevm mp test zevmMPRunner, err := initTestRunner( "zevm_mp", conf, deployerRunner, - UserZEVMMPTestAddress, - UserZEVMMPTestPrivateKey, + account, runner.NewLogger(verbose, color.FgHiRed, "zevm_mp"), ) if err != nil { @@ -36,7 +36,7 @@ func zevmMPTestRoutine( startTime := time.Now() // funding the account - txZetaSend := deployerRunner.SendZetaOnEvm(UserZEVMMPTestAddress, 1000) + txZetaSend := deployerRunner.SendZetaOnEvm(account.EVMAddress(), 1000) zevmMPRunner.WaitForTxReceiptOnEvm(txZetaSend) // depositing the necessary tokens on ZetaChain diff --git a/cmd/zetae2e/run.go b/cmd/zetae2e/run.go index 7d57500823..9c36d8e3d2 100644 --- a/cmd/zetae2e/run.go +++ b/cmd/zetae2e/run.go @@ -8,7 +8,6 @@ import ( "strings" "time" - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/fatih/color" "github.com/spf13/cobra" @@ -75,20 +74,13 @@ func runE2ETest(cmd *cobra.Command, args []string) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // get EVM address from config - evmAddr := conf.Accounts.EVMAddress - if !ethcommon.IsHexAddress(evmAddr) { - return errors.New("invalid EVM address") - } - // initialize deployer runner with config testRunner, err := zetae2econfig.RunnerFromConfig( ctx, "e2e", cancel, conf, - ethcommon.HexToAddress(evmAddr), - conf.Accounts.EVMPrivKey, + conf.DefaultAccount, logger, ) if err != nil { diff --git a/cmd/zetae2e/setup_bitcoin.go b/cmd/zetae2e/setup_bitcoin.go index f77924e768..99a5365adc 100644 --- a/cmd/zetae2e/setup_bitcoin.go +++ b/cmd/zetae2e/setup_bitcoin.go @@ -2,9 +2,7 @@ package main import ( "context" - "errors" - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/fatih/color" "github.com/spf13/cobra" @@ -42,20 +40,13 @@ func runSetupBitcoin(_ *cobra.Command, args []string) error { // initialize context ctx, cancel := context.WithCancel(context.Background()) - // get EVM address from config - evmAddr := conf.Accounts.EVMAddress - if !ethcommon.IsHexAddress(evmAddr) { - cancel() - return errors.New("invalid EVM address") - } // initialize deployer runner with config r, err := zetae2econfig.RunnerFromConfig( ctx, "e2e", cancel, conf, - ethcommon.HexToAddress(evmAddr), - conf.Accounts.EVMPrivKey, + conf.DefaultAccount, logger, ) if err != nil { diff --git a/cmd/zetae2e/show_tss.go b/cmd/zetae2e/show_tss.go index 780a525b19..01b61317a1 100644 --- a/cmd/zetae2e/show_tss.go +++ b/cmd/zetae2e/show_tss.go @@ -2,9 +2,7 @@ package main import ( "context" - "errors" - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/fatih/color" "github.com/spf13/cobra" @@ -42,21 +40,13 @@ func runShowTSS(_ *cobra.Command, args []string) error { // initialize context ctx, cancel := context.WithCancel(context.Background()) - // get EVM address from config - evmAddr := conf.Accounts.EVMAddress - if !ethcommon.IsHexAddress(evmAddr) { - cancel() - return errors.New("invalid EVM address") - } - // initialize deployer runner with config testRunner, err := zetae2econfig.RunnerFromConfig( ctx, "tss", cancel, conf, - ethcommon.HexToAddress(evmAddr), - conf.Accounts.EVMPrivKey, + conf.DefaultAccount, logger, ) if err != nil { diff --git a/cmd/zetae2e/stress.go b/cmd/zetae2e/stress.go index ca0446cbc9..30b2faf924 100644 --- a/cmd/zetae2e/stress.go +++ b/cmd/zetae2e/stress.go @@ -12,7 +12,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/accounts/abi/bind" - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/fatih/color" "github.com/spf13/cobra" @@ -38,12 +37,10 @@ var ( ) type stressArguments struct { - deployerAddress string - deployerPrivateKey string - network string - txnInterval int64 - contractsDeployed bool - config string + network string + txnInterval int64 + contractsDeployed bool + config string } var stressTestArgs = stressArguments{} @@ -57,10 +54,6 @@ func NewStressTestCmd() *cobra.Command { 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]") @@ -69,8 +62,6 @@ func NewStressTestCmd() *cobra.Command { StressCmd.Flags().StringVar(&stressTestArgs.config, local.FlagConfigFile, "", "config file to use for the E2E test") StressCmd.Flags().Bool(flagVerbose, false, "set to true to enable verbose logging") - local.DeployerAddress = ethcommon.HexToAddress(stressTestArgs.deployerAddress) - return StressCmd } @@ -93,11 +84,13 @@ func StressTest(cmd *cobra.Command, _ []string) { // initialize E2E tests config conf := must(local.GetConfig(cmd)) + deployerAccount := conf.DefaultAccount + // Initialize clients ---------------------------------------------------------------- evmClient := must(ethclient.Dial(conf.RPCs.EVM)) - bal := must(evmClient.BalanceAt(context.TODO(), local.DeployerAddress, nil)) + bal := must(evmClient.BalanceAt(context.TODO(), deployerAccount.EVMAddress(), nil)) - fmt.Printf("Deployer address: %s, balance: %d Wei\n", local.DeployerAddress.Hex(), bal) + fmt.Printf("Deployer address: %s, balance: %d Wei\n", deployerAccount.EVMAddress().Hex(), bal) grpcConn := must(grpc.Dial(conf.RPCs.ZetaCoreGRPC, grpc.WithInsecure())) @@ -136,8 +129,7 @@ func StressTest(cmd *cobra.Command, _ []string) { "deployer", cancel, conf, - local.DeployerAddress, - local.DeployerPrivateKey, + conf.DefaultAccount, logger, )) @@ -164,7 +156,7 @@ func StressTest(cmd *cobra.Command, _ []string) { } // Check zrc20 balance of Deployer address - ethZRC20Balance := must(e2eTest.ETHZRC20.BalanceOf(nil, local.DeployerAddress)) + ethZRC20Balance := must(e2eTest.ETHZRC20.BalanceOf(nil, deployerAccount.EVMAddress())) fmt.Printf("eth zrc20 balance: %s Wei \n", ethZRC20Balance.String()) //Pre-approve ETH withdraw on ZEVM @@ -179,7 +171,7 @@ func StressTest(cmd *cobra.Command, _ []string) { blockNum := must(e2eTest.ZEVMClient.BlockNumber(ctx)) // #nosec G701 e2eTest - always in range - nonce := must(e2eTest.ZEVMClient.NonceAt(ctx, local.DeployerAddress, big.NewInt(int64(blockNum)))) + nonce := must(e2eTest.ZEVMClient.NonceAt(ctx, deployerAccount.EVMAddress(), big.NewInt(int64(blockNum)))) // #nosec G701 e2e - always in range zevmNonce = big.NewInt(int64(nonce)) @@ -309,7 +301,7 @@ func WithdrawETHZRC20(r *runner.E2ERunner) { ethZRC20 := r.ETHZRC20 r.ZEVMAuth.Nonce = zevmNonce - must(ethZRC20.Withdraw(r.ZEVMAuth, local.DeployerAddress.Bytes(), big.NewInt(100))) + must(ethZRC20.Withdraw(r.ZEVMAuth, r.EVMAddress().Bytes(), big.NewInt(100))) } // Get ETH based chain ID diff --git a/contrib/localnet/orchestrator/Dockerfile.fastbuild b/contrib/localnet/orchestrator/Dockerfile.fastbuild index 2ef5520c64..96f437ed30 100644 --- a/contrib/localnet/orchestrator/Dockerfile.fastbuild +++ b/contrib/localnet/orchestrator/Dockerfile.fastbuild @@ -3,13 +3,14 @@ FROM ethereum/client-go:v1.10.26 as geth FROM golang:1.20.14-bookworm as orchestrator RUN apt update && \ - apt install -yq jq curl tmux python3 openssh-server iputils-ping iproute2 && \ + apt install -yq jq yq curl tmux python3 openssh-server iputils-ping iproute2 && \ rm -rf /var/lib/apt/lists/* COPY --from=geth /usr/local/bin/geth /usr/local/bin/ COPY --from=zeta /usr/local/bin/zetacored /usr/local/bin/zetaclientd /usr/local/bin/zetae2e /usr/local/bin/ COPY contrib/localnet/orchestrator/start-zetae2e.sh /work/ +COPY cmd/zetae2e/config/localnet.yml /work/config.yml RUN chmod +x /work/*.sh WORKDIR /work diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index 791f0a6074..676d55e26e 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -37,41 +37,45 @@ sleep 2 ### Create the accounts and fund them with Ether on local Ethereum network -# unlock the deployer account -echo "funding deployer address 0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC with 10000 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC", value: web3.toWei(10000,"ether")})' attach http://eth:8545 +# unlock the default account account +address=$(yq -r '.default_account.evm_address' config.yml) +echo "funding deployer address ${address} with 10000 Ether" +geth --exec "eth.sendTransaction({from: eth.coinbase, to: '${address}', value: web3.toWei(10000,'ether')})" attach http://eth:8545 # unlock erc20 tester accounts -echo "funding deployer address 0x6F57D5E7c6DBb75e59F1524a3dE38Fc389ec5Fd6 with 10000 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x6F57D5E7c6DBb75e59F1524a3dE38Fc389ec5Fd6", value: web3.toWei(10000,"ether")})' attach http://eth:8545 +address=$(yq -r '.additional_accounts.user_erc20.evm_address' config.yml) +echo "funding erc20 address ${address} with 10000 Ether" +geth --exec "eth.sendTransaction({from: eth.coinbase, to: '${address}', value: web3.toWei(10000,'ether')})" attach http://eth:8545 # unlock zeta tester accounts -echo "funding deployer address 0x5cC2fBb200A929B372e3016F1925DcF988E081fd with 10000 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x5cC2fBb200A929B372e3016F1925DcF988E081fd", value: web3.toWei(10000,"ether")})' attach http://eth:8545 +address=$(yq -r '.additional_accounts.user_zeta_test.evm_address' config.yml) +echo "funding zeta tester address ${address} with 10000 Ether" +geth --exec "eth.sendTransaction({from: eth.coinbase, to: '${address}', value: web3.toWei(10000,'ether')})" attach http://eth:8545 # unlock zevm message passing tester accounts -echo "funding deployer address 0x8Ae229198eCE3c889C07DB648Ec7C30E6051592c with 10000 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x8Ae229198eCE3c889C07DB648Ec7C30E6051592c", value: web3.toWei(10000,"ether")})' attach http://eth:8545 +address=$(yq -r '.additional_accounts.user_zevm_mp_test.evm_address' config.yml) +echo "funding zevm mp tester address ${address} with 10000 Ether" +geth --exec "eth.sendTransaction({from: eth.coinbase, to: '${address}', value: web3.toWei(10000,'ether')})" attach http://eth:8545 # unlock bitcoin tester accounts -echo "funding deployer address 0x283d810090EdF4043E75247eAeBcE848806237fD with 10000 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x283d810090EdF4043E75247eAeBcE848806237fD", value: web3.toWei(10000,"ether")})' attach http://eth:8545 +address=$(yq -r '.additional_accounts.user_bitcoin.evm_address' config.yml) +echo "funding bitcoin tester address ${address} with 10000 Ether" +geth --exec "eth.sendTransaction({from: eth.coinbase, to: '${address}', value: web3.toWei(10000,'ether')})" attach http://eth:8545 # unlock ethers tester accounts -echo "funding deployer address 0x8D47Db7390AC4D3D449Cc20D799ce4748F97619A with 10000 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x8D47Db7390AC4D3D449Cc20D799ce4748F97619A", value: web3.toWei(10000,"ether")})' attach http://eth:8545 +address=$(yq -r '.additional_accounts.user_ether.evm_address' config.yml) +echo "funding ether tester address ${address} with 10000 Ether" +geth --exec "eth.sendTransaction({from: eth.coinbase, to: '${address}', value: web3.toWei(10000,'ether')})" attach http://eth:8545 # unlock miscellaneous tests accounts -echo "funding deployer address 0x90126d02E41c9eB2a10cfc43aAb3BD3460523Cdf with 10000 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x90126d02E41c9eB2a10cfc43aAb3BD3460523Cdf", value: web3.toWei(10000,"ether")})' attach http://eth:8545 +address=$(yq -r '.additional_accounts.user_misc.evm_address' config.yml) +echo "funding misc tester address ${address} with 10000 Ether" +geth --exec "eth.sendTransaction({from: eth.coinbase, to: '${address}', value: web3.toWei(10000,'ether')})" attach http://eth:8545 # unlock admin erc20 tests accounts -echo "funding deployer address 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 with 10000 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", value: web3.toWei(10000,"ether")})' attach http://eth:8545 - -# unlock the TSS account -echo "funding TSS address 0xF421292cb0d3c97b90EEEADfcD660B893592c6A2 with 10000 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xF421292cb0d3c97b90EEEADfcD660B893592c6A2", value: web3.toWei(10000,"ether")})' attach http://eth:8545 +address=$(yq -r '.additional_accounts.user_admin.evm_address' config.yml) +echo "funding admin tester address ${address} with 10000 Ether" +geth --exec "eth.sendTransaction({from: eth.coinbase, to: '${address}', value: web3.toWei(10000,'ether')})" attach http://eth:8545 ### Run zetae2e command depending on the option passed @@ -83,7 +87,7 @@ if [ "$LOCALNET_MODE" == "upgrade" ]; then UPGRADE_HEIGHT=${UPGRADE_HEIGHT:=225} if [[ ! -f deployed.yml ]]; then - zetae2e local $E2E_ARGS --setup-only --config-out deployed.yml --skip-header-proof + zetae2e local $E2E_ARGS --setup-only --config config.yml --config-out deployed.yml --skip-header-proof if [ $? -ne 0 ]; then echo "e2e setup failed" exit 1 @@ -159,7 +163,7 @@ else echo "running e2e setup..." if [[ ! -f deployed.yml ]]; then - zetae2e local $E2E_ARGS --setup-only --config-out deployed.yml + zetae2e local $E2E_ARGS --config config.yml --setup-only --config-out deployed.yml if [ $? -ne 0 ]; then echo "e2e setup failed" exit 1 diff --git a/contrib/localnet/scripts/start-zetacored.sh b/contrib/localnet/scripts/start-zetacored.sh index 29be9fb1ad..aba9538c5e 100755 --- a/contrib/localnet/scripts/start-zetacored.sh +++ b/contrib/localnet/scripts/start-zetacored.sh @@ -213,23 +213,30 @@ then fi # set admin account - zetacored add-genesis-account zeta1svzuz982w09vf2y08xsh8qplj36phyz466krj3 100000000000000000000000000azeta zetacored add-genesis-account zeta1n0rn6sne54hv7w2uu93fl48ncyqz97d3kty6sh 100000000000000000000000000azeta # Funds the localnet_gov_admin account - cat $HOME/.zetacored/config/genesis.json | jq '.app_state["authority"]["policies"]["items"][0]["address"]="zeta1svzuz982w09vf2y08xsh8qplj36phyz466krj3"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json - cat $HOME/.zetacored/config/genesis.json | jq '.app_state["authority"]["policies"]["items"][1]["address"]="zeta1svzuz982w09vf2y08xsh8qplj36phyz466krj3"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json - cat $HOME/.zetacored/config/genesis.json | jq '.app_state["authority"]["policies"]["items"][2]["address"]="zeta1svzuz982w09vf2y08xsh8qplj36phyz466krj3"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json + + address=$(yq -r '.additional_accounts.user_fungible_admin.bech32_address' /root/config.yml) + zetacored add-genesis-account "$address" 100000000000000000000000000azeta + cat $HOME/.zetacored/config/genesis.json | jq --arg address "$address" '.app_state["authority"]["policies"]["items"][0]["address"] = $address' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json + cat $HOME/.zetacored/config/genesis.json | jq --arg address "$address" '.app_state["authority"]["policies"]["items"][1]["address"] = $address' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json + cat $HOME/.zetacored/config/genesis.json | jq --arg address "$address" '.app_state["authority"]["policies"]["items"][2]["address"] = $address' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json # give balance to runner accounts to deploy contracts directly on zEVM -# deployer - zetacored add-genesis-account zeta1uhznv7uzyjq84s3q056suc8pkme85lkvhrz3dd 100000000000000000000000000azeta +# default account + address=$(yq -r '.default_account.bech32_address' /root/config.yml) + zetacored add-genesis-account "$address" 100000000000000000000000000azeta # erc20 tester - zetacored add-genesis-account zeta1datate7xmwm4uk032f9rmcu0cwy7ch7kg6y6zv 100000000000000000000000000azeta + address=$(yq -r '.additional_accounts.user_erc20.bech32_address' /root/config.yml) + zetacored add-genesis-account "$address" 100000000000000000000000000azeta # zeta tester - zetacored add-genesis-account zeta1tnp0hvsq4y5mxuhrq9h3jfwulxywpq0ads0rer 100000000000000000000000000azeta + address=$(yq -r '.additional_accounts.user_zeta_test.bech32_address' /root/config.yml) + zetacored add-genesis-account "$address" 100000000000000000000000000azeta # bitcoin tester - zetacored add-genesis-account zeta19q7czqysah6qg0n4y3l2a08gfzqxydla492v80 100000000000000000000000000azeta + address=$(yq -r '.additional_accounts.user_bitcoin.bech32_address' /root/config.yml) + zetacored add-genesis-account "$address" 100000000000000000000000000azeta # ethers tester - zetacored add-genesis-account zeta134rakuus43xn63yucgxhn88ywj8ewcv6ezn2ga 100000000000000000000000000azeta + address=$(yq -r '.additional_accounts.user_ether.bech32_address' /root/config.yml) + zetacored add-genesis-account "$address" 100000000000000000000000000azeta # 3. Copy the genesis.json to all the nodes .And use it to create a gentx for every node zetacored gentx operator 1000000000000000000000azeta --chain-id=$CHAINID --keyring-backend=$KEYRING --gas-prices 20000000000azeta diff --git a/e2e/config/config.go b/e2e/config/config.go index 450b02c5a3..66409ee339 100644 --- a/e2e/config/config.go +++ b/e2e/config/config.go @@ -1,26 +1,70 @@ package config import ( + "crypto/ecdsa" "errors" "fmt" "os" + "strings" "github.com/btcsuite/btcd/chaincfg" - "gopkg.in/yaml.v2" + "github.com/cosmos/cosmos-sdk/types/bech32" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "gopkg.in/yaml.v3" ) +// DoubleQuotedString forces a string to be double quoted when marshaling to yaml. +// This is required because of https://github.com/go-yaml/yaml/issues/847 +type DoubleQuotedString string + +func (s DoubleQuotedString) MarshalYAML() (interface{}, error) { + return yaml.Node{ + Value: string(s), + Kind: yaml.ScalarNode, + Style: yaml.DoubleQuotedStyle, + }, nil +} + +func (s DoubleQuotedString) String() string { + return string(s) +} + +func (s DoubleQuotedString) AsEVMAddress() (ethcommon.Address, error) { + if !ethcommon.IsHexAddress(string(s)) { + return ethcommon.Address{}, fmt.Errorf("invalid evm address: %s", string(s)) + } + return ethcommon.HexToAddress(string(s)), nil +} + // Config contains the configuration for the e2e test type Config struct { - Accounts Accounts `yaml:"accounts"` - RPCs RPCs `yaml:"rpcs"` - Contracts Contracts `yaml:"contracts"` - ZetaChainID string `yaml:"zeta_chain_id"` + // Default account to use when running tests and running setup + DefaultAccount Account `yaml:"default_account"` + AdditionalAccounts AdditionalAccounts `yaml:"additional_accounts"` + RPCs RPCs `yaml:"rpcs"` + Contracts Contracts `yaml:"contracts"` + ZetaChainID string `yaml:"zeta_chain_id"` +} + +// Account contains configuration for an account +type Account struct { + RawBech32Address DoubleQuotedString `yaml:"bech32_address"` + RawEVMAddress DoubleQuotedString `yaml:"evm_address"` + RawPrivateKey DoubleQuotedString `yaml:"private_key"` } -// Accounts contains the configuration for the accounts -type Accounts struct { - EVMAddress string `yaml:"evm_address"` - EVMPrivKey string `yaml:"evm_priv_key"` +// AdditionalAccounts are extra accounts required to run specific tests +type AdditionalAccounts struct { + UserERC20 Account `yaml:"user_erc20"` + UserZetaTest Account `yaml:"user_zeta_test"` + UserZEVMMPTest Account `yaml:"user_zevm_mp_test"` + UserBitcoin Account `yaml:"user_bitcoin"` + UserEther Account `yaml:"user_ether"` + UserMisc Account `yaml:"user_misc"` + UserAdmin Account `yaml:"user_admin"` + UserFungibleAdmin Account `yaml:"user_fungible_admin"` } // RPCs contains the configuration for the RPC endpoints @@ -50,26 +94,26 @@ type Contracts struct { // EVM contains the addresses of predeployed contracts on the EVM chain type EVM struct { - ZetaEthAddress string `yaml:"zeta_eth"` - ConnectorEthAddr string `yaml:"connector_eth"` - CustodyAddr string `yaml:"custody"` - ERC20 string `yaml:"erc20"` - TestDappAddr string `yaml:"test_dapp"` + ZetaEthAddr DoubleQuotedString `yaml:"zeta_eth"` + ConnectorEthAddr DoubleQuotedString `yaml:"connector_eth"` + CustodyAddr DoubleQuotedString `yaml:"custody"` + ERC20 DoubleQuotedString `yaml:"erc20"` + TestDappAddr DoubleQuotedString `yaml:"test_dapp"` } // ZEVM contains the addresses of predeployed contracts on the zEVM chain type ZEVM struct { - SystemContractAddr string `yaml:"system_contract"` - ETHZRC20Addr string `yaml:"eth_zrc20"` - ERC20ZRC20Addr string `yaml:"erc20_zrc20"` - BTCZRC20Addr string `yaml:"btc_zrc20"` - UniswapFactoryAddr string `yaml:"uniswap_factory"` - UniswapRouterAddr string `yaml:"uniswap_router"` - ConnectorZEVMAddr string `yaml:"connector_zevm"` - WZetaAddr string `yaml:"wzeta"` - ZEVMSwapAppAddr string `yaml:"zevm_swap_app"` - ContextAppAddr string `yaml:"context_app"` - TestDappAddr string `yaml:"test_dapp"` + SystemContractAddr DoubleQuotedString `yaml:"system_contract"` + ETHZRC20Addr DoubleQuotedString `yaml:"eth_zrc20"` + ERC20ZRC20Addr DoubleQuotedString `yaml:"erc20_zrc20"` + BTCZRC20Addr DoubleQuotedString `yaml:"btc_zrc20"` + UniswapFactoryAddr DoubleQuotedString `yaml:"uniswap_factory"` + UniswapRouterAddr DoubleQuotedString `yaml:"uniswap_router"` + ConnectorZEVMAddr DoubleQuotedString `yaml:"connector_zevm"` + WZetaAddr DoubleQuotedString `yaml:"wzeta"` + ZEVMSwapAppAddr DoubleQuotedString `yaml:"zevm_swap_app"` + ContextAppAddr DoubleQuotedString `yaml:"context_app"` + TestDappAddr DoubleQuotedString `yaml:"test_dapp"` } // DefaultConfig returns the default config using values for localnet testing @@ -137,6 +181,21 @@ func WriteConfig(file string, config Config) error { return nil } +// AsSlice gets all accounts as a slice rather than a +// struct +func (a AdditionalAccounts) AsSlice() []Account { + return []Account{ + a.UserERC20, + a.UserZetaTest, + a.UserZEVMMPTest, + a.UserBitcoin, + a.UserEther, + a.UserMisc, + a.UserAdmin, + a.UserFungibleAdmin, + } +} + // Validate validates the config func (c Config) Validate() error { if c.RPCs.Bitcoin.Params != Mainnet && @@ -144,6 +203,105 @@ func (c Config) Validate() error { c.RPCs.Bitcoin.Params != Regnet { return errors.New("invalid bitcoin params") } + + err := c.DefaultAccount.Validate() + if err != nil { + return fmt.Errorf("validating deployer account: %w", err) + } + + accounts := c.AdditionalAccounts.AsSlice() + for i, account := range accounts { + if account.RawEVMAddress == "" { + continue + } + err := account.Validate() + if err != nil { + return fmt.Errorf("validating account %d: %w", i, err) + } + } + return nil +} + +// GenerateKeys generates new key pairs for all accounts +func (c *Config) GenerateKeys() error { + var err error + c.DefaultAccount, err = generateAccount() + if err != nil { + return err + } + c.AdditionalAccounts.UserERC20, err = generateAccount() + if err != nil { + return err + } + c.AdditionalAccounts.UserZetaTest, err = generateAccount() + if err != nil { + return err + } + c.AdditionalAccounts.UserZEVMMPTest, err = generateAccount() + if err != nil { + return err + } + c.AdditionalAccounts.UserBitcoin, err = generateAccount() + if err != nil { + return err + } + c.AdditionalAccounts.UserEther, err = generateAccount() + if err != nil { + return err + } + c.AdditionalAccounts.UserMisc, err = generateAccount() + if err != nil { + return err + } + c.AdditionalAccounts.UserAdmin, err = generateAccount() + if err != nil { + return err + } + c.AdditionalAccounts.UserFungibleAdmin, err = generateAccount() + if err != nil { + return err + } + return nil +} + +func (a Account) EVMAddress() ethcommon.Address { + return ethcommon.HexToAddress(a.RawEVMAddress.String()) +} + +func (a Account) PrivateKey() (*ecdsa.PrivateKey, error) { + return crypto.HexToECDSA(a.RawPrivateKey.String()) +} + +// Validate that the address and the private key specified in the +// config actually match +func (a Account) Validate() error { + privateKey, err := a.PrivateKey() + if err != nil { + return fmt.Errorf("invalid private key: %w", err) + } + privateKeyAddress := crypto.PubkeyToAddress(privateKey.PublicKey) + if a.RawEVMAddress.String() != privateKeyAddress.Hex() { + return fmt.Errorf( + "address derived from private key (%s) does not match configured address (%s)", + privateKeyAddress, + a.RawEVMAddress, + ) + } + _, _, err = bech32.DecodeAndConvert(a.RawBech32Address.String()) + if err != nil { + return fmt.Errorf("decoding bech32 address: %w", err) + } + bech32PrivateKeyAddress, err := bech32.ConvertAndEncode("zeta", privateKeyAddress.Bytes()) + if err != nil { + return fmt.Errorf("encoding private key to bech32: %w", err) + } + if a.RawBech32Address.String() != bech32PrivateKeyAddress { + return fmt.Errorf( + "address derived from private key (%s) does not match configured address (%s)", + bech32PrivateKeyAddress, + a.RawBech32Address, + ) + } return nil } @@ -170,3 +328,25 @@ func (bnt BitcoinNetworkType) GetParams() (chaincfg.Params, error) { return chaincfg.Params{}, fmt.Errorf("invalid bitcoin params %s", bnt) } } + +func generateAccount() (Account, error) { + privateKey, err := crypto.GenerateKey() + if err != nil { + return Account{}, fmt.Errorf("generating private key: %w", err) + } + // encode private key and strip 0x prefix + encodedPrivateKey := hexutil.Encode(crypto.FromECDSA(privateKey)) + encodedPrivateKey = strings.TrimPrefix(encodedPrivateKey, "0x") + + evmAddress := crypto.PubkeyToAddress(privateKey.PublicKey) + bech32Address, err := bech32.ConvertAndEncode("zeta", evmAddress.Bytes()) + if err != nil { + return Account{}, fmt.Errorf("bech32 convert and encode: %w", err) + } + + return Account{ + RawEVMAddress: DoubleQuotedString(evmAddress.String()), + RawPrivateKey: DoubleQuotedString(encodedPrivateKey), + RawBech32Address: DoubleQuotedString(bech32Address), + }, nil +} diff --git a/e2e/config/config_test.go b/e2e/config/config_test.go new file mode 100644 index 0000000000..033efb81b6 --- /dev/null +++ b/e2e/config/config_test.go @@ -0,0 +1,39 @@ +package config + +import ( + "reflect" + "testing" + + "github.com/stretchr/testify/require" +) + +// TestAdditionalAccountsSlicesSynced ensures than if any new accounts are added the +// AccountsSlice() function is updated +func TestConfigAdditionalAccountsSliceSynced(t *testing.T) { + additionalAccountsType := reflect.TypeOf(AdditionalAccounts{}) + numberOfAdditionalAccounts := additionalAccountsType.NumField() + + require.Greater(t, numberOfAdditionalAccounts, 0) + + conf := Config{} + err := conf.GenerateKeys() + require.NoError(t, err) + + additionalAccountsSlice := conf.AdditionalAccounts.AsSlice() + require.Len(t, additionalAccountsSlice, numberOfAdditionalAccounts) + + for _, account := range additionalAccountsSlice { + require.NoError(t, account.Validate()) + } +} + +func TestConfigInvalidAccount(t *testing.T) { + conf := Config{ + DefaultAccount: Account{ + RawEVMAddress: "asdf", + RawPrivateKey: "asdf", + }, + } + err := conf.Validate() + require.Error(t, err) +} diff --git a/e2e/e2etests/test_context_upgrade.go b/e2e/e2etests/test_context_upgrade.go index 4d06ee84d1..4a71b07428 100644 --- a/e2e/e2etests/test_context_upgrade.go +++ b/e2e/e2etests/test_context_upgrade.go @@ -57,7 +57,7 @@ func TestContextUpgrade(r *runner.E2ERunner, args []string) { r.Logger.Info(" msgsender: %s", eventIter.Event.MsgSender.Hex()) found = true - require.Equal(r, 0, bytes.Compare(eventIter.Event.Origin, r.DeployerAddress.Bytes()), "origin mismatch") + require.Equal(r, 0, bytes.Compare(eventIter.Event.Origin, r.EVMAddress().Bytes()), "origin mismatch") chainID, err := r.EVMClient.ChainID(r.Ctx) require.NoError(r, err) diff --git a/e2e/e2etests/test_crosschain_swap.go b/e2e/e2etests/test_crosschain_swap.go index f1fe6f54aa..798958a652 100644 --- a/e2e/e2etests/test_crosschain_swap.go +++ b/e2e/e2etests/test_crosschain_swap.go @@ -58,7 +58,7 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { big.NewInt(1e8), big.NewInt(1e8), big.NewInt(1e5), - r.DeployerAddress, + r.EVMAddress(), big.NewInt(time.Now().Add(10*time.Minute).Unix()), ) require.NoError(r, err) @@ -80,7 +80,7 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { r.Logger.Info("***** First test: ERC20 -> BTC") // Should deposit ERC20 for swap, swap for BTC and withdraw BTC - txHash := r.DepositERC20WithAmountAndMessage(r.DeployerAddress, big.NewInt(8e7), msg) + txHash := r.DepositERC20WithAmountAndMessage(r.EVMAddress(), big.NewInt(8e7), msg) cctx1 := utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) // check the cctx status @@ -110,7 +110,7 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { r.Logger.Info("#utxos %d", len(utxos)) r.Logger.Info("memo address %s", r.ERC20ZRC20Addr) - memo, err := r.ZEVMSwapApp.EncodeMemo(&bind.CallOpts{}, r.ERC20ZRC20Addr, r.DeployerAddress.Bytes()) + memo, err := r.ZEVMSwapApp.EncodeMemo(&bind.CallOpts{}, r.ERC20ZRC20Addr, r.EVMAddress().Bytes()) require.NoError(r, err) memo = append(r.ZEVMSwapAppAddr.Bytes(), memo...) @@ -138,7 +138,7 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { r.Logger.Info("******* Third test: BTC -> ETH with contract call reverted; should refund BTC") // the following memo will result in a revert in the contract call as targetZRC20 is set to DeployerAddress // which is apparently not a ZRC20 contract; the UNISWAP call will revert - memo, err := r.ZEVMSwapApp.EncodeMemo(&bind.CallOpts{}, r.DeployerAddress, r.DeployerAddress.Bytes()) + memo, err := r.ZEVMSwapApp.EncodeMemo(&bind.CallOpts{}, r.EVMAddress(), r.EVMAddress().Bytes()) require.NoError(r, err) memo = append(r.ZEVMSwapAppAddr.Bytes(), memo...) diff --git a/e2e/e2etests/test_erc20_deposit.go b/e2e/e2etests/test_erc20_deposit.go index 2f763f34b0..c7f1d4fc5f 100644 --- a/e2e/e2etests/test_erc20_deposit.go +++ b/e2e/e2etests/test_erc20_deposit.go @@ -15,7 +15,7 @@ func TestERC20Deposit(r *runner.E2ERunner, args []string) { amount, ok := big.NewInt(0).SetString(args[0], 10) require.True(r, ok, "Invalid amount specified for TestERC20Deposit.") - hash := r.DepositERC20WithAmountAndMessage(r.DeployerAddress, amount, []byte{}) + hash := r.DepositERC20WithAmountAndMessage(r.EVMAddress(), amount, []byte{}) // wait for the cctx to be mined cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, hash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) diff --git a/e2e/e2etests/test_erc20_deposit_refund.go b/e2e/e2etests/test_erc20_deposit_refund.go index ad0a962507..5e8d1173ef 100644 --- a/e2e/e2etests/test_erc20_deposit_refund.go +++ b/e2e/e2etests/test_erc20_deposit_refund.go @@ -17,7 +17,7 @@ import ( func TestERC20DepositAndCallRefund(r *runner.E2ERunner, _ []string) { // Get the initial balance of the deployer - initialBal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + initialBal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) r.Logger.Info("Sending a deposit that should revert without a liquidity pool makes the cctx aborted") @@ -36,13 +36,13 @@ func TestERC20DepositAndCallRefund(r *runner.E2ERunner, _ []string) { r.Logger.CCTX(*cctx, "deposit") r.Logger.Info("Refunding the cctx via admin") - msg := types.NewMsgRefundAbortedCCTX(r.ZetaTxServer.GetAccountAddress(0), cctx.Index, r.DeployerAddress.String()) + msg := types.NewMsgRefundAbortedCCTX(r.ZetaTxServer.GetAccountAddress(0), cctx.Index, r.EVMAddress().String()) _, err = r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, msg) require.NoError(r, err) // Check that the erc20 in the aborted cctx was refunded on ZetaChain - newBalance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + newBalance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) expectedBalance := initialBal.Add(initialBal, amount) @@ -65,7 +65,7 @@ func TestERC20DepositAndCallRefund(r *runner.E2ERunner, _ []string) { r.Logger.Info("Liquidity pool created") - erc20Balance, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + erc20Balance, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) // send the deposit @@ -87,7 +87,7 @@ func TestERC20DepositAndCallRefund(r *runner.E2ERunner, _ []string) { utils.RequireTxSuccessful(r, receipt) // check that the erc20 in the reverted cctx was refunded on EVM - erc20BalanceAfterRefund, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + erc20BalanceAfterRefund, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) // the new balance must be higher than the previous one because of the revert refund @@ -118,7 +118,7 @@ func TestERC20DepositAndCallRefund(r *runner.E2ERunner, _ []string) { func createZetaERC20LiquidityPool(r *runner.E2ERunner) error { amount := big.NewInt(1e10) - txHash := r.DepositERC20WithAmountAndMessage(r.DeployerAddress, amount, []byte{}) + txHash := r.DepositERC20WithAmountAndMessage(r.EVMAddress(), amount, []byte{}) utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) tx, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, big.NewInt(1e10)) @@ -138,7 +138,7 @@ func createZetaERC20LiquidityPool(r *runner.E2ERunner) error { amount, big.NewInt(0), big.NewInt(0), - r.DeployerAddress, + r.EVMAddress(), big.NewInt(time.Now().Add(10*time.Minute).Unix()), ) r.ZEVMAuth.Value = previousValue @@ -163,7 +163,7 @@ func sendInvalidERC20Deposit(r *runner.E2ERunner, amount *big.Int) (string, erro tx, err = r.ERC20Custody.Deposit( r.EVMAuth, - r.DeployerAddress.Bytes(), + r.EVMAddress().Bytes(), r.ERC20Addr, amount, []byte("this is an invalid msg that will cause the contract to revert"), diff --git a/e2e/e2etests/test_erc20_multiple_deposits.go b/e2e/e2etests/test_erc20_multiple_deposits.go index a99642f356..87b8309924 100644 --- a/e2e/e2etests/test_erc20_multiple_deposits.go +++ b/e2e/e2etests/test_erc20_multiple_deposits.go @@ -22,7 +22,7 @@ func TestMultipleERC20Deposit(r *runner.E2ERunner, args []string) { require.True(r, ok) require.NotZero(r, numberOfDeposits.Int64()) - initialBal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + initialBal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) txhash := multipleDeposits(r, depositAmount, numberOfDeposits) @@ -37,7 +37,7 @@ func TestMultipleERC20Deposit(r *runner.E2ERunner, args []string) { require.Len(r, cctxs, 3) // check new balance is increased by amount * count - bal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + bal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) diff := big.NewInt(0).Sub(bal, initialBal) @@ -61,7 +61,7 @@ func multipleDeposits(r *runner.E2ERunner, amount, count *big.Int) ethcommon.Has r.Logger.Info("ERC20 Approve receipt tx hash: %s", tx.Hash().Hex()) // deposit - tx, err = depositor.RunDeposits(r.EVMAuth, r.DeployerAddress.Bytes(), r.ERC20Addr, amount, []byte{}, count) + tx, err = depositor.RunDeposits(r.EVMAuth, r.EVMAddress().Bytes(), r.ERC20Addr, amount, []byte{}, count) require.NoError(r, err) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) diff --git a/e2e/e2etests/test_erc20_multiple_withdraws.go b/e2e/e2etests/test_erc20_multiple_withdraws.go index 14bbb176ca..53a45d1b41 100644 --- a/e2e/e2etests/test_erc20_multiple_withdraws.go +++ b/e2e/e2etests/test_erc20_multiple_withdraws.go @@ -56,7 +56,7 @@ func TestMultipleERC20Withdraws(r *runner.E2ERunner, args []string) { r.Logger.Info("eth zrc20 approve receipt: status %d", receipt.Status) // check the balance - bal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + bal, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) r.Logger.Info("balance of deployer on ERC20 ZRC20: %d", bal) @@ -65,7 +65,7 @@ func TestMultipleERC20Withdraws(r *runner.E2ERunner, args []string) { // withdraw tx, err = withdrawer.RunWithdraws( r.ZEVMAuth, - r.DeployerAddress.Bytes(), + r.EVMAddress().Bytes(), r.ERC20ZRC20Addr, withdrawalAmount, numberOfWithdrawals, diff --git a/e2e/e2etests/test_eth_deposit_call.go b/e2e/e2etests/test_eth_deposit_call.go index 0d7734fbdb..7fd928266d 100644 --- a/e2e/e2etests/test_eth_deposit_call.go +++ b/e2e/e2etests/test_eth_deposit_call.go @@ -5,7 +5,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" @@ -33,7 +32,7 @@ func TestEtherDepositAndCall(r *runner.E2ERunner, args []string) { gasPrice, err := evmClient.SuggestGasPrice(r.Ctx) require.NoError(r, err) - nonce, err := evmClient.PendingNonceAt(r.Ctx, r.DeployerAddress) + nonce, err := evmClient.PendingNonceAt(r.Ctx, r.EVMAddress()) require.NoError(r, err) data := append(exampleAddr.Bytes(), []byte("hello sailors")...) @@ -41,7 +40,7 @@ func TestEtherDepositAndCall(r *runner.E2ERunner, args []string) { chainID, err := evmClient.NetworkID(r.Ctx) require.NoError(r, err) - deployerPrivkey, err := crypto.HexToECDSA(r.DeployerPrivateKey) + deployerPrivkey, err := r.Account.PrivateKey() require.NoError(r, err) signedTx, err := ethtypes.SignTx(tx, ethtypes.NewEIP155Signer(chainID), deployerPrivkey) @@ -80,7 +79,7 @@ func TestEtherDepositAndCall(r *runner.E2ERunner, args []string) { gasPrice, err = evmClient.SuggestGasPrice(r.Ctx) require.NoError(r, err) - nonce, err = evmClient.PendingNonceAt(r.Ctx, r.DeployerAddress) + nonce, err = evmClient.PendingNonceAt(r.Ctx, r.EVMAddress()) require.NoError(r, err) data = append(reverterAddr.Bytes(), []byte("hello sailors")...) diff --git a/e2e/e2etests/test_eth_deposit_liquidity_cap.go b/e2e/e2etests/test_eth_deposit_liquidity_cap.go index f64b041478..2f03c7a568 100644 --- a/e2e/e2etests/test_eth_deposit_liquidity_cap.go +++ b/e2e/e2etests/test_eth_deposit_liquidity_cap.go @@ -47,7 +47,7 @@ func TestDepositEtherLiquidityCap(r *runner.E2ERunner, args []string) { r.Logger.Info("CCTX has been reverted") r.Logger.Info("Depositing less than liquidity cap should still succeed") - initialBal, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + initialBal, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) signedTx, err = r.SendEther(r.TSSAddress, amountLessThanCap, nil) @@ -61,7 +61,7 @@ func TestDepositEtherLiquidityCap(r *runner.E2ERunner, args []string) { expectedBalance := big.NewInt(0).Add(initialBal, amountLessThanCap) - bal, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + bal, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) require.Equal(r, 0, bal.Cmp(expectedBalance)) @@ -79,7 +79,7 @@ func TestDepositEtherLiquidityCap(r *runner.E2ERunner, args []string) { r.Logger.Info("remove liquidity cap tx hash: %s", res.TxHash) - initialBal, err = r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + initialBal, err = r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) signedTx, err = r.SendEther(r.TSSAddress, amountMoreThanCap, nil) @@ -91,7 +91,7 @@ func TestDepositEtherLiquidityCap(r *runner.E2ERunner, args []string) { utils.WaitCctxMinedByInboundHash(r.Ctx, signedTx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) expectedBalance = big.NewInt(0).Add(initialBal, amountMoreThanCap) - bal, err = r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + bal, err = r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) require.Equal(r, 0, diff --git a/e2e/e2etests/test_eth_deposit_refund.go b/e2e/e2etests/test_eth_deposit_refund.go index 394ffdd8e4..946c457927 100644 --- a/e2e/e2etests/test_eth_deposit_refund.go +++ b/e2e/e2etests/test_eth_deposit_refund.go @@ -5,7 +5,6 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/e2e/runner" @@ -21,7 +20,7 @@ func TestEtherDepositAndCallRefund(r *runner.E2ERunner, args []string) { evmClient := r.EVMClient - nonce, err := evmClient.PendingNonceAt(r.Ctx, r.DeployerAddress) + nonce, err := evmClient.PendingNonceAt(r.Ctx, r.EVMAddress()) require.NoError(r, err) gasLimit := uint64(23000) // in units @@ -33,7 +32,7 @@ func TestEtherDepositAndCallRefund(r *runner.E2ERunner, args []string) { chainID, err := evmClient.NetworkID(r.Ctx) require.NoError(r, err) - deployerPrivkey, err := crypto.HexToECDSA(r.DeployerPrivateKey) + deployerPrivkey, err := r.Account.PrivateKey() require.NoError(r, err) signedTx, err := ethtypes.SignTx(tx, ethtypes.NewEIP155Signer(chainID), deployerPrivkey) @@ -66,7 +65,7 @@ func TestEtherDepositAndCallRefund(r *runner.E2ERunner, args []string) { utils.RequireCCTXStatus(r, cctx, types.CctxStatus_Reverted) utils.RequireTxSuccessful(r, receipt) - require.Equal(r, r.DeployerAddress, *tx.To(), "expected tx to %s; got %s", r.DeployerAddress.Hex(), tx.To().Hex()) + require.Equal(r, r.EVMAddress(), *tx.To(), "expected tx to %s; got %s", r.EVMAddress().Hex(), tx.To().Hex()) // the received value must be lower than the original value because of the paid fees for the revert tx // we check that the value is still greater than 0 diff --git a/e2e/e2etests/test_message_passing_external_chains.go b/e2e/e2etests/test_message_passing_external_chains.go index 317665920b..2c2ed65997 100644 --- a/e2e/e2etests/test_message_passing_external_chains.go +++ b/e2e/e2etests/test_message_passing_external_chains.go @@ -39,7 +39,7 @@ func TestMessagePassingExternalChains(r *runner.E2ERunner, args []string) { r.Logger.Info("Calling ConnectorEth.Send") tx, err = r.ConnectorEth.Send(auth, zetaconnectoreth.ZetaInterfacesSendInput{ DestinationChainId: chainID, - DestinationAddress: r.DeployerAddress.Bytes(), + DestinationAddress: r.EVMAddress().Bytes(), DestinationGasLimit: big.NewInt(400_000), Message: nil, ZetaValueAndGas: amount, diff --git a/e2e/e2etests/test_message_passing_external_chains_revert_fail.go b/e2e/e2etests/test_message_passing_external_chains_revert_fail.go index 3950a8cdd5..9cc1ee8d8f 100644 --- a/e2e/e2etests/test_message_passing_external_chains_revert_fail.go +++ b/e2e/e2etests/test_message_passing_external_chains_revert_fail.go @@ -39,7 +39,7 @@ func TestMessagePassingRevertFailExternalChains(r *runner.E2ERunner, args []stri tx, err = r.ConnectorEth.Send(auth, zetaconnectoreth.ZetaInterfacesSendInput{ DestinationChainId: chainID, - DestinationAddress: r.DeployerAddress.Bytes(), + DestinationAddress: r.EVMAddress().Bytes(), DestinationGasLimit: big.NewInt(400_000), Message: []byte( "revert", diff --git a/e2e/e2etests/test_migrate_chain_support.go b/e2e/e2etests/test_migrate_chain_support.go index 848335ddef..07f49a5815 100644 --- a/e2e/e2etests/test_migrate_chain_support.go +++ b/e2e/e2etests/test_migrate_chain_support.go @@ -9,12 +9,12 @@ import ( "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/fatih/color" "github.com/stretchr/testify/require" "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" + "github.com/zeta-chain/zetacore/e2e/config" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/txserver" "github.com/zeta-chain/zetacore/e2e/utils" @@ -38,7 +38,7 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { // deposit most of the ZETA supply on ZetaChain zetaAmount := big.NewInt(1e18) zetaAmount = zetaAmount.Mul(zetaAmount, big.NewInt(20_000_000_000)) // 20B Zeta - r.DepositZetaWithAmount(r.DeployerAddress, zetaAmount) + r.DepositZetaWithAmount(r.EVMAddress(), zetaAmount) // do an ethers withdraw on the previous chain (0.01eth) for some interaction TestEtherWithdraw(r, []string{"10000000000000000"}) @@ -120,7 +120,7 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { time.Sleep(10 * time.Second) // emitting a withdraw with the previous chain should fail - txWithdraw, err := r.ETHZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), big.NewInt(10000000000000000)) + txWithdraw, err := r.ETHZRC20.Withdraw(r.ZEVMAuth, r.EVMAddress().Bytes(), big.NewInt(10000000000000000)) if err == nil { receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txWithdraw, r.Logger, r.ReceiptTimeout) utils.RequiredTxFailed(r, receipt) @@ -199,8 +199,7 @@ func configureEVM2(r *runner.E2ERunner) (*runner.E2ERunner, error) { r.Ctx, "admin-evm2", r.CtxCancel, - r.DeployerAddress, - r.DeployerPrivateKey, + r.Account, r.EVMClient, r.ZEVMClient, r.CctxClient, @@ -217,7 +216,7 @@ func configureEVM2(r *runner.E2ERunner) (*runner.E2ERunner, error) { ) // All existing fields of the runner are the same except for the RPC URL and client for EVM - ewvmClient, evmAuth, err := getEVMClient(newRunner.Ctx, EVM2RPCURL, r.DeployerPrivateKey) + ewvmClient, evmAuth, err := getEVMClient(newRunner.Ctx, EVM2RPCURL, r.Account) if err != nil { return nil, err } @@ -243,7 +242,11 @@ func configureEVM2(r *runner.E2ERunner) (*runner.E2ERunner, error) { } // getEVMClient get evm client from rpc and private key -func getEVMClient(ctx context.Context, rpc, privKey string) (*ethclient.Client, *bind.TransactOpts, error) { +func getEVMClient( + ctx context.Context, + rpc string, + account config.Account, +) (*ethclient.Client, *bind.TransactOpts, error) { evmClient, err := ethclient.Dial(rpc) if err != nil { return nil, nil, err @@ -253,7 +256,7 @@ func getEVMClient(ctx context.Context, rpc, privKey string) (*ethclient.Client, if err != nil { return nil, nil, err } - deployerPrivkey, err := crypto.HexToECDSA(privKey) + deployerPrivkey, err := account.PrivateKey() if err != nil { return nil, nil, err } diff --git a/e2e/e2etests/test_rate_limiter.go b/e2e/e2etests/test_rate_limiter.go index 446d49a6b2..739d7821dc 100644 --- a/e2e/e2etests/test_rate_limiter.go +++ b/e2e/e2etests/test_rate_limiter.go @@ -221,7 +221,7 @@ func addZetaGasLiquidity(r *runner.E2ERunner) error { amount, big.NewInt(1e18), big.NewInt(1e18), - r.DeployerAddress, + r.EVMAddress(), big.NewInt(time.Now().Add(10*time.Minute).Unix()), ) if err != nil { diff --git a/e2e/e2etests/test_stress_eth_withdraw.go b/e2e/e2etests/test_stress_eth_withdraw.go index 3a67ca8f94..2abd036a25 100644 --- a/e2e/e2etests/test_stress_eth_withdraw.go +++ b/e2e/e2etests/test_stress_eth_withdraw.go @@ -40,7 +40,7 @@ func TestStressEtherWithdraw(r *runner.E2ERunner, args []string) { for i := 0; i < numWithdraws; i++ { i := i - tx, err := r.ETHZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), withdrawalAmount) + tx, err := r.ETHZRC20.Withdraw(r.ZEVMAuth, r.EVMAddress().Bytes(), withdrawalAmount) require.NoError(r, err) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) diff --git a/e2e/e2etests/test_update_bytecode_zrc20.go b/e2e/e2etests/test_update_bytecode_zrc20.go index ba914655d1..8205b88d9c 100644 --- a/e2e/e2etests/test_update_bytecode_zrc20.go +++ b/e2e/e2etests/test_update_bytecode_zrc20.go @@ -60,10 +60,10 @@ func TestUpdateBytecodeZRC20(r *runner.E2ERunner, _ []string) { totalSupply, err := r.ETHZRC20.TotalSupply(&bind.CallOpts{}) require.NoError(r, err) - balance, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + balance, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) - approval, err := r.ETHZRC20.Allowance(&bind.CallOpts{}, r.DeployerAddress, approved) + approval, err := r.ETHZRC20.Allowance(&bind.CallOpts{}, r.EVMAddress(), approved) require.NoError(r, err) r.Logger.Info("Updating the bytecode of the ZRC20") @@ -95,11 +95,11 @@ func TestUpdateBytecodeZRC20(r *runner.E2ERunner, _ []string) { require.NoError(r, err) require.Equal(r, 0, totalSupply.Cmp(newTotalSupply)) - newBalance, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + newBalance, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) require.Equal(r, 0, balance.Cmp(newBalance)) - newApproval, err := r.ETHZRC20.Allowance(&bind.CallOpts{}, r.DeployerAddress, approved) + newApproval, err := r.ETHZRC20.Allowance(&bind.CallOpts{}, r.EVMAddress(), approved) require.NoError(r, err) require.Equal(r, 0, approval.Cmp(newApproval)) diff --git a/e2e/e2etests/test_zeta_deposit.go b/e2e/e2etests/test_zeta_deposit.go index 056ee5709f..eb8021876d 100644 --- a/e2e/e2etests/test_zeta_deposit.go +++ b/e2e/e2etests/test_zeta_deposit.go @@ -15,7 +15,7 @@ func TestZetaDeposit(r *runner.E2ERunner, args []string) { amount, ok := big.NewInt(0).SetString(args[0], 10) require.True(r, ok, "Invalid amount specified for TestZetaDeposit.") - hash := r.DepositZetaWithAmount(r.DeployerAddress, amount) + hash := r.DepositZetaWithAmount(r.EVMAddress(), amount) // wait for the cctx to be mined cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, hash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) diff --git a/e2e/e2etests/test_zeta_withdraw_bitcoin_revert.go b/e2e/e2etests/test_zeta_withdraw_bitcoin_revert.go index ae34058c94..3685dccfb3 100644 --- a/e2e/e2etests/test_zeta_withdraw_bitcoin_revert.go +++ b/e2e/e2etests/test_zeta_withdraw_bitcoin_revert.go @@ -41,7 +41,7 @@ func TestZetaWithdrawBTCRevert(r *runner.E2ERunner, args []string) { lessThanAmount := amount.Div(amount, big.NewInt(10)) // 1/10 of amount tx, err = r.ConnectorZEVM.Send(r.ZEVMAuth, connectorzevm.ZetaInterfacesSendInput{ DestinationChainId: big.NewInt(chains.BitcoinRegtest.ChainId), - DestinationAddress: r.DeployerAddress.Bytes(), + DestinationAddress: r.EVMAddress().Bytes(), DestinationGasLimit: big.NewInt(400_000), Message: nil, ZetaValueAndGas: lessThanAmount, diff --git a/e2e/e2etests/test_zrc20_swap.go b/e2e/e2etests/test_zrc20_swap.go index 661d2fc40f..14febbe800 100644 --- a/e2e/e2etests/test_zrc20_swap.go +++ b/e2e/e2etests/test_zrc20_swap.go @@ -56,7 +56,7 @@ func TestZRC20Swap(r *runner.E2ERunner, _ []string) { big.NewInt(1000), big.NewInt(90000), big.NewInt(1000), - r.DeployerAddress, + r.EVMAddress(), big.NewInt(time.Now().Add(10*time.Minute).Unix()), ) require.NoError(r, err) @@ -64,7 +64,7 @@ func TestZRC20Swap(r *runner.E2ERunner, _ []string) { receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.Info("Add liquidity receipt txhash %s status %d", receipt.TxHash, receipt.Status) - balETHBefore, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + balETHBefore, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) ethOutAmout := big.NewInt(1) @@ -73,7 +73,7 @@ func TestZRC20Swap(r *runner.E2ERunner, _ []string) { big.NewInt(1000), ethOutAmout, []ethcommon.Address{r.ERC20ZRC20Addr, r.ETHZRC20Addr}, - r.DeployerAddress, + r.EVMAddress(), big.NewInt(time.Now().Add(10*time.Minute).Unix()), ) require.NoError(r, err) @@ -81,7 +81,7 @@ func TestZRC20Swap(r *runner.E2ERunner, _ []string) { receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) r.Logger.Info("Swap ERC20 ZRC20 for ETH ZRC20 %s status %d", receipt.TxHash, receipt.Status) - balETHAfter, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + balETHAfter, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) ethDiff := big.NewInt(0).Sub(balETHAfter, balETHBefore) diff --git a/e2e/runner/balances.go b/e2e/runner/balances.go index 8a0c37782a..d1e19d4c61 100644 --- a/e2e/runner/balances.go +++ b/e2e/runner/balances.go @@ -33,37 +33,37 @@ type AccountBalancesDiff struct { // GetAccountBalances returns the account balances of the accounts used in the E2E test func (r *E2ERunner) GetAccountBalances(skipBTC bool) (AccountBalances, error) { // zevm - zetaZeta, err := r.ZEVMClient.BalanceAt(r.Ctx, r.DeployerAddress, nil) + zetaZeta, err := r.ZEVMClient.BalanceAt(r.Ctx, r.EVMAddress(), nil) if err != nil { return AccountBalances{}, err } - zetaWZeta, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + zetaWZeta, err := r.WZeta.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) if err != nil { return AccountBalances{}, err } - zetaEth, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + zetaEth, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) if err != nil { return AccountBalances{}, err } - zetaErc20, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + zetaErc20, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) if err != nil { return AccountBalances{}, err } - zetaBtc, err := r.BTCZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + zetaBtc, err := r.BTCZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) if err != nil { return AccountBalances{}, err } // evm - evmEth, err := r.EVMClient.BalanceAt(r.Ctx, r.DeployerAddress, nil) + evmEth, err := r.EVMClient.BalanceAt(r.Ctx, r.EVMAddress(), nil) if err != nil { return AccountBalances{}, err } - evmZeta, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + evmZeta, err := r.ZetaEth.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) if err != nil { return AccountBalances{}, err } - evmErc20, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + evmErc20, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) if err != nil { return AccountBalances{}, err } @@ -129,7 +129,7 @@ func (r *E2ERunner) GetBitcoinBalanceByAddress(address btcutil.Address) (btcutil // PrintAccountBalances shows the account balances of the accounts used in the E2E test // Note: USDT is mentioned as erc20 here because we want to show the balance of any erc20 contract func (r *E2ERunner) PrintAccountBalances(balances AccountBalances) { - r.Logger.Print(" ---💰 Account info %s ---", r.DeployerAddress.Hex()) + r.Logger.Print(" ---💰 Account info %s ---", r.EVMAddress().Hex()) // zevm r.Logger.Print("ZetaChain:") diff --git a/e2e/runner/bitcoin.go b/e2e/runner/bitcoin.go index c096bfc748..3165d745ca 100644 --- a/e2e/runner/bitcoin.go +++ b/e2e/runner/bitcoin.go @@ -141,7 +141,7 @@ func (r *E2ERunner) DepositBTC(testHeader bool) { ) utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined) - balance, err := r.BTCZRC20.BalanceOf(&bind.CallOpts{}, r.DeployerAddress) + balance, err := r.BTCZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) require.Equal(r, 1, balance.Sign(), "balance should be positive") @@ -156,7 +156,7 @@ func (r *E2ERunner) SendToTSSFromDeployerToDeposit(amount float64, inputUTXOs [] *chainhash.Hash, error, ) { - return r.SendToTSSFromDeployerWithMemo(amount, inputUTXOs, r.DeployerAddress.Bytes()) + return r.SendToTSSFromDeployerWithMemo(amount, inputUTXOs, r.EVMAddress().Bytes()) } func (r *E2ERunner) SendToTSSFromDeployerWithMemo( diff --git a/e2e/runner/evm.go b/e2e/runner/evm.go index 523e01e207..88c1e100bf 100644 --- a/e2e/runner/evm.go +++ b/e2e/runner/evm.go @@ -7,7 +7,6 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rpc" "github.com/stretchr/testify/require" @@ -66,7 +65,7 @@ func (r *E2ERunner) SendERC20OnEvm(address ethcommon.Address, amountERC20 int64) func (r *E2ERunner) DepositERC20() ethcommon.Hash { r.Logger.Print("⏳ depositing ERC20 into ZEVM") - return r.DepositERC20WithAmountAndMessage(r.DeployerAddress, big.NewInt(1e18), []byte{}) + return r.DepositERC20WithAmountAndMessage(r.EVMAddress(), big.NewInt(1e18), []byte{}) } func (r *E2ERunner) DepositERC20WithAmountAndMessage(to ethcommon.Address, amount *big.Int, msg []byte) ethcommon.Hash { @@ -143,7 +142,7 @@ func (r *E2ERunner) DepositEtherWithAmount(testHeader bool, amount *big.Int) eth func (r *E2ERunner) SendEther(_ ethcommon.Address, value *big.Int, data []byte) (*ethtypes.Transaction, error) { evmClient := r.EVMClient - nonce, err := evmClient.PendingNonceAt(r.Ctx, r.DeployerAddress) + nonce, err := evmClient.PendingNonceAt(r.Ctx, r.EVMAddress()) if err != nil { return nil, err } @@ -160,7 +159,7 @@ func (r *E2ERunner) SendEther(_ ethcommon.Address, value *big.Int, data []byte) return nil, err } - deployerPrivkey, err := crypto.HexToECDSA(r.DeployerPrivateKey) + deployerPrivkey, err := r.Account.PrivateKey() if err != nil { return nil, err } diff --git a/e2e/runner/runner.go b/e2e/runner/runner.go index e27de63247..a9c5c11d00 100644 --- a/e2e/runner/runner.go +++ b/e2e/runner/runner.go @@ -25,6 +25,7 @@ import ( "github.com/zeta-chain/protocol-contracts/pkg/uniswap/v2-core/contracts/uniswapv2factory.sol" uniswapv2router "github.com/zeta-chain/protocol-contracts/pkg/uniswap/v2-periphery/contracts/uniswapv2router02.sol" + "github.com/zeta-chain/zetacore/e2e/config" "github.com/zeta-chain/zetacore/e2e/contracts/contextapp" "github.com/zeta-chain/zetacore/e2e/contracts/erc20" "github.com/zeta-chain/zetacore/e2e/contracts/zevmswap" @@ -49,8 +50,7 @@ func WithZetaTxServer(txServer *txserver.ZetaTxServer) E2ERunnerOption { // It also provides some helper functions type E2ERunner struct { // accounts - DeployerAddress ethcommon.Address - DeployerPrivateKey string + Account config.Account TSSAddress ethcommon.Address BTCTSSAddress btcutil.Address BTCDeployerAddress *btcutil.AddressWitnessPubKeyHash @@ -128,8 +128,7 @@ func NewE2ERunner( ctx context.Context, name string, ctxCancel context.CancelFunc, - deployerAddress ethcommon.Address, - deployerPrivateKey string, + account config.Account, evmClient *ethclient.Client, zevmClient *ethclient.Client, cctxClient crosschaintypes.QueryClient, @@ -148,8 +147,7 @@ func NewE2ERunner( Name: name, CtxCancel: ctxCancel, - DeployerAddress: deployerAddress, - DeployerPrivateKey: deployerPrivateKey, + Account: account, ZEVMClient: zevmClient, EVMClient: evmClient, @@ -314,3 +312,8 @@ func (r *E2ERunner) FailNow() { func (r *E2ERunner) requireTxSuccessful(receipt *ethtypes.Receipt, msgAndArgs ...any) { utils.RequireTxSuccessful(r, receipt, msgAndArgs...) } + +// EVMAddress is shorthand to get the EVM address of the account +func (r *E2ERunner) EVMAddress() ethcommon.Address { + return r.Account.EVMAddress() +} diff --git a/e2e/runner/setup_bitcoin.go b/e2e/runner/setup_bitcoin.go index 92a7eac428..15b6d4a11d 100644 --- a/e2e/runner/setup_bitcoin.go +++ b/e2e/runner/setup_bitcoin.go @@ -40,7 +40,7 @@ func (r *E2ERunner) SetupBitcoinAccount(initNetwork bool) { // GetBtcAddress returns the BTC address of the deployer from its EVM private key func (r *E2ERunner) GetBtcAddress() (string, string, error) { - skBytes, err := hex.DecodeString(r.DeployerPrivateKey) + skBytes, err := hex.DecodeString(r.Account.RawPrivateKey.String()) if err != nil { return "", "", err } @@ -65,7 +65,7 @@ func (r *E2ERunner) GetBtcAddress() (string, string, error) { // SetBtcAddress imports the deployer's private key into the Bitcoin node func (r *E2ERunner) SetBtcAddress(name string, rescan bool) { - skBytes, err := hex.DecodeString(r.DeployerPrivateKey) + skBytes, err := hex.DecodeString(r.Account.RawPrivateKey.String()) require.NoError(r, err) sk, _ := btcec.PrivKeyFromBytes(btcec.S256(), skBytes) diff --git a/e2e/runner/setup_evm.go b/e2e/runner/setup_evm.go index ff5b2e0ddc..7b61d43163 100644 --- a/e2e/runner/setup_evm.go +++ b/e2e/runner/setup_evm.go @@ -28,12 +28,12 @@ func (r *E2ERunner) SetEVMContractsFromConfig() { require.NoError(r, err) // Set ZetaEthAddr - r.ZetaEthAddr = ethcommon.HexToAddress(conf.Contracts.EVM.ZetaEthAddress) + r.ZetaEthAddr = ethcommon.HexToAddress(conf.Contracts.EVM.ZetaEthAddr.String()) r.ZetaEth, err = zetaeth.NewZetaEth(r.ZetaEthAddr, r.EVMClient) require.NoError(r, err) // Set ConnectorEthAddr - r.ConnectorEthAddr = ethcommon.HexToAddress(conf.Contracts.EVM.ConnectorEthAddr) + r.ConnectorEthAddr = ethcommon.HexToAddress(conf.Contracts.EVM.ConnectorEthAddr.String()) r.ConnectorEth, err = zetaconnectoreth.NewZetaConnectorEth(r.ConnectorEthAddr, r.EVMClient) require.NoError(r, err) } @@ -66,14 +66,14 @@ func (r *E2ERunner) SetupEVM(contractsDeployed bool, whitelistERC20 bool) { zetaEthAddr, txZetaEth, ZetaEth, err := zetaeth.DeployZetaEth( r.EVMAuth, r.EVMClient, - r.DeployerAddress, + r.EVMAddress(), big.NewInt(21_000_000_000), ) require.NoError(r, err) r.ZetaEth = ZetaEth r.ZetaEthAddr = zetaEthAddr - conf.Contracts.EVM.ZetaEthAddress = zetaEthAddr.String() + conf.Contracts.EVM.ZetaEthAddr = config.DoubleQuotedString(zetaEthAddr.String()) r.Logger.Info("ZetaEth contract address: %s, tx hash: %s", zetaEthAddr.Hex(), zetaEthAddr.Hash().Hex()) r.Logger.Info("Deploying ZetaConnectorEth contract") @@ -82,14 +82,14 @@ func (r *E2ERunner) SetupEVM(contractsDeployed bool, whitelistERC20 bool) { r.EVMClient, zetaEthAddr, r.TSSAddress, - r.DeployerAddress, - r.DeployerAddress, + r.EVMAddress(), + r.EVMAddress(), ) require.NoError(r, err) r.ConnectorEth = ConnectorEth r.ConnectorEthAddr = connectorEthAddr - conf.Contracts.EVM.ConnectorEthAddr = connectorEthAddr.String() + conf.Contracts.EVM.ConnectorEthAddr = config.DoubleQuotedString(connectorEthAddr.String()) r.Logger.Info( "ZetaConnectorEth contract address: %s, tx hash: %s", @@ -101,8 +101,8 @@ func (r *E2ERunner) SetupEVM(contractsDeployed bool, whitelistERC20 bool) { erc20CustodyAddr, txCustody, ERC20Custody, err := erc20custody.DeployERC20Custody( r.EVMAuth, r.EVMClient, - r.DeployerAddress, - r.DeployerAddress, + r.EVMAddress(), + r.EVMAddress(), big.NewInt(0), big.NewInt(1e18), ethcommon.HexToAddress("0x"), diff --git a/e2e/runner/zeta.go b/e2e/runner/zeta.go index 726f3f5cb6..732104afe1 100644 --- a/e2e/runner/zeta.go +++ b/e2e/runner/zeta.go @@ -66,7 +66,7 @@ func (r *E2ERunner) DepositZeta() ethcommon.Hash { amount := big.NewInt(1e18) amount = amount.Mul(amount, big.NewInt(100)) // 100 Zeta - return r.DepositZetaWithAmount(r.DeployerAddress, amount) + return r.DepositZetaWithAmount(r.EVMAddress(), amount) } // DepositZetaWithAmount deposits ZETA on ZetaChain from the ZETA smart contract on EVM with the specified amount @@ -149,7 +149,7 @@ func (r *E2ERunner) WithdrawZeta(amount *big.Int, waitReceipt bool) *ethtypes.Tr tx, err := r.ConnectorZEVM.Send(r.ZEVMAuth, connectorzevm.ZetaInterfacesSendInput{ DestinationChainId: chainID, - DestinationAddress: r.DeployerAddress.Bytes(), + DestinationAddress: r.EVMAddress().Bytes(), DestinationGasLimit: big.NewInt(400_000), Message: nil, ZetaValueAndGas: amount, @@ -182,7 +182,7 @@ func (r *E2ERunner) WithdrawZeta(amount *big.Int, waitReceipt bool) *ethtypes.Tr // WithdrawEther withdraws Ether from ZetaChain to the ZETA smart contract on EVM func (r *E2ERunner) WithdrawEther(amount *big.Int) *ethtypes.Transaction { // withdraw - tx, err := r.ETHZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), amount) + tx, err := r.ETHZRC20.Withdraw(r.ZEVMAuth, r.EVMAddress().Bytes(), amount) require.NoError(r, err) r.Logger.EVMTransaction(*tx, "withdraw") @@ -198,7 +198,7 @@ func (r *E2ERunner) WithdrawEther(amount *big.Int) *ethtypes.Transaction { // WithdrawERC20 withdraws an ERC20 token from ZetaChain to the ZETA smart contract on EVM func (r *E2ERunner) WithdrawERC20(amount *big.Int) *ethtypes.Transaction { - tx, err := r.ERC20ZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), amount) + tx, err := r.ERC20ZRC20.Withdraw(r.ZEVMAuth, r.EVMAddress().Bytes(), amount) require.NoError(r, err) r.Logger.EVMTransaction(*tx, "withdraw") From ef8470cf66b10ca09a2a14570c986e8069295012 Mon Sep 17 00:00:00 2001 From: Charlie <31941002+CharlieMc0@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:08:15 -0500 Subject: [PATCH 14/23] ci: enable artifact attenstations (#2388) * updated * Testing * Testing * Testing * Testing * Testing * Testing * Testing * Testing * Testing * Testing * Testing * enable all binaries * enable all binaries * Testing * Testing * Testing * Testing * Testing * enable all binaries * cleanup from testing * cleanup from testing * test default token * test default token * changed back to default token * updated changelog --------- Co-authored-by: Grant Zukel Co-authored-by: Alex Gartner --- .github/workflows/docker-build-and-push.yml | 4 ++-- .github/workflows/publish-release.yml | 24 +++++++++++++++++++-- .goreleaser.yaml | 1 - changelog.md | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docker-build-and-push.yml b/.github/workflows/docker-build-and-push.yml index 95ca015953..c2def3200d 100644 --- a/.github/workflows/docker-build-and-push.yml +++ b/.github/workflows/docker-build-and-push.yml @@ -30,7 +30,7 @@ jobs: fetch-depth: 0 - name: Set Version from the release title. - if: github.event_name != 'workflow_dispatch' + if: github.event_name == 'workflow_dispatch' run: | echo "GITHUB_TAG_MAJOR_VERSION=${{ github.event.release.name }}" >> $GITHUB_ENV @@ -62,7 +62,7 @@ jobs: fetch-depth: 0 - name: Set Version from the release title. - if: github.event_name != 'workflow_dispatch' + if: github.event_name == 'workflow_dispatch' run: | echo "GITHUB_TAG_MAJOR_VERSION=${{ github.event.release.name }}" >> $GITHUB_ENV diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 7eded17252..97dc97aa9a 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -425,6 +425,10 @@ jobs: echo "continue" publish-release: + permissions: + id-token: write + contents: write + attestations: write if: ${{ github.event.inputs.skip_release == 'false' }} needs: - gosec @@ -495,18 +499,34 @@ jobs: uses: softprops/action-gh-release@v1 with: prerelease: true - token: ${{ secrets.PAT_GITHUB_SERVICE_ACCT }} + token: ${{ secrets.GITHUB_TOKEN }} body_path: ${{ github.workspace }}-CHANGELOG.txt tag_name: ${{ env.GITHUB_TAG_MAJOR_VERSION }} - name: Publish Release Files env: - GITHUB_TOKEN: ${{ secrets.PAT_GITHUB_SERVICE_ACCT }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_CURRENT_TAG: ${{ env.GITHUB_TAG_MAJOR_VERSION }} run: | touch .release-env make release + - name: Artifact Attestations + id: attestation + uses: actions/attest-build-provenance@v1 + with: + subject-path: | + dist/zetacored_**/* + dist/zetaclientd_**/* + dist/checksums.txt + + - name: Upload Attestation Bundle + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + gh release upload ${{ env.GITHUB_TAG_MAJOR_VERSION }} ${{ steps.attestation.outputs.bundle-path }} + - name: Clean Up Workspace if: always() shell: bash diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 16541f2291..7291e57a08 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -6,7 +6,6 @@ # - Add SBOMs # - Add Docker Builds # - SLSA - https://github.com/goreleaser/goreleaser-example-slsa-provenance -# - Add Code Signing env: - CGO_ENABLED=1 diff --git a/changelog.md b/changelog.md index 1a7d568bd3..a16cd90d2d 100644 --- a/changelog.md +++ b/changelog.md @@ -88,7 +88,7 @@ * [2382](https://github.com/zeta-chain/node/pull/2382) - add tx input and gas in rpc methods for synthetic eth txs ### CI - +* [2388](https://github.com/zeta-chain/node/pull/2388) - added GitHub attestations of binaries produced in the release workflow. * [2285](https://github.com/zeta-chain/node/pull/2285) - added nightly EVM performance testing pipeline, modified localnet testing docker image to utilitze debian:bookworm, removed build-jet runners where applicable, removed deprecated/removed upgrade path testing pipeline * [2268](https://github.com/zeta-chain/node/pull/2268) - updated the publish-release pipeline to utilize the Github Actions Ubuntu 20.04 Runners * [2070](https://github.com/zeta-chain/node/pull/2070) - Added commands to build binaries from the working branch as a live full node rpc to test non-governance changes From 0660e73614aec34f15515a378557b046c6b07346 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Jun 2024 10:13:41 +0200 Subject: [PATCH 15/23] chore(deps): bump github.com/hashicorp/go-getter from 1.7.4 to 1.7.5 (#2392) Bumps [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) from 1.7.4 to 1.7.5. - [Release notes](https://github.com/hashicorp/go-getter/releases) - [Changelog](https://github.com/hashicorp/go-getter/blob/main/.goreleaser.yml) - [Commits](https://github.com/hashicorp/go-getter/compare/v1.7.4...v1.7.5) --- updated-dependencies: - dependency-name: github.com/hashicorp/go-getter dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Alex Gartner --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 60a7598f16..43584e6b4e 100644 --- a/go.mod +++ b/go.mod @@ -215,7 +215,7 @@ require ( github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.4 + github.com/hashicorp/go-getter v1.7.5 github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect diff --git a/go.sum b/go.sum index a5bbf02ee3..ad13862826 100644 --- a/go.sum +++ b/go.sum @@ -921,8 +921,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.4 h1:3yQjWuxICvSpYwqSayAdKRFcvBl1y/vogCxczWSmix0= -github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4= +github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= From 86298f28d8a4e6ea00f316840f409bcd4186dafa Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Fri, 28 Jun 2024 09:09:49 -0700 Subject: [PATCH 16/23] chore: update PR template (#2394) * chore: update PR template * remove checklist --- .github/pull_request_template.md | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 09a533c5d6..7abe7810e0 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,26 +1,13 @@ # Description -Please include a summary of the changes and the related issue. Please also include relevant motivation and context. List any dependencies that are required for this change. - -Closes: - -## Type of change - -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] This change requires a documentation update + # How Has This Been Tested? -Please describe the tests that you ran to verify your changes. Include instructions and any relevant details so others can reproduce. + - [ ] Tested CCTX in localnet - [ ] Tested in development environment - [ ] Go unit tests - [ ] Go integration tests -- [ ] Tested via GitHub Actions - -# Checklist: - -- [ ] I have added unit tests that prove my fix feature works +- [ ] Tested via GitHub Actions From 0bcb422e614c3e1b2c565de83017c93538ff668c Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Mon, 1 Jul 2024 19:11:00 +0200 Subject: [PATCH 17/23] chore: add fbac as codeowner (#2410) Signed-off-by: Francisco de Borja Aranda Castillejo Co-authored-by: Francisco de Borja Aranda Castillejo --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 65567bd2ab..084809afa5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ -* @brewmaster012 @kingpinXD @lumtis @ws4charlie @skosito @swift1337 +* @brewmaster012 @kingpinXD @lumtis @ws4charlie @skosito @swift1337 @fbac .github/** @zeta-chain/devops From 2d5519f4d64bb05b64e6f2c7ec9ef6a87e97610f Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Mon, 1 Jul 2024 21:04:06 +0200 Subject: [PATCH 18/23] feat(zetaclient): converge AppContext with ZetaCoreContext (#2395) * Converge AppContext and ZetaCoreContext * Embed AppContext into context.Context * Fix code after converging AppContext with ZetaCoreContext * Update changelog * Address PR comments * Add more test cases for AppContext --- changelog.md | 1 + cmd/zetaclientd/debug.go | 282 +++++++-------- cmd/zetaclientd/keygen_tss.go | 2 +- cmd/zetaclientd/start.go | 8 +- cmd/zetaclientd/utils.go | 16 +- zetaclient/chains/base/observer.go | 20 +- zetaclient/chains/base/observer_test.go | 25 +- zetaclient/chains/base/signer.go | 25 +- zetaclient/chains/base/signer_test.go | 13 +- zetaclient/chains/bitcoin/observer/inbound.go | 7 +- .../chains/bitcoin/observer/observer.go | 4 +- .../chains/bitcoin/observer/observer_test.go | 10 +- .../chains/bitcoin/observer/outbound.go | 3 +- zetaclient/chains/bitcoin/signer/signer.go | 6 +- zetaclient/chains/evm/observer/inbound.go | 9 +- zetaclient/chains/evm/observer/observer.go | 4 +- .../chains/evm/observer/observer_test.go | 9 +- zetaclient/chains/evm/observer/outbound.go | 3 +- zetaclient/chains/evm/signer/signer.go | 6 +- zetaclient/chains/evm/signer/signer_test.go | 6 +- zetaclient/config/config_chain.go | 7 +- zetaclient/context/app.go | 287 +++++++++++++++ zetaclient/context/app_context.go | 46 --- zetaclient/context/app_context_test.go | 1 - .../{zetacore_context_test.go => app_test.go} | 331 ++++++++++++------ zetaclient/context/context.go | 26 ++ zetaclient/context/context_test.go | 40 +++ zetaclient/context/zetacore_context.go | 253 ------------- zetaclient/orchestrator/orchestrator.go | 19 +- zetaclient/orchestrator/orchestrator_test.go | 23 +- .../supplychecker/zeta_supply_checker.go | 10 +- zetaclient/tss/tss_signer.go | 2 +- zetaclient/zetacore/client.go | 7 +- zetaclient/zetacore/tx.go | 2 +- zetaclient/zetacore/tx_test.go | 4 +- 35 files changed, 835 insertions(+), 682 deletions(-) create mode 100644 zetaclient/context/app.go delete mode 100644 zetaclient/context/app_context.go delete mode 100644 zetaclient/context/app_context_test.go rename zetaclient/context/{zetacore_context_test.go => app_test.go} (55%) create mode 100644 zetaclient/context/context.go create mode 100644 zetaclient/context/context_test.go delete mode 100644 zetaclient/context/zetacore_context.go diff --git a/changelog.md b/changelog.md index a16cd90d2d..4e7cd838a0 100644 --- a/changelog.md +++ b/changelog.md @@ -55,6 +55,7 @@ * [2357](https://github.com/zeta-chain/node/pull/2357) - integrate base Signer structure into EVM/Bitcoin Signer * [2359](https://github.com/zeta-chain/node/pull/2359) - integrate base Observer structure into EVM/Bitcoin Observer * [2375](https://github.com/zeta-chain/node/pull/2375) - improve & speedup code formatting +* [2395](https://github.com/zeta-chain/node/pull/2395) - converge AppContext with ZetaCoreContext in zetaclient ### Tests diff --git a/cmd/zetaclientd/debug.go b/cmd/zetaclientd/debug.go index 8aaeb6384e..08aadbe8a4 100644 --- a/cmd/zetaclientd/debug.go +++ b/cmd/zetaclientd/debug.go @@ -11,6 +11,7 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/onrik/ethrpc" + "github.com/rs/zerolog" "github.com/spf13/cobra" "github.com/zeta-chain/zetacore/pkg/chains" @@ -42,163 +43,166 @@ func init() { } func DebugCmd() *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "get-inbound-ballot [inboundHash] [chainID]", Short: "provide txHash and chainID to get the ballot status for the txHash", - RunE: func(_ *cobra.Command, args []string) error { - cobra.ExactArgs(2) - cfg, err := config.Load(debugArgs.zetaCoreHome) - if err != nil { - return err - } - coreContext := clientcontext.NewZetacoreContext(cfg) - chainID, err := strconv.ParseInt(args[1], 10, 64) - if err != nil { - return err - } - inboundHash := args[0] - var ballotIdentifier string - - // create a new zetacore client - client, err := zetacore.NewClient( - &keys.Keys{OperatorAddress: sdk.MustAccAddressFromBech32(sample.AccAddress())}, - debugArgs.zetaNode, - "", - debugArgs.zetaChainID, - false, - nil) - if err != nil { - return err - } - chainParams, err := client.GetChainParams() - if err != nil { - return err - } - tssEthAddress, err := client.GetEthTssAddress() - if err != nil { - return err - } - chain := chains.GetChainFromChainID(chainID) - if chain == nil { - return fmt.Errorf("invalid chain id") - } + RunE: debugCmd, + } +} - // get ballot identifier according to the chain type - if chains.IsEVMChain(chain.ChainId) { - evmObserver := evmobserver.Observer{} - evmObserver.WithZetacoreClient(client) - var ethRPC *ethrpc.EthRPC - var client *ethclient.Client - coinType := coin.CoinType_Cmd - for chain, evmConfig := range cfg.GetAllEVMConfigs() { - if chainID == chain { - ethRPC = ethrpc.NewEthRPC(evmConfig.Endpoint) - client, err = ethclient.Dial(evmConfig.Endpoint) - if err != nil { - return err - } - evmObserver.WithEvmClient(client) - evmObserver.WithEvmJSONRPC(ethRPC) - evmObserver.WithChain(*chains.GetChainFromChainID(chainID)) - } - } - hash := ethcommon.HexToHash(inboundHash) - tx, isPending, err := evmObserver.TransactionByHash(inboundHash) - if err != nil { - return fmt.Errorf("tx not found on chain %s , %d", err.Error(), chain.ChainId) - } - if isPending { - return fmt.Errorf("tx is still pending") - } - receipt, err := client.TransactionReceipt(context.Background(), hash) - if err != nil { - return fmt.Errorf("tx receipt not found on chain %s, %d", err.Error(), chain.ChainId) - } +func debugCmd(_ *cobra.Command, args []string) error { + cobra.ExactArgs(2) + cfg, err := config.Load(debugArgs.zetaCoreHome) + if err != nil { + return err + } - for _, chainParams := range chainParams { - if chainParams.ChainId == chainID { - evmObserver.SetChainParams(observertypes.ChainParams{ - ChainId: chainID, - ConnectorContractAddress: chainParams.ConnectorContractAddress, - ZetaTokenContractAddress: chainParams.ZetaTokenContractAddress, - Erc20CustodyContractAddress: chainParams.Erc20CustodyContractAddress, - }) - evmChainParams, found := coreContext.GetEVMChainParams(chainID) - if !found { - return fmt.Errorf("missing chain params for chain %d", chainID) - } - evmChainParams.ZetaTokenContractAddress = chainParams.ZetaTokenContractAddress - if strings.EqualFold(tx.To, chainParams.ConnectorContractAddress) { - coinType = coin.CoinType_Zeta - } else if strings.EqualFold(tx.To, chainParams.Erc20CustodyContractAddress) { - coinType = coin.CoinType_ERC20 - } else if strings.EqualFold(tx.To, tssEthAddress) { - coinType = coin.CoinType_Gas - } - } - } + appContext := clientcontext.New(cfg, zerolog.Nop()) - switch coinType { - case coin.CoinType_Zeta: - ballotIdentifier, err = evmObserver.CheckAndVoteInboundTokenZeta(tx, receipt, false) - if err != nil { - return err - } - - case coin.CoinType_ERC20: - ballotIdentifier, err = evmObserver.CheckAndVoteInboundTokenERC20(tx, receipt, false) - if err != nil { - return err - } - - case coin.CoinType_Gas: - ballotIdentifier, err = evmObserver.CheckAndVoteInboundTokenGas(tx, receipt, false) - if err != nil { - return err - } - default: - fmt.Println("CoinType not detected") - } - fmt.Println("CoinType : ", coinType) - } else if chains.IsBitcoinChain(chain.ChainId) { - btcObserver := btcobserver.Observer{} - btcObserver.WithZetacoreClient(client) - btcObserver.WithChain(*chains.GetChainFromChainID(chainID)) - connCfg := &rpcclient.ConnConfig{ - Host: cfg.BitcoinConfig.RPCHost, - User: cfg.BitcoinConfig.RPCUsername, - Pass: cfg.BitcoinConfig.RPCPassword, - HTTPPostMode: true, - DisableTLS: true, - Params: cfg.BitcoinConfig.RPCParams, - } + chainID, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + return err + } + + inboundHash := args[0] + var ballotIdentifier string + + // create a new zetacore client + client, err := zetacore.NewClient( + &keys.Keys{OperatorAddress: sdk.MustAccAddressFromBech32(sample.AccAddress())}, + debugArgs.zetaNode, + "", + debugArgs.zetaChainID, + false, + nil) + if err != nil { + return err + } + chainParams, err := client.GetChainParams() + if err != nil { + return err + } + tssEthAddress, err := client.GetEthTssAddress() + if err != nil { + return err + } + chain := chains.GetChainFromChainID(chainID) + if chain == nil { + return fmt.Errorf("invalid chain id") + } - btcClient, err := rpcclient.New(connCfg, nil) + // get ballot identifier according to the chain type + if chains.IsEVMChain(chain.ChainId) { + evmObserver := evmobserver.Observer{} + evmObserver.WithZetacoreClient(client) + var ethRPC *ethrpc.EthRPC + var client *ethclient.Client + coinType := coin.CoinType_Cmd + for chain, evmConfig := range cfg.GetAllEVMConfigs() { + if chainID == chain { + ethRPC = ethrpc.NewEthRPC(evmConfig.Endpoint) + client, err = ethclient.Dial(evmConfig.Endpoint) if err != nil { return err } - btcObserver.WithBtcClient(btcClient) - ballotIdentifier, err = btcObserver.CheckReceiptForBtcTxHash(inboundHash, false) - if err != nil { - return err + evmObserver.WithEvmClient(client) + evmObserver.WithEvmJSONRPC(ethRPC) + evmObserver.WithChain(*chains.GetChainFromChainID(chainID)) + } + } + hash := ethcommon.HexToHash(inboundHash) + tx, isPending, err := evmObserver.TransactionByHash(inboundHash) + if err != nil { + return fmt.Errorf("tx not found on chain %s , %d", err.Error(), chain.ChainId) + } + if isPending { + return fmt.Errorf("tx is still pending") + } + receipt, err := client.TransactionReceipt(context.Background(), hash) + if err != nil { + return fmt.Errorf("tx receipt not found on chain %s, %d", err.Error(), chain.ChainId) + } + + for _, chainParams := range chainParams { + if chainParams.ChainId == chainID { + evmObserver.SetChainParams(observertypes.ChainParams{ + ChainId: chainID, + ConnectorContractAddress: chainParams.ConnectorContractAddress, + ZetaTokenContractAddress: chainParams.ZetaTokenContractAddress, + Erc20CustodyContractAddress: chainParams.Erc20CustodyContractAddress, + }) + evmChainParams, found := appContext.GetEVMChainParams(chainID) + if !found { + return fmt.Errorf("missing chain params for chain %d", chainID) + } + evmChainParams.ZetaTokenContractAddress = chainParams.ZetaTokenContractAddress + if strings.EqualFold(tx.To, chainParams.ConnectorContractAddress) { + coinType = coin.CoinType_Zeta + } else if strings.EqualFold(tx.To, chainParams.Erc20CustodyContractAddress) { + coinType = coin.CoinType_ERC20 + } else if strings.EqualFold(tx.To, tssEthAddress) { + coinType = coin.CoinType_Gas } } - fmt.Println("BallotIdentifier : ", ballotIdentifier) + } - // query ballot - ballot, err := client.GetBallot(ballotIdentifier) + switch coinType { + case coin.CoinType_Zeta: + ballotIdentifier, err = evmObserver.CheckAndVoteInboundTokenZeta(tx, receipt, false) if err != nil { return err } - for _, vote := range ballot.Voters { - fmt.Printf("%s : %s \n", vote.VoterAddress, vote.VoteType) + case coin.CoinType_ERC20: + ballotIdentifier, err = evmObserver.CheckAndVoteInboundTokenERC20(tx, receipt, false) + if err != nil { + return err } - fmt.Println("BallotStatus : ", ballot.BallotStatus) - return nil - }, + case coin.CoinType_Gas: + ballotIdentifier, err = evmObserver.CheckAndVoteInboundTokenGas(tx, receipt, false) + if err != nil { + return err + } + default: + fmt.Println("CoinType not detected") + } + fmt.Println("CoinType : ", coinType) + } else if chains.IsBitcoinChain(chain.ChainId) { + btcObserver := btcobserver.Observer{} + btcObserver.WithZetacoreClient(client) + btcObserver.WithChain(*chains.GetChainFromChainID(chainID)) + connCfg := &rpcclient.ConnConfig{ + Host: cfg.BitcoinConfig.RPCHost, + User: cfg.BitcoinConfig.RPCUsername, + Pass: cfg.BitcoinConfig.RPCPassword, + HTTPPostMode: true, + DisableTLS: true, + Params: cfg.BitcoinConfig.RPCParams, + } + + btcClient, err := rpcclient.New(connCfg, nil) + if err != nil { + return err + } + btcObserver.WithBtcClient(btcClient) + ballotIdentifier, err = btcObserver.CheckReceiptForBtcTxHash(inboundHash, false) + if err != nil { + return err + } + } + fmt.Println("BallotIdentifier : ", ballotIdentifier) + + // query ballot + ballot, err := client.GetBallot(ballotIdentifier) + if err != nil { + return err + } + + for _, vote := range ballot.Voters { + fmt.Printf("%s : %s \n", vote.VoterAddress, vote.VoteType) } + fmt.Println("BallotStatus : ", ballot.BallotStatus) - return cmd + return nil } diff --git a/cmd/zetaclientd/keygen_tss.go b/cmd/zetaclientd/keygen_tss.go index 007ce9ec8c..63b5d98041 100644 --- a/cmd/zetaclientd/keygen_tss.go +++ b/cmd/zetaclientd/keygen_tss.go @@ -74,7 +74,7 @@ func GenerateTss( // This loop will try keygen at the keygen block and then wait for keygen to be successfully reported by all nodes before breaking out of the loop. // If keygen is unsuccessful, it will reset the triedKeygenAtBlock flag and try again at a new keygen block. - keyGen := appContext.ZetacoreContext().GetKeygen() + keyGen := appContext.GetKeygen() if keyGen.Status == observertypes.KeygenStatus_KeyGenSuccess { return tss, nil } diff --git a/cmd/zetaclientd/start.go b/cmd/zetaclientd/start.go index c815b616c0..3546cec8ad 100644 --- a/cmd/zetaclientd/start.go +++ b/cmd/zetaclientd/start.go @@ -144,8 +144,8 @@ func start(_ *cobra.Command, _ []string) error { startLogger.Debug().Msgf("CreateAuthzSigner is ready") // Initialize core parameters from zetacore - appContext := context.NewAppContext(context.NewZetacoreContext(cfg), cfg) - err = zetacoreClient.UpdateZetacoreContext(appContext.ZetacoreContext(), true, startLogger) + appContext := context.New(cfg, masterLogger) + err = zetacoreClient.UpdateZetacoreContext(appContext, true, startLogger) if err != nil { startLogger.Error().Err(err).Msg("Error getting core parameters") return err @@ -226,7 +226,7 @@ func start(_ *cobra.Command, _ []string) error { // For existing keygen, this should directly proceed to the next step ticker := time.NewTicker(time.Second * 1) for range ticker.C { - keyGen := appContext.ZetacoreContext().GetKeygen() + keyGen := appContext.GetKeygen() if keyGen.Status != observerTypes.KeygenStatus_KeyGenSuccess { startLogger.Info().Msgf("Waiting for TSS Keygen to be a success, current status %s", keyGen.Status) continue @@ -250,7 +250,7 @@ func start(_ *cobra.Command, _ []string) error { } startLogger.Info(). Msgf("Current TSS address \n ETH : %s \n BTC : %s \n PubKey : %s ", tss.EVMAddress(), tss.BTCAddress(), tss.CurrentPubkey) - if len(appContext.ZetacoreContext().GetEnabledChains()) == 0 { + if len(appContext.GetEnabledChains()) == 0 { startLogger.Error().Msgf("No chains enabled in updated config %s ", cfg.String()) } diff --git a/cmd/zetaclientd/utils.go b/cmd/zetaclientd/utils.go index 99dd26c487..99f6e03e59 100644 --- a/cmd/zetaclientd/utils.go +++ b/cmd/zetaclientd/utils.go @@ -65,7 +65,6 @@ func CreateSignerMap( logger base.Logger, ts *metrics.TelemetryServer, ) (map[int64]interfaces.ChainSigner, error) { - zetacoreContext := appContext.ZetacoreContext() signerMap := make(map[int64]interfaces.ChainSigner) // EVM signers @@ -73,7 +72,7 @@ func CreateSignerMap( if evmConfig.Chain.IsZetaChain() { continue } - evmChainParams, found := zetacoreContext.GetEVMChainParams(evmConfig.Chain.ChainId) + evmChainParams, found := appContext.GetEVMChainParams(evmConfig.Chain.ChainId) if !found { logger.Std.Error().Msgf("ChainParam not found for chain %s", evmConfig.Chain.String()) continue @@ -82,7 +81,7 @@ func CreateSignerMap( erc20CustodyAddress := ethcommon.HexToAddress(evmChainParams.Erc20CustodyContractAddress) signer, err := evmsigner.NewSigner( evmConfig.Chain, - zetacoreContext, + appContext, tss, ts, logger, @@ -100,7 +99,7 @@ func CreateSignerMap( // BTC signer btcChain, btcConfig, enabled := appContext.GetBTCChainAndConfig() if enabled { - signer, err := btcsigner.NewSigner(btcChain, zetacoreContext, tss, ts, logger, btcConfig) + signer, err := btcsigner.NewSigner(btcChain, appContext, tss, ts, logger, btcConfig) if err != nil { logger.Std.Error().Err(err).Msgf("NewBTCSigner error for chain %s", btcChain.String()) } else { @@ -120,14 +119,13 @@ func CreateChainObserverMap( logger base.Logger, ts *metrics.TelemetryServer, ) (map[int64]interfaces.ChainObserver, error) { - zetacoreContext := appContext.ZetacoreContext() observerMap := make(map[int64]interfaces.ChainObserver) // EVM observers for _, evmConfig := range appContext.Config().GetAllEVMConfigs() { if evmConfig.Chain.IsZetaChain() { continue } - chainParams, found := zetacoreContext.GetEVMChainParams(evmConfig.Chain.ChainId) + chainParams, found := appContext.GetEVMChainParams(evmConfig.Chain.ChainId) if !found { logger.Std.Error().Msgf("ChainParam not found for chain %s", evmConfig.Chain.String()) continue @@ -145,7 +143,7 @@ func CreateChainObserverMap( evmConfig, evmClient, *chainParams, - zetacoreContext, + appContext, zetacoreClient, tss, dbpath, @@ -160,7 +158,7 @@ func CreateChainObserverMap( } // BTC observer - _, chainParams, found := zetacoreContext.GetBTCChainParams() + _, chainParams, found := appContext.GetBTCChainParams() if !found { return nil, fmt.Errorf("bitcoin chains params not found") } @@ -177,7 +175,7 @@ func CreateChainObserverMap( btcChain, btcClient, *chainParams, - zetacoreContext, + appContext, zetacoreClient, tss, dbpath, diff --git a/zetaclient/chains/base/observer.go b/zetaclient/chains/base/observer.go index 1f3fc2d0ca..edfef83629 100644 --- a/zetaclient/chains/base/observer.go +++ b/zetaclient/chains/base/observer.go @@ -45,8 +45,8 @@ type Observer struct { // chainParams contains the dynamic chain parameters of the observed chain chainParams observertypes.ChainParams - // coreContext contains context data of ZetaChain - zetacoreContext *context.ZetacoreContext + // appContext contains context data for zetaclient & zetacore (e.g. supported chains) + appContext *context.AppContext // zetacoreClient is the client to interact with ZetaChain zetacoreClient interfaces.ZetacoreClient @@ -87,7 +87,7 @@ type Observer struct { func NewObserver( chain chains.Chain, chainParams observertypes.ChainParams, - zetacoreContext *context.ZetacoreContext, + appContext *context.AppContext, zetacoreClient interfaces.ZetacoreClient, tss interfaces.TSSSigner, blockCacheSize int, @@ -98,7 +98,7 @@ func NewObserver( ob := Observer{ chain: chain, chainParams: chainParams, - zetacoreContext: zetacoreContext, + appContext: appContext, zetacoreClient: zetacoreClient, tss: tss, lastBlock: 0, @@ -164,15 +164,9 @@ func (ob *Observer) WithChainParams(params observertypes.ChainParams) *Observer return ob } -// ZetacoreContext returns the zetacore context for the observer. -func (ob *Observer) ZetacoreContext() *context.ZetacoreContext { - return ob.zetacoreContext -} - -// WithZetacoreContext attaches a new zetacore context to the observer. -func (ob *Observer) WithZetacoreContext(context *context.ZetacoreContext) *Observer { - ob.zetacoreContext = context - return ob +// AppContext returns the zetacore context for the observer. +func (ob *Observer) AppContext() *context.AppContext { + return ob.appContext } // ZetacoreClient returns the zetacore client for the observer. diff --git a/zetaclient/chains/base/observer_test.go b/zetaclient/chains/base/observer_test.go index a04a48fcc3..e6d5a088a9 100644 --- a/zetaclient/chains/base/observer_test.go +++ b/zetaclient/chains/base/observer_test.go @@ -5,6 +5,7 @@ import ( "testing" lru "github.com/hashicorp/golang-lru" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/zetaclient/testutils" @@ -25,7 +26,7 @@ func createObserver(t *testing.T) *base.Observer { // constructor parameters chain := chains.Ethereum chainParams := *sample.ChainParams(chain.ChainId) - zetacoreContext := context.NewZetacoreContext(config.NewConfig()) + appContext := context.New(config.NewConfig(), zerolog.Nop()) zetacoreClient := mocks.NewMockZetacoreClient() tss := mocks.NewTSSMainnet() @@ -34,7 +35,7 @@ func createObserver(t *testing.T) *base.Observer { ob, err := base.NewObserver( chain, chainParams, - zetacoreContext, + appContext, zetacoreClient, tss, base.DefaultBlockCacheSize, @@ -51,7 +52,7 @@ func TestNewObserver(t *testing.T) { // constructor parameters chain := chains.Ethereum chainParams := *sample.ChainParams(chain.ChainId) - zetacoreContext := context.NewZetacoreContext(config.NewConfig()) + appContext := context.New(config.NewConfig(), zerolog.Nop()) zetacoreClient := mocks.NewMockZetacoreClient() tss := mocks.NewTSSMainnet() blockCacheSize := base.DefaultBlockCacheSize @@ -62,7 +63,7 @@ func TestNewObserver(t *testing.T) { name string chain chains.Chain chainParams observertypes.ChainParams - zetacoreContext *context.ZetacoreContext + appContext *context.AppContext zetacoreClient interfaces.ZetacoreClient tss interfaces.TSSSigner blockCacheSize int @@ -74,7 +75,7 @@ func TestNewObserver(t *testing.T) { name: "should be able to create new observer", chain: chain, chainParams: chainParams, - zetacoreContext: zetacoreContext, + appContext: appContext, zetacoreClient: zetacoreClient, tss: tss, blockCacheSize: blockCacheSize, @@ -85,7 +86,7 @@ func TestNewObserver(t *testing.T) { name: "should return error on invalid block cache size", chain: chain, chainParams: chainParams, - zetacoreContext: zetacoreContext, + appContext: appContext, zetacoreClient: zetacoreClient, tss: tss, blockCacheSize: 0, @@ -97,7 +98,7 @@ func TestNewObserver(t *testing.T) { name: "should return error on invalid header cache size", chain: chain, chainParams: chainParams, - zetacoreContext: zetacoreContext, + appContext: appContext, zetacoreClient: zetacoreClient, tss: tss, blockCacheSize: blockCacheSize, @@ -113,7 +114,7 @@ func TestNewObserver(t *testing.T) { ob, err := base.NewObserver( tt.chain, tt.chainParams, - tt.zetacoreContext, + tt.appContext, tt.zetacoreClient, tt.tss, tt.blockCacheSize, @@ -161,14 +162,6 @@ func TestObserverGetterAndSetter(t *testing.T) { ob = ob.WithChainParams(newChainParams) require.True(t, observertypes.ChainParamsEqual(newChainParams, ob.ChainParams())) }) - t.Run("should be able to update zetacore context", func(t *testing.T) { - ob := createObserver(t) - - // update zetacore context - newZetacoreContext := context.NewZetacoreContext(config.NewConfig()) - ob = ob.WithZetacoreContext(newZetacoreContext) - require.Equal(t, newZetacoreContext, ob.ZetacoreContext()) - }) t.Run("should be able to update zetacore client", func(t *testing.T) { ob := createObserver(t) diff --git a/zetaclient/chains/base/signer.go b/zetaclient/chains/base/signer.go index bc5ad7934f..0fc9ca4837 100644 --- a/zetaclient/chains/base/signer.go +++ b/zetaclient/chains/base/signer.go @@ -15,8 +15,7 @@ type Signer struct { // chain contains static information about the external chain chain chains.Chain - // zetacoreContext is the Zetacore client to interact with ZetaChain - zetacoreContext *context.ZetacoreContext + appContext *context.AppContext // tss is the TSS signer tss interfaces.TSSSigner @@ -35,16 +34,16 @@ type Signer struct { // NewSigner creates a new base signer func NewSigner( chain chains.Chain, - zetacoreContext *context.ZetacoreContext, + zetacoreContext *context.AppContext, tss interfaces.TSSSigner, ts *metrics.TelemetryServer, logger Logger, ) *Signer { return &Signer{ - chain: chain, - zetacoreContext: zetacoreContext, - tss: tss, - ts: ts, + chain: chain, + appContext: zetacoreContext, + tss: tss, + ts: ts, logger: Logger{ Std: logger.Std.With().Int64("chain", chain.ChainId).Str("module", "signer").Logger(), Compliance: logger.Compliance, @@ -63,15 +62,9 @@ func (s *Signer) WithChain(chain chains.Chain) *Signer { return s } -// ZetacoreContext returns the zetacore context for the signer -func (s *Signer) ZetacoreContext() *context.ZetacoreContext { - return s.zetacoreContext -} - -// WithZetacoreContext attaches a new zetacore context to the signer -func (s *Signer) WithZetacoreContext(context *context.ZetacoreContext) *Signer { - s.zetacoreContext = context - return s +// AppContext returns the zetacore context for the signer +func (s *Signer) AppContext() *context.AppContext { + return s.appContext } // Tss returns the tss signer for the signer diff --git a/zetaclient/chains/base/signer_test.go b/zetaclient/chains/base/signer_test.go index 960c508d6e..a0e2696b92 100644 --- a/zetaclient/chains/base/signer_test.go +++ b/zetaclient/chains/base/signer_test.go @@ -3,6 +3,7 @@ package base_test import ( "testing" + "github.com/rs/zerolog" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/pkg/chains" @@ -17,12 +18,12 @@ import ( func createSigner(_ *testing.T) *base.Signer { // constructor parameters chain := chains.Ethereum - zetacoreContext := context.NewZetacoreContext(config.NewConfig()) + appContext := context.New(config.NewConfig(), zerolog.Nop()) tss := mocks.NewTSSMainnet() logger := base.DefaultLogger() // create signer - return base.NewSigner(chain, zetacoreContext, tss, nil, logger) + return base.NewSigner(chain, appContext, tss, nil, logger) } func TestNewSigner(t *testing.T) { @@ -39,14 +40,6 @@ func TestSignerGetterAndSetter(t *testing.T) { signer = signer.WithChain(chains.BscMainnet) require.Equal(t, newChain, signer.Chain()) }) - t.Run("should be able to update zetacore context", func(t *testing.T) { - signer := createSigner(t) - - // update zetacore context - newZetacoreContext := context.NewZetacoreContext(config.NewConfig()) - signer = signer.WithZetacoreContext(newZetacoreContext) - require.Equal(t, newZetacoreContext, signer.ZetacoreContext()) - }) t.Run("should be able to update tss", func(t *testing.T) { signer := createSigner(t) diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index 037fd11cd1..1d528a7c62 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -20,7 +20,6 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" "github.com/zeta-chain/zetacore/zetaclient/compliance" "github.com/zeta-chain/zetacore/zetaclient/config" - "github.com/zeta-chain/zetacore/zetaclient/context" "github.com/zeta-chain/zetacore/zetaclient/types" "github.com/zeta-chain/zetacore/zetaclient/zetacore" ) @@ -43,7 +42,7 @@ func (ob *Observer) WatchInbound() { for { select { case <-ticker.C(): - if !context.IsInboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { + if !ob.AppContext().IsInboundObservationEnabled(ob.GetChainParams()) { sampledLogger.Info(). Msgf("WatchInbound: inbound observation is disabled for chain %d", ob.Chain().ChainId) continue @@ -109,7 +108,7 @@ func (ob *Observer) ObserveInbound() error { // https://github.com/zeta-chain/node/issues/1847 // TODO: move this logic in its own routine // https://github.com/zeta-chain/node/issues/2204 - blockHeaderVerification, found := ob.ZetacoreContext().GetBlockHeaderEnabledChains(ob.Chain().ChainId) + blockHeaderVerification, found := ob.AppContext().GetBlockHeaderEnabledChains(ob.Chain().ChainId) if found && blockHeaderVerification.Enabled { // #nosec G701 always in range err = ob.postBlockHeader(int64(blockNumber)) @@ -187,7 +186,7 @@ func (ob *Observer) WatchInboundTracker() { for { select { case <-ticker.C(): - if !context.IsInboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { + if !ob.AppContext().IsInboundObservationEnabled(ob.GetChainParams()) { continue } err := ob.ProcessInboundTrackers() diff --git a/zetaclient/chains/bitcoin/observer/observer.go b/zetaclient/chains/bitcoin/observer/observer.go index 11ccc5460a..a04188da80 100644 --- a/zetaclient/chains/bitcoin/observer/observer.go +++ b/zetaclient/chains/bitcoin/observer/observer.go @@ -112,7 +112,7 @@ func NewObserver( chain chains.Chain, btcClient interfaces.BTCRPCClient, chainParams observertypes.ChainParams, - zetacoreContext *context.ZetacoreContext, + appContext *context.AppContext, zetacoreClient interfaces.ZetacoreClient, tss interfaces.TSSSigner, dbpath string, @@ -123,7 +123,7 @@ func NewObserver( baseObserver, err := base.NewObserver( chain, chainParams, - zetacoreContext, + appContext, zetacoreClient, tss, btcBlocksPerDay, diff --git a/zetaclient/chains/bitcoin/observer/observer_test.go b/zetaclient/chains/bitcoin/observer/observer_test.go index c79209e3fc..8fb8838ae3 100644 --- a/zetaclient/chains/bitcoin/observer/observer_test.go +++ b/zetaclient/chains/bitcoin/observer/observer_test.go @@ -113,7 +113,7 @@ func Test_NewObserver(t *testing.T) { chain chains.Chain btcClient interfaces.BTCRPCClient chainParams observertypes.ChainParams - coreContext *context.ZetacoreContext + appContext *context.AppContext coreClient interfaces.ZetacoreClient tss interfaces.TSSSigner dbpath string @@ -127,7 +127,7 @@ func Test_NewObserver(t *testing.T) { chain: chain, btcClient: mocks.NewMockBTCRPCClient().WithBlockCount(100), chainParams: params, - coreContext: nil, + appContext: nil, coreClient: nil, tss: mocks.NewTSSMainnet(), dbpath: sample.CreateTempDir(t), @@ -140,7 +140,7 @@ func Test_NewObserver(t *testing.T) { chain: chains.Chain{ChainId: 111}, // invalid chain id btcClient: mocks.NewMockBTCRPCClient().WithBlockCount(100), chainParams: params, - coreContext: nil, + appContext: nil, coreClient: nil, tss: mocks.NewTSSMainnet(), dbpath: sample.CreateTempDir(t), @@ -153,7 +153,7 @@ func Test_NewObserver(t *testing.T) { name: "should fail on invalid dbpath", chain: chain, chainParams: params, - coreContext: nil, + appContext: nil, coreClient: nil, btcClient: mocks.NewMockBTCRPCClient().WithBlockCount(100), tss: mocks.NewTSSMainnet(), @@ -173,7 +173,7 @@ func Test_NewObserver(t *testing.T) { tt.chain, tt.btcClient, tt.chainParams, - tt.coreContext, + tt.appContext, tt.coreClient, tt.tss, tt.dbpath, diff --git a/zetaclient/chains/bitcoin/observer/outbound.go b/zetaclient/chains/bitcoin/observer/outbound.go index 5f4684f50f..681604d48b 100644 --- a/zetaclient/chains/bitcoin/observer/outbound.go +++ b/zetaclient/chains/bitcoin/observer/outbound.go @@ -16,7 +16,6 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/rpc" "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" "github.com/zeta-chain/zetacore/zetaclient/compliance" - "github.com/zeta-chain/zetacore/zetaclient/context" "github.com/zeta-chain/zetacore/zetaclient/types" ) @@ -44,7 +43,7 @@ func (ob *Observer) WatchOutbound() { for { select { case <-ticker.C(): - if !context.IsOutboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { + if !ob.AppContext().IsOutboundObservationEnabled(ob.GetChainParams()) { sampledLogger.Info(). Msgf("WatchOutbound: outbound observation is disabled for chain %d", chainID) continue diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index eae11a68ce..259f55bc53 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -58,13 +58,13 @@ type Signer struct { // NewSigner creates a new Bitcoin signer func NewSigner( chain chains.Chain, - zetacoreContext *context.ZetacoreContext, + appContext *context.AppContext, tss interfaces.TSSSigner, ts *metrics.TelemetryServer, logger base.Logger, cfg config.BTCConfig) (*Signer, error) { // create base signer - baseSigner := base.NewSigner(chain, zetacoreContext, tss, ts, logger) + baseSigner := base.NewSigner(chain, appContext, tss, ts, logger) // create the bitcoin rpc client using the provided config connCfg := &rpcclient.ConnConfig{ @@ -350,7 +350,7 @@ func (signer *Signer) TryProcessOutbound( logger.Error().Msgf("chain observer is not a bitcoin observer") return } - flags := signer.ZetacoreContext().GetCrossChainFlags() + flags := signer.AppContext().GetCrossChainFlags() if !flags.IsOutboundEnabled { logger.Info().Msgf("outbound is disabled") return diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index 40844ddbd7..20823f533b 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -27,7 +27,6 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/chains/evm" "github.com/zeta-chain/zetacore/zetaclient/compliance" "github.com/zeta-chain/zetacore/zetaclient/config" - clientcontext "github.com/zeta-chain/zetacore/zetaclient/context" "github.com/zeta-chain/zetacore/zetaclient/metrics" clienttypes "github.com/zeta-chain/zetacore/zetaclient/types" "github.com/zeta-chain/zetacore/zetaclient/zetacore" @@ -52,7 +51,7 @@ func (ob *Observer) WatchInbound() { for { select { case <-ticker.C(): - if !clientcontext.IsInboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { + if !ob.AppContext().IsInboundObservationEnabled(ob.GetChainParams()) { sampledLogger.Info(). Msgf("WatchInbound: inbound observation is disabled for chain %d", ob.Chain().ChainId) continue @@ -87,7 +86,7 @@ func (ob *Observer) WatchInboundTracker() { for { select { case <-ticker.C(): - if !clientcontext.IsInboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { + if !ob.AppContext().IsInboundObservationEnabled(ob.GetChainParams()) { continue } err := ob.ProcessInboundTrackers() @@ -395,7 +394,7 @@ func (ob *Observer) ObserverTSSReceive(startBlock, toBlock uint64) uint64 { // post new block header (if any) to zetacore and ignore error // TODO: consider having a independent ticker(from TSS scaning) for posting block headers // https://github.com/zeta-chain/node/issues/1847 - blockHeaderVerification, found := ob.ZetacoreContext().GetBlockHeaderEnabledChains(ob.Chain().ChainId) + blockHeaderVerification, found := ob.AppContext().GetBlockHeaderEnabledChains(ob.Chain().ChainId) if found && blockHeaderVerification.Enabled { // post block header for supported chains // TODO: move this logic in its own routine @@ -659,7 +658,7 @@ func (ob *Observer) BuildInboundVoteMsgForZetaSentEvent( } if !destChain.IsZetaChain() { - paramsDest, found := ob.ZetacoreContext().GetEVMChainParams(destChain.ChainId) + paramsDest, found := ob.AppContext().GetEVMChainParams(destChain.ChainId) if !found { ob.Logger().Inbound.Warn(). Msgf("chain id not present in EVMChainParams %d", event.DestinationChainId.Int64()) diff --git a/zetaclient/chains/evm/observer/observer.go b/zetaclient/chains/evm/observer/observer.go index 0a33603196..3a60b16e40 100644 --- a/zetaclient/chains/evm/observer/observer.go +++ b/zetaclient/chains/evm/observer/observer.go @@ -58,7 +58,7 @@ func NewObserver( evmCfg config.EVMConfig, evmClient interfaces.EVMRPCClient, chainParams observertypes.ChainParams, - zetacoreContext *clientcontext.ZetacoreContext, + appClient *clientcontext.AppContext, zetacoreClient interfaces.ZetacoreClient, tss interfaces.TSSSigner, dbpath string, @@ -69,7 +69,7 @@ func NewObserver( baseObserver, err := base.NewObserver( evmCfg.Chain, chainParams, - zetacoreContext, + appClient, zetacoreClient, tss, base.DefaultBlockCacheSize, diff --git a/zetaclient/chains/evm/observer/observer_test.go b/zetaclient/chains/evm/observer/observer_test.go index f149d1bae2..6cb97dd65d 100644 --- a/zetaclient/chains/evm/observer/observer_test.go +++ b/zetaclient/chains/evm/observer/observer_test.go @@ -37,7 +37,7 @@ func getZetacoreContext( evmChain chains.Chain, endpoint string, evmChainParams *observertypes.ChainParams, -) (*context.ZetacoreContext, config.EVMConfig) { +) (*context.AppContext, config.EVMConfig) { // use default endpoint if not provided if endpoint == "" { endpoint = "http://localhost:8545" @@ -51,12 +51,12 @@ func getZetacoreContext( } // create zetacore context - coreCtx := context.NewZetacoreContext(cfg) + appContext := context.New(cfg, zerolog.Nop()) evmChainParamsMap := make(map[int64]*observertypes.ChainParams) evmChainParamsMap[evmChain.ChainId] = evmChainParams // feed chain params - coreCtx.Update( + appContext.Update( &observertypes.Keygen{}, []chains.Chain{evmChain}, evmChainParamsMap, @@ -65,10 +65,9 @@ func getZetacoreContext( *sample.CrosschainFlags(), sample.HeaderSupportedChains(), true, - zerolog.Logger{}, ) // create app context - return coreCtx, cfg.EVMChainConfigs[evmChain.ChainId] + return appContext, cfg.EVMChainConfigs[evmChain.ChainId] } // MockEVMObserver creates a mock ChainObserver with custom chain, TSS, params etc diff --git a/zetaclient/chains/evm/observer/outbound.go b/zetaclient/chains/evm/observer/outbound.go index 2f3d3c136f..84103620dd 100644 --- a/zetaclient/chains/evm/observer/outbound.go +++ b/zetaclient/chains/evm/observer/outbound.go @@ -23,7 +23,6 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/chains/evm" "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" "github.com/zeta-chain/zetacore/zetaclient/compliance" - clientcontext "github.com/zeta-chain/zetacore/zetaclient/context" clienttypes "github.com/zeta-chain/zetacore/zetaclient/types" ) @@ -52,7 +51,7 @@ func (ob *Observer) WatchOutbound() { for { select { case <-ticker.C(): - if !clientcontext.IsOutboundObservationEnabled(ob.ZetacoreContext(), ob.GetChainParams()) { + if !ob.AppContext().IsOutboundObservationEnabled(ob.GetChainParams()) { sampledLogger.Info(). Msgf("WatchOutbound: outbound observation is disabled for chain %d", ob.Chain().ChainId) continue diff --git a/zetaclient/chains/evm/signer/signer.go b/zetaclient/chains/evm/signer/signer.go index 3ea7852766..8bba72d777 100644 --- a/zetaclient/chains/evm/signer/signer.go +++ b/zetaclient/chains/evm/signer/signer.go @@ -82,7 +82,7 @@ type Signer struct { // NewSigner creates a new EVM signer func NewSigner( chain chains.Chain, - zetacoreContext *clientcontext.ZetacoreContext, + appContext *clientcontext.AppContext, tss interfaces.TSSSigner, ts *metrics.TelemetryServer, logger base.Logger, @@ -93,7 +93,7 @@ func NewSigner( erc20CustodyAddress ethcommon.Address, ) (*Signer, error) { // create base signer - baseSigner := base.NewSigner(chain, zetacoreContext, tss, ts, logger) + baseSigner := base.NewSigner(chain, appContext, tss, ts, logger) // create EVM client client, ethSigner, err := getEVMRPC(endpoint) @@ -376,7 +376,7 @@ func (signer *Signer) TryProcessOutbound( toChain := chains.GetChainFromChainID(txData.toChainID.Int64()) // Get cross-chain flags - crossChainflags := signer.ZetacoreContext().GetCrossChainFlags() + crossChainflags := signer.AppContext().GetCrossChainFlags() // https://github.com/zeta-chain/node/issues/2050 var tx *ethtypes.Transaction // compliance check goes first diff --git a/zetaclient/chains/evm/signer/signer_test.go b/zetaclient/chains/evm/signer/signer_test.go index ea27152b97..13aaac87b1 100644 --- a/zetaclient/chains/evm/signer/signer_test.go +++ b/zetaclient/chains/evm/signer/signer_test.go @@ -47,7 +47,7 @@ func getNewEvmSigner(tss interfaces.TSSSigner) (*Signer, error) { return NewSigner( chains.BscMainnet, - context.NewZetacoreContext(cfg), + context.New(cfg, zerolog.Nop()), tss, nil, logger, @@ -71,7 +71,7 @@ func getNewEvmChainObserver(t *testing.T, tss interfaces.TSSSigner) (*observer.O evmClient := mocks.NewMockEvmClient().WithBlockNumber(1000) params := mocks.MockChainParams(evmcfg.Chain.ChainId, 10) cfg.EVMChainConfigs[chains.BscMainnet.ChainId] = evmcfg - coreCTX := context.NewZetacoreContext(cfg) + appContext := context.New(cfg, zerolog.Nop()) dbpath := sample.CreateTempDir(t) logger := base.Logger{} ts := &metrics.TelemetryServer{} @@ -80,7 +80,7 @@ func getNewEvmChainObserver(t *testing.T, tss interfaces.TSSSigner) (*observer.O evmcfg, evmClient, params, - coreCTX, + appContext, mocks.NewMockZetacoreClient(), tss, dbpath, diff --git a/zetaclient/config/config_chain.go b/zetaclient/config/config_chain.go index 5c2ed1d077..5946c4ca62 100644 --- a/zetaclient/config/config_chain.go +++ b/zetaclient/config/config_chain.go @@ -1,6 +1,10 @@ package config -import "github.com/zeta-chain/zetacore/pkg/chains" +import ( + "sync" + + "github.com/zeta-chain/zetacore/pkg/chains" +) const ( MaxBlocksPerPeriod = 100 @@ -32,6 +36,7 @@ func GetERC20CustodyABI() string { // It is initialize with default chain configs func New() Config { return Config{ + cfgLock: &sync.RWMutex{}, EVMChainConfigs: evmChainsConfigs, BitcoinConfig: bitcoinConfigRegnet, } diff --git a/zetaclient/context/app.go b/zetaclient/context/app.go new file mode 100644 index 0000000000..c40e769492 --- /dev/null +++ b/zetaclient/context/app.go @@ -0,0 +1,287 @@ +// Package context provides global app context for ZetaClient +package context + +import ( + "sort" + "sync" + + "github.com/rs/zerolog" + + "github.com/zeta-chain/zetacore/pkg/chains" + lightclienttypes "github.com/zeta-chain/zetacore/x/lightclient/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" + "github.com/zeta-chain/zetacore/zetaclient/config" +) + +// AppContext represents application context. +type AppContext struct { + config config.Config + logger zerolog.Logger + + keygen observertypes.Keygen + chainsEnabled []chains.Chain + evmChainParams map[int64]*observertypes.ChainParams + bitcoinChainParams *observertypes.ChainParams + currentTssPubkey string + crosschainFlags observertypes.CrosschainFlags + + // blockHeaderEnabledChains is used to store the list of chains that have block header verification enabled + // All chains in this list will have Enabled flag set to true + blockHeaderEnabledChains []lightclienttypes.HeaderSupportedChain + + mu sync.RWMutex +} + +// New creates and returns new AppContext +func New(cfg config.Config, logger zerolog.Logger) *AppContext { + evmChainParams := make(map[int64]*observertypes.ChainParams) + for _, e := range cfg.EVMChainConfigs { + evmChainParams[e.Chain.ChainId] = &observertypes.ChainParams{} + } + + var bitcoinChainParams *observertypes.ChainParams + _, found := cfg.GetBTCConfig() + if found { + bitcoinChainParams = &observertypes.ChainParams{} + } + + return &AppContext{ + config: cfg, + logger: logger.With().Str("module", "appcontext").Logger(), + + chainsEnabled: []chains.Chain{}, + evmChainParams: evmChainParams, + bitcoinChainParams: bitcoinChainParams, + crosschainFlags: observertypes.CrosschainFlags{}, + blockHeaderEnabledChains: []lightclienttypes.HeaderSupportedChain{}, + + currentTssPubkey: "", + keygen: observertypes.Keygen{}, + mu: sync.RWMutex{}, + } +} + +// Config returns the config of the app +func (a *AppContext) Config() config.Config { + return a.config +} + +// GetBTCChainAndConfig returns btc chain and config if enabled +func (a *AppContext) GetBTCChainAndConfig() (chains.Chain, config.BTCConfig, bool) { + btcConfig, configEnabled := a.Config().GetBTCConfig() + btcChain, _, paramsEnabled := a.GetBTCChainParams() + + if !configEnabled || !paramsEnabled { + return chains.Chain{}, config.BTCConfig{}, false + } + + return btcChain, btcConfig, true +} + +// IsOutboundObservationEnabled returns true if the chain is supported and outbound flag is enabled +func (a *AppContext) IsOutboundObservationEnabled(chainParams observertypes.ChainParams) bool { + flags := a.GetCrossChainFlags() + return chainParams.IsSupported && flags.IsOutboundEnabled +} + +// IsInboundObservationEnabled returns true if the chain is supported and inbound flag is enabled +func (a *AppContext) IsInboundObservationEnabled(chainParams observertypes.ChainParams) bool { + flags := a.GetCrossChainFlags() + return chainParams.IsSupported && flags.IsInboundEnabled +} + +// GetKeygen returns the current keygen +func (a *AppContext) GetKeygen() observertypes.Keygen { + a.mu.RLock() + defer a.mu.RUnlock() + + var copiedPubkeys []string + if a.keygen.GranteePubkeys != nil { + copiedPubkeys = make([]string, len(a.keygen.GranteePubkeys)) + copy(copiedPubkeys, a.keygen.GranteePubkeys) + } + + return observertypes.Keygen{ + Status: a.keygen.Status, + GranteePubkeys: copiedPubkeys, + BlockNumber: a.keygen.BlockNumber, + } +} + +// GetCurrentTssPubKey returns the current tss pubkey +func (a *AppContext) GetCurrentTssPubKey() string { + a.mu.RLock() + defer a.mu.RUnlock() + + return a.currentTssPubkey +} + +// GetEnabledChains returns all enabled chains including zetachain +func (a *AppContext) GetEnabledChains() []chains.Chain { + a.mu.RLock() + defer a.mu.RUnlock() + + copiedChains := make([]chains.Chain, len(a.chainsEnabled)) + copy(copiedChains, a.chainsEnabled) + + return copiedChains +} + +// GetEnabledExternalChains returns all enabled external chains +func (a *AppContext) GetEnabledExternalChains() []chains.Chain { + a.mu.RLock() + defer a.mu.RUnlock() + + externalChains := make([]chains.Chain, 0) + for _, chain := range a.chainsEnabled { + if chain.IsExternal { + externalChains = append(externalChains, chain) + } + } + return externalChains +} + +// GetEVMChainParams returns chain params for a specific EVM chain +func (a *AppContext) GetEVMChainParams(chainID int64) (*observertypes.ChainParams, bool) { + a.mu.RLock() + defer a.mu.RUnlock() + + evmChainParams, found := a.evmChainParams[chainID] + return evmChainParams, found +} + +// GetAllEVMChainParams returns all chain params for EVM chains +func (a *AppContext) GetAllEVMChainParams() map[int64]*observertypes.ChainParams { + a.mu.RLock() + defer a.mu.RUnlock() + + // deep copy evm chain params + copied := make(map[int64]*observertypes.ChainParams, len(a.evmChainParams)) + for chainID, evmConfig := range a.evmChainParams { + copied[chainID] = &observertypes.ChainParams{} + *copied[chainID] = *evmConfig + } + return copied +} + +// GetBTCChainParams returns (chain, chain params, found) for bitcoin chain +func (a *AppContext) GetBTCChainParams() (chains.Chain, *observertypes.ChainParams, bool) { + a.mu.RLock() + defer a.mu.RUnlock() + + if a.bitcoinChainParams == nil { // bitcoin is not enabled + return chains.Chain{}, nil, false + } + + chain := chains.GetChainFromChainID(a.bitcoinChainParams.ChainId) + if chain == nil { + return chains.Chain{}, nil, false + } + + return *chain, a.bitcoinChainParams, true +} + +// GetCrossChainFlags returns crosschain flags +func (a *AppContext) GetCrossChainFlags() observertypes.CrosschainFlags { + a.mu.RLock() + defer a.mu.RUnlock() + + return a.crosschainFlags +} + +// GetAllHeaderEnabledChains returns all verification flags +func (a *AppContext) GetAllHeaderEnabledChains() []lightclienttypes.HeaderSupportedChain { + a.mu.RLock() + defer a.mu.RUnlock() + + return a.blockHeaderEnabledChains +} + +// GetBlockHeaderEnabledChains checks if block header verification is enabled for a specific chain +func (a *AppContext) GetBlockHeaderEnabledChains(chainID int64) (lightclienttypes.HeaderSupportedChain, bool) { + a.mu.RLock() + defer a.mu.RUnlock() + + for _, flags := range a.blockHeaderEnabledChains { + if flags.ChainId == chainID { + return flags, true + } + } + + return lightclienttypes.HeaderSupportedChain{}, false +} + +// Update updates zetacore context and params for all chains +// this must be the ONLY function that writes to zetacore context +func (a *AppContext) Update( + keygen *observertypes.Keygen, + newChains []chains.Chain, + evmChainParams map[int64]*observertypes.ChainParams, + btcChainParams *observertypes.ChainParams, + tssPubKey string, + crosschainFlags observertypes.CrosschainFlags, + blockHeaderEnabledChains []lightclienttypes.HeaderSupportedChain, + init bool, +) { + // Ignore whatever order zetacore organizes chain list in state + sort.SliceStable(newChains, func(i, j int) bool { + return newChains[i].ChainId < newChains[j].ChainId + }) + + if len(newChains) == 0 { + a.logger.Warn().Msg("UpdateChainParams: No chains enabled in ZeroCore") + } + + a.mu.Lock() + defer a.mu.Unlock() + + // Add some warnings if chain list changes at runtime + if !init && !chainsEqual(a.chainsEnabled, newChains) { + a.logger.Warn(). + Interface("chains.current", a.chainsEnabled). + Interface("chains.new", newChains). + Msg("UpdateChainParams: ChainsEnabled changed at runtime!") + } + + if keygen != nil { + a.keygen = *keygen + } + + a.chainsEnabled = newChains + a.crosschainFlags = crosschainFlags + a.blockHeaderEnabledChains = blockHeaderEnabledChains + + // update chain params for bitcoin if it has config in file + if a.bitcoinChainParams != nil && btcChainParams != nil { + a.bitcoinChainParams = btcChainParams + } + + // update core params for evm chains we have configs in file + for _, params := range evmChainParams { + _, found := a.evmChainParams[params.ChainId] + if !found { + continue + } + a.evmChainParams[params.ChainId] = params + } + + if tssPubKey != "" { + a.currentTssPubkey = tssPubKey + } +} + +func chainsEqual(a []chains.Chain, b []chains.Chain) bool { + if len(a) != len(b) { + return false + } + + for i, left := range a { + right := b[i] + + if left.ChainId != right.ChainId || left.ChainName != right.ChainName { + return false + } + } + + return true +} diff --git a/zetaclient/context/app_context.go b/zetaclient/context/app_context.go deleted file mode 100644 index ffdfa05604..0000000000 --- a/zetaclient/context/app_context.go +++ /dev/null @@ -1,46 +0,0 @@ -// Package context provides global app context for ZetaClient -package context - -import ( - "github.com/zeta-chain/zetacore/pkg/chains" - "github.com/zeta-chain/zetacore/zetaclient/config" -) - -// AppContext contains global app structs like config, zetacore context and logger -type AppContext struct { - coreContext *ZetacoreContext - config config.Config -} - -// NewAppContext creates and returns new AppContext -func NewAppContext( - coreContext *ZetacoreContext, - config config.Config, -) *AppContext { - return &AppContext{ - coreContext: coreContext, - config: config, - } -} - -// Config returns the config of the app -func (a AppContext) Config() config.Config { - return a.config -} - -// ZetacoreContext returns the context for ZetaChain -func (a AppContext) ZetacoreContext() *ZetacoreContext { - return a.coreContext -} - -// GetBTCChainAndConfig returns btc chain and config if enabled -func (a AppContext) GetBTCChainAndConfig() (chains.Chain, config.BTCConfig, bool) { - btcConfig, configEnabled := a.Config().GetBTCConfig() - btcChain, _, paramsEnabled := a.coreContext.GetBTCChainParams() - - if !configEnabled || !paramsEnabled { - return chains.Chain{}, config.BTCConfig{}, false - } - - return btcChain, btcConfig, true -} diff --git a/zetaclient/context/app_context_test.go b/zetaclient/context/app_context_test.go deleted file mode 100644 index 960b2b7c5a..0000000000 --- a/zetaclient/context/app_context_test.go +++ /dev/null @@ -1 +0,0 @@ -package context_test diff --git a/zetaclient/context/zetacore_context_test.go b/zetaclient/context/app_test.go similarity index 55% rename from zetaclient/context/zetacore_context_test.go rename to zetaclient/context/app_test.go index d8117e124b..99b56c7d88 100644 --- a/zetaclient/context/zetacore_context_test.go +++ b/zetaclient/context/app_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/rs/zerolog" - "github.com/rs/zerolog/log" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/pkg/chains" @@ -12,68 +12,40 @@ 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/config" - context "github.com/zeta-chain/zetacore/zetaclient/context" + "github.com/zeta-chain/zetacore/zetaclient/context" ) -func getTestCoreContext( - evmChain chains.Chain, - evmChainParams *observertypes.ChainParams, - ccFlags observertypes.CrosschainFlags, - headerSupportedChains []lightclienttypes.HeaderSupportedChain, -) *context.ZetacoreContext { - // create config - cfg := config.NewConfig() - cfg.EVMChainConfigs[evmChain.ChainId] = config.EVMConfig{ - Chain: evmChain, - } - // create zetacore context - coreContext := context.NewZetacoreContext(cfg) - evmChainParamsMap := make(map[int64]*observertypes.ChainParams) - evmChainParamsMap[evmChain.ChainId] = evmChainParams - - // feed chain params - coreContext.Update( - &observertypes.Keygen{}, - []chains.Chain{evmChain}, - evmChainParamsMap, - nil, - "", - ccFlags, - headerSupportedChains, - true, - zerolog.Logger{}, +func TestNew(t *testing.T) { + var ( + testCfg = config.NewConfig() + logger = zerolog.Nop() ) - return coreContext -} -func TestNewZetaCoreContext(t *testing.T) { t.Run("should create new zetacore context with empty config", func(t *testing.T) { - testCfg := config.NewConfig() - - zetaContext := context.NewZetacoreContext(testCfg) - require.NotNil(t, zetaContext) + appContext := context.New(testCfg, logger) + require.NotNil(t, appContext) // assert keygen - keyGen := zetaContext.GetKeygen() + keyGen := appContext.GetKeygen() require.Equal(t, observertypes.Keygen{}, keyGen) // assert enabled chains - require.Empty(t, len(zetaContext.GetEnabledChains())) + require.Empty(t, len(appContext.GetEnabledChains())) // assert external chains - require.Empty(t, len(zetaContext.GetEnabledExternalChains())) + require.Empty(t, len(appContext.GetEnabledExternalChains())) // assert current tss pubkey - require.Equal(t, "", zetaContext.GetCurrentTssPubkey()) + require.Equal(t, "", appContext.GetCurrentTssPubKey()) // assert btc chain params - chain, btcChainParams, btcChainParamsFound := zetaContext.GetBTCChainParams() + chain, btcChainParams, btcChainParamsFound := appContext.GetBTCChainParams() require.Equal(t, chains.Chain{}, chain) require.False(t, btcChainParamsFound) require.Nil(t, btcChainParams) // assert evm chain params - allEVMChainParams := zetaContext.GetAllEVMChainParams() + allEVMChainParams := appContext.GetAllEVMChainParams() require.Empty(t, allEVMChainParams) }) @@ -86,11 +58,11 @@ func TestNewZetaCoreContext(t *testing.T) { } // create zetacore context with 0 chain id - zetaContext := context.NewZetacoreContext(testCfg) - require.NotNil(t, zetaContext) + appContext := context.New(testCfg, logger) + require.NotNil(t, appContext) // assert btc chain params - chain, btcChainParams, btcChainParamsFound := zetaContext.GetBTCChainParams() + chain, btcChainParams, btcChainParamsFound := appContext.GetBTCChainParams() require.Equal(t, chains.Chain{}, chain) require.False(t, btcChainParamsFound) require.Nil(t, btcChainParams) @@ -112,20 +84,20 @@ func TestNewZetaCoreContext(t *testing.T) { }, }, } - zetaContext := context.NewZetacoreContext(testCfg) - require.NotNil(t, zetaContext) + appContext := context.New(testCfg, logger) + require.NotNil(t, appContext) // assert evm chain params - allEVMChainParams := zetaContext.GetAllEVMChainParams() + allEVMChainParams := appContext.GetAllEVMChainParams() require.Equal(t, 2, len(allEVMChainParams)) require.Equal(t, &observertypes.ChainParams{}, allEVMChainParams[1]) require.Equal(t, &observertypes.ChainParams{}, allEVMChainParams[2]) - evmChainParams1, found := zetaContext.GetEVMChainParams(1) + evmChainParams1, found := appContext.GetEVMChainParams(1) require.True(t, found) require.Equal(t, &observertypes.ChainParams{}, evmChainParams1) - evmChainParams2, found := zetaContext.GetEVMChainParams(2) + evmChainParams2, found := appContext.GetEVMChainParams(2) require.True(t, found) require.Equal(t, &observertypes.ChainParams{}, evmChainParams2) }) @@ -138,17 +110,20 @@ func TestNewZetaCoreContext(t *testing.T) { RPCHost: "test host", RPCParams: "test params", } - zetaContext := context.NewZetacoreContext(testCfg) - require.NotNil(t, zetaContext) + appContext := context.New(testCfg, logger) + require.NotNil(t, appContext) }) } -func TestUpdateZetacoreContext(t *testing.T) { - t.Run("should update zetacore context after being created from empty config", func(t *testing.T) { - testCfg := config.NewConfig() +func TestAppContextUpdate(t *testing.T) { + var ( + testCfg = config.NewConfig() + logger = zerolog.Nop() + ) - zetaContext := context.NewZetacoreContext(testCfg) - require.NotNil(t, zetaContext) + t.Run("should update zetacore context after being created from empty config", func(t *testing.T) { + appContext := context.New(testCfg, logger) + require.NotNil(t, appContext) keyGenToUpdate := observertypes.Keygen{ Status: observertypes.KeygenStatus_KeyGenSuccess, @@ -183,7 +158,7 @@ func TestUpdateZetacoreContext(t *testing.T) { verificationFlags := sample.HeaderSupportedChains() require.NotNil(t, crosschainFlags) - zetaContext.Update( + appContext.Update( &keyGenToUpdate, enabledChainsToUpdate, evmChainParamsToUpdate, @@ -192,36 +167,35 @@ func TestUpdateZetacoreContext(t *testing.T) { *crosschainFlags, verificationFlags, false, - log.Logger, ) // assert keygen updated - keyGen := zetaContext.GetKeygen() + keyGen := appContext.GetKeygen() require.Equal(t, keyGenToUpdate, keyGen) // assert enabled chains updated - require.Equal(t, enabledChainsToUpdate, zetaContext.GetEnabledChains()) + require.Equal(t, enabledChainsToUpdate, appContext.GetEnabledChains()) // assert enabled external chains - require.Equal(t, enabledChainsToUpdate[0:2], zetaContext.GetEnabledExternalChains()) + require.Equal(t, enabledChainsToUpdate[0:2], appContext.GetEnabledExternalChains()) // assert current tss pubkey updated - require.Equal(t, tssPubKeyToUpdate, zetaContext.GetCurrentTssPubkey()) + require.Equal(t, tssPubKeyToUpdate, appContext.GetCurrentTssPubKey()) // assert btc chain params still empty because they were not specified in config - chain, btcChainParams, btcChainParamsFound := zetaContext.GetBTCChainParams() + chain, btcChainParams, btcChainParamsFound := appContext.GetBTCChainParams() require.Equal(t, chains.Chain{}, chain) require.False(t, btcChainParamsFound) require.Nil(t, btcChainParams) // assert evm chain params still empty because they were not specified in config - allEVMChainParams := zetaContext.GetAllEVMChainParams() + allEVMChainParams := appContext.GetAllEVMChainParams() require.Empty(t, allEVMChainParams) - ccFlags := zetaContext.GetCrossChainFlags() + ccFlags := appContext.GetCrossChainFlags() require.Equal(t, *crosschainFlags, ccFlags) - verFlags := zetaContext.GetAllHeaderEnabledChains() + verFlags := appContext.GetAllHeaderEnabledChains() require.Equal(t, verificationFlags, verFlags) }) @@ -250,8 +224,8 @@ func TestUpdateZetacoreContext(t *testing.T) { RPCParams: "test params", } - zetaContext := context.NewZetacoreContext(testCfg) - require.NotNil(t, zetaContext) + appContext := context.New(testCfg, logger) + require.NotNil(t, appContext) keyGenToUpdate := observertypes.Keygen{ Status: observertypes.KeygenStatus_KeyGenSuccess, @@ -284,7 +258,7 @@ func TestUpdateZetacoreContext(t *testing.T) { crosschainFlags := sample.CrosschainFlags() verificationFlags := sample.HeaderSupportedChains() require.NotNil(t, crosschainFlags) - zetaContext.Update( + appContext.Update( &keyGenToUpdate, enabledChainsToUpdate, evmChainParamsToUpdate, @@ -293,41 +267,40 @@ func TestUpdateZetacoreContext(t *testing.T) { *crosschainFlags, verificationFlags, false, - log.Logger, ) // assert keygen updated - keyGen := zetaContext.GetKeygen() + keyGen := appContext.GetKeygen() require.Equal(t, keyGenToUpdate, keyGen) // assert enabled chains updated - require.Equal(t, enabledChainsToUpdate, zetaContext.GetEnabledChains()) + require.Equal(t, enabledChainsToUpdate, appContext.GetEnabledChains()) // assert current tss pubkey updated - require.Equal(t, tssPubKeyToUpdate, zetaContext.GetCurrentTssPubkey()) + require.Equal(t, tssPubKeyToUpdate, appContext.GetCurrentTssPubKey()) // assert btc chain params - chain, btcChainParams, btcChainParamsFound := zetaContext.GetBTCChainParams() + chain, btcChainParams, btcChainParamsFound := appContext.GetBTCChainParams() require.Equal(t, testBtcChain, chain) require.True(t, btcChainParamsFound) require.Equal(t, btcChainParamsToUpdate, btcChainParams) // assert evm chain params - allEVMChainParams := zetaContext.GetAllEVMChainParams() + allEVMChainParams := appContext.GetAllEVMChainParams() require.Equal(t, evmChainParamsToUpdate, allEVMChainParams) - evmChainParams1, found := zetaContext.GetEVMChainParams(1) + evmChainParams1, found := appContext.GetEVMChainParams(1) require.True(t, found) require.Equal(t, evmChainParamsToUpdate[1], evmChainParams1) - evmChainParams2, found := zetaContext.GetEVMChainParams(2) + evmChainParams2, found := appContext.GetEVMChainParams(2) require.True(t, found) require.Equal(t, evmChainParamsToUpdate[2], evmChainParams2) - ccFlags := zetaContext.GetCrossChainFlags() + ccFlags := appContext.GetCrossChainFlags() require.Equal(t, ccFlags, *crosschainFlags) - verFlags := zetaContext.GetAllHeaderEnabledChains() + verFlags := appContext.GetAllHeaderEnabledChains() require.Equal(t, verFlags, verificationFlags) }, ) @@ -344,22 +317,22 @@ func TestIsOutboundObservationEnabled(t *testing.T) { } t.Run("should return true if chain is supported and outbound flag is enabled", func(t *testing.T) { - coreCTX := getTestCoreContext(evmChain, chainParams, ccFlags, verificationFlags) - require.True(t, context.IsOutboundObservationEnabled(coreCTX, *chainParams)) + appContext := makeAppContext(evmChain, chainParams, ccFlags, verificationFlags) + + require.True(t, appContext.IsOutboundObservationEnabled(*chainParams)) }) t.Run("should return false if chain is not supported yet", func(t *testing.T) { - paramsUnsupported := &observertypes.ChainParams{ - ChainId: evmChain.ChainId, - IsSupported: false, - } - coreCTXUnsupported := getTestCoreContext(evmChain, paramsUnsupported, ccFlags, verificationFlags) - require.False(t, context.IsOutboundObservationEnabled(coreCTXUnsupported, *paramsUnsupported)) + paramsUnsupported := &observertypes.ChainParams{ChainId: evmChain.ChainId, IsSupported: false} + appContextUnsupported := makeAppContext(evmChain, paramsUnsupported, ccFlags, verificationFlags) + + require.False(t, appContextUnsupported.IsOutboundObservationEnabled(*paramsUnsupported)) }) t.Run("should return false if outbound flag is disabled", func(t *testing.T) { flagsDisabled := ccFlags flagsDisabled.IsOutboundEnabled = false - coreCTXDisabled := getTestCoreContext(evmChain, chainParams, flagsDisabled, verificationFlags) - require.False(t, context.IsOutboundObservationEnabled(coreCTXDisabled, *chainParams)) + coreContextDisabled := makeAppContext(evmChain, chainParams, flagsDisabled, verificationFlags) + + require.False(t, coreContextDisabled.IsOutboundObservationEnabled(*chainParams)) }) } @@ -374,21 +347,179 @@ func TestIsInboundObservationEnabled(t *testing.T) { } t.Run("should return true if chain is supported and inbound flag is enabled", func(t *testing.T) { - coreCTX := getTestCoreContext(evmChain, chainParams, ccFlags, verificationFlags) - require.True(t, context.IsInboundObservationEnabled(coreCTX, *chainParams)) + appContext := makeAppContext(evmChain, chainParams, ccFlags, verificationFlags) + + require.True(t, appContext.IsInboundObservationEnabled(*chainParams)) }) + t.Run("should return false if chain is not supported yet", func(t *testing.T) { - paramsUnsupported := &observertypes.ChainParams{ - ChainId: evmChain.ChainId, - IsSupported: false, - } - coreCTXUnsupported := getTestCoreContext(evmChain, paramsUnsupported, ccFlags, verificationFlags) - require.False(t, context.IsInboundObservationEnabled(coreCTXUnsupported, *paramsUnsupported)) + paramsUnsupported := &observertypes.ChainParams{ChainId: evmChain.ChainId, IsSupported: false} + appContextUnsupported := makeAppContext(evmChain, paramsUnsupported, ccFlags, verificationFlags) + + require.False(t, appContextUnsupported.IsInboundObservationEnabled(*paramsUnsupported)) }) + t.Run("should return false if inbound flag is disabled", func(t *testing.T) { flagsDisabled := ccFlags flagsDisabled.IsInboundEnabled = false - coreCTXDisabled := getTestCoreContext(evmChain, chainParams, flagsDisabled, verificationFlags) - require.False(t, context.IsInboundObservationEnabled(coreCTXDisabled, *chainParams)) + appContextDisabled := makeAppContext(evmChain, chainParams, flagsDisabled, verificationFlags) + + require.False(t, appContextDisabled.IsInboundObservationEnabled(*chainParams)) }) } + +func TestGetBTCChainAndConfig(t *testing.T) { + logger := zerolog.Nop() + + emptyConfig := config.NewConfig() + nonEmptyConfig := config.New() + + assertEmpty := func(t *testing.T, chain chains.Chain, btcConfig config.BTCConfig, enabled bool) { + assert.Empty(t, chain) + assert.Empty(t, btcConfig) + assert.False(t, enabled) + } + + for _, tt := range []struct { + name string + cfg config.Config + setup func(app *context.AppContext) + assert func(t *testing.T, chain chains.Chain, btcConfig config.BTCConfig, enabled bool) + }{ + { + name: "no btc config", + cfg: emptyConfig, + setup: nil, + assert: assertEmpty, + }, + { + name: "btc config exists, but not chain params are set", + cfg: nonEmptyConfig, + setup: nil, + assert: assertEmpty, + }, + { + name: "btc config exists but chain is invalid", + cfg: nonEmptyConfig, + setup: func(app *context.AppContext) { + app.Update( + &observertypes.Keygen{}, + []chains.Chain{}, + nil, + &observertypes.ChainParams{ChainId: 123}, + "", + observertypes.CrosschainFlags{}, + nil, + true, + ) + }, + assert: assertEmpty, + }, + { + name: "btc config exists and chain params are set", + cfg: nonEmptyConfig, + setup: func(app *context.AppContext) { + app.Update( + &observertypes.Keygen{}, + []chains.Chain{}, + nil, + &observertypes.ChainParams{ChainId: chains.BitcoinMainnet.ChainId}, + "", + observertypes.CrosschainFlags{}, + nil, + true, + ) + }, + assert: func(t *testing.T, chain chains.Chain, btcConfig config.BTCConfig, enabled bool) { + assert.Equal(t, chains.BitcoinMainnet.ChainId, chain.ChainId) + assert.Equal(t, "smoketest", btcConfig.RPCUsername) + assert.True(t, enabled) + }, + }, + } { + t.Run(tt.name, func(t *testing.T) { + // ARRANGE + // Given app context + appContext := context.New(tt.cfg, logger) + + // And optional setup + if tt.setup != nil { + tt.setup(appContext) + } + + // ACT + chain, btcConfig, enabled := appContext.GetBTCChainAndConfig() + + // ASSERT + tt.assert(t, chain, btcConfig, enabled) + }) + } +} + +func TestGetBlockHeaderEnabledChains(t *testing.T) { + // ARRANGE + // Given app config + appContext := context.New(config.New(), zerolog.Nop()) + + // That was eventually updated + appContext.Update( + &observertypes.Keygen{}, + []chains.Chain{}, + nil, + &observertypes.ChainParams{ChainId: chains.BitcoinMainnet.ChainId}, + "", + observertypes.CrosschainFlags{}, + []lightclienttypes.HeaderSupportedChain{ + {ChainId: 1, Enabled: true}, + }, + true, + ) + + // ACT #1 (found) + chain, found := appContext.GetBlockHeaderEnabledChains(1) + + // ASSERT #1 + assert.True(t, found) + assert.Equal(t, int64(1), chain.ChainId) + assert.True(t, chain.Enabled) + + // ACT #2 (not found) + chain, found = appContext.GetBlockHeaderEnabledChains(2) + + // ASSERT #2 + assert.False(t, found) + assert.Empty(t, chain) +} + +func makeAppContext( + evmChain chains.Chain, + evmChainParams *observertypes.ChainParams, + ccFlags observertypes.CrosschainFlags, + headerSupportedChains []lightclienttypes.HeaderSupportedChain, +) *context.AppContext { + // create config + cfg := config.NewConfig() + logger := zerolog.Nop() + cfg.EVMChainConfigs[evmChain.ChainId] = config.EVMConfig{ + Chain: evmChain, + } + + // create zetacore context + coreContext := context.New(cfg, logger) + evmChainParamsMap := make(map[int64]*observertypes.ChainParams) + evmChainParamsMap[evmChain.ChainId] = evmChainParams + + // feed chain params + coreContext.Update( + &observertypes.Keygen{}, + []chains.Chain{evmChain}, + evmChainParamsMap, + nil, + "", + ccFlags, + headerSupportedChains, + true, + ) + + return coreContext +} diff --git a/zetaclient/context/context.go b/zetaclient/context/context.go new file mode 100644 index 0000000000..3f8b6177fa --- /dev/null +++ b/zetaclient/context/context.go @@ -0,0 +1,26 @@ +package context + +import ( + goctx "context" + + "github.com/pkg/errors" +) + +type appContextKey struct{} + +var ErrNotSet = errors.New("AppContext is not set in the context.Context") + +// WithAppContext applied AppContext to standard Go context.Context. +func WithAppContext(ctx goctx.Context, app *AppContext) goctx.Context { + return goctx.WithValue(ctx, appContextKey{}, app) +} + +// FromContext extracts AppContext from context.Context +func FromContext(ctx goctx.Context) (*AppContext, error) { + app, ok := ctx.Value(appContextKey{}).(*AppContext) + if !ok || app == nil { + return nil, ErrNotSet + } + + return app, nil +} diff --git a/zetaclient/context/context_test.go b/zetaclient/context/context_test.go new file mode 100644 index 0000000000..5bde4596d6 --- /dev/null +++ b/zetaclient/context/context_test.go @@ -0,0 +1,40 @@ +package context_test + +import ( + goctx "context" + "testing" + + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/zeta-chain/zetacore/zetaclient/config" + "github.com/zeta-chain/zetacore/zetaclient/context" +) + +func TestFromContext(t *testing.T) { + // ARRANGE #1 + // Given default go ctx + ctx := goctx.Background() + + // ACT #1 + // Extract App + _, err := context.FromContext(ctx) + + // ASSERT #1 + assert.ErrorIs(t, err, context.ErrNotSet) + + // ARRANGE #2 + // Given basic app + app := context.New(config.NewConfig(), zerolog.Nop()) + + // That is included in the ctx + ctx = context.WithAppContext(ctx, app) + + // ACT #2 + app2, err := context.FromContext(ctx) + + // ASSERT #2 + assert.NoError(t, err) + assert.NotNil(t, app2) + assert.Equal(t, app, app2) + assert.NotEmpty(t, app.Config()) +} diff --git a/zetaclient/context/zetacore_context.go b/zetaclient/context/zetacore_context.go deleted file mode 100644 index 17d4cc5c3d..0000000000 --- a/zetaclient/context/zetacore_context.go +++ /dev/null @@ -1,253 +0,0 @@ -package context - -import ( - "sort" - "sync" - - "github.com/rs/zerolog" - - "github.com/zeta-chain/zetacore/pkg/chains" - lightclienttypes "github.com/zeta-chain/zetacore/x/lightclient/types" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" - "github.com/zeta-chain/zetacore/zetaclient/config" -) - -// ZetacoreContext contains zetacore context params -// these are initialized and updated at runtime at every height -type ZetacoreContext struct { - coreContextLock *sync.RWMutex - keygen observertypes.Keygen - chainsEnabled []chains.Chain - evmChainParams map[int64]*observertypes.ChainParams - bitcoinChainParams *observertypes.ChainParams - currentTssPubkey string - crosschainFlags observertypes.CrosschainFlags - - // blockHeaderEnabledChains is used to store the list of chains that have block header verification enabled - // All chains in this list will have Enabled flag set to true - blockHeaderEnabledChains []lightclienttypes.HeaderSupportedChain -} - -// NewZetacoreContext creates and returns new ZetacoreContext -// it is initializing chain params from provided config -func NewZetacoreContext(cfg config.Config) *ZetacoreContext { - evmChainParams := make(map[int64]*observertypes.ChainParams) - for _, e := range cfg.EVMChainConfigs { - evmChainParams[e.Chain.ChainId] = &observertypes.ChainParams{} - } - - var bitcoinChainParams *observertypes.ChainParams - _, found := cfg.GetBTCConfig() - if found { - bitcoinChainParams = &observertypes.ChainParams{} - } - - return &ZetacoreContext{ - coreContextLock: new(sync.RWMutex), - chainsEnabled: []chains.Chain{}, - evmChainParams: evmChainParams, - bitcoinChainParams: bitcoinChainParams, - crosschainFlags: observertypes.CrosschainFlags{}, - blockHeaderEnabledChains: []lightclienttypes.HeaderSupportedChain{}, - } -} - -// GetKeygen returns the current keygen -func (c *ZetacoreContext) GetKeygen() observertypes.Keygen { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - - var copiedPubkeys []string - if c.keygen.GranteePubkeys != nil { - copiedPubkeys = make([]string, len(c.keygen.GranteePubkeys)) - copy(copiedPubkeys, c.keygen.GranteePubkeys) - } - - return observertypes.Keygen{ - Status: c.keygen.Status, - GranteePubkeys: copiedPubkeys, - BlockNumber: c.keygen.BlockNumber, - } -} - -// GetCurrentTssPubkey returns the current tss pubkey -func (c *ZetacoreContext) GetCurrentTssPubkey() string { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - return c.currentTssPubkey -} - -// GetEnabledChains returns all enabled chains including zetachain -func (c *ZetacoreContext) GetEnabledChains() []chains.Chain { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - - copiedChains := make([]chains.Chain, len(c.chainsEnabled)) - copy(copiedChains, c.chainsEnabled) - return copiedChains -} - -// GetEnabledExternalChains returns all enabled external chains -func (c *ZetacoreContext) GetEnabledExternalChains() []chains.Chain { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - - externalChains := make([]chains.Chain, 0) - for _, chain := range c.chainsEnabled { - if chain.IsExternal { - externalChains = append(externalChains, chain) - } - } - return externalChains -} - -// GetEVMChainParams returns chain params for a specific EVM chain -func (c *ZetacoreContext) GetEVMChainParams(chainID int64) (*observertypes.ChainParams, bool) { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - - evmChainParams, found := c.evmChainParams[chainID] - return evmChainParams, found -} - -// GetAllEVMChainParams returns all chain params for EVM chains -func (c *ZetacoreContext) GetAllEVMChainParams() map[int64]*observertypes.ChainParams { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - - // deep copy evm chain params - copied := make(map[int64]*observertypes.ChainParams, len(c.evmChainParams)) - for chainID, evmConfig := range c.evmChainParams { - copied[chainID] = &observertypes.ChainParams{} - *copied[chainID] = *evmConfig - } - return copied -} - -// GetBTCChainParams returns (chain, chain params, found) for bitcoin chain -func (c *ZetacoreContext) GetBTCChainParams() (chains.Chain, *observertypes.ChainParams, bool) { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - - if c.bitcoinChainParams == nil { // bitcoin is not enabled - return chains.Chain{}, nil, false - } - - chain := chains.GetChainFromChainID(c.bitcoinChainParams.ChainId) - if chain == nil { - return chains.Chain{}, nil, false - } - - return *chain, c.bitcoinChainParams, true -} - -// GetCrossChainFlags returns crosschain flags -func (c *ZetacoreContext) GetCrossChainFlags() observertypes.CrosschainFlags { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - return c.crosschainFlags -} - -// GetAllHeaderEnabledChains returns all verification flags -func (c *ZetacoreContext) GetAllHeaderEnabledChains() []lightclienttypes.HeaderSupportedChain { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - return c.blockHeaderEnabledChains -} - -// GetBlockHeaderEnabledChains checks if block header verification is enabled for a specific chain -func (c *ZetacoreContext) GetBlockHeaderEnabledChains(chainID int64) (lightclienttypes.HeaderSupportedChain, bool) { - c.coreContextLock.RLock() - defer c.coreContextLock.RUnlock() - for _, flags := range c.blockHeaderEnabledChains { - if flags.ChainId == chainID { - return flags, true - } - } - return lightclienttypes.HeaderSupportedChain{}, false -} - -// Update updates zetacore context and params for all chains -// this must be the ONLY function that writes to zetacore context -func (c *ZetacoreContext) Update( - keygen *observertypes.Keygen, - newChains []chains.Chain, - evmChainParams map[int64]*observertypes.ChainParams, - btcChainParams *observertypes.ChainParams, - tssPubKey string, - crosschainFlags observertypes.CrosschainFlags, - blockHeaderEnabledChains []lightclienttypes.HeaderSupportedChain, - init bool, - logger zerolog.Logger, -) { - c.coreContextLock.Lock() - defer c.coreContextLock.Unlock() - - // Ignore whatever order zetacore organizes chain list in state - sort.SliceStable(newChains, func(i, j int) bool { - return newChains[i].ChainId < newChains[j].ChainId - }) - - if len(newChains) == 0 { - logger.Warn().Msg("UpdateChainParams: No chains enabled in ZeroCore") - } - - // Add some warnings if chain list changes at runtime - if !init { - if len(c.chainsEnabled) != len(newChains) { - logger.Warn().Msgf( - "UpdateChainParams: ChainsEnabled changed at runtime!! current: %v, new: %v", - c.chainsEnabled, - newChains, - ) - } else { - for i, chain := range newChains { - if chain != c.chainsEnabled[i] { - logger.Warn().Msgf( - "UpdateChainParams: ChainsEnabled changed at runtime!! current: %v, new: %v", - c.chainsEnabled, - newChains, - ) - } - } - } - } - - if keygen != nil { - c.keygen = *keygen - } - - c.chainsEnabled = newChains - c.crosschainFlags = crosschainFlags - c.blockHeaderEnabledChains = blockHeaderEnabledChains - - // update chain params for bitcoin if it has config in file - if c.bitcoinChainParams != nil && btcChainParams != nil { - c.bitcoinChainParams = btcChainParams - } - - // update core params for evm chains we have configs in file - for _, params := range evmChainParams { - _, found := c.evmChainParams[params.ChainId] - if !found { - continue - } - c.evmChainParams[params.ChainId] = params - } - - if tssPubKey != "" { - c.currentTssPubkey = tssPubKey - } -} - -// IsOutboundObservationEnabled returns true if the chain is supported and outbound flag is enabled -func IsOutboundObservationEnabled(c *ZetacoreContext, chainParams observertypes.ChainParams) bool { - flags := c.GetCrossChainFlags() - return chainParams.IsSupported && flags.IsOutboundEnabled -} - -// IsInboundObservationEnabled returns true if the chain is supported and inbound flag is enabled -func IsInboundObservationEnabled(c *ZetacoreContext, chainParams observertypes.ChainParams) bool { - flags := c.GetCrossChainFlags() - return chainParams.IsSupported && flags.IsInboundEnabled -} diff --git a/zetaclient/orchestrator/orchestrator.go b/zetaclient/orchestrator/orchestrator.go index 2c5ea2d2de..348baac514 100644 --- a/zetaclient/orchestrator/orchestrator.go +++ b/zetaclient/orchestrator/orchestrator.go @@ -127,7 +127,7 @@ func (oc *Orchestrator) MonitorCore(appContext *context.AppContext) error { // GetUpdatedSigner returns signer with updated chain parameters func (oc *Orchestrator) GetUpdatedSigner( - coreContext *context.ZetacoreContext, + appContext *context.AppContext, chainID int64, ) (interfaces.ChainSigner, error) { signer, found := oc.signerMap[chainID] @@ -136,7 +136,7 @@ func (oc *Orchestrator) GetUpdatedSigner( } // update EVM signer parameters only. BTC signer doesn't use chain parameters for now. if chains.IsEVMChain(chainID) { - evmParams, found := coreContext.GetEVMChainParams(chainID) + evmParams, found := appContext.GetEVMChainParams(chainID) if found { // update zeta connector and ERC20 custody addresses zetaConnectorAddress := ethcommon.HexToAddress(evmParams.GetConnectorContractAddress()) @@ -158,7 +158,7 @@ func (oc *Orchestrator) GetUpdatedSigner( // GetUpdatedChainObserver returns chain observer with updated chain parameters func (oc *Orchestrator) GetUpdatedChainObserver( - coreContext *context.ZetacoreContext, + appContext *context.AppContext, chainID int64, ) (interfaces.ChainObserver, error) { observer, found := oc.observerMap[chainID] @@ -168,14 +168,14 @@ func (oc *Orchestrator) GetUpdatedChainObserver( // update chain observer chain parameters curParams := observer.GetChainParams() if chains.IsEVMChain(chainID) { - evmParams, found := coreContext.GetEVMChainParams(chainID) + evmParams, found := appContext.GetEVMChainParams(chainID) if found && !observertypes.ChainParamsEqual(curParams, *evmParams) { observer.SetChainParams(*evmParams) oc.logger.Std.Info().Msgf( "updated chain params for chainID %d, new params: %v", chainID, *evmParams) } } else if chains.IsBitcoinChain(chainID) { - _, btcParams, found := coreContext.GetBTCChainParams() + _, btcParams, found := appContext.GetBTCChainParams() if found && !observertypes.ChainParamsEqual(curParams, *btcParams) { observer.SetChainParams(*btcParams) @@ -281,8 +281,7 @@ func (oc *Orchestrator) StartCctxScheduler(appContext *context.AppContext) { metrics.HotKeyBurnRate.Set(float64(oc.ts.HotKeyBurnRate.GetBurnRate().Int64())) // get supported external chains - coreContext := appContext.ZetacoreContext() - externalChains := coreContext.GetEnabledExternalChains() + externalChains := appContext.GetEnabledExternalChains() // query pending cctxs across all external chains within rate limit cctxMap, err := oc.GetPendingCctxsWithinRatelimit(externalChains) @@ -300,21 +299,21 @@ func (oc *Orchestrator) StartCctxScheduler(appContext *context.AppContext) { } // update chain parameters for signer and chain observer - signer, err := oc.GetUpdatedSigner(coreContext, c.ChainId) + signer, err := oc.GetUpdatedSigner(appContext, c.ChainId) if err != nil { oc.logger.Std.Error(). Err(err). Msgf("StartCctxScheduler: GetUpdatedSigner failed for chain %d", c.ChainId) continue } - ob, err := oc.GetUpdatedChainObserver(coreContext, c.ChainId) + ob, err := oc.GetUpdatedChainObserver(appContext, c.ChainId) if err != nil { oc.logger.Std.Error(). Err(err). Msgf("StartCctxScheduler: GetUpdatedChainObserver failed for chain %d", c.ChainId) continue } - if !context.IsOutboundObservationEnabled(coreContext, ob.GetChainParams()) { + if !appContext.IsOutboundObservationEnabled(ob.GetChainParams()) { continue } diff --git a/zetaclient/orchestrator/orchestrator_test.go b/zetaclient/orchestrator/orchestrator_test.go index 131dc29656..69930bdbcf 100644 --- a/zetaclient/orchestrator/orchestrator_test.go +++ b/zetaclient/orchestrator/orchestrator_test.go @@ -53,10 +53,10 @@ func MockOrchestrator( return orchestrator } -func CreateCoreContext( +func CreateAppContext( evmChain, btcChain chains.Chain, evmChainParams, btcChainParams *observertypes.ChainParams, -) *context.ZetacoreContext { +) *context.AppContext { // new config cfg := config.NewConfig() cfg.EVMChainConfigs[evmChain.ChainId] = config.EVMConfig{ @@ -66,14 +66,14 @@ func CreateCoreContext( RPCHost: "localhost", } // new zetacore context - coreContext := context.NewZetacoreContext(cfg) + appContext := context.New(cfg, zerolog.Nop()) evmChainParamsMap := make(map[int64]*observertypes.ChainParams) evmChainParamsMap[evmChain.ChainId] = evmChainParams ccFlags := sample.CrosschainFlags() verificationFlags := sample.HeaderSupportedChains() // feed chain params - coreContext.Update( + appContext.Update( &observertypes.Keygen{}, []chains.Chain{evmChain, btcChain}, evmChainParamsMap, @@ -82,9 +82,8 @@ func CreateCoreContext( *ccFlags, verificationFlags, true, - zerolog.Logger{}, ) - return coreContext + return appContext } func Test_GetUpdatedSigner(t *testing.T) { @@ -107,14 +106,14 @@ func Test_GetUpdatedSigner(t *testing.T) { t.Run("signer should not be found", func(t *testing.T) { orchestrator := MockOrchestrator(t, nil, evmChain, btcChain, evmChainParams, btcChainParams) - context := CreateCoreContext(evmChain, btcChain, evmChainParamsNew, btcChainParams) + context := CreateAppContext(evmChain, btcChain, evmChainParamsNew, btcChainParams) // BSC signer should not be found _, err := orchestrator.GetUpdatedSigner(context, chains.BscMainnet.ChainId) require.ErrorContains(t, err, "signer not found") }) t.Run("should be able to update connector and erc20 custody address", func(t *testing.T) { orchestrator := MockOrchestrator(t, nil, evmChain, btcChain, evmChainParams, btcChainParams) - context := CreateCoreContext(evmChain, btcChain, evmChainParamsNew, btcChainParams) + context := CreateAppContext(evmChain, btcChain, evmChainParamsNew, btcChainParams) // update signer with new connector and erc20 custody address signer, err := orchestrator.GetUpdatedSigner(context, evmChain.ChainId) require.NoError(t, err) @@ -172,14 +171,14 @@ func Test_GetUpdatedChainObserver(t *testing.T) { t.Run("evm chain observer should not be found", func(t *testing.T) { orchestrator := MockOrchestrator(t, nil, evmChain, btcChain, evmChainParams, btcChainParams) - coreContext := CreateCoreContext(evmChain, btcChain, evmChainParamsNew, btcChainParams) + coreContext := CreateAppContext(evmChain, btcChain, evmChainParamsNew, btcChainParams) // BSC chain observer should not be found _, err := orchestrator.GetUpdatedChainObserver(coreContext, chains.BscMainnet.ChainId) require.ErrorContains(t, err, "chain observer not found") }) t.Run("chain params in evm chain observer should be updated successfully", func(t *testing.T) { orchestrator := MockOrchestrator(t, nil, evmChain, btcChain, evmChainParams, btcChainParams) - coreContext := CreateCoreContext(evmChain, btcChain, evmChainParamsNew, btcChainParams) + coreContext := CreateAppContext(evmChain, btcChain, evmChainParamsNew, btcChainParams) // update evm chain observer with new chain params chainOb, err := orchestrator.GetUpdatedChainObserver(coreContext, evmChain.ChainId) require.NoError(t, err) @@ -188,14 +187,14 @@ func Test_GetUpdatedChainObserver(t *testing.T) { }) t.Run("btc chain observer should not be found", func(t *testing.T) { orchestrator := MockOrchestrator(t, nil, evmChain, btcChain, evmChainParams, btcChainParams) - coreContext := CreateCoreContext(btcChain, btcChain, evmChainParams, btcChainParamsNew) + coreContext := CreateAppContext(btcChain, btcChain, evmChainParams, btcChainParamsNew) // BTC testnet chain observer should not be found _, err := orchestrator.GetUpdatedChainObserver(coreContext, chains.BitcoinTestnet.ChainId) require.ErrorContains(t, err, "chain observer not found") }) t.Run("chain params in btc chain observer should be updated successfully", func(t *testing.T) { orchestrator := MockOrchestrator(t, nil, evmChain, btcChain, evmChainParams, btcChainParams) - coreContext := CreateCoreContext(btcChain, btcChain, evmChainParams, btcChainParamsNew) + coreContext := CreateAppContext(btcChain, btcChain, evmChainParams, btcChainParamsNew) // update btc chain observer with new chain params chainOb, err := orchestrator.GetUpdatedChainObserver(coreContext, btcChain.ChainId) require.NoError(t, err) diff --git a/zetaclient/supplychecker/zeta_supply_checker.go b/zetaclient/supplychecker/zeta_supply_checker.go index 10ad1d5db1..4c16ffd203 100644 --- a/zetaclient/supplychecker/zeta_supply_checker.go +++ b/zetaclient/supplychecker/zeta_supply_checker.go @@ -23,7 +23,7 @@ import ( // ZetaSupplyChecker is a utility to check the total supply of Zeta tokens type ZetaSupplyChecker struct { - coreContext *context.ZetacoreContext + appContext *context.AppContext evmClient map[int64]*ethclient.Client zetaClient *zetacore.Client ticker *clienttypes.DynamicTicker @@ -52,8 +52,8 @@ func NewZetaSupplyChecker( logger: logger.With(). Str("module", "ZetaSupplyChecker"). Logger(), - coreContext: appContext.ZetacoreContext(), - zetaClient: zetaClient, + appContext: appContext, + zetaClient: zetaClient, } for _, evmConfig := range appContext.Config().GetAllEVMConfigs() { @@ -120,7 +120,7 @@ func (zs *ZetaSupplyChecker) Stop() { func (zs *ZetaSupplyChecker) CheckZetaTokenSupply() error { externalChainTotalSupply := sdkmath.ZeroInt() for _, chain := range zs.externalEvmChain { - externalEvmChainParams, ok := zs.coreContext.GetEVMChainParams(chain.ChainId) + externalEvmChainParams, ok := zs.appContext.GetEVMChainParams(chain.ChainId) if !ok { return fmt.Errorf("externalEvmChainParams not found for chain id %d", chain.ChainId) } @@ -146,7 +146,7 @@ func (zs *ZetaSupplyChecker) CheckZetaTokenSupply() error { externalChainTotalSupply = externalChainTotalSupply.Add(totalSupplyInt) } - evmChainParams, ok := zs.coreContext.GetEVMChainParams(zs.ethereumChain.ChainId) + evmChainParams, ok := zs.appContext.GetEVMChainParams(zs.ethereumChain.ChainId) if !ok { return fmt.Errorf("eth config not found for chain id %d", zs.ethereumChain.ChainId) } diff --git a/zetaclient/tss/tss_signer.go b/zetaclient/tss/tss_signer.go index 08d48833db..e00252db55 100644 --- a/zetaclient/tss/tss_signer.go +++ b/zetaclient/tss/tss_signer.go @@ -109,7 +109,7 @@ func NewTSS( newTss := TSS{ Server: server, Keys: make(map[string]*Key), - CurrentPubkey: appContext.ZetacoreContext().GetCurrentTssPubkey(), + CurrentPubkey: appContext.GetCurrentTssPubKey(), logger: logger, ZetacoreClient: client, KeysignsTracker: NewKeysignsTracker(logger), diff --git a/zetaclient/zetacore/client.go b/zetaclient/zetacore/client.go index 4443316a4a..140520fe11 100644 --- a/zetaclient/zetacore/client.go +++ b/zetaclient/zetacore/client.go @@ -193,11 +193,7 @@ func (c *Client) WaitForZetacoreToCreateBlocks() error { // UpdateZetacoreContext updates zetacore context // zetacore stores zetacore context for all clients -func (c *Client) UpdateZetacoreContext( - coreContext *context.ZetacoreContext, - init bool, - sampledLogger zerolog.Logger, -) error { +func (c *Client) UpdateZetacoreContext(coreContext *context.AppContext, init bool, sampledLogger zerolog.Logger) error { bn, err := c.GetBlockHeight() if err != nil { return fmt.Errorf("failed to get zetablock height: %w", err) @@ -278,7 +274,6 @@ func (c *Client) UpdateZetacoreContext( crosschainFlags, blockHeaderEnabledChains, init, - c.logger, ) return nil diff --git a/zetaclient/zetacore/tx.go b/zetaclient/zetacore/tx.go index 0a28336b04..1cf1c5c40e 100644 --- a/zetaclient/zetacore/tx.go +++ b/zetaclient/zetacore/tx.go @@ -185,7 +185,7 @@ func (c *Client) ZetacoreContextUpdater(appContext *appcontext.AppContext) { select { case <-ticker.C: c.logger.Debug().Msg("Running Updater") - err := c.UpdateZetacoreContext(appContext.ZetacoreContext(), false, sampledLogger) + err := c.UpdateZetacoreContext(appContext, false, sampledLogger) if err != nil { c.logger.Err(err).Msg("ZetacoreContextUpdater failed to update config") } diff --git a/zetaclient/zetacore/tx_test.go b/zetaclient/zetacore/tx_test.go index 1d00f33d1a..fbf9a10e7d 100644 --- a/zetaclient/zetacore/tx_test.go +++ b/zetaclient/zetacore/tx_test.go @@ -333,9 +333,9 @@ func TestZetacore_UpdateZetacoreContext(t *testing.T) { t.Run("zetacore update success", func(t *testing.T) { cfg := config.NewConfig() - coreCtx := context.NewZetacoreContext(cfg) + appContext := context.New(cfg, zerolog.Nop()) zetacoreBroadcast = MockBroadcast - err := client.UpdateZetacoreContext(coreCtx, false, zerolog.Logger{}) + err := client.UpdateZetacoreContext(appContext, false, zerolog.Logger{}) require.NoError(t, err) }) } From ba6bc6fe7bc610e078b7c8b8cc51dc7578867105 Mon Sep 17 00:00:00 2001 From: Grant Zukel <80433392+gzukel@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:43:07 -0600 Subject: [PATCH 19/23] ci: expand performance testing to catch errors, fixed connection refused errors, added performance testing with state. (#2400) * fixed bugs in the performance testing. * added command to start a network from the latest state-export from mainnet. * added additional test validation to display correctly in cloud reports. * added failure alerting and conditional outcome checking for the test reports to fail when there are issues and notify the team. --- .github/actions/performance-tests/art.yaml | 233 +++++++++++++++++- .../ci-nightly-performance-testing.yaml | 56 ++++- changelog.md | 1 + 3 files changed, 276 insertions(+), 14 deletions(-) diff --git a/.github/actions/performance-tests/art.yaml b/.github/actions/performance-tests/art.yaml index 71c1b3a15e..70d2ba1f85 100644 --- a/.github/actions/performance-tests/art.yaml +++ b/.github/actions/performance-tests/art.yaml @@ -1,7 +1,5 @@ -# artillery run art.yaml --output results.json -# artillery report results.json --output artillery_report.html config: - target: "http://127.0.0.1:8545" + target: "http://localhost:9545" phases: - duration: 60 arrivalRate: 10 @@ -13,10 +11,14 @@ config: plugins: metrics-by-endpoint: useOnlyRequestNames: true + ensure: + - type: "failure" + threshold: 1 summary: true reports: - type: "html" filename: "artillery_report.html" + logLevel: debug scenarios: - name: web3_clientVersion @@ -28,6 +30,15 @@ scenarios: jsonrpc: "2.0" method: "web3_clientVersion" params: [] + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: web3_sha3 flow: @@ -39,6 +50,15 @@ scenarios: method: "web3_sha3" params: - "0x68656c6c6f20776f726c64" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: net_version flow: @@ -49,6 +69,15 @@ scenarios: jsonrpc: "2.0" method: "net_version" params: [] + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: net_listening flow: @@ -59,6 +88,15 @@ scenarios: jsonrpc: "2.0" method: "net_listening" params: [] + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: net_peerCount flow: @@ -69,6 +107,15 @@ scenarios: jsonrpc: "2.0" method: "net_peerCount" params: [] + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_chainId flow: @@ -79,6 +126,15 @@ scenarios: jsonrpc: "2.0" method: "eth_chainId" params: [] + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getStorageAt flow: @@ -90,6 +146,15 @@ scenarios: method: "eth_getStorageAt" params: - "latest" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getTransactionByBlockHashAndIndex flow: @@ -101,6 +166,15 @@ scenarios: method: "eth_getTransactionByBlockHashAndIndex" params: - "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getTransactionByBlockNumberAndIndex flow: @@ -113,6 +187,15 @@ scenarios: params: - "latest" - "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getUncleByBlockHashAndIndex flow: @@ -124,6 +207,15 @@ scenarios: method: "eth_getUncleByBlockHashAndIndex" params: - "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getUncleByBlockNumberAndIndex flow: @@ -136,6 +228,15 @@ scenarios: params: - "latest" - "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_newFilter flow: @@ -152,6 +253,15 @@ scenarios: address: "0x0", topics: [] } + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getFilterChanges flow: @@ -163,6 +273,15 @@ scenarios: method: "eth_getFilterChanges" params: - "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getFilterLogs flow: @@ -174,6 +293,15 @@ scenarios: method: "eth_getFilterLogs" params: - "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_blockNumber flow: @@ -184,6 +312,15 @@ scenarios: jsonrpc: "2.0" method: "eth_blockNumber" params: [] + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getBlockByHash flow: @@ -196,6 +333,15 @@ scenarios: params: - "0x0" - true + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getBlockByNumber flow: @@ -208,6 +354,15 @@ scenarios: params: - "latest" - true + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getBlockTransactionCountByHash flow: @@ -219,6 +374,15 @@ scenarios: method: "eth_getBlockTransactionCountByHash" params: - "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getBlockTransactionCountByNumber flow: @@ -230,6 +394,15 @@ scenarios: method: "eth_getBlockTransactionCountByNumber" params: - "latest" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getCode flow: @@ -242,6 +415,15 @@ scenarios: params: - "0x0" - "latest" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getTransactionByHash flow: @@ -253,6 +435,15 @@ scenarios: method: "eth_getTransactionByHash" params: - "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getTransactionReceipt flow: @@ -264,6 +455,15 @@ scenarios: method: "eth_getTransactionReceipt" params: - "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getLogs flow: @@ -278,6 +478,15 @@ scenarios: toBlock: "latest" address: "0x0" topics: ["0x0"] + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_getBalance flow: @@ -290,6 +499,15 @@ scenarios: params: - "0x0" - "latest" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null - name: eth_estimateGas flow: @@ -301,3 +519,12 @@ scenarios: method: "eth_estimateGas" params: - from: "0x0" + capture: + - json: "$" + as: "response" + ensure: + - statusCode: 200 + - statusCode: 201 + assert: + - subject: response.error + equals: null diff --git a/.github/workflows/ci-nightly-performance-testing.yaml b/.github/workflows/ci-nightly-performance-testing.yaml index 30116f743f..a6a566f4aa 100644 --- a/.github/workflows/ci-nightly-performance-testing.yaml +++ b/.github/workflows/ci-nightly-performance-testing.yaml @@ -12,23 +12,57 @@ jobs: steps: - uses: actions/checkout@v4 - - name: "START:LOCAL:NET" + - name: "INSTALL:NODEJS" + uses: actions/setup-node@v4 + with: + node-version: 16 + + - name: "START:LOCAL:NET:WITH:STATE" run: | - make start-e2e-test + make start-e2e-import-mainnet-test - - name: "EXECUTE:LOADTESTS" - uses: artilleryio/action-cli@v1 - with: - command: run .github/actions/performance-tests/art.yaml --record --key ${{ secrets.ARTILLERY_KEY }} --output ./report.json + - name: "INSTALL:ARTILLERY" + run: | + npm install -g artillery@latest + + - name: "EXECUTE:PERFORMANCE:TESTS" + run: | + artillery run .github/actions/performance-tests/art.yaml --record --key ${{ secrets.ARTILLERY_KEY }} --output ./report.json + # Check Artillery exit status + if [ $? -ne 0 ]; then + echo "Artillery command failed to execute." + exit 1 + fi + + # Parse the results.json file to check for failed vusers and http response codes + failed_vusers=$(jq '.aggregate.counters["vusers.failed"] // 0' ./report.json) + http_codes_200=$(jq '.aggregate.counters["http.codes.200"] // 0' ./report.json) + http_responses=$(jq '.aggregate.counters["http.responses"] // 0' ./report.json) + + if [ "$failed_vusers" -gt 1 ] || [ "$http_codes_200" -ne "$http_responses" ]; then + echo "Performance Testing had Failed Tests." + exit 1 + else + echo "EVM Performance Testing Successful" + fi - name: "GENERATE:REPORT" - uses: artilleryio/action-cli@v1 - with: - command: report report.json --output artillery_report.html + if: always() + run: | + artillery report report.json --output artillery_report.html - name: "UPLOAD:REPORT" uses: actions/upload-artifact@v3 - if: success() + if: always() with: name: artillery-report - path: ./artillery_report.html \ No newline at end of file + path: ./artillery_report.html + + - name: "NOTIFY:SLACK:FAILURE" + if: failure() && github.event_name == 'schedule' + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,message,commit,author,action,eventName,ref,workflow,job,took + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_CI_ALERTS }} \ No newline at end of file diff --git a/changelog.md b/changelog.md index 4e7cd838a0..1506dee6ee 100644 --- a/changelog.md +++ b/changelog.md @@ -99,6 +99,7 @@ * [2192](https://github.com/zeta-chain/node/pull/2192) - Added release status checker and updater pipeline that will update release statuses when they go live on network * [2335](https://github.com/zeta-chain/node/pull/2335) - ci: updated the artillery report to publish to artillery cloud * [2377](https://github.com/zeta-chain/node/pull/2377) - ci: adjusted sast-linters.yml to not scan itself, nor alert on removal of nosec. +* [2400](https://github.com/zeta-chain/node/pull/2400) - ci: adjusted the performance test to pass or fail pipeline based on test results, alert slack, and launch network with state. Fixed connection issues as well. ### Documentation From 89821294fb3e4f14cf3504946ae518a8c8db593a Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 2 Jul 2024 17:37:49 +0200 Subject: [PATCH 20/23] refactor: use `ChainInfo` in `authority` to allow support chains dynamically (#2380) * add combine list function * remove unused functions and add combine default list method * use test package for chain_test * use additional info parameter for methods * rename additional chains * add GetChainList to authority interface * iteration 1 * crosschain refactoring * fungible refacotring * lightclient refactoring * observer refactoring * add additional chain list in context * zetaclient modification * fix build error * format * changelog * fix lint * test fixes 2 * observer test fix * zetaclient tests * fix test 2 * add more tests * rename getChainList * add issues * fix tests * Update pkg/chains/chains.go Co-authored-by: Dmitry S <11892559+swift1337@users.noreply.github.com> * Update pkg/chains/chains.go Co-authored-by: Dmitry S <11892559+swift1337@users.noreply.github.com> * add TODO * Update x/authority/keeper/chain_info.go Co-authored-by: Dmitry S <11892559+swift1337@users.noreply.github.com> * Update cmd/zetaclientd/debug.go Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> * remove pointers in chains * complete chain remove pointer * fix tests * dmitry comments * update comment * fix merge error * comments * use nil --------- Co-authored-by: Dmitry S <11892559+swift1337@users.noreply.github.com> Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> --- changelog.md | 1 + cmd/zetaclientd/debug.go | 16 +- pkg/chains/chain.go | 127 ++---- pkg/chains/chain_test.go | 422 ++++++++---------- pkg/chains/chains.go | 88 ++-- pkg/chains/chains_test.go | 394 +++++++++++----- pkg/chains/conversion.go | 22 +- pkg/chains/utils_test.go | 37 +- pkg/crypto/pubkey.go | 2 +- .../zetacore/observer/observer.proto | 1 - .../zetachain/zetacore/observer/params.proto | 1 - proto/zetachain/zetacore/observer/query.proto | 4 +- testutil/keeper/authority.go | 11 + testutil/keeper/crosschain.go | 26 +- testutil/keeper/mocks/crosschain/authority.go | 21 + testutil/keeper/mocks/crosschain/observer.go | 48 +- testutil/keeper/mocks/fungible/authority.go | 21 + testutil/keeper/mocks/fungible/observer.go | 8 +- .../keeper/mocks/lightclient/authority.go | 21 + testutil/keeper/mocks/observer/authority.go | 24 +- testutil/network/genesis_state.go | 2 +- testutil/sample/authority.go | 10 +- testutil/sample/crosschain.go | 4 +- testutil/sample/observer.go | 2 +- testutil/sample/sample.go | 4 +- x/authority/keeper/chain_info.go | 13 + x/authority/keeper/chain_info_test.go | 16 + x/authority/keeper/grpc_query_chain_info.go | 4 +- .../keeper/grpc_query_chain_info_test.go | 10 +- x/crosschain/keeper/abci.go | 6 +- x/crosschain/keeper/abci_test.go | 2 +- x/crosschain/keeper/cctx_gateway_observers.go | 5 +- .../cctx_orchestrator_validate_outbound.go | 5 +- ...ctx_orchestrator_validate_outbound_test.go | 51 +-- x/crosschain/keeper/cctx_utils.go | 4 +- x/crosschain/keeper/cctx_utils_test.go | 12 +- x/crosschain/keeper/events.go | 3 - x/crosschain/keeper/evm_deposit.go | 2 +- x/crosschain/keeper/evm_hooks.go | 59 +-- x/crosschain/keeper/evm_hooks_test.go | 16 +- x/crosschain/keeper/gas_payment.go | 6 +- .../keeper/grpc_query_cctx_rate_limit.go | 4 +- .../keeper/grpc_query_zeta_conversion_rate.go | 8 +- x/crosschain/keeper/initiate_outbound.go | 4 +- x/crosschain/keeper/initiate_outbound_test.go | 60 +-- .../keeper/msg_server_add_inbound_tracker.go | 4 +- .../msg_server_add_inbound_tracker_test.go | 18 +- .../keeper/msg_server_add_outbound_tracker.go | 5 +- .../msg_server_add_outbound_tracker_test.go | 30 +- .../keeper/msg_server_migrate_tss_funds.go | 11 +- .../msg_server_migrate_tss_funds_test.go | 21 +- .../msg_server_refund_aborted_tx_test.go | 4 + .../keeper/msg_server_vote_gas_price.go | 4 +- .../keeper/msg_server_vote_gas_price_test.go | 12 +- .../keeper/msg_server_vote_inbound_tx_test.go | 26 +- .../msg_server_vote_outbound_tx_test.go | 33 +- .../keeper/msg_server_whitelist_erc20.go | 4 +- x/crosschain/keeper/refund.go | 4 +- x/crosschain/keeper/utils_test.go | 8 +- x/crosschain/migrations/v4/migrate.go | 2 +- x/crosschain/migrations/v5/migrate.go | 4 +- x/crosschain/migrations/v5/migrate_test.go | 4 +- x/crosschain/types/cctx_test.go | 9 - x/crosschain/types/expected_keepers.go | 9 +- x/crosschain/types/inbound_params.go | 6 - x/crosschain/types/inbound_params_test.go | 4 - .../types/message_add_inbound_tracker.go | 15 +- .../types/message_add_inbound_tracker_test.go | 27 +- .../types/message_migrate_tss_funds.go | 6 +- .../types/message_migrate_tss_funds_test.go | 9 - x/crosschain/types/outbound_params.go | 6 - x/crosschain/types/outbound_params_test.go | 4 - x/crosschain/types/tx_body_verification.go | 15 +- x/crosschain/types/validate.go | 21 +- x/fungible/keeper/evm.go | 7 +- x/fungible/keeper/gas_coin_and_pool.go | 11 +- .../keeper/grpc_query_gas_stability_pool.go | 3 - .../grpc_query_gas_stability_pool_test.go | 18 +- ..._server_deploy_fungible_coin_zrc20_test.go | 3 + .../msg_server_remove_foreign_coin_test.go | 2 + ...sg_server_update_contract_bytecode_test.go | 2 + .../msg_server_update_system_contract_test.go | 4 + ...g_server_update_zrc20_withdraw_fee_test.go | 1 + x/fungible/types/expected_keepers.go | 3 +- x/lightclient/keeper/grpc_query_prove.go | 10 +- x/lightclient/keeper/proof.go | 6 +- x/lightclient/types/expected_keepers.go | 3 + .../message_disable_verification_flags.go | 17 +- ...message_disable_verification_flags_test.go | 20 +- .../message_enable_verification_flags.go | 21 +- .../message_enable_verification_flags_test.go | 20 +- x/observer/keeper/chain_params.go | 23 +- x/observer/keeper/chain_params_test.go | 27 +- .../keeper/grpc_query_supported_chain_test.go | 2 +- .../grpc_query_tss_funds_migrator_info.go | 3 +- .../msg_server_remove_chain_params_test.go | 22 +- .../keeper/msg_server_reset_chain_nonces.go | 4 +- .../msg_server_reset_chain_nonces_test.go | 2 + .../msg_server_update_chain_params_test.go | 10 +- x/observer/keeper/msg_server_vote_blame.go | 4 +- .../keeper/msg_server_vote_block_header.go | 4 +- .../msg_server_vote_block_header_test.go | 12 + x/observer/keeper/utils.go | 2 +- x/observer/keeper/utils_test.go | 2 +- x/observer/keeper/vote_inbound.go | 8 +- x/observer/keeper/vote_inbound_test.go | 21 + x/observer/keeper/vote_outbound.go | 4 +- x/observer/keeper/vote_outbound_test.go | 15 + x/observer/types/chain_params.go | 80 ++-- x/observer/types/chain_params_test.go | 4 +- x/observer/types/expected_keepers.go | 2 + .../types/message_remove_chain_params.go | 8 - .../types/message_remove_chain_params_test.go | 13 +- .../types/message_reset_chain_nonces.go | 8 - .../types/message_reset_chain_nonces_test.go | 22 +- .../types/message_update_chain_params_test.go | 6 +- x/observer/types/message_vote_blame.go | 6 +- x/observer/types/message_vote_blame_test.go | 9 - x/observer/types/message_vote_block_header.go | 5 - x/observer/types/observer.pb.go | 50 +-- x/observer/types/params.pb.go | 76 ++-- x/observer/types/query.pb.go | 294 ++++++------ zetaclient/chains/base/signer.go | 4 +- zetaclient/chains/evm/observer/inbound.go | 9 +- .../chains/evm/observer/observer_test.go | 1 + zetaclient/chains/evm/signer/outbound_data.go | 14 +- .../chains/evm/signer/outbound_data_test.go | 40 +- zetaclient/chains/evm/signer/signer.go | 101 +++-- zetaclient/chains/evm/signer/signer_test.go | 81 +++- zetaclient/context/app.go | 19 +- zetaclient/context/app_test.go | 39 ++ zetaclient/orchestrator/orchestrator.go | 10 +- zetaclient/orchestrator/orchestrator_test.go | 1 + .../supplychecker/zeta_supply_checker.go | 13 +- zetaclient/zetacore/client.go | 16 +- zetaclient/zetacore/query.go | 13 +- zetaclient/zetacore/query_test.go | 26 +- zetaclient/zetacore/tx.go | 10 +- zetaclient/zetacore/tx_test.go | 45 +- 139 files changed, 1806 insertions(+), 1467 deletions(-) diff --git a/changelog.md b/changelog.md index 1506dee6ee..9f40d4b256 100644 --- a/changelog.md +++ b/changelog.md @@ -55,6 +55,7 @@ * [2357](https://github.com/zeta-chain/node/pull/2357) - integrate base Signer structure into EVM/Bitcoin Signer * [2359](https://github.com/zeta-chain/node/pull/2359) - integrate base Observer structure into EVM/Bitcoin Observer * [2375](https://github.com/zeta-chain/node/pull/2375) - improve & speedup code formatting +* [2380](https://github.com/zeta-chain/node/pull/2380) - use `ChainInfo` in `authority` to allow dynamically support new chains * [2395](https://github.com/zeta-chain/node/pull/2395) - converge AppContext with ZetaCoreContext in zetaclient ### Tests diff --git a/cmd/zetaclientd/debug.go b/cmd/zetaclientd/debug.go index 08aadbe8a4..28a3932a8d 100644 --- a/cmd/zetaclientd/debug.go +++ b/cmd/zetaclientd/debug.go @@ -86,20 +86,20 @@ func debugCmd(_ *cobra.Command, args []string) error { if err != nil { return err } - chain := chains.GetChainFromChainID(chainID) - if chain == nil { + chain, found := chains.GetChainFromChainID(chainID, appContext.GetAdditionalChains()) + if !found { return fmt.Errorf("invalid chain id") } // get ballot identifier according to the chain type - if chains.IsEVMChain(chain.ChainId) { + if chains.IsEVMChain(chain.ChainId, appContext.GetAdditionalChains()) { evmObserver := evmobserver.Observer{} evmObserver.WithZetacoreClient(client) var ethRPC *ethrpc.EthRPC var client *ethclient.Client coinType := coin.CoinType_Cmd - for chain, evmConfig := range cfg.GetAllEVMConfigs() { - if chainID == chain { + for chainIDFromConfig, evmConfig := range cfg.GetAllEVMConfigs() { + if chainIDFromConfig == chainID { ethRPC = ethrpc.NewEthRPC(evmConfig.Endpoint) client, err = ethclient.Dial(evmConfig.Endpoint) if err != nil { @@ -107,7 +107,7 @@ func debugCmd(_ *cobra.Command, args []string) error { } evmObserver.WithEvmClient(client) evmObserver.WithEvmJSONRPC(ethRPC) - evmObserver.WithChain(*chains.GetChainFromChainID(chainID)) + evmObserver.WithChain(chain) } } hash := ethcommon.HexToHash(inboundHash) @@ -168,10 +168,10 @@ func debugCmd(_ *cobra.Command, args []string) error { fmt.Println("CoinType not detected") } fmt.Println("CoinType : ", coinType) - } else if chains.IsBitcoinChain(chain.ChainId) { + } else if chains.IsBitcoinChain(chain.ChainId, appContext.GetAdditionalChains()) { btcObserver := btcobserver.Observer{} btcObserver.WithZetacoreClient(client) - btcObserver.WithChain(*chains.GetChainFromChainID(chainID)) + btcObserver.WithChain(chain) connCfg := &rpcclient.ConnConfig{ Host: cfg.BitcoinConfig.RPCHost, User: cfg.BitcoinConfig.RPCUsername, diff --git a/pkg/chains/chain.go b/pkg/chains/chain.go index 681e13a5ae..46ead5f9f2 100644 --- a/pkg/chains/chain.go +++ b/pkg/chains/chain.go @@ -5,15 +5,9 @@ import ( "strings" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcutil" ethcommon "github.com/ethereum/go-ethereum/common" ) -type SigninAlgo string - -// Chains represent a slice of Chain -type Chains []Chain - // Validate checks whether the chain is valid // The function check the chain ID is positive and all enum fields have a defined value func (chain Chain) Validate() error { @@ -44,11 +38,6 @@ func (chain Chain) Validate() error { return nil } -// IsEqual compare two chain to see whether they represent the same chain -func (chain Chain) IsEqual(c Chain) bool { - return chain.ChainId == c.ChainId -} - // IsZetaChain returns true if the chain is a ZetaChain chain func (chain Chain) IsZetaChain() bool { return chain.Network == Network_zeta @@ -63,13 +52,13 @@ func (chain Chain) IsExternalChain() bool { // on EVM chain, it is 20Bytes // on Bitcoin chain, it is P2WPKH address, []byte(bech32 encoded string) func (chain Chain) EncodeAddress(b []byte) (string, error) { - if IsEVMChain(chain.ChainId) { + if chain.Consensus == Consensus_ethereum { addr := ethcommon.BytesToAddress(b) if addr == (ethcommon.Address{}) { return "", fmt.Errorf("invalid EVM address") } return addr.Hex(), nil - } else if IsBitcoinChain(chain.ChainId) { + } else if chain.Consensus == Consensus_bitcoin { addrStr := string(b) chainParams, err := GetBTCChainParams(chain.ChainId) if err != nil { @@ -87,61 +76,54 @@ func (chain Chain) EncodeAddress(b []byte) (string, error) { return "", fmt.Errorf("chain (%d) not supported", chain.ChainId) } -func (chain Chain) BTCAddressFromWitnessProgram(witnessProgram []byte) (string, error) { - chainParams, err := GetBTCChainParams(chain.ChainId) - if err != nil { - return "", err - } - address, err := btcutil.NewAddressWitnessPubKeyHash(witnessProgram, chainParams) - if err != nil { - return "", err - } - return address.EncodeAddress(), nil +func (chain Chain) IsEVMChain() bool { + return chain.Consensus == Consensus_ethereum } -// DecodeAddress decode the address string to bytes -func (chain Chain) DecodeAddress(addr string) ([]byte, error) { - return DecodeAddressFromChainID(chain.ChainId, addr) +func (chain Chain) IsBitcoinChain() bool { + return chain.Consensus == Consensus_bitcoin } // DecodeAddressFromChainID decode the address string to bytes -func DecodeAddressFromChainID(chainID int64, addr string) ([]byte, error) { - if IsEVMChain(chainID) { +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func DecodeAddressFromChainID(chainID int64, addr string, additionalChains []Chain) ([]byte, error) { + switch { + case IsEVMChain(chainID, additionalChains): return ethcommon.HexToAddress(addr).Bytes(), nil - } else if IsBitcoinChain(chainID) { + case IsBitcoinChain(chainID, additionalChains): return []byte(addr), nil + default: + return nil, fmt.Errorf("chain (%d) not supported", chainID) } - return nil, fmt.Errorf("chain (%d) not supported", chainID) } // IsEVMChain returns true if the chain is an EVM chain or uses the ethereum consensus mechanism for block finality -func IsEVMChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListByConsensus(Consensus_ethereum)) +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func IsEVMChain(chainID int64, additionalChains []Chain) bool { + return ChainIDInChainList(chainID, ChainListByConsensus(Consensus_ethereum, additionalChains)) } // IsBitcoinChain returns true if the chain is a Bitcoin-based chain or uses the bitcoin consensus mechanism for block finality -func IsBitcoinChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListByConsensus(Consensus_bitcoin)) +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func IsBitcoinChain(chainID int64, additionalChains []Chain) bool { + return ChainIDInChainList(chainID, ChainListByConsensus(Consensus_bitcoin, additionalChains)) } // IsEthereumChain returns true if the chain is an Ethereum chain -func IsEthereumChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListByNetwork(Network_eth)) +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func IsEthereumChain(chainID int64, additionalChains []Chain) bool { + return ChainIDInChainList(chainID, ChainListByNetwork(Network_eth, additionalChains)) } // IsZetaChain returns true if the chain is a Zeta chain -func IsZetaChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListByNetwork(Network_zeta)) -} - -// IsHeaderSupportedChain returns true if the chain's consensus supports block header-based verification -func IsHeaderSupportedChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListForHeaderSupport()) -} - -// SupportMerkleProof returns true if the chain supports block header-based verification -func (chain Chain) SupportMerkleProof() bool { - return IsEVMChain(chain.ChainId) || IsBitcoinChain(chain.ChainId) +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func IsZetaChain(chainID int64, additionalChains []Chain) bool { + return ChainIDInChainList(chainID, ChainListByNetwork(Network_zeta, additionalChains)) } // IsEmpty is to determinate whether the chain is empty @@ -149,45 +131,20 @@ func (chain Chain) IsEmpty() bool { return strings.TrimSpace(chain.String()) == "" } -// Has check whether chain c is in the list -func (chains Chains) Has(c Chain) bool { - for _, ch := range chains { - if ch.IsEqual(c) { - return true - } - } - return false -} - -// Distinct return a distinct set of chains, no duplicates -func (chains Chains) Distinct() Chains { - var newChains Chains - for _, chain := range chains { - if !newChains.Has(chain) { - newChains = append(newChains, chain) - } - } - return newChains -} - -func (chains Chains) Strings() []string { - str := make([]string, len(chains)) - for i, c := range chains { - str[i] = c.String() - } - return str -} - -func GetChainFromChainID(chainID int64) *Chain { - chains := DefaultChainsList() +// GetChainFromChainID returns the chain from the chain ID +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func GetChainFromChainID(chainID int64, additionalChains []Chain) (Chain, bool) { + chains := CombineDefaultChainsList(additionalChains) for _, chain := range chains { if chainID == chain.ChainId { - return chain + return chain, true } } - return nil + return Chain{}, false } +// GetBTCChainParams returns the bitcoin chain config params from the chain ID func GetBTCChainParams(chainID int64) (*chaincfg.Params, error) { switch chainID { case 18444: @@ -201,6 +158,7 @@ func GetBTCChainParams(chainID int64) (*chaincfg.Params, error) { } } +// GetBTCChainIDFromChainParams returns the bitcoin chain ID from the chain config params func GetBTCChainIDFromChainParams(params *chaincfg.Params) (int64, error) { switch params.Name { case chaincfg.RegressionNetParams.Name: @@ -214,13 +172,8 @@ func GetBTCChainIDFromChainParams(params *chaincfg.Params) (int64, error) { } } -// InChainList checks whether the chain is in the chain list -func (chain Chain) InChainList(chainList []*Chain) bool { - return ChainIDInChainList(chain.ChainId, chainList) -} - // ChainIDInChainList checks whether the chainID is in the chain list -func ChainIDInChainList(chainID int64, chainList []*Chain) bool { +func ChainIDInChainList(chainID int64, chainList []Chain) bool { for _, c := range chainList { if chainID == c.ChainId { return true diff --git a/pkg/chains/chain_test.go b/pkg/chains/chain_test.go index d14fd39a37..f495ba0c85 100644 --- a/pkg/chains/chain_test.go +++ b/pkg/chains/chain_test.go @@ -1,121 +1,120 @@ -package chains +package chains_test import ( - "encoding/hex" + "github.com/zeta-chain/zetacore/testutil/sample" "testing" - "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcutil" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/chains" ) func TestChain_Validate(t *testing.T) { tests := []struct { name string - chain Chain + chain chains.Chain errStr string }{ { name: "should pass if chain is valid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_optimism, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_optimism, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, }, { name: "should error if chain ID is zero", - chain: Chain{ + chain: chains.Chain{ ChainId: 0, - ChainName: ChainName_empty, - Network: Network_optimism, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_optimism, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "chain ID must be positive", }, { name: "should error if chain ID is negative", - chain: Chain{ + chain: chains.Chain{ ChainId: 0, - ChainName: ChainName_empty, - Network: Network_optimism, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_optimism, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "chain ID must be positive", }, { name: "should error if chain name invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_base_sepolia + 1, - Network: Network_optimism, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_base_sepolia + 1, + Network: chains.Network_optimism, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "invalid chain name", }, { name: "should error if network invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_base + 1, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_base + 1, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "invalid network", }, { name: "should error if network type invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_base, - NetworkType: NetworkType_devnet + 1, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_base, + NetworkType: chains.NetworkType_devnet + 1, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "invalid network type", }, { name: "should error if vm invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_base, - NetworkType: NetworkType_devnet, - Vm: Vm_evm + 1, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_base, + NetworkType: chains.NetworkType_devnet, + Vm: chains.Vm_evm + 1, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "invalid vm", }, { name: "should error if consensus invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_base, - NetworkType: NetworkType_devnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack + 1, + ChainName: chains.ChainName_empty, + Network: chains.Network_base, + NetworkType: chains.NetworkType_devnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack + 1, IsExternal: true, }, errStr: "invalid consensus", @@ -132,7 +131,7 @@ func TestChain_Validate(t *testing.T) { } t.Run("all default chains are valid", func(t *testing.T) { - for _, chain := range DefaultChainsList() { + for _, chain := range chains.DefaultChainsList() { require.NoError(t, chain.Validate()) } }) @@ -141,16 +140,17 @@ func TestChain_Validate(t *testing.T) { func TestChain_EncodeAddress(t *testing.T) { tests := []struct { name string - chain Chain + chain chains.Chain b []byte want string wantErr bool }{ { name: "should error if b is not a valid address on the bitcoin network", - chain: Chain{ - ChainName: ChainName_btc_testnet, + chain: chains.Chain{ + ChainName: chains.ChainName_btc_testnet, ChainId: 18332, + Consensus: chains.Consensus_bitcoin, }, b: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"), want: "", @@ -158,9 +158,10 @@ func TestChain_EncodeAddress(t *testing.T) { }, { name: "should pass if b is a valid address on the network", - chain: Chain{ - ChainName: ChainName_btc_mainnet, + chain: chains.Chain{ + ChainName: chains.ChainName_btc_mainnet, ChainId: 8332, + Consensus: chains.Consensus_bitcoin, }, b: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"), want: "bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c", @@ -168,8 +169,8 @@ func TestChain_EncodeAddress(t *testing.T) { }, { name: "should error if b is not a valid address on the evm network", - chain: Chain{ - ChainName: ChainName_goerli_testnet, + chain: chains.Chain{ + ChainName: chains.ChainName_goerli_testnet, ChainId: 5, }, b: ethcommon.Hex2Bytes("0x321"), @@ -178,8 +179,8 @@ func TestChain_EncodeAddress(t *testing.T) { }, { name: "should pass if b is a valid address on the evm network", - chain: Chain{ - ChainName: ChainName_goerli_testnet, + chain: chains.Chain{ + ChainName: chains.ChainName_goerli_testnet, ChainId: 5, }, b: []byte("0x321"), @@ -188,7 +189,7 @@ func TestChain_EncodeAddress(t *testing.T) { }, { name: "should error if chain not supported", - chain: Chain{ + chain: chains.Chain{ ChainName: 999, ChainId: 999, }, @@ -211,146 +212,125 @@ func TestChain_EncodeAddress(t *testing.T) { } } -func TestChain_DecodeAddress(t *testing.T) { +func TestChain_IsEVMChain(t *testing.T) { tests := []struct { - name string - chain Chain - b string - want []byte - wantErr bool + name string + chain chains.Chain + want bool }{ - { - name: "should decode on btc chain", - chain: Chain{ - ChainName: ChainName_btc_testnet, - ChainId: 18332, - }, - want: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"), - b: "bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c", - wantErr: false, - }, - { - name: "should decode on evm chain", - chain: Chain{ - ChainName: ChainName_goerli_testnet, - ChainId: 5, - }, - want: ethcommon.HexToAddress("0x321").Bytes(), - b: "0x321", - wantErr: false, - }, - { - name: "should error if chain not supported", - chain: Chain{ - ChainName: 999, - ChainId: 999, - }, - want: ethcommon.Hex2Bytes("0x321"), - b: "", - wantErr: true, - }, + {"Ethereum Mainnet", chains.Ethereum, true}, + {"Goerli Testnet", chains.Goerli, true}, + {"Sepolia Testnet", chains.Sepolia, true}, + {"Non-EVM", chains.BitcoinMainnet, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet, false}, } - for _, tc := range tests { - tc := tc - t.Run(tc.name, func(t *testing.T) { - s, err := tc.chain.DecodeAddress(tc.b) - if tc.wantErr { - require.Error(t, err) - return - } - require.Equal(t, tc.want, s) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.want, tt.chain.IsEVMChain()) }) } } -func TestChain_InChainList(t *testing.T) { - require.True(t, ZetaChainMainnet.InChainList(ChainListByNetwork(Network_zeta))) - require.True(t, ZetaChainDevnet.InChainList(ChainListByNetwork(Network_zeta))) - require.True(t, ZetaChainPrivnet.InChainList(ChainListByNetwork(Network_zeta))) - require.True(t, ZetaChainTestnet.InChainList(ChainListByNetwork(Network_zeta))) - require.False(t, Ethereum.InChainList(ChainListByNetwork(Network_zeta))) -} - -func TestIsZetaChain(t *testing.T) { +func TestChain_IsBitcoinChain(t *testing.T) { tests := []struct { - name string - chainID int64 - want bool + name string + chain chains.Chain + want bool }{ - {"Zeta Mainnet", ZetaChainMainnet.ChainId, true}, - {"Zeta Testnet", ZetaChainTestnet.ChainId, true}, - {"Zeta Mocknet", ZetaChainDevnet.ChainId, true}, - {"Zeta Privnet", ZetaChainPrivnet.ChainId, true}, - {"Non-Zeta", Ethereum.ChainId, false}, + {"Bitcoin Mainnet", chains.BitcoinMainnet, true}, + {"Bitcoin Testnet", chains.BitcoinTestnet, true}, + {"Bitcoin Regtest", chains.BitcoinRegtest, true}, + {"Non-Bitcoin", chains.Ethereum, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsZetaChain(tt.chainID)) + require.Equal(t, tt.want, tt.chain.IsBitcoinChain()) }) } } -func TestIsEVMChain(t *testing.T) { +func TestIsZetaChain(t *testing.T) { tests := []struct { name string chainID int64 want bool }{ - {"Ethereum Mainnet", Ethereum.ChainId, true}, - {"Goerli Testnet", Goerli.ChainId, true}, - {"Sepolia Testnet", Sepolia.ChainId, true}, - {"Non-EVM", BitcoinMainnet.ChainId, false}, - {"Zeta Mainnet", ZetaChainMainnet.ChainId, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet.ChainId, true}, + {"Zeta Testnet", chains.ZetaChainTestnet.ChainId, true}, + {"Zeta Mocknet", chains.ZetaChainDevnet.ChainId, true}, + {"Zeta Privnet", chains.ZetaChainPrivnet.ChainId, true}, + {"Non-Zeta", chains.Ethereum.ChainId, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsEVMChain(tt.chainID)) + require.Equal(t, tt.want, chains.IsZetaChain(tt.chainID, []chains.Chain{})) }) } } -func TestIsHeaderSupportedChain(t *testing.T) { +func TestDecodeAddressFromChainID(t *testing.T) { + ethAddr := sample.EthAddress() + tests := []struct { name string chainID int64 - want bool + addr string + want []byte + wantErr bool }{ - {"Ethereum Mainnet", Ethereum.ChainId, true}, - {"Goerli Testnet", Goerli.ChainId, true}, - {"Goerli Localnet", GoerliLocalnet.ChainId, true}, - {"Sepolia Testnet", Sepolia.ChainId, true}, - {"BSC Testnet", BscTestnet.ChainId, true}, - {"BSC Mainnet", BscMainnet.ChainId, true}, - {"BTC", BitcoinMainnet.ChainId, true}, - {"Zeta Mainnet", ZetaChainMainnet.ChainId, false}, + { + name: "Ethereum", + chainID: chains.Ethereum.ChainId, + addr: ethAddr.Hex(), + want: ethAddr.Bytes(), + }, + { + name: "Bitcoin", + chainID: chains.BitcoinMainnet.ChainId, + addr: "bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c", + want: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"), + }, + { + name: "Non-supported chain", + chainID: 9999, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsHeaderSupportedChain(tt.chainID)) + got, err := chains.DecodeAddressFromChainID(tt.chainID, tt.addr, []chains.Chain{}) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) }) + } } -func TestSupportMerkleProof(t *testing.T) { +func TestIsEVMChain(t *testing.T) { tests := []struct { - name string - chain Chain - want bool + name string + chainID int64 + want bool }{ - {"Ethereum Mainnet", Ethereum, true}, - {"BSC Testnet", BscTestnet, true}, - {"BSC Mainnet", BscMainnet, true}, - {"Non-EVM", BitcoinMainnet, true}, - {"Zeta Mainnet", ZetaChainMainnet, false}, + {"Ethereum Mainnet", chains.Ethereum.ChainId, true}, + {"Goerli Testnet", chains.Goerli.ChainId, true}, + {"Sepolia Testnet", chains.Sepolia.ChainId, true}, + {"Non-EVM", chains.BitcoinMainnet.ChainId, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet.ChainId, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, tt.chain.SupportMerkleProof()) + require.Equal(t, tt.want, chains.IsEVMChain(tt.chainID, []chains.Chain{})) }) } } @@ -361,16 +341,16 @@ func TestIsBitcoinChain(t *testing.T) { chainID int64 want bool }{ - {"Bitcoin Mainnet", BitcoinMainnet.ChainId, true}, - {"Bitcoin Testnet", BitcoinTestnet.ChainId, true}, - {"Bitcoin Regtest", BitcoinRegtest.ChainId, true}, - {"Non-Bitcoin", Ethereum.ChainId, false}, - {"Zeta Mainnet", ZetaChainMainnet.ChainId, false}, + {"Bitcoin Mainnet", chains.BitcoinMainnet.ChainId, true}, + {"Bitcoin Testnet", chains.BitcoinTestnet.ChainId, true}, + {"Bitcoin Regtest", chains.BitcoinRegtest.ChainId, true}, + {"Non-Bitcoin", chains.Ethereum.ChainId, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet.ChainId, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsBitcoinChain(tt.chainID)) + require.Equal(t, tt.want, chains.IsBitcoinChain(tt.chainID, []chains.Chain{})) }) } } @@ -381,128 +361,82 @@ func TestIsEthereumChain(t *testing.T) { chainID int64 want bool }{ - {"Ethereum Mainnet", Ethereum.ChainId, true}, - {"Goerli Testnet", Goerli.ChainId, true}, - {"Sepolia Testnet", Sepolia.ChainId, true}, - {"Non-Ethereum", BitcoinMainnet.ChainId, false}, - {"Zeta Mainnet", ZetaChainMainnet.ChainId, false}, + {"Ethereum Mainnet", chains.Ethereum.ChainId, true}, + {"Goerli Testnet", chains.Goerli.ChainId, true}, + {"Sepolia Testnet", chains.Sepolia.ChainId, true}, + {"Non-Ethereum", chains.BitcoinMainnet.ChainId, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet.ChainId, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsEthereumChain(tt.chainID)) + require.Equal(t, tt.want, chains.IsEthereumChain(tt.chainID, []chains.Chain{})) }) } } func TestChain_IsExternalChain(t *testing.T) { - require.False(t, ZetaChainMainnet.IsExternalChain()) - require.True(t, Ethereum.IsExternalChain()) + require.False(t, chains.ZetaChainMainnet.IsExternalChain()) + require.True(t, chains.Ethereum.IsExternalChain()) } func TestChain_IsZetaChain(t *testing.T) { - require.True(t, ZetaChainMainnet.IsZetaChain()) - require.False(t, Ethereum.IsZetaChain()) + require.True(t, chains.ZetaChainMainnet.IsZetaChain()) + require.False(t, chains.Ethereum.IsZetaChain()) } func TestChain_IsEmpty(t *testing.T) { - require.True(t, Chain{}.IsEmpty()) - require.False(t, ZetaChainMainnet.IsEmpty()) -} - -func TestChain_WitnessProgram(t *testing.T) { - // Ordinarily the private key would come from whatever storage mechanism - // is being used, but for this example just hard code it. - privKeyBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2" + - "d4f8720ee63e502ee2869afab7de234b80c") - require.NoError(t, err) - - t.Run("should return btc address", func(t *testing.T) { - _, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) - pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) - addr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, &chaincfg.RegressionNetParams) - require.NoError(t, err) - - chain := BitcoinTestnet - _, err = chain.BTCAddressFromWitnessProgram(addr.WitnessProgram()) - require.NoError(t, err) - }) - - t.Run("should fail for wrong chain id", func(t *testing.T) { - _, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) - pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) - addr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, &chaincfg.RegressionNetParams) - require.NoError(t, err) - - chain := Goerli - _, err = chain.BTCAddressFromWitnessProgram(addr.WitnessProgram()) - require.Error(t, err) - }) - - t.Run("should fail for wrong witness program", func(t *testing.T) { - _, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) - pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) - addr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, &chaincfg.RegressionNetParams) - require.NoError(t, err) - - chain := BitcoinTestnet - _, err = chain.BTCAddressFromWitnessProgram(addr.WitnessProgram()[0:19]) - require.Error(t, err) - }) -} - -func TestChains_Has(t *testing.T) { - chains := Chains{ZetaChainMainnet, ZetaChainTestnet} - require.True(t, chains.Has(ZetaChainMainnet)) - require.False(t, chains.Has(Ethereum)) -} - -func TestChains_Distinct(t *testing.T) { - chains := Chains{ZetaChainMainnet, ZetaChainMainnet, ZetaChainTestnet} - distinctChains := chains.Distinct() - require.Len(t, distinctChains, 2) -} - -func TestChains_Strings(t *testing.T) { - chains := Chains{ZetaChainMainnet, ZetaChainTestnet} - strings := chains.Strings() - expected := []string{chains[0].String(), chains[1].String()} - require.Equal(t, expected, strings) + require.True(t, chains.Chain{}.IsEmpty()) + require.False(t, chains.ZetaChainMainnet.IsEmpty()) } func TestGetChainFromChainID(t *testing.T) { - chain := GetChainFromChainID(ZetaChainMainnet.ChainId) - require.Equal(t, ZetaChainMainnet, *chain) - require.Nil(t, GetChainFromChainID(9999)) + chain, found := chains.GetChainFromChainID(chains.ZetaChainMainnet.ChainId, []chains.Chain{}) + require.EqualValues(t, chains.ZetaChainMainnet, chain) + require.True(t, found) + chain, found = chains.GetChainFromChainID(9999, []chains.Chain{}) + require.False(t, found) } func TestGetBTCChainParams(t *testing.T) { - params, err := GetBTCChainParams(BitcoinMainnet.ChainId) + params, err := chains.GetBTCChainParams(chains.BitcoinMainnet.ChainId) require.NoError(t, err) require.Equal(t, &chaincfg.MainNetParams, params) - _, err = GetBTCChainParams(9999) + _, err = chains.GetBTCChainParams(9999) require.Error(t, err) } func TestGetBTCChainIDFromChainParams(t *testing.T) { - chainID, err := GetBTCChainIDFromChainParams(&chaincfg.MainNetParams) + chainID, err := chains.GetBTCChainIDFromChainParams(&chaincfg.MainNetParams) require.NoError(t, err) require.Equal(t, int64(8332), chainID) - chainID, err = GetBTCChainIDFromChainParams(&chaincfg.RegressionNetParams) + chainID, err = chains.GetBTCChainIDFromChainParams(&chaincfg.RegressionNetParams) require.NoError(t, err) require.Equal(t, int64(18444), chainID) - chainID, err = GetBTCChainIDFromChainParams(&chaincfg.TestNet3Params) + chainID, err = chains.GetBTCChainIDFromChainParams(&chaincfg.TestNet3Params) require.NoError(t, err) require.Equal(t, int64(18332), chainID) - _, err = GetBTCChainIDFromChainParams(&chaincfg.Params{Name: "unknown"}) + _, err = chains.GetBTCChainIDFromChainParams(&chaincfg.Params{Name: "unknown"}) require.Error(t, err) } func TestChainIDInChainList(t *testing.T) { - require.True(t, ChainIDInChainList(ZetaChainMainnet.ChainId, ChainListByNetwork(Network_zeta))) - require.False(t, ChainIDInChainList(Ethereum.ChainId, ChainListByNetwork(Network_zeta))) + require.True( + t, + chains.ChainIDInChainList( + chains.ZetaChainMainnet.ChainId, + chains.ChainListByNetwork(chains.Network_zeta, []chains.Chain{}), + ), + ) + require.False( + t, + chains.ChainIDInChainList( + chains.Ethereum.ChainId, + chains.ChainListByNetwork(chains.Network_zeta, []chains.Chain{}), + ), + ) } diff --git a/pkg/chains/chains.go b/pkg/chains/chains.go index 11c6f952f0..333aa22001 100644 --- a/pkg/chains/chains.go +++ b/pkg/chains/chains.go @@ -265,14 +265,17 @@ var ( } ) +// ErrNotZetaChain is the error for chain not being a ZetaChain chain +var ErrNotZetaChain = fmt.Errorf("chain is not a ZetaChain chain") + // BtcNonceMarkOffset is the offset satoshi amount to calculate the nonce mark output func BtcNonceMarkOffset() int64 { return 2000 } // DefaultChainsList returns a list of default chains -func DefaultChainsList() []*Chain { - return chainListPointers([]Chain{ +func DefaultChainsList() []Chain { + return []Chain{ BitcoinMainnet, BscMainnet, Ethereum, @@ -293,13 +296,13 @@ func DefaultChainsList() []*Chain { OptimismSepolia, BaseMainnet, BaseSepolia, - }) + } } // ChainListByNetworkType returns a list of chains by network type -func ChainListByNetworkType(networkType NetworkType) []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ChainListByNetworkType(networkType NetworkType, additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.NetworkType == networkType { chainList = append(chainList, chain) } @@ -308,9 +311,9 @@ func ChainListByNetworkType(networkType NetworkType) []*Chain { } // ChainListByNetwork returns a list of chains by network -func ChainListByNetwork(network Network) []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ChainListByNetwork(network Network, additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.Network == network { chainList = append(chainList, chain) } @@ -319,9 +322,9 @@ func ChainListByNetwork(network Network) []*Chain { } // ExternalChainList returns a list chains that are not Zeta -func ExternalChainList() []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ExternalChainList(additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.IsExternal { chainList = append(chainList, chain) } @@ -330,9 +333,9 @@ func ExternalChainList() []*Chain { } // ChainListByConsensus returns a list of chains by consensus -func ChainListByConsensus(consensus Consensus) []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ChainListByConsensus(consensus Consensus, additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.Consensus == consensus { chainList = append(chainList, chain) } @@ -341,9 +344,9 @@ func ChainListByConsensus(consensus Consensus) []*Chain { } // ChainListForHeaderSupport returns a list of chains that support headers -func ChainListForHeaderSupport() []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ChainListForHeaderSupport(additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.Consensus == Consensus_ethereum || chain.Consensus == Consensus_bitcoin { chainList = append(chainList, chain) } @@ -351,14 +354,19 @@ func ChainListForHeaderSupport() []*Chain { return chainList } -// ZetaChainFromChainID returns a ZetaChain chain object from a Cosmos chain ID -func ZetaChainFromChainID(chainID string) (Chain, error) { +// ZetaChainFromCosmosChainID returns a ZetaChain chain object from a Cosmos chain ID +func ZetaChainFromCosmosChainID(chainID string) (Chain, error) { ethChainID, err := CosmosToEthChainID(chainID) if err != nil { return Chain{}, err } - switch ethChainID { + return ZetaChainFromChainID(ethChainID) +} + +// ZetaChainFromChainID returns a ZetaChain chain object from a chain ID +func ZetaChainFromChainID(chainID int64) (Chain, error) { + switch chainID { case ZetaChainPrivnet.ChainId: return ZetaChainPrivnet, nil case ZetaChainMainnet.ChainId: @@ -368,17 +376,37 @@ func ZetaChainFromChainID(chainID string) (Chain, error) { case ZetaChainDevnet.ChainId: return ZetaChainDevnet, nil default: - return Chain{}, fmt.Errorf("chain %d not found", ethChainID) + return Chain{}, ErrNotZetaChain } } -// TODO : https://github.com/zeta-chain/node/issues/2080 -// remove the usage of this function -// chainListPointers returns a list of chain pointers -func chainListPointers(chains []Chain) []*Chain { - var c []*Chain - for i := 0; i < len(chains); i++ { - c = append(c, &chains[i]) +// CombineDefaultChainsList combines the default chains list with a list of chains +// duplicated chain ID are overwritten by the second list +func CombineDefaultChainsList(chains []Chain) []Chain { + return CombineChainList(DefaultChainsList(), chains) +} + +// CombineChainList combines a list of chains with a list of chains +// duplicated chain ID are overwritten by the second list +func CombineChainList(base []Chain, additional []Chain) []Chain { + combined := make([]Chain, 0, len(base)+len(additional)) + combined = append(combined, base...) + + // map chain ID in combined to index in the list + chainIDIndexMap := make(map[int64]int) + for i, chain := range combined { + chainIDIndexMap[chain.ChainId] = i } - return c + + // add chains2 to combined + // if chain ID already exists in chains1, overwrite it + for _, chain := range additional { + if index, ok := chainIDIndexMap[chain.ChainId]; ok { + combined[index] = chain + } else { + combined = append(combined, chain) + } + } + + return combined } diff --git a/pkg/chains/chains_test.go b/pkg/chains/chains_test.go index dffb630086..5b85f39f22 100644 --- a/pkg/chains/chains_test.go +++ b/pkg/chains/chains_test.go @@ -1,59 +1,61 @@ -package chains +package chains_test import ( "testing" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/chains" + "github.com/zeta-chain/zetacore/testutil/sample" ) func TestChainListByNetworkType(t *testing.T) { listTests := []struct { name string - networkType NetworkType - expected []*Chain + networkType chains.NetworkType + expected []chains.Chain }{ { "mainnet chains", - NetworkType_mainnet, - []*Chain{ - &ZetaChainMainnet, - &BitcoinMainnet, - &BscMainnet, - &Ethereum, - &Polygon, - &OptimismMainnet, - &BaseMainnet, + chains.NetworkType_mainnet, + []chains.Chain{ + chains.ZetaChainMainnet, + chains.BitcoinMainnet, + chains.BscMainnet, + chains.Ethereum, + chains.Polygon, + chains.OptimismMainnet, + chains.BaseMainnet, }, }, { "testnet chains", - NetworkType_testnet, - []*Chain{ - &ZetaChainTestnet, - &BitcoinTestnet, - &Mumbai, - &Amoy, - &BscTestnet, - &Goerli, - &Sepolia, - &OptimismSepolia, - &BaseSepolia, + chains.NetworkType_testnet, + []chains.Chain{ + chains.ZetaChainTestnet, + chains.BitcoinTestnet, + chains.Mumbai, + chains.Amoy, + chains.BscTestnet, + chains.Goerli, + chains.Sepolia, + chains.OptimismSepolia, + chains.BaseSepolia, }, }, { "privnet chains", - NetworkType_privnet, - []*Chain{ - &ZetaChainPrivnet, - &BitcoinRegtest, - &GoerliLocalnet, + chains.NetworkType_privnet, + []chains.Chain{ + chains.ZetaChainPrivnet, + chains.BitcoinRegtest, + chains.GoerliLocalnet, }, }, } for _, lt := range listTests { t.Run(lt.name, func(t *testing.T) { - require.ElementsMatch(t, lt.expected, ChainListByNetworkType(lt.networkType)) + require.ElementsMatch(t, lt.expected, chains.ChainListByNetworkType(lt.networkType, []chains.Chain{})) }) } } @@ -61,167 +63,209 @@ func TestChainListByNetworkType(t *testing.T) { func TestChainListByNetwork(t *testing.T) { listTests := []struct { name string - network Network - expected []*Chain + network chains.Network + expected []chains.Chain }{ { "Zeta", - Network_zeta, - []*Chain{&ZetaChainMainnet, &ZetaChainDevnet, &ZetaChainPrivnet, &ZetaChainTestnet}, + chains.Network_zeta, + []chains.Chain{ + chains.ZetaChainMainnet, + chains.ZetaChainDevnet, + chains.ZetaChainPrivnet, + chains.ZetaChainTestnet, + }, }, { "Btc", - Network_btc, - []*Chain{&BitcoinMainnet, &BitcoinTestnet, &BitcoinRegtest}, + chains.Network_btc, + []chains.Chain{chains.BitcoinMainnet, chains.BitcoinTestnet, chains.BitcoinRegtest}, }, { "Eth", - Network_eth, - []*Chain{&Ethereum, &Goerli, &Sepolia, &GoerliLocalnet}, + chains.Network_eth, + []chains.Chain{chains.Ethereum, chains.Goerli, chains.Sepolia, chains.GoerliLocalnet}, }, { "Bsc", - Network_bsc, - []*Chain{&BscMainnet, &BscTestnet}, + chains.Network_bsc, + []chains.Chain{chains.BscMainnet, chains.BscTestnet}, }, { "Polygon", - Network_polygon, - []*Chain{&Polygon, &Mumbai, &Amoy}, + chains.Network_polygon, + []chains.Chain{chains.Polygon, chains.Mumbai, chains.Amoy}, }, { "Optimism", - Network_optimism, - []*Chain{&OptimismMainnet, &OptimismSepolia}, + chains.Network_optimism, + []chains.Chain{chains.OptimismMainnet, chains.OptimismSepolia}, }, { "Base", - Network_base, - []*Chain{&BaseMainnet, &BaseSepolia}, + chains.Network_base, + []chains.Chain{chains.BaseMainnet, chains.BaseSepolia}, }, } for _, lt := range listTests { t.Run(lt.name, func(t *testing.T) { - require.ElementsMatch(t, lt.expected, ChainListByNetwork(lt.network)) + require.ElementsMatch(t, lt.expected, chains.ChainListByNetwork(lt.network, []chains.Chain{})) }) } } -func TestChainListFunctions(t *testing.T) { - listTests := []struct { - name string - function func() []*Chain - expected []*Chain - }{ - { - "DefaultChainsList", - DefaultChainsList, - []*Chain{ - &BitcoinMainnet, - &BscMainnet, - &Ethereum, - &BitcoinTestnet, - &Mumbai, - &Amoy, - &BscTestnet, - &Goerli, - &Sepolia, - &BitcoinRegtest, - &GoerliLocalnet, - &ZetaChainMainnet, - &ZetaChainTestnet, - &ZetaChainDevnet, - &ZetaChainPrivnet, - &Polygon, - &OptimismMainnet, - &OptimismSepolia, - &BaseMainnet, - &BaseSepolia, - }, - }, - { - "ExternalChainList", - ExternalChainList, - []*Chain{ - &BitcoinMainnet, - &BscMainnet, - &Ethereum, - &BitcoinTestnet, - &Mumbai, - &Amoy, - &BscTestnet, - &Goerli, - &Sepolia, - &BitcoinRegtest, - &GoerliLocalnet, - &Polygon, - &OptimismMainnet, - &OptimismSepolia, - &BaseMainnet, - &BaseSepolia, - }, - }, - } - for _, lt := range listTests { - t.Run(lt.name, func(t *testing.T) { - chains := lt.function() - require.ElementsMatch(t, lt.expected, chains) - }) - } +func TestDefaultChainList(t *testing.T) { + require.ElementsMatch(t, []chains.Chain{ + chains.BitcoinMainnet, + chains.BscMainnet, + chains.Ethereum, + chains.BitcoinTestnet, + chains.Mumbai, + chains.Amoy, + chains.BscTestnet, + chains.Goerli, + chains.Sepolia, + chains.BitcoinRegtest, + chains.GoerliLocalnet, + chains.ZetaChainMainnet, + chains.ZetaChainTestnet, + chains.ZetaChainDevnet, + chains.ZetaChainPrivnet, + chains.Polygon, + chains.OptimismMainnet, + chains.OptimismSepolia, + chains.BaseMainnet, + chains.BaseSepolia, + }, chains.DefaultChainsList()) } -func TestZetaChainFromChainID(t *testing.T) { +func TestExternalChainList(t *testing.T) { + require.ElementsMatch(t, []chains.Chain{ + chains.BitcoinMainnet, + chains.BscMainnet, + chains.Ethereum, + chains.BitcoinTestnet, + chains.Mumbai, + chains.Amoy, + chains.BscTestnet, + chains.Goerli, + chains.Sepolia, + chains.BitcoinRegtest, + chains.GoerliLocalnet, + chains.Polygon, + chains.OptimismMainnet, + chains.OptimismSepolia, + chains.BaseMainnet, + chains.BaseSepolia, + }, chains.ExternalChainList([]chains.Chain{})) +} + +func TestZetaChainFromCosmosChainID(t *testing.T) { tests := []struct { name string chainID string - expected Chain + expected chains.Chain wantErr bool }{ { name: "ZetaChainMainnet", chainID: "cosmoshub_7000-1", - expected: ZetaChainMainnet, + expected: chains.ZetaChainMainnet, wantErr: false, }, { name: "ZetaChainTestnet", chainID: "cosmoshub_7001-1", - expected: ZetaChainTestnet, + expected: chains.ZetaChainTestnet, wantErr: false, }, { name: "ZetaChainDevnet", chainID: "cosmoshub_70000-1", - expected: ZetaChainDevnet, + expected: chains.ZetaChainDevnet, wantErr: false, }, { name: "ZetaChainPrivnet", chainID: "cosmoshub_101-1", - expected: ZetaChainPrivnet, + expected: chains.ZetaChainPrivnet, wantErr: false, }, { name: "unknown chain", chainID: "cosmoshub_1234-1", - expected: Chain{}, + expected: chains.Chain{}, wantErr: true, }, { name: "invalid chain id", chainID: "cosmoshub_abc-1", - expected: Chain{}, + expected: chains.Chain{}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := chains.ZetaChainFromCosmosChainID(tt.chainID) + if tt.wantErr { + require.Error(t, err) + require.Equal(t, chains.Chain{}, result) + } else { + require.NoError(t, err) + require.Equal(t, tt.expected, result) + } + }) + } +} + +func TestZetaChainFromChainID(t *testing.T) { + tests := []struct { + name string + chainID int64 + expected chains.Chain + wantErr bool + }{ + { + name: "ZetaChainMainnet", + chainID: 7000, + expected: chains.ZetaChainMainnet, + wantErr: false, + }, + { + name: "ZetaChainTestnet", + chainID: 7001, + expected: chains.ZetaChainTestnet, + wantErr: false, + }, + { + name: "ZetaChainDevnet", + chainID: 70000, + expected: chains.ZetaChainDevnet, + wantErr: false, + }, + { + name: "ZetaChainPrivnet", + chainID: 101, + expected: chains.ZetaChainPrivnet, + wantErr: false, + }, + { + name: "unknown chain", + chainID: 1234, + expected: chains.Chain{}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result, err := ZetaChainFromChainID(tt.chainID) + result, err := chains.ZetaChainFromChainID(tt.chainID) if tt.wantErr { require.Error(t, err) - require.Equal(t, Chain{}, result) + require.ErrorIs(t, err, chains.ErrNotZetaChain) + require.Equal(t, chains.Chain{}, result) } else { require.NoError(t, err) require.Equal(t, tt.expected, result) @@ -229,3 +273,119 @@ func TestZetaChainFromChainID(t *testing.T) { }) } } + +func TestCombineDefaultChainsList(t *testing.T) { + // prepare array containing pre-defined chains + // chain IDs are 11000 - 11009 to not conflict with the default chains + var chainList = make([]chains.Chain, 0, 10) + for i := int64(11000); i < 10; i++ { + chainList = append(chainList, sample.Chain(i)) + } + + bitcoinMainnetChainID := chains.BitcoinMainnet.ChainId + require.Equal( + t, + bitcoinMainnetChainID, + chains.DefaultChainsList()[0].ChainId, + "Bitcoin mainnet be the first in the default chain list for TestCombineDefaultChainsList tests", + ) + alternativeBitcoinMainnet := sample.Chain(bitcoinMainnetChainID) + + tests := []struct { + name string + list []chains.Chain + expected []chains.Chain + }{ + { + name: "empty list", + list: []chains.Chain{}, + expected: chains.DefaultChainsList(), + }, + { + name: "no duplicates", + list: chainList, + expected: append(chains.DefaultChainsList(), chainList...), + }, + { + name: "duplicates", + list: []chains.Chain{alternativeBitcoinMainnet}, + expected: append(chains.DefaultChainsList()[1:], alternativeBitcoinMainnet), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.ElementsMatch(t, tt.expected, chains.CombineDefaultChainsList(tt.list)) + }) + } +} + +func TestCombineChainList(t *testing.T) { + // prepare array containing pre-defined chains + var chainList = make([]chains.Chain, 0, 10) + for i := int64(0); i < 10; i++ { + chainList = append(chainList, sample.Chain(i)) + } + + // prepare second array for duplicated chain IDs + var duplicatedChainList = make([]chains.Chain, 0, 10) + for i := int64(0); i < 10; i++ { + duplicatedChainList = append(duplicatedChainList, sample.Chain(i)) + } + + tests := []struct { + name string + list1 []chains.Chain + list2 []chains.Chain + expected []chains.Chain + }{ + { + name: "empty lists", + list1: []chains.Chain{}, + list2: []chains.Chain{}, + expected: []chains.Chain{}, + }, + { + name: "empty list 1", + list1: []chains.Chain{}, + list2: chainList, + expected: chainList, + }, + { + name: "empty list 2", + list1: chainList, + list2: []chains.Chain{}, + expected: chainList, + }, + { + name: "no duplicates", + list1: chainList[:5], + list2: chainList[5:], + expected: chainList, + }, + { + name: "all duplicates", + list1: chainList, + list2: duplicatedChainList, + expected: duplicatedChainList, + }, + { + name: "some duplicates", + list1: chainList[:5], + list2: duplicatedChainList[3:], + expected: append(chainList[:3], duplicatedChainList[3:]...), + }, + { + name: "one duplicate", + list1: chainList[:5], + list2: append(chainList[5:], duplicatedChainList[0]), + expected: append(chainList[1:], duplicatedChainList[0]), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.ElementsMatch(t, tt.expected, chains.CombineChainList(tt.list1, tt.list2)) + }) + } +} diff --git a/pkg/chains/conversion.go b/pkg/chains/conversion.go index 200061c3ae..84b3eaf3aa 100644 --- a/pkg/chains/conversion.go +++ b/pkg/chains/conversion.go @@ -8,31 +8,17 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ) -// A very special value to mark current nonce in UTXO +// NonceMarkAmount uses special value to mark current nonce in UTXO func NonceMarkAmount(nonce uint64) int64 { // #nosec G701 always in range return int64(nonce) + BtcNonceMarkOffset() } -// HashToString convert hash bytes to string -func HashToString(chainID int64, blockHash []byte) (string, error) { - if IsEVMChain(chainID) { - return hex.EncodeToString(blockHash), nil - } else if IsBitcoinChain(chainID) { - hash, err := chainhash.NewHash(blockHash) - if err != nil { - return "", err - } - return hash.String(), nil - } - return "", fmt.Errorf("cannot convert hash to string for chain %d", chainID) -} - // StringToHash convert string to hash bytes -func StringToHash(chainID int64, hash string) ([]byte, error) { - if IsEVMChain(chainID) { +func StringToHash(chainID int64, hash string, additionalChains []Chain) ([]byte, error) { + if IsEVMChain(chainID, additionalChains) { return ethcommon.HexToHash(hash).Bytes(), nil - } else if IsBitcoinChain(chainID) { + } else if IsBitcoinChain(chainID, additionalChains) { hash, err := chainhash.NewHashFromStr(hash) if err != nil { return nil, err diff --git a/pkg/chains/utils_test.go b/pkg/chains/utils_test.go index cb025e025b..915fa2b8ca 100644 --- a/pkg/chains/utils_test.go +++ b/pkg/chains/utils_test.go @@ -27,41 +27,6 @@ func TestNonceMarkAmount(t *testing.T) { } } -func TestHashToString(t *testing.T) { - evmChainId := int64(5) - btcChainId := int64(8332) - unknownChainId := int64(3) - mockEthBlockHash := []byte("0xc2339489a45f8976d45482ad6fa08751a1eae91f92d60645521ca0aff2422639") - mockBtcBlockHash := []byte("00000000000000000002dcaa3853ac587d4cafdd0aa1fff45942ab5798f29afd") - expectedBtcHash, err := chainhash.NewHashFromStr("00000000000000000002dcaa3853ac587d4cafdd0aa1fff45942ab5798f29afd") - require.NoError(t, err) - - tests := []struct { - name string - chainID int64 - blockHash []byte - expect string - wantErr bool - }{ - {"evm chain", evmChainId, mockEthBlockHash, hex.EncodeToString(mockEthBlockHash), false}, - {"btc chain", btcChainId, expectedBtcHash.CloneBytes(), expectedBtcHash.String(), false}, - {"btc chain invalid hash", btcChainId, mockBtcBlockHash, "", true}, - {"unknown chain", unknownChainId, mockEthBlockHash, "", true}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result, err := HashToString(tt.chainID, tt.blockHash) - if tt.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.expect, result) - } - }) - } -} - func TestStringToHash(t *testing.T) { evmChainId := int64(5) btcChainId := int64(8332) @@ -91,7 +56,7 @@ func TestStringToHash(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result, err := StringToHash(tt.chainID, tt.hash) + result, err := StringToHash(tt.chainID, tt.hash, []Chain{}) if tt.wantErr { require.Error(t, err) } else { diff --git a/pkg/crypto/pubkey.go b/pkg/crypto/pubkey.go index 8c893664b0..545e5367ed 100644 --- a/pkg/crypto/pubkey.go +++ b/pkg/crypto/pubkey.go @@ -71,7 +71,7 @@ func (pubKey PubKey) String() string { // GetAddress will return an address for the given chain func (pubKey PubKey) GetAddress(chain chains.Chain) (chains.Address, error) { - if chains.IsEVMChain(chain.ChainId) { + if chain.IsEVMChain() { return pubKey.GetEVMAddress() } return chains.NoAddress, nil diff --git a/proto/zetachain/zetacore/observer/observer.proto b/proto/zetachain/zetacore/observer/observer.proto index 240f0025f0..7fc6eb5b7b 100644 --- a/proto/zetachain/zetacore/observer/observer.proto +++ b/proto/zetachain/zetacore/observer/observer.proto @@ -2,7 +2,6 @@ syntax = "proto3"; package zetachain.zetacore.observer; import "gogoproto/gogo.proto"; -import "zetachain/zetacore/pkg/chains/chains.proto"; option go_package = "github.com/zeta-chain/zetacore/x/observer/types"; diff --git a/proto/zetachain/zetacore/observer/params.proto b/proto/zetachain/zetacore/observer/params.proto index 1eb096fc0c..92d00763dd 100644 --- a/proto/zetachain/zetacore/observer/params.proto +++ b/proto/zetachain/zetacore/observer/params.proto @@ -3,7 +3,6 @@ package zetachain.zetacore.observer; import "gogoproto/gogo.proto"; import "zetachain/zetacore/observer/observer.proto"; -import "zetachain/zetacore/pkg/chains/chains.proto"; option go_package = "github.com/zeta-chain/zetacore/x/observer/types"; diff --git a/proto/zetachain/zetacore/observer/query.proto b/proto/zetachain/zetacore/observer/query.proto index 799bc1efb9..9ad1d71356 100644 --- a/proto/zetachain/zetacore/observer/query.proto +++ b/proto/zetachain/zetacore/observer/query.proto @@ -263,7 +263,9 @@ message QueryObserverSetResponse { repeated string observers = 1; } message QuerySupportedChains {} -message QuerySupportedChainsResponse { repeated pkg.chains.Chain chains = 1; } +message QuerySupportedChainsResponse { + repeated pkg.chains.Chain chains = 1 [ (gogoproto.nullable) = false ]; +} message QueryGetChainParamsForChainRequest { int64 chain_id = 1; } diff --git a/testutil/keeper/authority.go b/testutil/keeper/authority.go index 1e61bf9881..169b6df526 100644 --- a/testutil/keeper/authority.go +++ b/testutil/keeper/authority.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/authority/keeper" "github.com/zeta-chain/zetacore/x/authority/types" @@ -79,6 +80,16 @@ func MockCheckAuthorization(m *mock.Mock, msg sdk.Msg, authorizationResult error m.On("CheckAuthorization", mock.Anything, msg).Return(authorizationResult).Once() } +// MockGetChainList mocks the GetAdditionalChainList method of the authority keeper. +func MockGetChainList(m *mock.Mock, chainList []chains.Chain) { + m.On("GetAdditionalChainList", mock.Anything).Return(chainList).Once() +} + +// MockGetChainListEmpty mocks the GetAdditionalChainList method of the authority keeper. +func MockGetChainListEmpty(m *mock.Mock) { + m.On("GetAdditionalChainList", mock.Anything).Return([]chains.Chain{}) +} + func SetAdminPolicies(ctx sdk.Context, ak *keeper.Keeper) string { admin := sample.AccAddress() ak.SetPolicies(ctx, types.Policies{Items: []*types.Policy{ diff --git a/testutil/keeper/crosschain.go b/testutil/keeper/crosschain.go index d2b1bc1d5b..140a9538c5 100644 --- a/testutil/keeper/crosschain.go +++ b/testutil/keeper/crosschain.go @@ -261,24 +261,14 @@ func GetCrosschainFungibleMock(t testing.TB, keeper *keeper.Keeper) *crosschainm return cfk } -func MockGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeeper, senderChain *chains.Chain) { - if senderChain != nil { - m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(senderChain).Once() - } else { - m.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything). - Return(&chains.Chain{}).Once() - } +func MockGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeeper, senderChain chains.Chain) { + m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(senderChain, true).Once() } -func MockFailedGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeeper, senderChain *chains.Chain) { - if senderChain != nil { - m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(nil).Once() - } else { - m.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything). - Return(nil).Once() - } +func MockFailedGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeeper, senderChain chains.Chain) { + m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(chains.Chain{}, false).Once() } func MockGetRevertGasLimitForERC20( @@ -304,7 +294,7 @@ func MockPayGasAndUpdateCCTX( asset string, ) { m2.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(&senderChain).Twice() + Return(senderChain, true).Twice() m.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). Return(fungibletypes.ForeignCoins{ Zrc20ContractAddress: sample.EthAddress().String(), @@ -340,7 +330,7 @@ func MockUpdateNonce(m *crosschainmocks.CrosschainObserverKeeper, senderChain ch nonce = uint64(1) tss := sample.Tss() m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(senderChain) + Return(senderChain, true).Once() m.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). Return(observertypes.ChainNonces{Nonce: nonce}, true) m.On("GetTSS", mock.Anything). diff --git a/testutil/keeper/mocks/crosschain/authority.go b/testutil/keeper/mocks/crosschain/authority.go index 59edbd6d2d..d38c117dd6 100644 --- a/testutil/keeper/mocks/crosschain/authority.go +++ b/testutil/keeper/mocks/crosschain/authority.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + chains "github.com/zeta-chain/zetacore/pkg/chains" types "github.com/cosmos/cosmos-sdk/types" ) @@ -31,6 +32,26 @@ func (_m *CrosschainAuthorityKeeper) CheckAuthorization(ctx types.Context, msg t return r0 } +// GetAdditionalChainList provides a mock function with given fields: ctx +func (_m *CrosschainAuthorityKeeper) GetAdditionalChainList(ctx types.Context) []chains.Chain { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAdditionalChainList") + } + + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + return r0 +} + // NewCrosschainAuthorityKeeper creates a new instance of CrosschainAuthorityKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewCrosschainAuthorityKeeper(t interface { diff --git a/testutil/keeper/mocks/crosschain/observer.go b/testutil/keeper/mocks/crosschain/observer.go index d504d1a9c8..6e6bd7d951 100644 --- a/testutil/keeper/mocks/crosschain/observer.go +++ b/testutil/keeper/mocks/crosschain/observer.go @@ -110,7 +110,7 @@ func (_m *CrosschainObserverKeeper) CheckIfTssPubkeyHasBeenGenerated(ctx types.C } // FindBallot provides a mock function with given fields: ctx, index, chain, observationType -func (_m *CrosschainObserverKeeper) FindBallot(ctx types.Context, index string, chain *chains.Chain, observationType observertypes.ObservationType) (observertypes.Ballot, bool, error) { +func (_m *CrosschainObserverKeeper) FindBallot(ctx types.Context, index string, chain chains.Chain, observationType observertypes.ObservationType) (observertypes.Ballot, bool, error) { ret := _m.Called(ctx, index, chain, observationType) if len(ret) == 0 { @@ -120,22 +120,22 @@ func (_m *CrosschainObserverKeeper) FindBallot(ctx types.Context, index string, var r0 observertypes.Ballot var r1 bool var r2 error - if rf, ok := ret.Get(0).(func(types.Context, string, *chains.Chain, observertypes.ObservationType) (observertypes.Ballot, bool, error)); ok { + if rf, ok := ret.Get(0).(func(types.Context, string, chains.Chain, observertypes.ObservationType) (observertypes.Ballot, bool, error)); ok { return rf(ctx, index, chain, observationType) } - if rf, ok := ret.Get(0).(func(types.Context, string, *chains.Chain, observertypes.ObservationType) observertypes.Ballot); ok { + if rf, ok := ret.Get(0).(func(types.Context, string, chains.Chain, observertypes.ObservationType) observertypes.Ballot); ok { r0 = rf(ctx, index, chain, observationType) } else { r0 = ret.Get(0).(observertypes.Ballot) } - if rf, ok := ret.Get(1).(func(types.Context, string, *chains.Chain, observertypes.ObservationType) bool); ok { + if rf, ok := ret.Get(1).(func(types.Context, string, chains.Chain, observertypes.ObservationType) bool); ok { r1 = rf(ctx, index, chain, observationType) } else { r1 = ret.Get(1).(bool) } - if rf, ok := ret.Get(2).(func(types.Context, string, *chains.Chain, observertypes.ObservationType) error); ok { + if rf, ok := ret.Get(2).(func(types.Context, string, chains.Chain, observertypes.ObservationType) error); ok { r2 = rf(ctx, index, chain, observationType) } else { r2 = ret.Error(2) @@ -557,39 +557,47 @@ func (_m *CrosschainObserverKeeper) GetPendingNonces(ctx types.Context, tss stri } // GetSupportedChainFromChainID provides a mock function with given fields: ctx, chainID -func (_m *CrosschainObserverKeeper) GetSupportedChainFromChainID(ctx types.Context, chainID int64) *chains.Chain { +func (_m *CrosschainObserverKeeper) GetSupportedChainFromChainID(ctx types.Context, chainID int64) (chains.Chain, bool) { ret := _m.Called(ctx, chainID) if len(ret) == 0 { panic("no return value specified for GetSupportedChainFromChainID") } - var r0 *chains.Chain - if rf, ok := ret.Get(0).(func(types.Context, int64) *chains.Chain); ok { + var r0 chains.Chain + var r1 bool + if rf, ok := ret.Get(0).(func(types.Context, int64) (chains.Chain, bool)); ok { + return rf(ctx, chainID) + } + if rf, ok := ret.Get(0).(func(types.Context, int64) chains.Chain); ok { r0 = rf(ctx, chainID) } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*chains.Chain) - } + r0 = ret.Get(0).(chains.Chain) } - return r0 + if rf, ok := ret.Get(1).(func(types.Context, int64) bool); ok { + r1 = rf(ctx, chainID) + } else { + r1 = ret.Get(1).(bool) + } + + return r0, r1 } // GetSupportedChains provides a mock function with given fields: ctx -func (_m *CrosschainObserverKeeper) GetSupportedChains(ctx types.Context) []*chains.Chain { +func (_m *CrosschainObserverKeeper) GetSupportedChains(ctx types.Context) []chains.Chain { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for GetSupportedChains") } - var r0 []*chains.Chain - if rf, ok := ret.Get(0).(func(types.Context) []*chains.Chain); ok { + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { r0 = rf(ctx) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*chains.Chain) + r0 = ret.Get(0).([]chains.Chain) } } @@ -597,19 +605,19 @@ func (_m *CrosschainObserverKeeper) GetSupportedChains(ctx types.Context) []*cha } // GetSupportedForeignChains provides a mock function with given fields: ctx -func (_m *CrosschainObserverKeeper) GetSupportedForeignChains(ctx types.Context) []*chains.Chain { +func (_m *CrosschainObserverKeeper) GetSupportedForeignChains(ctx types.Context) []chains.Chain { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for GetSupportedForeignChains") } - var r0 []*chains.Chain - if rf, ok := ret.Get(0).(func(types.Context) []*chains.Chain); ok { + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { r0 = rf(ctx) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*chains.Chain) + r0 = ret.Get(0).([]chains.Chain) } } diff --git a/testutil/keeper/mocks/fungible/authority.go b/testutil/keeper/mocks/fungible/authority.go index b3ed6cae5a..ed9dbd0e28 100644 --- a/testutil/keeper/mocks/fungible/authority.go +++ b/testutil/keeper/mocks/fungible/authority.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + chains "github.com/zeta-chain/zetacore/pkg/chains" types "github.com/cosmos/cosmos-sdk/types" ) @@ -31,6 +32,26 @@ func (_m *FungibleAuthorityKeeper) CheckAuthorization(ctx types.Context, msg typ return r0 } +// GetAdditionalChainList provides a mock function with given fields: ctx +func (_m *FungibleAuthorityKeeper) GetAdditionalChainList(ctx types.Context) []chains.Chain { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAdditionalChainList") + } + + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + return r0 +} + // NewFungibleAuthorityKeeper creates a new instance of FungibleAuthorityKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewFungibleAuthorityKeeper(t interface { diff --git a/testutil/keeper/mocks/fungible/observer.go b/testutil/keeper/mocks/fungible/observer.go index bbe76b1afa..7a003686e4 100644 --- a/testutil/keeper/mocks/fungible/observer.go +++ b/testutil/keeper/mocks/fungible/observer.go @@ -15,19 +15,19 @@ type FungibleObserverKeeper struct { } // GetSupportedChains provides a mock function with given fields: ctx -func (_m *FungibleObserverKeeper) GetSupportedChains(ctx types.Context) []*chains.Chain { +func (_m *FungibleObserverKeeper) GetSupportedChains(ctx types.Context) []chains.Chain { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for GetSupportedChains") } - var r0 []*chains.Chain - if rf, ok := ret.Get(0).(func(types.Context) []*chains.Chain); ok { + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { r0 = rf(ctx) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*chains.Chain) + r0 = ret.Get(0).([]chains.Chain) } } diff --git a/testutil/keeper/mocks/lightclient/authority.go b/testutil/keeper/mocks/lightclient/authority.go index 8592036260..8d058dbfc0 100644 --- a/testutil/keeper/mocks/lightclient/authority.go +++ b/testutil/keeper/mocks/lightclient/authority.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + chains "github.com/zeta-chain/zetacore/pkg/chains" types "github.com/cosmos/cosmos-sdk/types" ) @@ -31,6 +32,26 @@ func (_m *LightclientAuthorityKeeper) CheckAuthorization(ctx types.Context, msg return r0 } +// GetAdditionalChainList provides a mock function with given fields: ctx +func (_m *LightclientAuthorityKeeper) GetAdditionalChainList(ctx types.Context) []chains.Chain { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAdditionalChainList") + } + + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + return r0 +} + // NewLightclientAuthorityKeeper creates a new instance of LightclientAuthorityKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewLightclientAuthorityKeeper(t interface { diff --git a/testutil/keeper/mocks/observer/authority.go b/testutil/keeper/mocks/observer/authority.go index 30a0d21b6d..9150ffcfc5 100644 --- a/testutil/keeper/mocks/observer/authority.go +++ b/testutil/keeper/mocks/observer/authority.go @@ -3,9 +3,11 @@ package mocks import ( - mock "github.com/stretchr/testify/mock" + chains "github.com/zeta-chain/zetacore/pkg/chains" authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" + mock "github.com/stretchr/testify/mock" + types "github.com/cosmos/cosmos-sdk/types" ) @@ -32,6 +34,26 @@ func (_m *ObserverAuthorityKeeper) CheckAuthorization(ctx types.Context, msg typ return r0 } +// GetAdditionalChainList provides a mock function with given fields: ctx +func (_m *ObserverAuthorityKeeper) GetAdditionalChainList(ctx types.Context) []chains.Chain { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAdditionalChainList") + } + + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + return r0 +} + // SetPolicies provides a mock function with given fields: ctx, policies func (_m *ObserverAuthorityKeeper) SetPolicies(ctx types.Context, policies authoritytypes.Policies) { _m.Called(ctx, policies) diff --git a/testutil/network/genesis_state.go b/testutil/network/genesis_state.go index 7f0bb2003c..ae6bc247bd 100644 --- a/testutil/network/genesis_state.go +++ b/testutil/network/genesis_state.go @@ -66,7 +66,7 @@ func SetupZetaGenesisState( } if setupChainNonces { - privatenetChains := chains.ChainListByNetworkType(chains.NetworkType_privnet) + privatenetChains := chains.ChainListByNetworkType(chains.NetworkType_privnet, []chains.Chain{}) chainNonceList := make([]observertypes.ChainNonces, len(privatenetChains)) for i, chain := range privatenetChains { chainNonceList[i] = observertypes.ChainNonces{ diff --git a/testutil/sample/authority.go b/testutil/sample/authority.go index be9ca2c555..d777373282 100644 --- a/testutil/sample/authority.go +++ b/testutil/sample/authority.go @@ -29,15 +29,11 @@ func Policies() authoritytypes.Policies { } func ChainInfo(startChainID int64) authoritytypes.ChainInfo { - chain1 := Chain(startChainID) - chain2 := Chain(startChainID + 1) - chain3 := Chain(startChainID + 2) - return authoritytypes.ChainInfo{ Chains: []chains.Chain{ - *chain1, - *chain2, - *chain3, + Chain(startChainID), + Chain(startChainID + 1), + Chain(startChainID + 2), }, } } diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 38d490af62..c4353681bf 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -280,9 +280,9 @@ func InboundVote(coinType coin.CoinType, from, to int64) types.MsgVoteInbound { return types.MsgVoteInbound{ Creator: "", Sender: EthAddress().String(), - SenderChainId: Chain(from).GetChainId(), + SenderChainId: Chain(from).ChainId, Receiver: EthAddress().String(), - ReceiverChain: Chain(to).GetChainId(), + ReceiverChain: Chain(to).ChainId, Amount: UintInRange(10000000, 1000000000), Message: base64.StdEncoding.EncodeToString(Bytes()), InboundBlockHeight: Uint64InRange(1, 10000), diff --git a/testutil/sample/observer.go b/testutil/sample/observer.go index 3c1a38bc0d..96621ccb26 100644 --- a/testutil/sample/observer.go +++ b/testutil/sample/observer.go @@ -111,7 +111,7 @@ func ChainParamsSupported(chainID int64) *types.ChainParams { } func ChainParamsList() (cpl types.ChainParamsList) { - chainList := chains.ChainListByNetworkType(chains.NetworkType_privnet) + chainList := chains.ChainListByNetworkType(chains.NetworkType_privnet, []chains.Chain{}) for _, chain := range chainList { cpl.ChainParams = append(cpl.ChainParams, ChainParams(chain.ChainId)) diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go index bdd7681ee1..1341be96e4 100644 --- a/testutil/sample/sample.go +++ b/testutil/sample/sample.go @@ -118,7 +118,7 @@ func GenDoc(t *testing.T) *types.GenesisDoc { return genDoc } -func Chain(chainID int64) *chains.Chain { +func Chain(chainID int64) chains.Chain { r := newRandFromSeed(chainID) chainNameLen := len(chains.ChainName_name) @@ -127,7 +127,7 @@ func Chain(chainID int64) *chains.Chain { vmLen := len(chains.Vm_name) consensusLen := len(chains.Consensus_name) - return &chains.Chain{ + return chains.Chain{ ChainId: chainID, ChainName: chains.ChainName(r.Intn(chainNameLen)), Network: chains.Network(r.Intn(networkLen)), diff --git a/x/authority/keeper/chain_info.go b/x/authority/keeper/chain_info.go index 5c9056fe0c..557ef7f1c4 100644 --- a/x/authority/keeper/chain_info.go +++ b/x/authority/keeper/chain_info.go @@ -4,6 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/x/authority/types" ) @@ -24,3 +25,15 @@ func (k Keeper) GetChainInfo(ctx sdk.Context) (val types.ChainInfo, found bool) k.cdc.MustUnmarshal(b, &val) return val, true } + +// GetAdditionalChainList returns the list of chains in chain info object +// additional chains are additional static chain information stored on-chain used in addition with the default chain information +// this list allow to add new chain support without doing an upgrade +// returns empty list if no chains are present +func (k Keeper) GetAdditionalChainList(ctx sdk.Context) []chains.Chain { + chainInfo, found := k.GetChainInfo(ctx) + if !found { + return nil + } + return chainInfo.Chains +} diff --git a/x/authority/keeper/chain_info_test.go b/x/authority/keeper/chain_info_test.go index 87424cb4dd..59f1714504 100644 --- a/x/authority/keeper/chain_info_test.go +++ b/x/authority/keeper/chain_info_test.go @@ -31,3 +31,19 @@ func TestKeeper_SetChainInfo(t *testing.T) { require.True(t, found) require.Equal(t, newChainInfo, got) } + +func TestKeeper_GetChainList(t *testing.T) { + k, ctx := keepertest.AuthorityKeeper(t) + + // Empty list + list := k.GetAdditionalChainList(ctx) + require.Empty(t, list) + + // Set chain info + chainInfo := sample.ChainInfo(42) + k.SetChainInfo(ctx, chainInfo) + + // Check list + list = k.GetAdditionalChainList(ctx) + require.Equal(t, chainInfo.Chains, list) +} diff --git a/x/authority/keeper/grpc_query_chain_info.go b/x/authority/keeper/grpc_query_chain_info.go index 695fcee025..f3632d71a6 100644 --- a/x/authority/keeper/grpc_query_chain_info.go +++ b/x/authority/keeper/grpc_query_chain_info.go @@ -7,6 +7,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/x/authority/types" ) @@ -21,9 +22,10 @@ func (k Keeper) ChainInfo( ctx := sdk.UnwrapSDKContext(c) // fetch chain info + // if the object has not been initialized, return an object containing an empty list chainInfo, found := k.GetChainInfo(ctx) if !found { - return nil, status.Error(codes.NotFound, "chain info not found") + chainInfo.Chains = []chains.Chain{} } return &types.QueryGetChainInfoResponse{ChainInfo: chainInfo}, nil diff --git a/x/authority/keeper/grpc_query_chain_info_test.go b/x/authority/keeper/grpc_query_chain_info_test.go index 7529e27437..bd20475a31 100644 --- a/x/authority/keeper/grpc_query_chain_info_test.go +++ b/x/authority/keeper/grpc_query_chain_info_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "github.com/zeta-chain/zetacore/pkg/chains" "testing" "github.com/stretchr/testify/require" @@ -21,8 +22,13 @@ func TestKeeper_ChainInfo(t *testing.T) { t.Run("chain info not found", func(t *testing.T) { k, ctx := keepertest.AuthorityKeeper(t) - _, err := k.ChainInfo(ctx, &types.QueryGetChainInfoRequest{}) - require.ErrorContains(t, err, "chain info not found") + res, err := k.ChainInfo(ctx, &types.QueryGetChainInfoRequest{}) + require.NoError(t, err) + require.Equal(t, res, &types.QueryGetChainInfoResponse{ + ChainInfo: types.ChainInfo{ + Chains: []chains.Chain{}, + }, + }) }) t.Run("can retrieve chain info", func(t *testing.T) { diff --git a/x/crosschain/keeper/abci.go b/x/crosschain/keeper/abci.go index 4897ae6f66..ee6cfb3aa3 100644 --- a/x/crosschain/keeper/abci.go +++ b/x/crosschain/keeper/abci.go @@ -30,7 +30,7 @@ type CheckAndUpdateCctxGasPriceFunc func( // The function returns the number of cctxs updated and the gas price increase flags used func (k Keeper) IterateAndUpdateCctxGasPrice( ctx sdk.Context, - chains []*zetachains.Chain, + chains []zetachains.Chain, updateFunc CheckAndUpdateCctxGasPriceFunc, ) (int, observertypes.GasPriceIncreaseFlags) { // fetch the gas price increase flags or use default @@ -45,12 +45,14 @@ func (k Keeper) IterateAndUpdateCctxGasPrice( return 0, gasPriceIncreaseFlags } + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + cctxCount := 0 IterateChains: for _, chain := range chains { // support only external evm chains - if zetachains.IsEVMChain(chain.ChainId) && !zetachains.IsZetaChain(chain.ChainId) { + if zetachains.IsEVMChain(chain.ChainId, additionalChains) && !zetachains.IsZetaChain(chain.ChainId, additionalChains) { res, err := k.ListPendingCctx(sdk.UnwrapSDKContext(ctx), &types.QueryListPendingCctxRequest{ ChainId: chain.ChainId, Limit: gasPriceIncreaseFlags.MaxPendingCctxs, diff --git a/x/crosschain/keeper/abci_test.go b/x/crosschain/keeper/abci_test.go index 36736b254b..817f930079 100644 --- a/x/crosschain/keeper/abci_test.go +++ b/x/crosschain/keeper/abci_test.go @@ -42,7 +42,7 @@ func TestKeeper_IterateAndUpdateCctxGasPrice(t *testing.T) { } // add some evm and non-evm chains - supportedChains := []*chains.Chain{ + supportedChains := []chains.Chain{ {ChainId: chains.Ethereum.ChainId}, {ChainId: chains.BitcoinMainnet.ChainId}, {ChainId: chains.BscMainnet.ChainId}, diff --git a/x/crosschain/keeper/cctx_gateway_observers.go b/x/crosschain/keeper/cctx_gateway_observers.go index 7155e61cd0..18bf31afb8 100644 --- a/x/crosschain/keeper/cctx_gateway_observers.go +++ b/x/crosschain/keeper/cctx_gateway_observers.go @@ -41,7 +41,10 @@ func (c CCTXGatewayObservers) InitiateOutbound( outboundReceiverChainID := config.CCTX.GetCurrentOutboundParam().ReceiverChainId // TODO (https://github.com/zeta-chain/node/issues/1010): workaround for this bug noEthereumTxEvent := false - if chains.IsZetaChain(config.CCTX.InboundParams.SenderChainId) { + if chains.IsZetaChain( + config.CCTX.InboundParams.SenderChainId, + c.crosschainKeeper.GetAuthorityKeeper().GetAdditionalChainList(ctx), + ) { noEthereumTxEvent = true } diff --git a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go index 77989b88fe..a1a25e9988 100644 --- a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go +++ b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go @@ -121,7 +121,7 @@ func (k Keeper) validateFailedOutboundObservers(ctx sdk.Context, cctx *types.Cro // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed cctx.SetAbort("Outbound failed") - } else if chains.IsZetaChain(cctx.InboundParams.SenderChainId) { + } else if chains.IsZetaChain(cctx.InboundParams.SenderChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { switch cctx.InboundParams.CoinType { // Try revert if the coin-type is ZETA case coin.CoinType_Zeta: @@ -159,8 +159,7 @@ func (k Keeper) validateFailedOutbound( ) error { switch oldStatus { case types.CctxStatus_PendingOutbound: - senderChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundParams.SenderChainId) - if senderChain == nil { + if _, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundParams.SenderChainId); !found { return observertypes.ErrSupportedChains } diff --git a/x/crosschain/keeper/cctx_orchestrator_validate_outbound_test.go b/x/crosschain/keeper/cctx_orchestrator_validate_outbound_test.go index fff52e599a..4d97c166f4 100644 --- a/x/crosschain/keeper/cctx_orchestrator_validate_outbound_test.go +++ b/x/crosschain/keeper/cctx_orchestrator_validate_outbound_test.go @@ -248,18 +248,15 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { asset := "" // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + _ = keepertest.MockUpdateNonce(observerMock, senderChain) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -288,18 +285,15 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { asset := "" // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 0) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 0) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + _ = keepertest.MockUpdateNonce(observerMock, senderChain) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -328,10 +322,10 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { asset := "" // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful GetSupportedChainFromChainID keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) @@ -340,7 +334,7 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). Return(observertypes.ChainNonces{}, false) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -367,7 +361,7 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { asset := "" // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful GetSupportedChainFromChainID keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) @@ -375,7 +369,7 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { // mock failed failed GetSupportedChainFromChainID to fail PayGasAndUpdateCctx keepertest.MockFailedGetSupportedChainFromChainID(observerMock, senderChain) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -405,7 +399,7 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { Zrc20ContractAddress: sample.EthAddress().String(), }, false).Once() - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -487,7 +481,7 @@ func TestKeeper_ValidateOutboundObservers(t *testing.T) { senderChain := getValidEthChain() asset := "" - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound oldOutboundParamsLen := len(cctx.OutboundParams) // mock failed GetRevertGasLimit for ERC20 @@ -521,7 +515,7 @@ func TestKeeper_ValidateOutboundObservers(t *testing.T) { senderChain := getValidEthChain() asset := "" - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.OutboundParams = append(cctx.OutboundParams, sample.OutboundParams(sample.Rand())) cctx.OutboundParams[1].ReceiverChainId = 5 cctx.OutboundParams[1].BallotIndex = "" @@ -529,7 +523,7 @@ func TestKeeper_ValidateOutboundObservers(t *testing.T) { cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) err := k.ValidateOutboundObservers( ctx, @@ -554,20 +548,17 @@ func TestKeeper_ValidateOutboundObservers(t *testing.T) { senderChain := getValidEthChain() asset := "" - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound oldOutboundParamsLen := len(cctx.OutboundParams) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + _ = keepertest.MockUpdateNonce(observerMock, senderChain) err := k.ValidateOutboundObservers( ctx, diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 3d3cf31cd5..8996ad0b5a 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -19,8 +19,8 @@ import ( // SetObserverOutboundInfo sets the CCTX outbound nonce to the next available nonce for the TSS address, and updates the nonce of blockchain state. // It also updates the PendingNonces that is used to track the unfulfilled outbound txs. func (k Keeper) SetObserverOutboundInfo(ctx sdk.Context, receiveChainID int64, cctx *types.CrossChainTx) error { - chain := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, receiveChainID) - if chain == nil { + chain, found := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, receiveChainID) + if !found { return zetaObserverTypes.ErrSupportedChains } diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 798fcdd8c4..dc05117c4e 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -234,7 +234,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock failed GetSupportedChainFromChainID - keepertest.MockFailedGetSupportedChainFromChainID(observerMock, nil) + keepertest.MockFailedGetSupportedChainFromChainID(observerMock, sample.Chain(5)) err := k.SetObserverOutboundInfo(ctx, 5, nil) require.Error(t, err) @@ -248,7 +248,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) @@ -274,7 +274,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) @@ -304,7 +304,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) @@ -336,7 +336,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) @@ -370,7 +370,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) diff --git a/x/crosschain/keeper/events.go b/x/crosschain/keeper/events.go index c503835f14..42b32bc589 100644 --- a/x/crosschain/keeper/events.go +++ b/x/crosschain/keeper/events.go @@ -5,7 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -15,13 +14,11 @@ func EmitEventInboundFinalized(ctx sdk.Context, cctx *types.CrossChainTx) { MsgTypeUrl: sdk.MsgTypeURL(&types.MsgVoteInbound{}), CctxIndex: cctx.Index, Sender: cctx.InboundParams.Sender, - SenderChain: chains.GetChainFromChainID(cctx.InboundParams.SenderChainId).ChainName.String(), TxOrgin: cctx.InboundParams.TxOrigin, Asset: cctx.InboundParams.Asset, InboundHash: cctx.InboundParams.ObservedHash, InboundBlockHeight: strconv.FormatUint(cctx.InboundParams.ObservedExternalHeight, 10), Receiver: currentOutParam.Receiver, - ReceiverChain: chains.GetChainFromChainID(currentOutParam.ReceiverChainId).ChainName.String(), Amount: cctx.InboundParams.Amount.String(), RelayedMessage: cctx.RelayedMessage, NewStatus: cctx.CctxStatus.Status.String(), diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index 858c709f18..0b60a3c9e6 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -78,7 +78,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo to = parsedAddress } - from, err := chains.DecodeAddressFromChainID(inboundSenderChainID, inboundSender) + from, err := chains.DecodeAddressFromChainID(inboundSenderChainID, inboundSender, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) if err != nil { return false, fmt.Errorf("HandleEVMDeposit: unable to decode address: %s", err.Error()) } diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index 2fc6310800..366dff4ee4 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -105,7 +105,7 @@ func (k Keeper) ProcessLogs( // If Validation fails, we will not process the event and return and error. This condition means that the event was correct, and emitted from a registered ZRC20 contract // But the information entered by the user is incorrect. In this case we can return an error and roll back the transaction - if err := ValidateZrc20WithdrawEvent(eventZrc20Withdrawal, coin.ForeignChainId); err != nil { + if err := k.ValidateZrc20WithdrawEvent(ctx, eventZrc20Withdrawal, coin.ForeignChainId); err != nil { return err } // If the event is valid, we will process it and create a new CCTX @@ -137,18 +137,21 @@ func (k Keeper) ProcessZRC20WithdrawalEvent( if !found { return fmt.Errorf("cannot find foreign coin with emittingContract address %s", event.Raw.Address.Hex()) } - receiverChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, foreignCoin.ForeignChainId) - if receiverChain == nil { + + receiverChain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, foreignCoin.ForeignChainId) + if !found { return errorsmod.Wrapf( observertypes.ErrSupportedChains, "chain with chainID %d not supported", foreignCoin.ForeignChainId, ) } - senderChain, err := chains.ZetaChainFromChainID(ctx.ChainID()) + + senderChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) if err != nil { return fmt.Errorf("ProcessZRC20WithdrawalEvent: failed to convert chainID: %s", err.Error()) } + toAddr, err := receiverChain.EncodeAddress(event.To) if err != nil { return fmt.Errorf("cannot encode address %s: %s", event.To, err.Error()) @@ -215,23 +218,27 @@ func (k Keeper) ProcessZetaSentEvent( receiverChainID := event.DestinationChainId - receiverChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, receiverChainID.Int64()) - if receiverChain == nil { + receiverChain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, receiverChainID.Int64()) + if !found { return observertypes.ErrSupportedChains } + // Validation if we want to send ZETA to an external chain, but there is no ZETA token. chainParams, found := k.zetaObserverKeeper.GetChainParamsByChainID(ctx, receiverChain.ChainId) if !found { return observertypes.ErrChainParamsNotFound } + if receiverChain.IsExternalChain() && chainParams.ZetaTokenContractAddress == "" { return types.ErrUnableToSendCoinType } + toAddr := "0x" + hex.EncodeToString(event.DestinationAddress) - senderChain, err := chains.ZetaChainFromChainID(ctx.ChainID()) + senderChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) if err != nil { return fmt.Errorf("ProcessZetaSentEvent: failed to convert chainID: %s", err.Error()) } + amount := math.NewUintFromBigInt(event.ZetaValueAndGas) messageString := base64.StdEncoding.EncodeToString(event.Message) // Bump gasLimit by event index (which is very unlikely to be larger than 1000) to always have different ZetaSent events msgs. @@ -264,29 +271,12 @@ func (k Keeper) ProcessZetaSentEvent( return nil } -// ParseZRC20WithdrawalEvent tries extracting ZRC20Withdrawal event from the input logs using the zrc20 contract; -// It only returns a not-nil event if the event has been correctly validated as a valid withdrawal event -func ParseZRC20WithdrawalEvent(log ethtypes.Log) (*zrc20.ZRC20Withdrawal, error) { - zrc20ZEVM, err := zrc20.NewZRC20Filterer(log.Address, bind.ContractFilterer(nil)) - if err != nil { - return nil, err - } - if len(log.Topics) == 0 { - return nil, fmt.Errorf("ParseZRC20WithdrawalEvent: invalid log - no topics") - } - event, err := zrc20ZEVM.ParseWithdrawal(log) - if err != nil { - return nil, err - } - return event, nil -} - // ValidateZrc20WithdrawEvent checks if the ZRC20Withdrawal event is valid // It verifies event information for BTC chains and returns an error if the event is invalid -func ValidateZrc20WithdrawEvent(event *zrc20.ZRC20Withdrawal, chainID int64) error { +func (k Keeper) ValidateZrc20WithdrawEvent(ctx sdk.Context, event *zrc20.ZRC20Withdrawal, chainID int64) error { // The event was parsed; that means the user has deposited tokens to the contract. - if chains.IsBitcoinChain(chainID) { + if chains.IsBitcoinChain(chainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { if event.Value.Cmp(big.NewInt(constant.BTCWithdrawalDustAmount)) < 0 { return errorsmod.Wrapf( types.ErrInvalidWithdrawalAmount, @@ -306,6 +296,23 @@ func ValidateZrc20WithdrawEvent(event *zrc20.ZRC20Withdrawal, chainID int64) err return nil } +// ParseZRC20WithdrawalEvent tries extracting ZRC20Withdrawal event from the input logs using the zrc20 contract; +// It only returns a not-nil event if the event has been correctly validated as a valid withdrawal event +func ParseZRC20WithdrawalEvent(log ethtypes.Log) (*zrc20.ZRC20Withdrawal, error) { + zrc20ZEVM, err := zrc20.NewZRC20Filterer(log.Address, bind.ContractFilterer(nil)) + if err != nil { + return nil, err + } + if len(log.Topics) == 0 { + return nil, fmt.Errorf("ParseZRC20WithdrawalEvent: invalid log - no topics") + } + event, err := zrc20ZEVM.ParseWithdrawal(log) + if err != nil { + return nil, err + } + return event, nil +} + // ParseZetaSentEvent tries extracting ZetaSent event from connectorZEVM contract; // returns error if the log entry is not a ZetaSent event, or is not emitted from connectorZEVM // It only returns a not-nil event if all the error checks pass diff --git a/x/crosschain/keeper/evm_hooks_test.go b/x/crosschain/keeper/evm_hooks_test.go index 20b1c87e47..36b8938a8a 100644 --- a/x/crosschain/keeper/evm_hooks_test.go +++ b/x/crosschain/keeper/evm_hooks_test.go @@ -157,15 +157,17 @@ func TestParseZRC20WithdrawalEvent(t *testing.T) { } func TestValidateZrc20WithdrawEvent(t *testing.T) { t.Run("successfully validate a valid event", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], ) require.NoError(t, err) - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) require.NoError(t, err) }) t.Run("unable to validate a btc withdrawal event with an invalid amount", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], ) @@ -173,32 +175,34 @@ func TestValidateZrc20WithdrawEvent(t *testing.T) { // 1000 satoshis is the minimum amount that can be withdrawn btcMainNetWithdrawalEvent.Value = big.NewInt(constant.BTCWithdrawalDustAmount) - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) require.NoError(t, err) // 999 satoshis cannot be withdrawn btcMainNetWithdrawalEvent.Value = big.NewInt(constant.BTCWithdrawalDustAmount - 1) - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) require.ErrorContains(t, err, "less than minimum amount") }) t.Run("unable to validate a event with an invalid chain ID", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], ) require.NoError(t, err) - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinTestnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinTestnet.ChainId) require.ErrorContains(t, err, "invalid address") }) t.Run("unable to validate an unsupported address type", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], ) require.NoError(t, err) btcMainNetWithdrawalEvent.To = []byte("04b2891ba8cb491828db3ebc8a780d43b169e7b3974114e6e50f9bab6ec" + "63c2f20f6d31b2025377d05c2a704d3bd799d0d56f3a8543d79a01ab6084a1cb204f260") - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) require.ErrorContains(t, err, "unsupported address") }) } @@ -313,7 +317,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { ctx = ctx.WithChainID("test_21-1") err = k.ProcessZRC20WithdrawalEvent(ctx, event, emittingContract, txOrigin.Hex()) - require.ErrorContains(t, err, "failed to convert chainID: chain 21 not found") + require.ErrorContains(t, err, "failed to convert chainID") require.Empty(t, k.GetAllCrossChainTx(ctx)) }) diff --git a/x/crosschain/keeper/gas_payment.go b/x/crosschain/keeper/gas_payment.go index 58bfe4ffbf..efac718932 100644 --- a/x/crosschain/keeper/gas_payment.go +++ b/x/crosschain/keeper/gas_payment.go @@ -97,7 +97,7 @@ func (k Keeper) PayGasNativeAndUpdateCctx( cctx.InboundParams.CoinType.String(), ) } - if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { + if _, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); !found { return observertypes.ErrSupportedChains } @@ -151,7 +151,7 @@ func (k Keeper) PayGasInERC20AndUpdateCctx( ) } - if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { + if _, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); !found { return observertypes.ErrSupportedChains } // get gas params @@ -300,7 +300,7 @@ func (k Keeper) PayGasInZetaAndUpdateCctx( ) } - if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { + if _, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); !found { return observertypes.ErrSupportedChains } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 270fb10b87..d2eb8d85ea 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -64,7 +64,7 @@ func (k Keeper) RateLimiterInput( // if a cctx is an outgoing cctx that orginates from ZetaChain // reverted incoming cctx has an external `SenderChainId` and should not be counted isCCTXOutgoing := func(cctx *types.CrossChainTx) bool { - return chains.IsZetaChain(cctx.InboundParams.SenderChainId) + return chains.IsZetaChain(cctx.InboundParams.SenderChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) } // it is a past cctx if its nonce < `nonceLow`, @@ -272,7 +272,7 @@ func (k Keeper) ListPendingCctxWithinRateLimit( // if a cctx is outgoing from ZetaChain // reverted incoming cctx has an external `SenderChainId` and should not be counted isCCTXOutgoing := func(cctx *types.CrossChainTx) bool { - return chains.IsZetaChain(cctx.InboundParams.SenderChainId) + return chains.IsZetaChain(cctx.InboundParams.SenderChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) } // query pending nonces for each foreign chain and get the lowest height of the pending cctxs diff --git a/x/crosschain/keeper/grpc_query_zeta_conversion_rate.go b/x/crosschain/keeper/grpc_query_zeta_conversion_rate.go index 184b398b66..7abf0f5401 100644 --- a/x/crosschain/keeper/grpc_query_zeta_conversion_rate.go +++ b/x/crosschain/keeper/grpc_query_zeta_conversion_rate.go @@ -19,25 +19,29 @@ func (k Keeper) ConvertGasToZeta( request *types.QueryConvertGasToZetaRequest, ) (*types.QueryConvertGasToZetaResponse, error) { ctx := sdk.UnwrapSDKContext(context) - chain := chains.GetChainFromChainID(request.ChainId) - if chain == nil { + chain, found := chains.GetChainFromChainID(request.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return nil, zetaObserverTypes.ErrSupportedChains } + medianGasPrice, isFound := k.GetMedianGasPriceInUint(ctx, chain.ChainId) if !isFound { return nil, status.Error(codes.InvalidArgument, "invalid request: param chain") } + gasLimit := math.NewUintFromString(request.GasLimit) outTxGasFee := medianGasPrice.Mul(gasLimit) zrc20, err := k.fungibleKeeper.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chain.ChainId)) if err != nil { return nil, status.Error(codes.NotFound, "zrc20 not found") } + outTxGasFeeInZeta, err := k.fungibleKeeper.QueryUniswapV2RouterGetZetaAmountsIn(ctx, outTxGasFee.BigInt(), zrc20) if err != nil { return nil, status.Error(codes.Internal, "zQueryUniswapv2RouterGetAmountsIn failed") } + return &types.QueryConvertGasToZetaResponse{ OutboundGasInZeta: outTxGasFeeInZeta.String(), ProtocolFeeInZeta: types.GetProtocolFee().String(), diff --git a/x/crosschain/keeper/initiate_outbound.go b/x/crosschain/keeper/initiate_outbound.go index 954db18778..7435517f2f 100644 --- a/x/crosschain/keeper/initiate_outbound.go +++ b/x/crosschain/keeper/initiate_outbound.go @@ -24,8 +24,8 @@ type InitiateOutboundConfig struct { // which handles the state changes and error handling. func (k Keeper) InitiateOutbound(ctx sdk.Context, config InitiateOutboundConfig) (types.CctxStatus, error) { receiverChainID := config.CCTX.GetCurrentOutboundParam().ReceiverChainId - chainInfo := chains.GetChainFromChainID(receiverChainID) - if chainInfo == nil { + chainInfo, found := chains.GetChainFromChainID(receiverChainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return config.CCTX.CctxStatus.Status, cosmoserrors.Wrap( types.ErrInitiatitingOutbound, fmt.Sprintf( diff --git a/x/crosschain/keeper/initiate_outbound_test.go b/x/crosschain/keeper/initiate_outbound_test.go index 78175a76a8..212e1dae75 100644 --- a/x/crosschain/keeper/initiate_outbound_test.go +++ b/x/crosschain/keeper/initiate_outbound_test.go @@ -103,7 +103,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockFailedGetSupportedChainFromChainID(observerMock, senderChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + cctx := GetERC20Cctx(t, receiver, senderChain, "", amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -143,7 +143,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { Return(fungibletypes.ForeignCoins{}, false) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -180,13 +180,13 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock unsuccessful PayGasInERC20AndUpdateCctx keepertest.MockFailedGetSupportedChainFromChainID(observerMock, senderChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -225,13 +225,13 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 0) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 0) // mock unsuccessful PayGasInERC20AndUpdateCctx keepertest.MockFailedGetSupportedChainFromChainID(observerMock, senderChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -268,17 +268,17 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // Mock unsuccessful UpdateNonce observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). Return(observertypes.ChainNonces{}, false) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -306,19 +306,16 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful UpdateNonce - updatedNonce := keepertest.MockUpdateNonce(observerMock, *senderChain) + updatedNonce := keepertest.MockUpdateNonce(observerMock, senderChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -352,10 +349,10 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId cctx.OutboundParams = append(cctx.OutboundParams, cctx.GetCurrentOutboundParam()) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) @@ -386,18 +383,27 @@ func TestKeeper_InitiateOutboundProcessCrosschainMsgPassing(t *testing.T) { receiverChain := getValidEthChain() // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, receiverChain, "") // mock successful UpdateNonce - updatedNonce := keepertest.MockUpdateNonce(observerMock, *receiverChain) + nonce := uint64(1) + tss := sample.Tss() + observerMock.On("GetChainNonces", mock.Anything, receiverChain.ChainName.String()). + Return(observertypes.ChainNonces{Nonce: nonce}, true) + observerMock.On("GetTSS", mock.Anything). + Return(tss, true) + observerMock.On("GetPendingNonces", mock.Anything, tss.TssPubkey, mock.Anything). + Return(observertypes.PendingNonces{NonceHigh: int64(nonce)}, true) + observerMock.On("SetChainNonces", mock.Anything, mock.Anything) + observerMock.On("SetPendingNonces", mock.Anything, mock.Anything) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + cctx := GetERC20Cctx(t, receiver, receiverChain, "", amount) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) require.Equal(t, types.CctxStatus_PendingOutbound, newStatus) - require.Equal(t, updatedNonce, cctx.GetCurrentOutboundParam().TssNonce) + require.Equal(t, nonce, cctx.GetCurrentOutboundParam().TssNonce) }) t.Run("unable to process crosschain msg passing PayGasAndUpdateCctx fails", func(t *testing.T) { @@ -413,10 +419,10 @@ func TestKeeper_InitiateOutboundProcessCrosschainMsgPassing(t *testing.T) { receiverChain := getValidEthChain() // mock unsuccessful PayGasAndUpdateCctx - keepertest.MockFailedGetSupportedChainFromChainID(observerMock, nil) + keepertest.MockFailedGetSupportedChainFromChainID(observerMock, receiverChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + cctx := GetERC20Cctx(t, receiver, receiverChain, "", amount) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.ErrorIs(t, err, observertypes.ErrSupportedChains) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) @@ -438,14 +444,14 @@ func TestKeeper_InitiateOutboundProcessCrosschainMsgPassing(t *testing.T) { receiverChain := getValidEthChain() // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, receiverChain, "") // mock unsuccessful UpdateNonce observerMock.On("GetChainNonces", mock.Anything, receiverChain.ChainName.String()). Return(observertypes.ChainNonces{}, false) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + cctx := GetERC20Cctx(t, receiver, receiverChain, "", amount) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.ErrorContains(t, err, "cannot find receiver chain nonce") require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) @@ -467,7 +473,7 @@ func TestKeeper_InitiateOutboundFailures(t *testing.T) { receiverChain := getValidEthChain() receiverChain.ChainId = 123 // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + cctx := GetERC20Cctx(t, receiver, receiverChain, "", amount) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.Error(t, err) require.Equal(t, types.CctxStatus_PendingInbound, newStatus) diff --git a/x/crosschain/keeper/msg_server_add_inbound_tracker.go b/x/crosschain/keeper/msg_server_add_inbound_tracker.go index fd9b8fa2bd..ae35036e88 100644 --- a/x/crosschain/keeper/msg_server_add_inbound_tracker.go +++ b/x/crosschain/keeper/msg_server_add_inbound_tracker.go @@ -18,8 +18,8 @@ func (k msgServer) AddInboundTracker( msg *types.MsgAddInboundTracker, ) (*types.MsgAddInboundTrackerResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - chain := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + + if _, found := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, msg.ChainId); !found { return nil, observertypes.ErrSupportedChains } diff --git a/x/crosschain/keeper/msg_server_add_inbound_tracker_test.go b/x/crosschain/keeper/msg_server_add_inbound_tracker_test.go index 9d135d513d..0345cba1a1 100644 --- a/x/crosschain/keeper/msg_server_add_inbound_tracker_test.go +++ b/x/crosschain/keeper/msg_server_add_inbound_tracker_test.go @@ -33,7 +33,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) msg := types.MsgAddInboundTracker{ @@ -62,7 +62,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { chainID := getValidEthChainID() observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(nil) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, false) msg := types.MsgAddInboundTracker{ Creator: sample.AccAddress(), @@ -92,7 +92,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) setSupportedChain(ctx, zk, chainID) @@ -127,7 +127,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) msg := types.MsgAddInboundTracker{ @@ -161,7 +161,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil, errors.New("error")) @@ -195,7 +195,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(sample.Bytes(), nil) @@ -231,7 +231,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(sample.Bytes(), nil) @@ -271,7 +271,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) observerMock.On("GetChainParamsByChainID", mock.Anything, mock.Anything). Return(sample.ChainParams(chains.Ethereum.ChainId), true) @@ -317,7 +317,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) observerMock.On("GetChainParamsByChainID", mock.Anything, mock.Anything). Return(sample.ChainParams(chains.Ethereum.ChainId), true) diff --git a/x/crosschain/keeper/msg_server_add_outbound_tracker.go b/x/crosschain/keeper/msg_server_add_outbound_tracker.go index ce7b2f0c03..5a3c98e9e9 100644 --- a/x/crosschain/keeper/msg_server_add_outbound_tracker.go +++ b/x/crosschain/keeper/msg_server_add_outbound_tracker.go @@ -27,8 +27,7 @@ func (k msgServer) AddOutboundTracker( ctx := sdk.UnwrapSDKContext(goCtx) // check the chain is supported - chain := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + if _, found := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, msg.ChainId); !found { return nil, observertypes.ErrSupportedChains } @@ -138,7 +137,7 @@ func verifyProofAndOutboundBody(ctx sdk.Context, k msgServer, msg *types.MsgAddO // get tss address var bitcoinChainID int64 - if chains.IsBitcoinChain(msg.ChainId) { + if chains.IsBitcoinChain(msg.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { bitcoinChainID = msg.ChainId } diff --git a/x/crosschain/keeper/msg_server_add_outbound_tracker_test.go b/x/crosschain/keeper/msg_server_add_outbound_tracker_test.go index e43800b2ac..7abe63fe15 100644 --- a/x/crosschain/keeper/msg_server_add_outbound_tracker_test.go +++ b/x/crosschain/keeper/msg_server_add_outbound_tracker_test.go @@ -39,7 +39,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -74,7 +74,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { chainID := getEthereumChainID() hash := sample.Hash().Hex() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -110,7 +110,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { existinghHash := sample.Hash().Hex() newHash := sample.Hash().Hex() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -163,7 +163,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { } observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) // set cctx status to outbound mined keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_OutboundMined, false) @@ -187,7 +187,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { admin := sample.AccAddress() observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(nil) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, false) chainID := getEthereumChainID() @@ -214,7 +214,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, true) chainID := getEthereumChainID() @@ -245,7 +245,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { chainID := getEthereumChainID() newHash := sample.Hash().Hex() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -291,7 +291,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -340,7 +340,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) observerMock.On("GetTssAddress", mock.Anything, mock.Anything).Return(&observertypes.QueryGetTssAddressResponse{ @@ -359,6 +359,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { Nonce: 42, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.AddOutboundTracker(ctx, &msg) require.NoError(t, err) tracker, found := k.GetOutboundTracker(ctx, chainID, 42) @@ -384,7 +385,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) observerMock.On("GetTssAddress", mock.Anything, mock.Anything).Return(&observertypes.QueryGetTssAddressResponse{ @@ -418,6 +419,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { Nonce: 42, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.AddOutboundTracker(ctx, &msg) require.NoError(t, err) tracker, found := k.GetOutboundTracker(ctx, chainID, 42) @@ -444,7 +446,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). @@ -481,7 +483,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). @@ -500,6 +502,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { Nonce: 42, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.AddOutboundTracker(ctx, &msg) require.ErrorIs(t, err, observertypes.ErrTssNotFound) }) @@ -520,7 +523,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) observerMock.On("GetTssAddress", mock.Anything, mock.Anything).Return(&observertypes.QueryGetTssAddressResponse{ @@ -541,6 +544,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { Nonce: 42, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.AddOutboundTracker(ctx, &msg) require.ErrorIs(t, err, types.ErrTxBodyVerificationFail) }) diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds.go b/x/crosschain/keeper/msg_server_migrate_tss_funds.go index 05f218162f..f5558fe689 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds.go @@ -143,9 +143,14 @@ func (k Keeper) MigrateTSSFundsForChain( EffectiveGasPrice: sdkmath.Int{}, EffectiveGasLimit: 0, TssPubkey: currentTss.TssPubkey, - }}} + }}, + } + + // retrieve from authority keeper additional chains + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + // Set the sender and receiver addresses for EVM chain - if chains.IsEVMChain(chainID) { + if chains.IsEVMChain(chainID, additionalChains) { ethAddressOld, err := zetacrypto.GetTssAddrEVM(currentTss.TssPubkey) if err != nil { return err @@ -179,7 +184,7 @@ func (k Keeper) MigrateTSSFundsForChain( cctx.GetCurrentOutboundParam().Amount = amount.Sub(evmFee) } // Set the sender and receiver addresses for Bitcoin chain - if chains.IsBitcoinChain(chainID) { + if chains.IsBitcoinChain(chainID, additionalChains) { bitcoinNetParams, err := chains.BitcoinNetParamsFromChainID(chainID) if err != nil { return err diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go b/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go index fbd3c870bf..9da596f876 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go @@ -99,7 +99,7 @@ func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) gp, found := k.GetMedianGasPriceInUint(ctx, chain.ChainId) require.True(t, found) msg := crosschaintypes.MsgMigrateTssFunds{ @@ -108,6 +108,7 @@ func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.NoError(t, err) hash := crypto.Keccak256Hash([]byte(indexString)) @@ -131,7 +132,7 @@ func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) gp, found := k.GetMedianGasPriceInUint(ctx, chain.ChainId) require.True(t, found) @@ -141,6 +142,7 @@ func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.NoError(t, err) hash := crypto.Keccak256Hash([]byte(indexString)) @@ -368,7 +370,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) msg := crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -376,6 +378,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.NoError(t, err) hash := crypto.Keccak256Hash([]byte(indexString)) @@ -398,7 +401,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) msg := crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -406,6 +409,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.ErrorContains(t, err, crosschaintypes.ErrCannotMigrateTssFunds.Error()) hash := crypto.Keccak256Hash([]byte(indexString)) @@ -425,7 +429,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, false, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, false, true) msg := crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -452,7 +456,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) k.GetObserverKeeper().SetPendingNonces(ctx, observertypes.PendingNonces{ NonceLow: 1, NonceHigh: 10, @@ -486,7 +490,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) k.GetObserverKeeper().SetPendingNonces(ctx, observertypes.PendingNonces{ NonceLow: 1, NonceHigh: 1, @@ -507,6 +511,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.ErrorIs(t, err, crosschaintypes.ErrCannotMigrateTssFunds) require.ErrorContains(t, err, "cannot migrate funds while there are pending migrations") @@ -532,7 +537,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, false, false) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, false, false) currentTss, found := k.GetObserverKeeper().GetTSS(ctx) require.True(t, found) newTss := sample.Tss() diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index bf3678ecaf..91ef323ad9 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -116,6 +116,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { RefundAddress: cctx.InboundParams.Sender, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.RefundAbortedCCTX(ctx, &msg) require.NoError(t, err) @@ -160,6 +161,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { RefundAddress: cctx.InboundParams.Sender, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.RefundAbortedCCTX(ctx, &msg) require.NoError(t, err) @@ -274,6 +276,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { RefundAddress: refundAddress.String(), } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.RefundAbortedCCTX(ctx, &msg) require.NoError(t, err) @@ -325,6 +328,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { RefundAddress: cctx.InboundParams.Sender, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.RefundAbortedCCTX(ctx, &msg) require.NoError(t, err) diff --git a/x/crosschain/keeper/msg_server_vote_gas_price.go b/x/crosschain/keeper/msg_server_vote_gas_price.go index 2fd84affc3..a5fbaf4c0c 100644 --- a/x/crosschain/keeper/msg_server_vote_gas_price.go +++ b/x/crosschain/keeper/msg_server_vote_gas_price.go @@ -26,8 +26,8 @@ func (k msgServer) VoteGasPrice( ) (*types.MsgVoteGasPriceResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + chain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, msg.ChainId) + if !found { return nil, cosmoserrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf("ChainID : %d ", msg.ChainId)) } if ok := k.zetaObserverKeeper.IsNonTombstonedObserver(ctx, msg.Creator); !ok { diff --git a/x/crosschain/keeper/msg_server_vote_gas_price_test.go b/x/crosschain/keeper/msg_server_vote_gas_price_test.go index a876e2582c..b5da0f0c1e 100644 --- a/x/crosschain/keeper/msg_server_vote_gas_price_test.go +++ b/x/crosschain/keeper/msg_server_vote_gas_price_test.go @@ -21,7 +21,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockFailedGetSupportedChainFromChainID(observerMock, nil) + keepertest.MockFailedGetSupportedChainFromChainID(observerMock, sample.Chain(5)) msgServer := keeper.NewMsgServerImpl(*k) res, err := msgServer.VoteGasPrice(ctx, &types.MsgVoteGasPrice{ @@ -37,7 +37,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, nil) + keepertest.MockGetSupportedChainFromChainID(observerMock, sample.Chain(5)) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) msgServer := keeper.NewMsgServerImpl(*k) @@ -56,7 +56,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainId: 5, }) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) @@ -81,7 +81,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainId: 5, }) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) @@ -118,7 +118,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainId: 5, }) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) @@ -164,7 +164,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainId: 5, }) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index 64a2153611..be03a407e5 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -53,10 +53,10 @@ func TestKeeper_VoteInbound(t *testing.T) { to, from := int64(1337), int64(101) supportedChains := zk.ObserverKeeper.GetSupportedChains(ctx) for _, chain := range supportedChains { - if chains.IsEVMChain(chain.ChainId) { + if chains.IsEVMChain(chain.ChainId, []chains.Chain{}) { from = chain.ChainId } - if chains.IsZetaChain(chain.ChainId) { + if chains.IsZetaChain(chain.ChainId, []chains.Chain{}) { to = chain.ChainId } } @@ -78,10 +78,14 @@ func TestKeeper_VoteInbound(t *testing.T) { ) require.NoError(t, err) } + + chain, found := zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, msg.SenderChainId) + require.True(t, found) + ballot, _, _ := zk.ObserverKeeper.FindBallot( ctx, msg.Digest(), - zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, msg.SenderChainId), + chain, observertypes.ObservationType_InboundTx, ) require.Equal(t, ballot.BallotStatus, observertypes.BallotStatus_BallotFinalized_SuccessObservation) @@ -201,10 +205,10 @@ func TestKeeper_VoteInbound(t *testing.T) { to, from := int64(1337), int64(101) supportedChains := zk.ObserverKeeper.GetSupportedChains(ctx) for _, chain := range supportedChains { - if chains.IsEVMChain(chain.ChainId) { + if chains.IsEVMChain(chain.ChainId, []chains.Chain{}) { from = chain.ChainId } - if chains.IsZetaChain(chain.ChainId) { + if chains.IsZetaChain(chain.ChainId, []chains.Chain{}) { to = chain.ChainId } } @@ -219,16 +223,20 @@ func TestKeeper_VoteInbound(t *testing.T) { ) require.NoError(t, err) } + + chain, found := zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, msg.SenderChainId) + require.True(t, found) + ballot, _, _ := zk.ObserverKeeper.FindBallot( ctx, msg.Digest(), - zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, msg.SenderChainId), + chain, observertypes.ObservationType_InboundTx, ) require.Equal(t, ballot.BallotStatus, observertypes.BallotStatus_BallotInProgress) require.Equal(t, ballot.Votes[0], observertypes.VoteType_SuccessObservation) require.Equal(t, ballot.Votes[1], observertypes.VoteType_NotYetVoted) - _, found := k.GetCrossChainTx(ctx, msg.Digest()) + _, found = k.GetCrossChainTx(ctx, msg.Digest()) require.False(t, found) }) @@ -307,7 +315,7 @@ func TestKeeper_SaveObservedInboundInformation(t *testing.T) { receiver := sample.EthAddress() amount := big.NewInt(42) senderChain := getValidEthChain() - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + cctx := GetERC20Cctx(t, receiver, senderChain, "", amount) eventIndex := sample.Uint64InRange(1, 100) k.SaveObservedInboundInformation(ctx, cctx, eventIndex) require.Equal(t, types.TxFinalizationStatus_Executed, cctx.InboundParams.TxFinalizationStatus) @@ -329,7 +337,7 @@ func TestKeeper_SaveObservedInboundInformation(t *testing.T) { receiver := sample.EthAddress() amount := big.NewInt(42) senderChain := getValidEthChain() - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + cctx := GetERC20Cctx(t, receiver, senderChain, "", amount) hash := sample.Hash() cctx.InboundParams.ObservedHash = hash.String() k.SetInboundTracker(ctx, types.InboundTracker{ diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go index 1fe87d98ea..77e52acede 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go @@ -137,14 +137,14 @@ func TestKeeper_VoteOutbound(t *testing.T) { observer := sample.AccAddress() tss := sample.Tss() zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() // Successfully mock VoteOnOutboundBallot - keepertest.MockVoteOnOutboundSuccessBallot(observerMock, ctx, cctx, *senderChain, observer) + keepertest.MockVoteOnOutboundSuccessBallot(observerMock, ctx, cctx, senderChain, observer) // Successfully mock GetOutbound keepertest.MockGetOutbound(observerMock, ctx) @@ -188,23 +188,22 @@ func TestKeeper_VoteOutbound(t *testing.T) { observer := sample.AccAddress() tss := sample.Tss() zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() // Successfully mock VoteOnOutboundBallot - keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, *senderChain, observer) + keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, senderChain, observer) // Successfully mock GetOutbound keepertest.MockGetOutbound(observerMock, ctx) // Successfully mock ProcessOutbound - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) + _ = keepertest.MockUpdateNonce(observerMock, senderChain) //Successfully mock SaveOutbound keepertest.MockSaveOutboundNewRevertCreated(observerMock, ctx, cctx, tss) @@ -248,21 +247,21 @@ func TestKeeper_VoteOutbound(t *testing.T) { observer := sample.AccAddress() tss := sample.Tss() zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() // Successfully mock VoteOnOutboundBallot - keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, *senderChain, observer) + keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, senderChain, observer) // Successfully mock GetOutbound keepertest.MockGetOutbound(observerMock, ctx) // Mock Failed ProcessOutbound - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). Return(observertypes.ChainNonces{}, false) keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) @@ -312,7 +311,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { observer := sample.AccAddress() tss := sample.Tss() zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) @@ -321,7 +320,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() // Successfully mock VoteOnOutboundBallot - keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, *senderChain, observer) + keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, senderChain, observer) // Successfully mock GetOutbound keepertest.MockGetOutbound(observerMock, ctx) @@ -330,7 +329,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, mock.Anything, mock.Anything). Return(fungibletypes.ForeignCoins{}, false) - // Successfully mock GetSupportedChainFromChainID + // Successfully mock GetSupportedChainFromChainID keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) //Successfully mock SaveFailedOutbound @@ -379,7 +378,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { }, ) sk.StakingKeeper.SetValidator(ctx, validator) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) @@ -426,7 +425,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { require.NoError(t, err) zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{accAddress.String()}}) sk.StakingKeeper.SetValidator(ctx, validator) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20.go b/x/crosschain/keeper/msg_server_whitelist_erc20.go index 04ceb4a1a4..e3ace26baa 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20.go @@ -63,8 +63,8 @@ func (k msgServer) WhitelistERC20( return nil, errorsmod.Wrapf(types.ErrCannotFindTSSKeys, "Cannot create new admin cmd of type whitelistERC20") } - chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + chain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, msg.ChainId) + if !found { return nil, errorsmod.Wrapf(types.ErrInvalidChainID, "chain id (%d) not supported", msg.ChainId) } diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index 19afd1be1f..a741434705 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -70,7 +70,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta( refundAmount := GetAbortedAmount(cctx) chainID := cctx.InboundParams.SenderChainId // check if chain is an EVM chain - if !chains.IsEVMChain(chainID) { + if !chains.IsEVMChain(chainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { return errors.New("only EVM chains are supported for refund when coin type is Zeta") } if cctx.InboundParams.Amount.IsNil() || cctx.InboundParams.Amount.IsZero() { @@ -96,7 +96,7 @@ func (k Keeper) RefundAmountOnZetaChainERC20( if cctx.InboundParams.CoinType != coin.CoinType_ERC20 { return errors.New("unsupported coin type for refund on ZetaChain") } - if !chains.IsEVMChain(cctx.InboundParams.SenderChainId) { + if !chains.IsEVMChain(cctx.InboundParams.SenderChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { return errors.New("only EVM chains are supported for refund on ZetaChain") } diff --git a/x/crosschain/keeper/utils_test.go b/x/crosschain/keeper/utils_test.go index 4539bd1637..6da6a501a2 100644 --- a/x/crosschain/keeper/utils_test.go +++ b/x/crosschain/keeper/utils_test.go @@ -27,14 +27,14 @@ func getValidEthChainID() int64 { } // getValidEthChain() get a valid eth chain -func getValidEthChain() *chains.Chain { +func getValidEthChain() chains.Chain { goerli := chains.GoerliLocalnet - return &goerli + return goerli } -func getValidBTCChain() *chains.Chain { +func getValidBTCChain() chains.Chain { btcRegNet := chains.BitcoinRegtest - return &btcRegNet + return btcRegNet } func getValidBtcChainID() int64 { diff --git a/x/crosschain/migrations/v4/migrate.go b/x/crosschain/migrations/v4/migrate.go index 367e9c54eb..b71fe26b1b 100644 --- a/x/crosschain/migrations/v4/migrate.go +++ b/x/crosschain/migrations/v4/migrate.go @@ -177,7 +177,7 @@ func SetBitcoinFinalizedInbound(ctx sdk.Context, crosschainKeeper crosschainKeep for _, cctx := range crosschainKeeper.GetAllCrossChainTx(ctx) { if cctx.InboundParams != nil { // check if bitcoin inbound - if chains.IsBitcoinChain(cctx.InboundParams.SenderChainId) { + if chains.IsBitcoinChain(cctx.InboundParams.SenderChainId, []chains.Chain{}) { // add finalized inbound crosschainKeeper.AddFinalizedInbound( ctx, diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go index fcb42dc4d0..bb650991f0 100644 --- a/x/crosschain/migrations/v5/migrate.go +++ b/x/crosschain/migrations/v5/migrate.go @@ -97,11 +97,11 @@ func SetZetaAccounting( switch cctx.InboundParams.CoinType { case coin.CoinType_ERC20: { - receiverChain := observerKeeper.GetSupportedChainFromChainID( + receiverChain, found := observerKeeper.GetSupportedChainFromChainID( ctx, cctx.GetCurrentOutboundParam().ReceiverChainId, ) - if receiverChain == nil { + if !found { ctx.Logger(). Error(fmt.Sprintf("Error getting chain from chain id: %d , cctx index", cctx.GetCurrentOutboundParam().ReceiverChainId), cctx.Index) continue diff --git a/x/crosschain/migrations/v5/migrate_test.go b/x/crosschain/migrations/v5/migrate_test.go index c95535a5b0..d3e55749c7 100644 --- a/x/crosschain/migrations/v5/migrate_test.go +++ b/x/crosschain/migrations/v5/migrate_test.go @@ -49,11 +49,11 @@ func TestMigrateStore(t *testing.T) { for _, cctx := range cctxListUpdated { switch cctx.InboundParams.CoinType { case coin.CoinType_ERC20: - receiverChain := zk.ObserverKeeper.GetSupportedChainFromChainID( + receiverChain, found := zk.ObserverKeeper.GetSupportedChainFromChainID( ctx, cctx.GetCurrentOutboundParam().ReceiverChainId, ) - require.NotNil(t, receiverChain) + require.True(t, found) if receiverChain.IsZetaChain() { require.True(t, cctx.CctxStatus.IsAbortRefunded) } else { diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index 1e2df98301..eecdf0cdf0 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -129,15 +129,6 @@ func TestCrossChainTx_Validate(t *testing.T) { require.ErrorContains(t, cctx.Validate(), "invalid index length 1") cctx = sample.CrossChainTx(t, "foo") cctx.InboundParams = sample.InboundParamsValidChainID(rand.New(rand.NewSource(42))) - cctx.InboundParams.SenderChainId = 1000 - require.ErrorContains(t, cctx.Validate(), "invalid sender chain id 1000") - cctx = sample.CrossChainTx(t, "foo") - cctx.OutboundParams = []*types.OutboundParams{sample.OutboundParamsValidChainID(rand.New(rand.NewSource(42)))} - cctx.InboundParams = sample.InboundParamsValidChainID(rand.New(rand.NewSource(42))) - cctx.InboundParams.ObservedHash = sample.Hash().String() - cctx.InboundParams.BallotIndex = sample.ZetaIndex(t) - cctx.OutboundParams[0].ReceiverChainId = 1000 - require.ErrorContains(t, cctx.Validate(), "invalid receiver chain id 1000") } func TestCrossChainTx_GetCurrentOutboundParam(t *testing.T) { diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index 6f35afa6c5..57f3d1492f 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -56,7 +56,7 @@ type ObserverKeeper interface { FindBallot( ctx sdk.Context, index string, - chain *chains.Chain, + chain chains.Chain, observationType observertypes.ObservationType, ) (ballot observertypes.Ballot, isNew bool, err error) AddBallotToList(ctx sdk.Context, ballot observertypes.Ballot) @@ -101,9 +101,9 @@ type ObserverKeeper interface { receiveStatus chains.ReceiveStatus, voter string, ) (bool, bool, observertypes.Ballot, string, error) - GetSupportedChainFromChainID(ctx sdk.Context, chainID int64) *chains.Chain - GetSupportedChains(ctx sdk.Context) []*chains.Chain - GetSupportedForeignChains(ctx sdk.Context) []*chains.Chain + GetSupportedChainFromChainID(ctx sdk.Context, chainID int64) (chains.Chain, bool) + GetSupportedChains(ctx sdk.Context) []chains.Chain + GetSupportedForeignChains(ctx sdk.Context) []chains.Chain } type FungibleKeeper interface { @@ -209,6 +209,7 @@ type FungibleKeeper interface { type AuthorityKeeper interface { CheckAuthorization(ctx sdk.Context, msg sdk.Msg) error + GetAdditionalChainList(ctx sdk.Context) (list []chains.Chain) } type LightclientKeeper interface { diff --git a/x/crosschain/types/inbound_params.go b/x/crosschain/types/inbound_params.go index f191d15e2d..18d75cd80f 100644 --- a/x/crosschain/types/inbound_params.go +++ b/x/crosschain/types/inbound_params.go @@ -2,8 +2,6 @@ package types import ( "fmt" - - "github.com/zeta-chain/zetacore/pkg/chains" ) func (m InboundParams) Validate() error { @@ -11,10 +9,6 @@ func (m InboundParams) Validate() error { return fmt.Errorf("sender cannot be empty") } - if chains.GetChainFromChainID(m.SenderChainId) == nil { - return fmt.Errorf("invalid sender chain id %d", m.SenderChainId) - } - if m.Amount.IsNil() { return fmt.Errorf("amount cannot be nil") } diff --git a/x/crosschain/types/inbound_params_test.go b/x/crosschain/types/inbound_params_test.go index 464f685475..42d92a8f3f 100644 --- a/x/crosschain/types/inbound_params_test.go +++ b/x/crosschain/types/inbound_params_test.go @@ -17,10 +17,6 @@ func TestInboundTxParams_Validate(t *testing.T) { inboundParams.Sender = "" require.ErrorContains(t, inboundParams.Validate(), "sender cannot be empty") - inboundParams = sample.InboundParamsValidChainID(r) - inboundParams.SenderChainId = 1000 - require.ErrorContains(t, inboundParams.Validate(), "invalid sender chain id 1000") - inboundParams = sample.InboundParamsValidChainID(r) inboundParams.Amount = sdkmath.Uint{} require.ErrorContains(t, inboundParams.Validate(), "amount cannot be nil") diff --git a/x/crosschain/types/message_add_inbound_tracker.go b/x/crosschain/types/message_add_inbound_tracker.go index 0734033569..1c4a0691e7 100644 --- a/x/crosschain/types/message_add_inbound_tracker.go +++ b/x/crosschain/types/message_add_inbound_tracker.go @@ -5,7 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/coin" ) @@ -48,20 +47,10 @@ func (msg *MsgAddInboundTracker) ValidateBasic() error { if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - chain := chains.GetChainFromChainID(msg.ChainId) - if chain == nil { - return errorsmod.Wrapf(ErrInvalidChainID, "chain id (%d)", msg.ChainId) - } - if msg.Proof != nil && !chain.SupportMerkleProof() { - return errorsmod.Wrapf( - ErrProofVerificationFail, - "chain id %d does not support proof-based trackers", - msg.ChainId, - ) - } + _, ok := coin.CoinType_value[msg.CoinType.String()] if !ok { - return errorsmod.Wrapf(ErrProofVerificationFail, "coin-type not supported") + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "coin-type not supported") } return nil } diff --git a/x/crosschain/types/message_add_inbound_tracker_test.go b/x/crosschain/types/message_add_inbound_tracker_test.go index 6251990d63..503c020c1d 100644 --- a/x/crosschain/types/message_add_inbound_tracker_test.go +++ b/x/crosschain/types/message_add_inbound_tracker_test.go @@ -10,7 +10,6 @@ import ( "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/coin" - "github.com/zeta-chain/zetacore/pkg/proofs" "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -31,30 +30,6 @@ func TestMsgAddInboundTracker_ValidateBasic(t *testing.T) { ), err: sdkerrors.ErrInvalidAddress, }, - { - name: "invalid chain id", - msg: types.NewMsgAddInboundTracker( - sample.AccAddress(), - 42, - coin.CoinType_Gas, - "hash", - ), - err: errorsmod.Wrapf(types.ErrInvalidChainID, "chain id (%d)", 42), - }, - { - name: "invalid proof", - msg: &types.MsgAddInboundTracker{ - Creator: sample.AccAddress(), - ChainId: chains.ZetaChainTestnet.ChainId, - CoinType: coin.CoinType_Gas, - Proof: &proofs.Proof{}, - }, - err: errorsmod.Wrapf( - types.ErrProofVerificationFail, - "chain id %d does not support proof-based trackers", - chains.ZetaChainTestnet.ChainId, - ), - }, { name: "invalid coin type", msg: &types.MsgAddInboundTracker{ @@ -62,7 +37,7 @@ func TestMsgAddInboundTracker_ValidateBasic(t *testing.T) { ChainId: chains.ZetaChainTestnet.ChainId, CoinType: 5, }, - err: errorsmod.Wrapf(types.ErrProofVerificationFail, "coin-type not supported"), + err: errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "coin-type not supported"), }, { name: "valid", diff --git a/x/crosschain/types/message_migrate_tss_funds.go b/x/crosschain/types/message_migrate_tss_funds.go index 2de565c72d..0f4d5a2ecf 100644 --- a/x/crosschain/types/message_migrate_tss_funds.go +++ b/x/crosschain/types/message_migrate_tss_funds.go @@ -5,8 +5,6 @@ import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const TypeMsgMigrateTssFunds = "MigrateTssFunds" @@ -47,9 +45,7 @@ func (msg *MsgMigrateTssFunds) ValidateBasic() error { if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - if chains.GetChainFromChainID(msg.ChainId) == nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid chain id (%d)", msg.ChainId) - } + if msg.Amount.IsZero() { return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "amount cannot be zero") } diff --git a/x/crosschain/types/message_migrate_tss_funds_test.go b/x/crosschain/types/message_migrate_tss_funds_test.go index f07943bf59..5514af9034 100644 --- a/x/crosschain/types/message_migrate_tss_funds_test.go +++ b/x/crosschain/types/message_migrate_tss_funds_test.go @@ -29,15 +29,6 @@ func TestNewMsgMigrateTssFunds_ValidateBasic(t *testing.T) { ), error: true, }, - { - name: "invalid chain id", - msg: types.NewMsgMigrateTssFunds( - sample.AccAddress(), - 999, - sdkmath.NewUintFromString("100000"), - ), - error: true, - }, { name: "invalid amount", msg: types.NewMsgMigrateTssFunds( diff --git a/x/crosschain/types/outbound_params.go b/x/crosschain/types/outbound_params.go index 34458763dd..361462a1b4 100644 --- a/x/crosschain/types/outbound_params.go +++ b/x/crosschain/types/outbound_params.go @@ -3,8 +3,6 @@ package types import ( "fmt" "strconv" - - "github.com/zeta-chain/zetacore/pkg/chains" ) func (m OutboundParams) GetGasPriceUInt64() (uint64, error) { @@ -21,10 +19,6 @@ func (m OutboundParams) Validate() error { return fmt.Errorf("receiver cannot be empty") } - if chains.GetChainFromChainID(m.ReceiverChainId) == nil { - return fmt.Errorf("invalid receiver chain id %d", m.ReceiverChainId) - } - if m.Amount.IsNil() { return fmt.Errorf("amount cannot be nil") } diff --git a/x/crosschain/types/outbound_params_test.go b/x/crosschain/types/outbound_params_test.go index e5caa4b1b0..16bfc17844 100644 --- a/x/crosschain/types/outbound_params_test.go +++ b/x/crosschain/types/outbound_params_test.go @@ -16,10 +16,6 @@ func TestOutboundParams_Validate(t *testing.T) { outTxParams.Receiver = "" require.ErrorContains(t, outTxParams.Validate(), "receiver cannot be empty") - outTxParams = sample.OutboundParamsValidChainID(r) - outTxParams.ReceiverChainId = 1000 - require.ErrorContains(t, outTxParams.Validate(), "invalid receiver chain id 1000") - outTxParams = sample.OutboundParamsValidChainID(r) outTxParams.Amount = sdkmath.Uint{} require.ErrorContains(t, outTxParams.Validate(), "amount cannot be nil") diff --git a/x/crosschain/types/tx_body_verification.go b/x/crosschain/types/tx_body_verification.go index fbb8d4c6ea..84d71054f1 100644 --- a/x/crosschain/types/tx_body_verification.go +++ b/x/crosschain/types/tx_body_verification.go @@ -22,7 +22,10 @@ func VerifyInboundBody( tss observertypes.QueryGetTssAddressResponse, ) error { // verify message against transaction body - if chains.IsEVMChain(msg.ChainId) { + // NOTE: since this functionality is disabled on live network we don't provide on-chain additional chains for simplicity + // TODO: use authorityKeeper.GetChainInfo to provide additional chains + // https://github.com/zeta-chain/node/issues/2385 + if chains.IsEVMChain(msg.ChainId, []chains.Chain{}) { return verifyInboundBodyEVM(msg, txBytes, chainParams, tss) } @@ -79,9 +82,12 @@ func verifyInboundBodyEVM( // VerifyOutboundBody verifies the tx body for an outbound func VerifyOutboundBody(msg MsgAddOutboundTracker, txBytes []byte, tss observertypes.QueryGetTssAddressResponse) error { // verify message against transaction body - if chains.IsEVMChain(msg.ChainId) { + // NOTE: since this functionality is disabled on live network we don't provide on-chain additional chains for simplicity + // TODO: use authorityKeeper.GetChainInfo to provide additional chains + // https://github.com/zeta-chain/node/issues/2385 + if chains.IsEVMChain(msg.ChainId, []chains.Chain{}) { return verifyOutboundBodyEVM(msg, txBytes, tss.Eth) - } else if chains.IsBitcoinChain(msg.ChainId) { + } else if chains.IsBitcoinChain(msg.ChainId, []chains.Chain{}) { return verifyOutboundBodyBTC(msg, txBytes, tss.Btc) } return fmt.Errorf("cannot verify outbound body for chain %d", msg.ChainId) @@ -122,9 +128,6 @@ func verifyOutboundBodyEVM(msg MsgAddOutboundTracker, txBytes []byte, tssEth str // TODO: Implement tests for the function // https://github.com/zeta-chain/node/issues/1994 func verifyOutboundBodyBTC(msg MsgAddOutboundTracker, txBytes []byte, tssBtc string) error { - if !chains.IsBitcoinChain(msg.ChainId) { - return fmt.Errorf("not a Bitcoin chain ID %d", msg.ChainId) - } tx, err := btcutil.NewTxFromBytes(txBytes) if err != nil { return err diff --git a/x/crosschain/types/validate.go b/x/crosschain/types/validate.go index 58305ffa02..1f1dd3814d 100644 --- a/x/crosschain/types/validate.go +++ b/x/crosschain/types/validate.go @@ -20,15 +20,21 @@ func ValidateCCTXIndex(index string) error { } // ValidateHashForChain validates the hash for the chain +// NOTE: since these checks are currently not used, we don't provide additional chains for simplicity +// TODO: use authorityKeeper.GetChainInfo to provide additional chains +// https://github.com/zeta-chain/node/issues/2234 +// https://github.com/zeta-chain/node/issues/2385 +// NOTE: We should eventually not using these hard-coded checks at all since it might make the protocol too rigid +// Example: hash algorithm is changed for a chain: this required a upgrade on the protocol func ValidateHashForChain(hash string, chainID int64) error { - if chains.IsEthereumChain(chainID) || chains.IsZetaChain(chainID) { + if chains.IsEthereumChain(chainID, []chains.Chain{}) || chains.IsZetaChain(chainID, []chains.Chain{}) { _, err := hexutil.Decode(hash) if err != nil { return fmt.Errorf("hash must be a valid ethereum hash %s", hash) } return nil } - if chains.IsBitcoinChain(chainID) { + if chains.IsBitcoinChain(chainID, []chains.Chain{}) { r, err := regexp.Compile("^[a-fA-F0-9]{64}$") if err != nil { return fmt.Errorf("error compiling regex") @@ -42,18 +48,23 @@ func ValidateHashForChain(hash string, chainID int64) error { } // ValidateAddressForChain validates the address for the chain +// NOTE: since these checks are currently not used, we don't provide additional chains for simplicity +// TODO: use authorityKeeper.GetChainInfo to provide additional chains +// https://github.com/zeta-chain/node/issues/2234 +// https://github.com/zeta-chain/node/issues/2385 +// NOTE: We should eventually not using these hard-coded checks at all for same reasons as above func ValidateAddressForChain(address string, chainID int64) error { // we do not validate the address for zeta chain as the address field can be btc or eth address - if chains.IsZetaChain(chainID) { + if chains.IsZetaChain(chainID, []chains.Chain{}) { return nil } - if chains.IsEthereumChain(chainID) { + if chains.IsEthereumChain(chainID, []chains.Chain{}) { if !ethcommon.IsHexAddress(address) { return fmt.Errorf("invalid address %s , chain %d", address, chainID) } return nil } - if chains.IsBitcoinChain(chainID) { + if chains.IsBitcoinChain(chainID, []chains.Chain{}) { addr, err := chains.DecodeBtcAddress(address, chainID) if err != nil { return fmt.Errorf("invalid address %s , chain %d: %s", address, chainID, err) diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index 43bffb6e75..5a9d950b14 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -110,12 +110,13 @@ func (k Keeper) DeployZRC20Contract( erc20Contract string, gasLimit *big.Int, ) (common.Address, error) { - chain := chains.GetChainFromChainID(chainID) - if chain == nil { + chain, found := chains.GetChainFromChainID(chainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return common.Address{}, cosmoserrors.Wrapf(zetaObserverTypes.ErrSupportedChains, "chain %d not found", chainID) } + // Check if Contract has already been deployed for Asset - _, found := k.GetForeignCoinFromAsset(ctx, erc20Contract, chainID) + _, found = k.GetForeignCoinFromAsset(ctx, erc20Contract, chainID) if found { return common.Address{}, types.ErrForeignCoinAlreadyExist } diff --git a/x/fungible/keeper/gas_coin_and_pool.go b/x/fungible/keeper/gas_coin_and_pool.go index 1ee7ece40c..8e01e0dc49 100644 --- a/x/fungible/keeper/gas_coin_and_pool.go +++ b/x/fungible/keeper/gas_coin_and_pool.go @@ -28,8 +28,11 @@ func (k Keeper) SetupChainGasCoinAndPool( decimals uint8, gasLimit *big.Int, ) (ethcommon.Address, error) { - chain := chains.GetChainFromChainID(chainID) - if chain == nil { + // additional on-chain static chain information + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + + chain, found := chains.GetChainFromChainID(chainID, additionalChains) + if !found { return ethcommon.Address{}, zetaObserverTypes.ErrSupportedChains } name := fmt.Sprintf("%s-%s", gasAssetName, chain.ChainName) @@ -37,7 +40,7 @@ func (k Keeper) SetupChainGasCoinAndPool( transferGasLimit := gasLimit // Check if gas coin already exists - _, found := k.GetGasCoinForForeignCoin(ctx, chainID) + _, found = k.GetGasCoinForForeignCoin(ctx, chainID) if found { return ethcommon.Address{}, types.ErrForeignCoinAlreadyExist } @@ -45,7 +48,7 @@ func (k Keeper) SetupChainGasCoinAndPool( // default values if transferGasLimit == nil { transferGasLimit = big.NewInt(21_000) - if chains.IsBitcoinChain(chain.ChainId) { + if chains.IsBitcoinChain(chain.ChainId, additionalChains) { transferGasLimit = big.NewInt(100) // 100B for a typical tx } } diff --git a/x/fungible/keeper/grpc_query_gas_stability_pool.go b/x/fungible/keeper/grpc_query_gas_stability_pool.go index 321fdb7e5b..3541aad8d4 100644 --- a/x/fungible/keeper/grpc_query_gas_stability_pool.go +++ b/x/fungible/keeper/grpc_query_gas_stability_pool.go @@ -57,9 +57,6 @@ func (k Keeper) GasStabilityPoolBalanceAll( chains := k.observerKeeper.GetSupportedChains(ctx) balances := make([]types.QueryAllGasStabilityPoolBalanceResponse_Balance, 0, len(chains)) for _, chain := range chains { - if chain == nil { - return nil, status.Error(codes.Internal, "invalid chain") - } chainID := chain.ChainId balance, err := k.GetGasStabilityPoolBalance(ctx, chainID) diff --git a/x/fungible/keeper/grpc_query_gas_stability_pool_test.go b/x/fungible/keeper/grpc_query_gas_stability_pool_test.go index f503c76698..d2a256e927 100644 --- a/x/fungible/keeper/grpc_query_gas_stability_pool_test.go +++ b/x/fungible/keeper/grpc_query_gas_stability_pool_test.go @@ -79,32 +79,20 @@ func TestKeeper_GasStabilityPoolBalanceAll(t *testing.T) { UseObserverMock: true, }) observerMock := keepertest.GetFungibleObserverMock(t, k) - observerMock.On("GetSupportedChains", mock.Anything).Return([]*chains.Chain{}) + observerMock.On("GetSupportedChains", mock.Anything).Return([]chains.Chain{}) res, err := k.GasStabilityPoolBalanceAll(ctx, &types.QueryAllGasStabilityPoolBalance{}) require.NoError(t, err) require.Empty(t, res.Balances) }) - t.Run("should error if chain is nil", func(t *testing.T) { - k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ - UseObserverMock: true, - }) - observerMock := keepertest.GetFungibleObserverMock(t, k) - observerMock.On("GetSupportedChains", mock.Anything).Return([]*chains.Chain{nil}) - - res, err := k.GasStabilityPoolBalanceAll(ctx, &types.QueryAllGasStabilityPoolBalance{}) - require.Error(t, err) - require.Nil(t, res) - }) - t.Run("should error if system contracts not deployed", func(t *testing.T) { k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ UseObserverMock: true, }) observerMock := keepertest.GetFungibleObserverMock(t, k) chainID := 5 - observerMock.On("GetSupportedChains", mock.Anything).Return([]*chains.Chain{ + observerMock.On("GetSupportedChains", mock.Anything).Return([]chains.Chain{ { ChainName: chains.ChainName(chainID), ChainId: int64(chainID), @@ -124,7 +112,7 @@ func TestKeeper_GasStabilityPoolBalanceAll(t *testing.T) { observerMock := keepertest.GetFungibleObserverMock(t, k) chainID := 5 - observerMock.On("GetSupportedChains", mock.Anything).Return([]*chains.Chain{ + observerMock.On("GetSupportedChains", mock.Anything).Return([]chains.Chain{ { ChainName: chains.ChainName(chainID), ChainId: int64(chainID), diff --git a/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go b/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go index b37dd82cf7..903b63aa31 100644 --- a/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go +++ b/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go @@ -42,6 +42,7 @@ func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) { 1000000, ) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) res, err := msgServer.DeployFungibleCoinZRC20(ctx, msg) require.NoError(t, err) gasAddress := res.Address @@ -174,6 +175,7 @@ func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) { 1000000, ) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := keeper.NewMsgServerImpl(*k).DeployFungibleCoinZRC20(ctx, msg) require.Error(t, err) require.ErrorIs(t, err, observertypes.ErrSupportedChains) @@ -203,6 +205,7 @@ func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) { 1000000, ) keepertest.MockCheckAuthorization(&authorityMock.Mock, deployMsg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // Attempt to deploy the same gas token twice should result in error _, err := keeper.NewMsgServerImpl(*k).DeployFungibleCoinZRC20(ctx, deployMsg) diff --git a/x/fungible/keeper/msg_server_remove_foreign_coin_test.go b/x/fungible/keeper/msg_server_remove_foreign_coin_test.go index 01ac286e9e..9e02d8a6f0 100644 --- a/x/fungible/keeper/msg_server_remove_foreign_coin_test.go +++ b/x/fungible/keeper/msg_server_remove_foreign_coin_test.go @@ -25,6 +25,7 @@ func TestMsgServer_RemoveForeignCoin(t *testing.T) { admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) chainID := getValidChainID(t) @@ -53,6 +54,7 @@ func TestMsgServer_RemoveForeignCoin(t *testing.T) { admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chainID, "foo", "foo") diff --git a/x/fungible/keeper/msg_server_update_contract_bytecode_test.go b/x/fungible/keeper/msg_server_update_contract_bytecode_test.go index 287cc18046..dadb62d145 100644 --- a/x/fungible/keeper/msg_server_update_contract_bytecode_test.go +++ b/x/fungible/keeper/msg_server_update_contract_bytecode_test.go @@ -39,6 +39,7 @@ func TestKeeper_UpdateContractBytecode(t *testing.T) { msgServer := keeper.NewMsgServerImpl(*k) authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // sample chainIDs and addresses chainList := chains.DefaultChainsList() @@ -147,6 +148,7 @@ func TestKeeper_UpdateContractBytecode(t *testing.T) { codeHash, ) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err = msgServer.UpdateContractBytecode(ctx, msg) require.NoError(t, err) balance, err = k.BalanceOfZRC4(ctx, zrc20, addr1) diff --git a/x/fungible/keeper/msg_server_update_system_contract_test.go b/x/fungible/keeper/msg_server_update_system_contract_test.go index bdea95980b..72b7bac265 100644 --- a/x/fungible/keeper/msg_server_update_system_contract_test.go +++ b/x/fungible/keeper/msg_server_update_system_contract_test.go @@ -30,6 +30,7 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) queryZRC20SystemContract := func(contract common.Address) string { abi, err := zrc20.ZRC20MetaData.GetAbi() @@ -210,6 +211,7 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) chains := chains.DefaultChainsList() require.True(t, len(chains) > 1) @@ -255,6 +257,7 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { // can't update the system contract msg = types.NewMsgUpdateSystemContract(admin, newSystemContract.Hex()) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err = msgServer.UpdateSystemContract(ctx, msg) require.ErrorIs(t, err, types.ErrContractCall) @@ -265,6 +268,7 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { // can't update the system contract msg = types.NewMsgUpdateSystemContract(admin, newSystemContract.Hex()) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err = msgServer.UpdateSystemContract(ctx, msg) require.ErrorIs(t, err, types.ErrContractCall) }) diff --git a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go index fb156a1c36..160b2cfc46 100644 --- a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go +++ b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go @@ -31,6 +31,7 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { // set coin admin admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // deploy the system contract and a ZRC20 contract deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) diff --git a/x/fungible/types/expected_keepers.go b/x/fungible/types/expected_keepers.go index b2997566ff..ad0521ab81 100644 --- a/x/fungible/types/expected_keepers.go +++ b/x/fungible/types/expected_keepers.go @@ -36,7 +36,7 @@ type BankKeeper interface { } type ObserverKeeper interface { - GetSupportedChains(ctx sdk.Context) []*chains.Chain + GetSupportedChains(ctx sdk.Context) []chains.Chain } type EVMKeeper interface { @@ -60,4 +60,5 @@ type EVMKeeper interface { type AuthorityKeeper interface { CheckAuthorization(ctx sdk.Context, msg sdk.Msg) error + GetAdditionalChainList(ctx sdk.Context) (list []chains.Chain) } diff --git a/x/lightclient/keeper/grpc_query_prove.go b/x/lightclient/keeper/grpc_query_prove.go index 4a2017c65b..b231906501 100644 --- a/x/lightclient/keeper/grpc_query_prove.go +++ b/x/lightclient/keeper/grpc_query_prove.go @@ -24,7 +24,11 @@ func (k Keeper) Prove(c context.Context, req *types.QueryProveRequest) (*types.Q } ctx := sdk.UnwrapSDKContext(c) - blockHash, err := chains.StringToHash(req.ChainId, req.BlockHash) + // additionalChains is a list of additional chains to search from + // it is used in the protocol to dynamically support new chains without doing an upgrade + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + + blockHash, err := chains.StringToHash(req.ChainId, req.BlockHash, additionalChains) if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } @@ -40,7 +44,7 @@ func (k Keeper) Prove(c context.Context, req *types.QueryProveRequest) (*types.Q return nil, status.Error(codes.Internal, err.Error()) } if err == nil { - if chains.IsEVMChain(req.ChainId) { + if chains.IsEVMChain(req.ChainId, additionalChains) { var txx ethtypes.Transaction err = txx.UnmarshalBinary(txBytes) if err != nil { @@ -53,7 +57,7 @@ func (k Keeper) Prove(c context.Context, req *types.QueryProveRequest) (*types.Q ) } proven = true - } else if chains.IsBitcoinChain(req.ChainId) { + } else if chains.IsBitcoinChain(req.ChainId, additionalChains) { tx, err := btcutil.NewTxFromBytes(txBytes) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("failed to unmarshal btc transaction: %s", err)) diff --git a/x/lightclient/keeper/proof.go b/x/lightclient/keeper/proof.go index 7067ab3ac1..ddc26eb12f 100644 --- a/x/lightclient/keeper/proof.go +++ b/x/lightclient/keeper/proof.go @@ -23,8 +23,12 @@ func (k Keeper) VerifyProof( return nil, err } + // additionalChains is a list of additional chains to search from + // it is used in the protocol to dynamically support new chains without doing an upgrade + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + // get block header from the store - hashBytes, err := chains.StringToHash(chainID, blockHash) + hashBytes, err := chains.StringToHash(chainID, blockHash, additionalChains) if err != nil { return nil, cosmoserror.Wrapf( types.ErrInvalidBlockHash, diff --git a/x/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index bee335d628..71f83b2c49 100644 --- a/x/lightclient/types/expected_keepers.go +++ b/x/lightclient/types/expected_keepers.go @@ -2,8 +2,11 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/zeta-chain/zetacore/pkg/chains" ) type AuthorityKeeper interface { CheckAuthorization(ctx sdk.Context, msg sdk.Msg) error + GetAdditionalChainList(ctx sdk.Context) (list []chains.Chain) } diff --git a/x/lightclient/types/message_disable_verification_flags.go b/x/lightclient/types/message_disable_verification_flags.go index 5ee2964aa7..511821919c 100644 --- a/x/lightclient/types/message_disable_verification_flags.go +++ b/x/lightclient/types/message_disable_verification_flags.go @@ -4,8 +4,6 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const ( @@ -46,21 +44,12 @@ func (msg *MsgDisableHeaderVerification) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(msg.Creator); err != nil { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - chainListForHeaderSupport := chains.ChainListForHeaderSupport() if len(msg.ChainIdList) == 0 { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list cannot be empty") } - if len(msg.ChainIdList) > len(chainListForHeaderSupport) { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list cannot be greater than supported chains") - } - for _, chainID := range msg.ChainIdList { - if !chains.ChainIDInChainList(chainID, chainListForHeaderSupport) { - return cosmoserrors.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid chain id header not supported (%d)", - chainID, - ) - } + + if len(msg.ChainIdList) > MaxChainIDListLength { + return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list too long") } return nil diff --git a/x/lightclient/types/message_disable_verification_flags_test.go b/x/lightclient/types/message_disable_verification_flags_test.go index 6ccde4a12b..8efb9d4c04 100644 --- a/x/lightclient/types/message_disable_verification_flags_test.go +++ b/x/lightclient/types/message_disable_verification_flags_test.go @@ -1,7 +1,6 @@ package types_test import ( - "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -43,26 +42,11 @@ func TestMsgDisableHeaderVerification_ValidateBasic(t *testing.T) { name: "chain id list is too long", msg: types.MsgDisableHeaderVerification{ Creator: sample.AccAddress(), - ChainIdList: make([]int64, 200), + ChainIdList: make([]int64, types.MaxChainIDListLength+1), }, err: func(t require.TestingT, err error, i ...interface{}) { require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains(t, err, "chain id list cannot be greater than supported chains") - }, - }, - { - name: "invalid chain id", - msg: types.MsgDisableHeaderVerification{ - Creator: sample.AccAddress(), - ChainIdList: []int64{chains.ZetaChainPrivnet.ChainId}, - }, - err: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains( - t, - err, - fmt.Sprintf("invalid chain id header not supported (%d)", chains.ZetaChainPrivnet.ChainId), - ) + require.ErrorContains(t, err, "chain id list too long") }, }, { diff --git a/x/lightclient/types/message_enable_verification_flags.go b/x/lightclient/types/message_enable_verification_flags.go index a77706699a..a0a9dac5bd 100644 --- a/x/lightclient/types/message_enable_verification_flags.go +++ b/x/lightclient/types/message_enable_verification_flags.go @@ -4,12 +4,14 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const ( TypeMsgEnableHeaderVerification = "enable_header_verification" + + // MaxChainIDListLength is the maximum number of chain IDs that can be enabled for header verification + // this is a value chosen arbitrarily to prevent abuse + MaxChainIDListLength = 200 ) var _ sdk.Msg = &MsgEnableHeaderVerification{} @@ -46,21 +48,12 @@ func (msg *MsgEnableHeaderVerification) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(msg.Creator); err != nil { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - chainListForHeaderSupport := chains.ChainListForHeaderSupport() if len(msg.ChainIdList) == 0 { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list cannot be empty") } - if len(msg.ChainIdList) > len(chainListForHeaderSupport) { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list cannot be greater than supported chains") - } - for _, chainID := range msg.ChainIdList { - if !chains.ChainIDInChainList(chainID, chainListForHeaderSupport) { - return cosmoserrors.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid chain id header not supported (%d)", - chainID, - ) - } + + if len(msg.ChainIdList) > MaxChainIDListLength { + return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list too long") } return nil diff --git a/x/lightclient/types/message_enable_verification_flags_test.go b/x/lightclient/types/message_enable_verification_flags_test.go index 0bda67f1b9..2f738f36f0 100644 --- a/x/lightclient/types/message_enable_verification_flags_test.go +++ b/x/lightclient/types/message_enable_verification_flags_test.go @@ -1,7 +1,6 @@ package types_test import ( - "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -43,26 +42,11 @@ func TestMsgEnableHeaderVerification_ValidateBasic(t *testing.T) { name: "chain id list is too long", msg: types.MsgEnableHeaderVerification{ Creator: sample.AccAddress(), - ChainIdList: make([]int64, 200), + ChainIdList: make([]int64, types.MaxChainIDListLength+1), }, err: func(t require.TestingT, err error, i ...interface{}) { require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains(t, err, "chain id list cannot be greater than supported chains") - }, - }, - { - name: "invalid chain id", - msg: types.MsgEnableHeaderVerification{ - Creator: sample.AccAddress(), - ChainIdList: []int64{chains.ZetaChainPrivnet.ChainId}, - }, - err: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains( - t, - err, - fmt.Sprintf("invalid chain id header not supported (%d)", chains.ZetaChainPrivnet.ChainId), - ) + require.ErrorContains(t, err, "chain id list too long") }, }, { diff --git a/x/observer/keeper/chain_params.go b/x/observer/keeper/chain_params.go index a2354f9b2c..9277010c3c 100644 --- a/x/observer/keeper/chain_params.go +++ b/x/observer/keeper/chain_params.go @@ -43,41 +43,44 @@ func (k Keeper) GetChainParamsByChainID(ctx sdk.Context, chainID int64) (*types. // GetSupportedChainFromChainID returns the chain from the chain id // it returns nil if the chain doesn't exist or is not supported -func (k Keeper) GetSupportedChainFromChainID(ctx sdk.Context, chainID int64) *chains.Chain { +func (k Keeper) GetSupportedChainFromChainID(ctx sdk.Context, chainID int64) (chains.Chain, bool) { cpl, found := k.GetChainParamsList(ctx) if !found { - return nil + return chains.Chain{}, false } for _, cp := range cpl.ChainParams { if cp.ChainId == chainID && cp.IsSupported { - return chains.GetChainFromChainID(chainID) + return chains.GetChainFromChainID(chainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) } } - return nil + return chains.Chain{}, false } // GetSupportedChains returns the list of supported chains -func (k Keeper) GetSupportedChains(ctx sdk.Context) []*chains.Chain { +func (k Keeper) GetSupportedChains(ctx sdk.Context) []chains.Chain { cpl, found := k.GetChainParamsList(ctx) if !found { - return []*chains.Chain{} + return []chains.Chain{} } - var c []*chains.Chain + var c []chains.Chain for _, cp := range cpl.ChainParams { if cp.IsSupported { - c = append(c, chains.GetChainFromChainID(cp.ChainId)) + chain, found := chains.GetChainFromChainID(cp.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if found { + c = append(c, chain) + } } } return c } // GetSupportedForeignChains returns the list of supported foreign chains -func (k Keeper) GetSupportedForeignChains(ctx sdk.Context) []*chains.Chain { +func (k Keeper) GetSupportedForeignChains(ctx sdk.Context) []chains.Chain { allChains := k.GetSupportedChains(ctx) - foreignChains := make([]*chains.Chain, 0) + foreignChains := make([]chains.Chain, 0) for _, chain := range allChains { if !chain.IsZetaChain() { foreignChains = append(foreignChains, chain) diff --git a/x/observer/keeper/chain_params_test.go b/x/observer/keeper/chain_params_test.go index 4d608f0462..733fafc0b8 100644 --- a/x/observer/keeper/chain_params_test.go +++ b/x/observer/keeper/chain_params_test.go @@ -16,26 +16,29 @@ func TestKeeper_GetSupportedChainFromChainID(t *testing.T) { k, ctx, _, _ := keepertest.ObserverKeeper(t) // no core params list - require.Nil(t, k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 0))) + _, found := k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 0)) + require.False(t, found) // core params list but chain not in list setSupportedChain(ctx, *k, getValidEthChainIDWithIndex(t, 0)) - require.Nil(t, k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 1))) + _, found = k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 1)) + require.False(t, found) // chain params list but chain not supported chainParams := sample.ChainParams(getValidEthChainIDWithIndex(t, 0)) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{chainParams}, }) - require.Nil(t, k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 0))) + _, found = k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 0)) + require.False(t, found) }) t.Run("return chain if chain found", func(t *testing.T) { k, ctx, _, _ := keepertest.ObserverKeeper(t) chainID := getValidEthChainIDWithIndex(t, 0) setSupportedChain(ctx, *k, getValidEthChainIDWithIndex(t, 1), chainID) - chain := k.GetSupportedChainFromChainID(ctx, chainID) - require.NotNil(t, chain) + chain, found := k.GetSupportedChainFromChainID(ctx, chainID) + require.True(t, found) require.EqualValues(t, chainID, chain.ChainId) }) } @@ -78,12 +81,14 @@ func TestKeeper_GetSupportedChains(t *testing.T) { t.Run("return list containing supported chains", func(t *testing.T) { k, ctx, _, _ := keepertest.ObserverKeeper(t) - require.Greater(t, len(chains.ExternalChainList()), 5) - supported1 := chains.ExternalChainList()[0] - supported2 := chains.ExternalChainList()[1] - unsupported := chains.ExternalChainList()[2] - supported3 := chains.ExternalChainList()[3] - supported4 := chains.ExternalChainList()[4] + chainList := chains.ExternalChainList([]chains.Chain{}) + + require.Greater(t, len(chainList), 5) + supported1 := chainList[0] + supported2 := chainList[1] + unsupported := chainList[2] + supported3 := chainList[3] + supported4 := chainList[4] var chainParamsList []*types.ChainParams chainParamsList = append(chainParamsList, sample.ChainParamsSupported(supported1.ChainId)) diff --git a/x/observer/keeper/grpc_query_supported_chain_test.go b/x/observer/keeper/grpc_query_supported_chain_test.go index 1b73c53394..0cdc276c9d 100644 --- a/x/observer/keeper/grpc_query_supported_chain_test.go +++ b/x/observer/keeper/grpc_query_supported_chain_test.go @@ -17,6 +17,6 @@ func TestKeeper_SupportedChains(t *testing.T) { res, err := k.SupportedChains(wctx, nil) require.NoError(t, err) - require.Equal(t, []*chains.Chain{}, res.Chains) + require.Equal(t, []chains.Chain{}, res.Chains) }) } diff --git a/x/observer/keeper/grpc_query_tss_funds_migrator_info.go b/x/observer/keeper/grpc_query_tss_funds_migrator_info.go index 7a2ab7e357..88558fd23a 100644 --- a/x/observer/keeper/grpc_query_tss_funds_migrator_info.go +++ b/x/observer/keeper/grpc_query_tss_funds_migrator_info.go @@ -22,7 +22,8 @@ func (k Keeper) TssFundsMigratorInfo( ctx := sdk.UnwrapSDKContext(goCtx) - if chains.GetChainFromChainID(req.ChainId) == nil { + _, found := chains.GetChainFromChainID(req.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return nil, status.Error(codes.InvalidArgument, "invalid chain id") } diff --git a/x/observer/keeper/msg_server_remove_chain_params_test.go b/x/observer/keeper/msg_server_remove_chain_params_test.go index 5139f84086..c7b60d7c07 100644 --- a/x/observer/keeper/msg_server_remove_chain_params_test.go +++ b/x/observer/keeper/msg_server_remove_chain_params_test.go @@ -24,9 +24,11 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { // mock the authority keeper for authorization authorityMock := keepertest.GetObserverAuthorityMock(t, k) - chain1 := chains.ExternalChainList()[0].ChainId - chain2 := chains.ExternalChainList()[1].ChainId - chain3 := chains.ExternalChainList()[2].ChainId + chainList := chains.ExternalChainList([]chains.Chain{}) + + chain1 := chainList[0].ChainId + chain2 := chainList[1].ChainId + chain3 := chainList[2].ChainId // set admin admin := sample.AccAddress() @@ -96,7 +98,7 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { msg := types.MsgRemoveChainParams{ Creator: admin, - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chains.ExternalChainList([]chains.Chain{})[0].ChainId, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) _, err := srv.RemoveChainParams(sdk.WrapSDKContext(ctx), &msg) @@ -117,9 +119,11 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { _, found := k.GetChainParamsList(ctx) require.False(t, found) + chainList := chains.ExternalChainList([]chains.Chain{}) + msg := types.MsgRemoveChainParams{ Creator: admin, - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) _, err := srv.RemoveChainParams(sdk.WrapSDKContext(ctx), &msg) @@ -128,16 +132,16 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { // add chain params k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ - sample.ChainParams(chains.ExternalChainList()[0].ChainId), - sample.ChainParams(chains.ExternalChainList()[1].ChainId), - sample.ChainParams(chains.ExternalChainList()[2].ChainId), + sample.ChainParams(chainList[0].ChainId), + sample.ChainParams(chainList[1].ChainId), + sample.ChainParams(chainList[2].ChainId), }, }) // not found if chain ID not in list msg = types.MsgRemoveChainParams{ Creator: admin, - ChainId: chains.ExternalChainList()[3].ChainId, + ChainId: chainList[3].ChainId, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) _, err = srv.RemoveChainParams(sdk.WrapSDKContext(ctx), &msg) diff --git a/x/observer/keeper/msg_server_reset_chain_nonces.go b/x/observer/keeper/msg_server_reset_chain_nonces.go index a3ea3ecc81..8cd61c97d6 100644 --- a/x/observer/keeper/msg_server_reset_chain_nonces.go +++ b/x/observer/keeper/msg_server_reset_chain_nonces.go @@ -27,8 +27,8 @@ func (k msgServer) ResetChainNonces( return nil, types.ErrTssNotFound } - chain := chains.GetChainFromChainID(msg.ChainId) - if chain == nil { + chain, found := chains.GetChainFromChainID(msg.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return nil, types.ErrSupportedChains } diff --git a/x/observer/keeper/msg_server_reset_chain_nonces_test.go b/x/observer/keeper/msg_server_reset_chain_nonces_test.go index 53009d9608..0b1c76113c 100644 --- a/x/observer/keeper/msg_server_reset_chain_nonces_test.go +++ b/x/observer/keeper/msg_server_reset_chain_nonces_test.go @@ -74,6 +74,7 @@ func TestMsgServer_ResetChainNonces(t *testing.T) { ChainNonceHigh: 5, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := srv.ResetChainNonces(sdk.WrapSDKContext(ctx), &msg) require.ErrorIs(t, err, types.ErrSupportedChains) @@ -109,6 +110,7 @@ func TestMsgServer_ResetChainNonces(t *testing.T) { ChainNonceHigh: int64(nonceHigh), } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := srv.ResetChainNonces(sdk.WrapSDKContext(ctx), &msg) require.NoError(t, err) diff --git a/x/observer/keeper/msg_server_update_chain_params_test.go b/x/observer/keeper/msg_server_update_chain_params_test.go index fc38200764..d8ad61820d 100644 --- a/x/observer/keeper/msg_server_update_chain_params_test.go +++ b/x/observer/keeper/msg_server_update_chain_params_test.go @@ -21,9 +21,11 @@ func TestMsgServer_UpdateChainParams(t *testing.T) { }) srv := keeper.NewMsgServerImpl(*k) - chain1 := chains.ExternalChainList()[0].ChainId - chain2 := chains.ExternalChainList()[1].ChainId - chain3 := chains.ExternalChainList()[2].ChainId + chainList := chains.ExternalChainList([]chains.Chain{}) + + chain1 := chainList[0].ChainId + chain2 := chainList[1].ChainId + chain3 := chainList[2].ChainId // set admin admin := sample.AccAddress() @@ -113,7 +115,7 @@ func TestMsgServer_UpdateChainParams(t *testing.T) { msg := types.MsgUpdateChainParams{ Creator: admin, - ChainParams: sample.ChainParams(chains.ExternalChainList()[0].ChainId), + ChainParams: sample.ChainParams(chains.ExternalChainList([]chains.Chain{})[0].ChainId), } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) _, err := srv.UpdateChainParams(sdk.WrapSDKContext(ctx), &msg) diff --git a/x/observer/keeper/msg_server_vote_blame.go b/x/observer/keeper/msg_server_vote_blame.go index 395b2fa9c1..217d5e5912 100644 --- a/x/observer/keeper/msg_server_vote_blame.go +++ b/x/observer/keeper/msg_server_vote_blame.go @@ -19,8 +19,8 @@ func (k msgServer) VoteBlame( observationType := types.ObservationType_TSSKeySign // GetChainFromChainID makes sure we are getting only supported chains , if a chain support has been turned on using gov proposal, this function returns nil - observationChain := k.GetSupportedChainFromChainID(ctx, vote.ChainId) - if observationChain == nil { + observationChain, found := k.GetSupportedChainFromChainID(ctx, vote.ChainId) + if !found { return nil, cosmoserrors.Wrap( crosschainTypes.ErrUnsupportedChain, fmt.Sprintf("ChainID %d, Blame vote", vote.ChainId), diff --git a/x/observer/keeper/msg_server_vote_block_header.go b/x/observer/keeper/msg_server_vote_block_header.go index 5e8c0e0bce..9ae7a35a56 100644 --- a/x/observer/keeper/msg_server_vote_block_header.go +++ b/x/observer/keeper/msg_server_vote_block_header.go @@ -18,8 +18,8 @@ func (k msgServer) VoteBlockHeader( ctx := sdk.UnwrapSDKContext(goCtx) // check if the chain is enabled - chain := k.GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + chain, found := k.GetSupportedChainFromChainID(ctx, msg.ChainId) + if !found { return nil, cosmoserrors.Wrapf(types.ErrSupportedChains, "chain id: %d", msg.ChainId) } diff --git a/x/observer/keeper/msg_server_vote_block_header_test.go b/x/observer/keeper/msg_server_vote_block_header_test.go index 0d41b1be0c..7ce0144e5f 100644 --- a/x/observer/keeper/msg_server_vote_block_header_test.go +++ b/x/observer/keeper/msg_server_vote_block_header_test.go @@ -93,6 +93,9 @@ func TestMsgServer_VoteBlockHeader(t *testing.T) { stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) lightclientMock := keepertest.GetObserverLightclientMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -131,6 +134,9 @@ func TestMsgServer_VoteBlockHeader(t *testing.T) { stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) lightclientMock := keepertest.GetObserverLightclientMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -176,6 +182,9 @@ func TestMsgServer_VoteBlockHeader(t *testing.T) { stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) lightclientMock := keepertest.GetObserverLightclientMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -250,6 +259,9 @@ func TestMsgServer_VoteBlockHeader(t *testing.T) { stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) lightclientMock := keepertest.GetObserverLightclientMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ diff --git a/x/observer/keeper/utils.go b/x/observer/keeper/utils.go index 8d37e82d57..3215a86307 100644 --- a/x/observer/keeper/utils.go +++ b/x/observer/keeper/utils.go @@ -56,7 +56,7 @@ func (k Keeper) IsNonTombstonedObserver(ctx sdk.Context, address string) bool { func (k Keeper) FindBallot( ctx sdk.Context, index string, - chain *chains.Chain, + chain chains.Chain, observationType types.ObservationType, ) (ballot types.Ballot, isNew bool, err error) { isNew = false diff --git a/x/observer/keeper/utils_test.go b/x/observer/keeper/utils_test.go index b11a4512ca..effd815ad5 100644 --- a/x/observer/keeper/utils_test.go +++ b/x/observer/keeper/utils_test.go @@ -314,7 +314,7 @@ func TestKeeper_FindBallot(t *testing.T) { t.Run("should err if chain params not found", func(t *testing.T) { k, ctx, _, _ := keepertest.ObserverKeeper(t) - _, _, err := k.FindBallot(ctx, "index", &chains.Chain{ + _, _, err := k.FindBallot(ctx, "index", chains.Chain{ ChainId: 987, }, types.ObservationType_InboundTx) require.Error(t, err) diff --git a/x/observer/keeper/vote_inbound.go b/x/observer/keeper/vote_inbound.go index b5fcdb1e38..676e93aeaa 100644 --- a/x/observer/keeper/vote_inbound.go +++ b/x/observer/keeper/vote_inbound.go @@ -29,8 +29,8 @@ func (k Keeper) VoteOnInboundBallot( // makes sure we are getting only supported chains // if a chain support has been turned on using gov proposal // this function returns nil - senderChain := k.GetSupportedChainFromChainID(ctx, senderChainID) - if senderChain == nil { + senderChain, found := k.GetSupportedChainFromChainID(ctx, senderChainID) + if !found { return false, false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( "ChainID %d, Observation %s", senderChainID, @@ -44,8 +44,8 @@ func (k Keeper) VoteOnInboundBallot( } // makes sure we are getting only supported chains - receiverChain := k.GetSupportedChainFromChainID(ctx, receiverChainID) - if receiverChain == nil { + receiverChain, found := k.GetSupportedChainFromChainID(ctx, receiverChainID) + if !found { return false, false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( "ChainID %d, Observation %s", receiverChainID, diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go index 9f9fa09b58..99951e287c 100644 --- a/x/observer/keeper/vote_inbound_test.go +++ b/x/observer/keeper/vote_inbound_test.go @@ -114,6 +114,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -179,6 +182,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -221,6 +227,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -265,6 +274,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -316,6 +328,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // threshold high enough to not finalize ballot threshold, err := sdk.NewDecFromStr("0.7") @@ -369,6 +384,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -433,6 +451,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, diff --git a/x/observer/keeper/vote_outbound.go b/x/observer/keeper/vote_outbound.go index 0dc946f5b4..a8212980ed 100644 --- a/x/observer/keeper/vote_outbound.go +++ b/x/observer/keeper/vote_outbound.go @@ -23,8 +23,8 @@ func (k Keeper) VoteOnOutboundBallot( /* EDGE CASE : Params updated in during the finalization process i.e Inbound has been finalized but outbound is still pending */ - observationChain := k.GetSupportedChainFromChainID(ctx, outTxChainID) - if observationChain == nil { + observationChain, found := k.GetSupportedChainFromChainID(ctx, outTxChainID) + if !found { return false, false, ballot, "", observertypes.ErrSupportedChains } if observertypes.CheckReceiveStatus(receiveStatus) != nil { diff --git a/x/observer/keeper/vote_outbound_test.go b/x/observer/keeper/vote_outbound_test.go index 4d14e828ba..bc88b21303 100644 --- a/x/observer/keeper/vote_outbound_test.go +++ b/x/observer/keeper/vote_outbound_test.go @@ -102,6 +102,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -140,6 +143,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -182,6 +188,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // threshold high enough to not finalize the ballot threshold, err := sdk.NewDecFromStr("0.7") @@ -228,6 +237,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -286,6 +298,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ diff --git a/x/observer/types/chain_params.go b/x/observer/types/chain_params.go index d67aa520ba..665be3de98 100644 --- a/x/observer/types/chain_params.go +++ b/x/observer/types/chain_params.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ethchains "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" "github.com/zeta-chain/zetacore/pkg/chains" ) @@ -54,15 +55,22 @@ func ValidateChainParams(params *ChainParams) error { if params == nil { return fmt.Errorf("chain params cannot be nil") } - chain := chains.GetChainFromChainID(params.ChainId) - if chain == nil { - return fmt.Errorf("ChainId %d not supported", params.ChainId) - } - // zeta chain skips the rest of the checks for now - if chain.IsZetaChain() { + + // TODO: ZetaChain chain params should be completely removed + // Once removed, this check is no longer necessary as all chasin params would need the same checks + // https://github.com/zeta-chain/node/issues/2419 + _, err := chains.ZetaChainFromChainID(params.ChainId) + if err == nil { + // zeta chain skips the rest of the checks for now return nil } + // ignore error from ZetaChainFromChainID if reason is chain is not zeta chain + // return error otherwise + if !errors.Is(err, chains.ErrNotZetaChain) { + return err + } + if params.ConfirmationCount == 0 { return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "ConfirmationCount must be greater than 0") } @@ -90,38 +98,36 @@ func ValidateChainParams(params *ChainParams) error { ) } - // chain type specific checks - if chains.IsBitcoinChain(params.ChainId) { - if params.WatchUtxoTicker == 0 || params.WatchUtxoTicker > 300 { - return errorsmod.Wrapf( - sdkerrors.ErrInvalidRequest, - "WatchUtxoTicker %d out of range", - params.WatchUtxoTicker, - ) - } + // if WatchUtxoTicker defined, check validity + if params.WatchUtxoTicker > 300 { + return errorsmod.Wrapf( + sdkerrors.ErrInvalidRequest, + "WatchUtxoTicker %d out of range", + params.WatchUtxoTicker, + ) } - if chains.IsEVMChain(params.ChainId) { - if !validChainContractAddress(params.ZetaTokenContractAddress) { - return errorsmod.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid ZetaTokenContractAddress %s", - params.ZetaTokenContractAddress, - ) - } - if !validChainContractAddress(params.ConnectorContractAddress) { - return errorsmod.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid ConnectorContractAddress %s", - params.ConnectorContractAddress, - ) - } - if !validChainContractAddress(params.Erc20CustodyContractAddress) { - return errorsmod.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid Erc20CustodyContractAddress %s", - params.Erc20CustodyContractAddress, - ) - } + + // if contract addresses are defined, check validity + if params.ZetaTokenContractAddress != "" && !validChainContractAddress(params.ZetaTokenContractAddress) { + return errorsmod.Wrapf( + sdkerrors.ErrInvalidRequest, + "invalid ZetaTokenContractAddress %s", + params.ZetaTokenContractAddress, + ) + } + if params.ConnectorContractAddress != "" && !validChainContractAddress(params.ConnectorContractAddress) { + return errorsmod.Wrapf( + sdkerrors.ErrInvalidRequest, + "invalid ConnectorContractAddress %s", + params.ConnectorContractAddress, + ) + } + if params.Erc20CustodyContractAddress != "" && !validChainContractAddress(params.Erc20CustodyContractAddress) { + return errorsmod.Wrapf( + sdkerrors.ErrInvalidRequest, + "invalid Erc20CustodyContractAddress %s", + params.Erc20CustodyContractAddress, + ) } if params.BallotThreshold.IsNil() || params.BallotThreshold.GT(sdk.OneDec()) { diff --git a/x/observer/types/chain_params_test.go b/x/observer/types/chain_params_test.go index 1703b43f54..dff1311a9c 100644 --- a/x/observer/types/chain_params_test.go +++ b/x/observer/types/chain_params_test.go @@ -99,9 +99,9 @@ func (s *UpdateChainParamsSuite) TestCommonParams() { s.Validate(s.btcParams) } -func (s *UpdateChainParamsSuite) TestBTCParams() { +func (s *UpdateChainParamsSuite) TestBTCParamsInvalid() { copy := *s.btcParams - copy.WatchUtxoTicker = 0 + copy.WatchUtxoTicker = 301 err := types.ValidateChainParams(©) require.NotNil(s.T(), err) } diff --git a/x/observer/types/expected_keepers.go b/x/observer/types/expected_keepers.go index 5eb8b03468..4a556d4fa4 100644 --- a/x/observer/types/expected_keepers.go +++ b/x/observer/types/expected_keepers.go @@ -5,6 +5,7 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/proofs" authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" ) @@ -33,6 +34,7 @@ type StakingHooks interface { type AuthorityKeeper interface { CheckAuthorization(ctx sdk.Context, msg sdk.Msg) error + GetAdditionalChainList(ctx sdk.Context) (list []chains.Chain) // SetPolicies is solely used for the migration of policies from observer to authority SetPolicies(ctx sdk.Context, policies authoritytypes.Policies) diff --git a/x/observer/types/message_remove_chain_params.go b/x/observer/types/message_remove_chain_params.go index b34574e4de..708f87290f 100644 --- a/x/observer/types/message_remove_chain_params.go +++ b/x/observer/types/message_remove_chain_params.go @@ -4,8 +4,6 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const TypeMsgRemoveChainParams = "remove_chain_params" @@ -46,11 +44,5 @@ func (msg *MsgRemoveChainParams) ValidateBasic() error { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - // Check if chain exists - chain := chains.GetChainFromChainID(msg.ChainId) - if chain == nil { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidChainID, "invalid chain id (%d)", msg.ChainId) - } - return nil } diff --git a/x/observer/types/message_remove_chain_params_test.go b/x/observer/types/message_remove_chain_params_test.go index b81f29ff77..69f8f83103 100644 --- a/x/observer/types/message_remove_chain_params_test.go +++ b/x/observer/types/message_remove_chain_params_test.go @@ -22,26 +22,17 @@ func TestMsgRemoveChainParams_ValidateBasic(t *testing.T) { name: "valid message", msg: types.NewMsgRemoveChainParams( sample.AccAddress(), - chains.ExternalChainList()[0].ChainId, + chains.ExternalChainList([]chains.Chain{})[0].ChainId, ), }, { name: "invalid address", msg: types.NewMsgRemoveChainParams( "invalid_address", - chains.ExternalChainList()[0].ChainId, + chains.ExternalChainList([]chains.Chain{})[0].ChainId, ), err: sdkerrors.ErrInvalidAddress, }, - - { - name: "invalid chain ID", - msg: types.NewMsgRemoveChainParams( - sample.AccAddress(), - 999, - ), - err: sdkerrors.ErrInvalidChainID, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/x/observer/types/message_reset_chain_nonces.go b/x/observer/types/message_reset_chain_nonces.go index ac14463af5..80e0a2d26b 100644 --- a/x/observer/types/message_reset_chain_nonces.go +++ b/x/observer/types/message_reset_chain_nonces.go @@ -6,8 +6,6 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const TypeMsgResetChainNonces = "reset_chain_nonces" @@ -55,12 +53,6 @@ func (msg *MsgResetChainNonces) ValidateBasic() error { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - // Check if chain exists - chain := chains.GetChainFromChainID(msg.ChainId) - if chain == nil { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidChainID, "invalid chain id (%d)", msg.ChainId) - } - if msg.ChainNonceLow < 0 { return errors.New("chain nonce low must be greater or equal 0") } diff --git a/x/observer/types/message_reset_chain_nonces_test.go b/x/observer/types/message_reset_chain_nonces_test.go index d131d32ed6..41da6643d2 100644 --- a/x/observer/types/message_reset_chain_nonces_test.go +++ b/x/observer/types/message_reset_chain_nonces_test.go @@ -12,6 +12,8 @@ import ( ) func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { + chainList := chains.ExternalChainList([]chains.Chain{}) + tests := []struct { name string msg types.MsgResetChainNonces @@ -21,7 +23,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "valid message chain nonce high greater than nonce low", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: 1, ChainNonceHigh: 5, }, @@ -31,7 +33,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "valid message chain nonce high same as nonce low", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: 1, ChainNonceHigh: 1, }, @@ -41,15 +43,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "invalid address", msg: types.MsgResetChainNonces{ Creator: "invalid_address", - ChainId: chains.ExternalChainList()[0].ChainId, - }, - wantErr: true, - }, - { - name: "invalid chain ID", - msg: types.MsgResetChainNonces{ - Creator: sample.AccAddress(), - ChainId: 999, + ChainId: chainList[0].ChainId, }, wantErr: true, }, @@ -57,7 +51,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "invalid chain nonce low", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: -1, }, wantErr: true, @@ -66,7 +60,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "invalid chain nonce high", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: 1, ChainNonceHigh: -1, }, @@ -76,7 +70,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "invalid chain nonce low greater than chain nonce high", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: 1, ChainNonceHigh: 0, }, diff --git a/x/observer/types/message_update_chain_params_test.go b/x/observer/types/message_update_chain_params_test.go index fe2d526631..69dd70ced8 100644 --- a/x/observer/types/message_update_chain_params_test.go +++ b/x/observer/types/message_update_chain_params_test.go @@ -13,6 +13,8 @@ import ( ) func TestMsgUpdateChainParams_ValidateBasic(t *testing.T) { + chainList := chains.ExternalChainList([]chains.Chain{}) + tests := []struct { name string msg *types.MsgUpdateChainParams @@ -22,14 +24,14 @@ func TestMsgUpdateChainParams_ValidateBasic(t *testing.T) { name: "valid message", msg: types.NewMsgUpdateChainParams( sample.AccAddress(), - sample.ChainParams(chains.ExternalChainList()[0].ChainId), + sample.ChainParams(chainList[0].ChainId), ), }, { name: "invalid address", msg: types.NewMsgUpdateChainParams( "invalid_address", - sample.ChainParams(chains.ExternalChainList()[0].ChainId), + sample.ChainParams(chainList[0].ChainId), ), err: sdkerrors.ErrInvalidAddress, }, diff --git a/x/observer/types/message_vote_blame.go b/x/observer/types/message_vote_blame.go index 2a06e84869..336a086185 100644 --- a/x/observer/types/message_vote_blame.go +++ b/x/observer/types/message_vote_blame.go @@ -5,8 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/crypto" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const TypeMsgVoteBlame = "vote_blame" @@ -34,9 +32,7 @@ func (m *MsgVoteBlame) ValidateBasic() error { if err != nil { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - if chains.GetChainFromChainID(m.ChainId) == nil { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidChainID, "chain id (%d)", m.ChainId) - } + return nil } diff --git a/x/observer/types/message_vote_blame_test.go b/x/observer/types/message_vote_blame_test.go index 9514beac40..6385621a12 100644 --- a/x/observer/types/message_vote_blame_test.go +++ b/x/observer/types/message_vote_blame_test.go @@ -28,15 +28,6 @@ func TestNewMsgVoteBlameMsg_ValidateBasic(t *testing.T) { ), error: true, }, - { - name: "invalid chain id", - msg: types.NewMsgVoteBlameMsg( - sample.AccAddress(), - -1, - sample.BlameRecordsList(t, 1)[0], - ), - error: true, - }, { name: "valid", msg: types.NewMsgVoteBlameMsg( diff --git a/x/observer/types/message_vote_block_header.go b/x/observer/types/message_vote_block_header.go index 004b2ce199..ba52975251 100644 --- a/x/observer/types/message_vote_block_header.go +++ b/x/observer/types/message_vote_block_header.go @@ -6,7 +6,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/crypto" - "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/proofs" ) @@ -59,10 +58,6 @@ func (msg *MsgVoteBlockHeader) ValidateBasic() error { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, err.Error()) } - if !chains.IsHeaderSupportedChain(msg.ChainId) { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid chain id (%d)", msg.ChainId) - } - if len(msg.BlockHash) != 32 { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid block hash length (%d)", len(msg.BlockHash)) } diff --git a/x/observer/types/observer.pb.go b/x/observer/types/observer.pb.go index 13d3e1c998..2d21b13149 100644 --- a/x/observer/types/observer.pb.go +++ b/x/observer/types/observer.pb.go @@ -7,7 +7,6 @@ import ( fmt "fmt" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" - _ "github.com/zeta-chain/zetacore/pkg/chains" io "io" math "math" math_bits "math/bits" @@ -194,31 +193,30 @@ func init() { } var fileDescriptor_05af1bc65780862e = []byte{ - // 378 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x51, 0xdf, 0xaa, 0xd3, 0x30, - 0x18, 0x6f, 0xb6, 0x29, 0x9c, 0x1c, 0x8f, 0xeb, 0xc2, 0x84, 0x31, 0xa1, 0x8c, 0x79, 0x33, 0x86, - 0xb6, 0xa0, 0x4f, 0xa0, 0x43, 0x74, 0x38, 0x18, 0xb4, 0x1b, 0x82, 0x37, 0x23, 0x6d, 0x63, 0x1b, - 0x5c, 0x93, 0xd2, 0x7c, 0x95, 0xd5, 0xa7, 0xf0, 0x21, 0xbc, 0xf0, 0x51, 0xbc, 0xdc, 0xa5, 0x97, - 0xb2, 0xbd, 0x88, 0x24, 0x5d, 0x26, 0xc8, 0xb9, 0xca, 0xf7, 0xfb, 0x9b, 0x8b, 0x1f, 0x9e, 0x7f, - 0x63, 0x40, 0x93, 0x9c, 0x72, 0x11, 0x98, 0x4b, 0x56, 0x2c, 0x90, 0xb1, 0x62, 0xd5, 0x57, 0x56, - 0x5d, 0x0f, 0xbf, 0xac, 0x24, 0x48, 0xf2, 0xf4, 0xea, 0xf5, 0xad, 0xd7, 0xb7, 0x96, 0xf1, 0x30, - 0x93, 0x99, 0x34, 0xbe, 0x40, 0x5f, 0x6d, 0x64, 0x7c, 0x5f, 0x7d, 0xf9, 0x25, 0x0b, 0x0c, 0xa5, - 0x2e, 0x4f, 0xeb, 0x9d, 0xbe, 0xc4, 0xb7, 0xeb, 0x4b, 0x5b, 0xc4, 0x80, 0x3c, 0xc3, 0x77, 0xb6, - 0x7c, 0xb7, 0xe7, 0x0a, 0x46, 0x68, 0xd2, 0x9d, 0xdd, 0x84, 0x8f, 0x2c, 0xb9, 0xe2, 0x0a, 0xa6, - 0x1f, 0xf1, 0x60, 0x45, 0x15, 0xd8, 0xdc, 0x42, 0xd6, 0x02, 0xc8, 0x10, 0x3f, 0x48, 0xf4, 0x31, - 0x42, 0x13, 0x34, 0xeb, 0x85, 0x2d, 0x20, 0xcf, 0x31, 0xd9, 0x53, 0x05, 0xbb, 0x24, 0xa7, 0x22, - 0x63, 0xbb, 0x9c, 0xf1, 0x2c, 0x87, 0x51, 0x67, 0x82, 0x66, 0xdd, 0xd0, 0xd5, 0xca, 0xc2, 0x08, - 0xef, 0x0d, 0x3f, 0xdf, 0xe3, 0x7e, 0x5b, 0x4a, 0x81, 0x4b, 0xb1, 0x69, 0x4a, 0x46, 0x9e, 0xe0, - 0xc1, 0xdb, 0xa2, 0x84, 0xc6, 0x7e, 0xa6, 0x49, 0xd7, 0x21, 0x77, 0xf8, 0x66, 0x29, 0x62, 0x59, - 0x8b, 0x74, 0x73, 0x70, 0x11, 0x79, 0x8c, 0xf1, 0xba, 0x06, 0x8b, 0x3b, 0x5a, 0xde, 0x44, 0xd1, - 0x07, 0xd6, 0xbc, 0x63, 0xc2, 0xed, 0x6a, 0xb9, 0x85, 0x11, 0xcf, 0x84, 0xdb, 0x1b, 0xf7, 0x7e, - 0xfe, 0xf0, 0xd0, 0x7c, 0x85, 0x87, 0xb6, 0x75, 0x5b, 0xa6, 0x14, 0x58, 0xc8, 0xa8, 0x92, 0x42, - 0x87, 0xb7, 0x22, 0x65, 0x9f, 0xb9, 0x60, 0xa9, 0xeb, 0x98, 0xb0, 0x2c, 0x62, 0x05, 0x52, 0x63, - 0x44, 0xfa, 0xf8, 0xf6, 0x75, 0x5a, 0x70, 0xd1, 0x66, 0xdc, 0x4e, 0xdb, 0xf6, 0x66, 0xf9, 0xeb, - 0xe4, 0xa1, 0xe3, 0xc9, 0x43, 0x7f, 0x4e, 0x1e, 0xfa, 0x7e, 0xf6, 0x9c, 0xe3, 0xd9, 0x73, 0x7e, - 0x9f, 0x3d, 0xe7, 0x53, 0x90, 0x71, 0xc8, 0xeb, 0xd8, 0x4f, 0x64, 0x61, 0xf6, 0x78, 0xf1, 0xdf, - 0x34, 0x87, 0x7f, 0xdb, 0x43, 0x53, 0x32, 0x15, 0x3f, 0x34, 0xd3, 0xbc, 0xfa, 0x1b, 0x00, 0x00, - 0xff, 0xff, 0xc7, 0x4c, 0xd1, 0x68, 0x27, 0x02, 0x00, 0x00, + // 367 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x51, 0xcf, 0x8a, 0xda, 0x40, + 0x1c, 0xce, 0xa8, 0x2d, 0x38, 0xd6, 0x1a, 0x07, 0x0b, 0x62, 0x21, 0x88, 0xbd, 0x88, 0xb4, 0x09, + 0xb4, 0x4f, 0xd0, 0x4a, 0x69, 0xa5, 0x82, 0x90, 0x28, 0x85, 0x5e, 0x64, 0x92, 0x4c, 0x93, 0x01, + 0x33, 0x13, 0x32, 0xbf, 0x14, 0xd3, 0xa7, 0xe8, 0x43, 0xf4, 0xb0, 0x8f, 0xb2, 0x47, 0x8f, 0x7b, + 0x5c, 0xf4, 0x45, 0x96, 0x49, 0x76, 0x5c, 0xd8, 0xdb, 0xf7, 0xfd, 0xbe, 0x3f, 0xbf, 0xc3, 0x87, + 0x17, 0x7f, 0x19, 0xd0, 0x28, 0xa5, 0x5c, 0x78, 0x35, 0x92, 0x05, 0xf3, 0x64, 0xa8, 0x58, 0xf1, + 0x87, 0x15, 0x57, 0xe0, 0xe6, 0x85, 0x04, 0x49, 0xde, 0x5e, 0xbd, 0xae, 0xf1, 0xba, 0xc6, 0x32, + 0x19, 0x25, 0x32, 0x91, 0xb5, 0xcf, 0xd3, 0xa8, 0x89, 0xcc, 0x3e, 0xe2, 0xde, 0xe6, 0xd1, 0x11, + 0x30, 0x20, 0xef, 0x70, 0xdf, 0x04, 0xf6, 0x07, 0xae, 0x60, 0x8c, 0xa6, 0xed, 0x79, 0xd7, 0x7f, + 0x65, 0x8e, 0x6b, 0xae, 0x60, 0xf6, 0x13, 0x0f, 0xd7, 0x54, 0x81, 0xc9, 0x2d, 0x65, 0x29, 0x80, + 0x8c, 0xf0, 0x8b, 0x48, 0x83, 0x31, 0x9a, 0xa2, 0x79, 0xc7, 0x6f, 0x08, 0x79, 0x8f, 0xc9, 0x81, + 0x2a, 0xd8, 0x47, 0x29, 0x15, 0x09, 0xdb, 0xa7, 0x8c, 0x27, 0x29, 0x8c, 0x5b, 0x53, 0x34, 0x6f, + 0xfb, 0xb6, 0x56, 0x96, 0xb5, 0xf0, 0xbd, 0xbe, 0x2f, 0x0e, 0x78, 0xd0, 0x94, 0x52, 0xe0, 0x52, + 0x6c, 0xab, 0x9c, 0x91, 0x37, 0x78, 0xf8, 0x35, 0xcb, 0xa1, 0x32, 0xcf, 0xf4, 0xd1, 0xb6, 0x48, + 0x1f, 0x77, 0x57, 0x22, 0x94, 0xa5, 0x88, 0xb7, 0x47, 0x1b, 0x91, 0xd7, 0x18, 0x6f, 0x4a, 0x30, + 0xbc, 0xa5, 0xe5, 0x6d, 0x10, 0xfc, 0x60, 0xd5, 0x37, 0x26, 0xec, 0xb6, 0x96, 0x1b, 0x1a, 0xf0, + 0x44, 0xd8, 0x9d, 0x49, 0xe7, 0xe6, 0xbf, 0x83, 0x16, 0x6b, 0x3c, 0x32, 0xad, 0xbb, 0x3c, 0xa6, + 0xc0, 0x7c, 0x46, 0x95, 0x14, 0x3a, 0xbc, 0x13, 0x31, 0xfb, 0xcd, 0x05, 0x8b, 0x6d, 0xab, 0x0e, + 0xcb, 0x2c, 0x54, 0x20, 0x35, 0x47, 0x64, 0x80, 0x7b, 0x9f, 0xe3, 0x8c, 0x8b, 0x26, 0x63, 0xb7, + 0x9a, 0xb6, 0x2f, 0xab, 0xdb, 0xb3, 0x83, 0x4e, 0x67, 0x07, 0xdd, 0x9f, 0x1d, 0xf4, 0xef, 0xe2, + 0x58, 0xa7, 0x8b, 0x63, 0xdd, 0x5d, 0x1c, 0xeb, 0x97, 0x97, 0x70, 0x48, 0xcb, 0xd0, 0x8d, 0x64, + 0x56, 0x4f, 0xf8, 0xe1, 0xd9, 0x9a, 0xc7, 0xa7, 0x3d, 0xa1, 0xca, 0x99, 0x0a, 0x5f, 0xd6, 0xd3, + 0x7c, 0x7a, 0x08, 0x00, 0x00, 0xff, 0xff, 0x30, 0x6b, 0xf8, 0xf8, 0xfb, 0x01, 0x00, 0x00, } func (m *ObserverSet) Marshal() (dAtA []byte, err error) { diff --git a/x/observer/types/params.pb.go b/x/observer/types/params.pb.go index 0588f7228c..358881c06c 100644 --- a/x/observer/types/params.pb.go +++ b/x/observer/types/params.pb.go @@ -8,7 +8,6 @@ import ( github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" - _ "github.com/zeta-chain/zetacore/pkg/chains" io "io" math "math" math_bits "math/bits" @@ -260,47 +259,46 @@ func init() { } var fileDescriptor_e7fa4666eddf88e5 = []byte{ - // 626 bytes of a gzipped FileDescriptorProto + // 617 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xc1, 0x4e, 0xd4, 0x40, 0x18, 0xc7, 0xb7, 0x2e, 0x22, 0xcc, 0x02, 0x0b, 0x0d, 0x6a, 0x81, 0xa4, 0xac, 0x24, 0x6a, 0x43, 0x42, 0x6b, 0xd0, 0xa3, 0x92, 0xc8, 0x72, 0x21, 0x62, 0x24, 0x05, 0x0f, 0x7a, 0x70, 0x32, 0x3b, - 0x1d, 0xda, 0xc9, 0xb6, 0xfd, 0x9a, 0x99, 0x29, 0x82, 0x4f, 0xe1, 0x3b, 0xf8, 0x32, 0x1c, 0x39, - 0x1a, 0x0f, 0xc4, 0xc0, 0x8b, 0x98, 0x4e, 0xa7, 0xcb, 0x0a, 0x86, 0x83, 0xa7, 0xce, 0x7c, 0xff, - 0xdf, 0xff, 0xbf, 0xdf, 0x6c, 0xbf, 0x0e, 0xf2, 0xbe, 0x31, 0x45, 0x68, 0x42, 0x78, 0x1e, 0xe8, - 0x15, 0x08, 0x16, 0xc0, 0x40, 0x32, 0x71, 0xcc, 0x44, 0x50, 0x10, 0x41, 0x32, 0xe9, 0x17, 0x02, - 0x14, 0xd8, 0x2b, 0x23, 0xd2, 0x6f, 0x48, 0xbf, 0x21, 0x97, 0x17, 0x63, 0x88, 0x41, 0x73, 0x41, - 0xb5, 0xaa, 0x2d, 0xcb, 0xeb, 0x77, 0x85, 0x37, 0x8b, 0x3b, 0xd8, 0x62, 0x18, 0x07, 0xba, 0x24, - 0xcd, 0xa3, 0x66, 0xd7, 0xbe, 0xa0, 0x6e, 0xbf, 0xda, 0xef, 0xeb, 0xfe, 0xf6, 0xb8, 0x54, 0xf6, - 0x3b, 0x34, 0xa3, 0x11, 0x5c, 0xf7, 0xec, 0x58, 0xbd, 0xb6, 0xd7, 0xd9, 0xf4, 0xfc, 0x3b, 0x9a, - 0xf6, 0xc7, 0x32, 0xc2, 0x0e, 0xbd, 0xde, 0xac, 0xfd, 0x98, 0x44, 0x9d, 0x31, 0xd1, 0x5e, 0x42, - 0x53, 0x75, 0x38, 0x8f, 0x9c, 0x4e, 0xcf, 0xf2, 0xda, 0xe1, 0x03, 0xbd, 0xdf, 0x8d, 0xec, 0x0d, - 0x64, 0x53, 0xc8, 0x8f, 0xb8, 0xc8, 0x88, 0xe2, 0x90, 0x63, 0x0a, 0x65, 0xae, 0x1c, 0xab, 0x67, - 0x79, 0x13, 0xe1, 0xc2, 0xb8, 0xd2, 0xaf, 0x04, 0xdb, 0x43, 0xf3, 0x31, 0x91, 0xb8, 0x10, 0x9c, - 0x32, 0xac, 0x38, 0x1d, 0x32, 0xe1, 0xdc, 0xd3, 0xf0, 0x5c, 0x4c, 0xe4, 0x7e, 0x55, 0x3e, 0xd4, - 0x55, 0xfb, 0x29, 0x9a, 0xe3, 0xf9, 0x00, 0xca, 0x3c, 0x6a, 0xb8, 0xb6, 0xe6, 0x66, 0x4d, 0xd5, - 0x60, 0xcf, 0x51, 0x17, 0x4a, 0xf5, 0x17, 0x37, 0x51, 0xe7, 0x35, 0x65, 0x03, 0xae, 0xa3, 0x85, - 0xaf, 0x44, 0xd1, 0x04, 0x97, 0xea, 0x04, 0x1a, 0xf4, 0xbe, 0x46, 0xbb, 0x5a, 0xf8, 0xa8, 0x4e, - 0xc0, 0xb0, 0x6f, 0x90, 0x7e, 0xd9, 0x58, 0xc1, 0x90, 0x55, 0x47, 0xca, 0x95, 0x20, 0x54, 0x61, - 0x12, 0x45, 0x82, 0x49, 0xe9, 0x4c, 0xf5, 0x2c, 0x6f, 0x3a, 0x74, 0x2a, 0xe4, 0xb0, 0x22, 0xfa, - 0x06, 0x78, 0x5b, 0xeb, 0xf6, 0x6b, 0xb4, 0x4c, 0x21, 0xcf, 0x19, 0x55, 0x20, 0x6e, 0xbb, 0xa7, - 0x6b, 0xf7, 0x88, 0xb8, 0xe9, 0xee, 0x23, 0x97, 0x09, 0xba, 0xf9, 0x02, 0xd3, 0x52, 0x2a, 0x88, - 0x4e, 0x6f, 0x27, 0x20, 0x9d, 0xb0, 0xa2, 0xa9, 0x7e, 0x0d, 0xfd, 0xa3, 0x85, 0xd1, 0xdf, 0x22, - 0x69, 0xc2, 0xa2, 0x32, 0x65, 0x98, 0xe7, 0x8a, 0x89, 0x63, 0x92, 0x3a, 0x33, 0xfa, 0x1d, 0x3a, - 0x0d, 0x71, 0x60, 0x80, 0x5d, 0xa3, 0xdb, 0x5b, 0x68, 0xe5, 0xb6, 0x3b, 0x05, 0x18, 0x92, 0x84, - 0x91, 0xc8, 0x99, 0xd5, 0xf6, 0xa5, 0x9b, 0xf6, 0xbd, 0x06, 0xb0, 0x3f, 0xa1, 0xf9, 0x01, 0x49, - 0x53, 0x50, 0x58, 0x25, 0x82, 0xc9, 0x04, 0xd2, 0xc8, 0x99, 0xab, 0x9a, 0xde, 0xf6, 0xcf, 0x2e, - 0x56, 0x5b, 0xbf, 0x2e, 0x56, 0x9f, 0xc5, 0x5c, 0x25, 0xe5, 0xc0, 0xa7, 0x90, 0x05, 0x14, 0x64, - 0x06, 0xd2, 0x3c, 0x36, 0x64, 0x34, 0x0c, 0xd4, 0x69, 0xc1, 0xa4, 0xbf, 0xc3, 0x68, 0xd8, 0xad, - 0x73, 0x0e, 0x9b, 0x18, 0xfb, 0x08, 0x3d, 0xce, 0x78, 0x8e, 0x9b, 0x19, 0xc6, 0x11, 0x4b, 0x59, - 0xac, 0x07, 0xcc, 0xe9, 0xfe, 0xd7, 0x2f, 0x3c, 0xcc, 0x78, 0xfe, 0xc1, 0xa4, 0xed, 0x8c, 0xc2, - 0xec, 0x27, 0x68, 0x86, 0x4b, 0x2c, 0xcb, 0xa2, 0x00, 0xa1, 0x58, 0xe4, 0xcc, 0xf7, 0x2c, 0x6f, - 0x2a, 0xec, 0x70, 0x79, 0xd0, 0x94, 0xd6, 0xb6, 0xd0, 0xa4, 0xf9, 0x3e, 0x5e, 0xa1, 0x47, 0xe6, - 0xbc, 0x19, 0x51, 0xa5, 0xe0, 0xea, 0x14, 0x0f, 0x52, 0xa0, 0x43, 0xa9, 0x67, 0xb6, 0x1d, 0x2e, - 0xd6, 0xea, 0x7b, 0x23, 0x6e, 0x6b, 0x6d, 0x7b, 0xf7, 0xec, 0xd2, 0xb5, 0xce, 0x2f, 0x5d, 0xeb, - 0xf7, 0xa5, 0x6b, 0x7d, 0xbf, 0x72, 0x5b, 0xe7, 0x57, 0x6e, 0xeb, 0xe7, 0x95, 0xdb, 0xfa, 0x1c, - 0x8c, 0xf5, 0x5e, 0x4d, 0xd9, 0xc6, 0x8d, 0x7b, 0xe1, 0xe4, 0xfa, 0x16, 0xd1, 0x07, 0x19, 0x4c, - 0xea, 0x7b, 0xe1, 0xe5, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x11, 0xb3, 0xd5, 0xce, 0x04, - 0x00, 0x00, + 0x1d, 0xb6, 0x93, 0x6d, 0xe7, 0xdb, 0xcc, 0x4c, 0x11, 0x7c, 0x0a, 0xdf, 0xc1, 0x97, 0xe1, 0xc8, + 0xd1, 0x78, 0x20, 0x06, 0x5e, 0xc4, 0x74, 0x3a, 0x5d, 0x56, 0x30, 0x1c, 0x3c, 0xed, 0xf4, 0xfb, + 0xff, 0xfe, 0xff, 0x7e, 0xb3, 0xf3, 0x75, 0x50, 0xf0, 0x8d, 0x69, 0x42, 0x53, 0xc2, 0x45, 0x64, + 0x56, 0x20, 0x59, 0x04, 0x3d, 0xc5, 0xe4, 0x31, 0x93, 0xd1, 0x90, 0x48, 0x92, 0xab, 0x70, 0x28, + 0x41, 0x83, 0xbb, 0x32, 0x22, 0xc3, 0x9a, 0x0c, 0x6b, 0x72, 0x79, 0xb1, 0x0f, 0x7d, 0x30, 0x5c, + 0x54, 0xae, 0x2a, 0xcb, 0xf2, 0xfa, 0x5d, 0xe1, 0xf5, 0xa2, 0x62, 0xd7, 0xbe, 0xa0, 0x76, 0xb7, + 0x24, 0xf7, 0xcd, 0x3b, 0xf7, 0xb8, 0xd2, 0xee, 0x3b, 0x34, 0x63, 0xcc, 0xb8, 0xea, 0xc3, 0x73, + 0x3a, 0xcd, 0xa0, 0xb5, 0x19, 0x84, 0x77, 0x34, 0x12, 0x8e, 0x65, 0xc4, 0x2d, 0x7a, 0xfd, 0xb0, + 0xf6, 0x63, 0x12, 0xb5, 0xc6, 0x44, 0x77, 0x09, 0x4d, 0x55, 0xe1, 0x3c, 0xf1, 0x5a, 0x1d, 0x27, + 0x68, 0xc6, 0x0f, 0xcc, 0xf3, 0x6e, 0xe2, 0x6e, 0x20, 0x97, 0x82, 0x38, 0xe2, 0x32, 0x27, 0x9a, + 0x83, 0xc0, 0x14, 0x0a, 0xa1, 0x3d, 0xa7, 0xe3, 0x04, 0x13, 0xf1, 0xc2, 0xb8, 0xd2, 0x2d, 0x05, + 0x37, 0x40, 0xf3, 0x7d, 0xa2, 0xf0, 0x50, 0x72, 0xca, 0xb0, 0xe6, 0x74, 0xc0, 0xa4, 0x77, 0xcf, + 0xc0, 0x73, 0x7d, 0xa2, 0xf6, 0xcb, 0xf2, 0xa1, 0xa9, 0xba, 0x4f, 0xd1, 0x1c, 0x17, 0x3d, 0x28, + 0x44, 0x52, 0x73, 0x4d, 0xc3, 0xcd, 0xda, 0xaa, 0xc5, 0x9e, 0xa3, 0x36, 0x14, 0xfa, 0x2f, 0x6e, + 0xa2, 0xca, 0xab, 0xcb, 0x16, 0x5c, 0x47, 0x0b, 0x5f, 0x89, 0xa6, 0x29, 0x2e, 0xf4, 0x09, 0xd4, + 0xe8, 0x7d, 0x83, 0xb6, 0x8d, 0xf0, 0x51, 0x9f, 0x80, 0x65, 0xdf, 0x20, 0x73, 0x80, 0x58, 0xc3, + 0x80, 0x95, 0x5b, 0x12, 0x5a, 0x12, 0xaa, 0x31, 0x49, 0x12, 0xc9, 0x94, 0xf2, 0xa6, 0x3a, 0x4e, + 0x30, 0x1d, 0x7b, 0x25, 0x72, 0x58, 0x12, 0x5d, 0x0b, 0xbc, 0xad, 0x74, 0xf7, 0x35, 0x5a, 0xa6, + 0x20, 0x04, 0xa3, 0x1a, 0xe4, 0x6d, 0xf7, 0x74, 0xe5, 0x1e, 0x11, 0x37, 0xdd, 0x5d, 0xe4, 0x33, + 0x49, 0x37, 0x5f, 0x60, 0x5a, 0x28, 0x0d, 0xc9, 0xe9, 0xed, 0x04, 0x64, 0x12, 0x56, 0x0c, 0xd5, + 0xad, 0xa0, 0x7f, 0xb4, 0x30, 0xfa, 0x5b, 0x14, 0x4d, 0x59, 0x52, 0x64, 0x0c, 0x73, 0xa1, 0x99, + 0x3c, 0x26, 0x99, 0x37, 0x63, 0xce, 0xd0, 0xab, 0x89, 0x03, 0x0b, 0xec, 0x5a, 0xdd, 0xdd, 0x42, + 0x2b, 0xb7, 0xdd, 0x19, 0xc0, 0x80, 0xa4, 0x8c, 0x24, 0xde, 0xac, 0xb1, 0x2f, 0xdd, 0xb4, 0xef, + 0xd5, 0x80, 0xfb, 0x09, 0xcd, 0xf7, 0x48, 0x96, 0x81, 0xc6, 0x3a, 0x95, 0x4c, 0xa5, 0x90, 0x25, + 0xde, 0x5c, 0xd9, 0xf4, 0x76, 0x78, 0x76, 0xb1, 0xda, 0xf8, 0x75, 0xb1, 0xfa, 0xac, 0xcf, 0x75, + 0x5a, 0xf4, 0x42, 0x0a, 0x79, 0x44, 0x41, 0xe5, 0xa0, 0xec, 0xcf, 0x86, 0x4a, 0x06, 0x91, 0x3e, + 0x1d, 0x32, 0x15, 0xee, 0x30, 0x1a, 0xb7, 0xab, 0x9c, 0xc3, 0x3a, 0xc6, 0x3d, 0x42, 0x8f, 0x73, + 0x2e, 0x70, 0x3d, 0xc3, 0x38, 0x61, 0x19, 0xeb, 0x9b, 0x01, 0xf3, 0xda, 0xff, 0xf5, 0x86, 0x87, + 0x39, 0x17, 0x1f, 0x6c, 0xda, 0xce, 0x28, 0xcc, 0x7d, 0x82, 0x66, 0xb8, 0xc2, 0xaa, 0x18, 0x0e, + 0x41, 0x6a, 0x96, 0x78, 0xf3, 0x1d, 0x27, 0x98, 0x8a, 0x5b, 0x5c, 0x1d, 0xd4, 0xa5, 0xb5, 0x2d, + 0x34, 0x69, 0xbf, 0x8f, 0x57, 0xe8, 0x91, 0xdd, 0x6f, 0x4e, 0x74, 0x21, 0xb9, 0x3e, 0xc5, 0xbd, + 0x0c, 0xe8, 0x40, 0x99, 0x99, 0x6d, 0xc6, 0x8b, 0x95, 0xfa, 0xde, 0x8a, 0xdb, 0x46, 0xdb, 0xde, + 0x3d, 0xbb, 0xf4, 0x9d, 0xf3, 0x4b, 0xdf, 0xf9, 0x7d, 0xe9, 0x3b, 0xdf, 0xaf, 0xfc, 0xc6, 0xf9, + 0x95, 0xdf, 0xf8, 0x79, 0xe5, 0x37, 0x3e, 0x47, 0x63, 0xbd, 0x97, 0x53, 0xb6, 0x71, 0xe3, 0x5e, + 0x38, 0xb9, 0xbe, 0x19, 0xcc, 0x46, 0x7a, 0x93, 0xe6, 0x5e, 0x78, 0xf9, 0x27, 0x00, 0x00, 0xff, + 0xff, 0xed, 0x67, 0xea, 0xcb, 0xa2, 0x04, 0x00, 0x00, } func (m *ChainParamsList) Marshal() (dAtA []byte, err error) { diff --git a/x/observer/types/query.pb.go b/x/observer/types/query.pb.go index 38d676df2b..6efedd0393 100644 --- a/x/observer/types/query.pb.go +++ b/x/observer/types/query.pb.go @@ -1329,7 +1329,7 @@ func (m *QuerySupportedChains) XXX_DiscardUnknown() { var xxx_messageInfo_QuerySupportedChains proto.InternalMessageInfo type QuerySupportedChainsResponse struct { - Chains []*chains.Chain `protobuf:"bytes,1,rep,name=chains,proto3" json:"chains,omitempty"` + Chains []chains.Chain `protobuf:"bytes,1,rep,name=chains,proto3" json:"chains"` } func (m *QuerySupportedChainsResponse) Reset() { *m = QuerySupportedChainsResponse{} } @@ -1365,7 +1365,7 @@ func (m *QuerySupportedChainsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QuerySupportedChainsResponse proto.InternalMessageInfo -func (m *QuerySupportedChainsResponse) GetChains() []*chains.Chain { +func (m *QuerySupportedChainsResponse) GetChains() []chains.Chain { if m != nil { return m.Chains } @@ -2301,150 +2301,150 @@ func init() { } var fileDescriptor_25b2aa420449a0c0 = []byte{ - // 2284 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x5a, 0xcf, 0x6f, 0x1b, 0xc7, - 0x15, 0xf6, 0x4a, 0x89, 0x22, 0x8d, 0x6c, 0xfd, 0x18, 0xcb, 0xb6, 0x42, 0x3b, 0xb2, 0x3c, 0x92, - 0x63, 0x59, 0x91, 0xb9, 0xb6, 0xec, 0xd4, 0xbf, 0x63, 0x8b, 0x6e, 0x24, 0xd9, 0x49, 0x6c, 0x87, - 0x74, 0x1b, 0xc0, 0x48, 0xcb, 0x2e, 0xc9, 0x21, 0xb9, 0xf5, 0x6a, 0x87, 0xd9, 0x19, 0x39, 0x61, - 0x54, 0x01, 0x45, 0x6f, 0xcd, 0xa1, 0x28, 0x50, 0xa0, 0xbd, 0x15, 0xb9, 0xf4, 0x58, 0xa0, 0x08, - 0x50, 0xb4, 0x40, 0xd1, 0x43, 0x4e, 0xcd, 0xa1, 0x87, 0x14, 0x2d, 0x8a, 0x9e, 0xda, 0xc0, 0xee, - 0x1f, 0x52, 0xec, 0xcc, 0x5b, 0x72, 0x77, 0xb9, 0xbb, 0x1c, 0xca, 0xea, 0x89, 0xdc, 0xd9, 0x79, - 0x6f, 0xbe, 0xef, 0xed, 0xcc, 0x7b, 0xdf, 0xce, 0x2c, 0x3a, 0xf3, 0x29, 0x15, 0x56, 0xb5, 0x69, - 0xd9, 0xae, 0x29, 0xff, 0x31, 0x8f, 0x9a, 0xac, 0xc2, 0xa9, 0xf7, 0x94, 0x7a, 0xe6, 0x47, 0xdb, - 0xd4, 0x6b, 0xe7, 0x5b, 0x1e, 0x13, 0x0c, 0x1f, 0xef, 0x74, 0xcc, 0x07, 0x1d, 0xf3, 0x41, 0xc7, - 0xdc, 0x72, 0x95, 0xf1, 0x2d, 0xc6, 0xcd, 0x8a, 0xc5, 0xa9, 0xb2, 0x32, 0x9f, 0x5e, 0xa8, 0x50, - 0x61, 0x5d, 0x30, 0x5b, 0x56, 0xc3, 0x76, 0x2d, 0x61, 0x33, 0x57, 0x39, 0xca, 0xcd, 0x34, 0x58, - 0x83, 0xc9, 0xbf, 0xa6, 0xff, 0x0f, 0x5a, 0x4f, 0x34, 0x18, 0x6b, 0x38, 0xd4, 0xb4, 0x5a, 0xb6, - 0x69, 0xb9, 0x2e, 0x13, 0xd2, 0x84, 0xc3, 0xdd, 0xa5, 0x2c, 0x94, 0x15, 0xcb, 0x71, 0x98, 0x80, - 0x9e, 0x99, 0x7c, 0x2a, 0x8e, 0xb5, 0x45, 0xa1, 0x63, 0x3e, 0xab, 0xa3, 0x6c, 0x2f, 0xbb, 0xcc, - 0xad, 0xd2, 0x00, 0xc2, 0x6a, 0x66, 0x7f, 0x8f, 0x71, 0xae, 0x8c, 0xea, 0x8e, 0xd5, 0xd0, 0x82, - 0xfd, 0x84, 0xb6, 0x1b, 0xd4, 0xd5, 0x41, 0xe3, 0xb2, 0x1a, 0x2d, 0x5b, 0xd5, 0x2a, 0xdb, 0x76, - 0x03, 0x9a, 0xcb, 0x59, 0xfd, 0x83, 0x3f, 0x3a, 0x28, 0x5a, 0x96, 0x67, 0x6d, 0x05, 0x78, 0xcf, - 0x67, 0xf6, 0xa4, 0x6e, 0xcd, 0x76, 0x1b, 0xd1, 0xa8, 0x9c, 0xce, 0xb2, 0x10, 0x9c, 0x67, 0xc0, - 0x6d, 0x3d, 0x69, 0xa8, 0x38, 0x73, 0xf8, 0xe9, 0xd3, 0xb7, 0xe5, 0x31, 0x56, 0xe7, 0xf0, 0x03, - 0x7d, 0x2f, 0xf5, 0x19, 0xbe, 0x5c, 0xdf, 0x76, 0x6b, 0xbc, 0xbc, 0x65, 0x37, 0x3c, 0x4b, 0x30, - 0x08, 0x08, 0x39, 0x8d, 0x16, 0xde, 0xf7, 0xe7, 0xe8, 0x23, 0xce, 0xd7, 0xfd, 0xfb, 0xef, 0xc1, - 0xed, 0xbb, 0x6e, 0x9d, 0xad, 0x39, 0x4e, 0x91, 0x7e, 0xb4, 0x4d, 0xb9, 0x20, 0x3f, 0x33, 0xd0, - 0x62, 0x76, 0x3f, 0xde, 0x62, 0x2e, 0xa7, 0xb8, 0x8e, 0x0e, 0xf7, 0x8e, 0xc5, 0x67, 0x8d, 0xf9, - 0xe1, 0xa5, 0xf1, 0xd5, 0xf3, 0xf9, 0x8c, 0x85, 0x93, 0x07, 0xd7, 0x61, 0xcf, 0x85, 0x97, 0xbe, - 0xfa, 0xf7, 0xc9, 0x03, 0xc5, 0x69, 0x11, 0x1b, 0x95, 0x93, 0x9b, 0x68, 0x3e, 0x15, 0x0f, 0x80, - 0xc6, 0xaf, 0xa2, 0x51, 0x35, 0x0f, 0xed, 0xda, 0xac, 0x31, 0x6f, 0x2c, 0x0d, 0x17, 0x5f, 0x91, - 0xd7, 0x77, 0x6b, 0xe4, 0xa7, 0x06, 0x3a, 0x95, 0x61, 0x0f, 0x64, 0x6a, 0x08, 0xf7, 0x92, 0x91, - 0xae, 0xf6, 0xce, 0x65, 0x2a, 0xce, 0x85, 0xac, 0xa2, 0x9c, 0x84, 0xb2, 0x41, 0xc5, 0x1d, 0xdf, - 0xdd, 0x7d, 0x39, 0xa9, 0x02, 0x12, 0x33, 0xe8, 0x65, 0xdb, 0xad, 0xd1, 0x4f, 0xe4, 0xb0, 0x63, - 0x45, 0x75, 0x41, 0x18, 0x3a, 0x9e, 0x68, 0x03, 0xc0, 0x1f, 0xa2, 0xf1, 0x50, 0x33, 0x20, 0x5e, - 0xca, 0x44, 0x1c, 0xea, 0x0f, 0x48, 0xc3, 0x2e, 0x48, 0x0d, 0x40, 0xae, 0x39, 0x4e, 0x02, 0xc8, - 0x75, 0x84, 0xba, 0xb9, 0x0d, 0x86, 0x7b, 0x3d, 0xaf, 0x12, 0x61, 0xde, 0x4f, 0x84, 0x79, 0x95, - 0x3e, 0x21, 0x11, 0xe6, 0x1f, 0x5a, 0x0d, 0x0a, 0xb6, 0xc5, 0x90, 0x25, 0xf9, 0xa3, 0x01, 0xbc, - 0xe2, 0xc3, 0xa4, 0xf1, 0x1a, 0x7e, 0x41, 0x5e, 0x78, 0x23, 0x82, 0x7c, 0x48, 0x22, 0x3f, 0xd3, - 0x17, 0xb9, 0x82, 0x13, 0x81, 0x5e, 0x47, 0x27, 0x02, 0xe4, 0x0f, 0x55, 0x76, 0xf8, 0xff, 0x84, - 0xe8, 0x4b, 0x03, 0xbd, 0x96, 0x32, 0x10, 0x04, 0xe9, 0x03, 0x34, 0x11, 0xcd, 0x4f, 0x10, 0xa7, - 0xe5, 0xcc, 0x38, 0x45, 0x7c, 0x41, 0xa4, 0x0e, 0xb5, 0xc2, 0x8d, 0xfb, 0x17, 0xab, 0x60, 0xf1, - 0x46, 0xc7, 0x6c, 0xcb, 0xe7, 0xa2, 0xb1, 0x78, 0x7f, 0x04, 0x6b, 0x37, 0xd9, 0x3c, 0x23, 0x0a, - 0xc6, 0x3e, 0x44, 0x81, 0xcc, 0x20, 0x1c, 0x2c, 0xbd, 0x47, 0xa5, 0x52, 0x90, 0x20, 0x1f, 0xa0, - 0xc3, 0x91, 0x56, 0x40, 0x71, 0x05, 0x0d, 0x3f, 0x2a, 0x95, 0x60, 0xe8, 0xf9, 0xec, 0x94, 0x51, - 0x2a, 0xc1, 0x80, 0xbe, 0x09, 0x79, 0x1b, 0xbd, 0xda, 0x71, 0xc8, 0xf9, 0x5a, 0xad, 0xe6, 0x51, - 0xde, 0x99, 0x4c, 0x4b, 0x68, 0xaa, 0x62, 0x8b, 0x2a, 0xb3, 0xdd, 0x72, 0x27, 0x48, 0x43, 0x32, - 0x48, 0x13, 0xd0, 0x7e, 0x07, 0x62, 0x75, 0xbb, 0x9b, 0x5c, 0xc2, 0x6e, 0x00, 0xde, 0x14, 0x1a, - 0xa6, 0xa2, 0x09, 0xa9, 0xc5, 0xff, 0xeb, 0xb7, 0x54, 0x44, 0x55, 0x3a, 0x1b, 0x2b, 0xfa, 0x7f, - 0xc9, 0x67, 0x06, 0x5a, 0xee, 0x75, 0x51, 0x68, 0xaf, 0xdb, 0xae, 0xe5, 0xd8, 0x9f, 0xd2, 0xda, - 0x26, 0xb5, 0x1b, 0x4d, 0x11, 0x40, 0x5b, 0x45, 0x47, 0xea, 0xc1, 0x9d, 0xb2, 0xcf, 0xb2, 0xdc, - 0x94, 0xf7, 0xe1, 0x21, 0x1e, 0xee, 0xdc, 0x7c, 0x4c, 0x85, 0xa5, 0x4c, 0x07, 0xa0, 0xf3, 0x3e, - 0x7a, 0x43, 0x0b, 0xcb, 0x00, 0xfc, 0x7e, 0x80, 0x8e, 0x06, 0x95, 0x60, 0xd3, 0xe6, 0x82, 0x79, - 0xed, 0xfd, 0x5e, 0xb2, 0xbf, 0x31, 0xd0, 0xb1, 0x9e, 0x21, 0x00, 0xe1, 0x1a, 0x1a, 0xf5, 0x4b, - 0x8c, 0x63, 0x73, 0x01, 0xcb, 0x54, 0x77, 0x96, 0xbc, 0x22, 0x38, 0x7f, 0xd7, 0xe6, 0x62, 0xff, - 0x96, 0x65, 0x13, 0xcd, 0x48, 0x98, 0x9b, 0x16, 0xff, 0x2e, 0x13, 0xb4, 0x16, 0xc4, 0xe1, 0x0d, - 0x34, 0xad, 0x74, 0x65, 0xd9, 0xae, 0x51, 0x57, 0xd8, 0x75, 0x9b, 0x7a, 0x10, 0xd3, 0x29, 0x75, - 0xe3, 0x6e, 0xa7, 0x1d, 0x2f, 0xa0, 0x43, 0x4f, 0x99, 0xa0, 0x5e, 0xd9, 0x52, 0x0f, 0x07, 0x42, - 0x7d, 0x50, 0x36, 0xc2, 0x03, 0x23, 0x97, 0xd0, 0x91, 0xd8, 0x48, 0x10, 0x8e, 0xe3, 0x68, 0xac, - 0x69, 0xf1, 0xb2, 0xdf, 0x59, 0x2d, 0xfb, 0xd1, 0xe2, 0x68, 0x13, 0x3a, 0x91, 0xf7, 0xd0, 0x9c, - 0xb4, 0x2a, 0xc8, 0x31, 0x0b, 0xed, 0xee, 0xa8, 0x7b, 0x41, 0x4a, 0x04, 0x1a, 0xf3, 0xfd, 0x7a, - 0x32, 0x88, 0x3d, 0xb0, 0x8d, 0x5e, 0xd8, 0xb8, 0x80, 0xc6, 0xfc, 0xeb, 0xb2, 0x68, 0xb7, 0xa8, - 0xe4, 0x35, 0xb1, 0x7a, 0x3a, 0xf3, 0x69, 0xf9, 0xfe, 0x1f, 0xb5, 0x5b, 0xb4, 0x38, 0xfa, 0x14, - 0xfe, 0x91, 0x3f, 0x0c, 0xa1, 0x93, 0xa9, 0x2c, 0x20, 0x0a, 0x03, 0x05, 0xfc, 0x2d, 0x34, 0x22, - 0x41, 0xfa, 0x91, 0x1e, 0x96, 0x33, 0xb4, 0x1f, 0x22, 0xc9, 0xb8, 0x08, 0x56, 0xf8, 0x03, 0x34, - 0xa5, 0xee, 0xca, 0x49, 0xa0, 0xb8, 0x0d, 0x4b, 0x6e, 0x2b, 0x99, 0x9e, 0x1e, 0x74, 0x8d, 0x24, - 0xc5, 0x49, 0x16, 0x6d, 0xc0, 0xf7, 0xd1, 0x21, 0x60, 0xc1, 0x85, 0x25, 0xb6, 0xf9, 0xec, 0x4b, - 0xd2, 0xeb, 0xd9, 0x4c, 0xaf, 0x2a, 0x2a, 0x25, 0x69, 0x50, 0x3c, 0x58, 0x09, 0x5d, 0x11, 0x8c, - 0xa6, 0x64, 0xe0, 0x1e, 0x40, 0xdf, 0x12, 0x15, 0xe4, 0x0a, 0x9a, 0x8d, 0xb7, 0x75, 0xa2, 0x78, - 0x02, 0x8d, 0x05, 0x6e, 0x55, 0x09, 0x1c, 0x2b, 0x76, 0x1b, 0xc8, 0x51, 0x98, 0xec, 0xa5, 0xed, - 0x56, 0x8b, 0x79, 0x82, 0xd6, 0x64, 0x8a, 0xe1, 0xe4, 0x43, 0xa8, 0xe3, 0xb1, 0xf6, 0x8e, 0xd7, - 0x1b, 0x68, 0x44, 0x49, 0x74, 0x58, 0xae, 0x8b, 0x49, 0x74, 0x5a, 0x4f, 0x1a, 0x79, 0x10, 0xf2, - 0xaa, 0x2a, 0x81, 0x0d, 0xb9, 0x85, 0x48, 0x44, 0xb7, 0x3d, 0x94, 0xaf, 0x1c, 0xeb, 0xcc, 0xd3, - 0xad, 0x7d, 0x1e, 0xe8, 0xf5, 0x34, 0x07, 0x80, 0xf2, 0x1d, 0x74, 0x50, 0x79, 0x50, 0xef, 0x34, - 0xfa, 0x0a, 0x50, 0xf9, 0x2b, 0x8e, 0x57, 0xbb, 0x17, 0xe4, 0x44, 0x4c, 0xa0, 0x42, 0x1f, 0xa8, - 0x7c, 0x6e, 0x4c, 0x8a, 0x06, 0x77, 0x01, 0xc9, 0x83, 0x44, 0x24, 0x2b, 0xba, 0x48, 0xe4, 0x54, - 0x8d, 0xa0, 0x09, 0xc9, 0xe5, 0xfb, 0xac, 0x46, 0xd7, 0xd4, 0xbb, 0x60, 0xb6, 0x5c, 0xfe, 0x61, - 0x17, 0x63, 0xc4, 0xa6, 0x1b, 0xad, 0xf0, 0x7b, 0xa5, 0x56, 0xb4, 0xc2, 0x7e, 0xc6, 0xdd, 0xee, - 0x45, 0x58, 0x29, 0x27, 0xe0, 0xdb, 0xaf, 0x9a, 0xf2, 0x45, 0x48, 0x29, 0x27, 0x51, 0xba, 0x87, - 0xc6, 0x43, 0xcd, 0x5a, 0x4a, 0x39, 0xc2, 0x28, 0x74, 0xb1, 0x7f, 0x05, 0x66, 0x1e, 0x12, 0xb8, - 0x3f, 0x55, 0x3a, 0xbb, 0x04, 0xeb, 0x8e, 0xd5, 0xe8, 0x4c, 0xa6, 0x1f, 0x1b, 0x90, 0x1d, 0x93, - 0xba, 0x00, 0xb5, 0xef, 0xa1, 0xa9, 0xf8, 0x1e, 0x83, 0xde, 0xac, 0x8a, 0xfa, 0x83, 0x32, 0x3a, - 0x59, 0x8d, 0x36, 0x93, 0x63, 0x50, 0x9b, 0x36, 0xa8, 0x78, 0x47, 0x6e, 0x4b, 0x04, 0xd8, 0xbe, - 0x03, 0x42, 0x21, 0x74, 0x03, 0x10, 0x5d, 0x47, 0x23, 0x6a, 0x07, 0x03, 0x70, 0x2c, 0x64, 0xe2, - 0x00, 0x63, 0x30, 0x21, 0x27, 0x41, 0xcf, 0x97, 0x9a, 0xec, 0xe3, 0x20, 0x8d, 0xdd, 0x09, 0x4d, - 0x19, 0x3f, 0x26, 0x73, 0x69, 0x3d, 0x00, 0xc0, 0xf7, 0xd1, 0x61, 0xc7, 0xe2, 0xa2, 0x1c, 0x8c, - 0x51, 0x0e, 0xcf, 0xe3, 0x7c, 0x26, 0x9a, 0x77, 0x2d, 0x2e, 0xa2, 0x4e, 0xa7, 0x9d, 0x78, 0x13, - 0xb9, 0x07, 0x18, 0x0b, 0x8e, 0xb5, 0x45, 0x93, 0x0a, 0xef, 0x59, 0x34, 0x25, 0x37, 0x94, 0x7a, - 0x0b, 0xd6, 0xa4, 0x6c, 0x0f, 0x95, 0xdd, 0x6a, 0x50, 0xc5, 0x7b, 0x7d, 0x75, 0x34, 0x11, 0x02, - 0x67, 0x6e, 0x9d, 0x01, 0x09, 0x92, 0x5d, 0x35, 0xfc, 0xee, 0xc5, 0x31, 0x35, 0x94, 0x5b, 0x67, - 0x84, 0x76, 0x57, 0x87, 0xba, 0x47, 0xab, 0xcc, 0xab, 0xed, 0xfb, 0xcb, 0xd8, 0xef, 0x8c, 0xee, - 0x5b, 0x5f, 0x74, 0x1c, 0xa0, 0xb2, 0x11, 0xa3, 0x32, 0xac, 0x47, 0x05, 0xe6, 0x66, 0x97, 0xd0, - 0xfe, 0xad, 0xc1, 0x12, 0xbc, 0x7b, 0x41, 0xf8, 0x65, 0xaa, 0x5d, 0x73, 0x6b, 0xf2, 0xe5, 0xa6, - 0x7f, 0xfd, 0xf1, 0xf3, 0xab, 0x7c, 0x9d, 0x02, 0x7d, 0xae, 0x2e, 0x48, 0x1d, 0xde, 0xc8, 0x92, - 0x9d, 0xa6, 0x3c, 0xd6, 0xe1, 0x81, 0x1f, 0xeb, 0xea, 0xe7, 0x8b, 0xe8, 0x65, 0x39, 0x10, 0xfe, - 0xb3, 0x81, 0x46, 0x03, 0xf5, 0x88, 0x2f, 0x64, 0x7a, 0x49, 0xd2, 0xb4, 0xb9, 0xd5, 0x41, 0x4c, - 0x14, 0x01, 0x72, 0xef, 0x27, 0x7f, 0xff, 0xef, 0x2f, 0x86, 0xbe, 0x8d, 0x0b, 0x72, 0x83, 0xed, - 0x9c, 0xda, 0x6b, 0xeb, 0x6c, 0xb1, 0x75, 0x74, 0xab, 0xb9, 0xd3, 0x23, 0xde, 0x76, 0xcd, 0x9d, - 0x88, 0xba, 0xdc, 0xc5, 0xff, 0x34, 0x10, 0xee, 0x55, 0x80, 0xf8, 0x7a, 0x7f, 0x58, 0xa9, 0xea, - 0x37, 0x77, 0x63, 0x6f, 0xc6, 0xc0, 0xee, 0x6d, 0xc9, 0xee, 0x16, 0xbe, 0x99, 0xc8, 0x0e, 0x28, - 0x55, 0xda, 0x21, 0x56, 0x49, 0x44, 0xf1, 0xaf, 0x0d, 0x34, 0x1e, 0x52, 0x63, 0xf8, 0x5c, 0x7f, - 0x50, 0xa1, 0xee, 0xb9, 0x37, 0x07, 0xea, 0xde, 0x01, 0x7f, 0x56, 0x82, 0x5f, 0xc0, 0xa7, 0x12, - 0xc1, 0x77, 0xd2, 0x22, 0xa7, 0x02, 0xff, 0xd6, 0x40, 0x93, 0x31, 0x71, 0xa7, 0x33, 0x81, 0x62, - 0x26, 0xb9, 0xab, 0x03, 0x9b, 0x74, 0xc0, 0xae, 0x48, 0xb0, 0xaf, 0xe3, 0xc5, 0x44, 0xb0, 0x3c, - 0x86, 0xed, 0x3f, 0x06, 0x3a, 0x9a, 0xac, 0xf6, 0xf0, 0xad, 0xfe, 0x18, 0x32, 0x85, 0x66, 0xee, - 0xf6, 0xde, 0x1d, 0x00, 0x97, 0x82, 0xe4, 0x72, 0x03, 0x5f, 0x4b, 0xe4, 0xd2, 0xa0, 0xa2, 0x1c, - 0x56, 0x7f, 0xe5, 0x3a, 0xf3, 0x54, 0x83, 0xb9, 0x13, 0x64, 0x98, 0x5d, 0xfc, 0x85, 0x81, 0x26, - 0xa2, 0xc3, 0xe0, 0xcb, 0x83, 0x02, 0x0b, 0x18, 0x5d, 0x19, 0xdc, 0x10, 0x98, 0x9c, 0x93, 0x4c, - 0xce, 0xe0, 0xd3, 0x5a, 0x4c, 0x7c, 0xd0, 0x11, 0x91, 0xa4, 0x87, 0xb8, 0x57, 0x11, 0x6a, 0x22, - 0x4e, 0xd0, 0x78, 0xe4, 0xbc, 0x44, 0xbc, 0x8c, 0x97, 0x12, 0x11, 0x87, 0x34, 0xa9, 0xb9, 0x23, - 0x65, 0xf0, 0xae, 0x3f, 0xf7, 0x27, 0x42, 0x9e, 0xd6, 0x1c, 0x47, 0x07, 0x77, 0xa2, 0x92, 0xd5, - 0xc1, 0x9d, 0xac, 0x4d, 0xc9, 0x92, 0xc4, 0x4d, 0xf0, 0x7c, 0x3f, 0xdc, 0xf8, 0x4f, 0x06, 0x9a, - 0x8c, 0xc9, 0x36, 0x9d, 0x14, 0x99, 0xaa, 0x2f, 0x75, 0x52, 0x64, 0xba, 0xf2, 0xec, 0x33, 0x45, - 0xe2, 0xa2, 0x14, 0xff, 0xd2, 0x40, 0x23, 0x4a, 0xec, 0xe1, 0x55, 0xad, 0x71, 0x23, 0x7a, 0x33, - 0x77, 0x71, 0x20, 0x1b, 0x80, 0xb8, 0x20, 0x21, 0xbe, 0x86, 0x8f, 0x27, 0x42, 0x54, 0x92, 0x13, - 0xff, 0xc5, 0x40, 0xd3, 0x3d, 0x62, 0x12, 0x5f, 0xd3, 0xc8, 0x68, 0x29, 0x1a, 0x35, 0x77, 0x7d, - 0x4f, 0xb6, 0x80, 0xf9, 0xaa, 0xc4, 0x7c, 0x11, 0x5f, 0x08, 0x63, 0xee, 0x3d, 0xc3, 0xe2, 0x4d, - 0xf6, 0x71, 0x4c, 0xe1, 0xe2, 0xbf, 0x19, 0x68, 0xba, 0x47, 0x48, 0xea, 0x30, 0x49, 0x53, 0xb2, - 0x3a, 0x4c, 0x52, 0x95, 0x2b, 0xb9, 0x23, 0x99, 0xdc, 0xc4, 0xd7, 0x93, 0x6b, 0xa8, 0x54, 0x3f, - 0xf1, 0x12, 0x1a, 0x93, 0xcd, 0xbb, 0xbe, 0xb4, 0xc1, 0x1b, 0x54, 0xc4, 0x24, 0x25, 0xd6, 0x5b, - 0x6f, 0x09, 0x6a, 0x57, 0xa7, 0x54, 0xa5, 0xe8, 0x57, 0xb2, 0x2a, 0x09, 0xad, 0xe0, 0xe5, 0xd4, - 0xa4, 0x68, 0x39, 0x4e, 0x59, 0x71, 0xf0, 0x00, 0xe8, 0x37, 0x06, 0x3a, 0x22, 0x9d, 0xf1, 0x98, - 0x12, 0xc4, 0x37, 0xb5, 0x63, 0x9b, 0x24, 0x4b, 0x73, 0x6f, 0xed, 0xd5, 0x1c, 0xc8, 0x6c, 0x4a, - 0x32, 0x05, 0x7c, 0x3b, 0xfb, 0xe9, 0xa8, 0x25, 0x6c, 0xb9, 0x35, 0x75, 0x70, 0x10, 0xaa, 0x54, - 0xe6, 0x8e, 0x6c, 0xd9, 0xc5, 0x5f, 0x1a, 0xe8, 0x50, 0x64, 0x0b, 0x1a, 0x7f, 0x4b, 0x6b, 0xb1, - 0xf6, 0xec, 0xe4, 0xe7, 0x2e, 0x0f, 0x6c, 0x07, 0x64, 0x6e, 0x49, 0x32, 0x57, 0xf1, 0xe5, 0xd4, - 0x27, 0x23, 0x38, 0x0f, 0xf4, 0xa6, 0xb9, 0x13, 0xdf, 0x5f, 0xdf, 0xc5, 0xbf, 0x1a, 0x42, 0x73, - 0xd9, 0xdb, 0xe8, 0x78, 0x63, 0x40, 0x70, 0x69, 0x87, 0x02, 0xb9, 0xcd, 0x17, 0x77, 0x04, 0xb4, - 0x2b, 0x92, 0xf6, 0x87, 0xf8, 0xb1, 0x0e, 0xed, 0x72, 0x53, 0xee, 0xb6, 0xdb, 0x55, 0xcb, 0x31, - 0x77, 0x12, 0x4f, 0x25, 0x76, 0x93, 0x22, 0xf3, 0x99, 0x21, 0x4f, 0x6d, 0xb0, 0xa9, 0x87, 0xba, - 0x73, 0x08, 0x94, 0x3b, 0xaf, 0x6f, 0x00, 0x74, 0xe6, 0x25, 0x9d, 0x1c, 0x9e, 0x4d, 0xa4, 0xe3, - 0x83, 0xf8, 0xdc, 0x40, 0xa8, 0x7b, 0x6e, 0x80, 0x35, 0x8a, 0x42, 0xcf, 0x41, 0x46, 0xee, 0xd2, - 0x60, 0x46, 0x80, 0xed, 0x8c, 0xc4, 0x76, 0x0a, 0x9f, 0x4c, 0xc4, 0x26, 0xba, 0x98, 0x7e, 0x6f, - 0xa0, 0xa9, 0xc8, 0xc1, 0x99, 0xaf, 0x2b, 0xf4, 0x92, 0x4e, 0xd2, 0x51, 0x69, 0xee, 0xda, 0x5e, - 0x4c, 0x01, 0xf4, 0xb2, 0x04, 0xbd, 0x88, 0x49, 0x22, 0xe8, 0xe8, 0x79, 0xe6, 0x5f, 0x0d, 0x34, - 0x93, 0x74, 0x86, 0xa8, 0x93, 0xa7, 0x32, 0x8e, 0x2e, 0x75, 0xf2, 0x54, 0xd6, 0xd1, 0x25, 0x79, - 0x53, 0x72, 0x30, 0xf1, 0xb9, 0xfe, 0x1c, 0x62, 0x32, 0x3a, 0x72, 0xb4, 0x3d, 0x80, 0x86, 0x8e, - 0xc6, 0xff, 0xca, 0xe0, 0x86, 0x5a, 0x8a, 0xb4, 0xda, 0xb5, 0x88, 0x28, 0xd2, 0x90, 0x27, 0x7d, - 0x45, 0xba, 0x37, 0xdc, 0xc9, 0xdf, 0x15, 0xf4, 0x51, 0xa4, 0x21, 0xdc, 0xbe, 0x74, 0x9a, 0x49, - 0xfa, 0x66, 0x44, 0x67, 0xce, 0x64, 0x7c, 0xab, 0xa2, 0x33, 0x67, 0xb2, 0x3e, 0x55, 0xe9, 0x13, - 0xf9, 0x86, 0x4c, 0xae, 0x11, 0x6b, 0xfc, 0x0f, 0x03, 0x1d, 0x4b, 0xf9, 0x9a, 0x07, 0xdf, 0xde, - 0x1b, 0x9a, 0xee, 0x07, 0x43, 0xb9, 0xb5, 0x17, 0xf0, 0x00, 0x94, 0x2e, 0x49, 0x4a, 0x79, 0xbc, - 0x92, 0x46, 0x69, 0xcd, 0x71, 0xe2, 0x3e, 0x78, 0xe1, 0xee, 0x57, 0xcf, 0xe6, 0x8c, 0xaf, 0x9f, - 0xcd, 0x19, 0xdf, 0x3c, 0x9b, 0x33, 0x7e, 0xfe, 0x7c, 0xee, 0xc0, 0xd7, 0xcf, 0xe7, 0x0e, 0xfc, - 0xeb, 0xf9, 0xdc, 0x81, 0xc7, 0x66, 0xc3, 0x16, 0xcd, 0xed, 0x4a, 0xbe, 0xca, 0xb6, 0x12, 0x85, - 0xe6, 0x27, 0xa1, 0xe4, 0xd6, 0x6e, 0x51, 0x5e, 0x19, 0x91, 0x9f, 0x48, 0x5d, 0xfc, 0x5f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xc1, 0xd9, 0x00, 0xc6, 0x18, 0x28, 0x00, 0x00, + // 2285 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x5a, 0xcf, 0x6f, 0xdc, 0xc6, + 0x15, 0x36, 0xa5, 0x44, 0x91, 0x9e, 0x6c, 0xfd, 0x18, 0xcb, 0xb6, 0xb2, 0x76, 0x64, 0x99, 0x92, + 0x63, 0x59, 0x91, 0x97, 0xb6, 0xec, 0xd4, 0xbf, 0xe2, 0xd8, 0x5a, 0x37, 0x92, 0xec, 0x24, 0xb6, + 0xb3, 0xeb, 0x36, 0x80, 0xd1, 0x76, 0xcb, 0xdd, 0x9d, 0xdd, 0x65, 0x4d, 0x71, 0x36, 0x9c, 0x91, + 0x93, 0x8d, 0x2a, 0xa0, 0xe8, 0xad, 0x39, 0x14, 0x05, 0x0a, 0xb4, 0xb7, 0x22, 0x97, 0x1e, 0x0b, + 0x14, 0x01, 0x8a, 0x16, 0x28, 0x7a, 0xc8, 0xa9, 0x39, 0xf4, 0x90, 0xa2, 0x45, 0xd1, 0x53, 0x6b, + 0xd8, 0xfd, 0x43, 0x0a, 0x0e, 0x1f, 0x77, 0x49, 0x2e, 0xc9, 0x9d, 0x95, 0x95, 0xd3, 0x2e, 0x87, + 0xef, 0xbd, 0xf9, 0xbe, 0xc7, 0x99, 0x37, 0x1f, 0x67, 0x08, 0x67, 0x3e, 0xa5, 0xc2, 0xac, 0x36, + 0x4d, 0xcb, 0x31, 0xe4, 0x3f, 0xe6, 0x52, 0x83, 0x55, 0x38, 0x75, 0x9f, 0x50, 0xd7, 0xf8, 0x68, + 0x9b, 0xba, 0xed, 0x7c, 0xcb, 0x65, 0x82, 0x91, 0xe3, 0x1d, 0xc3, 0x7c, 0x60, 0x98, 0x0f, 0x0c, + 0x73, 0xcb, 0x55, 0xc6, 0xb7, 0x18, 0x37, 0x2a, 0x26, 0xa7, 0xbe, 0x97, 0xf1, 0xe4, 0x42, 0x85, + 0x0a, 0xf3, 0x82, 0xd1, 0x32, 0x1b, 0x96, 0x63, 0x0a, 0x8b, 0x39, 0x7e, 0xa0, 0xdc, 0x4c, 0x83, + 0x35, 0x98, 0xfc, 0x6b, 0x78, 0xff, 0xb0, 0xf5, 0x44, 0x83, 0xb1, 0x86, 0x4d, 0x0d, 0xb3, 0x65, + 0x19, 0xa6, 0xe3, 0x30, 0x21, 0x5d, 0x38, 0xde, 0x5d, 0xca, 0x42, 0x59, 0x31, 0x6d, 0x9b, 0x09, + 0xb4, 0xcc, 0xe4, 0x53, 0xb1, 0xcd, 0x2d, 0x8a, 0x86, 0xf9, 0x2c, 0x43, 0xd9, 0x5e, 0x76, 0x98, + 0x53, 0xa5, 0x01, 0x84, 0xd5, 0x4c, 0x7b, 0x97, 0x71, 0xee, 0x3b, 0xd5, 0x6d, 0xb3, 0xa1, 0x04, + 0xfb, 0x31, 0x6d, 0x37, 0xa8, 0xa3, 0x82, 0xc6, 0x61, 0x35, 0x5a, 0x36, 0xab, 0x55, 0xb6, 0xed, + 0x04, 0x34, 0x97, 0xb3, 0xec, 0x83, 0x3f, 0x2a, 0x28, 0x5a, 0xa6, 0x6b, 0x6e, 0x05, 0x78, 0xcf, + 0x67, 0x5a, 0x52, 0xa7, 0x66, 0x39, 0x8d, 0x68, 0x56, 0x4e, 0x67, 0x79, 0x08, 0xce, 0x33, 0xe0, + 0xb6, 0x1e, 0x37, 0xfc, 0x3c, 0x73, 0xfc, 0xe9, 0x63, 0xdb, 0x72, 0x19, 0xab, 0x73, 0xfc, 0x41, + 0xdb, 0x4b, 0x7d, 0xba, 0x2f, 0xd7, 0xb7, 0x9d, 0x1a, 0x2f, 0x6f, 0x59, 0x0d, 0xd7, 0x14, 0x0c, + 0x13, 0xa2, 0x9f, 0x86, 0x85, 0x0f, 0xbc, 0x31, 0xfa, 0x90, 0xf3, 0x75, 0xef, 0xfe, 0xfb, 0x78, + 0xfb, 0x8e, 0x53, 0x67, 0x6b, 0xb6, 0x5d, 0xa4, 0x1f, 0x6d, 0x53, 0x2e, 0xf4, 0x9f, 0x6b, 0xb0, + 0x98, 0x6d, 0xc7, 0x5b, 0xcc, 0xe1, 0x94, 0xd4, 0xe1, 0x70, 0x6f, 0x5f, 0x7c, 0x56, 0x9b, 0x1f, + 0x5e, 0x1a, 0x5f, 0x3d, 0x9f, 0xcf, 0x98, 0x38, 0x79, 0x0c, 0x1d, 0x8e, 0x5c, 0x78, 0xe9, 0xab, + 0xff, 0x9c, 0x3c, 0x50, 0x9c, 0x16, 0xb1, 0x5e, 0xb9, 0x7e, 0x03, 0xe6, 0x53, 0xf1, 0x20, 0x68, + 0xf2, 0x2a, 0x8c, 0xfa, 0xe3, 0xd0, 0xaa, 0xcd, 0x6a, 0xf3, 0xda, 0xd2, 0x70, 0xf1, 0x15, 0x79, + 0x7d, 0xa7, 0xa6, 0xff, 0x4c, 0x83, 0x53, 0x19, 0xfe, 0x48, 0xa6, 0x06, 0xa4, 0x97, 0x8c, 0x0c, + 0xb5, 0x77, 0x2e, 0x53, 0x71, 0x2e, 0xfa, 0x2a, 0xe4, 0x24, 0x94, 0x0d, 0x2a, 0x6e, 0x7b, 0xe1, + 0xee, 0xc9, 0x41, 0x15, 0x90, 0x98, 0x81, 0x97, 0x2d, 0xa7, 0x46, 0x3f, 0x91, 0xdd, 0x8e, 0x15, + 0xfd, 0x0b, 0x9d, 0xc1, 0xf1, 0x44, 0x1f, 0x04, 0xfe, 0x00, 0xc6, 0x43, 0xcd, 0x88, 0x78, 0x29, + 0x13, 0x71, 0xc8, 0x1e, 0x91, 0x86, 0x43, 0xe8, 0x35, 0x04, 0xb9, 0x66, 0xdb, 0x09, 0x20, 0xd7, + 0x01, 0xba, 0xb5, 0x0d, 0xbb, 0x7b, 0x3d, 0xef, 0x17, 0xc2, 0xbc, 0x57, 0x08, 0xf3, 0x7e, 0xf9, + 0xc4, 0x42, 0x98, 0x7f, 0x60, 0x36, 0x28, 0xfa, 0x16, 0x43, 0x9e, 0xfa, 0x9f, 0x34, 0xe4, 0x15, + 0xef, 0x26, 0x8d, 0xd7, 0xf0, 0x0b, 0xf2, 0x22, 0x1b, 0x11, 0xe4, 0x43, 0x12, 0xf9, 0x99, 0xbe, + 0xc8, 0x7d, 0x38, 0x11, 0xe8, 0x75, 0x38, 0x11, 0x20, 0x7f, 0xe0, 0x57, 0x87, 0x6f, 0x26, 0x45, + 0x5f, 0x6a, 0xf0, 0x5a, 0x4a, 0x47, 0x98, 0xa4, 0x0f, 0x61, 0x22, 0x5a, 0x9f, 0x30, 0x4f, 0xcb, + 0x99, 0x79, 0x8a, 0xc4, 0xc2, 0x4c, 0x1d, 0x6a, 0x85, 0x1b, 0xf7, 0x2f, 0x57, 0xc1, 0xe4, 0x8d, + 0xf6, 0xd9, 0x96, 0xcf, 0x45, 0x61, 0xf2, 0xfe, 0x18, 0xe7, 0x6e, 0xb2, 0x7b, 0x46, 0x16, 0xb4, + 0x7d, 0xc8, 0x82, 0x3e, 0x03, 0x24, 0x98, 0x7a, 0x0f, 0x4b, 0xa5, 0xa0, 0x40, 0xde, 0x87, 0xc3, + 0x91, 0x56, 0x44, 0x71, 0x05, 0x86, 0x1f, 0x96, 0x4a, 0xd8, 0xf5, 0x7c, 0x76, 0xc9, 0x28, 0x95, + 0xb0, 0x43, 0xcf, 0x45, 0x7f, 0x07, 0x5e, 0xed, 0x04, 0xe4, 0x7c, 0xad, 0x56, 0x73, 0x29, 0xef, + 0x0c, 0xa6, 0x25, 0x98, 0xaa, 0x58, 0xa2, 0xca, 0x2c, 0xa7, 0xdc, 0x49, 0xd2, 0x90, 0x4c, 0xd2, + 0x04, 0xb6, 0xdf, 0xc6, 0x5c, 0xdd, 0xea, 0x16, 0x97, 0x70, 0x18, 0x84, 0x37, 0x05, 0xc3, 0x54, + 0x34, 0xb1, 0xb4, 0x78, 0x7f, 0xbd, 0x96, 0x8a, 0xa8, 0xca, 0x60, 0x63, 0x45, 0xef, 0xaf, 0xfe, + 0x99, 0x06, 0xcb, 0xbd, 0x21, 0x0a, 0xed, 0x75, 0xcb, 0x31, 0x6d, 0xeb, 0x53, 0x5a, 0xdb, 0xa4, + 0x56, 0xa3, 0x29, 0x02, 0x68, 0xab, 0x70, 0xa4, 0x1e, 0xdc, 0x29, 0x7b, 0x2c, 0xcb, 0x4d, 0x79, + 0x1f, 0x1f, 0xe2, 0xe1, 0xce, 0xcd, 0x47, 0x54, 0x98, 0xbe, 0xeb, 0x00, 0x74, 0x3e, 0x80, 0x37, + 0x94, 0xb0, 0x0c, 0xc0, 0xef, 0x87, 0x70, 0x34, 0x58, 0x09, 0x36, 0x2d, 0x2e, 0x98, 0xdb, 0xde, + 0xef, 0x29, 0xfb, 0x5b, 0x0d, 0x8e, 0xf5, 0x74, 0x81, 0x08, 0xd7, 0x60, 0xd4, 0x5b, 0x62, 0x6c, + 0x8b, 0x0b, 0x9c, 0xa6, 0xaa, 0xa3, 0xe4, 0x15, 0xc1, 0xf9, 0x7b, 0x16, 0x17, 0xfb, 0x37, 0x2d, + 0x9b, 0x30, 0x23, 0x61, 0x6e, 0x9a, 0xfc, 0xbb, 0x4c, 0xd0, 0x5a, 0x90, 0x87, 0x37, 0x60, 0xda, + 0xd7, 0x95, 0x65, 0xab, 0x46, 0x1d, 0x61, 0xd5, 0x2d, 0xea, 0x62, 0x4e, 0xa7, 0xfc, 0x1b, 0x77, + 0x3a, 0xed, 0x64, 0x01, 0x0e, 0x3d, 0x61, 0x82, 0xba, 0x65, 0xd3, 0x7f, 0x38, 0x98, 0xea, 0x83, + 0xb2, 0x11, 0x1f, 0x98, 0x7e, 0x09, 0x8e, 0xc4, 0x7a, 0xc2, 0x74, 0x1c, 0x87, 0xb1, 0xa6, 0xc9, + 0xcb, 0x9e, 0xb1, 0x3f, 0xed, 0x47, 0x8b, 0xa3, 0x4d, 0x34, 0xd2, 0xdf, 0x87, 0x39, 0xe9, 0x55, + 0x90, 0x7d, 0x16, 0xda, 0xdd, 0x5e, 0xf7, 0x82, 0x54, 0x17, 0x30, 0xe6, 0xc5, 0x75, 0x65, 0x12, + 0x7b, 0x60, 0x6b, 0xbd, 0xb0, 0x49, 0x01, 0xc6, 0xbc, 0xeb, 0xb2, 0x68, 0xb7, 0xa8, 0xe4, 0x35, + 0xb1, 0x7a, 0x3a, 0xf3, 0x69, 0x79, 0xf1, 0x1f, 0xb6, 0x5b, 0xb4, 0x38, 0xfa, 0x04, 0xff, 0xe9, + 0x7f, 0x1c, 0x82, 0x93, 0xa9, 0x2c, 0x30, 0x0b, 0x03, 0x25, 0xfc, 0x6d, 0x18, 0x91, 0x20, 0xbd, + 0x4c, 0x0f, 0xcb, 0x11, 0xda, 0x0f, 0x91, 0x64, 0x5c, 0x44, 0x2f, 0xf2, 0x21, 0x4c, 0xf9, 0x77, + 0xe5, 0x20, 0xf0, 0xb9, 0x0d, 0x4b, 0x6e, 0x2b, 0x99, 0x91, 0xee, 0x77, 0x9d, 0x24, 0xc5, 0x49, + 0x16, 0x6d, 0x20, 0xf7, 0xe0, 0x10, 0xb2, 0xe0, 0xc2, 0x14, 0xdb, 0x7c, 0xf6, 0x25, 0x19, 0xf5, + 0x6c, 0x66, 0x54, 0x3f, 0x2b, 0x25, 0xe9, 0x50, 0x3c, 0x58, 0x09, 0x5d, 0xe9, 0x04, 0xa6, 0x64, + 0xe2, 0xee, 0xa3, 0x6d, 0x89, 0x0a, 0xfd, 0x0a, 0xcc, 0xc6, 0xdb, 0x3a, 0x59, 0x3c, 0x01, 0x63, + 0x41, 0x58, 0x7f, 0x09, 0x1c, 0x2b, 0x76, 0x1b, 0xf4, 0xa3, 0x38, 0xd8, 0x4b, 0xdb, 0xad, 0x16, + 0x73, 0x05, 0xad, 0xc9, 0x12, 0xc3, 0xf5, 0x0a, 0xae, 0xe3, 0xb1, 0xf6, 0x4e, 0xd4, 0x02, 0x8c, + 0xf8, 0x12, 0x1d, 0xa7, 0xeb, 0x62, 0x12, 0x9d, 0xd6, 0xe3, 0x46, 0x1e, 0x85, 0xbc, 0x74, 0xc7, + 0x29, 0x8b, 0x9e, 0xfa, 0x4d, 0xd0, 0x23, 0xea, 0xed, 0x81, 0x7c, 0xf1, 0x58, 0x67, 0xae, 0xea, + 0x0a, 0xe8, 0xa2, 0x6a, 0x4f, 0x0b, 0x80, 0x58, 0xdf, 0x85, 0x83, 0x7e, 0x04, 0xff, 0xcd, 0x46, + 0x5d, 0x07, 0xfa, 0xf1, 0x8a, 0xe3, 0xd5, 0xee, 0x85, 0x7e, 0x22, 0x26, 0x53, 0xd1, 0x06, 0xd7, + 0x3f, 0x27, 0x26, 0x48, 0x83, 0xbb, 0x88, 0xe4, 0x7e, 0x22, 0x92, 0x15, 0x55, 0x24, 0x72, 0xc0, + 0x46, 0xd0, 0x84, 0x44, 0xf3, 0x3d, 0x56, 0xa3, 0x6b, 0xfe, 0x1b, 0x61, 0xb6, 0x68, 0xfe, 0x51, + 0x17, 0x63, 0xc4, 0xa7, 0x9b, 0xad, 0xf0, 0xdb, 0xa5, 0x52, 0xb6, 0xc2, 0x71, 0xc6, 0x9d, 0xee, + 0x45, 0x58, 0x2f, 0x27, 0xe0, 0xdb, 0xaf, 0x95, 0xe5, 0x8b, 0x90, 0x5e, 0x4e, 0xa2, 0x74, 0x17, + 0xc6, 0x43, 0xcd, 0x4a, 0x7a, 0x39, 0xc2, 0x28, 0x74, 0xb1, 0x7f, 0xcb, 0xcc, 0x3c, 0x96, 0x71, + 0x6f, 0xa8, 0x74, 0xf6, 0x0a, 0xd6, 0x6d, 0xb3, 0xd1, 0x19, 0x4c, 0x3f, 0xd1, 0xb0, 0x46, 0x26, + 0x99, 0x20, 0xb5, 0xef, 0xc3, 0x54, 0x7c, 0xa7, 0x41, 0x6d, 0x54, 0x45, 0xe3, 0xe1, 0xcc, 0x9c, + 0xac, 0x46, 0x9b, 0xf5, 0x63, 0xb8, 0x42, 0x6d, 0x50, 0xf1, 0xae, 0xdc, 0x9c, 0x08, 0xb0, 0x7d, + 0x07, 0xe5, 0x42, 0xe8, 0x06, 0x22, 0xba, 0x0e, 0x23, 0xfe, 0x3e, 0x06, 0xe2, 0x58, 0xc8, 0xc4, + 0x81, 0xce, 0xe8, 0xa2, 0x9f, 0x44, 0x55, 0x5f, 0x6a, 0xb2, 0x8f, 0x83, 0x62, 0x76, 0x3b, 0x34, + 0x64, 0xbc, 0x9c, 0xcc, 0xa5, 0x59, 0x20, 0x80, 0x1f, 0xc0, 0x61, 0xdb, 0xe4, 0xa2, 0x1c, 0xf4, + 0x51, 0x0e, 0x8f, 0xe3, 0x7c, 0x26, 0x9a, 0xf7, 0x4c, 0x2e, 0xa2, 0x41, 0xa7, 0xed, 0x78, 0x93, + 0x7e, 0x17, 0x31, 0x16, 0x6c, 0x73, 0x8b, 0x26, 0x2d, 0xbf, 0x67, 0x61, 0x4a, 0x6e, 0x2b, 0xf5, + 0x2e, 0x5b, 0x93, 0xb2, 0x3d, 0xb4, 0xf8, 0x56, 0x83, 0xb5, 0xbc, 0x37, 0x56, 0x47, 0x19, 0x01, + 0x06, 0x73, 0xea, 0x0c, 0x49, 0xe8, 0xd9, 0x6b, 0x87, 0x67, 0x5e, 0x1c, 0xf3, 0xbb, 0x72, 0xea, + 0x4c, 0xa7, 0xdd, 0xd9, 0xe1, 0xdf, 0xa3, 0x55, 0xe6, 0xd6, 0xf6, 0xfd, 0x95, 0xec, 0xf7, 0x5a, + 0xf7, 0xdd, 0x2f, 0xda, 0x0f, 0x52, 0xd9, 0x88, 0x51, 0x19, 0x56, 0xa3, 0x82, 0x63, 0xb3, 0x4b, + 0x68, 0xff, 0xe6, 0x60, 0x09, 0xdf, 0xc0, 0x30, 0xfd, 0xb2, 0xd4, 0xae, 0x39, 0x35, 0xf9, 0x8a, + 0xd3, 0x7f, 0xfd, 0xf1, 0xea, 0xab, 0x7c, 0xa9, 0x42, 0x95, 0xee, 0x5f, 0xe8, 0x75, 0x7c, 0x2f, + 0x4b, 0x0e, 0x9a, 0xf2, 0x58, 0x87, 0x07, 0x7e, 0xac, 0xab, 0x9f, 0x2f, 0xc2, 0xcb, 0xb2, 0x23, + 0xf2, 0x17, 0x0d, 0x46, 0x03, 0x0d, 0x49, 0x2e, 0x64, 0x46, 0x49, 0x52, 0xb6, 0xb9, 0xd5, 0x41, + 0x5c, 0x7c, 0x02, 0xfa, 0xdd, 0x9f, 0xfe, 0xe3, 0x7f, 0xbf, 0x1c, 0xfa, 0x36, 0x29, 0xc8, 0x6d, + 0xb6, 0x73, 0xfe, 0x8e, 0x5b, 0x67, 0xa3, 0xad, 0xa3, 0x5e, 0x8d, 0x9d, 0x1e, 0x09, 0xb7, 0x6b, + 0xec, 0x44, 0x34, 0xe6, 0x2e, 0xf9, 0x97, 0x06, 0xa4, 0x57, 0x07, 0x92, 0xeb, 0xfd, 0x61, 0xa5, + 0x6a, 0xe0, 0xdc, 0x5b, 0x7b, 0x73, 0x46, 0x76, 0xef, 0x48, 0x76, 0x37, 0xc9, 0x8d, 0x44, 0x76, + 0x48, 0xa9, 0xd2, 0x0e, 0xb1, 0x4a, 0x22, 0x4a, 0x7e, 0xa3, 0xc1, 0x78, 0x48, 0x93, 0x91, 0x73, + 0xfd, 0x41, 0x85, 0xcc, 0x73, 0x6f, 0x0e, 0x64, 0xde, 0x01, 0x7f, 0x56, 0x82, 0x5f, 0x20, 0xa7, + 0x12, 0xc1, 0x77, 0xca, 0x22, 0xa7, 0x82, 0xfc, 0x4e, 0x83, 0xc9, 0x98, 0xc4, 0x53, 0x19, 0x40, + 0x31, 0x97, 0xdc, 0xd5, 0x81, 0x5d, 0x3a, 0x60, 0x57, 0x24, 0xd8, 0xd7, 0xc9, 0x62, 0x22, 0x58, + 0x1e, 0xc3, 0xf6, 0x5f, 0x0d, 0x8e, 0x26, 0xab, 0x3d, 0x72, 0xb3, 0x3f, 0x86, 0x4c, 0xa1, 0x99, + 0xbb, 0xb5, 0xf7, 0x00, 0xc8, 0xa5, 0x20, 0xb9, 0xbc, 0x45, 0xae, 0x25, 0x72, 0x69, 0x50, 0x51, + 0x0e, 0xab, 0xbf, 0x72, 0x9d, 0xb9, 0x7e, 0x83, 0xb1, 0x13, 0x54, 0x98, 0x5d, 0xf2, 0x85, 0x06, + 0x13, 0xd1, 0x6e, 0xc8, 0xe5, 0x41, 0x81, 0x05, 0x8c, 0xae, 0x0c, 0xee, 0x88, 0x4c, 0xce, 0x49, + 0x26, 0x67, 0xc8, 0x69, 0x25, 0x26, 0x1e, 0xe8, 0x88, 0x48, 0x52, 0x43, 0xdc, 0xab, 0x08, 0x15, + 0x11, 0x27, 0x68, 0x3c, 0xfd, 0xbc, 0x44, 0xbc, 0x4c, 0x96, 0x12, 0x11, 0x87, 0x34, 0xa9, 0xb1, + 0x23, 0x65, 0xf0, 0xae, 0x37, 0xf6, 0x27, 0x42, 0x91, 0xd6, 0x6c, 0x5b, 0x05, 0x77, 0xa2, 0x92, + 0x55, 0xc1, 0x9d, 0xac, 0x4d, 0xf5, 0x25, 0x89, 0x5b, 0x27, 0xf3, 0xfd, 0x70, 0x93, 0x3f, 0x6b, + 0x30, 0x19, 0x93, 0x6d, 0x2a, 0x25, 0x32, 0x55, 0x5f, 0xaa, 0x94, 0xc8, 0x74, 0xe5, 0xd9, 0x67, + 0x88, 0xc4, 0x45, 0x29, 0xf9, 0x95, 0x06, 0x23, 0xbe, 0xd8, 0x23, 0xab, 0x4a, 0xfd, 0x46, 0xf4, + 0x66, 0xee, 0xe2, 0x40, 0x3e, 0x08, 0x71, 0x41, 0x42, 0x7c, 0x8d, 0x1c, 0x4f, 0x84, 0xe8, 0x4b, + 0x4e, 0xf2, 0x57, 0x0d, 0xa6, 0x7b, 0xc4, 0x24, 0xb9, 0xa6, 0x50, 0xd1, 0x52, 0x34, 0x6a, 0xee, + 0xfa, 0x9e, 0x7c, 0x11, 0xf3, 0x55, 0x89, 0xf9, 0x22, 0xb9, 0x10, 0xc6, 0xdc, 0x7b, 0x92, 0xc5, + 0x9b, 0xec, 0xe3, 0x98, 0xc2, 0x25, 0x7f, 0xd7, 0x60, 0xba, 0x47, 0x48, 0xaa, 0x30, 0x49, 0x53, + 0xb2, 0x2a, 0x4c, 0x52, 0x95, 0xab, 0x7e, 0x5b, 0x32, 0xb9, 0x41, 0xae, 0x27, 0xaf, 0xa1, 0x52, + 0xfd, 0xc4, 0x97, 0xd0, 0x98, 0x6c, 0xde, 0xf5, 0xa4, 0x0d, 0xd9, 0xa0, 0x22, 0x26, 0x29, 0x89, + 0xda, 0x7c, 0x4b, 0x50, 0xbb, 0x2a, 0x4b, 0x55, 0x8a, 0x7e, 0xd5, 0x57, 0x25, 0xa1, 0x15, 0xb2, + 0x9c, 0x5a, 0x14, 0x4d, 0xdb, 0x2e, 0xfb, 0x1c, 0x5c, 0x04, 0xfa, 0x54, 0x83, 0x23, 0x32, 0x18, + 0x8f, 0x29, 0x41, 0x72, 0x43, 0x39, 0xb7, 0x49, 0xb2, 0x34, 0xf7, 0xf6, 0x5e, 0xdd, 0x91, 0xcc, + 0xa6, 0x24, 0x53, 0x20, 0xb7, 0xb2, 0x9f, 0x8e, 0x3f, 0x85, 0x4d, 0xa7, 0xe6, 0x1f, 0x1f, 0x84, + 0x56, 0x2a, 0x63, 0x47, 0xb6, 0xec, 0x92, 0x2f, 0x35, 0x38, 0x14, 0xd9, 0x88, 0x26, 0xdf, 0x52, + 0x9a, 0xac, 0x3d, 0xfb, 0xf9, 0xb9, 0xcb, 0x03, 0xfb, 0x21, 0x99, 0x9b, 0x92, 0xcc, 0x55, 0x72, + 0x39, 0xf5, 0xc9, 0x08, 0xce, 0x03, 0xbd, 0x69, 0xec, 0xc4, 0x77, 0xd9, 0x77, 0xc9, 0xaf, 0x87, + 0x60, 0x2e, 0x7b, 0x33, 0x9d, 0x6c, 0x0c, 0x08, 0x2e, 0xed, 0x68, 0x20, 0xb7, 0xf9, 0xe2, 0x81, + 0x90, 0x76, 0x45, 0xd2, 0xfe, 0x1e, 0x79, 0xa4, 0x42, 0xbb, 0xdc, 0x94, 0x7b, 0xee, 0x56, 0xd5, + 0xb4, 0x8d, 0x9d, 0xc4, 0xb3, 0x89, 0xdd, 0xa4, 0xcc, 0x7c, 0xa6, 0xc9, 0xb3, 0x1b, 0x62, 0xa8, + 0xa1, 0xee, 0x1c, 0x05, 0xe5, 0xce, 0xab, 0x3b, 0x20, 0x9d, 0x79, 0x49, 0x27, 0x47, 0x66, 0x13, + 0xe9, 0x78, 0x20, 0x3e, 0xd7, 0x00, 0xba, 0xa7, 0x07, 0x44, 0x61, 0x51, 0xe8, 0x39, 0xce, 0xc8, + 0x5d, 0x1a, 0xcc, 0x09, 0xb1, 0x9d, 0x91, 0xd8, 0x4e, 0x91, 0x93, 0x89, 0xd8, 0x44, 0x17, 0xd3, + 0x1f, 0x34, 0x98, 0x8a, 0x1c, 0x9f, 0x79, 0xba, 0x42, 0xad, 0xe8, 0x24, 0x1d, 0x98, 0xe6, 0xae, + 0xed, 0xc5, 0x15, 0x41, 0x2f, 0x4b, 0xd0, 0x8b, 0x44, 0x4f, 0x04, 0x1d, 0x3d, 0xd5, 0xfc, 0x9b, + 0x06, 0x33, 0x49, 0x27, 0x89, 0x2a, 0x75, 0x2a, 0xe3, 0x00, 0x53, 0xa5, 0x4e, 0x65, 0x1d, 0x60, + 0xea, 0x6f, 0x4a, 0x0e, 0x06, 0x39, 0xd7, 0x9f, 0x43, 0x4c, 0x46, 0x47, 0x0e, 0xb8, 0x07, 0xd0, + 0xd0, 0xd1, 0xfc, 0x5f, 0x19, 0xdc, 0x51, 0x49, 0x91, 0x56, 0xbb, 0x1e, 0x11, 0x45, 0x1a, 0x8a, + 0xa4, 0xae, 0x48, 0xf7, 0x86, 0x3b, 0xf9, 0xeb, 0x82, 0x3e, 0x8a, 0x34, 0x84, 0xdb, 0x93, 0x4e, + 0x33, 0x49, 0x5f, 0x8e, 0xa8, 0x8c, 0x99, 0x8c, 0x2f, 0x56, 0x54, 0xc6, 0x4c, 0xd6, 0x07, 0x2b, + 0x7d, 0x32, 0xdf, 0x90, 0xc5, 0x35, 0xe2, 0x4d, 0xfe, 0xa9, 0xc1, 0xb1, 0x94, 0x6f, 0x7a, 0xc8, + 0xad, 0xbd, 0xa1, 0xe9, 0x7e, 0x36, 0x94, 0x5b, 0x7b, 0x81, 0x08, 0x48, 0xe9, 0x92, 0xa4, 0x94, + 0x27, 0x2b, 0x69, 0x94, 0xd6, 0x6c, 0x3b, 0x1e, 0x83, 0x17, 0xee, 0x7c, 0xf5, 0x6c, 0x4e, 0xfb, + 0xfa, 0xd9, 0x9c, 0xf6, 0xf4, 0xd9, 0x9c, 0xf6, 0x8b, 0xe7, 0x73, 0x07, 0xbe, 0x7e, 0x3e, 0x77, + 0xe0, 0xdf, 0xcf, 0xe7, 0x0e, 0x3c, 0x32, 0x1a, 0x96, 0x68, 0x6e, 0x57, 0xf2, 0x55, 0xb6, 0x95, + 0x28, 0x34, 0x3f, 0x09, 0x15, 0xb7, 0x76, 0x8b, 0xf2, 0xca, 0x88, 0xfc, 0x50, 0xea, 0xe2, 0xff, + 0x03, 0x00, 0x00, 0xff, 0xff, 0x7d, 0x2a, 0xd9, 0xa1, 0x1e, 0x28, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -8220,7 +8220,7 @@ func (m *QuerySupportedChainsResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Chains = append(m.Chains, &chains.Chain{}) + m.Chains = append(m.Chains, chains.Chain{}) if err := m.Chains[len(m.Chains)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/zetaclient/chains/base/signer.go b/zetaclient/chains/base/signer.go index 0fc9ca4837..2ac38e048d 100644 --- a/zetaclient/chains/base/signer.go +++ b/zetaclient/chains/base/signer.go @@ -34,14 +34,14 @@ type Signer struct { // NewSigner creates a new base signer func NewSigner( chain chains.Chain, - zetacoreContext *context.AppContext, + appContext *context.AppContext, tss interfaces.TSSSigner, ts *metrics.TelemetryServer, logger Logger, ) *Signer { return &Signer{ chain: chain, - appContext: zetacoreContext, + appContext: appContext, tss: tss, ts: ts, logger: Logger{ diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index 20823f533b..889d2215ac 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -642,8 +642,11 @@ func (ob *Observer) BuildInboundVoteMsgForDepositedEvent( func (ob *Observer) BuildInboundVoteMsgForZetaSentEvent( event *zetaconnector.ZetaConnectorNonEthZetaSent, ) *types.MsgVoteInbound { - destChain := chains.GetChainFromChainID(event.DestinationChainId.Int64()) - if destChain == nil { + destChain, found := chains.GetChainFromChainID( + event.DestinationChainId.Int64(), + ob.AppContext().GetAdditionalChains(), + ) + if !found { ob.Logger().Inbound.Warn().Msgf("chain id not supported %d", event.DestinationChainId.Int64()) return nil } @@ -667,7 +670,7 @@ func (ob *Observer) BuildInboundVoteMsgForZetaSentEvent( if strings.EqualFold(destAddr, paramsDest.ZetaTokenContractAddress) { ob.Logger().Inbound.Warn(). - Msgf("potential attack attempt: %s destination address is ZETA token contract address %s", destChain, destAddr) + Msgf("potential attack attempt: %s destination address is ZETA token contract address %s", destChain.String(), destAddr) return nil } } diff --git a/zetaclient/chains/evm/observer/observer_test.go b/zetaclient/chains/evm/observer/observer_test.go index 6cb97dd65d..e38ff877a1 100644 --- a/zetaclient/chains/evm/observer/observer_test.go +++ b/zetaclient/chains/evm/observer/observer_test.go @@ -63,6 +63,7 @@ func getZetacoreContext( nil, "", *sample.CrosschainFlags(), + []chains.Chain{}, sample.HeaderSupportedChains(), true, ) diff --git a/zetaclient/chains/evm/signer/outbound_data.go b/zetaclient/chains/evm/signer/outbound_data.go index 070c73597e..3e84fa83db 100644 --- a/zetaclient/chains/evm/signer/outbound_data.go +++ b/zetaclient/chains/evm/signer/outbound_data.go @@ -16,6 +16,7 @@ import ( "github.com/zeta-chain/zetacore/x/crosschain/types" "github.com/zeta-chain/zetacore/zetaclient/chains/evm/observer" "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" + clientcontext "github.com/zeta-chain/zetacore/zetaclient/context" ) const ( @@ -69,7 +70,7 @@ func (txData *OutboundData) SetupGas( cctx *types.CrossChainTx, logger zerolog.Logger, client interfaces.EVMRPCClient, - chain *chains.Chain, + chain chains.Chain, ) error { txData.gasLimit = cctx.GetCurrentOutboundParam().GasLimit if txData.gasLimit < MinGasLimit { @@ -89,10 +90,10 @@ func (txData *OutboundData) SetupGas( // we should possibly remove it completely and return an error if no GasPrice is provided because it means no fee is processed on ZetaChain specified, ok := new(big.Int).SetString(cctx.GetCurrentOutboundParam().GasPrice, 10) if !ok { - if chains.IsEthereumChain(chain.ChainId) { + if chain.Network == chains.Network_eth { suggested, err := client.SuggestGasPrice(context.Background()) if err != nil { - return errors.Join(err, fmt.Errorf("cannot get gas price from chain %s ", chain)) + return errors.Join(err, fmt.Errorf("cannot get gas price from chain %s ", chain.String())) } txData.gasPrice = roundUpToNearestGwei(suggested) } else { @@ -111,6 +112,7 @@ func (txData *OutboundData) SetupGas( // cctx will be skipped and false otherwise. // 3. error func NewOutboundData( + appontext *clientcontext.AppContext, cctx *types.CrossChainTx, evmObserver *observer.Observer, evmRPC interfaces.EVMRPCClient, @@ -132,8 +134,8 @@ func NewOutboundData( return nil, true, nil } - toChain := chains.GetChainFromChainID(txData.toChainID.Int64()) - if toChain == nil { + toChain, found := chains.GetChainFromChainID(txData.toChainID.Int64(), appontext.GetAdditionalChains()) + if !found { return nil, true, fmt.Errorf("unknown chain: %d", txData.toChainID.Int64()) } @@ -156,7 +158,7 @@ func NewOutboundData( // Get sendHash logger.Info(). - Msgf("chain %s minting %d to %s, nonce %d, finalized zeta bn %d", toChain, cctx.InboundParams.Amount, txData.to.Hex(), nonce, cctx.InboundParams.FinalizedZetaHeight) + Msgf("chain %s minting %d to %s, nonce %d, finalized zeta bn %d", toChain.String(), cctx.InboundParams.Amount, txData.to.Hex(), nonce, cctx.InboundParams.FinalizedZetaHeight) cctxIndex, err := hex.DecodeString(cctx.Index[2:]) // remove the leading 0x if err != nil || len(cctxIndex) != 32 { return nil, true, fmt.Errorf("decode CCTX %s error", cctx.Index) diff --git a/zetaclient/chains/evm/signer/outbound_data_test.go b/zetaclient/chains/evm/signer/outbound_data_test.go index d7df5a33d1..f5e3d39d3b 100644 --- a/zetaclient/chains/evm/signer/outbound_data_test.go +++ b/zetaclient/chains/evm/signer/outbound_data_test.go @@ -53,14 +53,14 @@ func TestSigner_SetupGas(t *testing.T) { t.Run("SetupGas_success", func(t *testing.T) { chain := chains.BscMainnet - err := txData.SetupGas(cctx, logger, evmSigner.EvmClient(), &chain) + err := txData.SetupGas(cctx, logger, evmSigner.EvmClient(), chain) require.NoError(t, err) }) t.Run("SetupGas_error", func(t *testing.T) { cctx.GetCurrentOutboundParam().GasPrice = "invalidGasPrice" chain := chains.BscMainnet - err := txData.SetupGas(cctx, logger, evmSigner.EvmClient(), &chain) + err := txData.SetupGas(cctx, logger, evmSigner.EvmClient(), chain) require.ErrorContains(t, err, "cannot convert gas price") }) } @@ -75,7 +75,14 @@ func TestSigner_NewOutboundData(t *testing.T) { t.Run("NewOutboundData success", func(t *testing.T) { cctx := getCCTX(t) - _, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + _, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) }) @@ -83,7 +90,14 @@ func TestSigner_NewOutboundData(t *testing.T) { t.Run("NewOutboundData skip", func(t *testing.T) { cctx := getCCTX(t) cctx.CctxStatus.Status = types.CctxStatus_Aborted - _, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + _, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.NoError(t, err) require.True(t, skip) }) @@ -91,7 +105,14 @@ func TestSigner_NewOutboundData(t *testing.T) { t.Run("NewOutboundData unknown chain", func(t *testing.T) { cctx := getInvalidCCTX(t) require.NoError(t, err) - _, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + _, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.ErrorContains(t, err, "unknown chain") require.True(t, skip) }) @@ -100,7 +121,14 @@ func TestSigner_NewOutboundData(t *testing.T) { cctx := getCCTX(t) require.NoError(t, err) cctx.GetCurrentOutboundParam().GasPrice = "invalidGasPrice" - _, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + _, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.True(t, skip) require.ErrorContains(t, err, "cannot convert gas price") }) diff --git a/zetaclient/chains/evm/signer/signer.go b/zetaclient/chains/evm/signer/signer.go index 8bba72d777..db4a15c856 100644 --- a/zetaclient/chains/evm/signer/signer.go +++ b/zetaclient/chains/evm/signer/signer.go @@ -363,7 +363,7 @@ func (signer *Signer) TryProcessOutbound( } // Setup Transaction input - txData, skipTx, err := NewOutboundData(cctx, evmObserver, signer.client, logger, height) + txData, skipTx, err := NewOutboundData(signer.AppContext(), cctx, evmObserver, signer.client, logger, height) if err != nil { logger.Err(err).Msg("error setting up transaction input fields") return @@ -372,8 +372,14 @@ func (signer *Signer) TryProcessOutbound( return } - // Get destination chain for logging - toChain := chains.GetChainFromChainID(txData.toChainID.Int64()) + toChain, found := chains.GetChainFromChainID( + txData.toChainID.Int64(), + signer.AppContext().GetAdditionalChains(), + ) + if !found { + logger.Warn().Msgf("unknown chain: %d", txData.toChainID.Int64()) + return + } // Get cross-chain flags crossChainflags := signer.AppContext().GetCrossChainFlags() @@ -425,7 +431,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignWithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -434,7 +440,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignERC20WithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -443,7 +449,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignOutbound: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -459,7 +465,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignRevertTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, cctx.GetCurrentOutboundParam().TssNonce, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) txData.srcChainID = big.NewInt(cctx.OutboundParams[0].ReceiverChainId) @@ -469,7 +475,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignWithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -477,7 +483,7 @@ func (signer *Signer) TryProcessOutbound( case coin.CoinType_ERC20: logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -491,7 +497,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignRevertTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -507,7 +513,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignOutbound: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -521,7 +527,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "Key-sign success: %d => %s, nonce %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, ) @@ -539,45 +545,52 @@ func (signer *Signer) BroadcastOutbound( txData *OutboundData, ) { // Get destination chain for logging - toChain := chains.GetChainFromChainID(txData.toChainID.Int64()) + toChain, found := chains.GetChainFromChainID( + txData.toChainID.Int64(), + signer.AppContext().GetAdditionalChains(), + ) + if !found { + logger.Warn().Msgf("BroadcastOutbound: unknown chain %d", txData.toChainID.Int64()) + return + } + if tx == nil { logger.Warn().Msgf("BroadcastOutbound: no tx to broadcast %s", cctx.Index) + return } // broadcast transaction - if tx != nil { - outboundHash := tx.Hash().Hex() - - // try broacasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error - backOff := broadcastBackoff - for i := 0; i < broadcastRetries; i++ { - time.Sleep(backOff) - err := signer.Broadcast(tx) - if err != nil { - log.Warn(). - Err(err). - Msgf("BroadcastOutbound: error broadcasting tx %s on chain %d nonce %d retry %d signer %s", - outboundHash, toChain.ChainId, cctx.GetCurrentOutboundParam().TssNonce, i, myID) - retry, report := zetacore.HandleBroadcastError( - err, - strconv.FormatUint(cctx.GetCurrentOutboundParam().TssNonce, 10), - toChain.String(), - outboundHash, - ) - if report { - signer.reportToOutboundTracker(zetacoreClient, toChain.ChainId, tx.Nonce(), outboundHash, logger) - } - if !retry { - break - } - backOff *= 2 - continue + outboundHash := tx.Hash().Hex() + + // try broacasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error + backOff := broadcastBackoff + for i := 0; i < broadcastRetries; i++ { + time.Sleep(backOff) + err := signer.Broadcast(tx) + if err != nil { + log.Warn(). + Err(err). + Msgf("BroadcastOutbound: error broadcasting tx %s on chain %d nonce %d retry %d signer %s", + outboundHash, toChain.ChainId, cctx.GetCurrentOutboundParam().TssNonce, i, myID) + retry, report := zetacore.HandleBroadcastError( + err, + strconv.FormatUint(cctx.GetCurrentOutboundParam().TssNonce, 10), + toChain.String(), + outboundHash, + ) + if report { + signer.reportToOutboundTracker(zetacoreClient, toChain.ChainId, tx.Nonce(), outboundHash, logger) + } + if !retry { + break } - logger.Info().Msgf("BroadcastOutbound: broadcasted tx %s on chain %d nonce %d signer %s", - outboundHash, toChain.ChainId, cctx.GetCurrentOutboundParam().TssNonce, myID) - signer.reportToOutboundTracker(zetacoreClient, toChain.ChainId, tx.Nonce(), outboundHash, logger) - break // successful broadcast; no need to retry + backOff *= 2 + continue } + logger.Info().Msgf("BroadcastOutbound: broadcasted tx %s on chain %d nonce %d signer %s", + outboundHash, toChain.ChainId, cctx.GetCurrentOutboundParam().TssNonce, myID) + signer.reportToOutboundTracker(zetacoreClient, toChain.ChainId, tx.Nonce(), outboundHash, logger) + break // successful broadcast; no need to retry } } diff --git a/zetaclient/chains/evm/signer/signer_test.go b/zetaclient/chains/evm/signer/signer_test.go index 13aaac87b1..fd412b4bfd 100644 --- a/zetaclient/chains/evm/signer/signer_test.go +++ b/zetaclient/chains/evm/signer/signer_test.go @@ -180,7 +180,14 @@ func TestSigner_SignOutbound(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -214,7 +221,14 @@ func TestSigner_SignRevertTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -252,7 +266,14 @@ func TestSigner_SignCancelTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -290,7 +311,14 @@ func TestSigner_SignWithdrawTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -326,7 +354,14 @@ func TestSigner_SignCommandTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, nil) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -371,7 +406,14 @@ func TestSigner_SignERC20WithdrawTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -409,7 +451,14 @@ func TestSigner_BroadcastOutbound(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, nil) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -459,7 +508,14 @@ func TestSigner_SignWhitelistERC20Cmd(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -502,7 +558,14 @@ func TestSigner_SignMigrateTssFundsCmd(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) diff --git a/zetaclient/context/app.go b/zetaclient/context/app.go index c40e769492..4888443ea9 100644 --- a/zetaclient/context/app.go +++ b/zetaclient/context/app.go @@ -25,6 +25,10 @@ type AppContext struct { currentTssPubkey string crosschainFlags observertypes.CrosschainFlags + // additionalChains is a list of additional static chain information to use when searching from chain IDs + // it is stored in the protocol to dynamically support new chains without doing an upgrade + additionalChain []chains.Chain + // blockHeaderEnabledChains is used to store the list of chains that have block header verification enabled // All chains in this list will have Enabled flag set to true blockHeaderEnabledChains []lightclienttypes.HeaderSupportedChain @@ -173,12 +177,12 @@ func (a *AppContext) GetBTCChainParams() (chains.Chain, *observertypes.ChainPara return chains.Chain{}, nil, false } - chain := chains.GetChainFromChainID(a.bitcoinChainParams.ChainId) - if chain == nil { + chain, found := chains.GetChainFromChainID(a.bitcoinChainParams.ChainId, a.additionalChain) + if !found { return chains.Chain{}, nil, false } - return *chain, a.bitcoinChainParams, true + return chain, a.bitcoinChainParams, true } // GetCrossChainFlags returns crosschain flags @@ -189,6 +193,13 @@ func (a *AppContext) GetCrossChainFlags() observertypes.CrosschainFlags { return a.crosschainFlags } +// GetAdditionalChains returns additional chains +func (a *AppContext) GetAdditionalChains() []chains.Chain { + a.mu.RLock() + defer a.mu.RUnlock() + return a.additionalChain +} + // GetAllHeaderEnabledChains returns all verification flags func (a *AppContext) GetAllHeaderEnabledChains() []lightclienttypes.HeaderSupportedChain { a.mu.RLock() @@ -220,6 +231,7 @@ func (a *AppContext) Update( btcChainParams *observertypes.ChainParams, tssPubKey string, crosschainFlags observertypes.CrosschainFlags, + additionalChains []chains.Chain, blockHeaderEnabledChains []lightclienttypes.HeaderSupportedChain, init bool, ) { @@ -249,6 +261,7 @@ func (a *AppContext) Update( a.chainsEnabled = newChains a.crosschainFlags = crosschainFlags + a.additionalChain = additionalChains a.blockHeaderEnabledChains = blockHeaderEnabledChains // update chain params for bitcoin if it has config in file diff --git a/zetaclient/context/app_test.go b/zetaclient/context/app_test.go index 99b56c7d88..640e5d7386 100644 --- a/zetaclient/context/app_test.go +++ b/zetaclient/context/app_test.go @@ -165,6 +165,7 @@ func TestAppContextUpdate(t *testing.T) { btcChainParamsToUpdate, tssPubKeyToUpdate, *crosschainFlags, + []chains.Chain{}, verificationFlags, false, ) @@ -265,6 +266,7 @@ func TestAppContextUpdate(t *testing.T) { btcChainParamsToUpdate, tssPubKeyToUpdate, *crosschainFlags, + []chains.Chain{}, verificationFlags, false, ) @@ -409,6 +411,7 @@ func TestGetBTCChainAndConfig(t *testing.T) { &observertypes.ChainParams{ChainId: 123}, "", observertypes.CrosschainFlags{}, + []chains.Chain{}, nil, true, ) @@ -426,6 +429,7 @@ func TestGetBTCChainAndConfig(t *testing.T) { &observertypes.ChainParams{ChainId: chains.BitcoinMainnet.ChainId}, "", observertypes.CrosschainFlags{}, + []chains.Chain{}, nil, true, ) @@ -469,6 +473,7 @@ func TestGetBlockHeaderEnabledChains(t *testing.T) { &observertypes.ChainParams{ChainId: chains.BitcoinMainnet.ChainId}, "", observertypes.CrosschainFlags{}, + []chains.Chain{}, []lightclienttypes.HeaderSupportedChain{ {ChainId: 1, Enabled: true}, }, @@ -491,6 +496,39 @@ func TestGetBlockHeaderEnabledChains(t *testing.T) { assert.Empty(t, chain) } +func TestGetAdditionalChains(t *testing.T) { + // ARRANGE + // Given app config + appContext := context.New(config.New(), zerolog.Nop()) + + additionalChains := []chains.Chain{ + sample.Chain(1), + sample.Chain(2), + sample.Chain(3), + } + + // That was eventually updated + appContext.Update( + &observertypes.Keygen{}, + []chains.Chain{}, + nil, + &observertypes.ChainParams{}, + "", + observertypes.CrosschainFlags{}, + additionalChains, + []lightclienttypes.HeaderSupportedChain{ + {ChainId: 1, Enabled: true}, + }, + true, + ) + + // ACT + found := appContext.GetAdditionalChains() + + // ASSERT + assert.EqualValues(t, additionalChains, found) +} + func makeAppContext( evmChain chains.Chain, evmChainParams *observertypes.ChainParams, @@ -517,6 +555,7 @@ func makeAppContext( nil, "", ccFlags, + []chains.Chain{}, headerSupportedChains, true, ) diff --git a/zetaclient/orchestrator/orchestrator.go b/zetaclient/orchestrator/orchestrator.go index 348baac514..b233c9d582 100644 --- a/zetaclient/orchestrator/orchestrator.go +++ b/zetaclient/orchestrator/orchestrator.go @@ -135,7 +135,7 @@ func (oc *Orchestrator) GetUpdatedSigner( return nil, fmt.Errorf("signer not found for chainID %d", chainID) } // update EVM signer parameters only. BTC signer doesn't use chain parameters for now. - if chains.IsEVMChain(chainID) { + if chains.IsEVMChain(chainID, appContext.GetAdditionalChains()) { evmParams, found := appContext.GetEVMChainParams(chainID) if found { // update zeta connector and ERC20 custody addresses @@ -167,14 +167,14 @@ func (oc *Orchestrator) GetUpdatedChainObserver( } // update chain observer chain parameters curParams := observer.GetChainParams() - if chains.IsEVMChain(chainID) { + if chains.IsEVMChain(chainID, appContext.GetAdditionalChains()) { evmParams, found := appContext.GetEVMChainParams(chainID) if found && !observertypes.ChainParamsEqual(curParams, *evmParams) { observer.SetChainParams(*evmParams) oc.logger.Std.Info().Msgf( "updated chain params for chainID %d, new params: %v", chainID, *evmParams) } - } else if chains.IsBitcoinChain(chainID) { + } else if chains.IsBitcoinChain(chainID, appContext.GetAdditionalChains()) { _, btcParams, found := appContext.GetBTCChainParams() if found && !observertypes.ChainParamsEqual(curParams, *btcParams) { @@ -319,9 +319,9 @@ func (oc *Orchestrator) StartCctxScheduler(appContext *context.AppContext) { // #nosec G701 range is verified zetaHeight := uint64(bn) - if chains.IsEVMChain(c.ChainId) { + if chains.IsEVMChain(c.ChainId, appContext.GetAdditionalChains()) { oc.ScheduleCctxEVM(zetaHeight, c.ChainId, cctxList, ob, signer) - } else if chains.IsBitcoinChain(c.ChainId) { + } else if chains.IsBitcoinChain(c.ChainId, appContext.GetAdditionalChains()) { oc.ScheduleCctxBTC(zetaHeight, c.ChainId, cctxList, ob, signer) } else { oc.logger.Std.Error().Msgf("StartCctxScheduler: unsupported chain %d", c.ChainId) diff --git a/zetaclient/orchestrator/orchestrator_test.go b/zetaclient/orchestrator/orchestrator_test.go index 69930bdbcf..9eab334bfe 100644 --- a/zetaclient/orchestrator/orchestrator_test.go +++ b/zetaclient/orchestrator/orchestrator_test.go @@ -80,6 +80,7 @@ func CreateAppContext( btcChainParams, "", *ccFlags, + []chains.Chain{}, verificationFlags, true, ) diff --git a/zetaclient/supplychecker/zeta_supply_checker.go b/zetaclient/supplychecker/zeta_supply_checker.go index 4c16ffd203..3355d4ff5e 100644 --- a/zetaclient/supplychecker/zeta_supply_checker.go +++ b/zetaclient/supplychecker/zeta_supply_checker.go @@ -68,12 +68,15 @@ func NewZetaSupplyChecker( } for chainID := range zetaSupplyChecker.evmClient { - chain := chains.GetChainFromChainID(chainID) - if chain.IsExternalChain() && chains.IsEVMChain(chain.ChainId) && !chains.IsEthereumChain(chain.ChainId) { - zetaSupplyChecker.externalEvmChain = append(zetaSupplyChecker.externalEvmChain, *chain) + chain, found := chains.GetChainFromChainID(chainID, appContext.GetAdditionalChains()) + if !found { + return zetaSupplyChecker, fmt.Errorf("chain not found for chain id %d", chainID) } - if chains.IsEthereumChain(chain.ChainId) { - zetaSupplyChecker.ethereumChain = *chain + if chain.IsExternalChain() && chain.IsEVMChain() && + chain.Network != chains.Network_eth { + zetaSupplyChecker.externalEvmChain = append(zetaSupplyChecker.externalEvmChain, chain) + } else { + zetaSupplyChecker.ethereumChain = chain } } diff --git a/zetaclient/zetacore/client.go b/zetaclient/zetacore/client.go index 140520fe11..53d1d5958c 100644 --- a/zetaclient/zetacore/client.go +++ b/zetaclient/zetacore/client.go @@ -83,7 +83,7 @@ func NewClient( seqMap[keyType] = 0 } - zetaChain, err := chains.ZetaChainFromChainID(chainID) + zetaChain, err := chains.ZetaChainFromCosmosChainID(chainID) if err != nil { return nil, fmt.Errorf("invalid chain id %s, %w", chainID, err) } @@ -111,7 +111,7 @@ func (c *Client) UpdateChainID(chainID string) error { if c.chainID != chainID { c.chainID = chainID - zetaChain, err := chains.ZetaChainFromChainID(chainID) + zetaChain, err := chains.ZetaChainFromCosmosChainID(chainID) if err != nil { return fmt.Errorf("invalid chain id %s, %w", chainID, err) } @@ -210,6 +210,11 @@ func (c *Client) UpdateZetacoreContext(coreContext *context.AppContext, init boo c.pause <- struct{}{} // notify Orchestrator to stop Observers, Signers, and Orchestrator itself } + additionalChains, err := c.GetAdditionalChains() + if err != nil { + return fmt.Errorf("failed to additional chains: %w", err) + } + chainParams, err := c.GetChainParams() if err != nil { return fmt.Errorf("failed to get chain params: %w", err) @@ -225,9 +230,9 @@ func (c *Client) UpdateZetacoreContext(coreContext *context.AppContext, init boo sampledLogger.Warn().Err(err).Msgf("Invalid chain params for chain %d", chainParam.ChainId) continue } - if chains.IsBitcoinChain(chainParam.ChainId) { + if chains.IsBitcoinChain(chainParam.ChainId, additionalChains) { newBTCParams = chainParam - } else if chains.IsEVMChain(chainParam.ChainId) { + } else if chains.IsEVMChain(chainParam.ChainId, additionalChains) { newEVMParams[chainParam.ChainId] = chainParam } } @@ -238,7 +243,7 @@ func (c *Client) UpdateZetacoreContext(coreContext *context.AppContext, init boo } newChains := make([]chains.Chain, len(supportedChains)) for i, chain := range supportedChains { - newChains[i] = *chain + newChains[i] = chain } keyGen, err := c.GetKeyGen() if err != nil { @@ -272,6 +277,7 @@ func (c *Client) UpdateZetacoreContext(coreContext *context.AppContext, init boo newBTCParams, tssPubKey, crosschainFlags, + additionalChains, blockHeaderEnabledChains, init, ) diff --git a/zetaclient/zetacore/query.go b/zetaclient/zetacore/query.go index e90be274ff..52a9a8e5fc 100644 --- a/zetaclient/zetacore/query.go +++ b/zetaclient/zetacore/query.go @@ -19,6 +19,7 @@ import ( "github.com/zeta-chain/zetacore/cmd/zetacored/config" "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/proofs" + 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" observertypes "github.com/zeta-chain/zetacore/x/observer/types" @@ -480,7 +481,7 @@ func (c *Client) GetBlockHeaderChainState(chainID int64) (lightclienttypes.Query } // GetSupportedChains returns the supported chains -func (c *Client) GetSupportedChains() ([]*chains.Chain, error) { +func (c *Client) GetSupportedChains() ([]chains.Chain, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.SupportedChains(context.Background(), &observertypes.QuerySupportedChains{}) if err != nil { @@ -489,6 +490,16 @@ func (c *Client) GetSupportedChains() ([]*chains.Chain, error) { return resp.GetChains(), nil } +// GetAdditionalChains returns the additional chains +func (c *Client) GetAdditionalChains() ([]chains.Chain, error) { + client := authoritytypes.NewQueryClient(c.grpcConn) + resp, err := client.ChainInfo(context.Background(), &authoritytypes.QueryGetChainInfoRequest{}) + if err != nil { + return nil, err + } + return resp.GetChainInfo().Chains, nil +} + // GetPendingNonces returns the pending nonces func (c *Client) GetPendingNonces() (*observertypes.QueryAllPendingNoncesResponse, error) { client := observertypes.NewQueryClient(c.grpcConn) diff --git a/zetaclient/zetacore/query_test.go b/zetaclient/zetacore/query_test.go index 70898b8e11..baba533cfa 100644 --- a/zetaclient/zetacore/query_test.go +++ b/zetaclient/zetacore/query_test.go @@ -1,6 +1,7 @@ package zetacore import ( + authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" "net" "testing" @@ -815,7 +816,7 @@ func TestZetacore_GetBlockHeaderChainState(t *testing.T) { func TestZetacore_GetSupportedChains(t *testing.T) { expectedOutput := observertypes.QuerySupportedChainsResponse{ - Chains: []*chains.Chain{ + Chains: []chains.Chain{ { ChainName: chains.BitcoinMainnet.ChainName, ChainId: chains.BitcoinMainnet.ChainId, @@ -850,6 +851,29 @@ func TestZetacore_GetSupportedChains(t *testing.T) { require.Equal(t, expectedOutput.Chains, resp) } +func TestZetacore_GetAdditionalChains(t *testing.T) { + expectedOutput := authoritytypes.QueryGetChainInfoResponse{ + ChainInfo: authoritytypes.ChainInfo{ + Chains: []chains.Chain{ + chains.BitcoinMainnet, + chains.Ethereum, + }, + }, + } + input := observertypes.QuerySupportedChains{} + method := "/zetachain.zetacore.authority.Query/ChainInfo" + server := setupMockServer(t, authoritytypes.RegisterQueryServer, method, input, expectedOutput) + server.Serve() + defer closeMockServer(t, server) + + client, err := setupZetacoreClient() + require.NoError(t, err) + + resp, err := client.GetAdditionalChains() + require.NoError(t, err) + require.Equal(t, expectedOutput.ChainInfo.Chains, resp) +} + func TestZetacore_GetPendingNonces(t *testing.T) { expectedOutput := observertypes.QueryAllPendingNoncesResponse{ PendingNonces: []observertypes.PendingNonces{ diff --git a/zetaclient/zetacore/tx.go b/zetaclient/zetacore/tx.go index 1cf1c5c40e..2ef142d03f 100644 --- a/zetaclient/zetacore/tx.go +++ b/zetaclient/zetacore/tx.go @@ -61,13 +61,13 @@ func GetInboundVoteMessage( } // GasPriceMultiplier returns the gas price multiplier for the given chain -func GasPriceMultiplier(chainID int64) (float64, error) { - if chains.IsEVMChain(chainID) { +func GasPriceMultiplier(chain chains.Chain) (float64, error) { + if chain.IsEVMChain() { return clientcommon.EVMOutboundGasPriceMultiplier, nil - } else if chains.IsBitcoinChain(chainID) { + } else if chain.IsBitcoinChain() { return clientcommon.BTCOutboundGasPriceMultiplier, nil } - return 0, fmt.Errorf("cannot get gas price multiplier for unknown chain %d", chainID) + return 0, fmt.Errorf("cannot get gas price multiplier for unknown chain %d", chain.ChainId) } // WrapMessageWithAuthz wraps a message with an authz message @@ -89,7 +89,7 @@ func (c *Client) WrapMessageWithAuthz(msg sdk.Msg) (sdk.Msg, clientauthz.Signer, // TODO(revamp): rename to PostVoteGasPrice func (c *Client) PostGasPrice(chain chains.Chain, gasPrice uint64, supply string, blockNum uint64) (string, error) { // apply gas price multiplier for the chain - multiplier, err := GasPriceMultiplier(chain.ChainId) + multiplier, err := GasPriceMultiplier(chain) if err != nil { return "", err } diff --git a/zetaclient/zetacore/tx_test.go b/zetaclient/zetacore/tx_test.go index fbf9a10e7d..d53e93bda9 100644 --- a/zetaclient/zetacore/tx_test.go +++ b/zetaclient/zetacore/tx_test.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/hex" "errors" + "github.com/zeta-chain/zetacore/testutil/sample" + authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" "math/big" "net" "os" @@ -41,68 +43,70 @@ const ( func Test_GasPriceMultiplier(t *testing.T) { tt := []struct { name string - chainID int64 + chain chains.Chain multiplier float64 fail bool }{ { name: "get Ethereum multiplier", - chainID: 1, + chain: chains.Ethereum, multiplier: 1.2, fail: false, }, { name: "get Goerli multiplier", - chainID: 5, + chain: chains.Goerli, multiplier: 1.2, fail: false, }, { name: "get BSC multiplier", - chainID: 56, + chain: chains.BscMainnet, multiplier: 1.2, fail: false, }, { name: "get BSC Testnet multiplier", - chainID: 97, + chain: chains.BscTestnet, multiplier: 1.2, fail: false, }, { name: "get Polygon multiplier", - chainID: 137, + chain: chains.Polygon, multiplier: 1.2, fail: false, }, { name: "get Mumbai Testnet multiplier", - chainID: 80001, + chain: chains.Mumbai, multiplier: 1.2, fail: false, }, { name: "get Bitcoin multiplier", - chainID: 8332, + chain: chains.BitcoinMainnet, multiplier: 2.0, fail: false, }, { name: "get Bitcoin Testnet multiplier", - chainID: 18332, + chain: chains.BitcoinTestnet, multiplier: 2.0, fail: false, }, { - name: "get unknown chain gas price multiplier", - chainID: 1234, + name: "get unknown chain gas price multiplier", + chain: chains.Chain{ + Consensus: chains.Consensus_tendermint, + }, multiplier: 1.0, fail: true, }, } for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { - multiplier, err := GasPriceMultiplier(tc.chainID) + multiplier, err := GasPriceMultiplier(tc.chain) if tc.fail { require.Error(t, err) return @@ -209,6 +213,7 @@ func TestZetacore_UpdateZetacoreContext(t *testing.T) { grpcmock.RegisterService(upgradetypes.RegisterQueryServer), grpcmock.RegisterService(observertypes.RegisterQueryServer), grpcmock.RegisterService(lightclienttypes.RegisterQueryServer), + grpcmock.RegisterService(authoritytypes.RegisterQueryServer), grpcmock.WithPlanner(planner.FirstMatch()), grpcmock.WithListener(listener), func(s *grpcmock.Server) { @@ -246,7 +251,7 @@ func TestZetacore_UpdateZetacoreContext(t *testing.T) { UnlimitedTimes(). WithPayload(observertypes.QuerySupportedChains{}). Return(observertypes.QuerySupportedChainsResponse{ - Chains: []*chains.Chain{ + Chains: []chains.Chain{ { chains.BitcoinMainnet.ChainId, chains.BitcoinMainnet.ChainName, @@ -319,6 +324,20 @@ func TestZetacore_UpdateZetacoreContext(t *testing.T) { Enabled: false, }, }}) + + method = "/zetachain.zetacore.authority.Query/ChainInfo" + s.ExpectUnary(method). + UnlimitedTimes(). + WithPayload(authoritytypes.QueryGetChainInfoRequest{}). + Return(authoritytypes.QueryGetChainInfoResponse{ + ChainInfo: authoritytypes.ChainInfo{ + Chains: []chains.Chain{ + sample.Chain(1000), + sample.Chain(1001), + sample.Chain(1002), + }, + }, + }) }, )(t) From 41c6ef2a849ccbddcc7e13c92665007d77c10ef1 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Tue, 2 Jul 2024 09:16:45 -0700 Subject: [PATCH 21/23] refactor: more docker compose deduplicating (#2415) * refactor: more docker compose deduplicating * newline --- Dockerfile-localnet | 2 +- Makefile | 14 +- .../localnet/docker-compose-additionalevm.yml | 24 ---- contrib/localnet/docker-compose-stress.yml | 73 ----------- contrib/localnet/docker-compose-upgrade.yml | 43 ++---- contrib/localnet/docker-compose.yml | 123 +++++++++++++++++- contrib/localnet/scripts/start-zetaclientd.sh | 9 +- contrib/localnet/scripts/start-zetacored.sh | 25 ++-- 8 files changed, 157 insertions(+), 156 deletions(-) delete mode 100644 contrib/localnet/docker-compose-additionalevm.yml delete mode 100644 contrib/localnet/docker-compose-stress.yml diff --git a/Dockerfile-localnet b/Dockerfile-localnet index 1ed82c6b98..f9ff74d48a 100644 --- a/Dockerfile-localnet +++ b/Dockerfile-localnet @@ -28,7 +28,7 @@ RUN go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@v1.5.0 FROM golang:1.20.14-bookworm AS base-runtime RUN apt update && \ - apt install -yq jq yq curl tmux python3 openssh-server iputils-ping iproute2 && \ + apt install -yq jq yq curl tmux python3 openssh-server iputils-ping iproute2 bind9-host && \ rm -rf /var/lib/apt/lists/* RUN ssh-keygen -A && \ diff --git a/Makefile b/Makefile index 509cb40fd7..6fd58f0484 100644 --- a/Makefile +++ b/Makefile @@ -215,8 +215,9 @@ start-localnet-skip-build: export LOCALNET_MODE=setup-only && \ cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml up -d +# stop-localnet should include all profiles so other containers are also removed stop-localnet: - cd contrib/localnet/ && $(DOCKER) compose down --remove-orphans + cd contrib/localnet/ && $(DOCKER) compose --profile eth2 --profile stress --profile upgrade down --remove-orphans ############################################################################### ### E2E tests ### @@ -240,7 +241,7 @@ start-e2e-test: zetanode start-e2e-admin-test: zetanode @echo "--> Starting e2e admin test" export E2E_ARGS="--skip-regular --test-admin" && \ - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-additionalevm.yml up -d + cd contrib/localnet/ && $(DOCKER) compose --profile eth2 -f docker-compose.yml up -d start-e2e-performance-test: zetanode @echo "--> Starting e2e performance test" @@ -255,7 +256,7 @@ start-e2e-import-mainnet-test: zetanode start-stress-test: zetanode @echo "--> Starting stress test" - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-stress.yml up -d + cd contrib/localnet/ && $(DOCKER) compose --profile stress -f docker-compose.yml up -d ############################################################################### ### Upgrade Tests ### @@ -272,13 +273,13 @@ start-upgrade-test: zetanode-upgrade @echo "--> Starting upgrade test" export LOCALNET_MODE=upgrade && \ export UPGRADE_HEIGHT=225 && \ - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-upgrade.yml up -d + cd contrib/localnet/ && $(DOCKER) compose --profile upgrade -f docker-compose.yml -f docker-compose-upgrade.yml up -d start-upgrade-test-light: zetanode-upgrade @echo "--> Starting light upgrade test (no ZetaChain state populating before upgrade)" export LOCALNET_MODE=upgrade && \ export UPGRADE_HEIGHT=90 && \ - cd contrib/localnet/ && $(DOCKER) compose -f docker-compose.yml -f docker-compose-upgrade.yml up -d + cd contrib/localnet/ && $(DOCKER) compose --profile upgrade -f docker-compose.yml -f docker-compose-upgrade.yml up -d start-upgrade-import-mainnet-test: zetanode-upgrade @echo "--> Starting import-data upgrade test" @@ -286,7 +287,8 @@ start-upgrade-import-mainnet-test: zetanode-upgrade export ZETACORED_IMPORT_GENESIS_DATA=true && \ export ZETACORED_START_PERIOD=15m && \ export UPGRADE_HEIGHT=225 && \ - cd contrib/localnet/ && ./scripts/import-data.sh mainnet && $(DOCKER) compose -f docker-compose.yml -f docker-compose-upgrade.yml up -d + cd contrib/localnet/ && ./scripts/import-data.sh mainnet && $(DOCKER) compose --profile upgrade -f docker-compose.yml -f docker-compose-upgrade.yml up -d + ############################################################################### ### Monitoring ### ############################################################################### diff --git a/contrib/localnet/docker-compose-additionalevm.yml b/contrib/localnet/docker-compose-additionalevm.yml deleted file mode 100644 index 208a8e30e9..0000000000 --- a/contrib/localnet/docker-compose-additionalevm.yml +++ /dev/null @@ -1,24 +0,0 @@ -# This docker-compose file overrides the orchestrator service to specify the flag to test the admin functions -# and skip the regular tests -# it also adds another local Ethereum network to test EVM chain migration and use the additional-evm flag - -services: - eth2: - build: - context: ./anvil - container_name: eth2 - hostname: eth2 - platform: linux/amd64 - ports: - - "8546:8545" - networks: - mynetwork: - ipv4_address: 172.20.0.102 - - zetaclient0: - environment: - - ADDITIONAL_EVM=true - - zetaclient1: - environment: - - ADDITIONAL_EVM=true diff --git a/contrib/localnet/docker-compose-stress.yml b/contrib/localnet/docker-compose-stress.yml deleted file mode 100644 index fb11f01b5c..0000000000 --- a/contrib/localnet/docker-compose-stress.yml +++ /dev/null @@ -1,73 +0,0 @@ -# This docker-compose redefine the services: -# - ZetaChain with 4 nodes to test performance -# - ZetaChain observer set with 4 clients to test performance - -services: - zetacore0: - environment: - - ZETACORED_REPLICAS=4 - - zetacore1: - environment: - - ZETACORED_REPLICAS=4 - - zetacore2: - image: zetanode:latest - container_name: zetacore2 - hostname: zetacore2 - networks: - mynetwork: - ipv4_address: 172.20.0.13 - entrypoint: [ "/root/start-zetacored.sh", "4" ] - environment: - - HOTKEY_BACKEND=file - - HOTKEY_PASSWORD=password # test purposes only - - ZETACORED_REPLICAS=4 - - zetacore3: - image: zetanode:latest - container_name: zetacore3 - build: - context: ../../. - dockerfile: Dockerfile-localnet - hostname: zetacore3 - networks: - mynetwork: - ipv4_address: 172.20.0.14 - entrypoint: [ "/root/start-zetacored.sh", "4" ] - environment: - - HOTKEY_BACKEND=file - - HOTKEY_PASSWORD=password # test purposes only - - ZETACORED_REPLICAS=4 - - zetaclient2: - image: zetanode:latest - container_name: zetaclient2 - hostname: zetaclient2 - networks: - mynetwork: - ipv4_address: 172.20.0.23 - entrypoint: /root/start-zetaclientd.sh - environment: - - ETHDEV_ENDPOINT=http://eth:8545 - - HOTKEY_BACKEND=file - - HOTKEY_PASSWORD=password # test purposes only - volumes: - - ssh:/root/.ssh - - preparams:/root/preparams - - zetaclient3: - image: zetanode:latest - container_name: zetaclient3 - hostname: zetaclient3 - networks: - mynetwork: - ipv4_address: 172.20.0.24 - entrypoint: /root/start-zetaclientd.sh - environment: - - ETHDEV_ENDPOINT=http://eth:8545 - - HOTKEY_BACKEND=file - - HOTKEY_PASSWORD=password # test purposes only - volumes: - - ssh:/root/.ssh - - preparams:/root/preparams diff --git a/contrib/localnet/docker-compose-upgrade.yml b/contrib/localnet/docker-compose-upgrade.yml index badd7db8e5..7bcfb9a4fa 100644 --- a/contrib/localnet/docker-compose-upgrade.yml +++ b/contrib/localnet/docker-compose-upgrade.yml @@ -1,8 +1,5 @@ version: "3" -# This docker-compose redefine the services: -# - ZetaChain with 2 nodes (zetacore0, zetacore1) using the upgrade option for cosmovisor -# - ZetaChain observer set with 2 clients (zetaclient0, zetaclient1) using the background option -# - Orchestrator with upgrade option +# This docker-compose updates the services to use the old version of the zetanode image services: zetacore0: @@ -11,36 +8,20 @@ services: zetacore1: image: zetanode:old + zetacore2: + image: zetanode:old + + zetacore3: + image: zetanode:old + zetaclient0: image: zetanode:old zetaclient1: image: zetanode:old - upgrade-host: - image: zetanode:latest - container_name: upgrade-host - hostname: upgrade-host - entrypoint: ["/root/start-upgrade-host.sh"] - networks: - mynetwork: - ipv4_address: 172.20.0.250 - volumes: - - ssh:/root/.ssh - - upgrade-orchestrator: - # must run from old node for api compatibility - image: zetanode:old - container_name: upgrade-orchestrator - hostname: upgrade-orchestrator - entrypoint: ["/root/start-upgrade-orchestrator.sh"] - networks: - mynetwork: - ipv4_address: 172.20.0.251 - depends_on: - - zetacore0 - - upgrade-host - environment: - - UPGRADE_HEIGHT=${UPGRADE_HEIGHT} - volumes: - - ssh:/root/.ssh + zetaclient2: + image: zetanode:old + + zetaclient3: + image: zetanode:old diff --git a/contrib/localnet/docker-compose.yml b/contrib/localnet/docker-compose.yml index e73a946c04..cbfc17ff0f 100644 --- a/contrib/localnet/docker-compose.yml +++ b/contrib/localnet/docker-compose.yml @@ -1,11 +1,14 @@ # This docker-compose file configures the localnet environment # it contains the following services: -# - ZetaChain with 2 nodes (zetacore0, zetacore1) -# - A observer set with 2 clients (zetaclient0, zetaclient1) +# - ZetaChain with 2 nodes (zetacore0, zetacore1). When profile set to stress, 4 nodes will be created. +# - A observer set with 2 clients (zetaclient0, zetaclient1). When profile set to stress, 4 clients will be created. # - An Ethereum node (eth) +# - A secondary optional Ethereum node (eth2) enabled when profile is set to eth2 # - A Bitcoin node (bitcoin) # - A Rosetta API (rosetta) # - An orchestrator to manage interaction with the localnet (orchestrator) +# - An upgrade host to serve binaries for the upgrade tests (upgrade-host). Only enabled when profile is set to upgrade. +# - An upgrade orchestrator to send the upgrade governance proposal (upgrade-orchestrator). Only enabled when profile is set to upgrade. networks: mynetwork: @@ -56,7 +59,6 @@ services: environment: - HOTKEY_BACKEND=file - HOTKEY_PASSWORD=password # test purposes only - - ZETACORED_REPLICAS=2 - ZETACORED_IMPORT_GENESIS_DATA=${ZETACORED_IMPORT_GENESIS_DATA} volumes: - ssh:/root/.ssh @@ -73,7 +75,38 @@ services: environment: - HOTKEY_BACKEND=file - HOTKEY_PASSWORD=password # test purposes only - - ZETACORED_REPLICAS=2 + volumes: + - ssh:/root/.ssh + + zetacore2: + image: zetanode:latest + container_name: zetacore2 + hostname: zetacore2 + profiles: + - stress + networks: + mynetwork: + ipv4_address: 172.20.0.13 + entrypoint: [ "/root/start-zetacored.sh", "4" ] + environment: + - HOTKEY_BACKEND=file + - HOTKEY_PASSWORD=password # test purposes only + volumes: + - ssh:/root/.ssh + + zetacore3: + image: zetanode:latest + container_name: zetacore3 + hostname: zetacore3 + profiles: + - stress + networks: + mynetwork: + ipv4_address: 172.20.0.14 + entrypoint: [ "/root/start-zetacored.sh", "4" ] + environment: + - HOTKEY_BACKEND=file + - HOTKEY_PASSWORD=password # test purposes only volumes: - ssh:/root/.ssh @@ -109,6 +142,40 @@ services: - ssh:/root/.ssh - preparams:/root/preparams + zetaclient2: + image: zetanode:latest + container_name: zetaclient2 + hostname: zetaclient2 + profiles: + - stress + networks: + mynetwork: + ipv4_address: 172.20.0.23 + entrypoint: /root/start-zetaclientd.sh + environment: + - HOTKEY_BACKEND=file + - HOTKEY_PASSWORD=password # test purposes only + volumes: + - ssh:/root/.ssh + - preparams:/root/preparams + + zetaclient3: + image: zetanode:latest + container_name: zetaclient3 + hostname: zetaclient3 + profiles: + - stress + networks: + mynetwork: + ipv4_address: 172.20.0.24 + entrypoint: /root/start-zetaclientd.sh + environment: + - HOTKEY_BACKEND=file + - HOTKEY_PASSWORD=password # test purposes only + volumes: + - ssh:/root/.ssh + - preparams:/root/preparams + eth: image: ethereum/client-go:v1.10.26 container_name: eth @@ -120,6 +187,20 @@ services: ipv4_address: 172.20.0.100 entrypoint: ["geth", "--dev", "--http", "--http.addr", "172.20.0.100", "--http.vhosts", "*", "--http.api", "eth,web3,net", "--http.corsdomain", "https://remix.ethereum.org", "--dev.period", "2"] + eth2: + build: + context: ./anvil + container_name: eth2 + hostname: eth2 + profiles: + - eth2 + platform: linux/amd64 + ports: + - "8546:8545" + networks: + mynetwork: + ipv4_address: 172.20.0.102 + bitcoin: image: ruimarinho/bitcoin-core:22 # version 23 is not working with btcd 0.22.0 due to change in createwallet rpc container_name: bitcoin @@ -157,6 +238,38 @@ services: - UPGRADE_HEIGHT=${UPGRADE_HEIGHT} volumes: - ssh:/root/.ssh + + upgrade-host: + image: zetanode:latest + container_name: upgrade-host + hostname: upgrade-host + profiles: + - upgrade + entrypoint: ["/root/start-upgrade-host.sh"] + networks: + mynetwork: + ipv4_address: 172.20.0.250 + volumes: + - ssh:/root/.ssh + + upgrade-orchestrator: + # must run from old node for api compatibility + image: zetanode:old + container_name: upgrade-orchestrator + hostname: upgrade-orchestrator + profiles: + - upgrade + entrypoint: ["/root/start-upgrade-orchestrator.sh"] + networks: + mynetwork: + ipv4_address: 172.20.0.251 + depends_on: + - zetacore0 + - upgrade-host + environment: + - UPGRADE_HEIGHT=${UPGRADE_HEIGHT} + volumes: + - ssh:/root/.ssh volumes: ssh: - preparams: \ No newline at end of file + preparams: diff --git a/contrib/localnet/scripts/start-zetaclientd.sh b/contrib/localnet/scripts/start-zetaclientd.sh index a849891275..fea6b69779 100755 --- a/contrib/localnet/scripts/start-zetaclientd.sh +++ b/contrib/localnet/scripts/start-zetaclientd.sh @@ -7,7 +7,6 @@ /usr/sbin/sshd HOSTNAME=$(hostname) -OPTION=$1 export ZETACLIENTD_SUPERVISOR_ENABLE_AUTO_DOWNLOAD=true # sepolia is used in chain migration tests, this functions set the sepolia endpoint in the zetaclient_config.json @@ -28,15 +27,12 @@ while [ ! -f ~/.ssh/authorized_keys ]; do sleep 1 done - - # need to wait for zetacore0 to be up while ! curl -s -o /dev/null zetacore0:26657/status ; do echo "Waiting for zetacore0 rpc" sleep 10 done - # read HOTKEY_BACKEND env var for hotkey keyring backend and set default to test BACKEND="test" if [ "$HOTKEY_BACKEND" == "file" ]; then @@ -60,10 +56,11 @@ then MYIP=$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1) zetaclientd init --zetacore-url zetacore0 --chain-id athens_101-1 --operator "$operatorAddress" --log-format=text --public-ip "$MYIP" --keyring-backend "$BACKEND" --pre-params "$PREPARAMS_PATH" - # check if the option is additional-evm + # if eth2 is enabled, set the endpoint in the zetaclient_config.json # in this case, the additional evm is represented with the sepolia chain, we set manually the eth2 endpoint to the sepolia chain (11155111 -> http://eth2:8545) # in /root/.zetacored/config/zetaclient_config.json - if [[ -n $ADDITIONAL_EVM ]]; then + if host eth2 ; then + echo "enabling additional evm (eth2)" set_sepolia_endpoint fi fi diff --git a/contrib/localnet/scripts/start-zetacored.sh b/contrib/localnet/scripts/start-zetacored.sh index aba9538c5e..64779d2a39 100755 --- a/contrib/localnet/scripts/start-zetacored.sh +++ b/contrib/localnet/scripts/start-zetacored.sh @@ -85,16 +85,6 @@ export CLIENT_SKIP_UPGRADE=true export CLIENT_START_PROCESS=false export UNSAFE_SKIP_BACKUP=true -# generate node list -START=1 -# shellcheck disable=SC2100 -END=$((ZETACORED_REPLICAS - 1)) -NODELIST=() -for i in $(eval echo "{$START..$END}") -do - NODELIST+=("zetacore$i") -done - echo "HOSTNAME: $HOSTNAME" # init ssh keys @@ -162,6 +152,21 @@ fi # Skip genesis if it has already been completed (marked by presence of ~/.zetacored/init_complete file) if [[ $HOSTNAME == "zetacore0" && ! -f ~/.zetacored/init_complete ]] then + ZETACORED_REPLICAS=2 + if host zetacore3 ; then + echo "zetacore3 exists, setting ZETACORED_REPLICAS to 4" + ZETACORED_REPLICAS=4 + fi + # generate node list + START=1 + # shellcheck disable=SC2100 + END=$((ZETACORED_REPLICAS - 1)) + NODELIST=() + for i in $(eval echo "{$START..$END}") + do + NODELIST+=("zetacore$i") + done + # Misc : Copying the keyring to the client nodes so that they can sign the transactions ssh zetaclient0 mkdir -p ~/.zetacored/keyring-test/ scp ~/.zetacored/keyring-test/* zetaclient0:~/.zetacored/keyring-test/ From e6d8c490782db62689441065734342a6fb263b37 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 2 Jul 2024 18:46:51 +0200 Subject: [PATCH 22/23] feat: add Solana chain information (#2416) * proto * add new chains * add gateway address to chain params * changelog * comments --- changelog.md | 1 + docs/openapi/openapi.swagger.yaml | 8 ++ pkg/chains/chain_test.go | 8 +- pkg/chains/chains.go | 47 ++++++ pkg/chains/chains.pb.go | 127 ++++++++++------- pkg/chains/chains_test.go | 14 ++ .../zetachain/zetacore/observer/params.proto | 1 + .../zetacore/pkg/chains/chains.proto | 7 + .../zetacore/observer/params_pb.d.ts | 5 + .../zetacore/pkg/chains/chains_pb.d.ts | 30 ++++ x/observer/types/params.pb.go | 134 ++++++++++++------ 11 files changed, 285 insertions(+), 97 deletions(-) diff --git a/changelog.md b/changelog.md index 9f40d4b256..7b679fb678 100644 --- a/changelog.md +++ b/changelog.md @@ -30,6 +30,7 @@ * [2339](https://github.com/zeta-chain/node/pull/2339) - add binaries related question to syncing issue form * [2366](https://github.com/zeta-chain/node/pull/2366) - add migration script for adding authorizations table * [2372](https://github.com/zeta-chain/node/pull/2372) - add queries for tss fund migration info +* [2416g](https://github.com/zeta-chain/node/pull/2416) - add Solana chain information ### Refactor diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 987feb13d4..a6ee4a79f3 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -56965,6 +56965,9 @@ definitions: - optimism_sepolia - base_mainnet - base_sepolia + - solana_mainnet + - solana_devnet + - solana_localnet default: empty title: ChainName represents the name of the chain chainsConsensus: @@ -56974,6 +56977,7 @@ definitions: - tendermint - bitcoin - op_stack + - solana_consensus default: ethereum title: |- Consensus represents the consensus algorithm used by the chain @@ -56989,6 +56993,7 @@ definitions: - bsc - optimism - base + - solana default: eth title: |- Network represents the network of the chain @@ -57022,6 +57027,7 @@ definitions: enum: - no_vm - evm + - svm default: no_vm title: |- Vm represents the virtual machine type of the chain to support smart @@ -57832,6 +57838,8 @@ definitions: type: string is_supported: type: boolean + gateway_address: + type: string observerChainParamsList: type: object properties: diff --git a/pkg/chains/chain_test.go b/pkg/chains/chain_test.go index f495ba0c85..e9551d35c7 100644 --- a/pkg/chains/chain_test.go +++ b/pkg/chains/chain_test.go @@ -58,7 +58,7 @@ func TestChain_Validate(t *testing.T) { name: "should error if chain name invalid", chain: chains.Chain{ ChainId: 42, - ChainName: chains.ChainName_base_sepolia + 1, + ChainName: chains.ChainName_solana_localnet + 1, Network: chains.Network_optimism, NetworkType: chains.NetworkType_testnet, Vm: chains.Vm_evm, @@ -72,7 +72,7 @@ func TestChain_Validate(t *testing.T) { chain: chains.Chain{ ChainId: 42, ChainName: chains.ChainName_empty, - Network: chains.Network_base + 1, + Network: chains.Network_solana + 1, NetworkType: chains.NetworkType_testnet, Vm: chains.Vm_evm, Consensus: chains.Consensus_op_stack, @@ -100,7 +100,7 @@ func TestChain_Validate(t *testing.T) { ChainName: chains.ChainName_empty, Network: chains.Network_base, NetworkType: chains.NetworkType_devnet, - Vm: chains.Vm_evm + 1, + Vm: chains.Vm_svm + 1, Consensus: chains.Consensus_op_stack, IsExternal: true, }, @@ -114,7 +114,7 @@ func TestChain_Validate(t *testing.T) { Network: chains.Network_base, NetworkType: chains.NetworkType_devnet, Vm: chains.Vm_evm, - Consensus: chains.Consensus_op_stack + 1, + Consensus: chains.Consensus_solana_consensus + 1, IsExternal: true, }, errStr: "invalid consensus", diff --git a/pkg/chains/chains.go b/pkg/chains/chains.go index 333aa22001..2dcd0377ea 100644 --- a/pkg/chains/chains.go +++ b/pkg/chains/chains.go @@ -91,6 +91,20 @@ var ( CctxGateway: CCTXGateway_observers, } + // SolanaMainnet is Solana mainnet + // TODO: define final chain ID + // https://github.com/zeta-chain/node/issues/2421 + SolanaMainnet = Chain{ + ChainName: ChainName_solana_mainnet, + ChainId: 900, + Network: Network_solana, + NetworkType: NetworkType_mainnet, + Vm: Vm_svm, + Consensus: Consensus_solana_consensus, + IsExternal: true, + CctxGateway: CCTXGateway_observers, + } + /** * Testnet chains */ @@ -179,6 +193,22 @@ var ( CctxGateway: CCTXGateway_observers, } + // SolanaDevnet is Solana devnet + // NOTE: Solana devnet refers to Solana testnet in our terminology + // Solana uses devnet denomitation for network for development + // TODO: define final chain ID + // https://github.com/zeta-chain/node/issues/2421 + SolanaDevnet = Chain{ + ChainName: ChainName_solana_devnet, + ChainId: 901, + Network: Network_solana, + NetworkType: NetworkType_testnet, + Vm: Vm_svm, + Consensus: Consensus_solana_consensus, + IsExternal: true, + CctxGateway: CCTXGateway_observers, + } + /** * Devnet chains */ @@ -236,6 +266,20 @@ var ( CctxGateway: CCTXGateway_observers, } + // SolanaLocalnet is Solana localnet + // TODO: define final chain ID + // https://github.com/zeta-chain/node/issues/2421 + SolanaLocalnet = Chain{ + ChainName: ChainName_solana_localnet, + ChainId: 902, + Network: Network_solana, + NetworkType: NetworkType_privnet, + Vm: Vm_svm, + Consensus: Consensus_solana_consensus, + IsExternal: true, + CctxGateway: CCTXGateway_observers, + } + /** * Deprecated chains */ @@ -296,6 +340,9 @@ func DefaultChainsList() []Chain { OptimismSepolia, BaseMainnet, BaseSepolia, + SolanaMainnet, + SolanaDevnet, + SolanaLocalnet, } } diff --git a/pkg/chains/chains.pb.go b/pkg/chains/chains.pb.go index 848a7e1bc0..b49c3b0c96 100644 --- a/pkg/chains/chains.pb.go +++ b/pkg/chains/chains.pb.go @@ -78,6 +78,9 @@ const ( ChainName_optimism_sepolia ChainName = 18 ChainName_base_mainnet ChainName = 19 ChainName_base_sepolia ChainName = 20 + ChainName_solana_mainnet ChainName = 21 + ChainName_solana_devnet ChainName = 22 + ChainName_solana_localnet ChainName = 23 ) var ChainName_name = map[int32]string{ @@ -100,6 +103,9 @@ var ChainName_name = map[int32]string{ 18: "optimism_sepolia", 19: "base_mainnet", 20: "base_sepolia", + 21: "solana_mainnet", + 22: "solana_devnet", + 23: "solana_localnet", } var ChainName_value = map[string]int32{ @@ -122,6 +128,9 @@ var ChainName_value = map[string]int32{ "optimism_sepolia": 18, "base_mainnet": 19, "base_sepolia": 20, + "solana_mainnet": 21, + "solana_devnet": 22, + "solana_localnet": 23, } func (x ChainName) String() string { @@ -145,6 +154,7 @@ const ( Network_bsc Network = 4 Network_optimism Network = 5 Network_base Network = 6 + Network_solana Network = 7 ) var Network_name = map[int32]string{ @@ -155,6 +165,7 @@ var Network_name = map[int32]string{ 4: "bsc", 5: "optimism", 6: "base", + 7: "solana", } var Network_value = map[string]int32{ @@ -165,6 +176,7 @@ var Network_value = map[string]int32{ "bsc": 4, "optimism": 5, "base": 6, + "solana": 7, } func (x Network) String() string { @@ -215,16 +227,19 @@ type Vm int32 const ( Vm_no_vm Vm = 0 Vm_evm Vm = 1 + Vm_svm Vm = 2 ) var Vm_name = map[int32]string{ 0: "no_vm", 1: "evm", + 2: "svm", } var Vm_value = map[string]int32{ "no_vm": 0, "evm": 1, + "svm": 2, } func (x Vm) String() string { @@ -241,10 +256,11 @@ func (Vm) EnumDescriptor() ([]byte, []int) { type Consensus int32 const ( - Consensus_ethereum Consensus = 0 - Consensus_tendermint Consensus = 1 - Consensus_bitcoin Consensus = 2 - Consensus_op_stack Consensus = 3 + Consensus_ethereum Consensus = 0 + Consensus_tendermint Consensus = 1 + Consensus_bitcoin Consensus = 2 + Consensus_op_stack Consensus = 3 + Consensus_solana_consensus Consensus = 4 ) var Consensus_name = map[int32]string{ @@ -252,13 +268,15 @@ var Consensus_name = map[int32]string{ 1: "tendermint", 2: "bitcoin", 3: "op_stack", + 4: "solana_consensus", } var Consensus_value = map[string]int32{ - "ethereum": 0, - "tendermint": 1, - "bitcoin": 2, - "op_stack": 3, + "ethereum": 0, + "tendermint": 1, + "bitcoin": 2, + "op_stack": 3, + "solana_consensus": 4, } func (x Consensus) String() string { @@ -425,51 +443,54 @@ func init() { } var fileDescriptor_236b85e7bff6130d = []byte{ - // 704 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x3d, 0x8f, 0x2b, 0x35, - 0x14, 0xcd, 0x4c, 0xbe, 0xef, 0x64, 0xb3, 0xc6, 0x6f, 0x8b, 0xe1, 0x49, 0x0c, 0x0b, 0x05, 0x0a, - 0x11, 0x24, 0x02, 0x4a, 0x1a, 0x44, 0xc4, 0x7b, 0x02, 0x89, 0x57, 0x0c, 0xab, 0x15, 0xd0, 0x8c, - 0x3c, 0xce, 0x65, 0x62, 0x25, 0x1e, 0x8f, 0xc6, 0x4e, 0x76, 0xc3, 0xaf, 0xe0, 0x47, 0x50, 0xf0, - 0x53, 0x28, 0xb7, 0xa4, 0x44, 0xbb, 0x05, 0x25, 0x7f, 0x01, 0xd9, 0xf3, 0x91, 0xa5, 0x80, 0xdd, - 0x2a, 0xd7, 0x67, 0xce, 0x39, 0xf7, 0xd8, 0xbe, 0x31, 0xcc, 0x7f, 0x46, 0xc3, 0xf8, 0x86, 0x89, - 0x7c, 0xe9, 0x2a, 0x55, 0xe2, 0xb2, 0xd8, 0x66, 0x4b, 0x07, 0xe9, 0xfa, 0x67, 0x51, 0x94, 0xca, - 0x28, 0xfa, 0x4e, 0xcb, 0x5d, 0x34, 0xdc, 0x45, 0xb1, 0xcd, 0x16, 0x15, 0xe9, 0xe5, 0x45, 0xa6, - 0x32, 0xe5, 0x98, 0x4b, 0x5b, 0x55, 0xa2, 0xf7, 0xff, 0xea, 0x42, 0x7f, 0x65, 0x09, 0xf4, 0x6d, - 0x18, 0x39, 0x66, 0x22, 0xd6, 0xa1, 0x7f, 0xe9, 0xcd, 0xba, 0xf1, 0xd0, 0xad, 0xbf, 0x5e, 0xd3, - 0xd7, 0x00, 0xd5, 0xa7, 0x9c, 0x49, 0x0c, 0xbd, 0x4b, 0x6f, 0x36, 0xfd, 0x74, 0xb6, 0xf8, 0xdf, - 0x76, 0x0b, 0x67, 0xfa, 0x86, 0x49, 0x8c, 0xc7, 0xbc, 0x29, 0xe9, 0x17, 0x30, 0xcc, 0xd1, 0xdc, - 0xa8, 0x72, 0x1b, 0x76, 0x9d, 0xcb, 0x07, 0x4f, 0xb8, 0xbc, 0xa9, 0xd8, 0x71, 0x23, 0xa3, 0xdf, - 0xc2, 0xa4, 0x2e, 0x13, 0x73, 0x2c, 0x30, 0xec, 0x39, 0x9b, 0xf9, 0xf3, 0x6c, 0xae, 0x8e, 0x05, - 0xc6, 0x41, 0x7e, 0x5a, 0xd0, 0x4f, 0xc0, 0x3f, 0xc8, 0xb0, 0xef, 0x4c, 0xde, 0x7b, 0xc2, 0xe4, - 0x5a, 0xc6, 0xfe, 0x41, 0xd2, 0x57, 0x30, 0xe6, 0x2a, 0xd7, 0x98, 0xeb, 0xbd, 0x0e, 0x07, 0xcf, - 0x3b, 0x8b, 0x86, 0x1f, 0x9f, 0xa4, 0xf4, 0x5d, 0x08, 0x84, 0x4e, 0xf0, 0xd6, 0x60, 0x99, 0xb3, - 0x5d, 0x38, 0xbc, 0xf4, 0x66, 0xa3, 0x18, 0x84, 0xfe, 0xaa, 0x46, 0xec, 0x56, 0x39, 0x37, 0xb7, - 0x49, 0xc6, 0x0c, 0xde, 0xb0, 0x63, 0x38, 0x7a, 0xd6, 0x56, 0x57, 0xab, 0xab, 0xef, 0x5f, 0x57, - 0x8a, 0x38, 0xb0, 0xfa, 0x7a, 0x31, 0xff, 0x1c, 0xce, 0x62, 0xe4, 0x28, 0x0e, 0xf8, 0x9d, 0x61, - 0x66, 0xaf, 0x69, 0x00, 0x43, 0x5e, 0x22, 0x33, 0xb8, 0x26, 0x1d, 0xbb, 0xd0, 0x7b, 0xce, 0x51, - 0x6b, 0xe2, 0x51, 0x80, 0xc1, 0x4f, 0x4c, 0xec, 0x70, 0x4d, 0xfc, 0x97, 0xbd, 0xdf, 0x7e, 0x8d, - 0xbc, 0xf9, 0xdf, 0x3e, 0x8c, 0xdb, 0x1b, 0xa5, 0x63, 0xe8, 0xa3, 0x2c, 0xcc, 0x91, 0x74, 0xe8, - 0x39, 0x04, 0x68, 0x36, 0x89, 0x64, 0x22, 0xcf, 0xd1, 0x10, 0x8f, 0x12, 0x98, 0xd8, 0x58, 0x2d, - 0xe2, 0x5b, 0x4a, 0x6a, 0x78, 0x0b, 0x74, 0xe9, 0x0b, 0x38, 0x2f, 0xd4, 0xee, 0x98, 0xa9, 0xbc, - 0x05, 0x7b, 0x8e, 0xa5, 0x4f, 0xac, 0x3e, 0xa5, 0x30, 0xcd, 0x14, 0x96, 0x3b, 0x91, 0x18, 0xd4, - 0xc6, 0x62, 0x03, 0x8b, 0xc9, 0xbd, 0x4c, 0xd9, 0x09, 0x1b, 0x36, 0xc2, 0x06, 0x80, 0x36, 0x41, - 0x83, 0x04, 0x4d, 0x82, 0x06, 0x98, 0xd8, 0x04, 0x1a, 0x0b, 0xb5, 0x13, 0x27, 0xd6, 0x99, 0x05, - 0xeb, 0x86, 0x3b, 0xc5, 0xd9, 0xce, 0x82, 0xd3, 0x46, 0x5a, 0x62, 0x66, 0x89, 0xe4, 0xdc, 0xba, - 0x33, 0xa9, 0x8e, 0xad, 0x8e, 0xd0, 0x0b, 0x20, 0xaa, 0x30, 0x42, 0x0a, 0x2d, 0xdb, 0xf8, 0x6f, - 0xfd, 0x0b, 0xad, 0x7b, 0x11, 0x6a, 0xd5, 0x29, 0xd3, 0xd8, 0xf2, 0x5e, 0xb4, 0x48, 0xc3, 0xb9, - 0xa8, 0x4f, 0xfc, 0x07, 0x18, 0xd6, 0x53, 0x4b, 0x87, 0xd0, 0x45, 0xb3, 0x21, 0x1d, 0x3a, 0x82, - 0x9e, 0xdd, 0x19, 0xf1, 0x2c, 0x94, 0x1a, 0x4e, 0x7c, 0x7b, 0x6f, 0xf5, 0x59, 0x92, 0xae, 0x43, - 0x35, 0x27, 0x3d, 0x3a, 0x81, 0x51, 0xd3, 0x9c, 0xf4, 0xad, 0xcc, 0xb6, 0x20, 0x83, 0xda, 0xfa, - 0x15, 0x04, 0x8f, 0xfe, 0x10, 0xd6, 0xa2, 0x89, 0xe3, 0xe6, 0xa0, 0xd9, 0x99, 0xe7, 0xcc, 0x4b, - 0x71, 0xa8, 0xae, 0x11, 0x60, 0xb0, 0x46, 0x57, 0x77, 0x6b, 0x9f, 0x08, 0xfc, 0x6b, 0x69, 0x87, - 0x21, 0x57, 0xc9, 0x41, 0x92, 0x8e, 0x0b, 0x7a, 0x90, 0xc4, 0xab, 0xbf, 0x7f, 0x03, 0xe3, 0x76, - 0xf2, 0x6d, 0x24, 0x34, 0x1b, 0x2c, 0x71, 0x6f, 0x99, 0x53, 0x00, 0x83, 0xf9, 0x1a, 0x4b, 0x29, - 0xf2, 0xba, 0x53, 0x2a, 0x0c, 0x57, 0x22, 0x27, 0x7e, 0x95, 0x3e, 0xd1, 0x86, 0xf1, 0x6d, 0xdb, - 0xeb, 0x23, 0x08, 0x1e, 0x4d, 0x76, 0x75, 0x12, 0xae, 0xe7, 0x19, 0x8c, 0x55, 0xaa, 0xb1, 0x3c, - 0x60, 0xa9, 0x9b, 0xce, 0x5f, 0xae, 0x7e, 0xbf, 0x8f, 0xbc, 0xbb, 0xfb, 0xc8, 0xfb, 0xf3, 0x3e, - 0xf2, 0x7e, 0x79, 0x88, 0x3a, 0x77, 0x0f, 0x51, 0xe7, 0x8f, 0x87, 0xa8, 0xf3, 0xe3, 0x87, 0x99, - 0x30, 0x9b, 0x7d, 0xba, 0xe0, 0x4a, 0xba, 0x17, 0xf5, 0xe3, 0xff, 0x7c, 0x5c, 0xd3, 0x81, 0x7b, - 0x21, 0x3f, 0xfb, 0x27, 0x00, 0x00, 0xff, 0xff, 0x05, 0xa7, 0x7f, 0x40, 0x84, 0x05, 0x00, 0x00, + // 751 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x4d, 0x8f, 0xe3, 0x34, + 0x18, 0x6e, 0x9a, 0xb6, 0x69, 0xdf, 0xcc, 0x87, 0xd7, 0x3b, 0x40, 0x58, 0x89, 0x32, 0x70, 0x80, + 0x61, 0x04, 0x1d, 0x01, 0x47, 0x2e, 0x88, 0x11, 0xbb, 0xe2, 0xc0, 0x1e, 0xc2, 0x6a, 0x85, 0xb8, + 0x04, 0xc7, 0x7d, 0x49, 0xad, 0xc6, 0x71, 0x14, 0xbb, 0xd9, 0x2d, 0xbf, 0x82, 0x1f, 0xc1, 0x01, + 0x89, 0x3f, 0xc2, 0x71, 0x8f, 0x1c, 0xd1, 0xcc, 0x81, 0xbf, 0x81, 0xec, 0x38, 0xe9, 0x72, 0x80, + 0x99, 0x53, 0xed, 0xa7, 0xcf, 0xf3, 0xbe, 0xcf, 0xfb, 0xe1, 0xc0, 0xe5, 0xcf, 0x68, 0x18, 0xdf, + 0x30, 0x51, 0x5d, 0xb9, 0x93, 0x6a, 0xf0, 0xaa, 0xde, 0x16, 0x57, 0x0e, 0xd2, 0xfe, 0x67, 0x55, + 0x37, 0xca, 0x28, 0xfa, 0xce, 0xc0, 0x5d, 0xf5, 0xdc, 0x55, 0xbd, 0x2d, 0x56, 0x1d, 0xe9, 0xd1, + 0x59, 0xa1, 0x0a, 0xe5, 0x98, 0x57, 0xf6, 0xd4, 0x89, 0xde, 0xff, 0x3b, 0x84, 0xe9, 0xb5, 0x25, + 0xd0, 0xb7, 0x61, 0xee, 0x98, 0x99, 0x58, 0x27, 0xe3, 0xf3, 0xe0, 0x22, 0x4c, 0x23, 0x77, 0xff, + 0x66, 0x4d, 0x9f, 0x00, 0x74, 0x7f, 0x55, 0x4c, 0x62, 0x12, 0x9c, 0x07, 0x17, 0x27, 0x9f, 0x5d, + 0xac, 0xfe, 0x37, 0xdd, 0xca, 0x05, 0x7d, 0xca, 0x24, 0xa6, 0x0b, 0xde, 0x1f, 0xe9, 0x97, 0x10, + 0x55, 0x68, 0x5e, 0xa8, 0x66, 0x9b, 0x84, 0x2e, 0xca, 0x07, 0x77, 0x44, 0x79, 0xda, 0xb1, 0xd3, + 0x5e, 0x46, 0xbf, 0x85, 0x23, 0x7f, 0xcc, 0xcc, 0xbe, 0xc6, 0x64, 0xe2, 0xc2, 0x5c, 0xde, 0x2f, + 0xcc, 0xb3, 0x7d, 0x8d, 0x69, 0x5c, 0x1d, 0x2e, 0xf4, 0x53, 0x18, 0xb7, 0x32, 0x99, 0xba, 0x20, + 0xef, 0xdd, 0x11, 0xe4, 0xb9, 0x4c, 0xc7, 0xad, 0xa4, 0x8f, 0x61, 0xc1, 0x55, 0xa5, 0xb1, 0xd2, + 0x3b, 0x9d, 0xcc, 0xee, 0xd7, 0x8b, 0x9e, 0x9f, 0x1e, 0xa4, 0xf4, 0x5d, 0x88, 0x85, 0xce, 0xf0, + 0xa5, 0xc1, 0xa6, 0x62, 0x65, 0x12, 0x9d, 0x07, 0x17, 0xf3, 0x14, 0x84, 0xfe, 0xda, 0x23, 0xb6, + 0x54, 0xce, 0xcd, 0xcb, 0xac, 0x60, 0x06, 0x5f, 0xb0, 0x7d, 0x32, 0xbf, 0x57, 0xa9, 0xd7, 0xd7, + 0xcf, 0xbe, 0x7f, 0xd2, 0x29, 0xd2, 0xd8, 0xea, 0xfd, 0xe5, 0xf2, 0x0b, 0x38, 0x4e, 0x91, 0xa3, + 0x68, 0xf1, 0x3b, 0xc3, 0xcc, 0x4e, 0xd3, 0x18, 0x22, 0xde, 0x20, 0x33, 0xb8, 0x26, 0x23, 0x7b, + 0xd1, 0x3b, 0xce, 0x51, 0x6b, 0x12, 0x50, 0x80, 0xd9, 0x4f, 0x4c, 0x94, 0xb8, 0x26, 0xe3, 0x47, + 0x93, 0xdf, 0x7e, 0x5d, 0x06, 0x97, 0xbf, 0x87, 0xb0, 0x18, 0x26, 0x4a, 0x17, 0x30, 0x45, 0x59, + 0x9b, 0x3d, 0x19, 0xd1, 0x53, 0x88, 0xd1, 0x6c, 0x32, 0xc9, 0x44, 0x55, 0xa1, 0x21, 0x01, 0x25, + 0x70, 0x64, 0x6d, 0x0d, 0xc8, 0xd8, 0x52, 0x72, 0xc3, 0x07, 0x20, 0xa4, 0x0f, 0xe1, 0xb4, 0x56, + 0xe5, 0xbe, 0x50, 0xd5, 0x00, 0x4e, 0x1c, 0x4b, 0x1f, 0x58, 0x53, 0x4a, 0xe1, 0xa4, 0x50, 0xd8, + 0x94, 0x22, 0x33, 0xa8, 0x8d, 0xc5, 0x66, 0x16, 0x93, 0x3b, 0x99, 0xb3, 0x03, 0x16, 0xf5, 0xc2, + 0x1e, 0x80, 0xc1, 0x41, 0x8f, 0xc4, 0xbd, 0x83, 0x1e, 0x38, 0xb2, 0x0e, 0x34, 0xd6, 0xaa, 0x14, + 0x07, 0xd6, 0xb1, 0x05, 0x7d, 0xc2, 0x52, 0x71, 0x56, 0x5a, 0xf0, 0xa4, 0x97, 0x36, 0x58, 0x58, + 0x22, 0x39, 0xb5, 0xd1, 0x99, 0x54, 0xfb, 0x41, 0x47, 0xe8, 0x19, 0x10, 0x55, 0x1b, 0x21, 0x85, + 0x96, 0x83, 0xfd, 0x07, 0xff, 0x42, 0x7d, 0x2e, 0x42, 0xad, 0x3a, 0x67, 0x1a, 0x07, 0xde, 0xc3, + 0x01, 0xe9, 0x39, 0x67, 0xb6, 0x48, 0xad, 0x4a, 0x56, 0x1d, 0x7a, 0xf8, 0x06, 0x7d, 0x00, 0xc7, + 0x1e, 0x5b, 0x63, 0x6b, 0xa1, 0x37, 0x5d, 0x0d, 0x1d, 0x34, 0xd8, 0x7d, 0xcb, 0x4f, 0x0b, 0x21, + 0xf2, 0x1b, 0x4f, 0x23, 0x08, 0xd1, 0x6c, 0xc8, 0x88, 0xce, 0x61, 0x62, 0xbb, 0x42, 0x02, 0x0b, + 0xe5, 0x86, 0x93, 0xb1, 0x9d, 0xb9, 0x9f, 0x03, 0x09, 0x1d, 0xaa, 0x39, 0x99, 0xd0, 0x23, 0x98, + 0xf7, 0xc6, 0xc9, 0xd4, 0xca, 0xac, 0x3d, 0x32, 0xb3, 0x4b, 0xd1, 0xe5, 0x23, 0x91, 0x4f, 0xf3, + 0x18, 0xe2, 0xd7, 0x1e, 0x96, 0x0d, 0xd7, 0x1b, 0x76, 0xfb, 0xd4, 0x77, 0x28, 0x70, 0x89, 0x1a, + 0xd1, 0x76, 0xeb, 0x00, 0x30, 0xf3, 0x35, 0x84, 0x3e, 0xce, 0x87, 0x30, 0x7e, 0x2e, 0xed, 0x52, + 0x55, 0x2a, 0x6b, 0x25, 0x19, 0x39, 0xd3, 0xad, 0xec, 0xac, 0xea, 0x56, 0x0e, 0x5b, 0xf8, 0x23, + 0x2c, 0x86, 0xa7, 0x64, 0x7d, 0xa2, 0xd9, 0x60, 0x83, 0x3b, 0x2b, 0x39, 0x01, 0x30, 0x58, 0xad, + 0xb1, 0x91, 0xa2, 0xf2, 0x29, 0x73, 0x61, 0xb8, 0x12, 0x15, 0x19, 0x77, 0x25, 0x65, 0xda, 0x30, + 0xbe, 0x25, 0xa1, 0x9d, 0x8c, 0x6f, 0xdc, 0xf0, 0x18, 0xc9, 0xc4, 0x67, 0xf8, 0x18, 0xe2, 0xd7, + 0x1e, 0x50, 0xd7, 0x34, 0x67, 0xe9, 0x18, 0x16, 0x2a, 0xd7, 0xd8, 0xb4, 0xd8, 0x68, 0x12, 0x74, + 0xec, 0xaf, 0xae, 0xff, 0xb8, 0x59, 0x06, 0xaf, 0x6e, 0x96, 0xc1, 0x5f, 0x37, 0xcb, 0xe0, 0x97, + 0xdb, 0xe5, 0xe8, 0xd5, 0xed, 0x72, 0xf4, 0xe7, 0xed, 0x72, 0xf4, 0xc3, 0x47, 0x85, 0x30, 0x9b, + 0x5d, 0xbe, 0xe2, 0x4a, 0xba, 0x0f, 0xf7, 0x27, 0xff, 0xf9, 0x0d, 0xcf, 0x67, 0xee, 0x43, 0xfc, + 0xf9, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x26, 0xaa, 0x81, 0xba, 0xeb, 0x05, 0x00, 0x00, } func (m *Chain) Marshal() (dAtA []byte, err error) { diff --git a/pkg/chains/chains_test.go b/pkg/chains/chains_test.go index 5b85f39f22..fe947b11be 100644 --- a/pkg/chains/chains_test.go +++ b/pkg/chains/chains_test.go @@ -25,6 +25,7 @@ func TestChainListByNetworkType(t *testing.T) { chains.Polygon, chains.OptimismMainnet, chains.BaseMainnet, + chains.SolanaMainnet, }, }, { @@ -40,6 +41,7 @@ func TestChainListByNetworkType(t *testing.T) { chains.Sepolia, chains.OptimismSepolia, chains.BaseSepolia, + chains.SolanaDevnet, }, }, { @@ -49,6 +51,7 @@ func TestChainListByNetworkType(t *testing.T) { chains.ZetaChainPrivnet, chains.BitcoinRegtest, chains.GoerliLocalnet, + chains.SolanaLocalnet, }, }, } @@ -106,6 +109,11 @@ func TestChainListByNetwork(t *testing.T) { chains.Network_base, []chains.Chain{chains.BaseMainnet, chains.BaseSepolia}, }, + { + "Solana", + chains.Network_solana, + []chains.Chain{chains.SolanaMainnet, chains.SolanaDevnet, chains.SolanaLocalnet}, + }, } for _, lt := range listTests { @@ -137,6 +145,9 @@ func TestDefaultChainList(t *testing.T) { chains.OptimismSepolia, chains.BaseMainnet, chains.BaseSepolia, + chains.SolanaMainnet, + chains.SolanaDevnet, + chains.SolanaLocalnet, }, chains.DefaultChainsList()) } @@ -158,6 +169,9 @@ func TestExternalChainList(t *testing.T) { chains.OptimismSepolia, chains.BaseMainnet, chains.BaseSepolia, + chains.SolanaMainnet, + chains.SolanaDevnet, + chains.SolanaLocalnet, }, chains.ExternalChainList([]chains.Chain{})) } diff --git a/proto/zetachain/zetacore/observer/params.proto b/proto/zetachain/zetacore/observer/params.proto index 92d00763dd..c0c732b705 100644 --- a/proto/zetachain/zetacore/observer/params.proto +++ b/proto/zetachain/zetacore/observer/params.proto @@ -29,6 +29,7 @@ message ChainParams { (gogoproto.nullable) = false ]; bool is_supported = 16; + string gateway_address = 17; } // Deprecated(v17) diff --git a/proto/zetachain/zetacore/pkg/chains/chains.proto b/proto/zetachain/zetacore/pkg/chains/chains.proto index 8075822471..137d056713 100644 --- a/proto/zetachain/zetacore/pkg/chains/chains.proto +++ b/proto/zetachain/zetacore/pkg/chains/chains.proto @@ -43,6 +43,10 @@ enum ChainName { optimism_sepolia = 18; base_mainnet = 19; base_sepolia = 20; + + solana_mainnet = 21; + solana_devnet = 22; + solana_localnet = 23; } // Network represents the network of the chain @@ -57,6 +61,7 @@ enum Network { bsc = 4; optimism = 5; base = 6; + solana = 7; } // NetworkType represents the network type of the chain @@ -75,6 +80,7 @@ enum Vm { option (gogoproto.goproto_enum_stringer) = true; no_vm = 0; evm = 1; + svm = 2; } // Consensus represents the consensus algorithm used by the chain @@ -86,6 +92,7 @@ enum Consensus { tendermint = 1; bitcoin = 2; op_stack = 3; + solana_consensus = 4; } // CCTXGateway describes for the chain the gateway used to handle CCTX outbounds diff --git a/typescript/zetachain/zetacore/observer/params_pb.d.ts b/typescript/zetachain/zetacore/observer/params_pb.d.ts index 252793f418..9155826e05 100644 --- a/typescript/zetachain/zetacore/observer/params_pb.d.ts +++ b/typescript/zetachain/zetacore/observer/params_pb.d.ts @@ -104,6 +104,11 @@ export declare class ChainParams extends Message { */ isSupported: boolean; + /** + * @generated from field: string gateway_address = 17; + */ + gatewayAddress: string; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/typescript/zetachain/zetacore/pkg/chains/chains_pb.d.ts b/typescript/zetachain/zetacore/pkg/chains/chains_pb.d.ts index 782e669d43..ecaf732ec5 100644 --- a/typescript/zetachain/zetacore/pkg/chains/chains_pb.d.ts +++ b/typescript/zetachain/zetacore/pkg/chains/chains_pb.d.ts @@ -132,6 +132,21 @@ export declare enum ChainName { * @generated from enum value: base_sepolia = 20; */ base_sepolia = 20, + + /** + * @generated from enum value: solana_mainnet = 21; + */ + solana_mainnet = 21, + + /** + * @generated from enum value: solana_devnet = 22; + */ + solana_devnet = 22, + + /** + * @generated from enum value: solana_localnet = 23; + */ + solana_localnet = 23, } /** @@ -176,6 +191,11 @@ export declare enum Network { * @generated from enum value: base = 6; */ base = 6, + + /** + * @generated from enum value: solana = 7; + */ + solana = 7, } /** @@ -222,6 +242,11 @@ export declare enum Vm { * @generated from enum value: evm = 1; */ evm = 1, + + /** + * @generated from enum value: svm = 2; + */ + svm = 2, } /** @@ -251,6 +276,11 @@ export declare enum Consensus { * @generated from enum value: op_stack = 3; */ op_stack = 3, + + /** + * @generated from enum value: solana_consensus = 4; + */ + solana_consensus = 4, } /** diff --git a/x/observer/types/params.pb.go b/x/observer/types/params.pb.go index 358881c06c..98b425f77e 100644 --- a/x/observer/types/params.pb.go +++ b/x/observer/types/params.pb.go @@ -83,6 +83,7 @@ type ChainParams struct { BallotThreshold github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,14,opt,name=ballot_threshold,json=ballotThreshold,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"ballot_threshold"` MinObserverDelegation github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,15,opt,name=min_observer_delegation,json=minObserverDelegation,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"min_observer_delegation"` IsSupported bool `protobuf:"varint,16,opt,name=is_supported,json=isSupported,proto3" json:"is_supported,omitempty"` + GatewayAddress string `protobuf:"bytes,17,opt,name=gateway_address,json=gatewayAddress,proto3" json:"gateway_address,omitempty"` } func (m *ChainParams) Reset() { *m = ChainParams{} } @@ -202,6 +203,13 @@ func (m *ChainParams) GetIsSupported() bool { return false } +func (m *ChainParams) GetGatewayAddress() string { + if m != nil { + return m.GatewayAddress + } + return "" +} + // Deprecated(v17) type Params struct { // Deprecated(v17):Moved into the emissions module @@ -259,46 +267,47 @@ func init() { } var fileDescriptor_e7fa4666eddf88e5 = []byte{ - // 617 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xc1, 0x4e, 0xd4, 0x40, - 0x18, 0xc7, 0xb7, 0x2e, 0x22, 0xcc, 0x02, 0x0b, 0x0d, 0x6a, 0x81, 0xa4, 0xac, 0x24, 0x6a, 0x43, - 0x42, 0x6b, 0xd0, 0xa3, 0x92, 0xc8, 0x72, 0x21, 0x62, 0x24, 0x05, 0x0f, 0x7a, 0x70, 0x32, 0x3b, - 0x1d, 0xb6, 0x93, 0x6d, 0xe7, 0xdb, 0xcc, 0x4c, 0x11, 0x7c, 0x0a, 0xdf, 0xc1, 0x97, 0xe1, 0xc8, - 0xd1, 0x78, 0x20, 0x06, 0x5e, 0xc4, 0x74, 0x3a, 0x5d, 0x56, 0x30, 0x1c, 0x3c, 0xed, 0xf4, 0xfb, - 0xff, 0xfe, 0xff, 0x7e, 0xb3, 0xf3, 0x75, 0x50, 0xf0, 0x8d, 0x69, 0x42, 0x53, 0xc2, 0x45, 0x64, - 0x56, 0x20, 0x59, 0x04, 0x3d, 0xc5, 0xe4, 0x31, 0x93, 0xd1, 0x90, 0x48, 0x92, 0xab, 0x70, 0x28, - 0x41, 0x83, 0xbb, 0x32, 0x22, 0xc3, 0x9a, 0x0c, 0x6b, 0x72, 0x79, 0xb1, 0x0f, 0x7d, 0x30, 0x5c, - 0x54, 0xae, 0x2a, 0xcb, 0xf2, 0xfa, 0x5d, 0xe1, 0xf5, 0xa2, 0x62, 0xd7, 0xbe, 0xa0, 0x76, 0xb7, - 0x24, 0xf7, 0xcd, 0x3b, 0xf7, 0xb8, 0xd2, 0xee, 0x3b, 0x34, 0x63, 0xcc, 0xb8, 0xea, 0xc3, 0x73, - 0x3a, 0xcd, 0xa0, 0xb5, 0x19, 0x84, 0x77, 0x34, 0x12, 0x8e, 0x65, 0xc4, 0x2d, 0x7a, 0xfd, 0xb0, - 0xf6, 0x63, 0x12, 0xb5, 0xc6, 0x44, 0x77, 0x09, 0x4d, 0x55, 0xe1, 0x3c, 0xf1, 0x5a, 0x1d, 0x27, - 0x68, 0xc6, 0x0f, 0xcc, 0xf3, 0x6e, 0xe2, 0x6e, 0x20, 0x97, 0x82, 0x38, 0xe2, 0x32, 0x27, 0x9a, - 0x83, 0xc0, 0x14, 0x0a, 0xa1, 0x3d, 0xa7, 0xe3, 0x04, 0x13, 0xf1, 0xc2, 0xb8, 0xd2, 0x2d, 0x05, - 0x37, 0x40, 0xf3, 0x7d, 0xa2, 0xf0, 0x50, 0x72, 0xca, 0xb0, 0xe6, 0x74, 0xc0, 0xa4, 0x77, 0xcf, - 0xc0, 0x73, 0x7d, 0xa2, 0xf6, 0xcb, 0xf2, 0xa1, 0xa9, 0xba, 0x4f, 0xd1, 0x1c, 0x17, 0x3d, 0x28, - 0x44, 0x52, 0x73, 0x4d, 0xc3, 0xcd, 0xda, 0xaa, 0xc5, 0x9e, 0xa3, 0x36, 0x14, 0xfa, 0x2f, 0x6e, - 0xa2, 0xca, 0xab, 0xcb, 0x16, 0x5c, 0x47, 0x0b, 0x5f, 0x89, 0xa6, 0x29, 0x2e, 0xf4, 0x09, 0xd4, - 0xe8, 0x7d, 0x83, 0xb6, 0x8d, 0xf0, 0x51, 0x9f, 0x80, 0x65, 0xdf, 0x20, 0x73, 0x80, 0x58, 0xc3, - 0x80, 0x95, 0x5b, 0x12, 0x5a, 0x12, 0xaa, 0x31, 0x49, 0x12, 0xc9, 0x94, 0xf2, 0xa6, 0x3a, 0x4e, - 0x30, 0x1d, 0x7b, 0x25, 0x72, 0x58, 0x12, 0x5d, 0x0b, 0xbc, 0xad, 0x74, 0xf7, 0x35, 0x5a, 0xa6, - 0x20, 0x04, 0xa3, 0x1a, 0xe4, 0x6d, 0xf7, 0x74, 0xe5, 0x1e, 0x11, 0x37, 0xdd, 0x5d, 0xe4, 0x33, - 0x49, 0x37, 0x5f, 0x60, 0x5a, 0x28, 0x0d, 0xc9, 0xe9, 0xed, 0x04, 0x64, 0x12, 0x56, 0x0c, 0xd5, - 0xad, 0xa0, 0x7f, 0xb4, 0x30, 0xfa, 0x5b, 0x14, 0x4d, 0x59, 0x52, 0x64, 0x0c, 0x73, 0xa1, 0x99, - 0x3c, 0x26, 0x99, 0x37, 0x63, 0xce, 0xd0, 0xab, 0x89, 0x03, 0x0b, 0xec, 0x5a, 0xdd, 0xdd, 0x42, - 0x2b, 0xb7, 0xdd, 0x19, 0xc0, 0x80, 0xa4, 0x8c, 0x24, 0xde, 0xac, 0xb1, 0x2f, 0xdd, 0xb4, 0xef, - 0xd5, 0x80, 0xfb, 0x09, 0xcd, 0xf7, 0x48, 0x96, 0x81, 0xc6, 0x3a, 0x95, 0x4c, 0xa5, 0x90, 0x25, - 0xde, 0x5c, 0xd9, 0xf4, 0x76, 0x78, 0x76, 0xb1, 0xda, 0xf8, 0x75, 0xb1, 0xfa, 0xac, 0xcf, 0x75, - 0x5a, 0xf4, 0x42, 0x0a, 0x79, 0x44, 0x41, 0xe5, 0xa0, 0xec, 0xcf, 0x86, 0x4a, 0x06, 0x91, 0x3e, - 0x1d, 0x32, 0x15, 0xee, 0x30, 0x1a, 0xb7, 0xab, 0x9c, 0xc3, 0x3a, 0xc6, 0x3d, 0x42, 0x8f, 0x73, - 0x2e, 0x70, 0x3d, 0xc3, 0x38, 0x61, 0x19, 0xeb, 0x9b, 0x01, 0xf3, 0xda, 0xff, 0xf5, 0x86, 0x87, - 0x39, 0x17, 0x1f, 0x6c, 0xda, 0xce, 0x28, 0xcc, 0x7d, 0x82, 0x66, 0xb8, 0xc2, 0xaa, 0x18, 0x0e, - 0x41, 0x6a, 0x96, 0x78, 0xf3, 0x1d, 0x27, 0x98, 0x8a, 0x5b, 0x5c, 0x1d, 0xd4, 0xa5, 0xb5, 0x2d, - 0x34, 0x69, 0xbf, 0x8f, 0x57, 0xe8, 0x91, 0xdd, 0x6f, 0x4e, 0x74, 0x21, 0xb9, 0x3e, 0xc5, 0xbd, - 0x0c, 0xe8, 0x40, 0x99, 0x99, 0x6d, 0xc6, 0x8b, 0x95, 0xfa, 0xde, 0x8a, 0xdb, 0x46, 0xdb, 0xde, - 0x3d, 0xbb, 0xf4, 0x9d, 0xf3, 0x4b, 0xdf, 0xf9, 0x7d, 0xe9, 0x3b, 0xdf, 0xaf, 0xfc, 0xc6, 0xf9, - 0x95, 0xdf, 0xf8, 0x79, 0xe5, 0x37, 0x3e, 0x47, 0x63, 0xbd, 0x97, 0x53, 0xb6, 0x71, 0xe3, 0x5e, - 0x38, 0xb9, 0xbe, 0x19, 0xcc, 0x46, 0x7a, 0x93, 0xe6, 0x5e, 0x78, 0xf9, 0x27, 0x00, 0x00, 0xff, - 0xff, 0xed, 0x67, 0xea, 0xcb, 0xa2, 0x04, 0x00, 0x00, + // 636 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x41, 0x4f, 0xd4, 0x4e, + 0x18, 0xc6, 0xb7, 0xff, 0xe5, 0x8f, 0x30, 0x0b, 0xbb, 0xd0, 0xa0, 0x16, 0x48, 0xca, 0x4a, 0xa2, + 0x36, 0x24, 0xb4, 0x06, 0x3d, 0x2a, 0x89, 0x2c, 0x17, 0x22, 0x46, 0x52, 0xf0, 0xa0, 0x07, 0x27, + 0xb3, 0xd3, 0xa1, 0x9d, 0x6c, 0xdb, 0x77, 0x33, 0x33, 0x05, 0xd6, 0x4f, 0xe1, 0xc7, 0xe2, 0xe0, + 0x81, 0xa3, 0xf1, 0x40, 0x0c, 0x7c, 0x11, 0xd3, 0xe9, 0x74, 0x59, 0xc1, 0x70, 0xf0, 0xb4, 0xd3, + 0xf7, 0xf9, 0x3d, 0x4f, 0x67, 0xfa, 0xbe, 0x3b, 0xc8, 0xfb, 0xca, 0x14, 0xa1, 0x09, 0xe1, 0x79, + 0xa0, 0x57, 0x20, 0x58, 0x00, 0x7d, 0xc9, 0xc4, 0x09, 0x13, 0xc1, 0x90, 0x08, 0x92, 0x49, 0x7f, + 0x28, 0x40, 0x81, 0xbd, 0x3a, 0x26, 0xfd, 0x9a, 0xf4, 0x6b, 0x72, 0x65, 0x29, 0x86, 0x18, 0x34, + 0x17, 0x94, 0xab, 0xca, 0xb2, 0xb2, 0x71, 0x5f, 0x78, 0xbd, 0xa8, 0xd8, 0xf5, 0x2f, 0xa8, 0xd3, + 0x2b, 0xc9, 0x03, 0xfd, 0xce, 0x7d, 0x2e, 0x95, 0xfd, 0x0e, 0xcd, 0x69, 0x33, 0xae, 0xf6, 0xe1, + 0x58, 0xdd, 0xa6, 0xd7, 0xda, 0xf2, 0xfc, 0x7b, 0x36, 0xe2, 0x4f, 0x64, 0x84, 0x2d, 0x7a, 0xf3, + 0xb0, 0xfe, 0x7d, 0x1a, 0xb5, 0x26, 0x44, 0x7b, 0x19, 0xcd, 0x54, 0xe1, 0x3c, 0x72, 0x5a, 0x5d, + 0xcb, 0x6b, 0x86, 0x0f, 0xf4, 0xf3, 0x5e, 0x64, 0x6f, 0x22, 0x9b, 0x42, 0x7e, 0xcc, 0x45, 0x46, + 0x14, 0x87, 0x1c, 0x53, 0x28, 0x72, 0xe5, 0x58, 0x5d, 0xcb, 0x9b, 0x0a, 0x17, 0x27, 0x95, 0x5e, + 0x29, 0xd8, 0x1e, 0x5a, 0x88, 0x89, 0xc4, 0x43, 0xc1, 0x29, 0xc3, 0x8a, 0xd3, 0x01, 0x13, 0xce, + 0x7f, 0x1a, 0x6e, 0xc7, 0x44, 0x1e, 0x94, 0xe5, 0x23, 0x5d, 0xb5, 0x9f, 0xa2, 0x36, 0xcf, 0xfb, + 0x50, 0xe4, 0x51, 0xcd, 0x35, 0x35, 0x37, 0x6f, 0xaa, 0x06, 0x7b, 0x8e, 0x3a, 0x50, 0xa8, 0x3f, + 0xb8, 0xa9, 0x2a, 0xaf, 0x2e, 0x1b, 0x70, 0x03, 0x2d, 0x9e, 0x12, 0x45, 0x13, 0x5c, 0xa8, 0x33, + 0xa8, 0xd1, 0xff, 0x35, 0xda, 0xd1, 0xc2, 0x47, 0x75, 0x06, 0x86, 0x7d, 0x83, 0x74, 0x03, 0xb1, + 0x82, 0x01, 0x2b, 0x8f, 0x94, 0x2b, 0x41, 0xa8, 0xc2, 0x24, 0x8a, 0x04, 0x93, 0xd2, 0x99, 0xe9, + 0x5a, 0xde, 0x6c, 0xe8, 0x94, 0xc8, 0x51, 0x49, 0xf4, 0x0c, 0xf0, 0xb6, 0xd2, 0xed, 0xd7, 0x68, + 0x85, 0x42, 0x9e, 0x33, 0xaa, 0x40, 0xdc, 0x75, 0xcf, 0x56, 0xee, 0x31, 0x71, 0xdb, 0xdd, 0x43, + 0x2e, 0x13, 0x74, 0xeb, 0x05, 0xa6, 0x85, 0x54, 0x10, 0x8d, 0xee, 0x26, 0x20, 0x9d, 0xb0, 0xaa, + 0xa9, 0x5e, 0x05, 0xfd, 0x65, 0x0b, 0xe3, 0xcf, 0x22, 0x69, 0xc2, 0xa2, 0x22, 0x65, 0x98, 0xe7, + 0x8a, 0x89, 0x13, 0x92, 0x3a, 0x73, 0xba, 0x87, 0x4e, 0x4d, 0x1c, 0x1a, 0x60, 0xcf, 0xe8, 0xf6, + 0x36, 0x5a, 0xbd, 0xeb, 0x4e, 0x01, 0x06, 0x24, 0x61, 0x24, 0x72, 0xe6, 0xb5, 0x7d, 0xf9, 0xb6, + 0x7d, 0xbf, 0x06, 0xec, 0x4f, 0x68, 0xa1, 0x4f, 0xd2, 0x14, 0x14, 0x56, 0x89, 0x60, 0x32, 0x81, + 0x34, 0x72, 0xda, 0xe5, 0xa6, 0x77, 0xfc, 0xf3, 0xcb, 0xb5, 0xc6, 0xcf, 0xcb, 0xb5, 0x67, 0x31, + 0x57, 0x49, 0xd1, 0xf7, 0x29, 0x64, 0x01, 0x05, 0x99, 0x81, 0x34, 0x3f, 0x9b, 0x32, 0x1a, 0x04, + 0x6a, 0x34, 0x64, 0xd2, 0xdf, 0x65, 0x34, 0xec, 0x54, 0x39, 0x47, 0x75, 0x8c, 0x7d, 0x8c, 0x1e, + 0x67, 0x3c, 0xc7, 0xf5, 0x0c, 0xe3, 0x88, 0xa5, 0x2c, 0xd6, 0x03, 0xe6, 0x74, 0xfe, 0xe9, 0x0d, + 0x0f, 0x33, 0x9e, 0x7f, 0x30, 0x69, 0xbb, 0xe3, 0x30, 0xfb, 0x09, 0x9a, 0xe3, 0x12, 0xcb, 0x62, + 0x38, 0x04, 0xa1, 0x58, 0xe4, 0x2c, 0x74, 0x2d, 0x6f, 0x26, 0x6c, 0x71, 0x79, 0x58, 0x97, 0xca, + 0xd1, 0x8b, 0x89, 0x62, 0xa7, 0x64, 0x34, 0xee, 0xcc, 0xa2, 0xee, 0x4c, 0xdb, 0x94, 0x4d, 0x33, + 0xd6, 0xb7, 0xd1, 0xb4, 0xf9, 0x23, 0xbd, 0x42, 0x8f, 0xcc, 0x87, 0xc9, 0x88, 0x2a, 0x04, 0x57, + 0x23, 0xdc, 0x4f, 0x81, 0x0e, 0xa4, 0x1e, 0xee, 0x66, 0xb8, 0x54, 0xa9, 0xef, 0x8d, 0xb8, 0xa3, + 0xb5, 0x9d, 0xbd, 0xf3, 0x2b, 0xd7, 0xba, 0xb8, 0x72, 0xad, 0x5f, 0x57, 0xae, 0xf5, 0xed, 0xda, + 0x6d, 0x5c, 0x5c, 0xbb, 0x8d, 0x1f, 0xd7, 0x6e, 0xe3, 0x73, 0x30, 0x71, 0xc8, 0x72, 0x1c, 0x37, + 0x6f, 0x5d, 0x20, 0x67, 0x37, 0x57, 0x88, 0x3e, 0x71, 0x7f, 0x5a, 0x5f, 0x20, 0x2f, 0x7f, 0x07, + 0x00, 0x00, 0xff, 0xff, 0xf4, 0x06, 0xb1, 0x0a, 0xcb, 0x04, 0x00, 0x00, } func (m *ChainParamsList) Marshal() (dAtA []byte, err error) { @@ -358,6 +367,15 @@ func (m *ChainParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.GatewayAddress) > 0 { + i -= len(m.GatewayAddress) + copy(dAtA[i:], m.GatewayAddress) + i = encodeVarintParams(dAtA, i, uint64(len(m.GatewayAddress))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + } if m.IsSupported { i-- if m.IsSupported { @@ -557,6 +575,10 @@ func (m *ChainParams) Size() (n int) { if m.IsSupported { n += 3 } + l = len(m.GatewayAddress) + if l > 0 { + n += 2 + l + sovParams(uint64(l)) + } return n } @@ -1027,6 +1049,38 @@ func (m *ChainParams) Unmarshal(dAtA []byte) error { } } m.IsSupported = bool(v != 0) + case 17: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GatewayAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GatewayAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) From d4bec8b2e1f4d13e424ad5222888c0e6592411d9 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Tue, 2 Jul 2024 10:19:56 -0700 Subject: [PATCH 23/23] ci: add build cache to e2e (#2412) * ci: add build cache to e2e * fix docker login conditional --- .github/workflows/build.yml | 71 +++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fc58eb6c56..0d316ebfb3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -106,38 +106,57 @@ jobs: timeout-minutes: 25 steps: - uses: actions/checkout@v4 + + # configure docker to use the containerd snapshotter + # so that we can use the buildkit cache + - uses: depot/use-containerd-snapshotter-action@v1 - - name: Set CPU Architecture - shell: bash - run: | - if [ "$(uname -m)" == "aarch64" ]; then - echo "CPU_ARCH=arm64" >> $GITHUB_ENV - elif [ "$(uname -m)" == "x86_64" ]; then - echo "CPU_ARCH=amd64" >> $GITHUB_ENV - else - echo "Unsupported architecture" >&2 - exit 1 - fi + - name: Login to Docker Hub registry + uses: docker/login-action@v2 + if: (github.event_name == 'push' && github.repository == 'zeta-chain/node') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'zeta-chain/node') + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_READ_ONLY }} - - name: Install Pipeline Dependencies - uses: ./.github/actions/install-dependencies - timeout-minutes: 8 + - name: Login to github docker registry + uses: docker/login-action@v2 with: - cpu_architecture: ${{ env.CPU_ARCH }} - skip_python: "false" - skip_aws_cli: "true" - skip_docker_compose: "false" + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} - - run: | - echo "github.repository: ${{ github.repository }}" - echo "github.event.pull_request.head.repo.full_name: ${{ github.event.pull_request.head.repo.full_name }}" + - name: Restore go cache + uses: actions/cache@v4 + id: restore-go-cache + with: + path: | + go-cache + key: cache-${{ hashFiles('go.sum') }} + lookup-only: ${{ github.event_name != 'push' }} - - name: Login to Docker Hub - uses: docker/login-action@v2 - if: github.event_name != 'pull_request' || github.repository == github.event.pull_request.head.repo.full_name + - name: Inject go cache into docker + uses: reproducible-containers/buildkit-cache-dance@v3.1.2 with: - username: ${{ secrets.DOCKER_HUB_USERNAME }} - password: ${{ secrets.DOCKER_HUB_READ_ONLY }} + cache-map: | + { + "go-cache": "/root/.cache/go-build" + } + skip-extraction: ${{ steps.restore-go-cache.outputs.cache-hit || github.event_name != 'push' }} + + # build zetanode with cache options + - name: Build zetanode for cache + uses: docker/build-push-action@v6 + env: + CACHE_FROM_CONFIG: "type=registry,ref=ghcr.io/${{ github.repository }}:buildcache" + CACHE_TO_CONFIG: "type=registry,ref=ghcr.io/${{ github.repository }}:buildcache,mode=max" + with: + context: . + file: ./Dockerfile-localnet + push: false + tags: zetanode:latest + cache-from: ${{ env.CACHE_FROM_CONFIG }} + cache-to: ${{ github.event_name == 'push' && env.CACHE_TO_CONFIG || '' }} + target: latest-runtime - name: Start Test run: make start-e2e-test