From a52ed2612d9070af7133dd1c8b3a519d1b9eefaa Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Tue, 10 Oct 2023 17:31:19 +0200 Subject: [PATCH] feat!: allow for hardcoded upgrade schedules (#2583) This PR implements the protocol work behind ADR018. After several iterations I have come across a design which I think best meets our requirements. I will need to update the ADR afterwards. This still relies on a hardcoded upgrade schedule but rather than simply upgrading at that height through `EndBlocker`, a proposer will modify the proposed block of the height before with a message indicating a version change. Nodes will vote on that version change in `ProcessProposal`. If 2/3+ support that app version then the proposal will pass and the block be committed. In the following height the upgraded nodes will perform the state migration if any and propose a block corresponding to that new app version. Nodes that don't support that app version will panic in `DeliverTx`. --------- Co-authored-by: Rootul P --- app/app.go | 48 ++- app/default_overrides.go | 2 +- app/deliver_tx.go | 23 ++ app/prepare_proposal.go | 30 ++ app/process_proposal.go | 28 +- app/test/integration_test.go | 8 +- app/version.go | 94 ++++++ cmd/celestia-appd/cmd/root.go | 17 +- proto/celestia/blob/v1/query.proto | 1 - proto/celestia/qgb/v1/query.proto | 1 - proto/celestia/upgrade/v1/types.proto | 10 + test/tokenfilter/setup.go | 2 +- test/util/malicious/app.go | 4 +- test/util/malicious/test_app.go | 12 +- test/util/network/network.go | 8 +- test/util/test_app.go | 14 +- test/util/testnode/config.go | 1 + x/blob/types/query.pb.go | 40 ++- x/qgb/types/query.pb.go | 111 ++++--- x/upgrade/keeper.go | 101 ++++++ .../integration_test.go => legacy_test.go} | 37 ++- x/upgrade/module.go | 21 -- x/upgrade/test/removal_test.go | 20 -- x/upgrade/types.go | 138 ++++++++ x/upgrade/types.pb.go | 301 ++++++++++++++++++ x/upgrade/types_test.go | 69 ++++ x/upgrade/upgrade.go | 40 +++ x/upgrade/upgrade_test.go | 230 +++++++++++++ 28 files changed, 1216 insertions(+), 195 deletions(-) create mode 100644 app/deliver_tx.go create mode 100644 app/version.go create mode 100644 proto/celestia/upgrade/v1/types.proto create mode 100644 x/upgrade/keeper.go rename x/upgrade/{test/integration_test.go => legacy_test.go} (83%) delete mode 100644 x/upgrade/module.go delete mode 100644 x/upgrade/test/removal_test.go create mode 100644 x/upgrade/types.go create mode 100644 x/upgrade/types.pb.go create mode 100644 x/upgrade/types_test.go create mode 100644 x/upgrade/upgrade.go create mode 100644 x/upgrade/upgrade_test.go diff --git a/app/app.go b/app/app.go index 128aabc4af..7a6ab7acdb 100644 --- a/app/app.go +++ b/app/app.go @@ -8,6 +8,7 @@ import ( "github.com/celestiaorg/celestia-app/x/mint" mintkeeper "github.com/celestiaorg/celestia-app/x/mint/keeper" minttypes "github.com/celestiaorg/celestia-app/x/mint/types" + "github.com/celestiaorg/celestia-app/x/upgrade" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" @@ -66,8 +67,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - sdkupgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" - sdkupgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/cosmos/ibc-go/v6/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v6/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" @@ -92,7 +91,6 @@ import ( blobmoduletypes "github.com/celestiaorg/celestia-app/x/blob/types" "github.com/celestiaorg/celestia-app/x/paramfilter" "github.com/celestiaorg/celestia-app/x/tokenfilter" - appupgrade "github.com/celestiaorg/celestia-app/x/upgrade" qgbmodule "github.com/celestiaorg/celestia-app/x/qgb" qgbmodulekeeper "github.com/celestiaorg/celestia-app/x/qgb/keeper" @@ -160,7 +158,7 @@ var ( // ModuleEncodingRegisters keeps track of all the module methods needed to // register interfaces and specific type to encoding config - ModuleEncodingRegisters = extractRegisters(ModuleBasics, appupgrade.TypeRegister{}) + ModuleEncodingRegisters = extractRegisters(ModuleBasics, upgrade.TypeRegister{}) // module account permissions maccPerms = map[string][]string{ @@ -219,7 +217,7 @@ type App struct { DistrKeeper distrkeeper.Keeper GovKeeper govkeeper.Keeper CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper sdkupgradekeeper.Keeper + UpgradeKeeper upgrade.Keeper ParamsKeeper paramskeeper.Keeper IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly EvidenceKeeper evidencekeeper.Keeper @@ -235,6 +233,9 @@ type App struct { // the module manager mm *module.Manager + + // module configurator + configurator module.Configurator } // New returns a reference to an initialized celestia app. @@ -243,13 +244,18 @@ func New( db dbm.DB, traceStore io.Writer, loadLatest bool, - skipUpgradeHeights map[int64]bool, - homePath string, invCheckPeriod uint, encodingConfig encoding.Config, + upgradeSchedule map[string]upgrade.Schedule, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *App { + for _, schedule := range upgradeSchedule { + if err := schedule.ValidateVersions(supportedVersions); err != nil { + panic(err) + } + } + appCodec := encodingConfig.Codec cdc := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry @@ -262,7 +268,7 @@ func New( keys := sdk.NewKVStoreKeys( authtypes.StoreKey, authzkeeper.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, paramstypes.StoreKey, sdkupgradetypes.StoreKey, feegrant.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, upgrade.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, capabilitytypes.StoreKey, blobmoduletypes.StoreKey, qgbmoduletypes.StoreKey, @@ -328,7 +334,7 @@ func New( ) app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], app.AccountKeeper) - app.UpgradeKeeper = sdkupgradekeeper.NewKeeper(skipUpgradeHeights, keys[sdkupgradetypes.StoreKey], appCodec, homePath, app.BaseApp, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + app.UpgradeKeeper = upgrade.NewKeeper(keys[upgrade.StoreKey], upgradeSchedule) app.QgbKeeper = *qgbmodulekeeper.NewKeeper( appCodec, @@ -463,6 +469,7 @@ func New( paramstypes.ModuleName, authz.ModuleName, vestingtypes.ModuleName, + upgrade.ModuleName, ) app.mm.SetOrderEndBlockers( @@ -485,6 +492,7 @@ func New( paramstypes.ModuleName, authz.ModuleName, vestingtypes.ModuleName, + upgrade.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -512,7 +520,7 @@ func New( feegrant.ModuleName, paramstypes.ModuleName, authz.ModuleName, - sdkupgradetypes.ModuleName, + upgrade.ModuleName, ) app.QueryRouter().AddRoute(proof.TxInclusionQueryPath, proof.QueryTxInclusionProof) @@ -520,8 +528,8 @@ func New( app.mm.RegisterInvariants(&app.CrisisKeeper) app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) - configurator := module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) - app.mm.RegisterServices(configurator) + app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) + app.mm.RegisterServices(app.configurator) // initialize stores app.MountKVStores(keys) @@ -565,7 +573,17 @@ func (app *App) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.R // EndBlocker application updates every end block func (app *App) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { - return app.mm.EndBlock(ctx, req) + res := app.mm.EndBlock(ctx, req) + if app.UpgradeKeeper.ShouldUpgrade() { + newAppVersion := app.UpgradeKeeper.GetNextAppVersion() + app.SetProtocolVersion(newAppVersion) + _, err := app.mm.RunMigrations(ctx, app.configurator, GetModuleVersion(newAppVersion)) + if err != nil { + panic(err) + } + app.UpgradeKeeper.MarkUpgradeComplete() + } + return res } // InitChainer application update at chain initialization @@ -574,7 +592,9 @@ func (app *App) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.Res if err := tmjson.Unmarshal(req.AppStateBytes, &genesisState); err != nil { panic(err) } - app.UpgradeKeeper.SetModuleVersionMap(ctx, app.mm.GetVersionMap()) + if req.ConsensusParams != nil && req.ConsensusParams.Version != nil { + app.SetProtocolVersion(req.ConsensusParams.Version.AppVersion) + } return app.mm.InitGenesis(ctx, app.appCodec, genesisState) } diff --git a/app/default_overrides.go b/app/default_overrides.go index c2a9d6f199..73862c601a 100644 --- a/app/default_overrides.go +++ b/app/default_overrides.go @@ -187,7 +187,7 @@ func DefaultConsensusParams() *tmproto.ConsensusParams { Evidence: DefaultEvidenceParams(), Validator: coretypes.DefaultValidatorParams(), Version: tmproto.VersionParams{ - AppVersion: appconsts.LatestVersion, + AppVersion: DefaultInitialVersion, }, } } diff --git a/app/deliver_tx.go b/app/deliver_tx.go new file mode 100644 index 0000000000..1b3dbc3d6f --- /dev/null +++ b/app/deliver_tx.go @@ -0,0 +1,23 @@ +package app + +import ( + "fmt" + + "github.com/celestiaorg/celestia-app/x/upgrade" + abci "github.com/tendermint/tendermint/abci/types" +) + +func (app *App) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx { + sdkTx, err := app.txConfig.TxDecoder()(req.Tx) + if err == nil { + if appVersion, ok := upgrade.IsUpgradeMsg(sdkTx.GetMsgs()); ok { + if !IsSupported(appVersion) { + panic(fmt.Sprintf("network has upgraded to version %d which is not supported by this node. Please upgrade and restart", appVersion)) + } + app.UpgradeKeeper.PrepareUpgradeAtEndBlock(appVersion) + // TODO: we may want to emit an event for this + return abci.ResponseDeliverTx{Code: abci.CodeTypeOK} + } + } + return app.BaseApp.DeliverTx(req) +} diff --git a/app/prepare_proposal.go b/app/prepare_proposal.go index 2240f79371..8929c31cd5 100644 --- a/app/prepare_proposal.go +++ b/app/prepare_proposal.go @@ -7,6 +7,7 @@ import ( "github.com/celestiaorg/celestia-app/pkg/da" "github.com/celestiaorg/celestia-app/pkg/shares" "github.com/celestiaorg/celestia-app/pkg/square" + "github.com/celestiaorg/celestia-app/x/upgrade" "github.com/cosmos/cosmos-sdk/telemetry" abci "github.com/tendermint/tendermint/abci/types" core "github.com/tendermint/tendermint/proto/tendermint/types" @@ -58,6 +59,27 @@ func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePr txs = make([][]byte, 0) } else { txs = FilterTxs(app.Logger(), sdkCtx, handler, app.txConfig, req.BlockData.Txs) + + // TODO: this would be improved if we only attempted the upgrade in the first round of the + // height to still allow transactions to pass through without being delayed from trying + // to coordinate the upgrade height + if newVersion, ok := app.UpgradeKeeper.ShouldProposeUpgrade(req.ChainId, req.Height); ok && newVersion > app.GetBaseApp().AppVersion() { + upgradeTx, err := upgrade.NewMsgVersionChange(app.txConfig, newVersion) + if err != nil { + panic(err) + } + // the upgrade transaction must be the first transaction in the block + txs = append([][]byte{upgradeTx}, txs...) + + // because we are adding bytes, we need to check that we are not going over the limit + // if we are, we continually prune the last tx (the lowest paying blobTx). + size := sizeOf(txs) + for size > int(req.BlockDataSize) { + lastTx := txs[len(txs)-1] + txs = txs[:len(txs)-1] + size -= len(lastTx) + } + } } // build the square from the set of valid and prioritised transactions. @@ -102,3 +124,11 @@ func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePr }, } } + +func sizeOf(txs [][]byte) int { + size := 0 + for _, tx := range txs { + size += len(tx) + } + return size +} diff --git a/app/process_proposal.go b/app/process_proposal.go index b2e6a446b9..5089e995bc 100644 --- a/app/process_proposal.go +++ b/app/process_proposal.go @@ -10,6 +10,7 @@ import ( "github.com/celestiaorg/celestia-app/pkg/shares" "github.com/celestiaorg/celestia-app/pkg/square" blobtypes "github.com/celestiaorg/celestia-app/x/blob/types" + "github.com/celestiaorg/celestia-app/x/upgrade" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/tendermint/abci/types" @@ -66,19 +67,42 @@ func (app *App) ProcessProposal(req abci.RequestProcessProposal) (resp abci.Resp // handle non-blob transactions first if !isBlobTx { - _, has := hasPFB(sdkTx.GetMsgs()) + msgs := sdkTx.GetMsgs() + + _, has := hasPFB(msgs) if has { // A non blob tx has a PFB, which is invalid logInvalidPropBlock(app.Logger(), req.Header, fmt.Sprintf("tx %d has PFB but is not a blob tx", idx)) return reject() } + if appVersion, ok := upgrade.IsUpgradeMsg(msgs); ok { + if idx != 0 { + logInvalidPropBlock(app.Logger(), req.Header, fmt.Sprintf("upgrade message %d is not the first transaction", idx)) + return reject() + } + + if !IsSupported(appVersion) { + logInvalidPropBlock(app.Logger(), req.Header, fmt.Sprintf("block proposes an unsupported app version %d", appVersion)) + return reject() + } + + // app version must always increase + if appVersion <= app.GetBaseApp().AppVersion() { + logInvalidPropBlock(app.Logger(), req.Header, fmt.Sprintf("block proposes an app version %d that is not greater than the current app version %d", appVersion, app.GetBaseApp().AppVersion())) + return reject() + } + + // we don't need to pass this message through the ante handler + continue + } + // we need to increment the sequence for every transaction so that // the signature check below is accurate. this error only gets hit // if the account in question doens't exist. sdkCtx, err = handler(sdkCtx, sdkTx, false) if err != nil { - logInvalidPropBlockError(app.Logger(), req.Header, "failure to incrememnt sequence", err) + logInvalidPropBlockError(app.Logger(), req.Header, "failure to increment sequence", err) return reject() } diff --git a/app/test/integration_test.go b/app/test/integration_test.go index 3fcb9d5dfd..5c00219038 100644 --- a/app/test/integration_test.go +++ b/app/test/integration_test.go @@ -192,7 +192,9 @@ func (s *IntegrationTestSuite) TestMaxBlockSize() { require.GreaterOrEqual(t, size, uint64(appconsts.MinSquareSize)) // assert that the app version is correctly set - require.Equal(t, appconsts.LatestVersion, blockRes.Block.Header.Version.App) + // FIXME: This should return the latest version but tendermint v0.34.x doesn't copy + // over the version when converting from proto so it disappears + require.EqualValues(t, 0, blockRes.Block.Header.Version.App) sizes = append(sizes, size) ExtendBlobTest(t, blockRes.Block) @@ -329,7 +331,9 @@ func (s *IntegrationTestSuite) TestShareInclusionProof() { blockRes, err := node.Block(context.Background(), &txResp.Height) require.NoError(t, err) - require.Equal(t, appconsts.LatestVersion, blockRes.Block.Header.Version.App) + // FIXME: This should return the latest version but tendermint v0.34.x doesn't copy + // over the version when converting from proto so it disappears + require.EqualValues(t, 0, blockRes.Block.Header.Version.App) _, isBlobTx := coretypes.UnmarshalBlobTx(blockRes.Block.Txs[txResp.Index]) require.True(t, isBlobTx) diff --git a/app/version.go b/app/version.go new file mode 100644 index 0000000000..7b711abdaf --- /dev/null +++ b/app/version.go @@ -0,0 +1,94 @@ +package app + +import ( + "fmt" + + v1 "github.com/celestiaorg/celestia-app/pkg/appconsts/v1" + v2 "github.com/celestiaorg/celestia-app/pkg/appconsts/v2" + "github.com/celestiaorg/celestia-app/x/blob" + "github.com/celestiaorg/celestia-app/x/mint" + "github.com/celestiaorg/celestia-app/x/qgb" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" + "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/capability" + "github.com/cosmos/cosmos-sdk/x/crisis" + "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/evidence" + feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/slashing" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/ibc-go/v6/modules/apps/transfer" + ibc "github.com/cosmos/ibc-go/v6/modules/core" +) + +var ( + // versions that the current state machine supports + supportedVersions = []uint64{v1.Version, v2.Version} + + v1moduleVersionMap = module.VersionMap{ + "bank": bank.AppModule{}.ConsensusVersion(), + "auth": auth.AppModule{}.ConsensusVersion(), + "authz": authzmodule.AppModule{}.ConsensusVersion(), + "staking": staking.AppModule{}.ConsensusVersion(), + "mint": mint.AppModule{}.ConsensusVersion(), + "distribution": distribution.AppModule{}.ConsensusVersion(), + "slashing": slashing.AppModule{}.ConsensusVersion(), + "gov": gov.AppModule{}.ConsensusVersion(), + "params": params.AppModule{}.ConsensusVersion(), + "vesting": vesting.AppModule{}.ConsensusVersion(), + "feegrant": feegrantmodule.AppModule{}.ConsensusVersion(), + "evidence": evidence.AppModule{}.ConsensusVersion(), + "crisis": crisis.AppModule{}.ConsensusVersion(), + "genutil": genutil.AppModule{}.ConsensusVersion(), + "capability": capability.AppModule{}.ConsensusVersion(), + "blob": blob.AppModule{}.ConsensusVersion(), + "qgb": qgb.AppModule{}.ConsensusVersion(), + "ibc": ibc.AppModule{}.ConsensusVersion(), + "transfer": transfer.AppModule{}.ConsensusVersion(), + } + + // There is currently complete parity between v1 and v2 modules, but this + // will likely change + v2moduleVersionMap = v1moduleVersionMap +) + +const DefaultInitialVersion = v1.Version + +// this is used as a compile time consistency check across different module +// based maps +func init() { + for moduleName := range ModuleBasics { + for _, v := range supportedVersions { + versionMap := GetModuleVersion(v) + if _, ok := versionMap[moduleName]; !ok { + panic(fmt.Sprintf("inconsistency: module %s not found in module version map for version %d", moduleName, v)) + } + } + } +} + +func IsSupported(version uint64) bool { + for _, v := range supportedVersions { + if v == version { + return true + } + } + return false +} + +func GetModuleVersion(appVersion uint64) module.VersionMap { + switch appVersion { + case v1.Version: + return v1moduleVersionMap + case v2.Version: + return v2moduleVersionMap + default: + panic(fmt.Sprintf("unsupported app version %d", appVersion)) + } +} diff --git a/cmd/celestia-appd/cmd/root.go b/cmd/celestia-appd/cmd/root.go index 91c86dc787..4e48f24dd4 100644 --- a/cmd/celestia-appd/cmd/root.go +++ b/cmd/celestia-appd/cmd/root.go @@ -5,7 +5,6 @@ import ( "os" "path/filepath" - "github.com/celestiaorg/celestia-app/pkg/appconsts" qgbcmd "github.com/celestiaorg/celestia-app/x/qgb/client" "github.com/celestiaorg/celestia-app/app" @@ -211,11 +210,6 @@ func NewAppServer(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts se cache = store.NewCommitKVStoreCacheManager() } - skipUpgradeHeights := make(map[int64]bool) - for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { - skipUpgradeHeights[int64(h)] = true - } - pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) if err != nil { panic(err) @@ -234,10 +228,10 @@ func NewAppServer(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts se } return app.New( - logger, db, traceStore, true, skipUpgradeHeights, - cast.ToString(appOpts.Get(flags.FlagHome)), + logger, db, traceStore, true, cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), encoding.MakeConfig(app.ModuleEncodingRegisters...), // Ideally, we would reuse the one created by NewRootCmd. + nil, appOpts, baseapp.SetPruning(pruningOpts), baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), @@ -249,9 +243,6 @@ func NewAppServer(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts se baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval)), cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent)))), - func(b *baseapp.BaseApp) { - b.SetProtocolVersion(appconsts.LatestVersion) - }, ) } @@ -263,13 +254,13 @@ func createAppAndExport( encCfg.Codec = codec.NewProtoCodec(encCfg.InterfaceRegistry) var capp *app.App if height != -1 { - capp = app.New(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), encCfg, appOpts) + capp = app.New(logger, db, traceStore, false, uint(1), encCfg, nil, appOpts) if err := capp.LoadHeight(height); err != nil { return servertypes.ExportedApp{}, err } } else { - capp = app.New(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), encCfg, appOpts) + capp = app.New(logger, db, traceStore, true, uint(1), encCfg, nil, appOpts) } return capp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) diff --git a/proto/celestia/blob/v1/query.proto b/proto/celestia/blob/v1/query.proto index 8c6c49e9f8..47d484b3c6 100644 --- a/proto/celestia/blob/v1/query.proto +++ b/proto/celestia/blob/v1/query.proto @@ -3,7 +3,6 @@ package celestia.blob.v1; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; import "celestia/blob/v1/params.proto"; option go_package = "github.com/celestiaorg/celestia-app/x/blob/types"; diff --git a/proto/celestia/qgb/v1/query.proto b/proto/celestia/qgb/v1/query.proto index f3ac2a4474..d09d5ee80f 100644 --- a/proto/celestia/qgb/v1/query.proto +++ b/proto/celestia/qgb/v1/query.proto @@ -4,7 +4,6 @@ package celestia.qgb.v1; import "celestia/qgb/v1/genesis.proto"; import "celestia/qgb/v1/types.proto"; import "google/api/annotations.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; import "gogoproto/gogo.proto"; import "cosmos_proto/cosmos.proto"; import "google/protobuf/any.proto"; diff --git a/proto/celestia/upgrade/v1/types.proto b/proto/celestia/upgrade/v1/types.proto new file mode 100644 index 0000000000..cee2591479 --- /dev/null +++ b/proto/celestia/upgrade/v1/types.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package celestia.upgrade.v1; + +option go_package = "github.com/celestiaorg/celestia-app/x/upgrade"; + +// MsgVersionChange is a message that signals an app version change +message MsgVersionChange { + // the app version this message proposes upgrading to + uint64 version = 1; +} diff --git a/test/tokenfilter/setup.go b/test/tokenfilter/setup.go index c91e70cb16..454ea97e93 100644 --- a/test/tokenfilter/setup.go +++ b/test/tokenfilter/setup.go @@ -140,7 +140,7 @@ func SetupWithGenesisValSet(t testing.TB, valSet *tmtypes.ValidatorSet, genAccs encCdc := encoding.MakeConfig(app.ModuleEncodingRegisters...) genesisState := app.NewDefaultGenesisState(encCdc.Codec) app := app.New( - log.NewNopLogger(), db, nil, true, map[int64]bool{}, app.DefaultNodeHome, 5, encCdc, simapp.EmptyAppOptions{}, + log.NewNopLogger(), db, nil, true, 5, encCdc, nil, simapp.EmptyAppOptions{}, ) // set genesis accounts diff --git a/test/util/malicious/app.go b/test/util/malicious/app.go index ac0e510d2e..20e813748c 100644 --- a/test/util/malicious/app.go +++ b/test/util/malicious/app.go @@ -52,14 +52,12 @@ func New( db dbm.DB, traceStore io.Writer, loadLatest bool, - skipUpgradeHeights map[int64]bool, - homePath string, invCheckPeriod uint, encodingConfig encoding.Config, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *App { - goodApp := app.New(logger, db, traceStore, loadLatest, skipUpgradeHeights, homePath, invCheckPeriod, encodingConfig, appOpts, baseAppOptions...) + goodApp := app.New(logger, db, traceStore, loadLatest, invCheckPeriod, encodingConfig, nil, appOpts, baseAppOptions...) badApp := &App{App: goodApp} // set the malicious prepare proposal handler if it is set in the app options diff --git a/test/util/malicious/test_app.go b/test/util/malicious/test_app.go index c7f0b80329..c5c00ae135 100644 --- a/test/util/malicious/test_app.go +++ b/test/util/malicious/test_app.go @@ -6,7 +6,6 @@ import ( "github.com/celestiaorg/celestia-app/app" "github.com/celestiaorg/celestia-app/app/encoding" - "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/test/util" "github.com/celestiaorg/celestia-app/test/util/testnode" "github.com/cosmos/cosmos-sdk/baseapp" @@ -60,11 +59,6 @@ func NewAppServer(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts se cache = store.NewCommitKVStoreCacheManager() } - skipUpgradeHeights := make(map[int64]bool) - for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { - skipUpgradeHeights[int64(h)] = true - } - pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) if err != nil { panic(err) @@ -83,8 +77,7 @@ func NewAppServer(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts se } return New( - logger, db, traceStore, true, skipUpgradeHeights, - cast.ToString(appOpts.Get(flags.FlagHome)), + logger, db, traceStore, true, cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), encoding.MakeConfig(app.ModuleEncodingRegisters...), // Ideally, we would reuse the one created by NewRootCmd. appOpts, @@ -98,8 +91,5 @@ func NewAppServer(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts se baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval)), cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent)))), - func(b *baseapp.BaseApp) { - b.SetProtocolVersion(appconsts.LatestVersion) - }, ) } diff --git a/test/util/network/network.go b/test/util/network/network.go index b3b0c298d2..fc130e7d23 100644 --- a/test/util/network/network.go +++ b/test/util/network/network.go @@ -8,7 +8,6 @@ import ( "github.com/celestiaorg/celestia-app/app" "github.com/celestiaorg/celestia-app/app/encoding" - "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -77,14 +76,11 @@ func DefaultConfig() network.Config { AccountRetriever: authtypes.AccountRetriever{}, AppConstructor: func(val network.Validator) servertypes.Application { return app.New( - val.Ctx.Logger, tmdb.NewMemDB(), nil, true, map[int64]bool{}, val.Ctx.Config.RootDir, 0, - encCfg, + val.Ctx.Logger, tmdb.NewMemDB(), nil, true, 0, + encCfg, nil, simapp.EmptyAppOptions{}, baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices), - func(b *baseapp.BaseApp) { - b.SetProtocolVersion(appconsts.LatestVersion) - }, ) }, GenesisState: app.ModuleBasics.DefaultGenesis(encCfg.Codec), diff --git a/test/util/test_app.go b/test/util/test_app.go index 2fde7bbff9..f13ace9243 100644 --- a/test/util/test_app.go +++ b/test/util/test_app.go @@ -10,7 +10,6 @@ import ( "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/test/util/testfactory" "github.com/celestiaorg/celestia-app/test/util/testnode" - "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" @@ -39,10 +38,10 @@ func init() { simapp.GetSimulatorFlags() } -type emptyAppOptions struct{} +type EmptyAppOptions struct{} // Get implements AppOptions -func (ao emptyAppOptions) Get(_ string) interface{} { +func (ao EmptyAppOptions) Get(_ string) interface{} { return nil } @@ -53,21 +52,19 @@ func (ao emptyAppOptions) Get(_ string) interface{} { func SetupTestAppWithGenesisValSet(cparams *tmproto.ConsensusParams, genAccounts ...string) (*app.App, keyring.Keyring) { // var cache sdk.MultiStorePersistentCache // EmptyAppOptions is a stub implementing AppOptions - emptyOpts := emptyAppOptions{} + emptyOpts := EmptyAppOptions{} // var anteOpt = func(bapp *baseapp.BaseApp) { bapp.SetAnteHandler(nil) } db := dbm.NewMemDB() - skipUpgradeHeights := make(map[int64]bool) encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) testApp := app.New( - log.NewNopLogger(), db, nil, true, skipUpgradeHeights, - cast.ToString(emptyOpts.Get(flags.FlagHome)), + log.NewNopLogger(), db, nil, true, cast.ToUint(emptyOpts.Get(server.FlagInvCheckPeriod)), encCfg, + nil, emptyOpts, ) - testApp.GetBaseApp().SetProtocolVersion(appconsts.LatestVersion) genesisState, valSet, kr := GenesisStateWithSingleValidator(testApp, genAccounts...) @@ -85,6 +82,7 @@ func SetupTestAppWithGenesisValSet(cparams *tmproto.ConsensusParams, genAccounts }, Evidence: &cparams.Evidence, Validator: &cparams.Validator, + Version: &cparams.Version, } genesisTime := time.Date(2023, 1, 1, 1, 1, 1, 1, time.UTC).UTC() diff --git a/test/util/testnode/config.go b/test/util/testnode/config.go index 5e272e10bf..bb04f44ee4 100644 --- a/test/util/testnode/config.go +++ b/test/util/testnode/config.go @@ -153,6 +153,7 @@ func DefaultParams() *tmproto.ConsensusParams { cparams := types.DefaultConsensusParams() cparams.Block.TimeIotaMs = 1 cparams.Block.MaxBytes = appconsts.DefaultMaxBytes + cparams.Version.AppVersion = appconsts.LatestVersion return cparams } diff --git a/x/blob/types/query.pb.go b/x/blob/types/query.pb.go index 3e96f05c2e..c28b5b01ed 100644 --- a/x/blob/types/query.pb.go +++ b/x/blob/types/query.pb.go @@ -6,7 +6,6 @@ package types import ( context "context" fmt "fmt" - _ "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -120,26 +119,25 @@ func init() { func init() { proto.RegisterFile("celestia/blob/v1/query.proto", fileDescriptor_29ba8a4248383b64) } var fileDescriptor_29ba8a4248383b64 = []byte{ - // 304 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x90, 0x41, 0x4b, 0xc3, 0x30, - 0x18, 0x86, 0x5b, 0xd1, 0x1d, 0xe2, 0x41, 0x8d, 0x03, 0xc7, 0x98, 0x51, 0x86, 0x82, 0x08, 0x26, - 0x76, 0x82, 0x3f, 0x60, 0x47, 0x41, 0xd0, 0x1d, 0xbd, 0x25, 0x23, 0xc4, 0xc2, 0x96, 0x2f, 0x6b, - 0xd2, 0xea, 0xae, 0xfe, 0x02, 0xc1, 0x3f, 0xb5, 0xe3, 0xc0, 0x8b, 0x27, 0x91, 0xd6, 0x1f, 0x22, - 0x6d, 0x3a, 0xc1, 0xf5, 0xe0, 0xed, 0xe3, 0x7b, 0x9f, 0xf7, 0xcd, 0xfb, 0x05, 0xf5, 0xc6, 0x72, - 0x22, 0xad, 0x8b, 0x39, 0x13, 0x13, 0x10, 0x2c, 0x8b, 0xd8, 0x2c, 0x95, 0xc9, 0x9c, 0x9a, 0x04, - 0x1c, 0xe0, 0xdd, 0x95, 0x4a, 0x4b, 0x95, 0x66, 0x51, 0xb7, 0xad, 0x40, 0x41, 0x25, 0xb2, 0x72, - 0xf2, 0x5c, 0xb7, 0xa7, 0x00, 0xd4, 0x44, 0x32, 0x6e, 0x62, 0xc6, 0xb5, 0x06, 0xc7, 0x5d, 0x0c, - 0xda, 0xd6, 0xea, 0xf9, 0x18, 0xec, 0x14, 0x2c, 0x13, 0xdc, 0x4a, 0x1f, 0xcf, 0xb2, 0x48, 0x48, - 0xc7, 0x23, 0x66, 0xb8, 0x8a, 0x75, 0x05, 0xd7, 0xec, 0x61, 0xa3, 0x8f, 0xe1, 0x09, 0x9f, 0xd6, - 0x51, 0xfd, 0x36, 0xc2, 0xf7, 0x65, 0xc0, 0x5d, 0xb5, 0x1c, 0xc9, 0x59, 0x2a, 0xad, 0xeb, 0xdf, - 0xa2, 0xfd, 0x3f, 0x5b, 0x6b, 0x40, 0x5b, 0x89, 0xaf, 0x51, 0xcb, 0x9b, 0x3b, 0xe1, 0x71, 0x78, - 0xb6, 0x3d, 0xe8, 0xd0, 0xf5, 0x73, 0xa8, 0x77, 0x0c, 0x37, 0x17, 0x9f, 0x47, 0xc1, 0xa8, 0xa6, - 0x07, 0x4f, 0x68, 0xab, 0x8a, 0xc3, 0x1a, 0xb5, 0x3c, 0x80, 0x4f, 0x9a, 0xd6, 0x66, 0x8f, 0xee, - 0xe9, 0x3f, 0x94, 0xef, 0xd5, 0x3f, 0x78, 0x79, 0xff, 0x7e, 0xdb, 0xd8, 0xc3, 0x3b, 0x6b, 0x37, - 0x0e, 0x6f, 0x16, 0x39, 0x09, 0x97, 0x39, 0x09, 0xbf, 0x72, 0x12, 0xbe, 0x16, 0x24, 0x58, 0x16, - 0x24, 0xf8, 0x28, 0x48, 0xf0, 0x70, 0xa9, 0x62, 0xf7, 0x98, 0x0a, 0x3a, 0x86, 0x29, 0x5b, 0xbd, - 0x01, 0x89, 0xfa, 0x9d, 0x2f, 0xb8, 0x31, 0xec, 0xd9, 0xe7, 0xb9, 0xb9, 0x91, 0x56, 0xb4, 0xaa, - 0x0f, 0xbb, 0xfa, 0x09, 0x00, 0x00, 0xff, 0xff, 0x39, 0x82, 0x2f, 0xc4, 0xe1, 0x01, 0x00, 0x00, + // 275 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x49, 0x4e, 0xcd, 0x49, + 0x2d, 0x2e, 0xc9, 0x4c, 0xd4, 0x4f, 0xca, 0xc9, 0x4f, 0xd2, 0x2f, 0x33, 0xd4, 0x2f, 0x2c, 0x4d, + 0x2d, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x80, 0xc9, 0xea, 0x81, 0x64, 0xf5, + 0xca, 0x0c, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x92, 0xfa, 0x20, 0x16, 0x44, 0x9d, 0x94, + 0x4c, 0x7a, 0x7e, 0x7e, 0x7a, 0x4e, 0xaa, 0x7e, 0x62, 0x41, 0xa6, 0x7e, 0x62, 0x5e, 0x5e, 0x7e, + 0x49, 0x62, 0x49, 0x66, 0x7e, 0x5e, 0x31, 0x54, 0x56, 0x16, 0xc3, 0x8e, 0x82, 0xc4, 0xa2, 0xc4, + 0x5c, 0xa8, 0xb4, 0x92, 0x08, 0x97, 0x50, 0x20, 0xc8, 0xce, 0x00, 0xb0, 0x60, 0x50, 0x6a, 0x61, + 0x69, 0x6a, 0x71, 0x89, 0x92, 0x2f, 0x97, 0x30, 0x8a, 0x68, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0xaa, + 0x90, 0x19, 0x17, 0x1b, 0x44, 0xb3, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0x84, 0x1e, 0xba, + 0x13, 0xf5, 0x20, 0x3a, 0x9c, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0xaa, 0x36, 0x2a, 0xe7, + 0x62, 0x05, 0x1b, 0x27, 0x94, 0xc7, 0xc5, 0x06, 0x51, 0x20, 0xa4, 0x82, 0xa9, 0x15, 0xd3, 0x1d, + 0x52, 0xaa, 0x04, 0x54, 0x41, 0xdc, 0xa5, 0x24, 0xde, 0x74, 0xf9, 0xc9, 0x64, 0x26, 0x41, 0x21, + 0x7e, 0x34, 0x3f, 0x3a, 0x79, 0x9d, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, + 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, + 0x41, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0xcc, 0x8e, 0xfc, 0xa2, + 0x74, 0x38, 0x5b, 0x37, 0xb1, 0xa0, 0x40, 0xbf, 0x02, 0x62, 0x5e, 0x49, 0x65, 0x41, 0x6a, 0x71, + 0x12, 0x1b, 0x38, 0xc0, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb0, 0x7e, 0x20, 0x5f, 0xb5, + 0x01, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/qgb/types/query.pb.go b/x/qgb/types/query.pb.go index c5e8f7c4c0..ed7df634a6 100644 --- a/x/qgb/types/query.pb.go +++ b/x/qgb/types/query.pb.go @@ -8,7 +8,6 @@ import ( fmt "fmt" _ "github.com/cosmos/cosmos-proto" types "github.com/cosmos/cosmos-sdk/codec/types" - _ "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -763,62 +762,60 @@ func init() { func init() { proto.RegisterFile("celestia/qgb/v1/query.proto", fileDescriptor_c8535c57355a2b91) } var fileDescriptor_c8535c57355a2b91 = []byte{ - // 873 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x96, 0xcd, 0x6f, 0xe3, 0x44, - 0x18, 0xc6, 0x63, 0xb4, 0x1b, 0x89, 0xb7, 0xd2, 0x7e, 0x4c, 0xb2, 0x29, 0xf5, 0x2e, 0x6e, 0xd7, - 0xe9, 0x76, 0xbb, 0xbb, 0xd4, 0xa3, 0xa4, 0x7c, 0x88, 0xdd, 0xe5, 0xd0, 0x40, 0x51, 0x2b, 0x95, - 0xaf, 0x48, 0xf4, 0xc0, 0x81, 0x6a, 0x9c, 0x4c, 0x5d, 0x8b, 0xd8, 0xe3, 0xd8, 0x4e, 0x44, 0x04, - 0x5c, 0xf8, 0x0b, 0x90, 0x38, 0x72, 0xe6, 0xca, 0x89, 0x13, 0x1c, 0xb9, 0x54, 0x3d, 0x55, 0xe2, - 0xc2, 0x09, 0xa1, 0x96, 0x3f, 0x04, 0x65, 0x3e, 0x52, 0x27, 0x76, 0x9c, 0xa4, 0xe2, 0xe6, 0x99, - 0x79, 0xde, 0xe7, 0xfd, 0xbd, 0xd3, 0xfa, 0x89, 0xe1, 0x7e, 0x8b, 0x76, 0x68, 0x14, 0xbb, 0x04, - 0x77, 0x1d, 0x1b, 0xf7, 0x6b, 0xb8, 0xdb, 0xa3, 0xe1, 0xc0, 0x0a, 0x42, 0x16, 0x33, 0x74, 0x5b, - 0x1d, 0x5a, 0x5d, 0xc7, 0xb6, 0xfa, 0x35, 0xfd, 0xf5, 0x49, 0xb5, 0x43, 0x7d, 0x1a, 0xb9, 0x91, - 0xd0, 0xeb, 0x29, 0xb3, 0x78, 0x10, 0x50, 0x75, 0xf8, 0xc0, 0x61, 0xcc, 0xe9, 0x50, 0x4c, 0x02, - 0x17, 0x13, 0xdf, 0x67, 0x31, 0x89, 0x5d, 0xe6, 0xab, 0xd3, 0xa7, 0x2d, 0x16, 0x79, 0x2c, 0xc2, - 0x36, 0x89, 0xa8, 0x60, 0xc0, 0xfd, 0x9a, 0x4d, 0x63, 0x52, 0xc3, 0x01, 0x71, 0x5c, 0x9f, 0x8b, - 0xa5, 0xb6, 0xec, 0x30, 0x87, 0xf1, 0x47, 0x3c, 0x7c, 0x92, 0xbb, 0x2b, 0xc2, 0xe1, 0x48, 0x1c, - 0x88, 0x85, 0x3a, 0x92, 0xad, 0xf9, 0xca, 0xee, 0x1d, 0x63, 0xe2, 0xcb, 0x11, 0xcd, 0x32, 0xa0, - 0xcf, 0x86, 0xdd, 0x3e, 0x25, 0x21, 0xf1, 0xa2, 0x26, 0xed, 0xf6, 0x68, 0x14, 0x9b, 0x07, 0x50, - 0x1a, 0xdb, 0x8d, 0x02, 0xe6, 0x47, 0x14, 0xbd, 0x05, 0xc5, 0x80, 0xef, 0xbc, 0xa6, 0xad, 0x69, - 0x9b, 0x4b, 0xf5, 0x65, 0x6b, 0xe2, 0x82, 0x2c, 0x51, 0xd0, 0xb8, 0x71, 0xfa, 0xf7, 0x6a, 0xa1, - 0x29, 0xc5, 0xe6, 0x7b, 0xf0, 0x88, 0xbb, 0xed, 0xc4, 0x31, 0x8d, 0xc4, 0xd8, 0xb2, 0x51, 0x63, - 0xf0, 0x31, 0xf3, 0x5b, 0x54, 0xae, 0x50, 0x19, 0x6e, 0xfa, 0xc3, 0x35, 0xb7, 0xbf, 0xd1, 0x14, - 0x0b, 0x73, 0x00, 0x1b, 0xb3, 0xca, 0x25, 0xdf, 0x27, 0xb0, 0x44, 0xae, 0x44, 0x12, 0xb2, 0x6c, - 0x89, 0xe9, 0x2d, 0x35, 0xbd, 0xb5, 0xe3, 0x0f, 0x1a, 0xcb, 0x67, 0xbf, 0x6e, 0x95, 0xd2, 0x8e, - 0xfb, 0xcd, 0xa4, 0x83, 0xb9, 0x0e, 0x26, 0x6f, 0x7d, 0x40, 0x86, 0x7b, 0x09, 0x79, 0x12, 0xdb, - 0x7c, 0x01, 0xd5, 0x5c, 0x95, 0xa4, 0xcb, 0x9e, 0xae, 0x01, 0x4f, 0x13, 0xc5, 0x87, 0xa4, 0x13, - 0xd1, 0x58, 0x8d, 0x47, 0x8f, 0x59, 0x48, 0xe7, 0xb8, 0xa1, 0x2f, 0xe1, 0xd9, 0x5c, 0x1e, 0x12, - 0x04, 0x43, 0xb1, 0xcf, 0x35, 0x53, 0xff, 0x8c, 0xd2, 0x42, 0xca, 0xcc, 0x2a, 0x3c, 0x4c, 0xf8, - 0x7f, 0xee, 0xdb, 0xcc, 0x6f, 0xbb, 0xbe, 0xb3, 0x47, 0x5d, 0xe7, 0x44, 0x35, 0x32, 0x5f, 0x8e, - 0xdd, 0x55, 0x4a, 0x24, 0x7b, 0x57, 0xa0, 0x78, 0xc2, 0x77, 0xe4, 0x04, 0x72, 0x65, 0x9a, 0xb0, - 0x96, 0xa8, 0xfe, 0x80, 0xc4, 0xe4, 0x7d, 0xe6, 0x79, 0x6e, 0xec, 0x51, 0x7f, 0xd4, 0xc1, 0x1b, - 0xc3, 0x98, 0xd4, 0xc8, 0x06, 0x7b, 0x70, 0xbb, 0x4d, 0x62, 0x72, 0xd4, 0x1a, 0x1d, 0xc9, 0x29, - 0x57, 0x53, 0x53, 0x4e, 0x38, 0xdc, 0x6a, 0x8f, 0xad, 0xcd, 0x06, 0x6c, 0xf2, 0x76, 0x13, 0x32, - 0xe2, 0x3b, 0xf4, 0x43, 0x16, 0x8e, 0x0d, 0x3f, 0x75, 0xac, 0x1e, 0x3c, 0x99, 0xc3, 0xe3, 0x7f, - 0x47, 0xdf, 0x85, 0x0a, 0x6f, 0xbb, 0x7b, 0xf8, 0xd1, 0x4e, 0xbb, 0x1d, 0xd2, 0x48, 0xbd, 0xd9, - 0xe8, 0x19, 0xdc, 0xed, 0x93, 0x8e, 0xdb, 0x26, 0x31, 0x0b, 0x8f, 0x88, 0x38, 0xe3, 0x5d, 0x5e, - 0x6d, 0xde, 0x19, 0x1d, 0xc8, 0x1a, 0xf3, 0x39, 0x2c, 0xa7, 0x6c, 0x24, 0xeb, 0x2a, 0x2c, 0xd1, - 0xbe, 0x37, 0xe1, 0x00, 0xb4, 0xef, 0x49, 0x61, 0xfd, 0x37, 0x80, 0x9b, 0xbc, 0x18, 0x7d, 0x05, - 0x45, 0x11, 0x0b, 0xa8, 0x9a, 0x9a, 0x23, 0x9d, 0x3d, 0xfa, 0x7a, 0xbe, 0x48, 0xf4, 0x37, 0x2b, - 0xdf, 0xff, 0xf9, 0xef, 0x8f, 0xaf, 0xdc, 0x41, 0xb7, 0x54, 0xd4, 0x8a, 0xac, 0x41, 0xbf, 0x6b, - 0xb0, 0x32, 0x35, 0x28, 0xd0, 0xdb, 0xd9, 0xde, 0xb3, 0x82, 0x49, 0x7f, 0x67, 0xe1, 0x3a, 0x89, - 0xb9, 0xc5, 0x31, 0x1f, 0xa3, 0x47, 0x0a, 0x33, 0x91, 0x2e, 0x11, 0x0e, 0x45, 0x51, 0x84, 0xbf, - 0xe1, 0xef, 0xf1, 0x77, 0xe8, 0x17, 0x0d, 0x2a, 0xd9, 0x29, 0x82, 0xb6, 0xb3, 0x11, 0x72, 0x93, - 0x49, 0x7f, 0x73, 0xb1, 0x22, 0x09, 0xfd, 0x84, 0x43, 0x57, 0xd1, 0xc3, 0x4c, 0x68, 0x8e, 0x8a, - 0x3b, 0xdc, 0x02, 0x9d, 0x69, 0x60, 0xe4, 0xa7, 0x0e, 0x7a, 0x91, 0xc7, 0x30, 0x23, 0xef, 0xf4, - 0x97, 0xd7, 0x2b, 0x9e, 0x76, 0xfb, 0x22, 0xcf, 0xd4, 0xbd, 0x63, 0x9b, 0xd7, 0x8c, 0x6e, 0xff, - 0x27, 0x0d, 0xee, 0x65, 0xa6, 0x17, 0xaa, 0xe7, 0x61, 0x64, 0xe7, 0xa1, 0xbe, 0xbd, 0x50, 0x8d, - 0x24, 0x5e, 0xe1, 0xc4, 0x25, 0x74, 0x57, 0x11, 0xf7, 0x94, 0x10, 0xfd, 0xa1, 0xc1, 0x83, 0xbc, - 0x18, 0x41, 0xef, 0x66, 0x37, 0x9c, 0x23, 0xbe, 0xf4, 0xe7, 0xd7, 0x29, 0x95, 0xc8, 0x6f, 0x70, - 0xe4, 0x0d, 0xb4, 0xae, 0x90, 0x27, 0x32, 0x0c, 0x87, 0xc3, 0x3a, 0x2c, 0x02, 0x11, 0xfd, 0xac, - 0x41, 0x39, 0x2b, 0xbf, 0x51, 0x2d, 0xef, 0xba, 0x32, 0x7f, 0x0f, 0xf4, 0xfa, 0x22, 0x25, 0x92, - 0x76, 0x83, 0xd3, 0xae, 0x21, 0x63, 0x1a, 0xad, 0xfc, 0xc7, 0xfe, 0x16, 0xe0, 0x2a, 0xf5, 0xd0, - 0xe3, 0xec, 0x4e, 0xa9, 0x78, 0xd5, 0x37, 0x67, 0x0b, 0x25, 0xc8, 0x7d, 0x0e, 0x72, 0x0f, 0x95, - 0x14, 0x48, 0x22, 0x4e, 0x1b, 0xfb, 0xa7, 0x17, 0x86, 0x76, 0x7e, 0x61, 0x68, 0xff, 0x5c, 0x18, - 0xda, 0x0f, 0x97, 0x46, 0xe1, 0xfc, 0xd2, 0x28, 0xfc, 0x75, 0x69, 0x14, 0xbe, 0xc0, 0x8e, 0x1b, - 0x9f, 0xf4, 0x6c, 0xab, 0xc5, 0x3c, 0xac, 0x5a, 0xb1, 0xd0, 0x19, 0x3d, 0x6f, 0x91, 0x20, 0xc0, - 0x5f, 0x73, 0x4f, 0xfe, 0xf1, 0x69, 0x17, 0xf9, 0x67, 0xcf, 0xf6, 0x7f, 0x01, 0x00, 0x00, 0xff, - 0xff, 0x05, 0xfd, 0x5a, 0x43, 0xe9, 0x0a, 0x00, 0x00, + // 848 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x96, 0xcb, 0x4f, 0xeb, 0x46, + 0x14, 0xc6, 0xe3, 0x0a, 0x22, 0xf5, 0x20, 0xf1, 0x98, 0x84, 0x50, 0x0c, 0x35, 0xe0, 0xf0, 0x2c, + 0xc5, 0x23, 0x42, 0x1f, 0x2a, 0xd0, 0x05, 0x69, 0xa9, 0x40, 0xa2, 0xaf, 0x48, 0x65, 0xd1, 0x45, + 0xd1, 0x24, 0x19, 0x8c, 0xd5, 0xd8, 0x93, 0xd8, 0x4e, 0xd4, 0xa8, 0xed, 0xa6, 0x7f, 0x41, 0xa5, + 0x2e, 0xbb, 0xee, 0xb6, 0xab, 0xae, 0xda, 0x65, 0x37, 0x88, 0x15, 0x52, 0x37, 0x5d, 0x55, 0x15, + 0xdc, 0x3f, 0xe4, 0x2a, 0xe3, 0x99, 0xe0, 0xc4, 0x8e, 0x93, 0xa0, 0xbb, 0xf3, 0xcc, 0x9c, 0xef, + 0x3b, 0xbf, 0x33, 0xe0, 0x2f, 0x86, 0xa5, 0x0a, 0xad, 0x51, 0xcf, 0xb7, 0x08, 0x6e, 0x98, 0x65, + 0xdc, 0xda, 0xc7, 0x8d, 0x26, 0x75, 0xdb, 0x46, 0xdd, 0x65, 0x3e, 0x43, 0x33, 0xf2, 0xd0, 0x68, + 0x98, 0x65, 0xa3, 0xb5, 0xaf, 0xbe, 0xd9, 0x5f, 0x6d, 0x52, 0x87, 0x7a, 0x96, 0x17, 0xd4, 0xab, + 0x11, 0x33, 0xbf, 0x5d, 0xa7, 0xf2, 0x70, 0xd9, 0x64, 0xcc, 0xac, 0x51, 0x4c, 0xea, 0x16, 0x26, + 0x8e, 0xc3, 0x7c, 0xe2, 0x5b, 0xcc, 0x91, 0xa7, 0x59, 0x93, 0x99, 0x8c, 0x3f, 0xe2, 0xce, 0x93, + 0xd8, 0x5d, 0xac, 0x30, 0xcf, 0x66, 0xde, 0x55, 0x70, 0x10, 0x2c, 0xe4, 0x91, 0xb0, 0xe3, 0xab, + 0x72, 0xf3, 0x1a, 0x13, 0x47, 0x60, 0xeb, 0x59, 0x40, 0x5f, 0x76, 0xa6, 0xf8, 0x82, 0xb8, 0xc4, + 0xf6, 0x4a, 0xb4, 0xd1, 0xa4, 0x9e, 0xaf, 0x5f, 0x40, 0xa6, 0x67, 0xd7, 0xab, 0x33, 0xc7, 0xa3, + 0xe8, 0x5d, 0x48, 0xd7, 0xf9, 0xce, 0x1b, 0xca, 0xaa, 0xb2, 0x3d, 0x55, 0x58, 0x30, 0xfa, 0x86, + 0x36, 0x02, 0x41, 0x71, 0xe2, 0xf6, 0xbf, 0x95, 0x54, 0x49, 0x14, 0xeb, 0x1f, 0xc2, 0x06, 0x77, + 0x3b, 0xf1, 0x7d, 0xea, 0x05, 0xa3, 0x88, 0x46, 0xc5, 0xf6, 0x67, 0xcc, 0xa9, 0x50, 0xb1, 0x42, + 0x59, 0x98, 0x74, 0x3a, 0x6b, 0x6e, 0x3f, 0x51, 0x0a, 0x16, 0x7a, 0x1b, 0x36, 0x87, 0xc9, 0x05, + 0xdf, 0xe7, 0x30, 0x45, 0x9e, 0x8a, 0x04, 0x64, 0xd6, 0x08, 0xa6, 0x37, 0xe4, 0xf4, 0xc6, 0x89, + 0xd3, 0x2e, 0x2e, 0xdc, 0xfd, 0xb1, 0x97, 0x89, 0x3a, 0x9e, 0x97, 0xc2, 0x0e, 0xfa, 0x3a, 0xe8, + 0xbc, 0xf5, 0x05, 0xe9, 0xec, 0x85, 0xca, 0xc3, 0xd8, 0xfa, 0x11, 0xe4, 0x13, 0xab, 0x04, 0x5d, + 0xfc, 0x74, 0x45, 0x78, 0x2b, 0x24, 0xbe, 0x24, 0x35, 0x8f, 0xfa, 0x72, 0x3c, 0x7a, 0xcd, 0x5c, + 0x3a, 0xc2, 0x0d, 0x7d, 0x03, 0xbb, 0x23, 0x79, 0x08, 0x10, 0x0c, 0xe9, 0x16, 0xaf, 0x19, 0xf8, + 0x67, 0x14, 0x16, 0xa2, 0x4c, 0xcf, 0xc3, 0x5a, 0xc8, 0xff, 0x2b, 0xa7, 0xcc, 0x9c, 0xaa, 0xe5, + 0x98, 0x67, 0xd4, 0x32, 0x6f, 0x64, 0x23, 0xfd, 0xb8, 0xe7, 0xae, 0x22, 0x45, 0xa2, 0x77, 0x0e, + 0xd2, 0x37, 0x7c, 0x47, 0x4c, 0x20, 0x56, 0xba, 0x0e, 0xab, 0x21, 0xf5, 0xc7, 0xc4, 0x27, 0x1f, + 0x31, 0xdb, 0xb6, 0x7c, 0x9b, 0x3a, 0xdd, 0x0e, 0x76, 0x0f, 0x46, 0x7f, 0x8d, 0x68, 0x70, 0x06, + 0x33, 0x55, 0xe2, 0x93, 0xab, 0x4a, 0xf7, 0x48, 0x4c, 0xb9, 0x12, 0x99, 0xb2, 0xcf, 0x61, 0xba, + 0xda, 0xb3, 0xd6, 0x8b, 0xb0, 0xcd, 0xdb, 0xf5, 0x95, 0x11, 0xc7, 0xa4, 0x9f, 0x30, 0xb7, 0x67, + 0xf8, 0x81, 0x63, 0x35, 0x61, 0x67, 0x04, 0x8f, 0x57, 0x8e, 0x7e, 0x0a, 0x39, 0xde, 0xf6, 0xf4, + 0xf2, 0xd3, 0x93, 0x6a, 0xd5, 0xa5, 0x9e, 0x7c, 0xb3, 0xd1, 0x2e, 0xcc, 0xb5, 0x48, 0xcd, 0xaa, + 0x12, 0x9f, 0xb9, 0x57, 0x24, 0x38, 0xe3, 0x5d, 0x5e, 0x2f, 0xcd, 0x76, 0x0f, 0x84, 0x46, 0x3f, + 0x84, 0x85, 0x88, 0x8d, 0x60, 0x5d, 0x81, 0x29, 0xda, 0xb2, 0xfb, 0x1c, 0x80, 0xb6, 0x6c, 0x51, + 0x58, 0xf8, 0x13, 0x60, 0x92, 0x8b, 0xd1, 0xb7, 0x90, 0x0e, 0x62, 0x01, 0xe5, 0x23, 0x73, 0x44, + 0xb3, 0x47, 0x5d, 0x4f, 0x2e, 0x0a, 0xfa, 0xeb, 0xb9, 0x9f, 0xfe, 0x79, 0xf1, 0xcb, 0x6b, 0xb3, + 0x68, 0x5a, 0xc6, 0x67, 0x90, 0x35, 0xe8, 0x2f, 0x05, 0x16, 0x07, 0x06, 0x05, 0x7a, 0x2f, 0xde, + 0x7b, 0x58, 0x30, 0xa9, 0xef, 0x8f, 0xad, 0x13, 0x98, 0x7b, 0x1c, 0x73, 0x0b, 0x6d, 0x48, 0xcc, + 0x50, 0xba, 0x78, 0xd8, 0x0d, 0x44, 0x1e, 0xfe, 0x9e, 0xbf, 0xc7, 0x3f, 0xa2, 0xdf, 0x15, 0xc8, + 0xc5, 0xa7, 0x08, 0x3a, 0x88, 0x47, 0x48, 0x4c, 0x26, 0xf5, 0x9d, 0xf1, 0x44, 0x02, 0x7a, 0x87, + 0x43, 0xe7, 0xd1, 0x5a, 0x2c, 0x34, 0x47, 0xc5, 0x35, 0x6e, 0x81, 0xee, 0x14, 0xd0, 0x92, 0x53, + 0x07, 0x1d, 0x25, 0x31, 0x0c, 0xc9, 0x3b, 0xf5, 0xf8, 0x79, 0xe2, 0x41, 0xb7, 0x1f, 0xe4, 0x99, + 0xbc, 0x77, 0x5c, 0xe6, 0x9a, 0xee, 0xed, 0xff, 0xaa, 0xc0, 0x7c, 0x6c, 0x7a, 0xa1, 0x42, 0x12, + 0x46, 0x7c, 0x1e, 0xaa, 0x07, 0x63, 0x69, 0x04, 0xf1, 0x22, 0x27, 0xce, 0xa0, 0x39, 0x49, 0xdc, + 0x94, 0x85, 0xe8, 0x6f, 0x05, 0x96, 0x93, 0x62, 0x04, 0x7d, 0x10, 0xdf, 0x70, 0x84, 0xf8, 0x52, + 0x0f, 0x9f, 0x23, 0x15, 0xc8, 0x6f, 0x73, 0xe4, 0x4d, 0xb4, 0x2e, 0x91, 0xfb, 0x32, 0x0c, 0xbb, + 0x1d, 0x1d, 0x0e, 0x02, 0x11, 0xfd, 0xa6, 0x40, 0x36, 0x2e, 0xbf, 0xd1, 0x7e, 0xd2, 0x75, 0xc5, + 0xfe, 0x1e, 0xa8, 0x85, 0x71, 0x24, 0x82, 0x76, 0x93, 0xd3, 0xae, 0x22, 0x6d, 0x10, 0xad, 0xf8, + 0xc7, 0xfe, 0x01, 0xe0, 0x29, 0xf5, 0xd0, 0x56, 0x7c, 0xa7, 0x48, 0xbc, 0xaa, 0xdb, 0xc3, 0x0b, + 0x05, 0xc8, 0x12, 0x07, 0x99, 0x47, 0x19, 0x09, 0x12, 0x8a, 0xd3, 0xe2, 0xf9, 0xed, 0x83, 0xa6, + 0xdc, 0x3f, 0x68, 0xca, 0xff, 0x0f, 0x9a, 0xf2, 0xf3, 0xa3, 0x96, 0xba, 0x7f, 0xd4, 0x52, 0xff, + 0x3e, 0x6a, 0xa9, 0xaf, 0xb1, 0x69, 0xf9, 0x37, 0xcd, 0xb2, 0x51, 0x61, 0x36, 0x96, 0xad, 0x98, + 0x6b, 0x76, 0x9f, 0xf7, 0x48, 0xbd, 0x8e, 0xbf, 0xe3, 0x9e, 0xfc, 0x83, 0xb2, 0x9c, 0xe6, 0x9f, + 0x3d, 0x07, 0x2f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x58, 0x42, 0xec, 0x98, 0xbd, 0x0a, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/upgrade/keeper.go b/x/upgrade/keeper.go new file mode 100644 index 0000000000..2b8b15c81f --- /dev/null +++ b/x/upgrade/keeper.go @@ -0,0 +1,101 @@ +package upgrade + +import ( + fmt "fmt" + + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" + ibctypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" +) + +var _ ibctypes.UpgradeKeeper = (*Keeper)(nil) + +type Keeper struct { + // we use the same upgrade store key so existing IBC client state can + // safely be ported over without any migration + storeKey storetypes.StoreKey + + // in memory copy of the upgrade schedule if any. This is local per node + // and configured from the config. + upgradeSchedule map[string]Schedule + + // the app version that should be set in end blocker + pendingAppVersion uint64 +} + +type VersionSetter func(version uint64) + +// NewKeeper constructs an upgrade keeper +func NewKeeper(storeKey storetypes.StoreKey, upgradeSchedule map[string]Schedule) Keeper { + for chainID, schedule := range upgradeSchedule { + if err := schedule.ValidateBasic(); err != nil { + panic(fmt.Sprintf("invalid schedule %s: %v", chainID, err)) + } + } + return Keeper{ + storeKey: storeKey, + upgradeSchedule: upgradeSchedule, + } +} + +// ScheduleUpgrade implements the ibc upgrade keeper interface. This is a noop as +// no other process is allowed to schedule an upgrade but the upgrade keeper itself. +// This is kept around to support the interface. +func (k Keeper) ScheduleUpgrade(_ sdk.Context, _ types.Plan) error { + return nil +} + +// GetUpgradePlan implements the ibc upgrade keeper interface. This is used in BeginBlock +// to know when to write the upgraded consensus state. The IBC module needs to sign over +// the next consensus state to ensure a smooth transition for counterparty chains. This +// is implemented as a noop. Any IBC breaking change would be invoked by this upgrade module +// in end blocker. +func (k Keeper) GetUpgradePlan(_ sdk.Context) (plan types.Plan, havePlan bool) { + return types.Plan{}, false +} + +// SetUpgradedClient sets the expected upgraded client for the next version of this chain at the last height the current chain will commit. +func (k Keeper) SetUpgradedClient(ctx sdk.Context, planHeight int64, bz []byte) error { + store := ctx.KVStore(k.storeKey) + store.Set(types.UpgradedClientKey(planHeight), bz) + return nil +} + +// GetUpgradedClient gets the expected upgraded client for the next version of this chain +func (k Keeper) GetUpgradedClient(ctx sdk.Context, height int64) ([]byte, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.UpgradedClientKey(height)) + if len(bz) == 0 { + return nil, false + } + + return bz, true +} + +// SetUpgradedConsensusState set the expected upgraded consensus state for the next version of this chain +// using the last height committed on this chain. +func (k Keeper) SetUpgradedConsensusState(ctx sdk.Context, planHeight int64, bz []byte) error { + store := ctx.KVStore(k.storeKey) + store.Set(types.UpgradedConsStateKey(planHeight), bz) + return nil +} + +// GetUpgradedConsensusState get the expected upgraded consensus state for the next version of this chain +func (k Keeper) GetUpgradedConsensusState(ctx sdk.Context, lastHeight int64) ([]byte, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.UpgradedConsStateKey(lastHeight)) + if len(bz) == 0 { + return nil, false + } + + return bz, true +} + +// ClearIBCState clears any planned IBC state +func (k Keeper) ClearIBCState(ctx sdk.Context, lastHeight int64) { + // delete IBC client and consensus state from store if this is IBC plan + store := ctx.KVStore(k.storeKey) + store.Delete(types.UpgradedClientKey(lastHeight)) + store.Delete(types.UpgradedConsStateKey(lastHeight)) +} diff --git a/x/upgrade/test/integration_test.go b/x/upgrade/legacy_test.go similarity index 83% rename from x/upgrade/test/integration_test.go rename to x/upgrade/legacy_test.go index ddae14016d..dc17b4e890 100644 --- a/x/upgrade/test/integration_test.go +++ b/x/upgrade/legacy_test.go @@ -1,4 +1,4 @@ -package test +package upgrade_test import ( "context" @@ -8,6 +8,7 @@ import ( "github.com/celestiaorg/celestia-app/app" "github.com/celestiaorg/celestia-app/app/encoding" + testutil "github.com/celestiaorg/celestia-app/test/util" "github.com/celestiaorg/celestia-app/test/util/blobfactory" "github.com/celestiaorg/celestia-app/test/util/genesis" "github.com/celestiaorg/celestia-app/test/util/testnode" @@ -25,14 +26,24 @@ import ( tmrand "github.com/tendermint/tendermint/libs/rand" ) -func TestUpgrade(t *testing.T) { +func TestLegacyUpgrade(t *testing.T) { if testing.Short() { t.Skip("skipping x/upgrade SDK integration test in short mode.") } - suite.Run(t, new(UpgradeTestSuite)) + suite.Run(t, new(LegacyUpgradeTestSuite)) } -type UpgradeTestSuite struct { +// TestRemoval verifies that no handler exists for msg-based software upgrade +// proposals. +func TestRemoval(t *testing.T) { + app, _ := testutil.SetupTestAppWithGenesisValSet(app.DefaultConsensusParams()) + sftwrUpgrd := types.MsgSoftwareUpgrade{} + router := app.MsgServiceRouter() + handler := router.Handler(&sftwrUpgrd) + require.Nil(t, handler) +} + +type LegacyUpgradeTestSuite struct { suite.Suite accounts []string @@ -47,7 +58,7 @@ type UpgradeTestSuite struct { // SetupSuite inits a standard chain, with the only exception being a // dramatically lowered quorum and threshold to pass proposals -func (s *UpgradeTestSuite) SetupSuite() { +func (s *LegacyUpgradeTestSuite) SetupSuite() { t := s.T() s.ecfg = encoding.MakeConfig(app.ModuleBasics) @@ -86,7 +97,7 @@ func (s *UpgradeTestSuite) SetupSuite() { s.govModuleAddress = acc.GetAddress().String() } -func (s *UpgradeTestSuite) unusedAccount() string { +func (s *LegacyUpgradeTestSuite) unusedAccount() string { s.mut.Lock() acc := s.accounts[s.accountCounter] s.accountCounter++ @@ -96,7 +107,7 @@ func (s *UpgradeTestSuite) unusedAccount() string { // TestLegacyGovUpgradeFailure verifies that a transaction with a legacy // software upgrade proposal fails to execute. -func (s *UpgradeTestSuite) TestLegacyGovUpgradeFailure() { +func (s *LegacyUpgradeTestSuite) TestLegacyGovUpgradeFailure() { t := s.T() dep := sdk.NewCoins(sdk.NewCoin(app.BondDenom, sdk.NewInt(1000000000000))) @@ -119,13 +130,13 @@ func (s *UpgradeTestSuite) TestLegacyGovUpgradeFailure() { defer cancel() res, err := signer.SubmitTx(subCtx, []sdk.Msg{msg}, blobfactory.DefaultTxOpts()...) require.Error(t, err) - require.EqualValues(t, 9, res.Code, res.RawLog) // we're only submitting the tx, so we expect everything to work - assert.Contains(t, res.RawLog, "no handler exists for proposal type") + // As the type is not registered, the message will fail with unable to resolve type URL + require.EqualValues(t, 2, res.Code, res.RawLog) } // TestNewGovUpgradeFailure verifies that a transaction with a // MsgSoftwareUpgrade fails to execute. -func (s *UpgradeTestSuite) TestNewGovUpgradeFailure() { +func (s *LegacyUpgradeTestSuite) TestNewGovUpgradeFailure() { t := s.T() sss := types.MsgSoftwareUpgrade{ Authority: s.govModuleAddress, @@ -148,11 +159,11 @@ func (s *UpgradeTestSuite) TestNewGovUpgradeFailure() { defer cancel() res, err := signer.SubmitTx(subCtx, []sdk.Msg{msg}, blobfactory.DefaultTxOpts()...) require.Error(t, err) - require.EqualValues(t, 10, res.Code, res.RawLog) // we're only submitting the tx, so we expect everything to work - require.Contains(t, res.RawLog, "proposal message not recognized by router") + // As the type is not registered, the message will fail with unable to resolve type URL + require.EqualValues(t, 2, res.Code, res.RawLog) } -func (s *UpgradeTestSuite) TestIBCUpgradeFailure() { +func (s *LegacyUpgradeTestSuite) TestIBCUpgradeFailure() { t := s.T() plan := types.Plan{ Name: "v2", diff --git a/x/upgrade/module.go b/x/upgrade/module.go deleted file mode 100644 index 34eb187b54..0000000000 --- a/x/upgrade/module.go +++ /dev/null @@ -1,21 +0,0 @@ -package upgrade - -import ( - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" -) - -// TypeRegister is used to register the upgrade module's types in the encoding -// config without defining an entire module. -type TypeRegister struct{} - -// RegisterLegacyAminoCodec registers the upgrade types on the LegacyAmino codec. -func (TypeRegister) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - upgradetypes.RegisterLegacyAminoCodec(cdc) -} - -// RegisterInterfaces registers the upgrade module types. -func (TypeRegister) RegisterInterfaces(registry codectypes.InterfaceRegistry) { - upgradetypes.RegisterInterfaces(registry) -} diff --git a/x/upgrade/test/removal_test.go b/x/upgrade/test/removal_test.go deleted file mode 100644 index e7313277ea..0000000000 --- a/x/upgrade/test/removal_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package test - -import ( - "testing" - - "github.com/celestiaorg/celestia-app/app" - testutil "github.com/celestiaorg/celestia-app/test/util" - sdkupgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/stretchr/testify/require" -) - -// TestRemoval verifies that no handler exists for msg-based software upgrade -// proposals. -func TestRemoval(t *testing.T) { - app, _ := testutil.SetupTestAppWithGenesisValSet(app.DefaultConsensusParams()) - sftwrUpgrd := sdkupgradetypes.MsgSoftwareUpgrade{} - router := app.MsgServiceRouter() - handler := router.Handler(&sftwrUpgrd) - require.Nil(t, handler) -} diff --git a/x/upgrade/types.go b/x/upgrade/types.go new file mode 100644 index 0000000000..79fe78cfdb --- /dev/null +++ b/x/upgrade/types.go @@ -0,0 +1,138 @@ +package upgrade + +import ( + fmt "fmt" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" +) + +const ( + StoreKey = upgradetypes.StoreKey + ModuleName = upgradetypes.ModuleName +) + +var _ sdk.Msg = &MsgVersionChange{} + +// TypeRegister is used to register the upgrade module's types in the encoding +// config without defining an entire module. +type TypeRegister struct{} + +// RegisterLegacyAminoCodec registers the upgrade types on the LegacyAmino codec. +func (TypeRegister) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(upgradetypes.Plan{}, "cosmos-sdk/Plan", nil) + cdc.RegisterConcrete(MsgVersionChange{}, "celestia/MsgVersionChange", nil) +} + +// RegisterInterfaces registers the upgrade module types. +func (TypeRegister) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgVersionChange{}, + ) +} + +func (msg *MsgVersionChange) GetSigners() []sdk.AccAddress { + return nil +} + +func (msg *MsgVersionChange) ValidateBasic() error { + return nil +} + +// NewMsgVersionChange creates a tx in byte form used to signal to validators +// to change to a new version +func NewMsgVersionChange(txConfig client.TxConfig, version uint64) ([]byte, error) { + builder := txConfig.NewTxBuilder() + msg := &MsgVersionChange{ + Version: version, + } + if err := builder.SetMsgs(msg); err != nil { + return nil, err + } + return txConfig.TxEncoder()(builder.GetTx()) +} + +func IsUpgradeMsg(msg []sdk.Msg) (uint64, bool) { + if len(msg) != 1 { + return 0, false + } + msgVersionChange, ok := msg[0].(*MsgVersionChange) + if !ok { + return 0, false + } + return msgVersionChange.Version, true +} + +func (s Schedule) ValidateBasic() error { + lastHeight := 0 + lastVersion := uint64(0) + for idx, plan := range s { + if err := plan.ValidateBasic(); err != nil { + return fmt.Errorf("plan %d: %w", idx, err) + } + if plan.Start <= int64(lastHeight) { + return fmt.Errorf("plan %d: start height must be greater than %d, got %d", idx, lastHeight, plan.Start) + } + if plan.Version <= lastVersion { + return fmt.Errorf("plan %d: version must be greater than %d, got %d", idx, lastVersion, plan.Version) + } + lastHeight = int(plan.End) + lastVersion = plan.Version + } + return nil +} + +// ValidateVersions checks if all plan versions are covered by all the app versions +// that the state machine supports. +func (s Schedule) ValidateVersions(appVersions []uint64) error { + versionMap := make(map[uint64]struct{}) + for _, version := range appVersions { + versionMap[version] = struct{}{} + } + for _, plan := range s { + if _, ok := versionMap[plan.Version]; !ok { + return fmt.Errorf("plan version %d not found in app versions %v", plan.Version, appVersions) + } + } + return nil +} + +func (s Schedule) ShouldProposeUpgrade(height int64) (uint64, bool) { + for _, plan := range s { + if height >= plan.Start-1 && height < plan.End { + return plan.Version, true + } + } + return 0, false +} + +func (p Plan) ValidateBasic() error { + if p.Start < 1 { + return fmt.Errorf("plan start height cannot be negative or zero: %d", p.Start) + } + if p.End < 1 { + return fmt.Errorf("plan end height cannot be negative or zero: %d", p.End) + } + if p.Start > p.End { + return fmt.Errorf("plan end height must be greater or equal than start height: %d >= %d", p.Start, p.End) + } + if p.Version == 0 { + return fmt.Errorf("plan version cannot be zero") + } + return nil +} + +func NewSchedule(plans ...Plan) Schedule { + return plans +} + +func NewPlan(startHeight, endHeight int64, version uint64) Plan { + return Plan{ + Start: startHeight, + End: endHeight, + Version: version, + } +} diff --git a/x/upgrade/types.pb.go b/x/upgrade/types.pb.go new file mode 100644 index 0000000000..3e5eb9271e --- /dev/null +++ b/x/upgrade/types.pb.go @@ -0,0 +1,301 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: celestia/upgrade/v1/types.proto + +package upgrade + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgVersionChange is a message that signals an app version change +type MsgVersionChange struct { + // the app version this message proposes upgrading to + Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` +} + +func (m *MsgVersionChange) Reset() { *m = MsgVersionChange{} } +func (m *MsgVersionChange) String() string { return proto.CompactTextString(m) } +func (*MsgVersionChange) ProtoMessage() {} +func (*MsgVersionChange) Descriptor() ([]byte, []int) { + return fileDescriptor_0195354c266f07b3, []int{0} +} +func (m *MsgVersionChange) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgVersionChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgVersionChange.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgVersionChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgVersionChange.Merge(m, src) +} +func (m *MsgVersionChange) XXX_Size() int { + return m.Size() +} +func (m *MsgVersionChange) XXX_DiscardUnknown() { + xxx_messageInfo_MsgVersionChange.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgVersionChange proto.InternalMessageInfo + +func (m *MsgVersionChange) GetVersion() uint64 { + if m != nil { + return m.Version + } + return 0 +} + +func init() { + proto.RegisterType((*MsgVersionChange)(nil), "celestia.upgrade.v1.MsgVersionChange") +} + +func init() { proto.RegisterFile("celestia/upgrade/v1/types.proto", fileDescriptor_0195354c266f07b3) } + +var fileDescriptor_0195354c266f07b3 = []byte{ + // 164 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0x4e, 0xcd, 0x49, + 0x2d, 0x2e, 0xc9, 0x4c, 0xd4, 0x2f, 0x2d, 0x48, 0x2f, 0x4a, 0x4c, 0x49, 0xd5, 0x2f, 0x33, 0xd4, + 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x86, 0x29, 0xd0, + 0x83, 0x2a, 0xd0, 0x2b, 0x33, 0x54, 0xd2, 0xe1, 0x12, 0xf0, 0x2d, 0x4e, 0x0f, 0x4b, 0x2d, 0x2a, + 0xce, 0xcc, 0xcf, 0x73, 0xce, 0x48, 0xcc, 0x4b, 0x4f, 0x15, 0x92, 0xe0, 0x62, 0x2f, 0x83, 0x08, + 0x48, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x04, 0xc1, 0xb8, 0x4e, 0xee, 0x27, 0x1e, 0xc9, 0x31, 0x5e, + 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, + 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0xa5, 0x9b, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, + 0xab, 0x0f, 0xb3, 0x27, 0xbf, 0x28, 0x1d, 0xce, 0xd6, 0x4d, 0x2c, 0x28, 0xd0, 0xaf, 0x80, 0x39, + 0x2d, 0x89, 0x0d, 0xec, 0x24, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x04, 0x7a, 0xde, 0x74, + 0xb5, 0x00, 0x00, 0x00, +} + +func (m *MsgVersionChange) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgVersionChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgVersionChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgVersionChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Version != 0 { + n += 1 + sovTypes(uint64(m.Version)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgVersionChange) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgVersionChange: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgVersionChange: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/upgrade/types_test.go b/x/upgrade/types_test.go new file mode 100644 index 0000000000..aef2e8bb5e --- /dev/null +++ b/x/upgrade/types_test.go @@ -0,0 +1,69 @@ +package upgrade_test + +import ( + fmt "fmt" + "testing" + + "github.com/celestiaorg/celestia-app/x/upgrade" + "github.com/stretchr/testify/require" +) + +func TestScheduleValidity(t *testing.T) { + testCases := []struct { + schedule upgrade.Schedule + valid bool + }{ + // can be empty + {upgrade.Schedule{}, true}, + // plan can not start at height 0 + {upgrade.Schedule{upgrade.Plan{Start: 0, End: 2, Version: 1}}, false}, + // end height can not be 0 + {upgrade.Schedule{upgrade.Plan{Version: 1}}, false}, + {upgrade.Schedule{upgrade.Plan{Start: 1, End: 2, Version: 1}}, true}, + // version can't be 0 + {upgrade.Schedule{upgrade.Plan{Start: 1, End: 2, Version: 0}}, false}, + // start and end height can be the same + {upgrade.Schedule{upgrade.Plan{Start: 2, End: 2, Version: 1}}, true}, + // end height must be greater than start height + {upgrade.Schedule{upgrade.Plan{Start: 2, End: 1, Version: 1}}, false}, + // plans can not overlap + {upgrade.Schedule{upgrade.Plan{Start: 1, End: 2, Version: 1}, upgrade.Plan{Start: 2, End: 3, Version: 2}}, false}, + // plans must be in order. They can skip versions + {upgrade.Schedule{upgrade.Plan{Start: 1, End: 2, Version: 1}, upgrade.Plan{Start: 3, End: 4, Version: 2}, upgrade.Plan{Start: 5, End: 6, Version: 4}}, true}, + {upgrade.Schedule{upgrade.Plan{Start: 1, End: 2, Version: 1}, upgrade.Plan{Start: 3, End: 4, Version: 2}, upgrade.Plan{Start: 5, End: 10, Version: 1}}, false}, + } + + for idx, tc := range testCases { + t.Run(fmt.Sprintf("case%d", idx), func(t *testing.T) { + if tc.valid { + require.NoError(t, tc.schedule.ValidateBasic()) + } else { + require.Error(t, tc.schedule.ValidateBasic()) + } + }) + } +} + +func TestScheduleValidateVersions(t *testing.T) { + testCases := []struct { + schedule upgrade.Schedule + appVersions []uint64 + valid bool + }{ + // can be empty + {upgrade.Schedule{}, []uint64{1, 2, 3}, true}, + {upgrade.Schedule{upgrade.Plan{Version: 3}}, []uint64{1, 2, 3}, true}, + {upgrade.Schedule{upgrade.Plan{Version: 4}}, []uint64{1, 2, 3}, false}, + {upgrade.Schedule{upgrade.Plan{Version: 2}, upgrade.Plan{Version: 5}}, []uint64{1, 2, 3}, false}, + } + + for idx, tc := range testCases { + t.Run(fmt.Sprintf("case%d", idx), func(t *testing.T) { + if tc.valid { + require.NoError(t, tc.schedule.ValidateVersions(tc.appVersions)) + } else { + require.Error(t, tc.schedule.ValidateVersions(tc.appVersions)) + } + }) + } +} diff --git a/x/upgrade/upgrade.go b/x/upgrade/upgrade.go new file mode 100644 index 0000000000..aedf46aa91 --- /dev/null +++ b/x/upgrade/upgrade.go @@ -0,0 +1,40 @@ +package upgrade + +type Schedule []Plan + +type Plan struct { + Start int64 + End int64 + Version uint64 +} + +// ShouldUpgradeNextHeight returns true if the network of the given chainID should +// modify the app version in the following block. This can be used for both upgrading +// and downgrading. This relies on social consensus to work. At least 2/3+ of the +// validators must have the same app version and height in their schedule for the +// upgrade to happen successfully. +func (k Keeper) ShouldProposeUpgrade(chainID string, height int64) (uint64, bool) { + if k.upgradeSchedule == nil { + return 0, false + } + if schedule, ok := k.upgradeSchedule[chainID]; ok { + return schedule.ShouldProposeUpgrade(height) + } + return 0, false +} + +func (k *Keeper) PrepareUpgradeAtEndBlock(version uint64) { + k.pendingAppVersion = version +} + +func (k *Keeper) ShouldUpgrade() bool { + return k.pendingAppVersion != 0 +} + +func (k Keeper) GetNextAppVersion() uint64 { + return k.pendingAppVersion +} + +func (k *Keeper) MarkUpgradeComplete() { + k.pendingAppVersion = 0 +} diff --git a/x/upgrade/upgrade_test.go b/x/upgrade/upgrade_test.go new file mode 100644 index 0000000000..2921d472e5 --- /dev/null +++ b/x/upgrade/upgrade_test.go @@ -0,0 +1,230 @@ +package upgrade_test + +import ( + "encoding/json" + "testing" + "time" + + "github.com/celestiaorg/celestia-app/app" + "github.com/celestiaorg/celestia-app/app/encoding" + "github.com/celestiaorg/celestia-app/pkg/appconsts" + "github.com/celestiaorg/celestia-app/pkg/da" + "github.com/celestiaorg/celestia-app/pkg/shares" + "github.com/celestiaorg/celestia-app/pkg/square" + "github.com/celestiaorg/celestia-app/pkg/user" + "github.com/celestiaorg/celestia-app/test/util" + "github.com/celestiaorg/celestia-app/test/util/testfactory" + "github.com/celestiaorg/celestia-app/x/upgrade" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/types" + bank "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" +) + +func TestUpgradeAppVersion(t *testing.T) { + testApp, kr := setupTestApp(t, upgrade.NewSchedule(upgrade.NewPlan(3, 5, 2))) + addr := testfactory.GetAddress(kr, "account") + encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) + signer, err := user.NewSigner(kr, nil, addr, encCfg.TxConfig, testApp.GetChainID(), 1, 0) + require.NoError(t, err) + coins := types.NewCoins(types.NewCoin("utia", types.NewInt(10))) + sendMsg := bank.NewMsgSend(addr, addr, coins) + sendTx, err := signer.CreateTx([]types.Msg{sendMsg}, user.SetGasLimitAndFee(1e6, 1)) + require.NoError(t, err) + + upgradeTx, err := upgrade.NewMsgVersionChange(testApp.GetTxConfig(), 3) + require.NoError(t, err) + respCheckTx := testApp.CheckTx(abci.RequestCheckTx{Tx: upgradeTx}) + // we expect that a new msg version change should always be rejected + // by checkTx + require.EqualValues(t, 15, respCheckTx.Code, respCheckTx.Log) + + resp := testApp.PrepareProposal(abci.RequestPrepareProposal{ + Height: 2, + ChainId: testApp.GetChainID(), + BlockData: &tmproto.Data{}, + BlockDataSize: 1e6, + }) + + // At the height before the first height in the upgrade plan, the + // node should prepend a signal upgrade message. + require.Len(t, resp.BlockData.Txs, 1) + tx, err := testApp.GetTxConfig().TxDecoder()(resp.BlockData.Txs[0]) + require.NoError(t, err) + require.Len(t, tx.GetMsgs(), 1) + msg, ok := tx.GetMsgs()[0].(*upgrade.MsgVersionChange) + require.True(t, ok) + require.EqualValues(t, 2, msg.Version) + + { + // the same thing should happen if we run prepare proposal + // at height 4 as it is within the range + resp := testApp.PrepareProposal(abci.RequestPrepareProposal{ + Height: 4, + ChainId: testApp.GetChainID(), + BlockData: &tmproto.Data{}, + BlockDataSize: 1e6, + }) + + require.Len(t, resp.BlockData.Txs, 1) + tx, err := testApp.GetTxConfig().TxDecoder()(resp.BlockData.Txs[0]) + require.NoError(t, err) + require.Len(t, tx.GetMsgs(), 1) + msg, ok := tx.GetMsgs()[0].(*upgrade.MsgVersionChange) + require.True(t, ok) + require.EqualValues(t, 2, msg.Version) + } + + { + // we send the same proposal but now with an existing message and a + // smaller BlockDataSize. It should kick out the tx in place of the + // upgrade tx + resp := testApp.PrepareProposal(abci.RequestPrepareProposal{ + Height: 2, + ChainId: testApp.GetChainID(), + BlockData: &tmproto.Data{Txs: [][]byte{sendTx}}, + BlockDataSize: 1e2, + }) + require.Len(t, resp.BlockData.Txs, 1) + tx, err := testApp.GetTxConfig().TxDecoder()(resp.BlockData.Txs[0]) + require.NoError(t, err) + require.Len(t, tx.GetMsgs(), 1) + msg, ok := tx.GetMsgs()[0].(*upgrade.MsgVersionChange) + require.True(t, ok) + require.EqualValues(t, 2, msg.Version) + } + + { + // Height 5 however is outside the range and thus the upgrade + // message should not be prepended + resp := testApp.PrepareProposal(abci.RequestPrepareProposal{ + Height: 5, + ChainId: testApp.GetChainID(), + BlockData: &tmproto.Data{}, + BlockDataSize: 1e6, + }) + require.Len(t, resp.BlockData.Txs, 0) + } + + // We should accept this proposal as valid + processProposalResp := testApp.ProcessProposal(abci.RequestProcessProposal{ + Header: tmproto.Header{ + Height: 2, + DataHash: resp.BlockData.Hash, + }, + BlockData: resp.BlockData, + }) + require.True(t, processProposalResp.IsOK()) + + { + // to assert that the upgrade tx must be the first tx + // we insert a tx before the upgrade tx. To get the hash + // we need to build the square and data availability header + txs := [][]byte{[]byte("hello world"), upgradeTx} + dataSquare, txs, err := square.Build(txs, appconsts.LatestVersion, appconsts.DefaultGovMaxSquareSize) + require.NoError(t, err) + eds, err := da.ExtendShares(shares.ToBytes(dataSquare)) + require.NoError(t, err) + dah, err := da.NewDataAvailabilityHeader(eds) + require.NoError(t, err) + blockData := &tmproto.Data{ + Txs: txs, + SquareSize: uint64(dataSquare.Size()), + Hash: dah.Hash(), + } + + processProposalResp := testApp.ProcessProposal(abci.RequestProcessProposal{ + Header: tmproto.Header{ + Height: 2, + DataHash: blockData.Hash, + }, + BlockData: blockData, + }) + require.True(t, processProposalResp.IsRejected()) + } + + testApp.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 2}}) + respDeliverTx := testApp.DeliverTx(abci.RequestDeliverTx{Tx: resp.BlockData.Txs[0]}) + require.EqualValues(t, 0, respDeliverTx.Code, respDeliverTx.Log) + // app version should not have changed yet + require.EqualValues(t, 1, testApp.AppVersion()) + respEndBlock := testApp.EndBlock(abci.RequestEndBlock{Height: 2}) + // now the app version changes + require.EqualValues(t, 2, respEndBlock.ConsensusParamUpdates.Version.AppVersion) + require.EqualValues(t, 2, testApp.AppVersion()) + + _ = testApp.Commit() + + // If another node proposes a block with a version change that is + // not supported by the nodes own state machine then the node + // rejects the proposed block + respProcessProposal := testApp.ProcessProposal(abci.RequestProcessProposal{ + Header: tmproto.Header{ + Height: 3, + }, + BlockData: &tmproto.Data{ + Txs: [][]byte{upgradeTx}, + }, + }) + require.True(t, respProcessProposal.IsRejected()) + + // if we ask the application to prepare another proposal + // it will not add the upgrade signal message even though + // its within the range of the plan because the application + // has already upgraded to that height + respPrepareProposal := testApp.PrepareProposal(abci.RequestPrepareProposal{ + Height: 3, + ChainId: testApp.GetChainID(), + BlockData: &tmproto.Data{}, + BlockDataSize: 1e6, + }) + require.Len(t, respPrepareProposal.BlockData.Txs, 0) +} + +func setupTestApp(t *testing.T, schedule upgrade.Schedule) (*app.App, keyring.Keyring) { + t.Helper() + + db := dbm.NewMemDB() + chainID := "test_chain" + encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) + upgradeSchedule := make(map[string]upgrade.Schedule) + upgradeSchedule[chainID] = schedule + testApp := app.New(log.NewNopLogger(), db, nil, true, 0, encCfg, upgradeSchedule, util.EmptyAppOptions{}) + + genesisState, _, kr := util.GenesisStateWithSingleValidator(testApp, "account") + + stateBytes, err := json.MarshalIndent(genesisState, "", " ") + require.NoError(t, err) + require.EqualValues(t, 0, testApp.GetBaseApp().AppVersion()) + + cp := app.DefaultConsensusParams() + abciParams := &abci.ConsensusParams{ + Block: &abci.BlockParams{ + MaxBytes: cp.Block.MaxBytes, + MaxGas: cp.Block.MaxGas, + }, + Evidence: &cp.Evidence, + Validator: &cp.Validator, + Version: &cp.Version, + } + + _ = testApp.InitChain( + abci.RequestInitChain{ + Time: time.Now(), + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: abciParams, + AppStateBytes: stateBytes, + ChainId: chainID, + }, + ) + + // assert that the chain starts with version provided in genesis + require.EqualValues(t, app.DefaultConsensusParams().Version.AppVersion, testApp.GetBaseApp().AppVersion()) + + _ = testApp.Commit() + return testApp, kr +}