From 6423ca3849d3b92083255b8895f3251ee8fd2e3a Mon Sep 17 00:00:00 2001 From: yakud Date: Thu, 4 Apr 2024 19:52:31 +0300 Subject: [PATCH 1/4] Upgrade v0.1.2, network halt fix. Addresses a critical staking PowerReduction issue by mutating validators power for accurate voting power recalibration and network integrity. Do not run before we have finished everything! --- app/app.go | 6 +++ app/upgrade_v0_1_2.go | 90 ++++++++++++++++++++++++++++++++++ app/upgrades/v0_1_2/upgrade.go | 32 ++++++++++++ cmd/galacticad/cmd/config.go | 6 +++ 4 files changed, 134 insertions(+) create mode 100644 app/upgrade_v0_1_2.go create mode 100644 app/upgrades/v0_1_2/upgrade.go diff --git a/app/app.go b/app/app.go index df4a3f6..4ea6060 100644 --- a/app/app.go +++ b/app/app.go @@ -479,6 +479,8 @@ func New( panic(err) } + app.applyUpgrades() + return app } @@ -655,3 +657,7 @@ func initParamsKeeper( return paramsKeeper } + +func (app *App) applyUpgrades() { + app.applyUpgrade_v0_1_2() +} diff --git a/app/upgrade_v0_1_2.go b/app/upgrade_v0_1_2.go new file mode 100644 index 0000000..60b8c3f --- /dev/null +++ b/app/upgrade_v0_1_2.go @@ -0,0 +1,90 @@ +// Copyright 2024 Galactica Network +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package app + +import ( + "bytes" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + "github.com/Galactica-corp/galactica/app/upgrades/v0_1_2" +) + +// applyUpgrade_v0_1_2 checks and applies the upgrade plan if necessary. +func (app *App) applyUpgrade_v0_1_2() { + ctx, err := app.CreateQueryContext(v0_1_2.UpgradeBlockHeight, false) + if err != nil { + return + } + + plan, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() + if err != nil || plan.Height < v0_1_2.UpgradeBlockHeight { + app.UpgradeKeeper.SetUpgradeHandler(v0_1_2.UpgradeName, app.upgradeHandler_v0_1_2()) + app.UpgradeKeeper.ApplyUpgrade(ctx, v0_1_2.Plan) + } +} + +// upgradeHandler_v0_1_2 returns a handler function for processing the upgrade. +func (app *App) upgradeHandler_v0_1_2() func( + ctx sdk.Context, + _ upgradetypes.Plan, + fromVM module.VersionMap, +) (module.VersionMap, error) { + return func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + logger := ctx.Logger().With("upgrade", v0_1_2.UpgradeName) + validators := app.StakingKeeper.GetAllValidators(ctx) + + for _, validator := range validators { + if err := app.updateValidatorPowerIndex(ctx, validator); err != nil { + panic(fmt.Sprintf("failed to update validator power index: %v", err)) + } + + logger.Info("Validator power index updated", "validator", validator.OperatorAddress) + } + logger.Info("All validators updated successfully.") + + if err := app.UpgradeKeeper.DumpUpgradeInfoToDisk(v0_1_2.UpgradeBlockHeight, v0_1_2.Plan); err != nil { + return nil, err + } + + return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM) + } +} + +// updateValidatorPowerIndex updates the power index for a single validator. +func (app *App) updateValidatorPowerIndex(ctx sdk.Context, validator stakingtypes.Validator) error { + store := ctx.KVStore(app.GetKey(stakingtypes.StoreKey)) + iterator := sdk.KVStorePrefixIterator(store, stakingtypes.ValidatorsByPowerIndexKey) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + valAddr := stakingtypes.ParseValidatorPowerRankKey(iterator.Key()) + if bytes.Equal(valAddr, validator.GetOperator()) { + store.Delete(iterator.Key()) + break // Assuming unique power index key per validator. + } + } + + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validator) + if _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx); err != nil { + return err + } + + return nil +} diff --git a/app/upgrades/v0_1_2/upgrade.go b/app/upgrades/v0_1_2/upgrade.go new file mode 100644 index 0000000..3afecbe --- /dev/null +++ b/app/upgrades/v0_1_2/upgrade.go @@ -0,0 +1,32 @@ +// Copyright 2024 Galactica Network +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v0_1_2 + +import ( + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" +) + +const ( + UpgradeName = "0.1.2" + UpgradeBlockHeight = 16951 +) + +// Plan defines the upgrade plan for addressing the staking PowerReduction issue. +var Plan = upgradetypes.Plan{ + Name: UpgradeName, + Height: UpgradeBlockHeight, + Info: "Addresses a critical staking PowerReduction issue by mutating validators' " + + "power for accurate voting power recalibration and network integrity.", +} diff --git a/cmd/galacticad/cmd/config.go b/cmd/galacticad/cmd/config.go index 6cca750..0eb94f5 100644 --- a/cmd/galacticad/cmd/config.go +++ b/cmd/galacticad/cmd/config.go @@ -15,6 +15,8 @@ package cmd import ( + "math/big" + "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -73,6 +75,10 @@ func initSDKConfig() { RegisterDenoms() + sdk.DefaultPowerReduction = sdk.NewIntFromBigInt( + new(big.Int).Exp(big.NewInt(10), big.NewInt(BaseDenomUnit), nil), + ) + config.Seal() } From 2e01f3fbd9366234fcd43277c5b73e9729f79831 Mon Sep 17 00:00:00 2001 From: yakud Date: Fri, 5 Apr 2024 19:42:27 +0300 Subject: [PATCH 2/4] Add upgrade_v0_1_2.sh script. More logs while upgrade applying. --- app/upgrade_v0_1_2.go | 26 +++++++++++----- scripts/upgrade_v0_1_2.sh | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 7 deletions(-) create mode 100755 scripts/upgrade_v0_1_2.sh diff --git a/app/upgrade_v0_1_2.go b/app/upgrade_v0_1_2.go index 60b8c3f..fb5a9f2 100644 --- a/app/upgrade_v0_1_2.go +++ b/app/upgrade_v0_1_2.go @@ -16,7 +16,6 @@ package app import ( "bytes" - "fmt" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" @@ -28,13 +27,18 @@ import ( // applyUpgrade_v0_1_2 checks and applies the upgrade plan if necessary. func (app *App) applyUpgrade_v0_1_2() { - ctx, err := app.CreateQueryContext(v0_1_2.UpgradeBlockHeight, false) + latestBlock := app.LastBlockHeight() + logger := app.Logger().With("upgrade", v0_1_2.UpgradeName) + + ctx, err := app.CreateQueryContext(latestBlock, false) if err != nil { + logger.Error("Failed to create query context with block", "error", err, "block", latestBlock) return } plan, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() if err != nil || plan.Height < v0_1_2.UpgradeBlockHeight { + logger.Info("Applying upgrade plan", "info", plan.Info) app.UpgradeKeeper.SetUpgradeHandler(v0_1_2.UpgradeName, app.upgradeHandler_v0_1_2()) app.UpgradeKeeper.ApplyUpgrade(ctx, v0_1_2.Plan) } @@ -46,20 +50,28 @@ func (app *App) upgradeHandler_v0_1_2() func( _ upgradetypes.Plan, fromVM module.VersionMap, ) (module.VersionMap, error) { - return func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - logger := ctx.Logger().With("upgrade", v0_1_2.UpgradeName) + return func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + logger := ctx.Logger().With("upgrade", plan.Name) + + if plan.Name != v0_1_2.UpgradeName { + logger.Error("Invalid upgrade plan", "expected", v0_1_2.UpgradeName, "got", plan.Name) + return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM) + } + validators := app.StakingKeeper.GetAllValidators(ctx) for _, validator := range validators { if err := app.updateValidatorPowerIndex(ctx, validator); err != nil { - panic(fmt.Sprintf("failed to update validator power index: %v", err)) + logger.Error("Failed to update validator power index", "error", err, "validator", validator.OperatorAddress) + return nil, err } - logger.Info("Validator power index updated", "validator", validator.OperatorAddress) } + logger.Info("All validators updated successfully.") - if err := app.UpgradeKeeper.DumpUpgradeInfoToDisk(v0_1_2.UpgradeBlockHeight, v0_1_2.Plan); err != nil { + if err := app.UpgradeKeeper.DumpUpgradeInfoToDisk(plan.Height, plan); err != nil { + logger.Error("Failed to dump upgrade info to disk", "error", err) return nil, err } diff --git a/scripts/upgrade_v0_1_2.sh b/scripts/upgrade_v0_1_2.sh new file mode 100755 index 0000000..30747c4 --- /dev/null +++ b/scripts/upgrade_v0_1_2.sh @@ -0,0 +1,65 @@ +# Copyright 2024 Galactica Network +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#!/bin/bash + +# This script is used to prepare the upgrade from v0.1.1 to v0.1.2 + +GALACTICAD_VERSION=$(galacticad version) +if [[ $GALACTICAD_VERSION != *"0.1.2"* ]]; then + echo "Galactica version must be 0.1.2" + exit 1 +fi + +# check env var GALACTICA_HOME and if not exists exit +if [ -z "$GALACTICA_HOME" ]; then + echo "GALACTICA_HOME is not set, using default path" + GALACTICA_HOME="$HOME/.galactica" +fi + +# ask user to confirm: +echo "GALACTICA_HOME: $GALACTICA_HOME" +echo "\nThis script will perform the following actions:\n\ +- Backup the existing priv_validator_state.json and replace it with a new one containing default values\n\ +- Upgrade the node storage to v0.1.2\n\ +- Rollback the latest block state\n" + +if [ "$1" != "-y" ]; then + read -p "Do you want to continue? (y/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "User cancelled the script" + exit 1 + fi +fi + +PRIV_VAL_STATE=$GALACTICA_HOME/data/priv_validator_state.json + +UPGRADE_INFO_FILE=$GALACTICA_HOME/data/upgrade-info.json +if [ -f "$UPGRADE_INFO_FILE" ]; then + echo "upgrade v0.1.2 already applied" + exit 1 +fi + +if [ ! -f "$PRIV_VAL_STATE" ]; then + echo "priv_validator_state.json not found at $PRIV_VAL_STATE" + exit 1 +fi + +cp $PRIV_VAL_STATE $PRIV_VAL_STATE.bkp + +galacticad --home $GALACTICA_HOME rollback --hard + +echo '{"height":"0","round":0,"step":0}' > $PRIV_VAL_STATE + From bed649ba039063bfa178cc79e5c077781ca5f4ce Mon Sep 17 00:00:00 2001 From: yakud Date: Fri, 5 Apr 2024 19:57:34 +0300 Subject: [PATCH 3/4] Add upgrade instruction --- app/upgrades/v0_1_2/README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 app/upgrades/v0_1_2/README.md diff --git a/app/upgrades/v0_1_2/README.md b/app/upgrades/v0_1_2/README.md new file mode 100644 index 0000000..facaeda --- /dev/null +++ b/app/upgrades/v0_1_2/README.md @@ -0,0 +1,26 @@ +# Upgrade to v0.1.2 + +## Guide for Upgrading from v0.1.1 to v0.1.2 + +1. Halt the currently running `galacticad` process. +2. Fetch the latest updates from the repository and switch to the `v0.1.2` tag. + ```bash + git fetch --all --tags + git checkout v0.1.2 + ``` +3. Build the updated source code. + ```bash + make install + ``` +4. Execute the upgrade script located at ./scripts/upgrade_v0_1_2.sh + ```bash + ./scripts/upgrade_v0_1_2.sh + ``` + Ensure the following environment variable is defined: + - `GALACTICA_HOME`: Specifies the home directory for the `galacticad` node. + + The script executes the following operations: + - Updates the node storage to version v0.1.2. + - Reverts the state of the latest block. + - Creates a backup of the current priv_validator_state.json and replaces it with a new version with default settings. +5. Restart the `galacticad` node. From 4cbed9fd8bae1a8a97ccbc899e22fe60b7eba3c5 Mon Sep 17 00:00:00 2001 From: yakud Date: Fri, 5 Apr 2024 20:11:34 +0300 Subject: [PATCH 4/4] Update upgrade README.md --- app/upgrades/v0_1_2/README.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/app/upgrades/v0_1_2/README.md b/app/upgrades/v0_1_2/README.md index facaeda..177393c 100644 --- a/app/upgrades/v0_1_2/README.md +++ b/app/upgrades/v0_1_2/README.md @@ -3,16 +3,17 @@ ## Guide for Upgrading from v0.1.1 to v0.1.2 1. Halt the currently running `galacticad` process. -2. Fetch the latest updates from the repository and switch to the `v0.1.2` tag. +2. **!!! Backup the data directory.** !!! +3. Fetch the latest updates from the repository and switch to the `v0.1.2` tag. ```bash git fetch --all --tags git checkout v0.1.2 ``` -3. Build the updated source code. +4. Build the updated source code. ```bash make install ``` -4. Execute the upgrade script located at ./scripts/upgrade_v0_1_2.sh +5. Execute the upgrade script located at ./scripts/upgrade_v0_1_2.sh ```bash ./scripts/upgrade_v0_1_2.sh ``` @@ -21,6 +22,15 @@ The script executes the following operations: - Updates the node storage to version v0.1.2. - - Reverts the state of the latest block. - - Creates a backup of the current priv_validator_state.json and replaces it with a new version with default settings. -5. Restart the `galacticad` node. + - Roll back the state of the most recent block. + - Backup of the current priv_validator_state.json and replaces it with a new version with default settings. + + Alternatively, these steps can be performed manually: + ```bash + galacticad --home $GALACTICA_HOME rollback --hard + echo '{"height":"0","round":0,"step":0}' > $GALACTICA_HOME/data/priv_validator_state.json + ``` + Executing the rollback command will also automatically execute the storage upgrade. + +6. Restart the `galacticad` node. +