From 2329180847e8b4634bf330a1e15fa187681f078d Mon Sep 17 00:00:00 2001 From: emidev98 Date: Tue, 23 Jul 2024 16:55:42 +0300 Subject: [PATCH] feat: upgrade hanlder --- app/upgrade_handler.go | 1 + app/upgrades/v2.12/upgrade.go | 100 +++++++++++ integration-tests/package.json | 1 + .../src/setup/chain-upgrade/chain-upgrade.sh | 4 +- .../chain-upgrade/upgrade-simulation-12.sh | 170 ++++++++++++++++++ 5 files changed, 274 insertions(+), 2 deletions(-) create mode 100755 integration-tests/src/setup/chain-upgrade/upgrade-simulation-12.sh diff --git a/app/upgrade_handler.go b/app/upgrade_handler.go index e8def989..6c3e4837 100644 --- a/app/upgrade_handler.go +++ b/app/upgrade_handler.go @@ -117,6 +117,7 @@ func (app *TerraApp) RegisterUpgradeHandlers() { v2_12.CreateUpgradeHandler( app.GetModuleManager(), app.GetConfigurator(), + app.Keepers, ), ) } diff --git a/app/upgrades/v2.12/upgrade.go b/app/upgrades/v2.12/upgrade.go index d6970cfc..ae0943b6 100644 --- a/app/upgrades/v2.12/upgrade.go +++ b/app/upgrades/v2.12/upgrade.go @@ -3,7 +3,9 @@ package v2_12 import ( 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/terra-money/core/v2/app/keepers" ) type EscrowUpdate struct { @@ -11,11 +13,109 @@ type EscrowUpdate struct { Assets []sdk.Coin } +// To test this upgrade handler set the following address "terra1v0eee20gjl68fuk0chyrkch2z7suw2mhg3wkxf" +// on the variables below: addr and multisigAddr. +// then run: npm run test:chain:upgrade:v12 func CreateUpgradeHandler( mm *module.Manager, cfg module.Configurator, + k keepers.TerraAppKeepers, ) upgradetypes.UpgradeHandler { return func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + if ctx.ChainID() != "phoenix-1" { + return mm.RunMigrations(ctx, cfg, vm) + } + addr := sdk.MustAccAddressFromBech32("") + multisigAddr := sdk.MustAccAddressFromBech32("") + + // Iterate delegations and unbond all shares + // burning the coins immediately + k.StakingKeeper.IterateDelegatorDelegations(ctx, addr, func(d stakingtypes.Delegation) (stop bool) { + valAddr, err := sdk.ValAddressFromBech32(d.ValidatorAddress) + if err != nil { + panic(err) + } + // Use this method without adding unbonding to the unbondings queue + // because it's not necessary to wait for the unbonding period + // (basically burn the shares and coins immediately) + _, err = k.StakingKeeper.Unbond(ctx, addr, valAddr, d.Shares) + if err != nil { + panic(err) + } + return false + }) + + // Given one of the states can be undelegating, we need to iterate over all unbonding delegations + // and remove them manually to ensure that the undelegated coins are burned. + bondDenom := k.StakingKeeper.GetParams(ctx).BondDenom + k.StakingKeeper.IterateDelegatorUnbondingDelegations(ctx, addr, func(ubd stakingtypes.UnbondingDelegation) (stop bool) { + balances := sdk.NewCoins() + for i := 0; i < len(ubd.Entries); i++ { + entry := ubd.Entries[i] + ubd.RemoveEntry(int64(i)) + i-- + k.StakingKeeper.DeleteUnbondingIndex(ctx, entry.UnbondingId) + + // track undelegation only when remaining or truncated shares are non-zero + if !entry.Balance.IsZero() { + amt := sdk.NewCoin(bondDenom, entry.Balance) + if err := k.BankKeeper.UndelegateCoinsFromModuleToAccount( + ctx, stakingtypes.NotBondedPoolName, addr, sdk.NewCoins(amt), + ); err != nil { + panic(err) + } + + balances = balances.Add(amt) + } + } + k.StakingKeeper.RemoveUnbondingDelegation(ctx, ubd) + return false + }) + + // Redelegations are two queues but no coins are custodied in any "redelegations_pool", + // so we can just iterate over all redelegations and remove the indices to prevent issues. + k.StakingKeeper.IterateDelegatorRedelegations(ctx, addr, func(red stakingtypes.Redelegation) (stop bool) { + balances := sdk.NewCoins() + for i := 0; i < len(red.Entries); i++ { + entry := red.Entries[i] + red.RemoveEntry(int64(i)) + i-- + k.StakingKeeper.DeleteUnbondingIndex(ctx, entry.UnbondingId) + + if !entry.InitialBalance.IsZero() { + balances = balances.Add(sdk.NewCoin(bondDenom, entry.InitialBalance)) + } + } + k.StakingKeeper.RemoveRedelegation(ctx, red) + return false + }) + + // Burn all coins in the addr + k.BankKeeper.IterateAccountBalances(ctx, addr, func(balance sdk.Coin) bool { + err := k.BankKeeper.SendCoinsFromAccountToModule(ctx, addr, stakingtypes.NotBondedPoolName, sdk.NewCoins(balance)) + if err != nil { + panic(err) + } + err = k.BankKeeper.BurnCoins(ctx, stakingtypes.NotBondedPoolName, sdk.NewCoins(balance)) + if err != nil { + panic(err) + } + return false + }) + + // Burn all coins from the multisig account + k.BankKeeper.IterateAccountBalances(ctx, multisigAddr, func(balance sdk.Coin) bool { + err := k.BankKeeper.SendCoinsFromAccountToModule(ctx, multisigAddr, stakingtypes.NotBondedPoolName, sdk.NewCoins(balance)) + if err != nil { + panic(err) + } + err = k.BankKeeper.BurnCoins(ctx, stakingtypes.NotBondedPoolName, sdk.NewCoins(balance)) + if err != nil { + panic(err) + } + return false + }) + return mm.RunMigrations(ctx, cfg, vm) } } diff --git a/integration-tests/package.json b/integration-tests/package.json index 05ad01bb..974860cc 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -7,6 +7,7 @@ "test:init" : "bash src/setup/init-test-framework.sh", "test:relayer": "bash src/setup/relayer/init-relayer.sh", "test:chain:upgrade" : "bash src/setup/chain-upgrade/chain-upgrade.sh", + "test:chain:upgrade:v12" : "bash src/setup/chain-upgrade/upgrade-simulation-12.sh", "test:start" : "jest --runInBand --detectOpenHandles", "start": "npm run test:init && npm run test:relayer && npm run test:start", "test:clean": "rm -rf src/test-data chain-upgrade-data && pkill terrad && pkill terrad && pkill relayer" diff --git a/integration-tests/src/setup/chain-upgrade/chain-upgrade.sh b/integration-tests/src/setup/chain-upgrade/chain-upgrade.sh index 9bce11ec..7f4396ba 100755 --- a/integration-tests/src/setup/chain-upgrade/chain-upgrade.sh +++ b/integration-tests/src/setup/chain-upgrade/chain-upgrade.sh @@ -42,10 +42,10 @@ fi # init genesis $OLD_BINARY init test --home $CHAIN_HOME --chain-id=$CHAIN_ID echo $VAL_MNEMONIC_1 | $OLD_BINARY keys add val1 --home $CHAIN_HOME --recover --keyring-backend=test -VAL_ADDR_1=$($OLD_BINARY keys list emi --output=json | jq .[0].address -r) +VAL_ADDR_1=$($OLD_BINARY keys list val1 --output=json | jq .[0].address -r) echo $WALLET_MNEMONIC_1 | $OLD_BINARY keys add wallet1 --home $CHAIN_HOME --recover --keyring-backend=test -WALLET_ADDR_1=$($OLD_BINARY keys list emi --output=json | jq .[0].address -r) +WALLET_ADDR_1=$($OLD_BINARY keys list wallet1 --output=json | jq .[0].address -r) $OLD_BINARY genesis add-genesis-account $($OLD_BINARY --home $CHAIN_HOME keys show val1 --keyring-backend test -a) 100000000000uluna --home $CHAIN_HOME $OLD_BINARY genesis gentx val1 1000000000uluna --home $CHAIN_HOME --chain-id $CHAIN_ID --keyring-backend test diff --git a/integration-tests/src/setup/chain-upgrade/upgrade-simulation-12.sh b/integration-tests/src/setup/chain-upgrade/upgrade-simulation-12.sh new file mode 100755 index 00000000..960617f6 --- /dev/null +++ b/integration-tests/src/setup/chain-upgrade/upgrade-simulation-12.sh @@ -0,0 +1,170 @@ +#!/bin/bash + +OLD_VERSION=release/v2.11 +UPGRADE_HEIGHT=35 +CHAIN_ID=phoenix-1 +CHAIN_HOME=$(pwd)/chain-upgrade-data +DENOM=uluna +SOFTWARE_UPGRADE_NAME="v2.12" +GOV_PERIOD="3s" + +VAL_MNEMONIC_1="clock post desk civil pottery foster expand merit dash seminar song memory figure uniform spice circle try happy obvious trash crime hybrid hood cushion" +VAL_MNEMONIC_2="alley afraid soup fall idea toss can goose become valve initial strong forward bright dish figure check leopard decide warfare hub unusual join cart" +WALLET_MNEMONIC_1="banner spread envelope side kite person disagree path silver will brother under couch edit food venture squirrel civil budget number acquire point work mass" + +export OLD_BINARY=$CHAIN_HOME/terrad_old +export NEW_BINARY=$CHAIN_HOME/terrad_new + +rm -rf /tmp/terra +rm -r $CHAIN_HOME +mkdir $CHAIN_HOME +killall terrad_old +killall terrad_new + +# install old binary +if ! command -v $OLD_BINARY &> /dev/null +then + mkdir -p /tmp/terra + cd /tmp/terra + git clone https://github.com/terra-money/core + cd core + git checkout $OLD_VERSION + make build + cp /tmp/terra/core/build/terrad $CHAIN_HOME/terrad_old + cd $CHAIN_HOME +fi + +# install new binary +if ! command -v $NEW_BINARY &> /dev/null +then + cd ../.. + make build + cp build/terrad $NEW_BINARY +fi + +# init genesis +$OLD_BINARY init test --home $CHAIN_HOME --chain-id=$CHAIN_ID +echo $VAL_MNEMONIC_1 | $OLD_BINARY keys add val1 --home $CHAIN_HOME --recover --keyring-backend=test +VAL_ADDR_1=$($OLD_BINARY keys show val1 --home $CHAIN_HOME --keyring-backend=test --output=json | jq .address -r) + +echo $WALLET_MNEMONIC_1 | $OLD_BINARY keys add wallet1 --home $CHAIN_HOME --recover --keyring-backend=test +WALLET_ADDR_1=$($OLD_BINARY keys show wallet1 --home $CHAIN_HOME --keyring-backend=test --output=json | jq .address -r) + +$OLD_BINARY genesis add-genesis-account $($OLD_BINARY --home $CHAIN_HOME keys show val1 --keyring-backend test -a) 100000000000uluna --home $CHAIN_HOME + +CURRENT_TIME=$(date +%s) +echo "Current time: $CURRENT_TIME" +$OLD_BINARY genesis add-genesis-account $($OLD_BINARY --home $CHAIN_HOME keys show wallet1 --keyring-backend test -a) 100000000000uluna --vesting-amount 100000uluna --vesting-start-time $CURRENT_TIME --vesting-end-time $(($CURRENT_TIME + 10000)) --home $CHAIN_HOME + +$OLD_BINARY genesis gentx val1 1000000000uluna --home $CHAIN_HOME --chain-id $CHAIN_ID --keyring-backend test +$OLD_BINARY genesis collect-gentxs --home $CHAIN_HOME + +sed -i -e "s/\"max_deposit_period\": \"172800s\"/\"max_deposit_period\": \"$GOV_PERIOD\"/g" $CHAIN_HOME/config/genesis.json +sed -i -e "s/\"voting_period\": \"172800s\"/\"voting_period\": \"$GOV_PERIOD\"/g" $CHAIN_HOME/config/genesis.json + +sed -i -e 's/timeout_commit = "5s"/timeout_commit = "1s"/g' $CHAIN_HOME/config/config.toml +sed -i -e 's/timeout_propose = "3s"/timeout_propose = "1s"/g' $CHAIN_HOME/config/config.toml +sed -i -e 's/index_all_keys = false/index_all_keys = true/g' $CHAIN_HOME/config/config.toml +sed -i -e 's/enable = false/enable = true/g' $CHAIN_HOME/config/app.toml +sed -i -e 's/swagger = false/swagger = true/g' $CHAIN_HOME/config/app.toml + +# run old node +echo "Starting old binary on a separate process" +if [[ "$OSTYPE" == "darwin"* ]]; then + screen -L -dmS node1 $OLD_BINARY start --log_level trace --log_format json --home $CHAIN_HOME --pruning=nothing +else + screen -L -Logfile $CHAIN_HOME/log-screen.log -dmS node1 $OLD_BINARY start --log_level trace --log_format json --home $CHAIN_HOME --pruning=nothing +fi + +sleep 15 + +VALOPER_ADDR_1=$($OLD_BINARY q staking validators --output=json | jq .validators[0].operator_address -r) + +# Stake and assert it is staked +echo "Delegate" +NO_ECHO=$($OLD_BINARY tx staking delegate $VALOPER_ADDR_1 100000000uluna --keyring-backend test --chain-id $CHAIN_ID --home $CHAIN_HOME --from wallet1 -y) +sleep 2 +DELEGATIONS=$($OLD_BINARY query staking delegations $WALLET_ADDR_1 --output=json | jq ".delegation_responses | length") +if [[ "$DELEGATIONS" == "0" ]]; then + echo "Delegation failed" + exit 1 +fi + +# Unbond and assert the unbonding delegation +echo "Unbond" +NO_ECHO=$($OLD_BINARY tx staking unbond $VALOPER_ADDR_1 1000000uluna --keyring-backend test --chain-id $CHAIN_ID --home $CHAIN_HOME --from wallet1 -y) +sleep 2 +UNBONDINGS=$($OLD_BINARY query staking unbonding-delegations $WALLET_ADDR_1 --output=json | jq ".unbonding_responses | length" ) +if [[ "$UNBONDINGS" == "0" ]]; then + echo "Unbonding failed" + exit 1 +fi + +GOV_ADDRESS=$($OLD_BINARY query auth module-account gov --output json | jq .account.base_account.address -r) +echo '{ + "messages": [ + { + "@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade", + "authority" : "'"$GOV_ADDRESS"'", + "plan" : { + "name": "'"$SOFTWARE_UPGRADE_NAME"'", + "time": "0001-01-01T00:00:00Z", + "height": "'"$UPGRADE_HEIGHT"'", + "upgraded_client_state": null + } + } + ], + "metadata": "", + "deposit": "550000000'$DENOM'", + "title": "Upgrade to '$SOFTWARE_UPGRADE_NAME'", + "summary": "Source Code Version https://github.com/terra-money/core" +}' > $CHAIN_HOME/software-upgrade.json + +echo "Submit proposal" +NO_ECHO=$($OLD_BINARY tx gov submit-proposal $CHAIN_HOME/software-upgrade.json --from val1 --keyring-backend test --chain-id $CHAIN_ID --home $CHAIN_HOME -y) +sleep 2 +echo "Vote" +NO_ECHO=$($OLD_BINARY tx gov vote 1 yes --from val1 --keyring-backend test --chain-id $CHAIN_ID --home $CHAIN_HOME -y) + +## determine block_height to halt +while true; do + BLOCK_HEIGHT=$($OLD_BINARY status | jq '.SyncInfo.latest_block_height' -r) + if [ $BLOCK_HEIGHT = "$UPGRADE_HEIGHT" ]; then + # assuming running only 1 terrad + echo "BLOCK HEIGHT = $UPGRADE_HEIGHT REACHED, STOPPING OLD BINARY" + pkill terrad_old + break + else + STATUS=$($OLD_BINARY query gov proposal 1 --output=json | jq ".status" -r) + echo "BLOCK_HEIGHT = $BLOCK_HEIGHT $STATUS" + sleep 1 + fi +done +sleep 1 + +# run new binary +echo "Starting new binary" +if [[ "$OSTYPE" == "darwin"* ]]; then + screen -L -dmS node1 $NEW_BINARY start --log_level trace --log_format json --home $CHAIN_HOME --pruning=nothing +else + screen -L -Logfile $CHAIN_HOME/log-screen.log -dmS node1 $NEW_BINARY start --log_level trace --log_format json --home $CHAIN_HOME --pruning=nothing +fi +sleep 15 + +DELEGATIONS=$($NEW_BINARY query staking delegations $WALLET_ADDR_1 --output=json | jq ".delegation_responses | length") +echo "DELEGATIONS $DELEGATIONS" +if [[ "$DELEGATIONS" == "0" ]]; then + echo "Delegations removed when upgrading" +fi + +UNBONDINGS=$($NEW_BINARY query staking unbonding-delegations $WALLET_ADDR_1 --output=json | jq ".unbonding_responses | length") +echo "UNBONDINGS $UNBONDINGS" +if [[ "$UNBONDINGS" == "0" ]]; then + echo "Unbondings removed when upgrading" +fi + +BALANCES=$($NEW_BINARY query bank balances $WALLET_ADDR_1 --output=json | jq ".balances | length") +echo "BALANCES $BALANCES" +if [[ "$BALANCES" == "0" ]]; then + echo "Balance removed when upgrading" +fi