diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index d60a8f4711..580c60e08d 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -28,9 +28,9 @@ inputs: runs: using: "composite" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 if: ${{ inputs.skip_go == 'false' }} with: go-version: '1.20' diff --git a/.github/actions/set-branch-name/action.yml b/.github/actions/set-branch-name/action.yml index 076f60cb93..94412fb63f 100644 --- a/.github/actions/set-branch-name/action.yml +++ b/.github/actions/set-branch-name/action.yml @@ -19,7 +19,7 @@ inputs: runs: using: "composite" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set branch name id: set-branch-name diff --git a/.github/actions/upgrade-testing/action.yml b/.github/actions/upgrade-testing/action.yml index da9019e8df..55ba9f8524 100644 --- a/.github/actions/upgrade-testing/action.yml +++ b/.github/actions/upgrade-testing/action.yml @@ -8,7 +8,7 @@ inputs: runs: using: "composite" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 83ef3e964c..4fdd5c2149 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,12 +25,12 @@ env: jobs: build-and-test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-20.04 timeout-minutes: 15 concurrency: group: "build-and-test" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set CPU Architecture shell: bash @@ -54,7 +54,7 @@ jobs: skip_docker_compose: "false" - name: Test - uses: nick-fields/retry@v2 + uses: nick-fields/retry@v3 with: timeout_minutes: 20 max_attempts: 2 @@ -82,16 +82,30 @@ jobs: chmod a+x ./zetacored ./zetacored version + - name: Upload zetacored + uses: actions/upload-artifact@v4 + with: + name: zetacored + path: ~/go/bin/zetacored + retention-days: 30 + + - name: Upload zetaclientd + uses: actions/upload-artifact@v4 + with: + name: zetaclientd + path: ~/go/bin/zetaclientd + retention-days: 30 + - name: Clean Up Workspace if: always() shell: bash run: rm -rf * e2e-test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-20.04 timeout-minutes: 25 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set CPU Architecture shell: bash diff --git a/.github/workflows/change-log-check.yml b/.github/workflows/change-log-check.yml index e720c4ac68..dd3a98d4bf 100644 --- a/.github/workflows/change-log-check.yml +++ b/.github/workflows/change-log-check.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/docker-build-and-push.yml b/.github/workflows/docker-build-and-push.yml index ef2f147c3d..397affe896 100644 --- a/.github/workflows/docker-build-and-push.yml +++ b/.github/workflows/docker-build-and-push.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -57,7 +57,7 @@ jobs: runs-on: buildjet-4vcpu-ubuntu-2204-arm timeout-minutes: 30 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/execute_advanced_tests.yaml b/.github/workflows/execute_advanced_tests.yaml index 201fcc829f..e42d08e9d6 100644 --- a/.github/workflows/execute_advanced_tests.yaml +++ b/.github/workflows/execute_advanced_tests.yaml @@ -35,7 +35,7 @@ jobs: timeout-minutes: 120 steps: - name: "Checkout Code" - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Start Test run: make start-e2e-admin-test @@ -68,7 +68,7 @@ jobs: timeout-minutes: 120 steps: - name: "Checkout Code" - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Start Test run: make start-upgrade-test @@ -100,7 +100,7 @@ jobs: timeout-minutes: 120 steps: - name: "Checkout Code" - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Start Test run: make start-upgrade-test-light @@ -123,7 +123,7 @@ jobs: timeout-minutes: 120 steps: - name: "Checkout Code" - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Start Test run: make start-e2e-performance-test diff --git a/.github/workflows/generate-files.yml b/.github/workflows/generate-files.yml index 032a44e818..1a948ceb96 100644 --- a/.github/workflows/generate-files.yml +++ b/.github/workflows/generate-files.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - uses: bufbuild/buf-setup-action@v1 diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index d2b75106e4..ef58c59c31 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -40,13 +40,13 @@ jobs: steps: - name: Checkout Source if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: '1.20' @@ -71,13 +71,13 @@ jobs: steps: - name: Checkout Source if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: '1.20' @@ -101,13 +101,13 @@ jobs: steps: - name: Checkout Source if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: '1.20' @@ -133,7 +133,7 @@ jobs: - name: Checkout code if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -174,7 +174,7 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 if: ${{ github.event.inputs.skip_checks != 'true' }} with: fetch-depth: 0 @@ -209,7 +209,7 @@ jobs: steps: - name: "Checkout Code" if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set CPU Architecture if: ${{ github.event.inputs.skip_checks != 'true' }} @@ -284,7 +284,7 @@ jobs: steps: - name: "Checkout Code" if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set CPU Architecture if: ${{ github.event.inputs.skip_checks != 'true' }} @@ -362,7 +362,7 @@ jobs: steps: - name: "Checkout Code" if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Execute e2e-admin-tests if: ${{ github.event.inputs.skip_checks != 'true' }} @@ -384,7 +384,7 @@ jobs: steps: - name: "Checkout Code" if: ${{ github.event.inputs.skip_checks != 'true' }} - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Execute upgrade-test if: ${{ github.event.inputs.skip_checks != 'true' }} @@ -415,7 +415,7 @@ jobs: timeout-minutes: 60 environment: release steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Pipeline Dependencies uses: ./.github/actions/install-dependencies diff --git a/.github/workflows/rc-release.yml b/.github/workflows/rc-release.yml index ceb529300e..04257ef171 100644 --- a/.github/workflows/rc-release.yml +++ b/.github/workflows/rc-release.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -39,7 +39,7 @@ jobs: needs: - pre-release-checks steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set CPU Architecture shell: bash diff --git a/.github/workflows/sast-linters.yml b/.github/workflows/sast-linters.yml index b2f4d7f646..5f754ba1ac 100644 --- a/.github/workflows/sast-linters.yml +++ b/.github/workflows/sast-linters.yml @@ -20,12 +20,12 @@ jobs: GO111MODULE: on steps: - name: Checkout Source - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: '1.20' @@ -40,12 +40,12 @@ jobs: GO111MODULE: on steps: - name: Checkout Source - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: '1.20' @@ -59,12 +59,12 @@ jobs: GO111MODULE: on steps: - name: Checkout Source - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: '1.20' diff --git a/.github/workflows/upgrade_path_testing.yaml b/.github/workflows/upgrade_path_testing.yaml index 681e6a28dc..a4a2af9204 100644 --- a/.github/workflows/upgrade_path_testing.yaml +++ b/.github/workflows/upgrade_path_testing.yaml @@ -66,7 +66,7 @@ jobs: with: version: 2 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: check-latest: false go-version: '^1.20' diff --git a/changelog.md b/changelog.md index b044150dc8..1e6c8b2614 100644 --- a/changelog.md +++ b/changelog.md @@ -19,13 +19,14 @@ ### Refactor * [2094](https://github.com/zeta-chain/node/pull/2094) - upgrade go-tss to use cosmos v0.47 -* [2110](https://github.com/zeta-chain/node/pull/2110) - move non-query rate limiter logic to zetaclient side and code refactor. +* [2110](https://github.com/zeta-chain/node/pull/2110) - move non-query rate limiter logic to zetaclient side and code refactor * [2032](https://github.com/zeta-chain/node/pull/2032) - improve some general structure of the ZetaClient codebase * [2097](https://github.com/zeta-chain/node/pull/2097) - refactor lightclient verification flags to account for individual chains * [2071](https://github.com/zeta-chain/node/pull/2071) - Modify chains struct to add all chain related information * [2118](https://github.com/zeta-chain/node/pull/2118) - consolidate inbound and outbound naming * [2124](https://github.com/zeta-chain/node/pull/2124) - removed unused variables and method -* [2150](https://github.com/zeta-chain/node/pull/2150) - created `chains` `zetacore` `orchestrator` packages in zetaclient and reorganized source files accordingly. +* [2150](https://github.com/zeta-chain/node/pull/2150) - created `chains` `zetacore` `orchestrator` packages in zetaclient and reorganized source files accordingly +* [2210](https://github.com/zeta-chain/node/pull/2210) - removed uncessary panics in the zetaclientd process * [2205](https://github.com/zeta-chain/node/pull/2205) - remove deprecated variables pre-v17 ### Tests diff --git a/cmd/zetaclientd-supervisor/main.go b/cmd/zetaclientd-supervisor/main.go index b8ce42ea5e..e3a1c301e5 100644 --- a/cmd/zetaclientd-supervisor/main.go +++ b/cmd/zetaclientd-supervisor/main.go @@ -16,10 +16,13 @@ import ( ) func main() { + // load zetaclient config cfg, err := config.Load(app.DefaultNodeHome) if err != nil { - panic(fmt.Errorf("failed to load config: %w", err)) + fmt.Println("failed to load config: ", err) + os.Exit(1) } + // log outputs must be serialized since we are writing log messages in this process and // also directly from the zetaclient process serializedStdout := &serializedWriter{upstream: os.Stdout} @@ -38,13 +41,15 @@ func main() { hotkeyPassword, tssPassword, err := promptPasswords() if err != nil { - panic(fmt.Errorf("unable to get passwords: %w", err)) + logger.Error().Err(err).Msg("unable to get passwords") + os.Exit(1) } _, enableAutoDownload := os.LookupEnv("ZETACLIENTD_SUPERVISOR_ENABLE_AUTO_DOWNLOAD") supervisor, err := newZetaclientdSupervisor(cfg.ZetaCoreURL, logger, enableAutoDownload) if err != nil { - panic(fmt.Errorf("unable to get supervisor: %w", err)) + logger.Error().Err(err).Msg("unable to get supervisor") + os.Exit(1) } supervisor.Start(ctx) diff --git a/cmd/zetaclientd/debug.go b/cmd/zetaclientd/debug.go index 1d778e2ffc..8d64e77f29 100644 --- a/cmd/zetaclientd/debug.go +++ b/cmd/zetaclientd/debug.go @@ -24,7 +24,6 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/config" clientcontext "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/zetacore" ) @@ -62,22 +61,14 @@ func DebugCmd() *cobra.Command { var ballotIdentifier string chainLogger := zerolog.New(io.Discard).Level(zerolog.Disabled) - telemetryServer := metrics.NewTelemetryServer() - go func() { - err := telemetryServer.Start() - if err != nil { - panic("telemetryServer error") - } - }() - + // create a new zetacore client client, err := zetacore.NewClient( &keys.Keys{OperatorAddress: sdk.MustAccAddressFromBech32(sample.AccAddress())}, debugArgs.zetaNode, "", debugArgs.zetaChainID, false, - telemetryServer) - + nil) if err != nil { return err } @@ -89,14 +80,13 @@ func DebugCmd() *cobra.Command { if err != nil { return err } - chain := chains.GetChainFromChainID(chainID) if chain == nil { return fmt.Errorf("invalid chain id") } + // get ballot identifier according to the chain type if chains.IsEVMChain(chain.ChainId) { - evmObserver := evmobserver.Observer{ Mu: &sync.Mutex{}, } @@ -204,6 +194,7 @@ func DebugCmd() *cobra.Command { } fmt.Println("BallotIdentifier : ", ballotIdentifier) + // query ballot ballot, err := client.GetBallot(ballotIdentifier) if err != nil { return err diff --git a/cmd/zetaclientd/p2p_diagnostics.go b/cmd/zetaclientd/p2p_diagnostics.go index 8794be30d1..0c112861e1 100644 --- a/cmd/zetaclientd/p2p_diagnostics.go +++ b/cmd/zetaclientd/p2p_diagnostics.go @@ -151,68 +151,70 @@ func RunDiagnostics(startLogger zerolog.Logger, peers p2p.AddrList, hotkeyPk cry // every 1min, print out the p2p diagnostic ticker := time.NewTicker(time.Duration(cfg.P2PDiagnosticTicker) * time.Second) round := 0 - for { - select { - case <-ticker.C: - round++ - // Now, look for others who have announced - // This is like your friend telling you the location to meet you. - startLogger.Info().Msgf("Searching for other peers...") - peerChan, err := routingDiscovery.FindPeers(context.Background(), "ZetaZetaOpenTheDoor") + + for range ticker.C { + round++ + // Now, look for others who have announced + // This is like your friend telling you the location to meet you. + startLogger.Info().Msgf("Searching for other peers...") + peerChan, err := routingDiscovery.FindPeers(context.Background(), "ZetaZetaOpenTheDoor") + if err != nil { + return err + } + + peerCount := 0 + okPingPongCount := 0 + for peer := range peerChan { + peerCount++ + if peer.ID == host.ID() { + startLogger.Info().Msgf("Found myself #(%d): %s", peerCount, peer) + continue + } + startLogger.Info().Msgf("Found peer #(%d): %s; pinging the peer...", peerCount, peer) + stream, err := host.NewStream(context.Background(), peer.ID, protocol.ID(ProtocolID)) if err != nil { - panic(err) + startLogger.Error().Err(err).Msgf("fail to create stream to peer %s", peer) + continue } - peerCount := 0 - okPingPongCount := 0 - for peer := range peerChan { - peerCount++ - if peer.ID == host.ID() { - startLogger.Info().Msgf("Found myself #(%d): %s", peerCount, peer) - continue - } - startLogger.Info().Msgf("Found peer #(%d): %s; pinging the peer...", peerCount, peer) - stream, err := host.NewStream(context.Background(), peer.ID, protocol.ID(ProtocolID)) - if err != nil { - startLogger.Error().Err(err).Msgf("fail to create stream to peer %s", peer) - continue - } - message := fmt.Sprintf("round %d %s => %s", round, host.ID().String()[len(host.ID().String())-5:], peer.ID.String()[len(peer.ID.String())-5:]) - _, err = stream.Write([]byte(message)) - if err != nil { - startLogger.Error().Err(err).Msgf("fail to write to stream to peer %s", peer) - err = stream.Close() - if err != nil { - startLogger.Warn().Err(err).Msgf("fail to close stream to peer %s", peer) - } - continue - } - //startLogger.Debug().Msgf("wrote %d bytes", nw) - buf := make([]byte, 1024) - nr, err := stream.Read(buf) + // write a message to the stream + message := fmt.Sprintf("round %d %s => %s", round, host.ID().String()[len(host.ID().String())-5:], peer.ID.String()[len(peer.ID.String())-5:]) + _, err = stream.Write([]byte(message)) + if err != nil { + startLogger.Error().Err(err).Msgf("fail to write to stream to peer %s", peer) + err = stream.Close() if err != nil { - startLogger.Error().Err(err).Msgf("fail to read from stream to peer %s", peer) - err = stream.Close() - if err != nil { - startLogger.Warn().Err(err).Msgf("fail to close stream to peer %s", peer) - } - continue + startLogger.Warn().Err(err).Msgf("fail to close stream to peer %s", peer) } - //startLogger.Debug().Msgf("read %d bytes", nr) - startLogger.Debug().Msgf("echoed message: %s", string(buf[:nr])) + continue + } + + // read the echoed message + buf := make([]byte, 1024) + nr, err := stream.Read(buf) + if err != nil { + startLogger.Error().Err(err).Msgf("fail to read from stream to peer %s", peer) err = stream.Close() if err != nil { startLogger.Warn().Err(err).Msgf("fail to close stream to peer %s", peer) } + continue + } + startLogger.Debug().Msgf("echoed message: %s", string(buf[:nr])) + err = stream.Close() + if err != nil { + startLogger.Warn().Err(err).Msgf("fail to close stream to peer %s", peer) + } - if string(buf[:nr]) != message { - startLogger.Error().Msgf("ping-pong failed with peer #(%d): %s; want %s got %s", peerCount, peer, message, string(buf[:nr])) - continue - } - startLogger.Info().Msgf("ping-pong success with peer #(%d): %s;", peerCount, peer) - okPingPongCount++ + // check if the message is echoed correctly + if string(buf[:nr]) != message { + startLogger.Error().Msgf("ping-pong failed with peer #(%d): %s; want %s got %s", peerCount, peer, message, string(buf[:nr])) + continue } - startLogger.Info().Msgf("Expect %d peers in total; successful pings (%d/%d)", peerCount, okPingPongCount, peerCount-1) + startLogger.Info().Msgf("ping-pong success with peer #(%d): %s;", peerCount, peer) + okPingPongCount++ } + startLogger.Info().Msgf("Expect %d peers in total; successful pings (%d/%d)", peerCount, okPingPongCount, peerCount-1) } + return nil } diff --git a/cmd/zetaclientd/start.go b/cmd/zetaclientd/start.go index b16b9b7888..3448db3ed3 100644 --- a/cmd/zetaclientd/start.go +++ b/cmd/zetaclientd/start.go @@ -91,24 +91,38 @@ func start(_ *cobra.Command, _ []string) error { } }() - // CreateZetaCoreClient: zetacore client is used for all communication to zetacore , which this client connects to. + // CreateZetacoreClient: zetacore client is used for all communication to zetacore , which this client connects to. // Zetacore accumulates votes , and provides a centralized source of truth for all clients - zetacoreClient, err := CreateZetaCoreClient(cfg, telemetryServer, hotkeyPass) + zetacoreClient, err := CreateZetacoreClient(cfg, telemetryServer, hotkeyPass) if err != nil { - panic(err) + startLogger.Error().Err(err).Msg("CreateZetacoreClient error") + return err + } + + // Wait until zetacore is ready to create blocks + err = zetacoreClient.WaitForZetacoreToCreateBlocks() + if err != nil { + startLogger.Error().Err(err).Msg("WaitForZetacoreToCreateBlocks error") + return err } - zetacoreClient.WaitForCoreToCreateBlocks() startLogger.Info().Msgf("Zetacore client is ready") - zetacoreClient.SetAccountNumber(authz.ZetaClientGranteeKey) + + // Set grantee account number and sequence number + err = zetacoreClient.SetAccountNumber(authz.ZetaClientGranteeKey) + if err != nil { + startLogger.Error().Err(err).Msg("SetAccountNumber error") + return err + } // cross-check chainid res, err := zetacoreClient.GetNodeInfo() if err != nil { - panic(err) + startLogger.Error().Err(err).Msg("GetNodeInfo error") + return err } if strings.Compare(res.GetDefaultNodeInfo().Network, cfg.ChainID) != 0 { - startLogger.Warn().Msgf("chain id mismatch, zeta-core chain id %s, zeta client chain id %s; reset zeta client chain id", res.GetDefaultNodeInfo().Network, cfg.ChainID) + startLogger.Warn().Msgf("chain id mismatch, zetacore chain id %s, zetaclient configured chain id %s; reset zetaclient chain id", res.GetDefaultNodeInfo().Network, cfg.ChainID) cfg.ChainID = res.GetDefaultNodeInfo().Network err := zetacoreClient.UpdateChainID(cfg.ChainID) if err != nil { @@ -118,7 +132,12 @@ func start(_ *cobra.Command, _ []string) error { // CreateAuthzSigner : which is used to sign all authz messages . All votes broadcast to zetacore are wrapped in authz exec . // This is to ensure that the user does not need to keep their operator key online , and can use a cold key to sign votes - CreateAuthzSigner(zetacoreClient.GetKeys().GetOperatorAddress().String(), zetacoreClient.GetKeys().GetAddress()) + signerAddress, err := zetacoreClient.GetKeys().GetAddress() + if err != nil { + startLogger.Error().Err(err).Msg("error getting signer address") + return err + } + CreateAuthzSigner(zetacoreClient.GetKeys().GetOperatorAddress().String(), signerAddress) startLogger.Debug().Msgf("CreateAuthzSigner is ready") // Initialize core parameters from zetacore @@ -265,8 +284,12 @@ func start(_ *cobra.Command, _ []string) error { } // Orchestrator wraps the zetacore client and adds the observers and signer maps to it . This is the high level object used for CCTX interactions - mo1 := orchestrator.NewOrchestrator(zetacoreClient, signerMap, observerMap, masterLogger, telemetryServer) - mo1.MonitorCore(appContext) + orchestrator := orchestrator.NewOrchestrator(zetacoreClient, signerMap, observerMap, masterLogger, telemetryServer) + err = orchestrator.MonitorCore(appContext) + if err != nil { + startLogger.Error().Err(err).Msg("Orchestrator failed to start") + return err + } // start zeta supply checker // TODO: enable diff --git a/cmd/zetaclientd/utils.go b/cmd/zetaclientd/utils.go index 7f4ec66ce0..af8af41f1c 100644 --- a/cmd/zetaclientd/utils.go +++ b/cmd/zetaclientd/utils.go @@ -21,7 +21,7 @@ func CreateAuthzSigner(granter string, grantee sdk.AccAddress) { authz.SetupAuthZSignerList(granter, grantee) } -func CreateZetaCoreClient(cfg config.Config, telemetry *metrics.TelemetryServer, hotkeyPassword string) (*zetacore.Client, error) { +func CreateZetacoreClient(cfg config.Config, telemetry *metrics.TelemetryServer, hotkeyPassword string) (*zetacore.Client, error) { hotKey := cfg.AuthzHotkey if cfg.HsmMode { hotKey = cfg.HsmHotKey diff --git a/cmd/zetacore_utils/main.go b/cmd/zetacore_utils/main.go index f7dcff1e67..74395a51b8 100644 --- a/cmd/zetacore_utils/main.go +++ b/cmd/zetacore_utils/main.go @@ -36,20 +36,24 @@ type TokenDistribution struct { func main() { file, err := filepath.Abs(filepath.Join("cmd", "zetacore_utils", "address-list.json")) if err != nil { - panic(err) + fmt.Printf("error getting absolute path of address-list.json: %s\n", err) + os.Exit(1) } addresses, err := readLines(file) if err != nil { - panic(err) + fmt.Printf("error read file: %s\n", err) + os.Exit(1) } addresses = removeDuplicates(addresses) fileS, err := filepath.Abs(filepath.Join("cmd", "zetacore_utils", "successful_address.json")) if err != nil { - panic(err) + fmt.Printf("error getting absolute path of successful_address.json: %s\n", err) + os.Exit(1) } fileF, err := filepath.Abs(filepath.Join("cmd", "zetacore_utils", "failed_address.json")) if err != nil { - panic(err) + fmt.Printf("error getting absolute path of failed_address.json: %s\n", err) + os.Exit(1) } distributionList := make([]TokenDistribution, len(addresses)) @@ -59,17 +63,19 @@ func main() { output, err := cmd.CombinedOutput() if err != nil { fmt.Println(cmd.String()) - fmt.Println(fmt.Sprint(err) + ": " + string(output)) - return + fmt.Printf("error getting balance for address %s: %s\n", address, string(output)) + os.Exit(1) } balance := sdk.Coin{} err = json.Unmarshal(output, &balance) if err != nil { - panic(err) + fmt.Printf("error unmarshal balance for address %s: %s\n", address, err) + os.Exit(1) } distributionAmount, ok := sdkmath.NewIntFromString(amount) if !ok { - panic("parse error for amount") + fmt.Printf("error unmarshalling amount: %s\n", amount) + os.Exit(1) } distributionList[i] = TokenDistribution{ Address: address, @@ -79,10 +85,7 @@ func main() { } args := []string{"tx", "bank", "multi-send", signer} - for _, address := range addresses { - args = append(args, address) - } - + args = append(args, addresses...) args = append(args, []string{distributionList[0].TokensDistributed.String(), "--keyring-backend", "test", "--chain-id", chainID, "--yes", "--broadcast-mode", broadcastMode, "--gas=auto", "--gas-adjustment=2", "--gas-prices=0.001azeta", "--node", node}...) @@ -91,8 +94,8 @@ func main() { output, err := cmd.CombinedOutput() if err != nil { fmt.Println(cmd.String()) - fmt.Println(fmt.Sprint(err) + ": " + string(output)) - return + fmt.Printf("error distributing tokens: %s\n", string(output)) + os.Exit(1) } fmt.Println(string(output)) @@ -104,13 +107,14 @@ func main() { output, err := cmd.CombinedOutput() if err != nil { fmt.Println(cmd.String()) - fmt.Println(fmt.Sprint(err) + ": " + string(output)) - return + fmt.Printf("error getting balance for address %s: %s\n", address, string(output)) + os.Exit(1) } balance := sdk.Coin{} err = json.Unmarshal(output, &balance) if err != nil { - panic(err) + fmt.Printf("error unmarshal balance for address %s: %s\n", address, err) + os.Exit(1) } distributionList[i].BalanceAfter = balance } @@ -125,19 +129,23 @@ func main() { } successFile, err := json.MarshalIndent(successfullDistributions, "", " ") if err != nil { - panic(err) + fmt.Printf("error marshalling successful distributions: %s\n", err) + os.Exit(1) } err = os.WriteFile(fileS, successFile, 0600) if err != nil { - panic(err) + fmt.Printf("error writing successful distributions to file: %s\n", err) + os.Exit(1) } failedFile, err := json.MarshalIndent(failedDistributions, "", " ") if err != nil { - panic(err) + fmt.Printf("error marshalling failed distributions: %s\n", err) + os.Exit(1) } err = os.WriteFile(fileF, failedFile, 0600) if err != nil { - panic(err) + fmt.Printf("error writing failed distributions to file: %s\n", err) + os.Exit(1) } } diff --git a/cmd/zetae2e/config/clients.go b/cmd/zetae2e/config/clients.go index bb8bc85dbb..061520df01 100644 --- a/cmd/zetae2e/config/clients.go +++ b/cmd/zetae2e/config/clients.go @@ -91,20 +91,20 @@ func getBtcClient(rpcConf config.BitcoinRPC) (*rpcclient.Client, error) { func getEVMClient(ctx context.Context, rpc, privKey string) (*ethclient.Client, *bind.TransactOpts, error) { evmClient, err := ethclient.Dial(rpc) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to dial evm client: %w", err) } chainid, err := evmClient.ChainID(ctx) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get chain id: %w", err) } deployerPrivkey, err := crypto.HexToECDSA(privKey) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get deployer privkey: %w", err) } evmAuth, err := bind.NewKeyedTransactorWithChainID(deployerPrivkey, chainid) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get keyed transactor: %w", err) } return evmClient, evmAuth, nil diff --git a/cmd/zetae2e/local/accounts.go b/cmd/zetae2e/local/accounts.go index bcdd741e7f..daf10eabc2 100644 --- a/cmd/zetae2e/local/accounts.go +++ b/cmd/zetae2e/local/accounts.go @@ -13,10 +13,14 @@ var ( UserERC20Address = ethcommon.HexToAddress("0x6F57D5E7c6DBb75e59F1524a3dE38Fc389ec5Fd6") UserERC20PrivateKey = "fda3be1b1517bdf48615bdadacc1e6463d2865868dc8077d2cdcfa4709a16894" // #nosec G101 - used for testing - // UserZetaTestAddress is the address of the account for testing Zeta + // 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 diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 46e3fc91ce..4513901a24 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -265,14 +265,17 @@ func localE2ETest(cmd *cobra.Command, _ []string) { } zetaAdvancedTests := []string{ e2etests.TestZetaDepositRestrictedName, + e2etests.TestZetaDepositName, + e2etests.TestZetaDepositNewAddressName, + } + zevmMPTests := []string{} + zevmMPAdvancedTests := []string{ e2etests.TestMessagePassingZEVMToEVMName, e2etests.TestMessagePassingEVMtoZEVMName, e2etests.TestMessagePassingEVMtoZEVMRevertName, e2etests.TestMessagePassingZEVMtoEVMRevertName, e2etests.TestMessagePassingZEVMtoEVMRevertFailName, e2etests.TestMessagePassingEVMtoZEVMRevertFailName, - e2etests.TestZetaDepositName, - e2etests.TestZetaDepositNewAddressName, } bitcoinTests := []string{ e2etests.TestBitcoinWithdrawSegWitName, @@ -300,6 +303,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { if !light { erc20Tests = append(erc20Tests, erc20AdvancedTests...) zetaTests = append(zetaTests, zetaAdvancedTests...) + zevmMPTests = append(zevmMPTests, zevmMPAdvancedTests...) bitcoinTests = append(bitcoinTests, bitcoinAdvancedTests...) ethereumTests = append(ethereumTests, ethereumAdvancedTests...) } @@ -309,6 +313,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { eg.Go(erc20TestRoutine(conf, deployerRunner, verbose, erc20Tests...)) eg.Go(zetaTestRoutine(conf, deployerRunner, verbose, zetaTests...)) + eg.Go(zevmMPTestRoutine(conf, deployerRunner, verbose, zevmMPTests...)) eg.Go(bitcoinTestRoutine(conf, deployerRunner, verbose, !skipBitcoinSetup, testHeader, bitcoinTests...)) eg.Go(ethereumTestRoutine(conf, deployerRunner, verbose, testHeader, ethereumTests...)) } diff --git a/cmd/zetae2e/local/zevm_mp.go b/cmd/zetae2e/local/zevm_mp.go new file mode 100644 index 0000000000..6200ee512c --- /dev/null +++ b/cmd/zetae2e/local/zevm_mp.go @@ -0,0 +1,77 @@ +package local + +import ( + "fmt" + "runtime" + "time" + + "github.com/fatih/color" + "github.com/zeta-chain/zetacore/e2e/config" + "github.com/zeta-chain/zetacore/e2e/e2etests" + "github.com/zeta-chain/zetacore/e2e/runner" +) + +// zevmMPTestRoutine runs ZEVM message passing related e2e tests +func zevmMPTestRoutine( + conf config.Config, + deployerRunner *runner.E2ERunner, + verbose bool, + 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", + conf, + deployerRunner, + UserZEVMMPTestAddress, + UserZEVMMPTestPrivateKey, + runner.NewLogger(verbose, color.FgHiRed, "zevm_mp"), + ) + if err != nil { + return err + } + + zevmMPRunner.Logger.Print("🏃 starting ZEVM Message Passing tests") + startTime := time.Now() + + // funding the account + txZetaSend := deployerRunner.SendZetaOnEvm(UserZEVMMPTestAddress, 1000) + zevmMPRunner.WaitForTxReceiptOnEvm(txZetaSend) + + // depositing the necessary tokens on ZetaChain + txZetaDeposit := zevmMPRunner.DepositZeta() + txEtherDeposit := zevmMPRunner.DepositEther(false) + zevmMPRunner.WaitForMinedCCTX(txZetaDeposit) + zevmMPRunner.WaitForMinedCCTX(txEtherDeposit) + + // run zevm message passing test + testsToRun, err := zevmMPRunner.GetE2ETestsToRunByName( + e2etests.AllE2ETests, + testNames..., + ) + if err != nil { + return fmt.Errorf("zevm message passing tests failed: %v", err) + } + + if err := zevmMPRunner.RunE2ETests(testsToRun); err != nil { + return fmt.Errorf("zevm message passing tests failed: %v", err) + } + + zevmMPRunner.Logger.Print("🍾 ZEVM message passing tests completed in %s", time.Since(startTime).String()) + + return err + } +} diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index a8e518fe0d..e2c9f07f14 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -46,6 +46,10 @@ geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x6F57D5E7c6DBb75e59F 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 +# 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 + # 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 diff --git a/contrib/localnet/scripts/start-upgrade-orchestrator.sh b/contrib/localnet/scripts/start-upgrade-orchestrator.sh index fdc03fc341..fb7bfe7a52 100755 --- a/contrib/localnet/scripts/start-upgrade-orchestrator.sh +++ b/contrib/localnet/scripts/start-upgrade-orchestrator.sh @@ -5,6 +5,13 @@ UPGRADE_HEIGHT=$1 CHAINID="athens_101-1" UPGRADE_AUTHORITY_ACCOUNT="zeta10d07y265gmmuvt4z0w9aw880jnsr700jvxasvr" +if [[ -z $ZETACORED_URL ]]; then + ZETACORED_URL='http://upgrade-host:8000/zetacored' +fi +if [[ -z $ZETACLIENTD_URL ]]; then + ZETACLIENTD_URL='http://upgrade-host:8000/zetaclientd' +fi + # Wait for authorized_keys file to exist (populated by zetacore0) while [ ! -f ~/.ssh/authorized_keys ]; do echo "Waiting for authorized_keys file to exist..." @@ -32,7 +39,7 @@ if [[ $(hostname) != "zetacore0" ]]; then fi # get new zetacored version -curl -o /tmp/zetacored.new http://upgrade-host:8000/zetacored +curl -L -o /tmp/zetacored.new "${ZETACORED_URL}" chmod +x /tmp/zetacored.new UPGRADE_NAME=$(/tmp/zetacored.new version) @@ -77,8 +84,8 @@ esac cat > upgrade_plan_info.json < 1 { - // get depositor fee - depositorFee := bitcoin.CalcDepositorFee(res.Block, ob.chain.ChainId, ob.netParams, ob.logger.Inbound) - - // filter incoming txs to TSS address - tssAddress := ob.Tss.BTCAddress() - // #nosec G701 always positive - inbounds, err := FilterAndParseIncomingTx( - ob.rpcClient, - res.Block.Tx, - uint64(res.Block.Height), - tssAddress, - ob.logger.Inbound, - ob.netParams, - depositorFee, - ) - if err != nil { - ob.logger.Inbound.Error().Err(err).Msgf("observeInboundBTC: error filtering incoming txs for block %d", blockNumber) - return err // we have to re-scan this block next time - } - - // post inbound vote message to zetacore - for _, inbound := range inbounds { - msg := ob.GetInboundVoteMessageFromBtcEvent(inbound) - if msg != nil { - zetaHash, ballot, err := ob.zetacoreClient.PostVoteInbound(zetacore.PostVoteInboundGasLimit, zetacore.PostVoteInboundExecutionGasLimit, msg) - if err != nil { - ob.logger.Inbound.Error().Err(err).Msgf("observeInboundBTC: error posting to zetacore for tx %s", inbound.TxHash) - return err // we have to re-scan this block next time - } else if zetaHash != "" { - ob.logger.Inbound.Info().Msgf("observeInboundBTC: PostVoteInbound zeta tx hash: %s inbound %s ballot %s fee %v", - zetaHash, inbound.TxHash, ballot, depositorFee) - } - } - } - } - - // Save LastBlockHeight - ob.SetLastBlockHeightScanned(blockNumber) - // #nosec G701 always positive inbounds, err := FilterAndParseIncomingTx( ob.rpcClient, diff --git a/zetaclient/chains/bitcoin/observer/live_test.go b/zetaclient/chains/bitcoin/observer/live_test.go index 0c19d59de4..8a1a000e88 100644 --- a/zetaclient/chains/bitcoin/observer/live_test.go +++ b/zetaclient/chains/bitcoin/observer/live_test.go @@ -416,7 +416,7 @@ BLOCKLOOP: continue BLOCKLOOP // retry the block } if senderAddr != mpvin.Prevout.ScriptpubkeyAddress { - panic(fmt.Sprintf("block %d, tx %s, vout %d: want %s, got %s\n", bn, vin.Txid, vin.Vout, mpvin.Prevout.ScriptpubkeyAddress, senderAddr)) + t.Errorf("block %d, tx %s, vout %d: want %s, got %s\n", bn, vin.Txid, vin.Vout, mpvin.Prevout.ScriptpubkeyAddress, senderAddr) } else { fmt.Printf("block: %d sender address type: %s\n", bn, mpvin.Prevout.ScriptpubkeyType) } diff --git a/zetaclient/chains/bitcoin/observer/observer.go b/zetaclient/chains/bitcoin/observer/observer.go index d41f27f791..dd52de0b2b 100644 --- a/zetaclient/chains/bitcoin/observer/observer.go +++ b/zetaclient/chains/bitcoin/observer/observer.go @@ -341,34 +341,20 @@ func (ob *Observer) Stop() { } func (ob *Observer) SetLastBlockHeight(height int64) { - if height < 0 { - panic("lastBlock is negative") - } atomic.StoreInt64(&ob.lastBlock, height) } func (ob *Observer) GetLastBlockHeight() int64 { - height := atomic.LoadInt64(&ob.lastBlock) - if height < 0 { - panic("lastBlock is negative") - } - return height + return atomic.LoadInt64(&ob.lastBlock) } func (ob *Observer) SetLastBlockHeightScanned(height int64) { - if height < 0 { - panic("lastBlockScanned is negative") - } atomic.StoreInt64(&ob.lastBlockScanned, height) metrics.LastScannedBlockNumber.WithLabelValues(ob.chain.ChainName.String()).Set(float64(height)) } func (ob *Observer) GetLastBlockHeightScanned() int64 { - height := atomic.LoadInt64(&ob.lastBlockScanned) - if height < 0 { - panic("lastBlockScanned is negative") - } - return height + return atomic.LoadInt64(&ob.lastBlockScanned) } func (ob *Observer) GetPendingNonce() uint64 { @@ -549,7 +535,7 @@ func (ob *Observer) WatchUTXOS() { func (ob *Observer) FetchUTXOS() error { defer func() { if err := recover(); err != nil { - ob.logger.UTXOS.Error().Msgf("BTC fetchUTXOS: caught panic error: %v", err) + ob.logger.UTXOS.Error().Msgf("BTC FetchUTXOS: caught panic error: %v", err) } }() @@ -678,10 +664,14 @@ func (ob *Observer) BuildBroadcastedTxMap() error { // LoadLastBlock loads last scanned block from DB func (ob *Observer) LoadLastBlock() error { + // Get the latest block number from node bn, err := ob.rpcClient.GetBlockCount() if err != nil { return err } + if bn < 0 { + return fmt.Errorf("LoadLastBlock: negative block number %d", bn) + } //Load persisted block number var lastBlockNum clienttypes.LastBlockSQLType @@ -784,7 +774,8 @@ func (ob *Observer) loadDB(dbpath string) error { 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 { - panic("failed to connect database") + ob.logger.Chain.Error().Err(err).Msgf("failed to open observer database for %s", ob.chain.ChainName.String()) + return err } ob.db = db diff --git a/zetaclient/chains/bitcoin/observer/observer_test.go b/zetaclient/chains/bitcoin/observer/observer_test.go index 98bca623d1..1bf3dafa98 100644 --- a/zetaclient/chains/bitcoin/observer/observer_test.go +++ b/zetaclient/chains/bitcoin/observer/observer_test.go @@ -72,7 +72,7 @@ func TestNewBitcoinObserver(t *testing.T) { coreContext := context.NewZetacoreContext(cfg) appContext := context.NewAppContext(coreContext, cfg) chain := chains.BtcMainnetChain - zetacoreClient := mocks.NewMockZetaCoreClient() + zetacoreClient := mocks.NewMockZetacoreClient() tss := mocks.NewMockTSS(chains.BtcTestNetChain, sample.EthAddress().String(), "") loggers := clientcommon.ClientLogger{} btcCfg := cfg.BitcoinConfig diff --git a/zetaclient/chains/bitcoin/observer/outbound_test.go b/zetaclient/chains/bitcoin/observer/outbound_test.go index 0f0deed55a..1e291d1803 100644 --- a/zetaclient/chains/bitcoin/observer/outbound_test.go +++ b/zetaclient/chains/bitcoin/observer/outbound_test.go @@ -22,7 +22,7 @@ func MockBTCObserverMainnet() *Observer { return &Observer{ chain: chains.BtcMainnetChain, - zetacoreClient: mocks.NewMockZetaCoreClient(), + zetacoreClient: mocks.NewMockZetacoreClient(), Tss: mocks.NewTSSMainnet(), coreContext: coreContext, } diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index c9e4ec182c..6cef73a211 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -336,9 +336,14 @@ func (signer *Signer) TryProcessOutbound( return } chain := btcObserver.Chain() - myid := zetacoreClient.GetKeys().GetAddress() outboundTssNonce := params.TssNonce + signerAddress, err := zetacoreClient.GetKeys().GetAddress() + if err != nil { + logger.Error().Err(err).Msgf("cannot get signer address") + return + } + // get size limit and gas price sizelimit := params.GasLimit gasprice, ok := new(big.Int).SetString(params.GasPrice, 10) if !ok || gasprice.Cmp(big.NewInt(0)) < 0 { @@ -374,9 +379,9 @@ func (signer *Signer) TryProcessOutbound( true, chain.ChainId, cctx.Index, cctx.InboundParams.Sender, params.Receiver, "BTC") amount = 0.0 // zero out the amount to cancel the tx } - logger.Info().Msgf("SignWithdrawTx: to %s, value %d sats", to.EncodeAddress(), params.Amount.Uint64()) + // sign withdraw tx tx, err := signer.SignWithdrawTx( to, amount, @@ -401,7 +406,7 @@ func (signer *Signer) TryProcessOutbound( } if tx != nil { outboundHash := tx.TxHash().String() - logger.Info().Msgf("on chain %s nonce %d, outboundHash %s signer %s", chain.ChainName, outboundTssNonce, outboundHash, myid) + 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 diff --git a/zetaclient/chains/evm/observer/inbound_test.go b/zetaclient/chains/evm/observer/inbound_test.go index 478e02b5f7..308b89efd9 100644 --- a/zetaclient/chains/evm/observer/inbound_test.go +++ b/zetaclient/chains/evm/observer/inbound_test.go @@ -13,6 +13,7 @@ import ( "github.com/zeta-chain/zetacore/pkg/constant" "github.com/zeta-chain/zetacore/zetaclient/chains/evm" "github.com/zeta-chain/zetacore/zetaclient/config" + "github.com/zeta-chain/zetacore/zetaclient/keys" "github.com/zeta-chain/zetacore/zetaclient/testutils" "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" clienttypes "github.com/zeta-chain/zetacore/zetaclient/types" @@ -194,7 +195,7 @@ func Test_BuildInboundVoteMsgForZetaSentEvent(t *testing.T) { // parse ZetaSent event ob := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(1, 1)) - connector := mocks.MockConnectorNonEth(chainID) + connector := mocks.MockConnectorNonEth(t, chainID) event := testutils.ParseReceiptZetaSent(receipt, connector) // create test compliance config @@ -241,7 +242,7 @@ func Test_BuildInboundVoteMsgForDepositedEvent(t *testing.T) { // parse Deposited event ob := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(1, 1)) - custody := mocks.MockERC20Custody(chainID) + custody := mocks.MockERC20Custody(t, chainID) event := testutils.ParseReceiptERC20Deposited(receipt, custody) sender := ethcommon.HexToAddress(tx.From) @@ -345,7 +346,7 @@ func Test_ObserveTSSReceiveInBlock(t *testing.T) { // create mock client evmClient := mocks.NewMockEvmClient() evmJSONRPC := mocks.NewMockJSONRPCClient() - zetacoreClient := mocks.NewMockZetaCoreClient() + zetacoreClient := mocks.NewMockZetacoreClient().WithKeys(&keys.Keys{}) tss := mocks.NewTSSMainnet() lastBlock := receipt.BlockNumber.Uint64() + confirmation @@ -379,7 +380,7 @@ func Test_ObserveTSSReceiveInBlock(t *testing.T) { evmClient.WithReceipt(receipt) zetacoreClient.Pause() err := ob.ObserveTSSReceiveInBlock(blockNumber) - // error posting vote is expected because the mock zetaClient is paused + // error posting vote is expected because the mock zetacoreClient is paused require.ErrorContains(t, err, "error checking and voting") }) } diff --git a/zetaclient/chains/evm/observer/observer.go b/zetaclient/chains/evm/observer/observer.go index d011ed3e95..60436f4f9e 100644 --- a/zetaclient/chains/evm/observer/observer.go +++ b/zetaclient/chains/evm/observer/observer.go @@ -417,19 +417,12 @@ func (ob *Observer) GetLastBlockHeightScanned() uint64 { // SetLastBlockHeight set external last block height func (ob *Observer) SetLastBlockHeight(height uint64) { - if height >= math.MaxInt64 { - panic("lastBlock is too large") - } atomic.StoreUint64(&ob.lastBlock, height) } // GetLastBlockHeight get external last block height func (ob *Observer) GetLastBlockHeight() uint64 { - height := atomic.LoadUint64(&ob.lastBlock) - if height >= math.MaxInt64 { - panic("lastBlock is too large") - } - return height + return atomic.LoadUint64(&ob.lastBlock) } // WatchGasPrice watches evm chain for gas prices and post to zetacore @@ -614,7 +607,8 @@ func (ob *Observer) LoadDB(dbPath string, chain chains.Chain) error { 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 { - panic("failed to connect database") + ob.logger.Chain.Error().Err(err).Msgf("failed to open observer database for %s", ob.chain.ChainName.String()) + return err } err = db.AutoMigrate(&clienttypes.ReceiptSQLType{}, diff --git a/zetaclient/chains/evm/observer/observer_db_test.go b/zetaclient/chains/evm/observer/observer_db_test.go index 92747e01ce..d9d1cda1c1 100644 --- a/zetaclient/chains/evm/observer/observer_db_test.go +++ b/zetaclient/chains/evm/observer/observer_db_test.go @@ -66,7 +66,7 @@ func (suite *ObserverDBTestSuite) SetupTest() { //Create some transaction entries in the DB for i := 0; i < NumOfEntries; i++ { - transaction := legacyTx(i) + transaction := suite.legacyTx(i) trans, _ := clienttypes.ToTransactionSQLType(transaction, strconv.Itoa(i)) dbc := suite.db.Create(trans) suite.NoError(dbc.Error) @@ -125,33 +125,26 @@ func (suite *ObserverDBTestSuite) TestEVMLastBlock() { suite.Equal(lastBlockNum, lastBlockDB.Num) } -func legacyTx(nonce int) *ethtypes.Transaction { +func (suite *ObserverDBTestSuite) legacyTx(nonce int) *ethtypes.Transaction { gasPrice, err := hexutil.DecodeBig("0x2bd0875aed") - if err != nil { - panic(err) - } + suite.NoError(err) + gas, err := hexutil.DecodeUint64("0x5208") - if err != nil { - panic(err) - } + suite.NoError(err) + to := common.HexToAddress("0x2f14582947e292a2ecd20c430b46f2d27cfe213c") value, err := hexutil.DecodeBig("0x2386f26fc10000") - if err != nil { - panic(err) - } + suite.NoError(err) + data := common.Hex2Bytes("0x") v, err := hexutil.DecodeBig("0x1") - if err != nil { - panic(err) - } + suite.NoError(err) + r, err := hexutil.DecodeBig("0x56b5bf9222ce26c3239492173249696740bc7c28cd159ad083a0f4940baf6d03") - if err != nil { - panic(err) - } + suite.NoError(err) + s, err := hexutil.DecodeBig("0x5fcd608b3b638950d3fe007b19ca8c4ead37237eaf89a8426777a594fd245c2a") - if err != nil { - panic(err) - } + suite.NoError(err) newLegacyTx := ethtypes.NewTx(ðtypes.LegacyTx{ Nonce: uint64(nonce), diff --git a/zetaclient/chains/evm/observer/observer_test.go b/zetaclient/chains/evm/observer/observer_test.go index db317e33f5..bb9b3d848b 100644 --- a/zetaclient/chains/evm/observer/observer_test.go +++ b/zetaclient/chains/evm/observer/observer_test.go @@ -20,6 +20,7 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/common" "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/testutils" "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" ) @@ -69,7 +70,7 @@ func MockEVMObserver( params observertypes.ChainParams) *observer.Observer { // use default mock zetacore client if not provided if zetacoreClient == nil { - zetacoreClient = mocks.NewMockZetaCoreClient() + zetacoreClient = mocks.NewMockZetacoreClient().WithKeys(&keys.Keys{}) } // use default mock tss if not provided if tss == nil { diff --git a/zetaclient/chains/evm/observer/outbound_test.go b/zetaclient/chains/evm/observer/outbound_test.go index bd2ed78e77..da4525e624 100644 --- a/zetaclient/chains/evm/observer/outbound_test.go +++ b/zetaclient/chains/evm/observer/outbound_test.go @@ -19,10 +19,10 @@ import ( ) // getContractsByChainID is a helper func to get contracts and addresses by chainID -func getContractsByChainID(chainID int64) (*zetaconnector.ZetaConnectorNonEth, ethcommon.Address, *erc20custody.ERC20Custody, ethcommon.Address) { - connector := mocks.MockConnectorNonEth(chainID) +func getContractsByChainID(t *testing.T, chainID int64) (*zetaconnector.ZetaConnectorNonEth, ethcommon.Address, *erc20custody.ERC20Custody, ethcommon.Address) { + connector := mocks.MockConnectorNonEth(t, chainID) connectorAddress := testutils.ConnectorAddresses[chainID] - custody := mocks.MockERC20Custody(chainID) + custody := mocks.MockERC20Custody(t, chainID) custodyAddress := testutils.CustodyAddresses[chainID] return connector, connectorAddress, custody, custodyAddress } @@ -156,7 +156,7 @@ func Test_PostVoteOutbound(t *testing.T) { receiveStatus := chains.ReceiveStatus_success // create evm client using mock zetacore client and post outbound vote - zetacoreClient := mocks.NewMockZetaCoreClient() + zetacoreClient := mocks.NewMockZetacoreClient() client := MockEVMObserver(t, chain, nil, nil, zetacoreClient, nil, 1, observertypes.ChainParams{}) client.PostVoteOutbound(cctx.Index, receipt, outbound, receiveValue, receiveStatus, nonce, coinType, zerolog.Logger{}) @@ -172,7 +172,7 @@ func Test_ParseZetaReceived(t *testing.T) { chainID := chains.EthChain.ChainId nonce := uint64(9718) outboundHash := "0x81342051b8a85072d3e3771c1a57c7bdb5318e8caf37f5a687b7a91e50a7257f" - connector := mocks.MockConnectorNonEth(chainID) + connector := mocks.MockConnectorNonEth(t, chainID) connectorAddress := testutils.ConnectorAddresses[chainID] cctx := testutils.LoadCctxByNonce(t, chainID, nonce) receipt := testutils.LoadEVMOutboundReceipt(t, TestDataDir, chainID, outboundHash, coin.CoinType_Zeta, testutils.EventZetaReceived) @@ -233,7 +233,7 @@ func Test_ParseZetaReverted(t *testing.T) { chainID := chains.GoerliLocalnetChain.ChainId nonce := uint64(14) outboundHash := "0x1487e6a31dd430306667250b72bf15b8390b73108b69f3de5c1b2efe456036a7" - connector := mocks.MockConnectorNonEth(chainID) + connector := mocks.MockConnectorNonEth(t, chainID) connectorAddress := testutils.ConnectorAddresses[chainID] cctx := testutils.LoadCctxByNonce(t, chainID, nonce) receipt := testutils.LoadEVMOutboundReceipt(t, TestDataDir, chainID, outboundHash, coin.CoinType_Zeta, testutils.EventZetaReverted) @@ -285,7 +285,7 @@ func Test_ParseERC20WithdrawnEvent(t *testing.T) { chainID := chains.EthChain.ChainId nonce := uint64(8014) outboundHash := "0xd2eba7ac3da1b62800165414ea4bcaf69a3b0fb9b13a0fc32f4be11bfef79146" - custody := mocks.MockERC20Custody(chainID) + custody := mocks.MockERC20Custody(t, chainID) custodyAddress := testutils.CustodyAddresses[chainID] cctx := testutils.LoadCctxByNonce(t, chainID, nonce) receipt := testutils.LoadEVMOutboundReceipt(t, TestDataDir, chainID, outboundHash, coin.CoinType_ERC20, testutils.EventERC20Withdraw) @@ -339,7 +339,7 @@ func Test_ParseERC20WithdrawnEvent(t *testing.T) { func Test_ParseOutboundReceivedValue(t *testing.T) { chainID := chains.EthChain.ChainId - connector, connectorAddr, custody, custodyAddr := getContractsByChainID(chainID) + connector, connectorAddr, custody, custodyAddr := getContractsByChainID(t, chainID) t.Run("should parse and check ZetaReceived event from archived outbound receipt", func(t *testing.T) { // load archived outbound receipt that contains ZetaReceived event @@ -359,7 +359,7 @@ func Test_ParseOutboundReceivedValue(t *testing.T) { localChainID := chains.GoerliLocalnetChain.ChainId nonce := uint64(14) coinType := coin.CoinType_Zeta - connectorLocal, connectorAddrLocal, custodyLocal, custodyAddrLocal := getContractsByChainID(localChainID) + connectorLocal, connectorAddrLocal, custodyLocal, custodyAddrLocal := getContractsByChainID(t, localChainID) cctx, outbound, receipt := testutils.LoadEVMCctxNOutboundNReceipt(t, TestDataDir, localChainID, nonce, testutils.EventZetaReverted) params := cctx.GetCurrentOutboundParam() value, status, err := observer.ParseOutboundReceivedValue( diff --git a/zetaclient/chains/evm/signer/signer_test.go b/zetaclient/chains/evm/signer/signer_test.go index 106b556643..24a209e710 100644 --- a/zetaclient/chains/evm/signer/signer_test.go +++ b/zetaclient/chains/evm/signer/signer_test.go @@ -15,6 +15,7 @@ import ( "github.com/zeta-chain/zetacore/zetaclient/common" "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/outboundprocessor" "github.com/zeta-chain/zetacore/zetaclient/testutils" @@ -57,7 +58,7 @@ func getNewEvmChainObserver() (*observer.Observer, error) { coreCTX := context.NewZetacoreContext(cfg) appCTX := context.NewAppContext(coreCTX, cfg) - return observer.NewObserver(appCTX, mocks.NewMockZetaCoreClient(), tss, "", logger, evmcfg, ts) + return observer.NewObserver(appCTX, mocks.NewMockZetacoreClient(), tss, "", logger, evmcfg, ts) } func getNewOutboundProcessor() *outboundprocessor.Processor { @@ -108,9 +109,11 @@ func TestSigner_TryProcessOutbound(t *testing.T) { mockObserver, err := getNewEvmChainObserver() require.NoError(t, err) - evmSigner.TryProcessOutbound(cctx, processorManager, "123", mockObserver, mocks.NewMockZetaCoreClient(), 123) + // Test with mock client that has keys + client := mocks.NewMockZetacoreClient().WithKeys(&keys.Keys{}) + evmSigner.TryProcessOutbound(cctx, processorManager, "123", mockObserver, client, 123) - //Check if cctx was signed and broadcasted + // Check if cctx was signed and broadcasted list := evmSigner.GetReportedTxList() require.Len(t, *list, 1) } @@ -297,7 +300,7 @@ func TestSigner_BroadcastOutbound(t *testing.T) { tx, err := evmSigner.SignERC20WithdrawTx(txData) require.NoError(t, err) - evmSigner.BroadcastOutbound(tx, cctx, zerolog.Logger{}, sdktypes.AccAddress{}, mocks.NewMockZetaCoreClient(), txData) + evmSigner.BroadcastOutbound(tx, cctx, zerolog.Logger{}, sdktypes.AccAddress{}, mocks.NewMockZetacoreClient(), txData) //Check if cctx was signed and broadcasted list := evmSigner.GetReportedTxList() diff --git a/zetaclient/chains/interfaces/interfaces.go b/zetaclient/chains/interfaces/interfaces.go index effa9aca63..786905ebb3 100644 --- a/zetaclient/chains/interfaces/interfaces.go +++ b/zetaclient/chains/interfaces/interfaces.go @@ -22,7 +22,7 @@ import ( 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" - "github.com/zeta-chain/zetacore/zetaclient/keys" + keyinterfaces "github.com/zeta-chain/zetacore/zetaclient/keys/interfaces" "github.com/zeta-chain/zetacore/zetaclient/outboundprocessor" ) @@ -92,7 +92,7 @@ type ZetacoreClient interface { ) (string, error) Chain() chains.Chain GetLogger() *zerolog.Logger - GetKeys() *keys.Keys + GetKeys() keyinterfaces.ObserverKeys GetKeyGen() (*observertypes.Keygen, error) GetBlockHeight() (int64, error) GetLastBlockHeightByChain(chain chains.Chain) (*crosschaintypes.LastBlockHeight, error) diff --git a/zetaclient/context/zetacore_context.go b/zetaclient/context/zetacore_context.go index f7db2e9e96..e9f9d44bf3 100644 --- a/zetaclient/context/zetacore_context.go +++ b/zetaclient/context/zetacore_context.go @@ -1,7 +1,6 @@ package context import ( - "fmt" "sort" "sync" @@ -120,17 +119,18 @@ func (c *ZetacoreContext) GetAllEVMChainParams() map[int64]*observertypes.ChainP 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{}, &observertypes.ChainParams{}, false + return chains.Chain{}, nil, false } chain := chains.GetChainFromChainID(c.bitcoinChainParams.ChainId) if chain == nil { - panic(fmt.Sprintf("BTCChain is missing for chainID %d", c.bitcoinChainParams.ChainId)) + return chains.Chain{}, nil, false } return *chain, c.bitcoinChainParams, true diff --git a/zetaclient/context/zetacore_context_test.go b/zetaclient/context/zetacore_context_test.go index c21148fd80..409af6154a 100644 --- a/zetaclient/context/zetacore_context_test.go +++ b/zetaclient/context/zetacore_context_test.go @@ -14,16 +14,6 @@ import ( context "github.com/zeta-chain/zetacore/zetaclient/context" ) -func assertPanic(t *testing.T, f func(), errorLog string) { - defer func() { - r := recover() - if r != nil { - require.Contains(t, r, errorLog) - } - }() - f() -} - func getTestCoreContext( evmChain chains.Chain, evmChainParams *observertypes.ChainParams, @@ -79,13 +69,32 @@ func TestNewZetaCoreContext(t *testing.T) { chain, btcChainParams, btcChainParamsFound := zetaContext.GetBTCChainParams() require.Equal(t, chains.Chain{}, chain) require.False(t, btcChainParamsFound) - require.Equal(t, &observertypes.ChainParams{}, btcChainParams) + require.Nil(t, btcChainParams) // assert evm chain params allEVMChainParams := zetaContext.GetAllEVMChainParams() require.Empty(t, allEVMChainParams) }) + t.Run("should return nil chain params if chain id is not found", func(t *testing.T) { + // create config with btc config + testCfg := config.NewConfig() + testCfg.BitcoinConfig = config.BTCConfig{ + RPCUsername: "test_user", + RPCPassword: "test_password", + } + + // create zetacore context with 0 chain id + zetaContext := context.NewZetacoreContext(testCfg) + require.NotNil(t, zetaContext) + + // assert btc chain params + chain, btcChainParams, btcChainParamsFound := zetaContext.GetBTCChainParams() + require.Equal(t, chains.Chain{}, chain) + require.False(t, btcChainParamsFound) + require.Nil(t, btcChainParams) + }) + t.Run("should create new zetacore context with config containing evm chain params", func(t *testing.T) { testCfg := config.NewConfig() testCfg.EVMChainConfigs = map[int64]config.EVMConfig{ @@ -130,11 +139,6 @@ func TestNewZetaCoreContext(t *testing.T) { } zetaContext := context.NewZetacoreContext(testCfg) require.NotNil(t, zetaContext) - - // assert btc chain params panic because chain params are not yet updated - assertPanic(t, func() { - zetaContext.GetBTCChainParams() - }, "BTCChain is missing for chainID 0") }) } @@ -208,7 +212,7 @@ func TestUpdateZetacoreContext(t *testing.T) { chain, btcChainParams, btcChainParamsFound := zetaContext.GetBTCChainParams() require.Equal(t, chains.Chain{}, chain) require.False(t, btcChainParamsFound) - require.Equal(t, &observertypes.ChainParams{}, btcChainParams) + require.Nil(t, btcChainParams) // assert evm chain params still empty because they were not specified in config allEVMChainParams := zetaContext.GetAllEVMChainParams() diff --git a/zetaclient/keys/interfaces/interfaces.go b/zetaclient/keys/interfaces/interfaces.go new file mode 100644 index 0000000000..a3532770c3 --- /dev/null +++ b/zetaclient/keys/interfaces/interfaces.go @@ -0,0 +1,17 @@ +package interfaces + +import ( + ckeys "github.com/cosmos/cosmos-sdk/crypto/keyring" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ObserverKeys is the interface for observer's keys +type ObserverKeys interface { + GetSignerInfo() *ckeys.Record + GetOperatorAddress() sdk.AccAddress + GetAddress() (sdk.AccAddress, error) + GetPrivateKey(password string) (cryptotypes.PrivKey, error) + GetKeybase() ckeys.Keyring + GetHotkeyPassword() string +} diff --git a/zetaclient/keys/keys.go b/zetaclient/keys/keys.go index c709f8e6f8..5bee8af8b2 100644 --- a/zetaclient/keys/keys.go +++ b/zetaclient/keys/keys.go @@ -18,6 +18,7 @@ import ( "github.com/zeta-chain/zetacore/pkg/cosmos" zetacrypto "github.com/zeta-chain/zetacore/pkg/crypto" "github.com/zeta-chain/zetacore/zetaclient/config" + "github.com/zeta-chain/zetacore/zetaclient/keys/interfaces" ) var ( @@ -25,6 +26,8 @@ var ( ErrNewPubKey = errors.New("NewPubKey error from string") ) +var _ interfaces.ObserverKeys = &Keys{} + // Keys manages all the keys used by zeta client type Keys struct { signerName string @@ -95,7 +98,7 @@ func (k *Keys) GetSignerInfo() *ckeys.Record { signer := GetGranteeKeyName(k.signerName) info, err := k.kb.Key(signer) if err != nil { - panic(err) + return nil } return info } @@ -104,17 +107,18 @@ func (k *Keys) GetOperatorAddress() sdk.AccAddress { return k.OperatorAddress } -func (k *Keys) GetAddress() sdk.AccAddress { +// GetAddress return the signer address +func (k *Keys) GetAddress() (sdk.AccAddress, error) { signer := GetGranteeKeyName(k.signerName) info, err := k.kb.Key(signer) if err != nil { - panic(err) + return nil, err } addr, err := info.GetAddress() if err != nil { - return nil + return nil, err } - return addr + return addr, nil } // GetPrivateKey return the private key diff --git a/zetaclient/keys/keys_test.go b/zetaclient/keys/keys_test.go index 1eaf8ed3e5..81b46cd896 100644 --- a/zetaclient/keys/keys_test.go +++ b/zetaclient/keys/keys_test.go @@ -15,11 +15,12 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" hd "github.com/cosmos/cosmos-sdk/crypto/hd" cKeys "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/zeta-chain/zetacore/zetaclient/config" - . "gopkg.in/check.v1" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/cmd" + "github.com/zeta-chain/zetacore/zetaclient/config" + "github.com/zeta-chain/zetacore/zetaclient/testutils/mocks" + . "gopkg.in/check.v1" ) type KeysSuite struct{} @@ -102,8 +103,8 @@ func (ks *KeysSuite) TestNewKeys(c *C) { k, _, err := GetKeyringKeybase(cfg, "") c.Assert(err, IsNil) c.Assert(k, NotNil) - granter := sdk.AccAddress(crypto.AddressHash([]byte("granter"))) - ki := NewKeysWithKeybase(k, granter, signerNameForTest, "") + granterAddress := sdk.AccAddress(crypto.AddressHash([]byte("granter"))) + ki := NewKeysWithKeybase(k, granterAddress, signerNameForTest, "") kInfo := ki.GetSignerInfo() c.Assert(kInfo, NotNil) //c.Assert(kInfo.G, Equals, signerNameForTest) @@ -121,3 +122,14 @@ func (ks *KeysSuite) TestNewKeys(c *C) { c.Assert(err, IsNil) c.Assert(pubKey.VerifySignature([]byte(msg), signedMsg), Equals, true) } + +func TestGetSignerInfo(t *testing.T) { + // create a mock keyring + keyRing := mocks.NewKeyring() + + // create a new key using the mock keyring + granterAddress := sdk.AccAddress(crypto.AddressHash([]byte("granter"))) + keys := NewKeysWithKeybase(keyRing, granterAddress, "", "") + info := keys.GetSignerInfo() + require.Nil(t, info) +} diff --git a/zetaclient/orchestrator/orchestrator.go b/zetaclient/orchestrator/orchestrator.go index 6badf918a5..83caf9cf99 100644 --- a/zetaclient/orchestrator/orchestrator.go +++ b/zetaclient/orchestrator/orchestrator.go @@ -93,20 +93,29 @@ func NewOrchestrator( return &oc } -func (oc *Orchestrator) MonitorCore(appContext *context.AppContext) { - myid := oc.zetacoreClient.GetKeys().GetAddress() - oc.logger.Std.Info().Msgf("Starting orchestrator for %s", myid) +func (oc *Orchestrator) MonitorCore(appContext *context.AppContext) error { + signerAddress, err := oc.zetacoreClient.GetKeys().GetAddress() + if err != nil { + return fmt.Errorf("failed to get signer address: %w", err) + } + oc.logger.Std.Info().Msgf("Starting orchestrator for signer: %s", signerAddress) + + // start cctx scheduler go oc.StartCctxScheduler(appContext) + // watch for upgrade plan from zetacore go func() { - // query UpgradePlan from zetacore and send to its pause channel if upgrade height is reached + // wait for upgrade plan signal to arrive oc.zetacoreClient.Pause() - // now stop everything - close(oc.stop) // this stops the startSendScheduler() loop + + // now stop orchestrator and all observers + close(oc.stop) for _, c := range oc.observerMap { c.Stop() } }() + + return nil } // GetUpdatedSigner returns signer with updated chain parameters diff --git a/zetaclient/orchestrator/orchestrator_test.go b/zetaclient/orchestrator/orchestrator_test.go index cd709bb018..fa3fd2476b 100644 --- a/zetaclient/orchestrator/orchestrator_test.go +++ b/zetaclient/orchestrator/orchestrator_test.go @@ -308,7 +308,7 @@ func Test_GetPendingCctxsWithinRatelimit(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // create mock zetacore client - client := mocks.NewMockZetaCoreClient() + client := mocks.NewMockZetacoreClient() // load mock data client.WithRateLimiterFlags(tt.rateLimiterFlags) diff --git a/zetaclient/supplychecker/zeta_supply_checker.go b/zetaclient/supplychecker/zeta_supply_checker.go index 09a61f7ee6..6db00def4a 100644 --- a/zetaclient/supplychecker/zeta_supply_checker.go +++ b/zetaclient/supplychecker/zeta_supply_checker.go @@ -162,7 +162,10 @@ func (zs *ZetaSupplyChecker) CheckZetaTokenSupply() error { return fmt.Errorf("error parsing eth locked amount") } - zetaInTransit := zs.GetAmountOfZetaInTransit() + zetaInTransit, err := zs.GetAmountOfZetaInTransit() + if err != nil { + return err + } zetaTokenSupplyOnNode, err := zs.zetaClient.GetZetaTokenSupplyOnNode() if err != nil { return err @@ -190,7 +193,7 @@ func (zs *ZetaSupplyChecker) AbortedTxAmount() (sdkmath.Int, error) { return amountInt, nil } -func (zs *ZetaSupplyChecker) GetAmountOfZetaInTransit() sdkmath.Int { +func (zs *ZetaSupplyChecker) GetAmountOfZetaInTransit() (sdkmath.Int, error) { chainsToCheck := make([]chains.Chain, len(zs.externalEvmChain)+1) chainsToCheck = append(append(chainsToCheck, zs.externalEvmChain...), zs.ethereumChain) cctxs := zs.GetPendingCCTXInTransit(chainsToCheck) @@ -201,10 +204,10 @@ func (zs *ZetaSupplyChecker) GetAmountOfZetaInTransit() sdkmath.Int { } amountInt, ok := sdkmath.NewIntFromString(amount.String()) if !ok { - panic("error parsing amount") + return sdkmath.ZeroInt(), fmt.Errorf("error parsing amount %s", amount.String()) } - return amountInt + return amountInt, nil } func (zs *ZetaSupplyChecker) GetPendingCCTXInTransit(receivingChains []chains.Chain) []*types.CrossChainTx { diff --git a/zetaclient/supplychecker/zeta_supply_checker_test.go b/zetaclient/supplychecker/zeta_supply_checker_test.go index 73e3afd32d..48daed4557 100644 --- a/zetaclient/supplychecker/zeta_supply_checker_test.go +++ b/zetaclient/supplychecker/zeta_supply_checker_test.go @@ -9,11 +9,9 @@ import ( "github.com/stretchr/testify/require" ) -func MustNewIntFromString(val string) sdkmath.Int { +func MustNewIntFromString(t *testing.T, val string) sdkmath.Int { v, ok := sdkmath.NewIntFromString(val) - if !ok { - panic("invalid int") - } + require.True(t, ok) return v } func TestZetaSupplyChecker_ValidateZetaSupply(t *testing.T) { @@ -29,12 +27,12 @@ func TestZetaSupplyChecker_ValidateZetaSupply(t *testing.T) { }{ { name: "1 zeta cctx in progress", - abortedTxAmount: MustNewIntFromString("0"), - zetaInTransit: MustNewIntFromString("1000000000000000000"), - externalChainTotalSupply: MustNewIntFromString("9000000000000000000"), - genesisAmounts: MustNewIntFromString("1000000000000000000"), - zetaTokenSupplyOnNode: MustNewIntFromString("1000000000000000000"), - ethLockedAmount: MustNewIntFromString("10000000000000000000"), + abortedTxAmount: MustNewIntFromString(t, "0"), + zetaInTransit: MustNewIntFromString(t, "1000000000000000000"), + externalChainTotalSupply: MustNewIntFromString(t, "9000000000000000000"), + genesisAmounts: MustNewIntFromString(t, "1000000000000000000"), + zetaTokenSupplyOnNode: MustNewIntFromString(t, "1000000000000000000"), + ethLockedAmount: MustNewIntFromString(t, "10000000000000000000"), validate: func(t require.TestingT, b bool, i ...interface{}) { require.True(t, b, i...) }, diff --git a/zetaclient/testutils/mocks/chain_params.go b/zetaclient/testutils/mocks/chain_params.go index ae8b9c4dbe..e785007e61 100644 --- a/zetaclient/testutils/mocks/chain_params.go +++ b/zetaclient/testutils/mocks/chain_params.go @@ -1,7 +1,10 @@ package mocks import ( + "testing" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/require" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.non-eth.sol" observertypes "github.com/zeta-chain/zetacore/x/observer/types" @@ -18,18 +21,14 @@ func MockChainParams(chainID int64, confirmation uint64) observertypes.ChainPara } } -func MockConnectorNonEth(chainID int64) *zetaconnector.ZetaConnectorNonEth { +func MockConnectorNonEth(t *testing.T, chainID int64) *zetaconnector.ZetaConnectorNonEth { connector, err := zetaconnector.NewZetaConnectorNonEth(testutils.ConnectorAddresses[chainID], ðclient.Client{}) - if err != nil { - panic(err) - } + require.NoError(t, err) return connector } -func MockERC20Custody(chainID int64) *erc20custody.ERC20Custody { +func MockERC20Custody(t *testing.T, chainID int64) *erc20custody.ERC20Custody { custody, err := erc20custody.NewERC20Custody(testutils.CustodyAddresses[chainID], ðclient.Client{}) - if err != nil { - panic(err) - } + require.NoError(t, err) return custody } diff --git a/zetaclient/testutils/mocks/keyring.go b/zetaclient/testutils/mocks/keyring.go index 383a9d5887..b4265a86ae 100644 --- a/zetaclient/testutils/mocks/keyring.go +++ b/zetaclient/testutils/mocks/keyring.go @@ -1,6 +1,8 @@ package mocks import ( + "errors" + ckeys "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -34,7 +36,10 @@ func (m Keyring) SupportedAlgorithms() (ckeys.SigningAlgoList, ckeys.SigningAlgo return nil, nil } -func (m Keyring) Key(_ string) (*ckeys.Record, error) { +func (m Keyring) Key(uid string) (*ckeys.Record, error) { + if uid == "" { + return nil, errors.New("empty uid") + } return ckeys.NewLocalRecord("", TestKeyringPair, TestKeyringPair.PubKey()) } diff --git a/zetaclient/testutils/mocks/zetacore_client.go b/zetaclient/testutils/mocks/zetacore_client.go index 53b0752002..aaea360b8b 100644 --- a/zetaclient/testutils/mocks/zetacore_client.go +++ b/zetaclient/testutils/mocks/zetacore_client.go @@ -14,20 +14,23 @@ import ( 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" - "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" - "github.com/zeta-chain/zetacore/zetaclient/keys" + chaininterfaces "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" + keyinterfaces "github.com/zeta-chain/zetacore/zetaclient/keys/interfaces" "github.com/zeta-chain/zetacore/zetaclient/testutils" ) const ErrMsgPaused = "zetacore client is paused" const ErrMsgRPCFailed = "rpc failed" -var _ interfaces.ZetacoreClient = &MockZetaCoreClient{} +var _ chaininterfaces.ZetacoreClient = &MockZetacoreClient{} -type MockZetaCoreClient struct { +type MockZetacoreClient struct { paused bool zetaChain chains.Chain + // the mock observer keys + keys keyinterfaces.ObserverKeys + // the mock data for testing // pending cctxs pendingCctxs map[int64][]*crosschaintypes.CrossChainTx @@ -39,200 +42,196 @@ type MockZetaCoreClient struct { input *crosschaintypes.QueryRateLimiterInputResponse } -func NewMockZetaCoreClient() *MockZetaCoreClient { - zetaChain, err := chains.ZetaChainFromChainID("zetachain_7000-1") - if err != nil { - panic(err) - } - return &MockZetaCoreClient{ +func NewMockZetacoreClient() *MockZetacoreClient { + return &MockZetacoreClient{ paused: false, - zetaChain: zetaChain, + zetaChain: chains.ZetaChainMainnet, pendingCctxs: map[int64][]*crosschaintypes.CrossChainTx{}, } } -func (z *MockZetaCoreClient) PostVoteInbound(_, _ uint64, _ *crosschaintypes.MsgVoteInbound) (string, string, error) { - if z.paused { +func (m *MockZetacoreClient) PostVoteInbound(_, _ uint64, _ *crosschaintypes.MsgVoteInbound) (string, string, error) { + if m.paused { return "", "", errors.New(ErrMsgPaused) } return "", "", nil } -func (z *MockZetaCoreClient) PostVoteOutbound(_ string, _ string, _ uint64, _ uint64, _ *big.Int, _ uint64, _ *big.Int, _ chains.ReceiveStatus, _ chains.Chain, _ uint64, _ coin.CoinType) (string, string, error) { - if z.paused { +func (m *MockZetacoreClient) PostVoteOutbound(_ string, _ string, _ uint64, _ uint64, _ *big.Int, _ uint64, _ *big.Int, _ chains.ReceiveStatus, _ chains.Chain, _ uint64, _ coin.CoinType) (string, string, error) { + if m.paused { return "", "", errors.New(ErrMsgPaused) } return sample.Hash().Hex(), "", nil } -func (z *MockZetaCoreClient) PostGasPrice(_ chains.Chain, _ uint64, _ string, _ uint64) (string, error) { - if z.paused { +func (m *MockZetacoreClient) PostGasPrice(_ chains.Chain, _ uint64, _ string, _ uint64) (string, error) { + if m.paused { return "", errors.New(ErrMsgPaused) } return "", nil } -func (z *MockZetaCoreClient) PostVoteBlockHeader(_ int64, _ []byte, _ int64, _ proofs.HeaderData) (string, error) { - if z.paused { +func (m *MockZetacoreClient) PostVoteBlockHeader(_ int64, _ []byte, _ int64, _ proofs.HeaderData) (string, error) { + if m.paused { return "", errors.New(ErrMsgPaused) } return "", nil } -func (z *MockZetaCoreClient) GetBlockHeaderChainState(_ int64) (lightclienttypes.QueryGetChainStateResponse, error) { - if z.paused { +func (m *MockZetacoreClient) GetBlockHeaderChainState(_ int64) (lightclienttypes.QueryGetChainStateResponse, error) { + if m.paused { return lightclienttypes.QueryGetChainStateResponse{}, errors.New(ErrMsgPaused) } return lightclienttypes.QueryGetChainStateResponse{}, nil } -func (z *MockZetaCoreClient) PostBlameData(_ *blame.Blame, _ int64, _ string) (string, error) { - if z.paused { +func (m *MockZetacoreClient) PostBlameData(_ *blame.Blame, _ int64, _ string) (string, error) { + if m.paused { return "", errors.New(ErrMsgPaused) } return "", nil } -func (z *MockZetaCoreClient) AddOutboundTracker(_ int64, _ uint64, _ string, _ *proofs.Proof, _ string, _ int64) (string, error) { - if z.paused { +func (m *MockZetacoreClient) AddOutboundTracker(_ int64, _ uint64, _ string, _ *proofs.Proof, _ string, _ int64) (string, error) { + if m.paused { return "", errors.New(ErrMsgPaused) } return "", nil } -func (z *MockZetaCoreClient) Chain() chains.Chain { - return z.zetaChain +func (m *MockZetacoreClient) Chain() chains.Chain { + return m.zetaChain } -func (z *MockZetaCoreClient) GetLogger() *zerolog.Logger { +func (m *MockZetacoreClient) GetLogger() *zerolog.Logger { return nil } -func (z *MockZetaCoreClient) GetKeys() *keys.Keys { - return &keys.Keys{} +func (m *MockZetacoreClient) GetKeys() keyinterfaces.ObserverKeys { + return m.keys } -func (z *MockZetaCoreClient) GetKeyGen() (*observerTypes.Keygen, error) { - if z.paused { +func (m *MockZetacoreClient) GetKeyGen() (*observerTypes.Keygen, error) { + if m.paused { return nil, errors.New(ErrMsgPaused) } return &observerTypes.Keygen{}, nil } -func (z *MockZetaCoreClient) GetBlockHeight() (int64, error) { - if z.paused { +func (m *MockZetacoreClient) GetBlockHeight() (int64, error) { + if m.paused { return 0, errors.New(ErrMsgPaused) } return 0, nil } -func (z *MockZetaCoreClient) GetLastBlockHeightByChain(_ chains.Chain) (*crosschaintypes.LastBlockHeight, error) { - if z.paused { +func (m *MockZetacoreClient) GetLastBlockHeightByChain(_ chains.Chain) (*crosschaintypes.LastBlockHeight, error) { + if m.paused { return nil, errors.New(ErrMsgPaused) } return &crosschaintypes.LastBlockHeight{}, nil } -func (z *MockZetaCoreClient) GetRateLimiterInput(_ int64) (crosschaintypes.QueryRateLimiterInputResponse, error) { - if z.paused { +func (m *MockZetacoreClient) GetRateLimiterInput(_ int64) (crosschaintypes.QueryRateLimiterInputResponse, error) { + if m.paused { return crosschaintypes.QueryRateLimiterInputResponse{}, errors.New(ErrMsgPaused) } - if z.input == nil { + if m.input == nil { return crosschaintypes.QueryRateLimiterInputResponse{}, errors.New(ErrMsgRPCFailed) } - return *z.input, nil + return *m.input, nil } -func (z *MockZetaCoreClient) ListPendingCctx(chainID int64) ([]*crosschaintypes.CrossChainTx, uint64, error) { - if z.paused { +func (m *MockZetacoreClient) ListPendingCctx(chainID int64) ([]*crosschaintypes.CrossChainTx, uint64, error) { + if m.paused { return nil, 0, errors.New(ErrMsgPaused) } - return z.pendingCctxs[chainID], 0, nil + return m.pendingCctxs[chainID], 0, nil } -func (z *MockZetaCoreClient) ListPendingCctxWithinRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, int64, string, bool, error) { - if z.paused { +func (m *MockZetacoreClient) ListPendingCctxWithinRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, int64, string, bool, error) { + if m.paused { return nil, 0, 0, "", false, errors.New(ErrMsgPaused) } return []*crosschaintypes.CrossChainTx{}, 0, 0, "", false, nil } -func (z *MockZetaCoreClient) GetPendingNoncesByChain(_ int64) (observerTypes.PendingNonces, error) { - if z.paused { +func (m *MockZetacoreClient) GetPendingNoncesByChain(_ int64) (observerTypes.PendingNonces, error) { + if m.paused { return observerTypes.PendingNonces{}, errors.New(ErrMsgPaused) } return observerTypes.PendingNonces{}, nil } -func (z *MockZetaCoreClient) GetCctxByNonce(_ int64, _ uint64) (*crosschaintypes.CrossChainTx, error) { - if z.paused { +func (m *MockZetacoreClient) GetCctxByNonce(_ int64, _ uint64) (*crosschaintypes.CrossChainTx, error) { + if m.paused { return nil, errors.New(ErrMsgPaused) } return &crosschaintypes.CrossChainTx{}, nil } -func (z *MockZetaCoreClient) GetOutboundTracker(_ chains.Chain, _ uint64) (*crosschaintypes.OutboundTracker, error) { - if z.paused { +func (m *MockZetacoreClient) GetOutboundTracker(_ chains.Chain, _ uint64) (*crosschaintypes.OutboundTracker, error) { + if m.paused { return nil, errors.New(ErrMsgPaused) } return &crosschaintypes.OutboundTracker{}, nil } -func (z *MockZetaCoreClient) GetAllOutboundTrackerByChain(_ int64, _ interfaces.Order) ([]crosschaintypes.OutboundTracker, error) { - if z.paused { +func (m *MockZetacoreClient) GetAllOutboundTrackerByChain(_ int64, _ chaininterfaces.Order) ([]crosschaintypes.OutboundTracker, error) { + if m.paused { return nil, errors.New(ErrMsgPaused) } return []crosschaintypes.OutboundTracker{}, nil } -func (z *MockZetaCoreClient) GetCrosschainFlags() (observerTypes.CrosschainFlags, error) { - if z.paused { +func (m *MockZetacoreClient) GetCrosschainFlags() (observerTypes.CrosschainFlags, error) { + if m.paused { return observerTypes.CrosschainFlags{}, errors.New(ErrMsgPaused) } return observerTypes.CrosschainFlags{}, nil } -func (z *MockZetaCoreClient) GetRateLimiterFlags() (crosschaintypes.RateLimiterFlags, error) { - if z.paused { +func (m *MockZetacoreClient) GetRateLimiterFlags() (crosschaintypes.RateLimiterFlags, error) { + if m.paused { return crosschaintypes.RateLimiterFlags{}, errors.New(ErrMsgPaused) } - if z.rateLimiterFlags == nil { + if m.rateLimiterFlags == nil { return crosschaintypes.RateLimiterFlags{}, errors.New(ErrMsgRPCFailed) } - return *z.rateLimiterFlags, nil + return *m.rateLimiterFlags, nil } -func (z *MockZetaCoreClient) GetObserverList() ([]string, error) { - if z.paused { +func (m *MockZetacoreClient) GetObserverList() ([]string, error) { + if m.paused { return nil, errors.New(ErrMsgPaused) } return []string{}, nil } -func (z *MockZetaCoreClient) GetBtcTssAddress(_ int64) (string, error) { - if z.paused { +func (m *MockZetacoreClient) GetBtcTssAddress(_ int64) (string, error) { + if m.paused { return "", errors.New(ErrMsgPaused) } return testutils.TSSAddressBTCMainnet, nil } -func (z *MockZetaCoreClient) GetInboundTrackersForChain(_ int64) ([]crosschaintypes.InboundTracker, error) { - if z.paused { +func (m *MockZetacoreClient) GetInboundTrackersForChain(_ int64) ([]crosschaintypes.InboundTracker, error) { + if m.paused { return nil, errors.New(ErrMsgPaused) } return []crosschaintypes.InboundTracker{}, nil } -func (z *MockZetaCoreClient) Pause() { - z.paused = true +func (m *MockZetacoreClient) Pause() { + m.paused = true } -func (z *MockZetaCoreClient) Unpause() { - z.paused = false +func (m *MockZetacoreClient) Unpause() { + m.paused = false } -func (z *MockZetaCoreClient) GetZetaHotKeyBalance() (math.Int, error) { - if z.paused { +func (m *MockZetacoreClient) GetZetaHotKeyBalance() (math.Int, error) { + if m.paused { return math.NewInt(0), errors.New(ErrMsgPaused) } return math.NewInt(0), nil @@ -242,17 +241,22 @@ func (z *MockZetaCoreClient) GetZetaHotKeyBalance() (math.Int, error) { // Feed data to the mock zetacore client for testing // ---------------------------------------------------------------------------- -func (z *MockZetaCoreClient) WithPendingCctx(chainID int64, cctxs []*crosschaintypes.CrossChainTx) *MockZetaCoreClient { - z.pendingCctxs[chainID] = cctxs - return z +func (m *MockZetacoreClient) WithKeys(keys keyinterfaces.ObserverKeys) *MockZetacoreClient { + m.keys = keys + return m +} + +func (m *MockZetacoreClient) WithPendingCctx(chainID int64, cctxs []*crosschaintypes.CrossChainTx) *MockZetacoreClient { + m.pendingCctxs[chainID] = cctxs + return m } -func (z *MockZetaCoreClient) WithRateLimiterFlags(flags *crosschaintypes.RateLimiterFlags) *MockZetaCoreClient { - z.rateLimiterFlags = flags - return z +func (m *MockZetacoreClient) WithRateLimiterFlags(flags *crosschaintypes.RateLimiterFlags) *MockZetacoreClient { + m.rateLimiterFlags = flags + return m } -func (z *MockZetaCoreClient) WithRateLimiterInput(input *crosschaintypes.QueryRateLimiterInputResponse) *MockZetaCoreClient { - z.input = input - return z +func (m *MockZetacoreClient) WithRateLimiterInput(input *crosschaintypes.QueryRateLimiterInputResponse) *MockZetacoreClient { + m.input = input + return m } diff --git a/zetaclient/zetacore/broadcast.go b/zetaclient/zetacore/broadcast.go index a230df6258..7991f7edc6 100644 --- a/zetaclient/zetacore/broadcast.go +++ b/zetaclient/zetacore/broadcast.go @@ -152,7 +152,7 @@ func (c *Client) Broadcast(gaslimit uint64, authzWrappedMsg sdktypes.Msg, authzS // GetContext return a valid context with all relevant values set func (c *Client) GetContext() (client.Context, error) { ctx := client.Context{} - addr, err := c.keys.GetSignerInfo().GetAddress() + addr, err := c.keys.GetAddress() if err != nil { c.logger.Error().Err(err).Msg("fail to get address from key") return ctx, err diff --git a/zetaclient/zetacore/broadcast_test.go b/zetaclient/zetacore/broadcast_test.go index fbf9c756cf..b0aaaa8ca7 100644 --- a/zetaclient/zetacore/broadcast_test.go +++ b/zetaclient/zetacore/broadcast_test.go @@ -73,7 +73,7 @@ func TestBroadcast(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") t.Run("broadcast success", func(t *testing.T) { client.EnableMockSDKClient(mocks.NewSDKClientWithErr(nil, 0)) @@ -96,14 +96,13 @@ func TestBroadcast(t *testing.T) { _, err = BroadcastToZetaCore(client, 10000, authzMsg, authzSigner) require.Error(t, err) }) - } func TestZetacore_GetContext(t *testing.T) { address := types.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) client, err := setupZetacoreClient() require.NoError(t, err) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") _, err = client.GetContext() require.NoError(t, err) diff --git a/zetaclient/zetacore/client.go b/zetaclient/zetacore/client.go index 0fb3d9bdc6..05a54a4a38 100644 --- a/zetaclient/zetacore/client.go +++ b/zetaclient/zetacore/client.go @@ -7,6 +7,7 @@ import ( "cosmossdk.io/simapp/params" rpcclient "github.com/cometbft/cometbft/rpc/client" + "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/zeta-chain/zetacore/app" @@ -16,7 +17,7 @@ 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/keys" + keyinterfaces "github.com/zeta-chain/zetacore/zetaclient/keys/interfaces" "github.com/zeta-chain/zetacore/zetaclient/metrics" "google.golang.org/grpc" ) @@ -32,7 +33,7 @@ type Client struct { grpcConn *grpc.ClientConn cfg config.ClientConfiguration encodingCfg params.EncodingConfig - keys *keys.Keys + keys keyinterfaces.ObserverKeys broadcastLock *sync.RWMutex chainID string chain chains.Chain @@ -48,7 +49,7 @@ type Client struct { // NewClient create a new instance of Client func NewClient( - k *keys.Keys, + keys keyinterfaces.ObserverKeys, chainIP string, signerName string, chainID string, @@ -57,7 +58,7 @@ func NewClient( ) (*Client, error) { // main module logger - logger := log.With().Str("module", "ZetaCoreClient").Logger() + logger := log.With().Str("module", "ZetacoreClient").Logger() cfg := config.ClientConfiguration{ ChainHost: fmt.Sprintf("%s:1317", chainIP), SignerName: signerName, @@ -93,7 +94,7 @@ func NewClient( seqNumber: seqMap, cfg: cfg, encodingCfg: app.MakeEncodingConfig(), - keys: k, + keys: keys, broadcastLock: &sync.RWMutex{}, stop: make(chan struct{}), chainID: chainID, @@ -128,7 +129,7 @@ func (c *Client) GetLogger() *zerolog.Logger { return &c.logger } -func (c *Client) GetKeys() *keys.Keys { +func (c *Client) GetKeys() keyinterfaces.ObserverKeys { return c.keys } @@ -143,27 +144,35 @@ func (c *Client) GetAccountNumberAndSequenceNumber(_ authz.KeyType) (uint64, uin if err != nil { return 0, 0, err } - address := c.keys.GetAddress() + address, err := c.keys.GetAddress() + if err != nil { + return 0, 0, err + } return ctx.AccountRetriever.GetAccountNumberSequence(ctx, address) } -func (c *Client) SetAccountNumber(keyType authz.KeyType) { +// SetAccountNumber sets the account number and sequence number for the given keyType +func (c *Client) SetAccountNumber(keyType authz.KeyType) error { ctx, err := c.GetContext() if err != nil { - c.logger.Error().Err(err).Msg("fail to get context") - return + return errors.Wrap(err, "fail to get context") + } + address, err := c.keys.GetAddress() + if err != nil { + return errors.Wrap(err, "fail to get address") } - address := c.keys.GetAddress() accN, seq, err := ctx.AccountRetriever.GetAccountNumberSequence(ctx, address) if err != nil { - c.logger.Error().Err(err).Msg("fail to get account number and sequence number") - return + return errors.Wrap(err, "fail to get account number and sequence number") } c.accountNumber[keyType] = accN c.seqNumber[keyType] = seq + + return nil } -func (c *Client) WaitForCoreToCreateBlocks() { +// WaitForZetacoreToCreateBlocks waits for zetacore to create blocks +func (c *Client) WaitForZetacoreToCreateBlocks() error { retryCount := 0 for { block, err := c.GetLatestZetaBlock() @@ -174,10 +183,11 @@ func (c *Client) WaitForCoreToCreateBlocks() { retryCount++ c.logger.Debug().Msgf("Failed to get latest Block , Retry : %d/%d", retryCount, DefaultRetryCount) if retryCount > ExtendedRetryCount { - panic(fmt.Sprintf("Zetacore is not ready, waited for %d seconds", DefaultRetryCount*DefaultRetryInterval)) + return fmt.Errorf("zetacore is not ready, waited for %d seconds", DefaultRetryCount*DefaultRetryInterval) } time.Sleep(DefaultRetryInterval * time.Second) } + return nil } // UpdateZetacoreContext updates zetacore context diff --git a/zetaclient/zetacore/query.go b/zetaclient/zetacore/query.go index 4623f31a97..d813c3768b 100644 --- a/zetaclient/zetacore/query.go +++ b/zetaclient/zetacore/query.go @@ -483,8 +483,12 @@ func (c *Client) HasVoted(ballotIndex string, voterAddress string) (bool, error) func (c *Client) GetZetaHotKeyBalance() (sdkmath.Int, error) { client := banktypes.NewQueryClient(c.grpcConn) + address, err := c.keys.GetAddress() + if err != nil { + return sdkmath.ZeroInt(), err + } resp, err := client.Balance(context.Background(), &banktypes.QueryBalanceRequest{ - Address: c.keys.GetAddress().String(), + Address: address.String(), Denom: config.BaseDenom, }) if err != nil { diff --git a/zetaclient/zetacore/query_test.go b/zetaclient/zetacore/query_test.go index 3541983dd9..b1b2aedd2b 100644 --- a/zetaclient/zetacore/query_test.go +++ b/zetaclient/zetacore/query_test.go @@ -55,7 +55,7 @@ func setupZetacoreClient() (*Client, error) { return NewClient( &keys.Keys{}, "127.0.0.1", - "", + testSigner, "zetachain_7000-1", false, &metrics.TelemetryServer{}) @@ -959,9 +959,16 @@ func TestZetacore_GetZetaHotKeyBalance(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), types.AccAddress{}, "", "") + // should be able to get balance of signer + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), types.AccAddress{}, "bob", "") resp, err := client.GetZetaHotKeyBalance() require.NoError(t, err) require.Equal(t, expectedOutput.Balance.Amount, resp) + + // should return error on empty signer + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), types.AccAddress{}, "", "") + resp, err = client.GetZetaHotKeyBalance() + require.Error(t, err) + require.Equal(t, types.ZeroInt(), resp) } diff --git a/zetaclient/zetacore/tx_test.go b/zetaclient/zetacore/tx_test.go index e1f9e3ea97..335769a82f 100644 --- a/zetaclient/zetacore/tx_test.go +++ b/zetaclient/zetacore/tx_test.go @@ -32,6 +32,7 @@ import ( ) const ( + testSigner = `jack` sampleHash = "fa51db4412144f1130669f2bae8cb44aadbd8d85958dbffcb0fe236878097e1a" ethBlockHash = "1a17bcc359e84ba8ae03b17ec425f97022cd11c3e279f6bdf7a96fcffa12b366" ) @@ -139,7 +140,7 @@ func TestZetacore_PostGasPrice(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) address := sdktypes.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") t.Run("post gas price success", func(t *testing.T) { zetacoreBroadcast = MockBroadcast @@ -162,7 +163,7 @@ func TestZetacore_AddOutboundTracker(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) address := sdktypes.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") t.Run("add tx hash success", func(t *testing.T) { zetacoreBroadcast = MockBroadcast @@ -183,7 +184,7 @@ func TestZetacore_SetTSS(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) address := sdktypes.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") t.Run("set tss success", func(t *testing.T) { zetacoreBroadcast = MockBroadcast @@ -325,7 +326,7 @@ func TestZetacore_UpdateZetacoreContext(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) address := sdktypes.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") client.EnableMockSDKClient(mocks.NewSDKClientWithErr(nil, 0)) t.Run("zetacore update success", func(t *testing.T) { @@ -341,7 +342,7 @@ func TestZetacore_PostBlameData(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) address := sdktypes.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") t.Run("post blame data success", func(t *testing.T) { zetacoreBroadcast = MockBroadcast @@ -363,7 +364,7 @@ func TestZetacore_PostVoteBlockHeader(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) address := sdktypes.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") blockHash, err := hex.DecodeString(ethBlockHash) require.NoError(t, err) @@ -395,7 +396,7 @@ func TestZetacore_PostVoteInbound(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") client.EnableMockSDKClient(mocks.NewSDKClientWithErr(nil, 0)) t.Run("post inbound vote already voted", func(t *testing.T) { @@ -434,7 +435,7 @@ func TestZetacore_MonitorVoteInboundResult(t *testing.T) { address := sdktypes.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) client, err := setupZetacoreClient() require.NoError(t, err) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") client.EnableMockSDKClient(mocks.NewSDKClientWithErr(nil, 0)) t.Run("monitor inbound vote", func(t *testing.T) { @@ -462,7 +463,7 @@ func TestZetacore_PostVoteOutbound(t *testing.T) { client, err := setupZetacoreClient() require.NoError(t, err) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") client.EnableMockSDKClient(mocks.NewSDKClientWithErr(nil, 0)) zetacoreBroadcast = MockBroadcast @@ -487,7 +488,7 @@ func TestZetacore_MonitorVoteOutboundResult(t *testing.T) { address := sdktypes.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) client, err := setupZetacoreClient() require.NoError(t, err) - client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, "", "") + client.keys = keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "") client.EnableMockSDKClient(mocks.NewSDKClientWithErr(nil, 0)) t.Run("monitor outbound vote", func(t *testing.T) {