Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added v3patch1 upgrade plan and test #733

Merged
merged 2 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ import (
appupgradev2 "github.com/CoreumFoundation/coreum/v3/app/upgrade/v2"
appupgradev2patch1 "github.com/CoreumFoundation/coreum/v3/app/upgrade/v2/v2patch1"
appupgradev3 "github.com/CoreumFoundation/coreum/v3/app/upgrade/v3"
appupgradev3patch1 "github.com/CoreumFoundation/coreum/v3/app/upgrade/v3/v3patch1"
"github.com/CoreumFoundation/coreum/v3/docs"
"github.com/CoreumFoundation/coreum/v3/pkg/config"
"github.com/CoreumFoundation/coreum/v3/pkg/config/constant"
Expand Down Expand Up @@ -925,6 +926,7 @@ func New(
app.GovKeeper,
*app.StakingKeeper,
),
appupgradev3patch1.New(app.ModuleManager, app.configurator),
}

upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
Expand Down
24 changes: 24 additions & 0 deletions app/upgrade/v3/v3patch1/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package v3patch1

// This patch is supposed to be used on testnet only for upgrading from v3.0.0 (v3 plan) to v3.0.1 (v3patch1 plan).

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

"github.com/CoreumFoundation/coreum/v3/app/upgrade"
)

// Name defines the upgrade name.
const Name = "v3patch1"

// New makes an upgrade handler for v3patch1 upgrade.
func New(mm *module.Manager, configurator module.Configurator) upgrade.Upgrade {
return upgrade.Upgrade{
Name: Name,
Upgrade: func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
return mm.RunMigrations(ctx, configurator, vm)
},
}
}
122 changes: 120 additions & 2 deletions integration-tests/upgrade/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"time"

"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
govtypesv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
"github.com/pkg/errors"
Expand All @@ -16,6 +20,7 @@ import (

"github.com/CoreumFoundation/coreum-tools/pkg/retry"
appupgradev3 "github.com/CoreumFoundation/coreum/v3/app/upgrade/v3"
appupgradev3patch1 "github.com/CoreumFoundation/coreum/v3/app/upgrade/v3/v3patch1"
integrationtests "github.com/CoreumFoundation/coreum/v3/integration-tests"
"github.com/CoreumFoundation/coreum/v3/testutil/integration"
)
Expand All @@ -37,6 +42,10 @@ func TestUpgrade(t *testing.T) {
switch infoRes.ApplicationVersion.Version {
case "v2.0.2":
upgradeV3(t)
case "v3.0.0":
// Here we are testing the v3patch1 upgrade which will only run on testnet.
// It is OK to remove this test after we complete the migration there.
runUpgrade(t, "v3.0.0", appupgradev3patch1.Name, 30)
default:
requireT.Failf("not supported version: %s", infoRes.ApplicationVersion.Version)
}
Expand All @@ -56,17 +65,126 @@ func upgradeV3(t *testing.T) {
test.Before(t)
}

runUpgrade(t, "v2.0.2", appupgradev3.Name, 30)
runUpgradeLegacy(t, "v2.0.2", appupgradev3.Name, 30)

for _, test := range tests {
test.After(t)
}
}

func runUpgrade(
t *testing.T,
oldBinaryVersion string,
upgradeName string,
blocksToWait int64,
) {
ctx, chain := integrationtests.NewCoreumTestingContext(t)

requireT := require.New(t)
upgradeClient := upgradetypes.NewQueryClient(chain.ClientContext)

// Verify that there is no ongoing upgrade plan.
currentPlan, err := upgradeClient.CurrentPlan(ctx, &upgradetypes.QueryCurrentPlanRequest{})
requireT.NoError(err)
requireT.Nil(currentPlan.Plan)

tmQueryClient := tmservice.NewServiceClient(chain.ClientContext)
infoBeforeRes, err := tmQueryClient.GetNodeInfo(ctx, &tmservice.GetNodeInfoRequest{})
requireT.NoError(err)
// we start with the old binary version
require.Equal(t, oldBinaryVersion, infoBeforeRes.ApplicationVersion.Version)

latestBlockRes, err := tmQueryClient.GetLatestBlock(ctx, &tmservice.GetLatestBlockRequest{})
requireT.NoError(err)

upgradeHeight := latestBlockRes.SdkBlock.Header.Height + blocksToWait

// Create new proposer.
proposer := chain.GenAccount()
proposerBalance, err := chain.Governance.ComputeProposerBalance(ctx)
requireT.NoError(err)
chain.Faucet.FundAccounts(ctx, t, integration.NewFundedAccount(proposer, proposerBalance))

t.Logf("Creating proposal for upgrading, upgradeName:%s, upgradeHeight:%d", upgradeName, upgradeHeight)

upgradeMsg := &upgradetypes.MsgSoftwareUpgrade{
Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
Plan: upgradetypes.Plan{
Name: upgradeName,
Height: upgradeHeight,
},
}
proposalMsg, err := chain.Governance.NewMsgSubmitProposal(ctx, proposer, []sdk.Msg{upgradeMsg}, upgradeName, upgradeName, upgradeName)
requireT.NoError(err)
proposalID, err := chain.Governance.Propose(ctx, t, proposalMsg)
requireT.NoError(err)
t.Logf("Upgrade proposal has been submitted, proposalID:%d", proposalID)

// Verify that voting period started.
proposal, err := chain.Governance.GetProposal(ctx, proposalID)
requireT.NoError(err)
requireT.Equal(govtypesv1.StatusVotingPeriod, proposal.Status)

// Vote yes from all vote accounts.
err = chain.Governance.VoteAll(ctx, govtypesv1.OptionYes, proposal.Id)
requireT.NoError(err)

t.Logf("Voters have voted successfully, waiting for voting period to be finished, votingEndTime: %s", proposal.VotingEndTime)

// Wait for proposal result.
finalStatus, err := chain.Governance.WaitForVotingToFinalize(ctx, proposalID)
requireT.NoError(err)
requireT.Equal(govtypesv1.StatusPassed, finalStatus)

// Verify that upgrade plan is there waiting to be applied.
currentPlan, err = upgradeClient.CurrentPlan(ctx, &upgradetypes.QueryCurrentPlanRequest{})
requireT.NoError(err)
requireT.NotNil(currentPlan.Plan)
assert.Equal(t, upgradeName, currentPlan.Plan.Name)
assert.Equal(t, upgradeHeight, currentPlan.Plan.Height)

// Verify that we are before the upgrade
infoWaitingBlockRes, err := tmQueryClient.GetLatestBlock(ctx, &tmservice.GetLatestBlockRequest{})
requireT.NoError(err)
requireT.Less(infoWaitingBlockRes.SdkBlock.Header.Height, upgradeHeight)

retryCtx, cancel := context.WithTimeout(ctx, 6*time.Second*time.Duration(upgradeHeight-infoWaitingBlockRes.Block.Header.Height)) //nolint:staticcheck
defer cancel()
t.Logf("Waiting for upgrade, upgradeHeight:%d, currentHeight:%d", upgradeHeight, infoWaitingBlockRes.Block.Header.Height) //nolint:staticcheck
err = retry.Do(retryCtx, time.Second, func() error {
requestCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
var err error
infoAfterBlockRes, err := tmQueryClient.GetLatestBlock(requestCtx, &tmservice.GetLatestBlockRequest{})
if err != nil {
return retry.Retryable(err)
}
if infoAfterBlockRes.SdkBlock.Header.Height >= upgradeHeight+1 {
return nil
}
return retry.Retryable(errors.Errorf("waiting for upgraded block %d, current block: %d", upgradeHeight, infoAfterBlockRes.Block.Header.Height)) //nolint:staticcheck
})
requireT.NoError(err)

// Verify that upgrade was applied on chain.
appliedPlan, err := upgradeClient.AppliedPlan(ctx, &upgradetypes.QueryAppliedPlanRequest{
Name: upgradeName,
})
requireT.NoError(err)
assert.Equal(t, upgradeHeight, appliedPlan.Height)
t.Logf("Upgrade passed, applied plan height: %d", appliedPlan.Height)

// The new binary isn't equal to initial
infoAfterRes, err := tmQueryClient.GetNodeInfo(ctx, &tmservice.GetNodeInfoRequest{})
requireT.NoError(err)
t.Logf("New binary version: %s", infoAfterRes.ApplicationVersion.Version)
assert.NotEqual(t, infoAfterRes.ApplicationVersion.Version, infoBeforeRes.ApplicationVersion.Version)
}

// Note that inside this method we use deprecated Block attributed of GetLatestBlockResponse (latestBlockRes.Block)
// because we interact with older version of SDK before upgrade, and it doesn't have new SdkBlock attribute set.
// We also use deprecated v1beta1 gov because v1 doesn't exist in cored v2.0.2.
func runUpgrade(
func runUpgradeLegacy(
t *testing.T,
oldBinaryVersion string,
upgradeName string,
Expand Down