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

feat!: add a signalling mechanism for coordinated upgrades #2832

Merged
merged 39 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
65b954c
test: add minor version upgrade testing
cmwaters Oct 31, 2023
2477ef4
require version to be set
cmwaters Oct 31, 2023
1c7ad45
remove print statement
cmwaters Oct 31, 2023
f446568
use an upgrade flag for v2
cmwaters Nov 1, 2023
4ac4bdb
incorporate suggestions
cmwaters Nov 1, 2023
93a42f9
Simplify IsGreater
cmwaters Nov 2, 2023
f36db3a
add assertions that the network progresses
cmwaters Nov 6, 2023
4285736
Merge branch 'cal/minor-upgrade-testing' of github.com:celestiaorg/ce…
cmwaters Nov 6, 2023
c13fa61
Merge branch 'main' into cal/minor-upgrade-testing
cmwaters Nov 6, 2023
e14038e
Merge branch 'cal/minor-upgrade-testing' into cal/configured-upgrades
cmwaters Nov 6, 2023
a4eb85d
Apply suggestions from code review
cmwaters Nov 6, 2023
59c3b5d
fix parsing e2e_version env
cmwaters Nov 6, 2023
cfcfa5c
set global knuu timeout
cmwaters Nov 6, 2023
215a562
Merge branch 'main' into cal/minor-upgrade-testing
cmwaters Nov 6, 2023
4aa82ea
Update test/e2e/versions_test.go
cmwaters Nov 6, 2023
ebe2022
Merge branch 'main' into cal/minor-upgrade-testing
cmwaters Nov 6, 2023
4d14422
Merge branch 'cal/minor-upgrade-testing' into cal/configured-upgrades
cmwaters Nov 6, 2023
9e2ebab
add go doc to upgrade
cmwaters Nov 6, 2023
eae9549
Merge branch 'main' into cal/minor-upgrade-testing
cmwaters Nov 8, 2023
2856aaf
Merge branch 'cal/minor-upgrade-testing' into cal/configured-upgrades
cmwaters Nov 8, 2023
e36e241
define upgrade protos
cmwaters Nov 9, 2023
1365421
write out a large chunk of the logic
cmwaters Nov 9, 2023
f4e5489
resolve conflicts
cmwaters Nov 20, 2023
261ea06
Merge branch 'main' into cal/upgrade-module
cmwaters Nov 20, 2023
1b4c693
Merge branch 'main' into cal/upgrade-module
cmwaters Nov 27, 2023
1853460
use sdk.Dec instead of uint32. Write tests
cmwaters Nov 28, 2023
c81743a
wrap up unit tests
cmwaters Nov 28, 2023
4674c0f
Update x/upgrade/types/params.go
cmwaters Nov 28, 2023
0580b1b
Update proto/celestia/upgrade/v1/tx.proto
cmwaters Nov 28, 2023
9de3714
Update x/upgrade/types/params.go
cmwaters Nov 28, 2023
823c1ea
implement suggestions
cmwaters Nov 28, 2023
3d6160d
lint and rebuild protos
cmwaters Nov 28, 2023
6418b64
chore: make proto-gen
rootulp Nov 28, 2023
6156f3e
remove params and fix the threshold calculation
cmwaters Nov 29, 2023
5184c9a
Merge branch 'cal/upgrade-module' of github.com:celestiaorg/celestia-…
cmwaters Nov 29, 2023
b9349a1
Merge branch 'main' into cal/upgrade-module
cmwaters Nov 29, 2023
41f80b1
update the codec with the query server
cmwaters Nov 29, 2023
3ad204d
Merge branch 'cal/upgrade-module' of github.com:celestiaorg/celestia-…
cmwaters Nov 29, 2023
6274c98
revert the last commit
cmwaters Nov 29, 2023
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
31 changes: 21 additions & 10 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
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"
upgradetypes "github.com/celestiaorg/celestia-app/x/upgrade/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node"
Expand Down Expand Up @@ -85,6 +86,7 @@ import (
"github.com/celestiaorg/celestia-app/app/ante"
"github.com/celestiaorg/celestia-app/app/encoding"
"github.com/celestiaorg/celestia-app/pkg/appconsts"
v1 "github.com/celestiaorg/celestia-app/pkg/appconsts/v1"
v2 "github.com/celestiaorg/celestia-app/pkg/appconsts/v2"
"github.com/celestiaorg/celestia-app/pkg/proof"
blobmodule "github.com/celestiaorg/celestia-app/x/blob"
Expand Down Expand Up @@ -155,11 +157,12 @@ var (
vesting.AppModuleBasic{},
blobmodule.AppModuleBasic{},
bsmodule.AppModuleBasic{},
upgrade.AppModuleBasic{},
)

// ModuleEncodingRegisters keeps track of all the module methods needed to
// register interfaces and specific type to encoding config
ModuleEncodingRegisters = extractRegisters(ModuleBasics, upgrade.TypeRegister{})
ModuleEncodingRegisters = extractRegisters(ModuleBasics)

// module account permissions
maccPerms = map[string][]string{
Expand Down Expand Up @@ -267,7 +270,7 @@ func New(
keys := sdk.NewKVStoreKeys(
authtypes.StoreKey, authzkeeper.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey,
govtypes.StoreKey, paramstypes.StoreKey, upgrade.StoreKey, feegrant.StoreKey,
govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey,
evidencetypes.StoreKey, capabilitytypes.StoreKey,
blobmoduletypes.StoreKey,
bsmoduletypes.StoreKey,
Expand Down Expand Up @@ -333,7 +336,7 @@ func New(
)

app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], app.AccountKeeper)
app.UpgradeKeeper = upgrade.NewKeeper(keys[upgrade.StoreKey], upgradeHeight)
app.UpgradeKeeper = upgrade.NewKeeper(keys[upgradetypes.StoreKey], upgradeHeight, app.StakingKeeper)

app.BlobstreamKeeper = *bsmodulekeeper.NewKeeper(
appCodec,
Expand Down Expand Up @@ -442,6 +445,7 @@ func New(
transferModule,
blobmod,
bsmod,
upgrade.NewAppModule(app.UpgradeKeeper),
)

// During begin block slashing happens after distr.BeginBlocker so that
Expand All @@ -468,7 +472,7 @@ func New(
paramstypes.ModuleName,
authz.ModuleName,
vestingtypes.ModuleName,
upgrade.ModuleName,
upgradetypes.ModuleName,
)

app.mm.SetOrderEndBlockers(
Expand All @@ -491,7 +495,7 @@ func New(
paramstypes.ModuleName,
authz.ModuleName,
vestingtypes.ModuleName,
upgrade.ModuleName,
upgradetypes.ModuleName,
)

// NOTE: The genutils module must occur after staking so that pools are
Expand Down Expand Up @@ -519,7 +523,7 @@ func New(
feegrant.ModuleName,
paramstypes.ModuleName,
authz.ModuleName,
upgrade.ModuleName,
upgradetypes.ModuleName,
)

app.QueryRouter().AddRoute(proof.TxInclusionQueryPath, proof.QueryTxInclusionProof)
Expand Down Expand Up @@ -573,10 +577,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 {
res := app.mm.EndBlock(ctx, req)
// NOTE: this is a specific feature for upgrading to v2 as v3 and onward is expected
// to be coordinated through the signalling protocol
if app.UpgradeKeeper.ShouldUpgrade(req.Height) {
app.SetAppVersion(ctx, v2.Version)
// NOTE: this is a specific feature for upgrading from v1 to v2. It will be deprecated in v3
if app.UpgradeKeeper.ShouldUpgradeToV2(req.Height) {
if app.AppVersion(ctx) == v1.Version {
app.SetAppVersion(ctx, v2.Version)
}
// from v2 to v3 and onwards we use a signalling mechanism
} else if shouldUpgrade, version := app.UpgradeKeeper.ShouldUpgrade(); shouldUpgrade {
// Version changes must be increasing. Downgrades are not permitted
if version > app.AppVersion(ctx) {
app.SetAppVersion(ctx, version)
}
}
return res
}
Expand Down
35 changes: 24 additions & 11 deletions app/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/celestiaorg/celestia-app/x/blob"
"github.com/celestiaorg/celestia-app/x/blobstream"
"github.com/celestiaorg/celestia-app/x/mint"
"github.com/celestiaorg/celestia-app/x/upgrade"
upgradetypes "github.com/celestiaorg/celestia-app/x/upgrade/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
Expand All @@ -31,6 +33,15 @@ var (
// versions that the current state machine supports
supportedVersions = []uint64{v1.Version, v2.Version}

v1moduleVersionMap = make(module.VersionMap)
v2moduleVersionMap = make(module.VersionMap)
)

const DefaultInitialVersion = v1.Version

// this is used as a compile time consistency check across different module
// based maps
func init() {
v1moduleVersionMap = module.VersionMap{
"bank": bank.AppModule{}.ConsensusVersion(),
"auth": auth.AppModule{}.ConsensusVersion(),
Expand All @@ -53,23 +64,25 @@ var (
"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
// v2 has all the same modules as v1 with the addition of an upgrade module
v2moduleVersionMap = make(module.VersionMap)
for k, v := range v1moduleVersionMap {
v2moduleVersionMap[k] = v
}
v2moduleVersionMap[upgradetypes.ModuleName] = upgrade.AppModule{}.ConsensusVersion()

// this is used as a compile time consistency check across different module
// based maps
func init() {
for moduleName := range ModuleBasics {
isSupported := false
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))
if _, ok := versionMap[moduleName]; ok {
isSupported = true
break
}
}
if !isSupported {
panic(fmt.Sprintf("inconsistency: module %s not found in any version", moduleName))
}
}
}

Expand Down
28 changes: 28 additions & 0 deletions proto/celestia/upgrade/v1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
syntax = "proto3";
package celestia.upgrade.v1;

import "google/api/annotations.proto";

option go_package = "github.com/celestiaorg/celestia-app/x/upgrade/types";

// Query defines the upgrade Query service.
service Query {
// VersionTally allows the querying of the tally of voting power by all
// validators that have signalled for each version
rpc VersionTally(QueryVersionTallyRequest)
returns (QueryVersionTallyResponse) {
option (google.api.http).get = "/upgrade/v1/tally/{version}";
}
}

// QueryVersionTallyRequest is the request type for the UpgradeStatus RPC
// method.
message QueryVersionTallyRequest { uint64 version = 1; }

// QueryVersionTallyResponse is the response type for the UpgradeStatus RPC
// method.
message QueryVersionTallyResponse {
uint64 voting_power = 1;
uint64 threshold_power = 2;
uint64 total_voting_power = 3;
}
24 changes: 24 additions & 0 deletions proto/celestia/upgrade/v1/tx.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
syntax = "proto3";
package celestia.upgrade.v1;

import "google/api/annotations.proto";

option go_package = "github.com/celestiaorg/celestia-app/x/upgrade/types";

// Msg defines the upgrade Msg service.
service Msg {
// SignalVersion allows the validator to signal for an upgrade
rpc SignalVersion(MsgSignalVersion) returns (MsgSignalVersionResponse) {
option (google.api.http).post = "/upgrade/v1/signal";
}
}

// MsgSignalVersion signals for an upgrade
message MsgSignalVersion {
string validator_address = 1;
uint64 version = 2;
}

// MsgSignalVersionResponse describes the response returned after the submission
// of a SignalVersion
message MsgSignalVersionResponse {}
10 changes: 0 additions & 10 deletions proto/celestia/upgrade/v1/types.proto

This file was deleted.

72 changes: 72 additions & 0 deletions x/upgrade/ibc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package upgrade

import (
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"
)

// We need compatibility with the way that IBC uses the upgrade module. This file
// ensures that we comply to the interface that IBC expects
var _ ibctypes.UpgradeKeeper = (*Keeper)(nil)

// 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))
}
13 changes: 13 additions & 0 deletions x/upgrade/interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package upgrade

import (
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

type StakingKeeper interface {
GetLastValidatorPower(ctx sdk.Context, addr sdk.ValAddress) int64
GetLastTotalPower(ctx sdk.Context) math.Int
GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, found bool)
cmwaters marked this conversation as resolved.
Show resolved Hide resolved
}
Loading
Loading