diff --git a/changelog.md b/changelog.md index 528b4db956..e3c0336caa 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ * [3118](https://github.com/zeta-chain/node/pull/3118) - zetaclient: remove hsm signer * [3122](https://github.com/zeta-chain/node/pull/3122) - improve & refactor zetaclientd cli * [3125](https://github.com/zeta-chain/node/pull/3125) - drop support for header proofs +* [3131](https://github.com/zeta-chain/node/pull/3131) - move app context update from zetacore client * [3137](https://github.com/zeta-chain/node/pull/3137) - remove chain.Chain from zetaclientd config ### Fixes diff --git a/cmd/zetaclientd/inbound.go b/cmd/zetaclientd/inbound.go index bac3c96725..20a3422a37 100644 --- a/cmd/zetaclientd/inbound.go +++ b/cmd/zetaclientd/inbound.go @@ -22,6 +22,7 @@ import ( "github.com/zeta-chain/node/zetaclient/config" zctx "github.com/zeta-chain/node/zetaclient/context" "github.com/zeta-chain/node/zetaclient/keys" + "github.com/zeta-chain/node/zetaclient/orchestrator" "github.com/zeta-chain/node/zetaclient/zetacore" ) @@ -69,7 +70,8 @@ func InboundGetBallot(_ *cobra.Command, args []string) error { appContext := zctx.New(cfg, nil, zerolog.Nop()) ctx := zctx.WithAppContext(context.Background(), appContext) - if err := client.UpdateAppContext(ctx, appContext, zerolog.Nop()); err != nil { + err = orchestrator.UpdateAppContext(ctx, appContext, client, zerolog.Nop()) + if err != nil { return errors.Wrap(err, "failed to update app context") } diff --git a/cmd/zetaclientd/start.go b/cmd/zetaclientd/start.go index 6c3493ad06..46d204fa34 100644 --- a/cmd/zetaclientd/start.go +++ b/cmd/zetaclientd/start.go @@ -27,6 +27,7 @@ import ( "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/constant" zetaos "github.com/zeta-chain/node/pkg/os" + "github.com/zeta-chain/node/pkg/ticker" observerTypes "github.com/zeta-chain/node/x/observer/types" "github.com/zeta-chain/node/zetaclient/chains/base" "github.com/zeta-chain/node/zetaclient/config" @@ -100,7 +101,7 @@ func Start(_ *cobra.Command, _ []string) error { } // Wait until zetacore is ready to create blocks - if err = zetacoreClient.WaitForZetacoreToCreateBlocks(ctx); err != nil { + if err = waitForZetacoreToCreateBlocks(ctx, zetacoreClient, startLogger); err != nil { startLogger.Error().Err(err).Msg("WaitForZetacoreToCreateBlocks error") return err } @@ -141,14 +142,12 @@ func Start(_ *cobra.Command, _ []string) error { startLogger.Debug().Msgf("createAuthzSigner is ready") // Initialize core parameters from zetacore - if err = zetacoreClient.UpdateAppContext(ctx, appContext, startLogger); err != nil { + if err = orchestrator.UpdateAppContext(ctx, appContext, zetacoreClient, startLogger); err != nil { return errors.Wrap(err, "unable to update app context") } startLogger.Info().Msgf("Config is updated from zetacore\n %s", cfg.StringMasked()) - go zetacoreClient.UpdateAppContextWorker(ctx, appContext) - // Generate TSS address . The Tss address is generated through Keygen ceremony. The TSS key is used to sign all outbound transactions . // The hotkeyPk is private key for the Hotkey. The Hotkey is used to sign all inbound transactions // Each node processes a portion of the key stored in ~/.tss by default . Custom location can be specified in config file during init. @@ -201,33 +200,36 @@ func Start(_ *cobra.Command, _ []string) error { } // Create TSS server - server, err := mc.SetupTSSServer(peers, priKey, preParams, appContext.Config(), tssKeyPass, true, whitelistedPeers) + tssServer, err := mc.SetupTSSServer( + peers, + priKey, + preParams, + appContext.Config(), + tssKeyPass, + true, + whitelistedPeers, + ) if err != nil { return fmt.Errorf("SetupTSSServer error: %w", err) } + // Set P2P ID for telemetry - telemetryServer.SetP2PID(server.GetLocalPeerID()) + telemetryServer.SetP2PID(tssServer.GetLocalPeerID()) // Creating a channel to listen for os signals (or other signals) signalChannel := make(chan os.Signal, 1) signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM) - // Maintenance workers ============ - maintenance.NewTSSListener(zetacoreClient, masterLogger).Listen(ctx, func() { - masterLogger.Info().Msg("TSS listener received an action to shutdown zetaclientd.") - signalChannel <- syscall.SIGTERM - }) - go func() { for { time.Sleep(30 * time.Second) - ps := server.GetKnownPeers() + ps := tssServer.GetKnownPeers() metrics.NumConnectedPeers.Set(float64(len(ps))) telemetryServer.SetConnectedPeers(ps) } }() go func() { - host := server.GetP2PHost() + host := tssServer.GetP2PHost() pingRTT := make(map[peer.ID]int64) for { var wg sync.WaitGroup @@ -254,7 +256,7 @@ func Start(_ *cobra.Command, _ []string) error { // Generate a new TSS if keygen is set and add it into the tss server // If TSS has already been generated, and keygen was successful ; we use the existing TSS - err = mc.Generate(ctx, masterLogger, zetacoreClient, server) + err = mc.Generate(ctx, zetacoreClient, tssServer, masterLogger) if err != nil { return err } @@ -264,7 +266,7 @@ func Start(_ *cobra.Command, _ []string) error { zetacoreClient, tssHistoricalList, hotkeyPass, - server, + tssServer, ) if err != nil { startLogger.Error().Err(err).Msg("NewTSS error") @@ -279,23 +281,26 @@ func Start(_ *cobra.Command, _ []string) error { // Wait for TSS keygen to be successful before proceeding, This is a blocking thread only for a new keygen. // For existing keygen, this should directly proceed to the next step - ticker := time.NewTicker(time.Second * 1) - for range ticker.C { - keyGen := appContext.GetKeygen() - if keyGen.Status != observerTypes.KeygenStatus_KeyGenSuccess { - startLogger.Info().Msgf("Waiting for TSS Keygen to be a success, current status %s", keyGen.Status) - continue + _ = ticker.Run(ctx, time.Second, func(ctx context.Context, t *ticker.Ticker) error { + keygen, err = zetacoreClient.GetKeyGen(ctx) + switch { + case err != nil: + startLogger.Warn().Err(err).Msg("Waiting for TSS Keygen to be a success, got error") + case keygen.Status != observerTypes.KeygenStatus_KeyGenSuccess: + startLogger.Warn().Msgf("Waiting for TSS Keygen to be a success, current status %s", keygen.Status) + default: + t.Stop() } - break - } + + return nil + }) // Update Current TSS value from zetacore, if TSS keygen is successful, the TSS address is set on zeta-core // Returns err if the RPC call fails as zeta client needs the current TSS address to be set // This is only needed in case of a new Keygen , as the TSS address is set on zetacore only after the keygen is successful i.e enough votes have been broadcast currentTss, err := zetacoreClient.GetTSS(ctx) if err != nil { - startLogger.Error().Err(err).Msg("GetCurrentTSS error") - return err + return errors.Wrap(err, "unable to get current TSS") } // Filter supported BTC chain IDs @@ -314,6 +319,13 @@ func Start(_ *cobra.Command, _ []string) error { return err } + // Starts various background TSS listeners. + // Shuts down zetaclientd if any is triggered. + maintenance.NewTSSListener(zetacoreClient, masterLogger).Listen(ctx, func() { + masterLogger.Info().Msg("TSS listener received an action to shutdown zetaclientd.") + signalChannel <- syscall.SIGTERM + }) + if len(appContext.ListChainIDs()) == 0 { startLogger.Error().Interface("config", cfg).Msgf("No chains in updated config") } @@ -348,12 +360,12 @@ func Start(_ *cobra.Command, _ []string) error { // Each chain observer is responsible for observing events on the chain and processing them. observerMap, err := orchestrator.CreateChainObserverMap(ctx, zetacoreClient, tss, dbpath, logger, telemetryServer) if err != nil { - startLogger.Err(err).Msg("CreateChainObserverMap") - return err + return errors.Wrap(err, "unable to create chain observer map") } // Orchestrator wraps the zetacore client and adds the observers and signer maps to it. // This is the high level object used for CCTX interactions + // It also handles background configuration updates from zetacore maestro, err := orchestrator.New( ctx, zetacoreClient, @@ -365,14 +377,12 @@ func Start(_ *cobra.Command, _ []string) error { telemetryServer, ) if err != nil { - startLogger.Error().Err(err).Msg("Unable to create orchestrator") - return err + return errors.Wrap(err, "unable to create orchestrator") } // Start orchestrator with all observers and signers - if err := maestro.Start(ctx); err != nil { - startLogger.Error().Err(err).Msg("Unable to start orchestrator") - return err + if err = maestro.Start(ctx); err != nil { + return errors.Wrap(err, "unable to start orchestrator") } // start zeta supply checker @@ -389,12 +399,12 @@ func Start(_ *cobra.Command, _ []string) error { // defer zetaSupplyChecker.Stop() //} - startLogger.Info().Msgf("Zetaclientd is running") + startLogger.Info().Msg("zetaclientd is running") sig := <-signalChannel - startLogger.Info().Msgf("Stop signal received: %q", sig) + startLogger.Info().Msgf("Stop signal received: %q. Stopping zetaclientd", sig) - zetacoreClient.Stop() + maestro.Stop() return nil } diff --git a/cmd/zetaclientd/utils.go b/cmd/zetaclientd/utils.go index 011a1bc0ab..53f2f208bc 100644 --- a/cmd/zetaclientd/utils.go +++ b/cmd/zetaclientd/utils.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "net" "strings" @@ -13,6 +14,7 @@ import ( "google.golang.org/grpc/credentials/insecure" "github.com/zeta-chain/node/zetaclient/authz" + "github.com/zeta-chain/node/zetaclient/chains/interfaces" "github.com/zeta-chain/node/zetaclient/config" "github.com/zeta-chain/node/zetaclient/keys" "github.com/zeta-chain/node/zetaclient/zetacore" @@ -71,6 +73,34 @@ func waitForZetaCore(config config.Config, logger zerolog.Logger) { } } +func waitForZetacoreToCreateBlocks(ctx context.Context, zc interfaces.ZetacoreClient, logger zerolog.Logger) error { + const ( + interval = 5 * time.Second + attempts = 15 + ) + + var ( + retryCount = 0 + start = time.Now() + ) + + for { + blockHeight, err := zc.GetBlockHeight(ctx) + if err == nil && blockHeight > 1 { + logger.Info().Msgf("Zeta block height: %d", blockHeight) + return nil + } + + retryCount++ + if retryCount > attempts { + return fmt.Errorf("zetacore is not ready, timeout %s", time.Since(start).String()) + } + + logger.Info().Msgf("Failed to get block number, retry : %d/%d", retryCount, attempts) + time.Sleep(interval) + } +} + func validatePeer(seedPeer string) error { parsedPeer := strings.Split(seedPeer, "/") diff --git a/pkg/rpc/clients.go b/pkg/rpc/clients.go index 1dc0d7314e..4d94b317e4 100644 --- a/pkg/rpc/clients.go +++ b/pkg/rpc/clients.go @@ -98,7 +98,7 @@ func NewCometBFTClients(url string) (Clients, error) { return newClients(clientCtx) } -// NewGRPCClient creates a Clients which uses gRPC as the transport +// NewGRPCClients creates a Clients which uses gRPC as the transport func NewGRPCClients(url string, opts ...grpc.DialOption) (Clients, error) { grpcConn, err := grpc.Dial(url, opts...) if err != nil { diff --git a/pkg/rpc/clients_cosmos.go b/pkg/rpc/clients_cosmos.go index 329b5c2e20..59be82bfb5 100644 --- a/pkg/rpc/clients_cosmos.go +++ b/pkg/rpc/clients_cosmos.go @@ -11,8 +11,7 @@ import ( "github.com/zeta-chain/node/cmd/zetacored/config" ) -// GetUpgradePlan returns the current upgrade plan. -// if there is no active upgrade plan, plan will be nil, err will be nil as well. +// GetUpgradePlan returns the current upgrade plan or nil if there is no plan. func (c *Clients) GetUpgradePlan(ctx context.Context) (*upgradetypes.Plan, error) { in := &upgradetypes.QueryCurrentPlanRequest{} diff --git a/zetaclient/chains/interfaces/interfaces.go b/zetaclient/chains/interfaces/interfaces.go index 0043d0a7a9..4ed7c0797e 100644 --- a/zetaclient/chains/interfaces/interfaces.go +++ b/zetaclient/chains/interfaces/interfaces.go @@ -11,6 +11,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/wire" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -102,6 +103,10 @@ type ZetacoreClient interface { GetLogger() *zerolog.Logger GetKeys() keyinterfaces.ObserverKeys + GetSupportedChains(ctx context.Context) ([]chains.Chain, error) + GetAdditionalChains(ctx context.Context) ([]chains.Chain, error) + GetChainParams(ctx context.Context) ([]*observertypes.ChainParams, error) + GetKeyGen(ctx context.Context) (observertypes.Keygen, error) GetTSS(ctx context.Context) (observertypes.TSS, error) GetTSSHistory(ctx context.Context) ([]observertypes.TSS, error) @@ -130,10 +135,9 @@ type ZetacoreClient interface { GetZetaHotKeyBalance(ctx context.Context) (sdkmath.Int, error) GetInboundTrackersForChain(ctx context.Context, chainID int64) ([]crosschaintypes.InboundTracker, error) - PostOutboundTracker(ctx context.Context, chainID int64, nonce uint64, txHash string) (string, error) + GetUpgradePlan(ctx context.Context) (*upgradetypes.Plan, error) - Stop() - OnBeforeStop(callback func()) + PostOutboundTracker(ctx context.Context, chainID int64, nonce uint64, txHash string) (string, error) } // BTCRPCClient is the interface for BTC RPC client diff --git a/zetaclient/orchestrator/contextupdater.go b/zetaclient/orchestrator/contextupdater.go new file mode 100644 index 0000000000..02e4b275e0 --- /dev/null +++ b/zetaclient/orchestrator/contextupdater.go @@ -0,0 +1,172 @@ +package orchestrator + +import ( + "context" + + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/pkg/errors" + "github.com/rs/zerolog" + + "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/pkg/ticker" + observertypes "github.com/zeta-chain/node/x/observer/types" + zctx "github.com/zeta-chain/node/zetaclient/context" +) + +type Zetacore interface { + GetBlockHeight(ctx context.Context) (int64, error) + GetUpgradePlan(ctx context.Context) (*upgradetypes.Plan, error) + GetSupportedChains(ctx context.Context) ([]chains.Chain, error) + GetAdditionalChains(ctx context.Context) ([]chains.Chain, error) + GetCrosschainFlags(ctx context.Context) (observertypes.CrosschainFlags, error) + GetChainParams(ctx context.Context) ([]*observertypes.ChainParams, error) + GetTSS(ctx context.Context) (observertypes.TSS, error) + GetKeyGen(ctx context.Context) (observertypes.Keygen, error) +} + +var ErrUpgradeRequired = errors.New("upgrade required") + +func (oc *Orchestrator) runAppContextUpdater(ctx context.Context) error { + app, err := zctx.FromContext(ctx) + if err != nil { + return err + } + + interval := ticker.DurationFromUint64Seconds(app.Config().ConfigUpdateTicker) + + oc.logger.Info().Msg("UpdateAppContext worker started") + + task := func(ctx context.Context, t *ticker.Ticker) error { + err := UpdateAppContext(ctx, app, oc.zetacoreClient, oc.logger.Sampled) + switch { + case errors.Is(err, ErrUpgradeRequired): + oc.onUpgradeDetected(err) + t.Stop() + return nil + case err != nil: + oc.logger.Err(err).Msg("UpdateAppContext failed") + } + + return nil + } + + return ticker.Run( + ctx, + interval, + task, + ticker.WithLogger(oc.logger.Logger, "UpdateAppContext"), + ticker.WithStopChan(oc.stop), + ) +} + +// UpdateAppContext fetches latest data from Zetacore and updates the AppContext. +// Also detects if an upgrade is required. If an upgrade is required, it returns ErrUpgradeRequired. +func UpdateAppContext(ctx context.Context, app *zctx.AppContext, zc Zetacore, logger zerolog.Logger) error { + bn, err := zc.GetBlockHeight(ctx) + if err != nil { + return errors.Wrap(err, "unable to get zeta block height") + } + + if err = checkForZetacoreUpgrade(ctx, bn, zc); err != nil { + return err + } + + supportedChains, err := zc.GetSupportedChains(ctx) + if err != nil { + return errors.Wrap(err, "unable to fetch supported chains") + } + + additionalChains, err := zc.GetAdditionalChains(ctx) + if err != nil { + return errors.Wrap(err, "unable to fetch additional chains") + } + + chainParams, err := zc.GetChainParams(ctx) + if err != nil { + return errors.Wrap(err, "unable to fetch chain params") + } + + keyGen, err := zc.GetKeyGen(ctx) + if err != nil { + return errors.Wrap(err, "unable to fetch keygen from zetacore") + } + + crosschainFlags, err := zc.GetCrosschainFlags(ctx) + if err != nil { + return errors.Wrap(err, "unable to fetch crosschain flags from zetacore") + } + + tss, err := zc.GetTSS(ctx) + if err != nil { + return errors.Wrap(err, "unable to fetch current TSS") + } + + freshParams := make(map[int64]*observertypes.ChainParams, len(chainParams)) + + // check and update chain params for each chain + // Note that we are EXCLUDING ZetaChain from the chainParams if it's present + for i := range chainParams { + cp := chainParams[i] + + if !cp.IsSupported { + logger.Warn().Int64("chain.id", cp.ChainId).Msg("Skipping unsupported chain") + continue + } + + if chains.IsZetaChain(cp.ChainId, nil) { + continue + } + + if err := observertypes.ValidateChainParams(cp); err != nil { + logger.Warn().Err(err).Int64("chain.id", cp.ChainId).Msg("Skipping invalid chain params") + continue + } + + freshParams[cp.ChainId] = cp + } + + return app.Update( + keyGen, + supportedChains, + additionalChains, + freshParams, + tss.GetTssPubkey(), + crosschainFlags, + ) +} + +// returns an error if an upgrade is required +func checkForZetacoreUpgrade(ctx context.Context, zetaHeight int64, zc Zetacore) error { + plan, err := zc.GetUpgradePlan(ctx) + switch { + case err != nil: + return errors.Wrap(err, "unable to get upgrade plan") + case plan == nil: + // no upgrade planned + return nil + } + + upgradeHeight := plan.Height + + // We can return an error in a few blocks ahead. + // It's okay because the ticker might have an interval longer than 1 block (~5s). + // + // Example: if an upgrade is on block #102, we can return an error on block #100, #101, #102, ... + // Note that tha plan is deleted from zetacore after the upgrade block. + const upgradeBlockBuffer = 2 + + if (upgradeHeight - zetaHeight) <= upgradeBlockBuffer { + return errors.Wrapf(ErrUpgradeRequired, "current height: %d, upgrade height: %d", zetaHeight, upgradeHeight) + } + + return nil +} + +// onUpgradeDetected is called when an upgrade is detected. +func (oc *Orchestrator) onUpgradeDetected(errDetected error) { + const msg = "Upgrade detected." + + " Kill the process, replace the binary with upgraded version, and restart zetaclientd" + + oc.logger.Warn().Str("upgrade", errDetected.Error()).Msg(msg) + oc.Stop() +} diff --git a/zetaclient/orchestrator/contextupdater_test.go b/zetaclient/orchestrator/contextupdater_test.go new file mode 100644 index 0000000000..cc28d5ad9e --- /dev/null +++ b/zetaclient/orchestrator/contextupdater_test.go @@ -0,0 +1,82 @@ +package orchestrator + +import ( + "context" + "testing" + + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/rs/zerolog" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/chains" + observertypes "github.com/zeta-chain/node/x/observer/types" + "github.com/zeta-chain/node/zetaclient/testutils/mocks" +) + +func Test_UpdateAppContext(t *testing.T) { + var ( + eth = chains.Ethereum + ethParams = mocks.MockChainParams(eth.ChainId, 100) + + btc = chains.BitcoinMainnet + btcParams = mocks.MockChainParams(btc.ChainId, 100) + ) + + t.Run("Updates app context", func(t *testing.T) { + var ( + ctx = context.Background() + app = createAppContext(t, eth, ethParams) + zetacore = mocks.NewZetacoreClient(t) + logger = zerolog.New(zerolog.NewTestWriter(t)) + ) + + // Given zetacore client that has eth and btc chains + newChains := []chains.Chain{eth, btc} + newParams := []*observertypes.ChainParams{ðParams, &btcParams} + ccFlags := observertypes.CrosschainFlags{ + IsInboundEnabled: true, + IsOutboundEnabled: true, + } + + zetacore.On("GetBlockHeight", mock.Anything).Return(int64(123), nil) + zetacore.On("GetUpgradePlan", mock.Anything).Return(nil, nil) + zetacore.On("GetSupportedChains", mock.Anything).Return(newChains, nil) + zetacore.On("GetAdditionalChains", mock.Anything).Return(nil, nil) + zetacore.On("GetChainParams", mock.Anything).Return(newParams, nil) + zetacore.On("GetKeyGen", mock.Anything).Return(observertypes.Keygen{}, nil) + zetacore.On("GetCrosschainFlags", mock.Anything).Return(ccFlags, nil) + zetacore.On("GetTSS", mock.Anything).Return(observertypes.TSS{TssPubkey: "0x123"}, nil) + + // ACT + err := UpdateAppContext(ctx, app, zetacore, logger) + + // ASSERT + require.NoError(t, err) + + // New chains should be added + _, err = app.GetChain(btc.ChainId) + require.NoError(t, err) + }) + + t.Run("Upgrade plan detected", func(t *testing.T) { + // ARRANGE + var ( + ctx = context.Background() + app = createAppContext(t, eth, ethParams) + zetacore = mocks.NewZetacoreClient(t) + logger = zerolog.New(zerolog.NewTestWriter(t)) + ) + + zetacore.On("GetBlockHeight", mock.Anything).Return(int64(123), nil) + zetacore.On("GetUpgradePlan", mock.Anything).Return(&upgradetypes.Plan{ + Name: "hello", + Height: 124, + }, nil) + + // ACT + err := UpdateAppContext(ctx, app, zetacore, logger) + + // ASSERT + require.ErrorIs(t, err, ErrUpgradeRequired) + }) +} diff --git a/zetaclient/orchestrator/orchestrator.go b/zetaclient/orchestrator/orchestrator.go index 986b799f72..c29b41466a 100644 --- a/zetaclient/orchestrator/orchestrator.go +++ b/zetaclient/orchestrator/orchestrator.go @@ -132,20 +132,17 @@ func (oc *Orchestrator) Start(ctx context.Context) error { oc.logger.Info().Str("signer", signerAddress.String()).Msg("Starting orchestrator") - // start cctx scheduler bg.Work(ctx, oc.runScheduler, bg.WithName("runScheduler"), bg.WithLogger(oc.logger.Logger)) bg.Work(ctx, oc.runObserverSignerSync, bg.WithName("runObserverSignerSync"), bg.WithLogger(oc.logger.Logger)) - - shutdownOrchestrator := func() { - // now stop orchestrator and all observers - close(oc.stop) - } - - oc.zetacoreClient.OnBeforeStop(shutdownOrchestrator) + bg.Work(ctx, oc.runAppContextUpdater, bg.WithName("runAppContextUpdater"), bg.WithLogger(oc.logger.Logger)) return nil } +func (oc *Orchestrator) Stop() { + close(oc.stop) +} + // returns signer with updated chain parameters. func (oc *Orchestrator) resolveSigner(app *zctx.AppContext, chainID int64) (interfaces.ChainSigner, error) { signer, err := oc.getSigner(chainID) @@ -746,7 +743,13 @@ func (oc *Orchestrator) runObserverSignerSync(ctx context.Context) error { return nil } - return ticker.Run(ctx, cadence, task, ticker.WithLogger(oc.logger.Logger, "SyncObserverSigner")) + return ticker.Run( + ctx, + cadence, + task, + ticker.WithLogger(oc.logger.Logger, "SyncObserverSigner"), + ticker.WithStopChan(oc.stop), + ) } // syncs and provisions observers & signers. diff --git a/zetaclient/testutils/mocks/zetacore_client.go b/zetaclient/testutils/mocks/zetacore_client.go index 5bd9b685f9..6bbaee022c 100644 --- a/zetaclient/testutils/mocks/zetacore_client.go +++ b/zetaclient/testutils/mocks/zetacore_client.go @@ -20,6 +20,8 @@ import ( types "github.com/zeta-chain/node/x/crosschain/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + zerolog "github.com/rs/zerolog" ) @@ -46,6 +48,36 @@ func (_m *ZetacoreClient) Chain() chains.Chain { return r0 } +// GetAdditionalChains provides a mock function with given fields: ctx +func (_m *ZetacoreClient) GetAdditionalChains(ctx context.Context) ([]chains.Chain, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAdditionalChains") + } + + var r0 []chains.Chain + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]chains.Chain, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetAllOutboundTrackerByChain provides a mock function with given fields: ctx, chainID, order func (_m *ZetacoreClient) GetAllOutboundTrackerByChain(ctx context.Context, chainID int64, order interfaces.Order) ([]types.OutboundTracker, error) { ret := _m.Called(ctx, chainID, order) @@ -162,6 +194,36 @@ func (_m *ZetacoreClient) GetCctxByNonce(ctx context.Context, chainID int64, non return r0, r1 } +// GetChainParams provides a mock function with given fields: ctx +func (_m *ZetacoreClient) GetChainParams(ctx context.Context) ([]*observertypes.ChainParams, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetChainParams") + } + + var r0 []*observertypes.ChainParams + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]*observertypes.ChainParams, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []*observertypes.ChainParams); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*observertypes.ChainParams) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetCrosschainFlags provides a mock function with given fields: ctx func (_m *ZetacoreClient) GetCrosschainFlags(ctx context.Context) (observertypes.CrosschainFlags, error) { ret := _m.Called(ctx) @@ -434,6 +496,36 @@ func (_m *ZetacoreClient) GetRateLimiterInput(ctx context.Context, window int64) return r0, r1 } +// GetSupportedChains provides a mock function with given fields: ctx +func (_m *ZetacoreClient) GetSupportedChains(ctx context.Context) ([]chains.Chain, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetSupportedChains") + } + + var r0 []chains.Chain + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]chains.Chain, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetTSS provides a mock function with given fields: ctx func (_m *ZetacoreClient) GetTSS(ctx context.Context) (observertypes.TSS, error) { ret := _m.Called(ctx) @@ -492,6 +584,36 @@ func (_m *ZetacoreClient) GetTSSHistory(ctx context.Context) ([]observertypes.TS return r0, r1 } +// GetUpgradePlan provides a mock function with given fields: ctx +func (_m *ZetacoreClient) GetUpgradePlan(ctx context.Context) (*upgradetypes.Plan, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetUpgradePlan") + } + + var r0 *upgradetypes.Plan + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*upgradetypes.Plan, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *upgradetypes.Plan); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*upgradetypes.Plan) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetZetaHotKeyBalance provides a mock function with given fields: ctx func (_m *ZetacoreClient) GetZetaHotKeyBalance(ctx context.Context) (math.Int, error) { ret := _m.Called(ctx) @@ -587,11 +709,6 @@ func (_m *ZetacoreClient) ListPendingCCTXWithinRateLimit(ctx context.Context) (* return r0, r1 } -// OnBeforeStop provides a mock function with given fields: callback -func (_m *ZetacoreClient) OnBeforeStop(callback func()) { - _m.Called(callback) -} - // PostOutboundTracker provides a mock function with given fields: ctx, chainID, nonce, txHash func (_m *ZetacoreClient) PostOutboundTracker(ctx context.Context, chainID int64, nonce uint64, txHash string) (string, error) { ret := _m.Called(ctx, chainID, nonce, txHash) @@ -746,11 +863,6 @@ func (_m *ZetacoreClient) PostVoteOutbound(ctx context.Context, gasLimit uint64, return r0, r1, r2 } -// Stop provides a mock function with given fields: -func (_m *ZetacoreClient) Stop() { - _m.Called() -} - // NewZetacoreClient creates a new instance of ZetacoreClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewZetacoreClient(t interface { diff --git a/zetaclient/tss/generate.go b/zetaclient/tss/generate.go index 5334212332..1adaad8c5c 100644 --- a/zetaclient/tss/generate.go +++ b/zetaclient/tss/generate.go @@ -17,7 +17,7 @@ import ( "github.com/zeta-chain/node/pkg/chains" observertypes "github.com/zeta-chain/node/x/observer/types" "github.com/zeta-chain/node/zetaclient/chains/interfaces" - zctx "github.com/zeta-chain/node/zetaclient/context" + "github.com/zeta-chain/node/zetaclient/logs" "github.com/zeta-chain/node/zetaclient/metrics" "github.com/zeta-chain/node/zetaclient/zetacore" ) @@ -29,15 +29,11 @@ import ( // In case of a failed keygen a TSS failed vote is broadcasted to zetacore. func Generate( ctx context.Context, - logger zerolog.Logger, - zetaCoreClient *zetacore.Client, + zc *zetacore.Client, keygenTssServer *tss.TssServer, + logger zerolog.Logger, ) error { - keygenLogger := logger.With().Str("module", "keygen").Logger() - app, err := zctx.FromContext(ctx) - if err != nil { - return err - } + keygenLogger := logger.With().Str(logs.FieldModule, "tss_keygen").Logger() // If Keygen block is set it will try to generate new TSS at the block // This is a blocking thread and will wait until the ceremony is complete successfully // If the TSS generation is unsuccessful , it will loop indefinitely until a new TSS is generated @@ -52,19 +48,24 @@ func Generate( // Break out of loop only when TSS is generated successfully, either at the keygenBlock or if it has been generated already , Block set as zero in genesis file // This loop will try keygen at the keygen block and then wait for keygen to be successfully reported by all nodes before breaking out of the loop. // If keygen is unsuccessful, it will reset the triedKeygenAtBlock flag and try again at a new keygen block. - keyGen := app.GetKeygen() - if keyGen.Status == observertypes.KeygenStatus_KeyGenSuccess { + keyGen, err := zc.GetKeyGen(ctx) + switch { + case err != nil: + keygenLogger.Error().Err(err).Msg("GetKeyGen RPC error") + continue + case keyGen.Status == observertypes.KeygenStatus_KeyGenSuccess: return nil - } - // Arrive at this stage only if keygen is unsuccessfully reported by every node . This will reset the flag and to try again at a new keygen block - if keyGen.Status == observertypes.KeygenStatus_KeyGenFailed { + case keyGen.Status == observertypes.KeygenStatus_KeyGenFailed: + // Arrive at this stage only if keygen is unsuccessfully reported by every node. + // This will reset the flag and to try again at a new keygen block triedKeygenAtBlock = false continue } + // Try generating TSS at keygen block , only when status is pending keygen and generation has not been tried at the block if keyGen.Status == observertypes.KeygenStatus_PendingKeygen { // Return error if RPC is not working - currentBlock, err := zetaCoreClient.GetBlockHeight(ctx) + currentBlock, err := zc.GetBlockHeight(ctx) if err != nil { keygenLogger.Error().Err(err).Msg("GetBlockHeight RPC error") continue @@ -79,16 +80,16 @@ func Generate( if currentBlock > lastBlock { lastBlock = currentBlock keygenLogger.Info(). - Msgf("Waiting For Keygen Block to arrive or new keygen block to be set. Keygen Block : %d Current Block : %d ChainID %s ", keyGen.BlockNumber, currentBlock, app.Config().ChainID) + Msgf("Waiting For Keygen Block to arrive or new keygen block to be set. Keygen Block: %d; Current Block: %d", keyGen.BlockNumber, currentBlock) } continue } // Try keygen only once at a particular block, irrespective of whether it is successful or failure triedKeygenAtBlock = true - newPubkey, err := keygenTSS(ctx, keyGen, *keygenTssServer, zetaCoreClient, keygenLogger) + newPubkey, err := keygenTSS(ctx, keyGen, *keygenTssServer, zc, keygenLogger) if err != nil { keygenLogger.Error().Err(err).Msg("keygenTSS error") - tssFailedVoteHash, err := zetaCoreClient.PostVoteTSS(ctx, + tssFailedVoteHash, err := zc.PostVoteTSS(ctx, "", keyGen.BlockNumber, chains.ReceiveStatus_failed) if err != nil { keygenLogger.Error().Err(err).Msg("Failed to broadcast Failed TSS Vote to zetacore") @@ -98,7 +99,7 @@ func Generate( continue } // If TSS is successful , broadcast the vote to zetacore and also set the Pubkey - tssSuccessVoteHash, err := zetaCoreClient.PostVoteTSS(ctx, + tssSuccessVoteHash, err := zc.PostVoteTSS(ctx, newPubkey, keyGen.BlockNumber, chains.ReceiveStatus_success, @@ -117,7 +118,7 @@ func Generate( } } keygenLogger.Debug(). - Msgf("Waiting for TSS to be generated or Current Keygen to be be finalized. Keygen Block : %d ", keyGen.BlockNumber) + Msgf("Waiting for TSS to be generated or Current Keygen to be be finalized. Keygen Block: %d", keyGen.BlockNumber) } return errors.New("unexpected state for TSS generation") } @@ -173,7 +174,7 @@ func keygenTSS( // TestTSS tests the TSS keygen by signing a sample message with the TSS key. func TestTSS(pubkey string, tssServer tss.TssServer, logger zerolog.Logger) error { - keygenLogger := logger.With().Str("module", "test-keygen").Logger() + keygenLogger := logger.With().Str(logs.FieldModule, "tss_test_keygen").Logger() keygenLogger.Info().Msgf("KeyGen success ! Doing a Key-sign test") // KeySign can fail even if TSS keygen is successful, just logging the error here to break out of outer loop and report TSS err := TestKeysign(pubkey, tssServer) diff --git a/zetaclient/tss/tss_signer.go b/zetaclient/tss/tss_signer.go index 83ff502f4a..bb887d9380 100644 --- a/zetaclient/tss/tss_signer.go +++ b/zetaclient/tss/tss_signer.go @@ -277,32 +277,30 @@ func (tss *TSS) Sign( log.Info().Msgf("signature of digest is... %v", signature) if len(signature) == 0 { - log.Warn().Err(err).Msgf("signature has length 0") - return [65]byte{}, fmt.Errorf("keysign fail: %s", err) + return [65]byte{}, fmt.Errorf("keysign fail: signature list is empty") } if !verifySignature(tssPubkey, signature, H) { - log.Error().Err(err).Msgf("signature verification failure") - return [65]byte{}, fmt.Errorf("signuature verification fail") + return [65]byte{}, fmt.Errorf("signuature verification failue") } var sigbyte [65]byte _, err = base64.StdEncoding.Decode(sigbyte[:32], []byte(signature[0].R)) if err != nil { log.Error().Err(err).Msg("decoding signature R") - return [65]byte{}, fmt.Errorf("signuature verification fail") + return [65]byte{}, fmt.Errorf("signuature verification failure (R) %w", err) } _, err = base64.StdEncoding.Decode(sigbyte[32:64], []byte(signature[0].S)) if err != nil { log.Error().Err(err).Msg("decoding signature S") - return [65]byte{}, fmt.Errorf("signuature verification fail") + return [65]byte{}, fmt.Errorf("signuature verification failue (S): %w", err) } _, err = base64.StdEncoding.Decode(sigbyte[64:65], []byte(signature[0].RecoveryID)) if err != nil { log.Error().Err(err).Msg("decoding signature RecoveryID") - return [65]byte{}, fmt.Errorf("signuature verification fail") + return [65]byte{}, fmt.Errorf("signuature verification failue (V) %w", err) } return sigbyte, nil diff --git a/zetaclient/zetacore/client.go b/zetaclient/zetacore/client.go index dac6d400fb..65078a72cb 100644 --- a/zetaclient/zetacore/client.go +++ b/zetaclient/zetacore/client.go @@ -2,11 +2,9 @@ package zetacore import ( - "context" "fmt" "strings" "sync" - "time" rpchttp "github.com/cometbft/cometbft/rpc/client/http" cosmosclient "github.com/cosmos/cosmos-sdk/client" @@ -21,11 +19,10 @@ import ( "github.com/zeta-chain/node/pkg/authz" "github.com/zeta-chain/node/pkg/chains" zetacore_rpc "github.com/zeta-chain/node/pkg/rpc" - observertypes "github.com/zeta-chain/node/x/observer/types" "github.com/zeta-chain/node/zetaclient/chains/interfaces" "github.com/zeta-chain/node/zetaclient/config" - zctx "github.com/zeta-chain/node/zetaclient/context" keyinterfaces "github.com/zeta-chain/node/zetaclient/keys/interfaces" + "github.com/zeta-chain/node/zetaclient/logs" ) var _ interfaces.ZetacoreClient = &Client{} @@ -43,12 +40,10 @@ type Client struct { accountNumber map[authz.KeyType]uint64 seqNumber map[authz.KeyType]uint64 - encodingCfg etherminttypes.EncodingConfig - keys keyinterfaces.ObserverKeys - chainID string - chain chains.Chain - stop chan struct{} - onBeforeStopCallback []func() + encodingCfg etherminttypes.EncodingConfig + keys keyinterfaces.ObserverKeys + chainID string + chain chains.Chain mu sync.RWMutex } @@ -100,7 +95,7 @@ func NewClient( return nil, errors.Wrapf(err, "invalid chain id %q", chainID) } - log := logger.With().Str("module", "zetacoreClient").Logger() + log := logger.With().Str(logs.FieldModule, "zetacoreClient").Logger() cfg := config.ClientConfiguration{ ChainHost: cosmosREST(chainIP), @@ -140,7 +135,6 @@ func NewClient( encodingCfg: encodingCfg, keys: keys, - stop: make(chan struct{}), chainID: chainID, chain: zetaChain, }, nil @@ -248,23 +242,6 @@ func (c *Client) GetKeys() keyinterfaces.ObserverKeys { return c.keys } -// OnBeforeStop adds a callback to be called before the client stops. -func (c *Client) OnBeforeStop(callback func()) { - c.onBeforeStopCallback = append(c.onBeforeStopCallback, callback) -} - -// Stop stops the client and optionally calls the onBeforeStop callbacks. -func (c *Client) Stop() { - c.logger.Info().Msgf("Stopping zetacore client") - - for i := len(c.onBeforeStopCallback) - 1; i >= 0; i-- { - c.logger.Info().Int("callback.index", i).Msgf("calling onBeforeStopCallback") - c.onBeforeStopCallback[i]() - } - - close(c.stop) -} - // GetAccountNumberAndSequenceNumber We do not use multiple KeyType for now , but this can be optionally used in the future to seprate TSS signer from Zetaclient GRantee func (c *Client) GetAccountNumberAndSequenceNumber(_ authz.KeyType) (uint64, uint64, error) { address, err := c.keys.GetAddress() @@ -293,116 +270,6 @@ func (c *Client) SetAccountNumber(keyType authz.KeyType) error { return nil } -// WaitForZetacoreToCreateBlocks waits for zetacore to create blocks -func (c *Client) WaitForZetacoreToCreateBlocks(ctx context.Context) error { - retryCount := 0 - for { - block, err := c.GetLatestZetaBlock(ctx) - if err == nil && block.Header.Height > 1 { - c.logger.Info().Msgf("Zetacore height: %d", block.Header.Height) - break - } - retryCount++ - c.logger.Debug().Msgf("Failed to get latest Block , Retry : %d/%d", retryCount, DefaultRetryCount) - if retryCount > ExtendedRetryCount { - return fmt.Errorf("zetacore is not ready, waited for %d seconds", DefaultRetryCount*DefaultRetryInterval) - } - time.Sleep(DefaultRetryInterval * time.Second) - } - return nil -} - -// UpdateAppContext updates zctx.AppContext -// zetacore stores AppContext for all clients -func (c *Client) UpdateAppContext(ctx context.Context, appContext *zctx.AppContext, logger zerolog.Logger) error { - bn, err := c.GetBlockHeight(ctx) - if err != nil { - return errors.Wrap(err, "unable to get zetablock height") - } - - plan, err := c.GetUpgradePlan(ctx) - if err != nil { - return errors.Wrap(err, "unable to get upgrade plan") - } - - // Stop client and notify dependant services to stop (Orchestrator, Observers, and Signers) - if plan != nil && bn == plan.Height-1 { - c.logger.Warn().Msgf( - "Active upgrade plan detected and upgrade height reached: %s at height %d; Stopping ZetaClient;"+ - " please kill this process, replace zetaclientd binary with upgraded version, and restart zetaclientd", - plan.Name, - plan.Height, - ) - - c.Stop() - - return nil - } - - supportedChains, err := c.GetSupportedChains(ctx) - if err != nil { - return errors.Wrap(err, "unable to fetch supported chains") - } - - additionalChains, err := c.GetAdditionalChains(ctx) - if err != nil { - return errors.Wrap(err, "unable to fetch additional chains") - } - - chainParams, err := c.GetChainParams(ctx) - if err != nil { - return errors.Wrap(err, "unable to fetch chain params") - } - - keyGen, err := c.GetKeyGen(ctx) - if err != nil { - return errors.Wrap(err, "unable to fetch keygen from zetacore") - } - - crosschainFlags, err := c.GetCrosschainFlags(ctx) - if err != nil { - return errors.Wrap(err, "unable to fetch crosschain flags from zetacore") - } - - tss, err := c.GetTSS(ctx) - if err != nil { - return errors.Wrap(err, "unable to fetch current TSS") - } - - freshParams := make(map[int64]*observertypes.ChainParams, len(chainParams)) - - // check and update chain params for each chain - // Note that we are EXCLUDING ZetaChain from the chainParams if it's present - for i := range chainParams { - cp := chainParams[i] - - if !cp.IsSupported { - logger.Warn().Int64("chain.id", cp.ChainId).Msg("Skipping unsupported chain") - continue - } - - if chains.IsZetaChain(cp.ChainId, nil) { - continue - } - - if err := observertypes.ValidateChainParams(cp); err != nil { - logger.Warn().Err(err).Int64("chain.id", cp.ChainId).Msg("Skipping invalid chain params") - continue - } - - freshParams[cp.ChainId] = cp - } - - return appContext.Update( - keyGen, - supportedChains, - additionalChains, - freshParams, - tss.GetTssPubkey(), - crosschainFlags, - ) -} - func cosmosREST(host string) string { return fmt.Sprintf("%s:1317", host) } diff --git a/zetaclient/zetacore/client_worker.go b/zetaclient/zetacore/client_worker.go deleted file mode 100644 index b1fb4a6074..0000000000 --- a/zetaclient/zetacore/client_worker.go +++ /dev/null @@ -1,44 +0,0 @@ -package zetacore - -import ( - "context" - "time" - - "github.com/rs/zerolog" - - appcontext "github.com/zeta-chain/node/zetaclient/context" -) - -var logSampler = &zerolog.BasicSampler{N: 10} - -// UpdateAppContextWorker is a polling goroutine that checks and updates AppContext at every height. -// todo implement graceful shutdown and work group -func (c *Client) UpdateAppContextWorker(ctx context.Context, app *appcontext.AppContext) { - defer func() { - if r := recover(); r != nil { - c.logger.Error().Interface("panic", r).Msg("UpdateAppContextWorker: recovered from panic") - } - }() - - var ( - // #nosec G115 interval is in range and not user controlled - updateEvery = time.Duration(app.Config().ConfigUpdateTicker) * time.Second - ticker = time.NewTicker(updateEvery) - logger = c.logger.Sample(logSampler) - ) - - c.logger.Info().Msg("UpdateAppContextWorker started") - - for { - select { - case <-ticker.C: - c.logger.Debug().Msg("UpdateAppContextWorker invocation") - if err := c.UpdateAppContext(ctx, app, logger); err != nil { - c.logger.Err(err).Msg("UpdateAppContextWorker failed to update config") - } - case <-c.stop: - c.logger.Info().Msg("UpdateAppContextWorker stopped") - return - } - } -} diff --git a/zetaclient/zetacore/constant.go b/zetaclient/zetacore/constant.go index ab13e741d0..c2185a08e1 100644 --- a/zetaclient/zetacore/constant.go +++ b/zetaclient/zetacore/constant.go @@ -33,15 +33,6 @@ const ( // PostBlameDataGasLimit is the gas limit for voting on blames PostBlameDataGasLimit = 200_000 - // DefaultRetryCount is the number of retries for broadcasting a tx - DefaultRetryCount = 5 - - // ExtendedRetryCount is an extended number of retries for broadcasting a tx, used in keygen operations - ExtendedRetryCount = 15 - - // DefaultRetryInterval is the interval between retries in seconds - DefaultRetryInterval = 5 - // PostVoteOutboundGasLimit is the gas limit for voting on observed outbound tx (for zetachain itself) PostVoteOutboundGasLimit = 500_000 diff --git a/zetaclient/zetacore/tx_test.go b/zetaclient/zetacore/tx_test.go index f1cac183f1..f12d7fc0e9 100644 --- a/zetaclient/zetacore/tx_test.go +++ b/zetaclient/zetacore/tx_test.go @@ -2,32 +2,20 @@ package zetacore import ( "context" - "net" "testing" - "github.com/zeta-chain/node/testutil/sample" - authoritytypes "github.com/zeta-chain/node/x/authority/types" - "cosmossdk.io/math" sdktypes "github.com/cosmos/cosmos-sdk/types" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/pkg/errors" - "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - zctx "github.com/zeta-chain/node/zetaclient/context" - "gitlab.com/thorchain/tss/go-tss/blame" - "go.nhat.io/grpcmock" - "go.nhat.io/grpcmock/planner" - "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" - lightclienttypes "github.com/zeta-chain/node/x/lightclient/types" observertypes "github.com/zeta-chain/node/x/observer/types" - "github.com/zeta-chain/node/zetaclient/config" "github.com/zeta-chain/node/zetaclient/keys" "github.com/zeta-chain/node/zetaclient/testutils/mocks" + "gitlab.com/thorchain/tss/go-tss/blame" ) const ( @@ -199,149 +187,6 @@ func TestZetacore_SetTSS(t *testing.T) { }) } -func TestZetacore_UpdateAppContext(t *testing.T) { - ctx := context.Background() - - //Setup server for multiple grpc calls - listener, err := net.Listen("tcp", "127.0.0.1:9090") - require.NoError(t, err) - - ethChainParams := mocks.MockChainParams(chains.Ethereum.ChainId, 100) - - server := grpcmock.MockUnstartedServer( - grpcmock.RegisterService(crosschaintypes.RegisterQueryServer), - grpcmock.RegisterService(upgradetypes.RegisterQueryServer), - grpcmock.RegisterService(observertypes.RegisterQueryServer), - grpcmock.RegisterService(lightclienttypes.RegisterQueryServer), - grpcmock.RegisterService(authoritytypes.RegisterQueryServer), - grpcmock.WithPlanner(planner.FirstMatch()), - grpcmock.WithListener(listener), - func(s *grpcmock.Server) { - method := "/zetachain.zetacore.crosschain.Query/LastZetaHeight" - s.ExpectUnary(method). - UnlimitedTimes(). - WithPayload(crosschaintypes.QueryLastZetaHeightRequest{}). - Return(crosschaintypes.QueryLastZetaHeightResponse{Height: 12345}) - - method = "/cosmos.upgrade.v1beta1.Query/CurrentPlan" - s.ExpectUnary(method). - UnlimitedTimes(). - WithPayload(upgradetypes.QueryCurrentPlanRequest{}). - Return(upgradetypes.QueryCurrentPlanResponse{ - Plan: &upgradetypes.Plan{ - Name: "big upgrade", - Height: 100, - }, - }) - - method = "/zetachain.zetacore.observer.Query/GetChainParams" - s.ExpectUnary(method). - UnlimitedTimes(). - WithPayload(observertypes.QueryGetChainParamsRequest{}). - Return(observertypes.QueryGetChainParamsResponse{ChainParams: &observertypes.ChainParamsList{ - ChainParams: []*observertypes.ChainParams{ - {ChainId: 7000}, // ZetaChain - ðChainParams, - }, - }}) - - method = "/zetachain.zetacore.observer.Query/SupportedChains" - s.ExpectUnary(method). - UnlimitedTimes(). - WithPayload(observertypes.QuerySupportedChains{}). - Return(observertypes.QuerySupportedChainsResponse{ - Chains: []chains.Chain{ - { - ChainId: chains.BitcoinMainnet.ChainId, - Network: chains.BscMainnet.Network, - NetworkType: chains.BscMainnet.NetworkType, - Vm: chains.BscMainnet.Vm, - Consensus: chains.BscMainnet.Consensus, - IsExternal: chains.BscMainnet.IsExternal, - CctxGateway: chains.BscMainnet.CctxGateway, - Name: chains.BscMainnet.Name, - }, - { - ChainId: chains.Ethereum.ChainId, - Network: chains.Ethereum.Network, - NetworkType: chains.Ethereum.NetworkType, - Vm: chains.Ethereum.Vm, - Consensus: chains.Ethereum.Consensus, - IsExternal: chains.Ethereum.IsExternal, - CctxGateway: chains.Ethereum.CctxGateway, - Name: chains.Ethereum.Name, - }, - }, - }) - - method = "/zetachain.zetacore.observer.Query/Keygen" - s.ExpectUnary(method). - UnlimitedTimes(). - WithPayload(observertypes.QueryGetKeygenRequest{}). - Return(observertypes.QueryGetKeygenResponse{ - Keygen: &observertypes.Keygen{ - Status: observertypes.KeygenStatus_KeyGenSuccess, - GranteePubkeys: nil, - BlockNumber: 5646, - }}) - - method = "/zetachain.zetacore.observer.Query/TSS" - s.ExpectUnary(method). - UnlimitedTimes(). - WithPayload(observertypes.QueryGetTSSRequest{}). - Return(observertypes.QueryGetTSSResponse{ - TSS: observertypes.TSS{ - TssPubkey: "zetapub1addwnpepqtadxdyt037h86z60nl98t6zk56mw5zpnm79tsmvspln3hgt5phdc79kvfc", - TssParticipantList: nil, - OperatorAddressList: nil, - FinalizedZetaHeight: 1000, - KeyGenZetaHeight: 900, - }, - }) - - method = "/zetachain.zetacore.observer.Query/CrosschainFlags" - s.ExpectUnary(method). - UnlimitedTimes(). - WithPayload(observertypes.QueryGetCrosschainFlagsRequest{}). - Return(observertypes.QueryGetCrosschainFlagsResponse{CrosschainFlags: observertypes.CrosschainFlags{ - IsInboundEnabled: true, - IsOutboundEnabled: false, - GasPriceIncreaseFlags: nil, - }}) - - method = "/zetachain.zetacore.authority.Query/ChainInfo" - s.ExpectUnary(method). - UnlimitedTimes(). - WithPayload(authoritytypes.QueryGetChainInfoRequest{}). - Return(authoritytypes.QueryGetChainInfoResponse{ - ChainInfo: authoritytypes.ChainInfo{ - Chains: []chains.Chain{ - sample.Chain(1000), - sample.Chain(1001), - sample.Chain(1002), - }, - }, - }) - }, - )(t) - - server.Serve() - defer server.Close() - - address := sdktypes.AccAddress(mocks.TestKeyringPair.PubKey().Address().Bytes()) - client := setupZetacoreClient(t, - withObserverKeys(keys.NewKeysWithKeybase(mocks.NewKeyring(), address, testSigner, "")), - withTendermint(mocks.NewSDKClientWithErr(t, nil, 0)), - ) - - t.Run("zetacore update success", func(t *testing.T) { - cfg := config.New(false) - appContext := zctx.New(cfg, nil, zerolog.Nop()) - err := client.UpdateAppContext(ctx, appContext, zerolog.New(zerolog.NewTestWriter(t))) - require.NoError(t, err) - }) -} - func TestZetacore_PostBlameData(t *testing.T) { ctx := context.Background()