diff --git a/app/consumer-democracy/app.go b/app/consumer-democracy/app.go index f3ac4b024b..93066e87b3 100644 --- a/app/consumer-democracy/app.go +++ b/app/consumer-democracy/app.go @@ -8,6 +8,14 @@ import ( "os" "path/filepath" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + paramsrest "github.com/cosmos/cosmos-sdk/x/params/client/rest" + upgraderest "github.com/cosmos/cosmos-sdk/x/upgrade/client/rest" + adminmodulemodule "github.com/cosmos/interchain-security/x/ccv/adminmodule" + adminmodulecli "github.com/cosmos/interchain-security/x/ccv/adminmodule/client/cli" + adminmodulemodulekeeper "github.com/cosmos/interchain-security/x/ccv/adminmodule/keeper" + adminmodulemoduletypes "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" @@ -61,6 +69,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/upgrade" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" + icahost "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" + icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" "github.com/cosmos/ibc-go/v3/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" @@ -82,6 +95,7 @@ import ( distr "github.com/cosmos/cosmos-sdk/x/distribution" ccvdistrclient "github.com/cosmos/cosmos-sdk/x/distribution/client" + distrrest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest" ccvdistrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" ccvdistrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/interchain-security/testutil/e2e" @@ -147,6 +161,25 @@ var ( vesting.AppModuleBasic{}, //router.AppModuleBasic{}, ibcconsumer.AppModuleBasic{}, + ica.AppModuleBasic{}, + adminmodulemodule.NewAppModuleBasic( + govclient.NewProposalHandler( + adminmodulecli.NewSubmitParamChangeProposalTxCmd, + paramsrest.ProposalRESTHandler, + ), + govclient.NewProposalHandler( + adminmodulecli.NewSubmitPoolSpendProposalTxCmd, + distrrest.ProposalRESTHandler, + ), + govclient.NewProposalHandler( + adminmodulecli.NewCmdSubmitUpgradeProposal, + upgraderest.ProposalRESTHandler, + ), + govclient.NewProposalHandler( + adminmodulecli.NewCmdSubmitCancelUpgradeProposal, + upgraderest.ProposalCancelRESTHandler, + ), + ), ) // module account permissions @@ -158,6 +191,7 @@ var ( ccvminttypes.ModuleName: {authtypes.Minter}, ibcconsumertypes.ConsumerRedistributeName: nil, ibcconsumertypes.ConsumerToSendToProviderName: nil, + icatypes.ModuleName: nil, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, ccvgovtypes.ModuleName: {authtypes.Burner}, } @@ -187,28 +221,31 @@ type App struct { // nolint: golint memKeys map[string]*sdk.MemoryStoreKey // keepers - AccountKeeper authkeeper.AccountKeeper - BankKeeper bankkeeper.Keeper - CapabilityKeeper *capabilitykeeper.Keeper - StakingKeeper ccvstakingkeeper.Keeper - SlashingKeeper slashingkeeper.Keeper - MintKeeper ccvmintkeeper.Keeper - DistrKeeper ccvdistrkeeper.Keeper - GovKeeper ccvgovkeeper.Keeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.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 - TransferKeeper ibctransferkeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper - AuthzKeeper authzkeeper.Keeper - ConsumerKeeper ibcconsumerkeeper.Keeper + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + CapabilityKeeper *capabilitykeeper.Keeper + StakingKeeper ccvstakingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper + MintKeeper ccvmintkeeper.Keeper + DistrKeeper ccvdistrkeeper.Keeper + GovKeeper ccvgovkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.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 + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + AuthzKeeper authzkeeper.Keeper + ConsumerKeeper ibcconsumerkeeper.Keeper + ICAHostKeeper icahostkeeper.Keeper + AdminmoduleKeeper adminmodulemodulekeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper ScopedTransferKeeper capabilitykeeper.ScopedKeeper ScopedIBCConsumerKeeper capabilitykeeper.ScopedKeeper + ScopedICAHostKeeper capabilitykeeper.ScopedKeeper // the module manager MM *module.Manager @@ -256,7 +293,8 @@ func New( ccvgovtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, authzkeeper.StoreKey, - ibcconsumertypes.StoreKey, + ibcconsumertypes.StoreKey, icahosttypes.StoreKey, + adminmodulemoduletypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -294,6 +332,7 @@ func New( scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) scopedIBCConsumerKeeper := app.CapabilityKeeper.ScopeToModule(ibcconsumertypes.ModuleName) + scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) app.CapabilityKeeper.Seal() // add keepers @@ -452,10 +491,25 @@ func New( transferModule := transfer.NewAppModule(app.TransferKeeper) ibcmodule := transfer.NewIBCModule(app.TransferKeeper) + app.ICAHostKeeper = icahostkeeper.NewKeeper( + appCodec, + keys[icahosttypes.StoreKey], + app.GetSubspace(icahosttypes.SubModuleName), + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, + app.AccountKeeper, + scopedICAHostKeeper, + app.MsgServiceRouter(), + ) + + icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) + icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) + // create static IBC router, add transfer route, then set and seal it ibcRouter := porttypes.NewRouter() ibcRouter.AddRoute(ibctransfertypes.ModuleName, ibcmodule) ibcRouter.AddRoute(ibcconsumertypes.ModuleName, consumerModule) + ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) app.IBCKeeper.SetRouter(ibcRouter) // create evidence keeper with router @@ -468,6 +522,25 @@ func New( app.EvidenceKeeper = *evidenceKeeper + adminRouter := ccvgovtypes.NewRouter() + adminRouter.AddRoute(ccvgovtypes.RouterKey, ccvgovtypes.ProposalHandler). + AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). + AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)). + AddRoute(ccvdistrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)) + + app.AdminmoduleKeeper = *adminmodulemodulekeeper.NewKeeper( + appCodec, + keys[adminmodulemoduletypes.StoreKey], + keys[adminmodulemoduletypes.MemStoreKey], + adminRouter, + // this allows any type of proposal to be submitted to the admin module (everything is whitelisted) + // projects will implement their functions to define what is allowed for provider and consumer admins. + // Implementation example can be found in app/consumer-democracy/proposals_whitelisting.go + func(ccvgovtypes.Content) bool { return true }, + func(ccvgovtypes.Content) bool { return true }, + ) + adminModule := adminmodulemodule.NewAppModule(appCodec, app.AdminmoduleKeeper, app.ICAHostKeeper, app.ConsumerKeeper) + skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) // NOTE: Any module instantiated in the module manager that is later modified @@ -491,6 +564,8 @@ func New( ibc.NewAppModule(app.IBCKeeper), transferModule, consumerModule, + icaModule, + adminModule, ) // During begin block slashing happens after distr.BeginBlocker so that @@ -517,7 +592,9 @@ func New( vestingtypes.ModuleName, ibctransfertypes.ModuleName, ibchost.ModuleName, + icatypes.ModuleName, ibcconsumertypes.ModuleName, + adminmodulemoduletypes.ModuleName, ) app.MM.SetOrderEndBlockers( crisistypes.ModuleName, @@ -537,7 +614,9 @@ func New( vestingtypes.ModuleName, ibctransfertypes.ModuleName, ibchost.ModuleName, + icatypes.ModuleName, ibcconsumertypes.ModuleName, + adminmodulemoduletypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -563,8 +642,10 @@ func New( upgradetypes.ModuleName, vestingtypes.ModuleName, ibchost.ModuleName, + icatypes.ModuleName, ibctransfertypes.ModuleName, ibcconsumertypes.ModuleName, + adminmodulemoduletypes.ModuleName, ) app.MM.RegisterInvariants(&app.CrisisKeeper) @@ -660,6 +741,7 @@ func New( app.ScopedIBCKeeper = scopedIBCKeeper app.ScopedTransferKeeper = scopedTransferKeeper app.ScopedIBCConsumerKeeper = scopedIBCConsumerKeeper + app.ScopedICAHostKeeper = scopedICAHostKeeper return app } @@ -817,6 +899,11 @@ func (app *App) GetStakingKeeper() ibcclienttypes.StakingKeeper { return app.ConsumerKeeper } +// GetICAHostKeeper implements the TestingApp interface. +func (app *App) GetICAHostKeeper() icahostkeeper.Keeper { + return app.ICAHostKeeper +} + // GetIBCKeeper implements the TestingApp interface. func (app *App) GetIBCKeeper() *ibckeeper.Keeper { return app.IBCKeeper @@ -899,6 +986,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) paramsKeeper.Subspace(ibcconsumertypes.ModuleName) + paramsKeeper.Subspace(icahosttypes.SubModuleName) return paramsKeeper } diff --git a/app/consumer-democracy/proposals_whitelisting.go b/app/consumer-democracy/proposals_whitelisting.go index 3519d8d7ac..6053f5dc39 100644 --- a/app/consumer-democracy/proposals_whitelisting.go +++ b/app/consumer-democracy/proposals_whitelisting.go @@ -7,6 +7,7 @@ import ( minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" ) @@ -64,5 +65,7 @@ var WhitelistedParams = map[paramChangeKey]struct{}{ //ibc transfer {Subspace: ibctransfertypes.ModuleName, Key: "SendEnabled"}: {}, {Subspace: ibctransfertypes.ModuleName, Key: "ReceiveEnabled"}: {}, - //add interchain account params(HostEnabled, AllowedMessages) once the module is added to the consumer app + //ica + {Subspace: icahosttypes.SubModuleName, Key: "HostEnabled"}: {}, + {Subspace: icahosttypes.SubModuleName, Key: "AllowMessages"}: {}, } diff --git a/app/consumer/app.go b/app/consumer/app.go index 4cd1dee606..2bdca8a668 100644 --- a/app/consumer/app.go +++ b/app/consumer/app.go @@ -8,6 +8,16 @@ import ( "os" "path/filepath" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + paramsrest "github.com/cosmos/cosmos-sdk/x/params/client/rest" + proposaltypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + upgraderest "github.com/cosmos/cosmos-sdk/x/upgrade/client/rest" + adminmodulemodule "github.com/cosmos/interchain-security/x/ccv/adminmodule" + adminmodulecli "github.com/cosmos/interchain-security/x/ccv/adminmodule/client/cli" + adminmodulemodulekeeper "github.com/cosmos/interchain-security/x/ccv/adminmodule/keeper" + adminmodulemoduletypes "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" @@ -58,6 +68,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/upgrade" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" + icahost "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" + icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" "github.com/cosmos/ibc-go/v3/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" @@ -116,6 +131,21 @@ var ( vesting.AppModuleBasic{}, //router.AppModuleBasic{}, ibcconsumer.AppModuleBasic{}, + ica.AppModuleBasic{}, + adminmodulemodule.NewAppModuleBasic( + govclient.NewProposalHandler( + adminmodulecli.NewSubmitParamChangeProposalTxCmd, + paramsrest.ProposalRESTHandler, + ), + govclient.NewProposalHandler( + adminmodulecli.NewCmdSubmitUpgradeProposal, + upgraderest.ProposalRESTHandler, + ), + govclient.NewProposalHandler( + adminmodulecli.NewCmdSubmitCancelUpgradeProposal, + upgraderest.ProposalCancelRESTHandler, + ), + ), ) // module account permissions @@ -123,6 +153,7 @@ var ( authtypes.FeeCollectorName: nil, ibcconsumertypes.ConsumerRedistributeName: nil, ibcconsumertypes.ConsumerToSendToProviderName: nil, + icatypes.ModuleName: nil, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, } ) @@ -160,20 +191,23 @@ type App struct { // nolint: golint // from consumer chain or set to use an independant // different fee-pool from the consumer chain ConsumerKeeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.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 - TransferKeeper ibctransferkeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper - AuthzKeeper authzkeeper.Keeper - ConsumerKeeper ibcconsumerkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.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 + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + AuthzKeeper authzkeeper.Keeper + ConsumerKeeper ibcconsumerkeeper.Keeper + ICAHostKeeper icahostkeeper.Keeper + AdminmoduleKeeper adminmodulemodulekeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper ScopedTransferKeeper capabilitykeeper.ScopedKeeper ScopedIBCConsumerKeeper capabilitykeeper.ScopedKeeper + ScopedICAHostKeeper capabilitykeeper.ScopedKeeper // the module manager MM *module.Manager @@ -220,7 +254,7 @@ func New( paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, feegrant.StoreKey, authzkeeper.StoreKey, - ibcconsumertypes.StoreKey, + ibcconsumertypes.StoreKey, icahosttypes.StoreKey, adminmodulemoduletypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -258,6 +292,7 @@ func New( scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) scopedIBCConsumerKeeper := app.CapabilityKeeper.ScopeToModule(ibcconsumertypes.ModuleName) + scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) app.CapabilityKeeper.Seal() // add keepers @@ -366,10 +401,25 @@ func New( transferModule := transfer.NewAppModule(app.TransferKeeper) ibcmodule := transfer.NewIBCModule(app.TransferKeeper) + app.ICAHostKeeper = icahostkeeper.NewKeeper( + appCodec, + keys[icahosttypes.StoreKey], + app.GetSubspace(icahosttypes.SubModuleName), + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, + app.AccountKeeper, + scopedICAHostKeeper, + app.MsgServiceRouter(), + ) + + icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper) + icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) + // create static IBC router, add transfer route, then set and seal it ibcRouter := porttypes.NewRouter() ibcRouter.AddRoute(ibctransfertypes.ModuleName, ibcmodule) ibcRouter.AddRoute(ibcconsumertypes.ModuleName, consumerModule) + ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) app.IBCKeeper.SetRouter(ibcRouter) // create evidence keeper with router @@ -382,6 +432,24 @@ func New( app.EvidenceKeeper = *evidenceKeeper + adminRouter := govtypes.NewRouter() + adminRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). + AddRoute(proposaltypes.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). + AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) + + app.AdminmoduleKeeper = *adminmodulemodulekeeper.NewKeeper( + appCodec, + keys[adminmodulemoduletypes.StoreKey], + keys[adminmodulemoduletypes.MemStoreKey], + adminRouter, + // this allows any type of proposal to be submitted to the admin module (everything is whitelisted) + // projects will implement their functions to define what is allowed for provider and consumer admins. + // Implementation example can be found in app/consumer-democracy/proposals_whitelisting.go + func(govtypes.Content) bool { return true }, + func(govtypes.Content) bool { return true }, + ) + adminModule := adminmodulemodule.NewAppModule(appCodec, app.AdminmoduleKeeper, app.ICAHostKeeper, app.ConsumerKeeper) + skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) // NOTE: Any module instantiated in the module manager that is later modified @@ -401,6 +469,8 @@ func New( params.NewAppModule(app.ParamsKeeper), transferModule, consumerModule, + icaModule, + adminModule, ) // During begin block slashing happens after distr.BeginBlocker so that @@ -415,6 +485,7 @@ func New( crisistypes.ModuleName, ibctransfertypes.ModuleName, ibchost.ModuleName, + icatypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, slashingtypes.ModuleName, @@ -424,11 +495,13 @@ func New( paramstypes.ModuleName, vestingtypes.ModuleName, ibcconsumertypes.ModuleName, + adminmodulemoduletypes.ModuleName, ) app.MM.SetOrderEndBlockers( crisistypes.ModuleName, ibctransfertypes.ModuleName, ibchost.ModuleName, + icatypes.ModuleName, feegrant.ModuleName, authz.ModuleName, capabilitytypes.ModuleName, @@ -440,6 +513,7 @@ func New( upgradetypes.ModuleName, vestingtypes.ModuleName, ibcconsumertypes.ModuleName, + adminmodulemoduletypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -454,6 +528,7 @@ func New( slashingtypes.ModuleName, crisistypes.ModuleName, ibchost.ModuleName, + icatypes.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName, feegrant.ModuleName, @@ -464,6 +539,7 @@ func New( upgradetypes.ModuleName, vestingtypes.ModuleName, ibcconsumertypes.ModuleName, + adminmodulemoduletypes.ModuleName, ) app.MM.RegisterInvariants(&app.CrisisKeeper) @@ -554,6 +630,7 @@ func New( app.ScopedIBCKeeper = scopedIBCKeeper app.ScopedTransferKeeper = scopedTransferKeeper app.ScopedIBCConsumerKeeper = scopedIBCConsumerKeeper + app.ScopedICAHostKeeper = scopedICAHostKeeper return app } @@ -691,6 +768,11 @@ func (app *App) GetStakingKeeper() ibcclienttypes.StakingKeeper { return app.ConsumerKeeper } +// GetICAHostKeeper implements the TestingApp interface. +func (app *App) GetICAHostKeeper() icahostkeeper.Keeper { + return app.ICAHostKeeper +} + // GetIBCKeeper implements the TestingApp interface. func (app *App) GetIBCKeeper() *ibckeeper.Keeper { return app.IBCKeeper @@ -769,6 +851,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) paramsKeeper.Subspace(ibcconsumertypes.ModuleName) + paramsKeeper.Subspace(icahosttypes.SubModuleName) return paramsKeeper } diff --git a/app/provider/app.go b/app/provider/app.go index 25ec012836..95d1796beb 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -76,6 +76,11 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" + icacontroller "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller" + icacontrollerkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/keeper" + icacontrollertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" "github.com/cosmos/ibc-go/v3/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" @@ -88,6 +93,9 @@ import ( ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/interchain-security/x/ccv/icamauth" + icamauthkeeper "github.com/cosmos/interchain-security/x/ccv/icamauth/keeper" + icamauthtypes "github.com/cosmos/interchain-security/x/ccv/icamauth/types" "github.com/gorilla/mux" "github.com/gravity-devs/liquidity/x/liquidity" @@ -145,6 +153,7 @@ var ( ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler, ibcproviderclient.ProposalHandler, + ibcproviderclient.ConsumerGovernanceHandler, ), params.AppModuleBasic{}, crisis.AppModuleBasic{}, @@ -159,12 +168,15 @@ var ( liquidity.AppModuleBasic{}, //router.AppModuleBasic{}, ibcprovider.AppModuleBasic{}, + ica.AppModuleBasic{}, + icamauth.AppModuleBasic{}, ) // module account permissions maccPerms = map[string][]string{ authtypes.FeeCollectorName: nil, distrtypes.ModuleName: nil, + icatypes.ModuleName: nil, minttypes.ModuleName: {authtypes.Minter}, stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, @@ -210,22 +222,26 @@ type App struct { // nolint: golint // different fee-pool from the consumer chain ConsumerKeeper DistrKeeper distrkeeper.Keeper - GovKeeper govkeeper.Keeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.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 - TransferKeeper ibctransferkeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper - AuthzKeeper authzkeeper.Keeper - LiquidityKeeper liquiditykeeper.Keeper - ProviderKeeper ibcproviderkeeper.Keeper + GovKeeper govkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.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 + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + AuthzKeeper authzkeeper.Keeper + LiquidityKeeper liquiditykeeper.Keeper + ProviderKeeper ibcproviderkeeper.Keeper + ICAControllerKeeper icacontrollerkeeper.Keeper + ICAMauthKeeper icamauthkeeper.Keeper // make scoped keepers public for test purposes - ScopedIBCKeeper capabilitykeeper.ScopedKeeper - ScopedTransferKeeper capabilitykeeper.ScopedKeeper - ScopedIBCProviderKeeper capabilitykeeper.ScopedKeeper + ScopedIBCKeeper capabilitykeeper.ScopedKeeper + ScopedTransferKeeper capabilitykeeper.ScopedKeeper + ScopedIBCProviderKeeper capabilitykeeper.ScopedKeeper + ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper + ScopedICAMauthKeeper capabilitykeeper.ScopedKeeper // the module manager MM *module.Manager @@ -273,7 +289,7 @@ func New( govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, liquiditytypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, feegrant.StoreKey, authzkeeper.StoreKey, - providertypes.StoreKey, + providertypes.StoreKey, icacontrollertypes.StoreKey, icamauthtypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -311,6 +327,8 @@ func New( scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) scopedIBCProviderKeeper := app.CapabilityKeeper.ScopeToModule(providertypes.ModuleName) + scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) + scopedICAMauthKeeper := app.CapabilityKeeper.ScopeToModule(icamauthtypes.ModuleName) app.CapabilityKeeper.Seal() // add keepers @@ -419,6 +437,16 @@ func New( scopedIBCKeeper, ) + app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( + appCodec, keys[icacontrollertypes.StoreKey], + app.GetSubspace(icacontrollertypes.SubModuleName), + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, + scopedICAControllerKeeper, + app.MsgServiceRouter(), + ) + app.ProviderKeeper = ibcproviderkeeper.NewKeeper( appCodec, keys[providertypes.StoreKey], @@ -431,10 +459,13 @@ func New( app.StakingKeeper, app.SlashingKeeper, app.AccountKeeper, + app.ICAControllerKeeper, + // ICA Authentication module's scoped keeper owns capability of the channel used to send txs through ICA + scopedICAMauthKeeper, authtypes.FeeCollectorName, ) - providerModule := ibcprovider.NewAppModule(&app.ProviderKeeper) + providerModule := ibcprovider.NewAppModule(&app.ProviderKeeper, app.AccountKeeper, app.ICAControllerKeeper) // register the proposal types govRouter := govtypes.NewRouter() @@ -471,10 +502,25 @@ func New( transferModule := transfer.NewAppModule(app.TransferKeeper) ibcmodule := transfer.NewIBCModule(app.TransferKeeper) + app.ICAMauthKeeper = icamauthkeeper.NewKeeper( + appCodec, + keys[icamauthtypes.StoreKey], + app.ICAControllerKeeper, + scopedICAMauthKeeper, + ) + + icaMauthModule := icamauth.NewAppModule(appCodec, app.ICAMauthKeeper) + icaMauthIBCModule := icamauth.NewIBCModule(app.ICAMauthKeeper) + + icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil) + icaControllerIBCModule := icacontroller.NewIBCModule(app.ICAControllerKeeper, icaMauthIBCModule) + // create static IBC router, add transfer route, then set and seal it ibcRouter := porttypes.NewRouter() ibcRouter.AddRoute(ibctransfertypes.ModuleName, ibcmodule) ibcRouter.AddRoute(providertypes.ModuleName, providerModule) + ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerIBCModule) + ibcRouter.AddRoute(icamauthtypes.ModuleName, icaControllerIBCModule) app.IBCKeeper.SetRouter(ibcRouter) // create evidence keeper with router @@ -517,6 +563,8 @@ func New( liquidity.NewAppModule(appCodec, app.LiquidityKeeper, app.AccountKeeper, app.BankKeeper, app.DistrKeeper), transferModule, providerModule, + icaModule, + icaMauthModule, ) // During begin block slashing happens after distr.BeginBlocker so that @@ -534,6 +582,8 @@ func New( liquiditytypes.ModuleName, ibctransfertypes.ModuleName, ibchost.ModuleName, + icatypes.ModuleName, + icamauthtypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, @@ -560,6 +610,8 @@ func New( liquiditytypes.ModuleName, ibctransfertypes.ModuleName, ibchost.ModuleName, + icatypes.ModuleName, + icamauthtypes.ModuleName, feegrant.ModuleName, authz.ModuleName, capabilitytypes.ModuleName, @@ -592,6 +644,8 @@ func New( minttypes.ModuleName, crisistypes.ModuleName, ibchost.ModuleName, + icatypes.ModuleName, + icamauthtypes.ModuleName, evidencetypes.ModuleName, liquiditytypes.ModuleName, ibctransfertypes.ModuleName, @@ -699,6 +753,8 @@ func New( app.ScopedIBCKeeper = scopedIBCKeeper app.ScopedTransferKeeper = scopedTransferKeeper app.ScopedIBCProviderKeeper = scopedIBCProviderKeeper + app.ScopedICAControllerKeeper = scopedICAControllerKeeper + app.ScopedICAMauthKeeper = scopedICAMauthKeeper return app } @@ -920,6 +976,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) paramsKeeper.Subspace(providertypes.ModuleName) + paramsKeeper.Subspace(icacontrollertypes.SubModuleName) return paramsKeeper } diff --git a/go.mod b/go.mod index 2ff5be48a5..dd77c60b31 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,10 @@ require ( github.com/confio/ics23/go v0.7.0 github.com/golang/mock v1.6.0 github.com/oxyno-zeta/gomock-extra-matcher v1.1.0 + github.com/pkg/errors v0.9.1 github.com/regen-network/cosmos-proto v0.3.1 + github.com/spf13/pflag v1.0.5 + github.com/spf13/viper v1.10.1 ) require ( @@ -99,7 +102,6 @@ require ( github.com/mtibben/percent v0.2.1 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.11.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect @@ -111,8 +113,6 @@ require ( github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect github.com/spf13/afero v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.10.1 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect diff --git a/proto/interchain_security/ccv/adminmodule/v1/genesis.proto b/proto/interchain_security/ccv/adminmodule/v1/genesis.proto new file mode 100644 index 0000000000..ce1d413238 --- /dev/null +++ b/proto/interchain_security/ccv/adminmodule/v1/genesis.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package interchain_security.ccv.adminmodule.v1; + +import "gogoproto/gogo.proto"; + +// this line is used by starport scaffolding # genesis/proto/import + +option go_package = "github.com/cosmos/interchain-security/x/ccv/adminmodule/types"; + +// GenesisState defines the adminmodule module's genesis state. +message GenesisState { repeated string admins = 1; } diff --git a/proto/interchain_security/ccv/adminmodule/v1/query.proto b/proto/interchain_security/ccv/adminmodule/v1/query.proto new file mode 100644 index 0000000000..0c948e91a2 --- /dev/null +++ b/proto/interchain_security/ccv/adminmodule/v1/query.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; + +package interchain_security.ccv.adminmodule.v1; + +import "google/api/annotations.proto"; +import "cosmos/gov/v1beta1/gov.proto"; +// this line is used by starport scaffolding # 1 + +option go_package = "github.com/cosmos/interchain-security/x/ccv/adminmodule/types"; + +// Query defines the gRPC querier service. +service Query { + // this line is used by starport scaffolding # 2 + + // Queries a list of admins items. + rpc Admins(QueryAdminsRequest) returns (QueryAdminsResponse) { + option (google.api.http).get = + "/interchain-security/ccv/adminmodule/admins"; + } + + // Queries a list of archived proposals. + rpc ArchivedProposals(QueryArchivedProposalsRequest) + returns (QueryArchivedProposalsResponse) { + option (google.api.http).get = + "/interchain-security/ccv/adminmodule/archivedproposals"; + } +} + +// this line is used by starport scaffolding # 3 +message QueryAdminsRequest {} + +message QueryAdminsResponse { repeated string admins = 1; } + +message QueryArchivedProposalsRequest {} + +message QueryArchivedProposalsResponse { + repeated cosmos.gov.v1beta1.Proposal proposals = 1; +} diff --git a/proto/interchain_security/ccv/adminmodule/v1/tx.proto b/proto/interchain_security/ccv/adminmodule/v1/tx.proto new file mode 100644 index 0000000000..9e1161e381 --- /dev/null +++ b/proto/interchain_security/ccv/adminmodule/v1/tx.proto @@ -0,0 +1,54 @@ +syntax = "proto3"; +package interchain_security.ccv.adminmodule.v1; + +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; +import "cosmos_proto/cosmos.proto"; + +// this line is used by starport scaffolding # proto/tx/import + +option go_package = "github.com/cosmos/interchain-security/x/ccv/adminmodule/types"; + +// Msg defines the Msg service. +service Msg { + rpc DeleteAdmin(MsgDeleteAdmin) returns (MsgDeleteAdminResponse); + rpc AddAdmin(MsgAddAdmin) returns (MsgAddAdminResponse); + rpc SubmitProposal(MsgSubmitProposal) returns (MsgSubmitProposalResponse); + // this line is used by starport scaffolding # proto/tx/rpc +} + +// this line is used by starport scaffolding # proto/tx/message +message MsgDeleteAdmin { + string creator = 1; + string admin = 2; +} + +message MsgDeleteAdminResponse {} + +message MsgAddAdmin { + string creator = 1; + string admin = 2; +} + +message MsgAddAdminResponse {} + +// MsgSubmitProposal defines an sdk.Msg type that supports submitting arbitrary +// proposal Content. +message MsgSubmitProposal { + option (gogoproto.equal) = false; + option (gogoproto.goproto_stringer) = false; + option (gogoproto.stringer) = false; + option (gogoproto.goproto_getters) = false; + + google.protobuf.Any content = 1 + [ (cosmos_proto.accepts_interface) = "Content" ]; + string proposer = 2; +} + +// MsgSubmitProposalResponse defines the Msg/SubmitProposal response type. +message MsgSubmitProposalResponse { + uint64 proposal_id = 1 [ + (gogoproto.jsontag) = "proposal_id", + (gogoproto.moretags) = "yaml:\"proposal_id\"" + ]; +} diff --git a/proto/interchain_security/ccv/consumer/v1/consumer.proto b/proto/interchain_security/ccv/consumer/v1/consumer.proto index 056e155ea3..3f480f7956 100644 --- a/proto/interchain_security/ccv/consumer/v1/consumer.proto +++ b/proto/interchain_security/ccv/consumer/v1/consumer.proto @@ -32,11 +32,11 @@ message Params { string provider_fee_pool_addr_str = 4; // Sent CCV related IBC packets will timeout after this duration google.protobuf.Duration ccv_timeout_period = 5 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; // Sent transfer related IBC packets will timeout after this duration google.protobuf.Duration transfer_timeout_period = 6 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; // The fraction of tokens allocated to the consumer redistribution address // during distribution events. The fraction is a string representing a @@ -44,7 +44,7 @@ message Params { string consumer_redistribution_fraction = 7; // The number of historical info entries to persist in store. - // This param is a part of the cosmos sdk staking module. In the case of + // This param is a part of the cosmos sdk staking module. In the case of // a ccv enabled consumer chain, the ccv module acts as the staking module. int64 historical_entries = 8; } @@ -66,12 +66,11 @@ message CrossChainValidator { // SlashRequest defines a slashing request for CCV consumer module message SlashRequest { - interchain_security.ccv.v1.SlashPacketData packet = 1; - cosmos.staking.v1beta1.InfractionType infraction = 2; + interchain_security.ccv.v1.SlashPacketData packet = 1; + cosmos.staking.v1beta1.InfractionType infraction = 2; } // SlashRequests is a list of slash requests for CCV consumer module message SlashRequests { - repeated SlashRequest requests = 1 - [ (gogoproto.nullable) = false ]; + repeated SlashRequest requests = 1 [ (gogoproto.nullable) = false ]; } diff --git a/proto/interchain_security/ccv/consumer/v1/genesis.proto b/proto/interchain_security/ccv/consumer/v1/genesis.proto index c71aecd64a..08e08635a8 100644 --- a/proto/interchain_security/ccv/consumer/v1/genesis.proto +++ b/proto/interchain_security/ccv/consumer/v1/genesis.proto @@ -15,7 +15,8 @@ message GenesisState { Params params = 1 [ (gogoproto.nullable) = false ]; string provider_client_id = 2; // empty for a completely new chain string provider_channel_id = 3; // empty for a completely new chain - bool new_chain = 4; // true for new chain GenesisState, false for chain restart. + bool new_chain = + 4; // true for new chain GenesisState, false for chain restart. // ProviderClientState filled in on new chain, nil on restart. ibc.lightclients.tendermint.v1.ClientState provider_client_state = 5; // ProviderConsensusState filled in on new chain, nil on restart. @@ -33,8 +34,10 @@ message GenesisState { repeated OutstandingDowntime outstanding_downtime_slashing = 10 [ (gogoproto.nullable) = false ]; // PendingSlashRequests filled in on new chain, nil on restart. - interchain_security.ccv.consumer.v1.SlashRequests pending_slash_requests = 11 - [ (gogoproto.nullable) = false ]; + interchain_security.ccv.consumer.v1.SlashRequests pending_slash_requests = 11 + [ (gogoproto.nullable) = false ]; + // Address of the provider's governance module + string provider_governance_address = 12; } // MaturingVSCPacket defines the genesis information for the @@ -44,7 +47,7 @@ message MaturingVSCPacket { uint64 maturity_time = 2; } -// HeightValsetUpdateID defines the genesis information for the mapping +// HeightValsetUpdateID defines the genesis information for the mapping // of each block height to a valset update id message HeightToValsetUpdateID { uint64 height = 1; diff --git a/proto/interchain_security/ccv/icamauth/v1/query.proto b/proto/interchain_security/ccv/icamauth/v1/query.proto new file mode 100644 index 0000000000..bd6f686d20 --- /dev/null +++ b/proto/interchain_security/ccv/icamauth/v1/query.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +package interchain_security.ccv.icamauth.v1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; + +option go_package = "github.com/cosmos/interchain-security/x/ccv/icamauth/types"; + +// Query defines the gRPC querier service. +service Query { + // QueryInterchainAccount returns the interchain account for given owner + // address on a given connection pair + rpc InterchainAccount(QueryInterchainAccountRequest) + returns (QueryInterchainAccountResponse) { + option (google.api.http).get = + "/interchain_security/ccv/icamauth/v1/interchain_account/owner/{owner}/" + "connection/{connection_id}"; + } +} + +// QueryInterchainAccountRequest is the request type for the +// Query/InterchainAccountAddress RPC +message QueryInterchainAccountRequest { + string owner = 1; + string connection_id = 2 [ (gogoproto.moretags) = "yaml:\"connection_id\"" ]; +} + +// QueryInterchainAccountResponse the response type for the +// Query/InterchainAccountAddress RPC +message QueryInterchainAccountResponse { + string interchain_account_address = 1 + [ (gogoproto.moretags) = "yaml:\"interchain_account_address\"" ]; +} diff --git a/proto/interchain_security/ccv/icamauth/v1/tx.proto b/proto/interchain_security/ccv/icamauth/v1/tx.proto new file mode 100644 index 0000000000..4ce332fa16 --- /dev/null +++ b/proto/interchain_security/ccv/icamauth/v1/tx.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package interchain_security.ccv.icamauth.v1; + +option go_package = "github.com/cosmos/interchain-security/x/ccv/icamauth/types"; + +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; + +// Msg defines the ica Msg service. +service Msg { + // Register defines a rpc handler for MsgRegisterAccount + rpc RegisterAccount(MsgRegisterAccount) returns (MsgRegisterAccountResponse); + // SubmitTx defines a rpc handler for MsgSubmitTx + rpc SubmitTx(MsgSubmitTx) returns (MsgSubmitTxResponse); +} + +// MsgRegisterAccount defines the payload for Msg/RegisterAccount +message MsgRegisterAccount { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string owner = 1; + string connection_id = 2 [ (gogoproto.moretags) = "yaml:\"connection_id\"" ]; + string version = 3; +} + +// MsgRegisterAccountResponse defines the response for Msg/RegisterAccount +message MsgRegisterAccountResponse {} + +// MsgSubmitTx defines the payload for Msg/SubmitTx +message MsgSubmitTx { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string owner = 1; + string connection_id = 2 [ (gogoproto.moretags) = "yaml:\"connection_id\"" ]; + google.protobuf.Any msg = 3; +} + +// MsgSubmitTxResponse defines the response for Msg/SubmitTx +message MsgSubmitTxResponse {} diff --git a/proto/interchain_security/ccv/provider/v1/genesis.proto b/proto/interchain_security/ccv/provider/v1/genesis.proto index dedfc72120..ebcd4de863 100644 --- a/proto/interchain_security/ccv/provider/v1/genesis.proto +++ b/proto/interchain_security/ccv/provider/v1/genesis.proto @@ -10,32 +10,30 @@ import "interchain_security/ccv/provider/v1/provider.proto"; import "interchain_security/ccv/consumer/v1/consumer.proto"; import "interchain_security/ccv/consumer/v1/genesis.proto"; - // GenesisState defines the CCV provider chain genesis state message GenesisState { // empty for a new chain - uint64 valset_update_id = 1; + uint64 valset_update_id = 1; // empty for a new chain - repeated ConsumerState consumer_states = 2 [ + repeated ConsumerState consumer_states = 2 [ (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"consumer_states\"" ]; // empty for a new chain repeated interchain_security.ccv.v1.UnbondingOp unbonding_ops = 3 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; // empty for a new chain interchain_security.ccv.v1.MaturedUnbondingOps mature_unbonding_ops = 4; - // empty for a new chain + // empty for a new chain repeated ValsetUpdateIdToHeight valset_update_id_to_height = 5 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; // empty for a new chain repeated ConsumerAdditionProposal consumer_addition_proposals = 6 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; // empty for a new chain repeated ConsumerRemovalProposal consumer_removal_proposals = 7 - [ (gogoproto.nullable) = false ]; - Params params = 8 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; + Params params = 8 [ (gogoproto.nullable) = false ]; } // consumer chain @@ -48,31 +46,32 @@ message ConsumerState { string client_id = 3; // InitalHeight defines the initial block height for the consumer chain uint64 initial_height = 4; - // LockUnbondingOnTimeout defines whether the unbonding funds should be released for this - // chain in case of a IBC channel timeout + // LockUnbondingOnTimeout defines whether the unbonding funds should be + // released for this chain in case of a IBC channel timeout bool lock_unbonding_on_timeout = 5; // ConsumerGenesis defines the initial consumer chain genesis states interchain_security.ccv.consumer.v1.GenesisState consumer_genesis = 6 - [ (gogoproto.nullable) = false ]; - // PendingValsetChanges defines the pending validator set changes for the consumer chain - repeated interchain_security.ccv.v1.ValidatorSetChangePacketData pending_valset_changes = 7 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; + // PendingValsetChanges defines the pending validator set changes for the + // consumer chain + repeated interchain_security.ccv.v1.ValidatorSetChangePacketData + pending_valset_changes = 7 [ (gogoproto.nullable) = false ]; repeated string slash_downtime_ack = 8; // UnbondingOpsIndex defines the unbonding operations on the consumer chain repeated UnbondingOpIndex unbonding_ops_index = 9 - [ (gogoproto.nullable) = false ]; + [ (gogoproto.nullable) = false ]; } -// UnbondingOpIndex defines the genesis information for each unbonding operations index -// referenced by chain id and valset udpate id +// UnbondingOpIndex defines the genesis information for each unbonding +// operations index referenced by chain id and valset udpate id message UnbondingOpIndex { uint64 valset_update_id = 1; repeated uint64 unbonding_op_index = 2; } -// ValsetUpdateIdToHeight defines the genesis information for the mapping +// ValsetUpdateIdToHeight defines the genesis information for the mapping // of each valset udpate id to a block height message ValsetUpdateIdToHeight { - uint64 valset_update_id = 1; - uint64 height = 2; + uint64 valset_update_id = 1; + uint64 height = 2; } diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index cf72e150ea..8b6dececb4 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -5,64 +5,75 @@ package interchain_security.ccv.provider.v1; option go_package = "github.com/cosmos/interchain-security/x/ccv/provider/types"; import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto"; import "ibc/core/client/v1/client.proto"; import "ibc/lightclients/tendermint/v1/tendermint.proto"; +import "cosmos_proto/cosmos.proto"; -// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain. -// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time -// or get slashed. It is recommended that spawn time occurs after the proposal end time. +// ConsumerAdditionProposal is a governance proposal on the provider chain to +// spawn a new consumer chain. If it passes, then all validators on the provider +// chain are expected to validate the consumer chain at spawn time or get +// slashed. It is recommended that spawn time occurs after the proposal end +// time. message ConsumerAdditionProposal { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - // the title of the proposal - string title = 1; - // the description of the proposal - string description = 2; - // the proposed chain-id of the new consumer chain, must be different from all other consumer chain ids of the executing - // provider chain. - string chain_id = 3 ; - // the proposed initial height of new consumer chain. - // For a completely new chain, this will be {0,1}. However, it may be different if this is a chain that is converting to a consumer chain. - ibc.core.client.v1.Height initial_height = 4 [(gogoproto.nullable) = false]; - // genesis hash with no staking information included. - bytes genesis_hash = 5 ; - // binary hash is the hash of the binary that should be used by validators on chain initialization. - bytes binary_hash = 6 ; - // spawn time is the time on the provider chain at which the consumer chain genesis is finalized and all validators - // will be responsible for starting their consumer chain validator node. - google.protobuf.Timestamp spawn_time = 7 - [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; - // Indicates whether the outstanding unbonding operations should be released - // in case of a channel time-outs. When set to true, a governance proposal - // on the provider chain would be necessary to release the locked funds. - bool lock_unbonding_on_timeout = 8; - } - -// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain. -// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding -// operation funds are released if the LockUnbondingOnTimeout parameter is set to false for the consumer chain ID. - message ConsumerRemovalProposal { - // the title of the proposal - string title = 1; - // the description of the proposal - string description = 2; - // the chain-id of the consumer chain to be stopped - string chain_id = 3; - // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node - google.protobuf.Timestamp stop_time = 4 - [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; - } + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + // the title of the proposal + string title = 1; + // the description of the proposal + string description = 2; + // the proposed chain-id of the new consumer chain, must be different from all + // other consumer chain ids of the executing provider chain. + string chain_id = 3; + // the proposed initial height of new consumer chain. + // For a completely new chain, this will be {0,1}. However, it may be + // different if this is a chain that is converting to a consumer chain. + ibc.core.client.v1.Height initial_height = 4 [ (gogoproto.nullable) = false ]; + // genesis hash with no staking information included. + bytes genesis_hash = 5; + // binary hash is the hash of the binary that should be used by validators on + // chain initialization. + bytes binary_hash = 6; + // spawn time is the time on the provider chain at which the consumer chain + // genesis is finalized and all validators will be responsible for starting + // their consumer chain validator node. + google.protobuf.Timestamp spawn_time = 7 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; + // Indicates whether the outstanding unbonding operations should be released + // in case of a channel time-outs. When set to true, a governance proposal + // on the provider chain would be necessary to release the locked funds. + bool lock_unbonding_on_timeout = 8; +} + +// ConsumerRemovalProposal is a governance proposal on the provider chain to +// remove (and stop) a consumer chain. If it passes, all the consumer chain's +// state is removed from the provider chain. The outstanding unbonding operation +// funds are released if the LockUnbondingOnTimeout parameter is set to false +// for the consumer chain ID. +message ConsumerRemovalProposal { + // the title of the proposal + string title = 1; + // the description of the proposal + string description = 2; + // the chain-id of the consumer chain to be stopped + string chain_id = 3; + // the time on the provider chain at which all validators are responsible to + // stop their consumer chain validator node + google.protobuf.Timestamp stop_time = 4 + [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; +} // Params defines the parameters for CCV Provider module message Params { ibc.lightclients.tendermint.v1.ClientState template_client = 1; // Sent IBC packets will timeout after this duration google.protobuf.Duration ccv_timeout_period = 2 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // TrustingPeriodFraction is used to compute the consumer and provider IBC client's TrustingPeriod + [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + // TrustingPeriodFraction is used to compute the consumer and provider IBC + // client's TrustingPeriod int64 trusting_period_fraction = 3; } @@ -73,6 +84,16 @@ message HandshakeMetadata { // SlashAcks contains addesses of consumer chain validators // successfully slashed on the provider chain -message SlashAcks { - repeated string addresses = 1; +message SlashAcks { repeated string addresses = 1; } + +// ConsumerGovernanceProposal contains a proposal that will be submitted to the +// consumer chain if voting pass successfully on the provider side. +message ConsumerGovernanceProposal { + // IBC connection identifier of the consumer chain for which the proposal is + // submitted + string connection_id = 1; + // An arbitrary proposal content which satisfies Content interface of the + // governance module + google.protobuf.Any content = 2 + [ (cosmos_proto.accepts_interface) = "Content" ]; } \ No newline at end of file diff --git a/proto/interchain_security/ccv/v1/ccv.proto b/proto/interchain_security/ccv/v1/ccv.proto index 23729db928..1d10cb263c 100644 --- a/proto/interchain_security/ccv/v1/ccv.proto +++ b/proto/interchain_security/ccv/v1/ccv.proto @@ -53,11 +53,8 @@ message SlashPacketData { } // UnbondingOpsIndex defines a list of unbonding operation ids. -message UnbondingOpsIndex { - repeated uint64 ids = 1; -} +message UnbondingOpsIndex { repeated uint64 ids = 1; } -// MaturedUnbondingOps defines a list of ids corresponding to ids of matured unbonding operations. -message MaturedUnbondingOps { - repeated uint64 ids = 1; -} +// MaturedUnbondingOps defines a list of ids corresponding to ids of matured +// unbonding operations. +message MaturedUnbondingOps { repeated uint64 ids = 1; } diff --git a/tests/difference/core/driver/setup.go b/tests/difference/core/driver/setup.go index a4d3e7d1a0..ad17cd9f15 100644 --- a/tests/difference/core/driver/setup.go +++ b/tests/difference/core/driver/setup.go @@ -44,6 +44,7 @@ import ( consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" providerkeeper "github.com/cosmos/interchain-security/x/ccv/provider/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" channelkeeper "github.com/cosmos/ibc-go/v3/modules/core/04-channel/keeper" ccv "github.com/cosmos/interchain-security/x/ccv/types" ) @@ -481,7 +482,9 @@ func (b *Builder) createConsumerGenesis(tmConfig *ibctesting.TendermintConfig) * consumertypes.DefaultConsumerRedistributeFrac, consumertypes.DefaultHistoricalEntries, ) - return consumertypes.NewInitialGenesisState(providerClient, providerConsState, valUpdates, consumertypes.SlashRequests{}, params) + + providerGovAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() + return consumertypes.NewInitialGenesisState(providerClient, providerConsState, valUpdates, consumertypes.SlashRequests{}, params, providerGovAddr) } func (b *Builder) createLink() { diff --git a/tests/e2e/ica_auth_keeper_test.go b/tests/e2e/ica_auth_keeper_test.go new file mode 100644 index 0000000000..fc81eadb71 --- /dev/null +++ b/tests/e2e/ica_auth_keeper_test.go @@ -0,0 +1,472 @@ +package e2e + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto" + + "bytes" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + appConsumer "github.com/cosmos/interchain-security/app/consumer" + appProvider "github.com/cosmos/interchain-security/app/provider" + "github.com/cosmos/interchain-security/testutil/simapp" + "github.com/cosmos/interchain-security/x/ccv/icamauth/keeper" + "github.com/cosmos/interchain-security/x/ccv/icamauth/types" + ccv "github.com/cosmos/interchain-security/x/ccv/types" + "github.com/cosmos/interchain-security/x/ccv/utils" + tmtypes "github.com/tendermint/tendermint/types" +) + +var ( + // TODO: Cosmos-SDK ADR-28: Update crypto.AddressHash() when sdk uses address.Module() + // https://github.com/cosmos/cosmos-sdk/issues/10225 + // + // TestAccAddress defines a reusable bech32 address for testing purposes + TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), ibctesting.FirstConnectionID, TestPortID) + // TestOwnerAddress defines a reusable bech32 address for testing purposes + TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + // TestPortID defines a resuable port identifier for testing purposes + TestPortID, _ = icatypes.NewControllerPortID(TestOwnerAddress) +) + +type ICAAuthKeeperTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + // testing chains + providerChain *ibctesting.TestChain + consumerChain *ibctesting.TestChain + + path *ibctesting.Path + transferPath *ibctesting.Path + icaPath *ibctesting.Path +} + +func (s *ICAAuthKeeperTestSuite) providerCtx() sdk.Context { + return s.providerChain.GetContext() +} + +func (s *ICAAuthKeeperTestSuite) consumerCtx() sdk.Context { + return s.consumerChain.GetContext() +} + +func (suite *ICAAuthKeeperTestSuite) SetupTest() { + suite.coordinator, suite.providerChain, suite.consumerChain = simapp.NewProviderConsumerCoordinator(suite.T()) + + // valsets must match + providerValUpdates := tmtypes.TM2PB.ValidatorUpdates(suite.providerChain.Vals) + consumerValUpdates := tmtypes.TM2PB.ValidatorUpdates(suite.consumerChain.Vals) + suite.Require().True(len(providerValUpdates) == len(consumerValUpdates), "initial valset not matching") + for i := 0; i < len(providerValUpdates); i++ { + addr1 := utils.GetChangePubKeyAddress(providerValUpdates[i]) + addr2 := utils.GetChangePubKeyAddress(consumerValUpdates[i]) + suite.Require().True(bytes.Equal(addr1, addr2), "validator mismatch") + } + + // move both chains to the next block + suite.providerChain.NextBlock() + suite.consumerChain.NextBlock() + + // create consumer client on provider chain and set as consumer client for consumer chainID in provider keeper. + err := suite.providerChain.App.(*appProvider.App).ProviderKeeper.CreateConsumerClient( + suite.providerCtx(), + suite.consumerChain.ChainID, + suite.consumerChain.LastHeader.GetHeight().(clienttypes.Height), + false, + ) + suite.Require().NoError(err) + // move provider to next block to commit the state + suite.providerChain.NextBlock() + + // initialize the consumer chain with the genesis state stored on the provider + consumerGenesis, found := suite.providerChain.App.(*appProvider.App).ProviderKeeper.GetConsumerGenesis( + suite.providerCtx(), + suite.consumerChain.ChainID, + ) + suite.Require().True(found, "consumer genesis not found") + suite.consumerChain.App.(*appConsumer.App).ConsumerKeeper.InitGenesis(suite.consumerChain.GetContext(), &consumerGenesis) + + // create path for the CCV channel + suite.path = ibctesting.NewPath(suite.consumerChain, suite.providerChain) + + // update CCV path with correct info + // - set provider endpoint's clientID + consumerClient, found := suite.providerChain.App.(*appProvider.App).ProviderKeeper.GetConsumerClientId( + suite.providerCtx(), + suite.consumerChain.ChainID, + ) + suite.Require().True(found, "consumer client not found") + suite.path.EndpointB.ClientID = consumerClient + // - set consumer endpoint's clientID + providerClient, found := suite.consumerChain.App.(*appConsumer.App).ConsumerKeeper.GetProviderClientID(suite.consumerChain.GetContext()) + suite.Require().True(found, "provider client not found") + suite.path.EndpointA.ClientID = providerClient + // - client config + trustingPeriodFraction := suite.providerChain.App.(*appProvider.App).GetProviderKeeper().GetTrustingPeriodFraction(suite.providerCtx()) + providerUnbondingPeriod := suite.providerChain.App.(*appProvider.App).GetStakingKeeper().UnbondingTime(suite.providerCtx()) + suite.path.EndpointB.ClientConfig.(*ibctesting.TendermintConfig).UnbondingPeriod = providerUnbondingPeriod + suite.path.EndpointB.ClientConfig.(*ibctesting.TendermintConfig).TrustingPeriod = providerUnbondingPeriod / time.Duration(trustingPeriodFraction) + consumerUnbondingPeriod := utils.ComputeConsumerUnbondingPeriod(providerUnbondingPeriod) + suite.path.EndpointA.ClientConfig.(*ibctesting.TendermintConfig).UnbondingPeriod = consumerUnbondingPeriod + suite.path.EndpointA.ClientConfig.(*ibctesting.TendermintConfig).TrustingPeriod = consumerUnbondingPeriod / time.Duration(trustingPeriodFraction) + // - channel config + suite.path.EndpointA.ChannelConfig.PortID = ccv.ConsumerPortID + suite.path.EndpointB.ChannelConfig.PortID = ccv.ProviderPortID + suite.path.EndpointA.ChannelConfig.Version = ccv.Version + suite.path.EndpointB.ChannelConfig.Version = ccv.Version + suite.path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + suite.path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + + // set chains sender account number + // TODO: to be fixed in #151 + err = suite.path.EndpointB.Chain.SenderAccount.SetAccountNumber(6) + suite.Require().NoError(err) + err = suite.path.EndpointA.Chain.SenderAccount.SetAccountNumber(1) + suite.Require().NoError(err) + + // create path for the transfer channel + suite.transferPath = ibctesting.NewPath(suite.consumerChain, suite.providerChain) + suite.transferPath.EndpointA.ChannelConfig.PortID = transfertypes.PortID + suite.transferPath.EndpointB.ChannelConfig.PortID = transfertypes.PortID + suite.transferPath.EndpointA.ChannelConfig.Version = transfertypes.Version + suite.transferPath.EndpointB.ChannelConfig.Version = transfertypes.Version + + controllerPortID, err := icatypes.NewControllerPortID(TestOwnerAddress) + suite.Require().NoError(err) + + // create path for the ica channel + suite.icaPath = ibctesting.NewPath(suite.consumerChain, suite.providerChain) + suite.icaPath.EndpointA.ChannelConfig.PortID = icatypes.PortID + suite.icaPath.EndpointB.ChannelConfig.PortID = controllerPortID + suite.icaPath.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + suite.icaPath.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + suite.icaPath.EndpointA.ChannelConfig.Version = TestVersion + suite.icaPath.EndpointB.ChannelConfig.Version = TestVersion +} + +func (suite *ICAAuthKeeperTestSuite) SetupIBCChannels() { + suite.StartSetupCCVChannel() + suite.CompleteSetupCCVChannel() + suite.SetupTransferChannel() + suite.SetupICAChannel() +} + +func (suite *ICAAuthKeeperTestSuite) StartSetupCCVChannel() { + suite.coordinator.CreateConnections(suite.path) + + err := suite.path.EndpointA.ChanOpenInit() + suite.Require().NoError(err) + + err = suite.path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) +} + +func (suite *ICAAuthKeeperTestSuite) CompleteSetupCCVChannel() { + err := suite.path.EndpointA.ChanOpenAck() + suite.Require().NoError(err) + + err = suite.path.EndpointB.ChanOpenConfirm() + suite.Require().NoError(err) + + // ensure counterparty is up to date + err = suite.path.EndpointA.UpdateClient() + suite.Require().NoError(err) +} + +func (suite *ICAAuthKeeperTestSuite) SetupTransferChannel() { + // transfer path will use the same connection as ccv path + + suite.transferPath.EndpointA.ClientID = suite.path.EndpointA.ClientID + suite.transferPath.EndpointA.ConnectionID = suite.path.EndpointA.ConnectionID + suite.transferPath.EndpointB.ClientID = suite.path.EndpointB.ClientID + suite.transferPath.EndpointB.ConnectionID = suite.path.EndpointB.ConnectionID + + // CCV channel handshake will automatically initiate transfer channel handshake on ACK + // so transfer channel will be on stage INIT when CompleteSetupCCVChannel returns. + suite.transferPath.EndpointA.ChannelID = suite.consumerChain.App.(*appConsumer.App). + ConsumerKeeper.GetDistributionTransmissionChannel(suite.consumerChain.GetContext()) + + // Complete TRY, ACK, CONFIRM for transfer path + err := suite.transferPath.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + + err = suite.transferPath.EndpointA.ChanOpenAck() + suite.Require().NoError(err) + + err = suite.transferPath.EndpointB.ChanOpenConfirm() + suite.Require().NoError(err) + + // ensure counterparty is up to date + err = suite.transferPath.EndpointA.UpdateClient() + suite.Require().NoError(err) +} + +func (suite *ICAAuthKeeperTestSuite) SetupICAChannel() { + // ica path will use the same connection as ccv path + + suite.icaPath.EndpointA.ClientID = suite.path.EndpointA.ClientID + suite.icaPath.EndpointA.ConnectionID = suite.path.EndpointA.ConnectionID + suite.icaPath.EndpointB.ClientID = suite.path.EndpointB.ClientID + suite.icaPath.EndpointB.ConnectionID = suite.path.EndpointB.ConnectionID +} + +// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers +func SetupICAPath(path *ibctesting.Path, owner string) error { + if err := RegisterInterchainAccount(path.EndpointB, owner); err != nil { + return err + } + + if err := path.EndpointA.ChanOpenTry(); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenAck(); err != nil { + return err + } + + if err := path.EndpointA.ChanOpenConfirm(); err != nil { + return err + } + + return nil +} + +func GetProviderICAApp(chain *ibctesting.TestChain) *appProvider.App { + app, ok := chain.App.(*appProvider.App) + if !ok { + panic("not ica app") + } + + return app +} + +func GetConsumerICAApp(chain *ibctesting.TestChain) *appConsumer.App { + app, ok := chain.App.(*appConsumer.App) + if !ok { + panic("not ica app") + } + + return app +} + +// RegisterInterchainAccount is a helper function for starting the channel handshake +func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { + portID, err := icatypes.NewControllerPortID(owner) + if err != nil { + return err + } + + channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) + + if err := GetProviderICAApp(endpoint.Chain).ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil { + return err + } + + // commit state changes for proof verification + endpoint.Chain.NextBlock() + + // update port/channel ids + endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + endpoint.ChannelConfig.PortID = portID + + return nil +} + +// TestICAAuthKeeperTestSuite runs all the tests within this package. +func TestICAAuthKeeperTestSuite(t *testing.T) { + suite.Run(t, new(ICAAuthKeeperTestSuite)) +} + +func (suite *ICAAuthKeeperTestSuite) TestRegisterInterchainAccount() { + var ( + owner string + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "failure - port is already bound", + func() { + GetProviderICAApp(suite.providerChain).IBCKeeper.PortKeeper.BindPort(suite.providerCtx(), TestPortID) + }, + false, + }, + { + "faliure - owner is empty", + func() { + owner = "" + }, + false, + }, + { + "failure - channel is already active", + func() { + portID, err := icatypes.NewControllerPortID(owner) + suite.Require().NoError(err) + + channel := channeltypes.NewChannel( + channeltypes.OPEN, + channeltypes.ORDERED, + channeltypes.NewCounterparty(suite.icaPath.EndpointB.ChannelConfig.PortID, suite.icaPath.EndpointB.ChannelID), + []string{suite.icaPath.EndpointA.ConnectionID}, + suite.icaPath.EndpointA.ChannelConfig.Version, + ) + + GetProviderICAApp(suite.providerChain).IBCKeeper.ChannelKeeper.SetChannel(suite.providerCtx(), portID, ibctesting.FirstChannelID, channel) + GetProviderICAApp(suite.providerChain).ICAControllerKeeper.SetActiveChannelID(suite.providerCtx(), ibctesting.FirstConnectionID, portID, ibctesting.FirstChannelID) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + suite.SetupIBCChannels() + owner = TestOwnerAddress // must be explicitly changed + + tc.malleate() // malleate mutates test data + + msgSrv := keeper.NewMsgServerImpl(GetProviderICAApp(suite.providerChain).ICAMauthKeeper) + msg := types.NewMsgRegisterAccount(owner, suite.icaPath.EndpointA.ConnectionID, suite.icaPath.EndpointA.ChannelConfig.Version) + + res, err := msgSrv.RegisterAccount(sdk.WrapSDKContext(suite.providerChain.GetContext()), msg) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + } else { + suite.Require().Error(err) + suite.Require().Nil(res) + } + }) + } +} + +func (suite *ICAAuthKeeperTestSuite) TestSubmitTx() { + var ( + registerInterchainAccount bool + owner string + connectionId string + icaMsg sdk.Msg + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() { + registerInterchainAccount = true + owner = TestOwnerAddress + connectionId = suite.icaPath.EndpointA.ConnectionID + }, true, + }, + { + "failure - owner address is empty", func() { + registerInterchainAccount = true + owner = "" + connectionId = suite.icaPath.EndpointA.ConnectionID + }, false, + }, + { + "failure - active channel does not exist for connection ID", func() { + registerInterchainAccount = true + owner = TestOwnerAddress + connectionId = "connection-100" + }, false, + }, + { + "failure - active channel does not exist for port ID", func() { + registerInterchainAccount = true + owner = "cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5" + connectionId = suite.icaPath.EndpointA.ConnectionID + }, false, + }, + { + "failure - module does not own channel capability", func() { + registerInterchainAccount = false + owner = TestOwnerAddress + connectionId = suite.icaPath.EndpointA.ConnectionID + icaMsg = &banktypes.MsgSend{ + FromAddress: "source-address", + ToAddress: "destination-address", + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + } + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() + suite.SetupIBCChannels() + + icaAppA := GetProviderICAApp(suite.providerChain) + icaAppB := GetConsumerICAApp(suite.consumerChain) + + tc.malleate() // malleate mutates test data + + if registerInterchainAccount { + err := SetupICAPath(suite.icaPath, TestOwnerAddress) + suite.Require().NoError(err) + + portID, err := icatypes.NewControllerPortID(TestOwnerAddress) + suite.Require().NoError(err) + + // Get the address of the interchain account stored in state during handshake step + interchainAccountAddr, found := GetProviderICAApp(suite.providerChain).ICAControllerKeeper.GetInterchainAccountAddress(suite.providerCtx(), suite.icaPath.EndpointA.ConnectionID, portID) + suite.Require().True(found) + + icaAddr, err := sdk.AccAddressFromBech32(interchainAccountAddr) + suite.Require().NoError(err) + + // Check if account is created + interchainAccount := icaAppB.AccountKeeper.GetAccount(suite.consumerCtx(), icaAddr) + suite.Require().Equal(interchainAccount.GetAddress().String(), interchainAccountAddr) + + // Create bank transfer message to execute on the host + icaMsg = &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.consumerChain.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + } + } + + msgSrv := keeper.NewMsgServerImpl(icaAppA.ICAMauthKeeper) + msg, err := types.NewMsgSubmitTx(icaMsg, connectionId, owner) + suite.Require().NoError(err) + + res, err := msgSrv.SubmitTx(sdk.WrapSDKContext(suite.providerCtx()), msg) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + } else { + suite.Require().Error(err) + suite.Require().Nil(res) + } + }) + } +} diff --git a/tests/e2e/provider_governance_test.go b/tests/e2e/provider_governance_test.go new file mode 100644 index 0000000000..14924d7045 --- /dev/null +++ b/tests/e2e/provider_governance_test.go @@ -0,0 +1,135 @@ +package e2e + +import ( + "fmt" + "time" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + paramsproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" + appConsumer "github.com/cosmos/interchain-security/app/consumer" + appProvider "github.com/cosmos/interchain-security/app/provider" + "github.com/cosmos/interchain-security/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/x/ccv/types" +) + +func (s *CCVTestSuite) TestProviderGovernance() { + s.SetupCCVChannel() + s.SetupGovernanceICAChannel() + + // Bond some tokens on provider to change validator powers + bondAmt := sdk.NewInt(1000000) + delAddr := s.providerChain.SenderAccount.GetAddress() + delegate(s, delAddr, bondAmt) + s.providerChain.NextBlock() + relayAllCommittedPackets(s, s.providerChain, s.path, ccv.ProviderPortID, s.path.EndpointB.ChannelID, 1) + + // this will add gov module ICA account as admin on consumer chain + s.consumerChain.NextBlock() + + // set provider voting period to 0s so that proposal passes immediately + govKeeper := s.providerChain.App.(*appProvider.App).GovKeeper + deposit := govKeeper.GetDepositParams(s.providerCtx()).MinDeposit + votingParams := govKeeper.GetVotingParams(s.providerCtx()) + votingParams.VotingPeriod = 0 * time.Second + govKeeper.SetVotingParams(s.providerCtx(), votingParams) + s.providerChain.NextBlock() + + // test software upgrade proposal type + swUpgradeProposal := upgradetypes.SoftwareUpgradeProposal{ + Title: "SW Upgrade Title", + Description: "SW Upgrade Description", + Plan: upgradetypes.Plan{ + Name: "SW Upgrade 1", + Height: 10000, + Info: "Upgrade Info", + }, + } + + swUpgradeProposalAny, err := codectypes.NewAnyWithValue(&swUpgradeProposal) + s.Require().NoError(err) + consumerGovernanceProposal := &types.ConsumerGovernanceProposal{ + ConnectionId: s.icaPath.EndpointA.ConnectionID, + Content: swUpgradeProposalAny, + } + + _, havePlan := s.consumerChain.App.(*appConsumer.App).UpgradeKeeper.GetUpgradePlan(s.consumerCtx()) + s.Assert().False(havePlan) + + // submits consumer SW upgrade proposal to the provider chain + err = submitProposalAndVote(s.providerCtx(), govKeeper, consumerGovernanceProposal, s.providerChain.SenderAccounts, deposit) + s.Require().NoError(err) + s.providerChain.NextBlock() + relayAllCommittedPackets(s, s.providerChain, s.icaPath, s.icaPath.EndpointB.ChannelConfig.PortID, s.icaPath.EndpointB.ChannelID, 1) + s.consumerChain.NextBlock() + + // check that proposal passed on the consumer chain (it will be archived in the adminmodule) + archivedProposals := s.consumerChain.App.(*appConsumer.App).AdminmoduleKeeper.GetArchivedProposals(s.consumerCtx()) + s.Assert().Equal(govtypes.StatusPassed, archivedProposals[0].Status) + + // check that upgrade plan is queued for execution + plan, havePlan := s.consumerChain.App.(*appConsumer.App).UpgradeKeeper.GetUpgradePlan(s.consumerCtx()) + s.Assert().True(havePlan) + s.Assert().Equal(swUpgradeProposal.Plan.Name, plan.Name) + s.Assert().Equal(swUpgradeProposal.Plan.Height, plan.Height) + + // test param change proposal + var newSignedBlocksVal int64 = 70 + paramChangeProposal := paramsproposal.ParameterChangeProposal{ + Title: "SignedBlocksWindow Change", + Description: "SignedBlocksWindow Description", + Changes: []paramsproposal.ParamChange{ + paramsproposal.NewParamChange("slashing", "SignedBlocksWindow", fmt.Sprintf("\"%d\"", newSignedBlocksVal)), + }, + } + + paramChangeProposalAny, err := codectypes.NewAnyWithValue(¶mChangeProposal) + s.Require().NoError(err) + consumerGovernanceProposal = &types.ConsumerGovernanceProposal{ + ConnectionId: s.icaPath.EndpointA.ConnectionID, + Content: paramChangeProposalAny, + } + + signedBlockWindowOld := s.consumerChain.App.(*appConsumer.App).SlashingKeeper.SignedBlocksWindow(s.consumerCtx()) + + // submits consumer param change proposal to the provider chain + err = submitProposalAndVote(s.providerCtx(), govKeeper, consumerGovernanceProposal, s.providerChain.SenderAccounts, deposit) + s.Require().NoError(err) + s.providerChain.NextBlock() + relayAllCommittedPackets(s, s.providerChain, s.icaPath, s.icaPath.EndpointB.ChannelConfig.PortID, s.icaPath.EndpointB.ChannelID, 1) + s.consumerChain.NextBlock() + + // check that proposal passed on the consumer chain (it will be archived in the adminmodule) + archivedProposals = s.consumerChain.App.(*appConsumer.App).AdminmoduleKeeper.GetArchivedProposals(s.consumerCtx()) + s.Assert().Equal(govtypes.StatusPassed, archivedProposals[1].Status) + + // check that signed blocks window has changed + signedBlockWindowNew := s.consumerChain.App.(*appConsumer.App).SlashingKeeper.SignedBlocksWindow(s.consumerCtx()) + s.Assert().NotEqual(signedBlockWindowOld, signedBlockWindowNew) + s.Assert().Equal(newSignedBlocksVal, signedBlockWindowNew) +} + +func submitProposalAndVote(ctx sdk.Context, govKeeper govkeeper.Keeper, content govtypes.Content, + accounts []ibctesting.SenderAccount, depositAmount sdk.Coins) error { + proposal, err := govKeeper.SubmitProposal(ctx, content) + if err != nil { + return err + } + _, err = govKeeper.AddDeposit(ctx, proposal.ProposalId, accounts[0].SenderAccount.GetAddress(), depositAmount) //proposal becomes active + if err != nil { + return err + } + + for _, account := range accounts { + err = govKeeper.AddVote(ctx, proposal.ProposalId, account.SenderAccount.GetAddress(), govtypes.NewNonSplitVoteOption(govtypes.OptionYes)) + if err != nil { + return err + } + } + + return nil +} diff --git a/tests/e2e/setup.go b/tests/e2e/setup.go index a1eac9182a..677541d845 100644 --- a/tests/e2e/setup.go +++ b/tests/e2e/setup.go @@ -13,6 +13,10 @@ import ( ccv "github.com/cosmos/interchain-security/x/ccv/types" "github.com/cosmos/interchain-security/x/ccv/utils" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + icahostkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -23,6 +27,17 @@ import ( "github.com/stretchr/testify/suite" ) +var ( + // TestVersion defines a reusable interchainaccounts version string for testing purposes + TestVersion = string(icatypes.ModuleCdc.MustMarshalJSON(&icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: ibctesting.FirstConnectionID, + HostConnectionId: ibctesting.FirstConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, + })) +) + // CCVTestSuite is an in-mem test suite which implements the standard group of tests validating // the e2e functionality of ccv enabled chains. // Any method implemented for this struct will be ran when suite.Run() is called. @@ -37,6 +52,7 @@ type CCVTestSuite struct { providerConsState *ibctmtypes.ConsensusState path *ibctesting.Path transferPath *ibctesting.Path + icaPath *ibctesting.Path setupCallback SetupCallback } @@ -103,6 +119,11 @@ func (suite *CCVTestSuite) SetupTest() { suite.providerClient = consumerGenesis.ProviderClientState suite.providerConsState = consumerGenesis.ProviderConsensusState + // allow MsgSubmitProposal from admin module to be sent through ICA + hostICAGenesis := icatypes.DefaultHostGenesis() + hostICAGenesis.Params.AllowMessages = []string{"/interchain_security.ccv.adminmodule.v1.MsgSubmitProposal"} + icahostkeeper.InitGenesis(suite.consumerChain.GetContext(), suite.consumerApp.GetICAHostKeeper(), hostICAGenesis) + // create path for the CCV channel suite.path = ibctesting.NewPath(suite.consumerChain, suite.providerChain) @@ -149,6 +170,18 @@ func (suite *CCVTestSuite) SetupTest() { suite.transferPath.EndpointB.ChannelConfig.PortID = transfertypes.PortID suite.transferPath.EndpointA.ChannelConfig.Version = transfertypes.Version suite.transferPath.EndpointB.ChannelConfig.Version = transfertypes.Version + + controllerPortID, err := icatypes.NewControllerPortID(authtypes.NewModuleAddress(govtypes.ModuleName).String()) + suite.Require().NoError(err) + + // create path for the ica governance channel + suite.icaPath = ibctesting.NewPath(suite.consumerChain, suite.providerChain) + suite.icaPath.EndpointA.ChannelConfig.PortID = icatypes.PortID + suite.icaPath.EndpointB.ChannelConfig.PortID = controllerPortID + suite.icaPath.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + suite.icaPath.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + suite.icaPath.EndpointA.ChannelConfig.Version = TestVersion + suite.icaPath.EndpointB.ChannelConfig.Version = TestVersion } func (suite *CCVTestSuite) SetupCCVChannel() { @@ -206,3 +239,29 @@ func (suite *CCVTestSuite) SetupTransferChannel() { err = suite.transferPath.EndpointA.UpdateClient() suite.Require().NoError(err) } + +func (suite *CCVTestSuite) SetupGovernanceICAChannel() { + // ica path will use the same connection as ccv path + suite.icaPath.EndpointA.ClientID = suite.path.EndpointA.ClientID + suite.icaPath.EndpointA.ConnectionID = suite.path.EndpointA.ConnectionID + suite.icaPath.EndpointB.ClientID = suite.path.EndpointB.ClientID + suite.icaPath.EndpointB.ConnectionID = suite.path.EndpointB.ConnectionID + + // CCV channel handshake will automatically initiate ICA gov channel handshake on Confirm + // so ICA gov channel will be on stage INIT when CompleteSetupCCVChannel returns. + suite.icaPath.EndpointB.ChannelID = "channel-1" + + // Complete TRY, ACK, CONFIRM for ICA path + err := suite.icaPath.EndpointA.ChanOpenTry() + suite.Require().NoError(err) + + err = suite.icaPath.EndpointB.ChanOpenAck() + suite.Require().NoError(err) + + err = suite.icaPath.EndpointA.ChanOpenConfirm() + suite.Require().NoError(err) + + // ensure counterparty is up to date + err = suite.icaPath.EndpointB.UpdateClient() + suite.Require().NoError(err) +} diff --git a/tests/integration/steps_start_chains.go b/tests/integration/steps_start_chains.go index fca51fa254..417ed4f7ac 100644 --- a/tests/integration/steps_start_chains.go +++ b/tests/integration/steps_start_chains.go @@ -174,7 +174,7 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step { portB: "transfer", order: "unordered", channelA: 1, - channelB: 1, + channelB: 2, // channel for governance module ica will use channel-1, since ChanOpenInit for it is called before transfer channel }, state: State{}, }) diff --git a/testutil/e2e/interfaces.go b/testutil/e2e/interfaces.go index 0e34aacbe6..dffd2f69c8 100644 --- a/testutil/e2e/interfaces.go +++ b/testutil/e2e/interfaces.go @@ -13,6 +13,7 @@ import ( paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking/types" + icahostkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" ibctesting "github.com/cosmos/ibc-go/v3/testing" consumerkeeper "github.com/cosmos/interchain-security/x/ccv/consumer/keeper" providerkeeper "github.com/cosmos/interchain-security/x/ccv/provider/keeper" @@ -47,6 +48,7 @@ type ConsumerApp interface { BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock GetConsumerKeeper() consumerkeeper.Keeper + GetICAHostKeeper() icahostkeeper.Keeper GetSubspace(moduleName string) paramstypes.Subspace // diff --git a/testutil/keeper/expectations.go b/testutil/keeper/expectations.go index 7390115c7a..6bc635c6e2 100644 --- a/testutil/keeper/expectations.go +++ b/testutil/keeper/expectations.go @@ -4,7 +4,9 @@ import ( time "time" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" conntypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -50,6 +52,8 @@ func GetMocksForCreateConsumerClient(ctx sdk.Context, mocks *MockedKeepers, // GetMocksForMakeConsumerGenesis returns mock expectations needed to call MakeConsumerGenesis(). func GetMocksForMakeConsumerGenesis(ctx sdk.Context, mocks *MockedKeepers, unbondingTimeToInject time.Duration) []*gomock.Call { + govModuleAddress := authtypes.NewModuleAddress(govtypes.ModuleName) + return []*gomock.Call{ mocks.MockStakingKeeper.EXPECT().UnbondingTime(ctx).Return(unbondingTimeToInject).Times(1), @@ -57,6 +61,7 @@ func GetMocksForMakeConsumerGenesis(ctx sdk.Context, mocks *MockedKeepers, clienttypes.GetSelfHeight(ctx)).Return(&ibctmtypes.ConsensusState{}, nil).Times(1), mocks.MockStakingKeeper.EXPECT().IterateLastValidatorPowers(ctx, gomock.Any()).Times(1), + mocks.MockAccountKeeper.EXPECT().GetModuleAddress(govtypes.ModuleName).Return(govModuleAddress).Times(1), } } diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index d96a0b381d..bc43cbb87a 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -13,12 +13,13 @@ import ( types1 "github.com/cosmos/cosmos-sdk/x/capability/types" types2 "github.com/cosmos/cosmos-sdk/x/slashing/types" types3 "github.com/cosmos/cosmos-sdk/x/staking/types" - types4 "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - types5 "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - types6 "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + types4 "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + types5 "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + types6 "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + types7 "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" exported "github.com/cosmos/ibc-go/v3/modules/core/exported" gomock "github.com/golang/mock/gomock" - types7 "github.com/tendermint/tendermint/abci/types" + types8 "github.com/tendermint/tendermint/abci/types" ) // MockStakingKeeper is a mock of StakingKeeper interface. @@ -75,10 +76,10 @@ func (mr *MockStakingKeeperMockRecorder) GetValidatorByConsAddr(ctx, consAddr in } // GetValidatorUpdates mocks base method. -func (m *MockStakingKeeper) GetValidatorUpdates(ctx types.Context) []types7.ValidatorUpdate { +func (m *MockStakingKeeper) GetValidatorUpdates(ctx types.Context) []types8.ValidatorUpdate { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetValidatorUpdates", ctx) - ret0, _ := ret[0].([]types7.ValidatorUpdate) + ret0, _ := ret[0].([]types8.ValidatorUpdate) return ret0 } @@ -336,10 +337,10 @@ func (mr *MockChannelKeeperMockRecorder) ChanCloseInit(ctx, portID, channelID, c } // GetChannel mocks base method. -func (m *MockChannelKeeper) GetChannel(ctx types.Context, srcPort, srcChan string) (types6.Channel, bool) { +func (m *MockChannelKeeper) GetChannel(ctx types.Context, srcPort, srcChan string) (types7.Channel, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetChannel", ctx, srcPort, srcChan) - ret0, _ := ret[0].(types6.Channel) + ret0, _ := ret[0].(types7.Channel) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -454,10 +455,10 @@ func (m *MockConnectionKeeper) EXPECT() *MockConnectionKeeperMockRecorder { } // GetConnection mocks base method. -func (m *MockConnectionKeeper) GetConnection(ctx types.Context, connectionID string) (types5.ConnectionEnd, bool) { +func (m *MockConnectionKeeper) GetConnection(ctx types.Context, connectionID string) (types6.ConnectionEnd, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetConnection", ctx, connectionID) - ret0, _ := ret[0].(types5.ConnectionEnd) + ret0, _ := ret[0].(types6.ConnectionEnd) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -688,6 +689,20 @@ func (mr *MockAccountKeeperMockRecorder) GetModuleAccount(ctx, name interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAccount), ctx, name) } +// GetModuleAddress mocks base method. +func (m *MockAccountKeeper) GetModuleAddress(moduleName string) types.AccAddress { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetModuleAddress", moduleName) + ret0, _ := ret[0].(types.AccAddress) + return ret0 +} + +// GetModuleAddress indicates an expected call of GetModuleAddress. +func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(moduleName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAddress", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAddress), moduleName) +} + // MockIBCTransferKeeper is a mock of IBCTransferKeeper interface. type MockIBCTransferKeeper struct { ctrl *gomock.Controller @@ -712,7 +727,7 @@ func (m *MockIBCTransferKeeper) EXPECT() *MockIBCTransferKeeperMockRecorder { } // SendTransfer mocks base method. -func (m *MockIBCTransferKeeper) SendTransfer(ctx types.Context, sourcePort, sourceChannel string, token types.Coin, sender types.AccAddress, receiver string, timeoutHeight types4.Height, timeoutTimestamp uint64) error { +func (m *MockIBCTransferKeeper) SendTransfer(ctx types.Context, sourcePort, sourceChannel string, token types.Coin, sender types.AccAddress, receiver string, timeoutHeight types5.Height, timeoutTimestamp uint64) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SendTransfer", ctx, sourcePort, sourceChannel, token, sender, receiver, timeoutHeight, timeoutTimestamp) ret0, _ := ret[0].(error) @@ -749,10 +764,10 @@ func (m *MockIBCCoreKeeper) EXPECT() *MockIBCCoreKeeperMockRecorder { } // ChannelOpenInit mocks base method. -func (m *MockIBCCoreKeeper) ChannelOpenInit(goCtx context.Context, msg *types6.MsgChannelOpenInit) (*types6.MsgChannelOpenInitResponse, error) { +func (m *MockIBCCoreKeeper) ChannelOpenInit(goCtx context.Context, msg *types7.MsgChannelOpenInit) (*types7.MsgChannelOpenInitResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ChannelOpenInit", goCtx, msg) - ret0, _ := ret[0].(*types6.MsgChannelOpenInitResponse) + ret0, _ := ret[0].(*types7.MsgChannelOpenInitResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -828,3 +843,85 @@ func (mr *MockScopedKeeperMockRecorder) GetCapability(ctx, name interface{}) *go mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCapability", reflect.TypeOf((*MockScopedKeeper)(nil).GetCapability), ctx, name) } + +// MockICAControllerKeeper is a mock of ICAControllerKeeper interface. +type MockICAControllerKeeper struct { + ctrl *gomock.Controller + recorder *MockICAControllerKeeperMockRecorder +} + +// MockICAControllerKeeperMockRecorder is the mock recorder for MockICAControllerKeeper. +type MockICAControllerKeeperMockRecorder struct { + mock *MockICAControllerKeeper +} + +// NewMockICAControllerKeeper creates a new mock instance. +func NewMockICAControllerKeeper(ctrl *gomock.Controller) *MockICAControllerKeeper { + mock := &MockICAControllerKeeper{ctrl: ctrl} + mock.recorder = &MockICAControllerKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockICAControllerKeeper) EXPECT() *MockICAControllerKeeperMockRecorder { + return m.recorder +} + +// GetActiveChannelID mocks base method. +func (m *MockICAControllerKeeper) GetActiveChannelID(ctx types.Context, connectionID, portID string) (string, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetActiveChannelID", ctx, connectionID, portID) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetActiveChannelID indicates an expected call of GetActiveChannelID. +func (mr *MockICAControllerKeeperMockRecorder) GetActiveChannelID(ctx, connectionID, portID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveChannelID", reflect.TypeOf((*MockICAControllerKeeper)(nil).GetActiveChannelID), ctx, connectionID, portID) +} + +// GetInterchainAccountAddress mocks base method. +func (m *MockICAControllerKeeper) GetInterchainAccountAddress(ctx types.Context, connectionID, portID string) (string, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetInterchainAccountAddress", ctx, connectionID, portID) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetInterchainAccountAddress indicates an expected call of GetInterchainAccountAddress. +func (mr *MockICAControllerKeeperMockRecorder) GetInterchainAccountAddress(ctx, connectionID, portID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInterchainAccountAddress", reflect.TypeOf((*MockICAControllerKeeper)(nil).GetInterchainAccountAddress), ctx, connectionID, portID) +} + +// RegisterInterchainAccount mocks base method. +func (m *MockICAControllerKeeper) RegisterInterchainAccount(ctx types.Context, connectionID, owner string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RegisterInterchainAccount", ctx, connectionID, owner) + ret0, _ := ret[0].(error) + return ret0 +} + +// RegisterInterchainAccount indicates an expected call of RegisterInterchainAccount. +func (mr *MockICAControllerKeeperMockRecorder) RegisterInterchainAccount(ctx, connectionID, owner interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterInterchainAccount", reflect.TypeOf((*MockICAControllerKeeper)(nil).RegisterInterchainAccount), ctx, connectionID, owner) +} + +// SendTx mocks base method. +func (m *MockICAControllerKeeper) SendTx(ctx types.Context, chanCap *types1.Capability, connectionID, portID string, icaPacketData types4.InterchainAccountPacketData, timeoutTimestamp uint64) (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendTx", ctx, chanCap, connectionID, portID, icaPacketData, timeoutTimestamp) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SendTx indicates an expected call of SendTx. +func (mr *MockICAControllerKeeperMockRecorder) SendTx(ctx, chanCap, connectionID, portID, icaPacketData, timeoutTimestamp interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTx", reflect.TypeOf((*MockICAControllerKeeper)(nil).SendTx), ctx, chanCap, connectionID, portID, icaPacketData, timeoutTimestamp) +} diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 203f1750fe..6c3e77d942 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -82,22 +82,24 @@ type MockedKeepers struct { *MockBankKeeper *MockIBCTransferKeeper *MockIBCCoreKeeper + *MockICAControllerKeeper } // NewMockedKeepers instantiates a struct with pointers to properly instantiated mocked keepers. func NewMockedKeepers(ctrl *gomock.Controller) MockedKeepers { return MockedKeepers{ - MockScopedKeeper: NewMockScopedKeeper(ctrl), - MockChannelKeeper: NewMockChannelKeeper(ctrl), - MockPortKeeper: NewMockPortKeeper(ctrl), - MockConnectionKeeper: NewMockConnectionKeeper(ctrl), - MockClientKeeper: NewMockClientKeeper(ctrl), - MockStakingKeeper: NewMockStakingKeeper(ctrl), - MockSlashingKeeper: NewMockSlashingKeeper(ctrl), - MockAccountKeeper: NewMockAccountKeeper(ctrl), - MockBankKeeper: NewMockBankKeeper(ctrl), - MockIBCTransferKeeper: NewMockIBCTransferKeeper(ctrl), - MockIBCCoreKeeper: NewMockIBCCoreKeeper(ctrl), + MockScopedKeeper: NewMockScopedKeeper(ctrl), + MockChannelKeeper: NewMockChannelKeeper(ctrl), + MockPortKeeper: NewMockPortKeeper(ctrl), + MockConnectionKeeper: NewMockConnectionKeeper(ctrl), + MockClientKeeper: NewMockClientKeeper(ctrl), + MockStakingKeeper: NewMockStakingKeeper(ctrl), + MockSlashingKeeper: NewMockSlashingKeeper(ctrl), + MockAccountKeeper: NewMockAccountKeeper(ctrl), + MockBankKeeper: NewMockBankKeeper(ctrl), + MockIBCTransferKeeper: NewMockIBCTransferKeeper(ctrl), + MockIBCCoreKeeper: NewMockIBCCoreKeeper(ctrl), + MockICAControllerKeeper: NewMockICAControllerKeeper(ctrl), } } @@ -116,6 +118,8 @@ func NewInMemProviderKeeper(params InMemKeeperParams, mocks MockedKeepers) provi mocks.MockStakingKeeper, mocks.MockSlashingKeeper, mocks.MockAccountKeeper, + mocks.MockICAControllerKeeper, + mocks.MockScopedKeeper, "", ) } diff --git a/third_party/proto/cosmos/gov/v1beta1/gov.proto b/third_party/proto/cosmos/gov/v1beta1/gov.proto new file mode 100644 index 0000000000..344b5ada19 --- /dev/null +++ b/third_party/proto/cosmos/gov/v1beta1/gov.proto @@ -0,0 +1,200 @@ +syntax = "proto3"; +package cosmos.gov.v1beta1; + +import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types"; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.stringer_all) = false; +option (gogoproto.goproto_getters_all) = false; + +// VoteOption enumerates the valid vote options for a given governance proposal. +enum VoteOption { + option (gogoproto.goproto_enum_prefix) = false; + + // VOTE_OPTION_UNSPECIFIED defines a no-op vote option. + VOTE_OPTION_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "OptionEmpty"]; + // VOTE_OPTION_YES defines a yes vote option. + VOTE_OPTION_YES = 1 [(gogoproto.enumvalue_customname) = "OptionYes"]; + // VOTE_OPTION_ABSTAIN defines an abstain vote option. + VOTE_OPTION_ABSTAIN = 2 [(gogoproto.enumvalue_customname) = "OptionAbstain"]; + // VOTE_OPTION_NO defines a no vote option. + VOTE_OPTION_NO = 3 [(gogoproto.enumvalue_customname) = "OptionNo"]; + // VOTE_OPTION_NO_WITH_VETO defines a no with veto vote option. + VOTE_OPTION_NO_WITH_VETO = 4 [(gogoproto.enumvalue_customname) = "OptionNoWithVeto"]; +} + +// WeightedVoteOption defines a unit of vote for vote split. +// +// Since: cosmos-sdk 0.43 +message WeightedVoteOption { + VoteOption option = 1; + string weight = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"weight\"" + ]; +} + +// TextProposal defines a standard text proposal whose changes need to be +// manually updated in case of approval. +message TextProposal { + option (cosmos_proto.implements_interface) = "Content"; + + option (gogoproto.equal) = true; + + string title = 1; + string description = 2; +} + +// Deposit defines an amount deposited by an account address to an active +// proposal. +message Deposit { + option (gogoproto.goproto_getters) = false; + option (gogoproto.equal) = false; + + uint64 proposal_id = 1 [(gogoproto.moretags) = "yaml:\"proposal_id\""]; + string depositor = 2; + repeated cosmos.base.v1beta1.Coin amount = 3 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} + +// Proposal defines the core field members of a governance proposal. +message Proposal { + option (gogoproto.equal) = true; + + uint64 proposal_id = 1 [(gogoproto.jsontag) = "id", (gogoproto.moretags) = "yaml:\"id\""]; + google.protobuf.Any content = 2 [(cosmos_proto.accepts_interface) = "Content"]; + ProposalStatus status = 3 [(gogoproto.moretags) = "yaml:\"proposal_status\""]; + TallyResult final_tally_result = 4 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"final_tally_result\""]; + google.protobuf.Timestamp submit_time = 5 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"submit_time\""]; + google.protobuf.Timestamp deposit_end_time = 6 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"deposit_end_time\""]; + repeated cosmos.base.v1beta1.Coin total_deposit = 7 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"total_deposit\"" + ]; + google.protobuf.Timestamp voting_start_time = 8 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"voting_start_time\""]; + google.protobuf.Timestamp voting_end_time = 9 + [(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"voting_end_time\""]; +} + +// ProposalStatus enumerates the valid statuses of a proposal. +enum ProposalStatus { + option (gogoproto.goproto_enum_prefix) = false; + + // PROPOSAL_STATUS_UNSPECIFIED defines the default propopsal status. + PROPOSAL_STATUS_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "StatusNil"]; + // PROPOSAL_STATUS_DEPOSIT_PERIOD defines a proposal status during the deposit + // period. + PROPOSAL_STATUS_DEPOSIT_PERIOD = 1 [(gogoproto.enumvalue_customname) = "StatusDepositPeriod"]; + // PROPOSAL_STATUS_VOTING_PERIOD defines a proposal status during the voting + // period. + PROPOSAL_STATUS_VOTING_PERIOD = 2 [(gogoproto.enumvalue_customname) = "StatusVotingPeriod"]; + // PROPOSAL_STATUS_PASSED defines a proposal status of a proposal that has + // passed. + PROPOSAL_STATUS_PASSED = 3 [(gogoproto.enumvalue_customname) = "StatusPassed"]; + // PROPOSAL_STATUS_REJECTED defines a proposal status of a proposal that has + // been rejected. + PROPOSAL_STATUS_REJECTED = 4 [(gogoproto.enumvalue_customname) = "StatusRejected"]; + // PROPOSAL_STATUS_FAILED defines a proposal status of a proposal that has + // failed. + PROPOSAL_STATUS_FAILED = 5 [(gogoproto.enumvalue_customname) = "StatusFailed"]; +} + +// TallyResult defines a standard tally for a governance proposal. +message TallyResult { + option (gogoproto.equal) = true; + + string yes = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; + string abstain = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; + string no = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false]; + string no_with_veto = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"no_with_veto\"" + ]; +} + +// Vote defines a vote on a governance proposal. +// A Vote consists of a proposal ID, the voter, and the vote option. +message Vote { + option (gogoproto.goproto_stringer) = false; + option (gogoproto.equal) = false; + + uint64 proposal_id = 1 [(gogoproto.moretags) = "yaml:\"proposal_id\""]; + string voter = 2; + // Deprecated: Prefer to use `options` instead. This field is set in queries + // if and only if `len(options) == 1` and that option has weight 1. In all + // other cases, this field will default to VOTE_OPTION_UNSPECIFIED. + VoteOption option = 3 [deprecated = true]; + // Since: cosmos-sdk 0.43 + repeated WeightedVoteOption options = 4 [(gogoproto.nullable) = false]; +} + +// DepositParams defines the params for deposits on governance proposals. +message DepositParams { + // Minimum deposit for a proposal to enter voting period. + repeated cosmos.base.v1beta1.Coin min_deposit = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"min_deposit\"", + (gogoproto.jsontag) = "min_deposit,omitempty" + ]; + + // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 + // months. + google.protobuf.Duration max_deposit_period = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.jsontag) = "max_deposit_period,omitempty", + (gogoproto.moretags) = "yaml:\"max_deposit_period\"" + ]; +} + +// VotingParams defines the params for voting on governance proposals. +message VotingParams { + // Length of the voting period. + google.protobuf.Duration voting_period = 1 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.jsontag) = "voting_period,omitempty", + (gogoproto.moretags) = "yaml:\"voting_period\"" + ]; +} + +// TallyParams defines the params for tallying votes on governance proposals. +message TallyParams { + // Minimum percentage of total stake needed to vote for a result to be + // considered valid. + bytes quorum = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "quorum,omitempty" + ]; + + // Minimum proportion of Yes votes for proposal to pass. Default value: 0.5. + bytes threshold = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "threshold,omitempty" + ]; + + // Minimum value of Veto votes to Total votes ratio for proposal to be + // vetoed. Default value: 1/3. + bytes veto_threshold = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "veto_threshold,omitempty", + (gogoproto.moretags) = "yaml:\"veto_threshold\"" + ]; +} diff --git a/x/ccv/adminmodule/README.md b/x/ccv/adminmodule/README.md new file mode 100644 index 0000000000..e6900a580c --- /dev/null +++ b/x/ccv/adminmodule/README.md @@ -0,0 +1,8 @@ +# Admin module +This module allows admin accounts to submit governance proposals that will be immediately executed in the first EndBlock. + +Originally, this module is taken from the [Composer repository](https://github.com/cosmos/composer). +All credit and thanks go to the original authors. + +To enable provider driven governance of interchain security, some modifications have been made in EndBlocker. The interchain account of the provider's governance module should be able to submit proposals to the admin module on the consumer chain side. To achieve this, the interchain account address of the provider's governance module is added as an admin in the EndBlocker of the admin module. +Also, separate whitelists are introduced to specify which types of proposals are allowed to be submitted by provider's governance module admin and all other admins from the consumer chain. \ No newline at end of file diff --git a/x/ccv/adminmodule/abci.go b/x/ccv/adminmodule/abci.go new file mode 100644 index 0000000000..6f9e38ef16 --- /dev/null +++ b/x/ccv/adminmodule/abci.go @@ -0,0 +1,109 @@ +package adminmodule + +import ( + "fmt" + "time" + + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/keeper" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + ccv "github.com/cosmos/interchain-security/x/ccv/types" +) + +// EndBlocker called every block, process inflation, update validator set. +func EndBlocker(ctx sdk.Context, keeper keeper.Keeper, icahostkeeper types.ICAHostKeeper, consumerkeeper types.ConsumerKeeper) { + defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker) + + logger := keeper.Logger(ctx) + + addGovernanceModuleAdmin(ctx, keeper, icahostkeeper, consumerkeeper) + + // fetch active proposals whose voting periods have ended (are passed the block time) + keeper.IterateActiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal govtypes.Proposal) bool { + var logMsg, tagValue string + + handler := keeper.Router().GetRoute(proposal.ProposalRoute()) + cacheCtx, writeCache := ctx.CacheContext() + + // The proposal handler may execute state mutating logic depending + // on the proposal content. If the handler fails, no state mutation + // is written and the error message is logged. + err := handler(cacheCtx, proposal.GetContent()) + if err == nil { + logMsg = "passed" + proposal.Status = govtypes.StatusPassed + tagValue = govtypes.AttributeValueProposalPassed + + // The cached context is created with a new EventManager. However, since + // the proposal handler execution was successful, we want to track/keep + // any events emitted, so we re-emit to "merge" the events into the + // original Context's EventManager. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + + // write state to the underlying multi-store + writeCache() + } else { + proposal.Status = govtypes.StatusFailed + tagValue = govtypes.AttributeValueProposalFailed + logMsg = fmt.Sprintf("proposal failed on execution: %s", err) + } + + keeper.SetProposal(ctx, proposal) + keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime) + + keeper.AddToArchive(ctx, proposal) + + logger.Info( + "proposal tallied", + "proposal", proposal.ProposalId, + "title", proposal.GetTitle(), + "result", logMsg, + ) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeAdminProposal, + sdk.NewAttribute(govtypes.AttributeKeyProposalID, fmt.Sprintf("%d", proposal.ProposalId)), + sdk.NewAttribute(govtypes.AttributeKeyProposalResult, tagValue), + ), + ) + return false + }) +} + +func addGovernanceModuleAdmin(ctx sdk.Context, keeper keeper.Keeper, icahostkeeper types.ICAHostKeeper, consumerkeeper types.ConsumerKeeper) { + if keeper.GetProviderICAAdmin(ctx) != "" { + return + } + + providerChannel, found := consumerkeeper.GetProviderChannel(ctx) + if !found { + return + } + + connHops, err := consumerkeeper.GetConnectionHops(ctx, ccv.ConsumerPortID, providerChannel) + if err != nil || len(connHops) == 0 { + return + } + + providerGovModAddress, found := consumerkeeper.GetProviderGovernanceAddress(ctx) + if !found { + return + } + + portID, err := icatypes.NewControllerPortID(providerGovModAddress) + if err != nil { + return + } + + govModICAAddress, found := icahostkeeper.GetInterchainAccountAddress(ctx, connHops[0], portID) + if !found { + return + } + + keeper.SetAdmin(ctx, govModICAAddress) + keeper.SetProviderICAAdmin(ctx, govModICAAddress) +} diff --git a/x/ccv/adminmodule/client/cli/helper.go b/x/ccv/adminmodule/client/cli/helper.go new file mode 100644 index 0000000000..8fa504e91a --- /dev/null +++ b/x/ccv/adminmodule/client/cli/helper.go @@ -0,0 +1,44 @@ +package cli + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + + "github.com/spf13/pflag" + + gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" +) + +func parseSubmitProposalFlags(fs *pflag.FlagSet) (*proposal, error) { + proposal := &proposal{} + proposalFile, _ := fs.GetString(FlagProposal) + + if proposalFile == "" { + proposalType, _ := fs.GetString(FlagProposalType) + + proposal.Title, _ = fs.GetString(FlagTitle) + proposal.Description, _ = fs.GetString(FlagDescription) + proposal.Type = gcutils.NormalizeProposalType(proposalType) + return proposal, nil + } + + for _, flag := range ProposalFlags { + if v, _ := fs.GetString(flag); v != "" { + return nil, fmt.Errorf("--%s flag provided alongside --proposal, which is a noop", flag) + } + } + + contents, err := os.ReadFile(filepath.Clean(proposalFile)) + if err != nil { + return nil, err + } + + err = json.Unmarshal(contents, proposal) + if err != nil { + return nil, err + } + + return proposal, nil +} diff --git a/x/ccv/adminmodule/client/cli/query.go b/x/ccv/adminmodule/client/cli/query.go new file mode 100644 index 0000000000..676b0e0846 --- /dev/null +++ b/x/ccv/adminmodule/client/cli/query.go @@ -0,0 +1,32 @@ +package cli + +import ( + "fmt" + // "strings" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + // "github.com/cosmos/cosmos-sdk/client/flags" + // sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd(queryRoute string) *cobra.Command { + // Group adminmodule queries under a subcommand + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + // this line is used by starport scaffolding # 1 + + cmd.AddCommand(CmdAdmins(), CmdArchivedProposals()) + + return cmd +} diff --git a/x/ccv/adminmodule/client/cli/query_admins.go b/x/ccv/adminmodule/client/cli/query_admins.go new file mode 100644 index 0000000000..0be622645a --- /dev/null +++ b/x/ccv/adminmodule/client/cli/query_admins.go @@ -0,0 +1,43 @@ +package cli + +import ( + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +var _ = strconv.Itoa(0) + +func CmdAdmins() *cobra.Command { + cmd := &cobra.Command{ + Use: "admins", + Short: "Query admins", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryAdminsRequest{} + + res, err := queryClient.Admins(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/adminmodule/client/cli/query_archived_proposals.go b/x/ccv/adminmodule/client/cli/query_archived_proposals.go new file mode 100644 index 0000000000..c06b970b53 --- /dev/null +++ b/x/ccv/adminmodule/client/cli/query_archived_proposals.go @@ -0,0 +1,43 @@ +package cli + +import ( + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +var _ = strconv.Itoa(0) + +func CmdArchivedProposals() *cobra.Command { + cmd := &cobra.Command{ + Use: "archivedproposals", + Short: "Query archived proposals", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryArchivedProposalsRequest{} + + res, err := queryClient.ArchivedProposals(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/adminmodule/client/cli/tx.go b/x/ccv/adminmodule/client/cli/tx.go new file mode 100644 index 0000000000..50764d155c --- /dev/null +++ b/x/ccv/adminmodule/client/cli/tx.go @@ -0,0 +1,37 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd(propCmds []*cobra.Command) *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(CmdDeleteAdmin()) + + cmd.AddCommand(CmdAddAdmin()) + + cmdSubmitProp := CmdSubmitProposal() + for _, propCmd := range propCmds { + flags.AddTxFlagsToCmd(propCmd) + cmdSubmitProp.AddCommand(propCmd) + } + + cmd.AddCommand(cmdSubmitProp) + // this line is used by starport scaffolding # 1 + + return cmd +} diff --git a/x/ccv/adminmodule/client/cli/tx_add_admin.go b/x/ccv/adminmodule/client/cli/tx_add_admin.go new file mode 100644 index 0000000000..fc44b44309 --- /dev/null +++ b/x/ccv/adminmodule/client/cli/tx_add_admin.go @@ -0,0 +1,45 @@ +package cli + +import ( + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +var _ = strconv.Itoa(0) + +func CmdAddAdmin() *cobra.Command { + cmd := &cobra.Command{ + Use: "add-admin [admin]", + Short: "Broadcast message AddAdmin", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + newAdmin, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgAddAdmin(clientCtx.GetFromAddress(), newAdmin) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/adminmodule/client/cli/tx_delete_admin.go b/x/ccv/adminmodule/client/cli/tx_delete_admin.go new file mode 100644 index 0000000000..b9e14689db --- /dev/null +++ b/x/ccv/adminmodule/client/cli/tx_delete_admin.go @@ -0,0 +1,44 @@ +package cli + +import ( + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +var _ = strconv.Itoa(0) + +func CmdDeleteAdmin() *cobra.Command { + cmd := &cobra.Command{ + Use: "delete-admin [admin]", + Short: "Broadcast message DeleteAdmin", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + removeAdmin, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgDeleteAdmin(clientCtx.GetFromAddress(), removeAdmin) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/adminmodule/client/cli/tx_software_upgrade_proposal.go b/x/ccv/adminmodule/client/cli/tx_software_upgrade_proposal.go new file mode 100644 index 0000000000..73822e72fb --- /dev/null +++ b/x/ccv/adminmodule/client/cli/tx_software_upgrade_proposal.go @@ -0,0 +1,158 @@ +package cli + +import ( + "fmt" + "time" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/x/gov/client/cli" + gov "github.com/cosmos/cosmos-sdk/x/gov/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +const ( + // TimeFormat specifies ISO UTC format for submitting the time for a new upgrade proposal + TimeFormat = "2006-01-02T15:04:05Z" + + FlagUpgradeHeight = "upgrade-height" + FlagUpgradeTime = "upgrade-time" + FlagUpgradeInfo = "upgrade-info" +) + +// NewCmdSubmitUpgradeProposal implements a command handler for submitting a software upgrade proposal transaction. +func NewCmdSubmitUpgradeProposal() *cobra.Command { + cmd := &cobra.Command{ + Use: "software-upgrade [name] (--upgrade-height [height] | --upgrade-time [time]) (--upgrade-info [info]) [flags]", + Args: cobra.ExactArgs(1), + Short: "Submit a software upgrade proposal", + Long: "Submit a software upgrade.\n" + + "Please specify a unique name and height OR time for the upgrade to take effect.\n" + + "You may include info to reference a binary download link, in a format compatible with: https://github.com/cosmos/cosmos-sdk/tree/master/cosmovisor", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + name := args[0] + content, err := parseArgsToContent(cmd, name) + if err != nil { + return err + } + + from := clientCtx.GetFromAddress() + + msg, err := types.NewMsgSubmitProposal(content, from) + if err != nil { + return err + } + + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(cli.FlagTitle, "", "title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "description of proposal") + cmd.Flags().Int64(FlagUpgradeHeight, 0, "The height at which the upgrade must happen (not to be used together with --upgrade-time)") + cmd.Flags().String(FlagUpgradeTime, "", fmt.Sprintf("The time at which the upgrade must happen (ex. %s) (not to be used together with --upgrade-height)", TimeFormat)) + cmd.Flags().String(FlagUpgradeInfo, "", "Optional info for the planned upgrade such as commit hash, etc.") + + return cmd +} + +// NewCmdSubmitCancelUpgradeProposal implements a command handler for submitting a software upgrade cancel proposal transaction. +func NewCmdSubmitCancelUpgradeProposal() *cobra.Command { + cmd := &cobra.Command{ + Use: "cancel-software-upgrade [flags]", + Args: cobra.ExactArgs(0), + Short: "Cancel the current software upgrade proposal", + Long: "Cancel a software upgrade.", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + from := clientCtx.GetFromAddress() + + title, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return err + } + + description, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return err + } + + content := upgradetypes.NewCancelSoftwareUpgradeProposal(title, description) + + msg, err := types.NewMsgSubmitProposal(content, from) + if err != nil { + return err + } + + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(cli.FlagTitle, "", "title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "description of proposal") + _ = cmd.MarkFlagRequired(cli.FlagTitle) + _ = cmd.MarkFlagRequired(cli.FlagDescription) + + return cmd +} + +func parseArgsToContent(cmd *cobra.Command, name string) (gov.Content, error) { + title, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return nil, err + } + + description, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return nil, err + } + + height, err := cmd.Flags().GetInt64(FlagUpgradeHeight) + if err != nil { + return nil, err + } + + timeStr, err := cmd.Flags().GetString(FlagUpgradeTime) + if err != nil { + return nil, err + } + + if height != 0 && len(timeStr) != 0 { + return nil, fmt.Errorf("only one of --upgrade-time or --upgrade-height should be specified") + } + + var upgradeTime time.Time + if len(timeStr) != 0 { + upgradeTime, err = time.Parse(TimeFormat, timeStr) + if err != nil { + return nil, err + } + } + + info, err := cmd.Flags().GetString(FlagUpgradeInfo) + if err != nil { + return nil, err + } + + plan := upgradetypes.Plan{Name: name, Time: upgradeTime, Height: height, Info: info} + content := upgradetypes.NewSoftwareUpgradeProposal(title, description, plan) + return content, nil +} diff --git a/x/ccv/adminmodule/client/cli/tx_submit_param_change_proposal.go b/x/ccv/adminmodule/client/cli/tx_submit_param_change_proposal.go new file mode 100644 index 0000000000..396dc1d213 --- /dev/null +++ b/x/ccv/adminmodule/client/cli/tx_submit_param_change_proposal.go @@ -0,0 +1,83 @@ +package cli + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/version" + paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils" + paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +// NewSubmitParamChangeProposalTxCmd returns a CLI command handler for creating +// a parameter change proposal governance transaction. +func NewSubmitParamChangeProposalTxCmd() *cobra.Command { + return &cobra.Command{ + Use: "param-change [proposal-file]", + Args: cobra.ExactArgs(1), + Short: "Submit a parameter change proposal", + Long: strings.TrimSpace( + fmt.Sprintf(`Submit a parameter proposal . +The proposal details must be supplied via a JSON file. For values that contains +objects, only non-empty fields will be updated. + +IMPORTANT: Currently parameter changes are evaluated but not validated, so it is +very important that any "value" change is valid (ie. correct type and within bounds) +for its respective parameter, eg. "MaxValidators" should be an integer and not a decimal. + +Proper vetting of a parameter change proposal should prevent this from happening +(no deposits should occur during the governance process), but it should be noted +regardless. + +Example: +$ %s tx adminmodule submit-proposal param-change --from= + +Where proposal.json contains: + +{ + "title": "Staking Param Change", + "description": "Update max validators", + "changes": [ + { + "subspace": "staking", + "key": "MaxValidators", + "value": 105 + } + ] +} +`, + version.AppName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + proposal, err := paramscutils.ParseParamChangeProposalJSON(clientCtx.LegacyAmino, args[0]) + if err != nil { + return err + } + + from := clientCtx.GetFromAddress() + content := paramproposal.NewParameterChangeProposal( + proposal.Title, proposal.Description, proposal.Changes.ToParamChanges(), + ) + + msg, err := types.NewMsgSubmitProposal(content, from) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} diff --git a/x/ccv/adminmodule/client/cli/tx_submit_pool_spend_proposal.go b/x/ccv/adminmodule/client/cli/tx_submit_pool_spend_proposal.go new file mode 100644 index 0000000000..aef76033c9 --- /dev/null +++ b/x/ccv/adminmodule/client/cli/tx_submit_pool_spend_proposal.go @@ -0,0 +1,99 @@ +package cli + +import ( + "fmt" + "os" + "strings" + + "path/filepath" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + "github.com/spf13/cobra" +) + +// NewSubmitPoolSpendProposalTxCmd implements the command to submit a community-pool-spend proposal +func NewSubmitPoolSpendProposalTxCmd() *cobra.Command { + bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix() + + cmd := &cobra.Command{ + Use: "community-pool-spend [proposal-file]", + Args: cobra.ExactArgs(1), + Short: "Submit a community pool spend proposal", + Long: strings.TrimSpace( + fmt.Sprintf(`Submit a community pool spend proposal. +The proposal details must be supplied via a JSON file. + +Example: +$ %s tx adminmodule submit-proposal community-pool-spend --from= + +Where proposal.json contains: + +{ + "title": "Community Pool Spend", + "description": "Pay me some Atoms!", + "recipient": "%s1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq", + "amount": "1000stake" +} +`, + version.AppName, bech32PrefixAccAddr, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + proposal, err := ParseCommunityPoolSpendProposalWithDeposit(clientCtx.JSONCodec, args[0]) + if err != nil { + return err + } + + amount, err := sdk.ParseCoinsNormalized(proposal.Amount) + if err != nil { + return err + } + + from := clientCtx.GetFromAddress() + recpAddr, err := sdk.AccAddressFromBech32(proposal.Recipient) + if err != nil { + return err + } + content := distrtypes.NewCommunityPoolSpendProposal(proposal.Title, proposal.Description, recpAddr, amount) + + msg, err := types.NewMsgSubmitProposal(content, from) + if err != nil { + return err + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + return cmd +} + +// ParseCommunityPoolSpendProposalWithDeposit reads and parses a CommunityPoolSpendProposalWithDeposit from a file. +func ParseCommunityPoolSpendProposalWithDeposit(cdc codec.JSONCodec, proposalFile string) (distrtypes.CommunityPoolSpendProposalWithDeposit, error) { + proposal := distrtypes.CommunityPoolSpendProposalWithDeposit{} + + contents, err := os.ReadFile(filepath.Clean(proposalFile)) + if err != nil { + return proposal, err + } + + if err = cdc.UnmarshalJSON(contents, &proposal); err != nil { + return proposal, err + } + + return proposal, nil +} diff --git a/x/ccv/adminmodule/client/cli/tx_submit_proposal.go b/x/ccv/adminmodule/client/cli/tx_submit_proposal.go new file mode 100644 index 0000000000..adaad6aecd --- /dev/null +++ b/x/ccv/adminmodule/client/cli/tx_submit_proposal.go @@ -0,0 +1,102 @@ +package cli + +import ( + "fmt" + "strconv" + "strings" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/version" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +var _ = strconv.Itoa(0) + +// Proposal flags +const ( + FlagTitle = "title" + FlagDescription = "description" + FlagProposalType = "type" + FlagProposal = "proposal" +) + +type proposal struct { + Title string + Description string + Type string +} + +// ProposalFlags defines the core required fields of a proposal. It is used to +// verify that these values are not provided in conjunction with a JSON proposal +// file. +var ProposalFlags = []string{ + FlagTitle, + FlagDescription, + FlagProposalType, +} + +func CmdSubmitProposal() *cobra.Command { + cmd := &cobra.Command{ + Use: "submit-proposal", + Short: "Submit a proposal", + Long: strings.TrimSpace( + fmt.Sprintf(`Submit a proposal. +Proposal title, description, type and can be given directly or through a proposal JSON file. + +Example: +$ %s adminmodule submit-proposal --proposal="path/to/proposal.json" --from mykey + +Where proposal.json contains: + +{ + "title": "Test Proposal", + "description": "My awesome proposal", + "type": "Text" +} + +Which is equivalent to: + +$ %s tx adminmodule submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --from mykey +`, + version.AppName, version.AppName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + proposal, err := parseSubmitProposalFlags(cmd.Flags()) + if err != nil { + return fmt.Errorf("failed to parse proposal: %w", err) + } + + content := govtypes.ContentFromProposalType(proposal.Title, proposal.Description, proposal.Type) + + msg, err := types.NewMsgSubmitProposal(content, clientCtx.GetFromAddress()) + if err != nil { + return fmt.Errorf("invalid message: %w", err) + } + + if err = msg.ValidateBasic(); err != nil { + return fmt.Errorf("message validation failed: %w", err) + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(FlagTitle, "", "The proposal title") + cmd.Flags().String(FlagDescription, "", "The proposal description") + cmd.Flags().String(FlagProposalType, "", "The proposal Type") + cmd.Flags().String(FlagProposal, "", "Proposal file path (if this path is given, other proposal flags are ignored)") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/adminmodule/client/rest/query.go b/x/ccv/adminmodule/client/rest/query.go new file mode 100644 index 0000000000..4d68c132a5 --- /dev/null +++ b/x/ccv/adminmodule/client/rest/query.go @@ -0,0 +1,52 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + "github.com/gorilla/mux" +) + +func registerQueryRoutes(clientCtx client.Context, r *mux.Router) { + // curl -X GET "http://localhost:1317/adminmodule/admins" + r.HandleFunc("/adminmodule/admins", queryAdminsHandlerFn(clientCtx)).Methods("GET") + // curl -X GET "http://localhost:1317/adminmodule/archivedproposals" + r.HandleFunc("/adminmodule/archivedproposals", queryArchivedProposalsHandlerFn(clientCtx)).Methods("GET") +} + +func queryAdminsHandlerFn(clientCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r) + if !ok { + return + } + + res, height, err := clientCtx.Query(fmt.Sprintf("custom/adminmodule/%s", types.QueryAdmins)) + if rest.CheckNotFoundError(w, err) { + return + } + + clientCtx = clientCtx.WithHeight(height) + rest.PostProcessResponse(w, clientCtx, res) + } +} + +func queryArchivedProposalsHandlerFn(clientCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r) + if !ok { + return + } + + res, height, err := clientCtx.Query(fmt.Sprintf("custom/adminmodule/%s", types.QueryArchivedProposals)) + if rest.CheckNotFoundError(w, err) { + return + } + + clientCtx = clientCtx.WithHeight(height) + rest.PostProcessResponse(w, clientCtx, res) + } +} diff --git a/x/ccv/adminmodule/client/rest/rest.go b/x/ccv/adminmodule/client/rest/rest.go new file mode 100644 index 0000000000..dd880c8a01 --- /dev/null +++ b/x/ccv/adminmodule/client/rest/rest.go @@ -0,0 +1,28 @@ +package rest + +import ( + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client" + clientrest "github.com/cosmos/cosmos-sdk/client/rest" + sdkrest "github.com/cosmos/cosmos-sdk/types/rest" + govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" +) + +func RegisterHandlers(clientCtx client.Context, rtr *mux.Router, phs []govrest.ProposalRESTHandler) { + r := clientrest.WithHTTPDeprecationHeaders(rtr) + registerQueryRoutes(clientCtx, r) + registerTxHandlers(clientCtx, r, phs) +} + +// AddAdminReq ... +type AddAdminReq struct { + BaseReq sdkrest.BaseReq `json:"base_req" yaml:"base_req"` + Admin string `json:"admin" yaml:"admin"` +} + +// DeleteAdminReq ... +type DeleteAdminReq struct { + BaseReq sdkrest.BaseReq `json:"base_req" yaml:"base_req"` + Admin string `json:"admin" yaml:"admin"` +} diff --git a/x/ccv/adminmodule/client/rest/tx.go b/x/ccv/adminmodule/client/rest/tx.go new file mode 100644 index 0000000000..a35b78ba17 --- /dev/null +++ b/x/ccv/adminmodule/client/rest/tx.go @@ -0,0 +1,87 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +func registerTxHandlers(clientCtx client.Context, r *mux.Router, phs []govrest.ProposalRESTHandler) { + propSubRtr := r.PathPrefix("/adminmodule/proposals").Subrouter() + for _, ph := range phs { + propSubRtr.HandleFunc(fmt.Sprintf("/%s", ph.SubRoute), ph.Handler).Methods("POST") + } + + r.HandleFunc("/adminmodule/addadmin", newAddAdminHandlerFn(clientCtx)).Methods("POST") + r.HandleFunc("/adminmodule/deleteadmin", newDeleteAdminHandlerFn(clientCtx)).Methods("POST") +} + +func newAddAdminHandlerFn(clientCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req AddAdminReq + if !rest.ReadRESTReq(w, r, clientCtx.LegacyAmino, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if rest.CheckBadRequestError(w, err) { + return + } + + newAdmin, err := sdk.AccAddressFromBech32(req.Admin) + if rest.CheckBadRequestError(w, err) { + return + } + + msg := types.NewMsgAddAdmin(fromAddr, newAdmin) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + tx.WriteGeneratedTxResponse(clientCtx, w, req.BaseReq, msg) + } +} + +func newDeleteAdminHandlerFn(clientCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req AddAdminReq + if !rest.ReadRESTReq(w, r, clientCtx.LegacyAmino, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if rest.CheckBadRequestError(w, err) { + return + } + + removeAdmin, err := sdk.AccAddressFromBech32(req.Admin) + if rest.CheckBadRequestError(w, err) { + return + } + + msg := types.NewMsgDeleteAdmin(fromAddr, removeAdmin) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + tx.WriteGeneratedTxResponse(clientCtx, w, req.BaseReq, msg) + } +} diff --git a/x/ccv/adminmodule/genesis.go b/x/ccv/adminmodule/genesis.go new file mode 100644 index 0000000000..78914c8dc9 --- /dev/null +++ b/x/ccv/adminmodule/genesis.go @@ -0,0 +1,23 @@ +package adminmodule + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/keeper" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +// InitGenesis initializes the capability module's state from a provided genesis +// state. +func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { + for _, admin := range genState.GetAdmins() { + k.SetAdmin(ctx, admin) + } + k.SetProposalID(ctx, 1) +} + +// ExportGenesis returns the capability module's exported genesis. +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { + return &types.GenesisState{ + Admins: k.GetAdmins(ctx), + } +} diff --git a/x/ccv/adminmodule/handler.go b/x/ccv/adminmodule/handler.go new file mode 100644 index 0000000000..507d315c0a --- /dev/null +++ b/x/ccv/adminmodule/handler.go @@ -0,0 +1,38 @@ +package adminmodule + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/keeper" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +// NewHandler ... +func NewHandler(k keeper.Keeper) sdk.Handler { + msgServer := keeper.NewMsgServerImpl(k) + + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case *types.MsgDeleteAdmin: + res, err := msgServer.DeleteAdmin(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + + case *types.MsgAddAdmin: + res, err := msgServer.AddAdmin(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + + case *types.MsgSubmitProposal: + res, err := msgServer.SubmitProposal(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + // this line is used by starport scaffolding # 1 + + default: + errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) + } + } +} diff --git a/x/ccv/adminmodule/keeper/admins.go b/x/ccv/adminmodule/keeper/admins.go new file mode 100644 index 0000000000..a7dee1d098 --- /dev/null +++ b/x/ccv/adminmodule/keeper/admins.go @@ -0,0 +1,54 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +func (k Keeper) GetAdmins(ctx sdk.Context) []string { + admins := make([]string, 0) + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.AdminKey)) + + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + admins = append(admins, string(iterator.Value())) + } + + return admins +} + +func (k Keeper) SetAdmin(ctx sdk.Context, admin string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.AdminKey)) + store.Set([]byte(admin), []byte(admin)) +} + +func (k Keeper) RemoveAdmin(ctx sdk.Context, admin string) error { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.AdminKey)) + storeAdmin := store.Get([]byte(admin)) + if storeAdmin == nil { + return fmt.Errorf("couldn't find admin '%s'", admin) + } + + store.Delete([]byte(admin)) + return nil +} + +func (k Keeper) SetProviderICAAdmin(ctx sdk.Context, providerICAAdmin string) { + store := ctx.KVStore(k.storeKey) + store.Set([]byte(types.ProviderICAAdminKey), []byte(providerICAAdmin)) +} + +func (k Keeper) GetProviderICAAdmin(ctx sdk.Context) string { + store := ctx.KVStore(k.storeKey) + bz := store.Get([]byte(types.ProviderICAAdminKey)) + if bz == nil { + return "" + } + + return string(bz) +} diff --git a/x/ccv/adminmodule/keeper/grpc_query.go b/x/ccv/adminmodule/keeper/grpc_query.go new file mode 100644 index 0000000000..806e673d64 --- /dev/null +++ b/x/ccv/adminmodule/keeper/grpc_query.go @@ -0,0 +1,7 @@ +package keeper + +import ( + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +var _ types.QueryServer = Keeper{} diff --git a/x/ccv/adminmodule/keeper/grpc_query_admins.go b/x/ccv/adminmodule/keeper/grpc_query_admins.go new file mode 100644 index 0000000000..97c31f3afc --- /dev/null +++ b/x/ccv/adminmodule/keeper/grpc_query_admins.go @@ -0,0 +1,20 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (k Keeper) Admins(goCtx context.Context, req *types.QueryAdminsRequest) (*types.QueryAdminsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + return &types.QueryAdminsResponse{ + Admins: k.GetAdmins(sdk.UnwrapSDKContext(goCtx)), + }, nil +} diff --git a/x/ccv/adminmodule/keeper/grpc_query_archived_proposals.go b/x/ccv/adminmodule/keeper/grpc_query_archived_proposals.go new file mode 100644 index 0000000000..23d813cf73 --- /dev/null +++ b/x/ccv/adminmodule/keeper/grpc_query_archived_proposals.go @@ -0,0 +1,20 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (k Keeper) ArchivedProposals(goCtx context.Context, req *types.QueryArchivedProposalsRequest) (*types.QueryArchivedProposalsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + proposals := k.GetArchivedProposals(sdk.UnwrapSDKContext(goCtx)) + return &types.QueryArchivedProposalsResponse{ + Proposals: proposals, + }, nil +} diff --git a/x/ccv/adminmodule/keeper/keeper.go b/x/ccv/adminmodule/keeper/keeper.go new file mode 100644 index 0000000000..ffd9a2d173 --- /dev/null +++ b/x/ccv/adminmodule/keeper/keeper.go @@ -0,0 +1,54 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + // this line is used by starport scaffolding # ibc/keeper/import +) + +type ( + Keeper struct { + cdc codec.Codec + storeKey sdk.StoreKey + memKey sdk.StoreKey + rtr govtypes.Router + IsWhitelistedForProvider func(govtypes.Content) bool + IsWhitelistedForConsumer func(govtypes.Content) bool + // this line is used by starport scaffolding # ibc/keeper/attribute + } +) + +func NewKeeper( + cdc codec.Codec, + storeKey, + memKey sdk.StoreKey, + rtr govtypes.Router, + isWhitelistedForProvider func(govtypes.Content) bool, + isWhitelistedForConsumer func(govtypes.Content) bool, + // this line is used by starport scaffolding # ibc/keeper/parameter +) *Keeper { + return &Keeper{ + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + rtr: rtr, + IsWhitelistedForProvider: isWhitelistedForProvider, + IsWhitelistedForConsumer: isWhitelistedForConsumer, + // this line is used by starport scaffolding # ibc/keeper/return + } +} + +// Router returns the adminmodule Keeper's Router +func (k Keeper) Router() govtypes.Router { + return k.rtr +} + +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} diff --git a/x/ccv/adminmodule/keeper/keeper_test.go b/x/ccv/adminmodule/keeper/keeper_test.go new file mode 100644 index 0000000000..48576102bf --- /dev/null +++ b/x/ccv/adminmodule/keeper/keeper_test.go @@ -0,0 +1,67 @@ +package keeper_test + +import ( + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/keeper" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmdb "github.com/tendermint/tm-db" +) + +func setupKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { + storeKey := sdk.NewKVStoreKey(types.StoreKey) + memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) + + // TODO Add more routes + rtr := govtypes.NewRouter() + rtr.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler) + + db := tmdb.NewMemDB() + stateStore := store.NewCommitMultiStore(db) + stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) + stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) + require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + //cdc := codec.NewProtoCodec(registry) + + types.RegisterInterfaces(registry) + k := keeper.NewKeeper( + codec.NewProtoCodec(registry), + storeKey, + memStoreKey, + rtr, + func(govtypes.Content) bool { return true }, + func(govtypes.Content) bool { return true }, + ) + ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) + return k, ctx +} + +// Using for setting admins before tests +func InitTestAdmins(k *keeper.Keeper, ctx sdk.Context, genesisAdmins []string) error { + // Removing old admins + oldAdmins := k.GetAdmins(ctx) + for _, admin := range oldAdmins { + err := k.RemoveAdmin(ctx, admin) + if err != nil { + return fmt.Errorf("Error removing admin %s\n, error: %s", admin, err) + } + } + + // Setting new admins + for _, admin := range genesisAdmins { + k.SetAdmin(ctx, admin) + } + return nil +} diff --git a/x/ccv/adminmodule/keeper/msg_server.go b/x/ccv/adminmodule/keeper/msg_server.go new file mode 100644 index 0000000000..e510398c4b --- /dev/null +++ b/x/ccv/adminmodule/keeper/msg_server.go @@ -0,0 +1,17 @@ +package keeper + +import ( + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(k Keeper) types.MsgServer { + return &msgServer{Keeper: k} +} + +var _ types.MsgServer = msgServer{} diff --git a/x/ccv/adminmodule/keeper/msg_server_add_admin.go b/x/ccv/adminmodule/keeper/msg_server_add_admin.go new file mode 100644 index 0000000000..58c52a72f5 --- /dev/null +++ b/x/ccv/adminmodule/keeper/msg_server_add_admin.go @@ -0,0 +1,26 @@ +package keeper + +import ( + "context" + + "fmt" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +func (k msgServer) AddAdmin(goCtx context.Context, msg *types.MsgAddAdmin) (*types.MsgAddAdminResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.AdminKey)) + + storeCreator := store.Get([]byte(msg.Creator)) + if storeCreator == nil { + return nil, fmt.Errorf("requester %s must be admin to add admins", msg.Creator) + } + + k.SetAdmin(ctx, msg.GetAdmin()) + + return &types.MsgAddAdminResponse{}, nil +} diff --git a/x/ccv/adminmodule/keeper/msg_server_add_admin_test.go b/x/ccv/adminmodule/keeper/msg_server_add_admin_test.go new file mode 100644 index 0000000000..a69b81dc17 --- /dev/null +++ b/x/ccv/adminmodule/keeper/msg_server_add_admin_test.go @@ -0,0 +1,93 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + "github.com/stretchr/testify/require" +) + +func TestAddAdmin(t *testing.T) { + // queryClient := suite.queryClient + // keeper, ctx := setupKeeper(t) + msgServer, ctx, keeper := setupMsgServer(t) + + var ( + req *types.QueryAdminsRequest + initialAdmin = "cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0" + ) + + testCases := []struct { + msg string + test func() + expPass bool + expRes []string + }{ + { + "empty admin address", + func() { + req = &types.QueryAdminsRequest{} + + initErr := InitTestAdmins(keeper, sdk.UnwrapSDKContext(ctx), []string{initialAdmin}) + if initErr != nil { + t.Errorf("Error initializing admins: %s\n", initErr) + } + + newAdmin := "" + newAdminMsg := &types.MsgAddAdmin{Creator: initialAdmin, Admin: newAdmin} + err := newAdminMsg.ValidateBasic() + require.Error(t, err) + }, + false, + []string{"cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0"}, + }, + { + "invalid admin address", + func() { + req = &types.QueryAdminsRequest{} + + initErr := InitTestAdmins(keeper, sdk.UnwrapSDKContext(ctx), []string{initialAdmin}) + if initErr != nil { + t.Errorf("Error initializing admins: %s\n", initErr) + } + + newAdmin := "invalid admin" + newAdminMsg := &types.MsgAddAdmin{Creator: initialAdmin, Admin: newAdmin} + err := newAdminMsg.ValidateBasic() + require.Error(t, err) + }, + false, + []string{"cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0"}, + }, + { + "valid request", + func() { + req = &types.QueryAdminsRequest{} + + initErr := InitTestAdmins(keeper, sdk.UnwrapSDKContext(ctx), []string{initialAdmin}) + if initErr != nil { + t.Errorf("Error initializing admins: %s\n", initErr) + } + + newAdmin := "cosmosTeStgx3kxcykszdxrk2gvrrfzchlqzfc59kx4s8" + newAdminMsg := &types.MsgAddAdmin{Creator: initialAdmin, Admin: newAdmin} + + // Actual add admin msg function + _, err := msgServer.AddAdmin(ctx, newAdminMsg) + require.NoError(t, err) + }, + true, + []string{"cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0", "cosmosTeStgx3kxcykszdxrk2gvrrfzchlqzfc59kx4s8"}, + }, + } + + for _, testCase := range testCases { + t.Logf("Case %s", testCase.msg) + testCase.test() + + admins, _ := keeper.Admins(ctx, req) + t.Log(testCase.expRes, admins.GetAdmins()) + require.Equal(t, testCase.expRes, admins.GetAdmins()) + } +} diff --git a/x/ccv/adminmodule/keeper/msg_server_delete_admin.go b/x/ccv/adminmodule/keeper/msg_server_delete_admin.go new file mode 100644 index 0000000000..413c84b267 --- /dev/null +++ b/x/ccv/adminmodule/keeper/msg_server_delete_admin.go @@ -0,0 +1,29 @@ +package keeper + +import ( + "context" + + "fmt" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +func (k msgServer) DeleteAdmin(goCtx context.Context, msg *types.MsgDeleteAdmin) (*types.MsgDeleteAdminResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.AdminKey)) + + storeCreator := store.Get([]byte(msg.Creator)) + if storeCreator == nil { + return nil, fmt.Errorf("requester %s must be admin to delete admins", msg.Creator) + } + + err := k.RemoveAdmin(ctx, msg.GetAdmin()) + if err != nil { + return nil, err + } + + return &types.MsgDeleteAdminResponse{}, nil +} diff --git a/x/ccv/adminmodule/keeper/msg_server_delete_admin_test.go b/x/ccv/adminmodule/keeper/msg_server_delete_admin_test.go new file mode 100644 index 0000000000..ed599bdc06 --- /dev/null +++ b/x/ccv/adminmodule/keeper/msg_server_delete_admin_test.go @@ -0,0 +1,98 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + "github.com/stretchr/testify/require" +) + +func TestDeleteAdmin(t *testing.T) { + // queryClient := suite.queryClient + // keeper, ctx := setupKeeper(t) + msgServer, ctx, keeper := setupMsgServer(t) + + var req *types.QueryAdminsRequest + + testCases := []struct { + msg string + test func() + expPass bool + expRes []string + }{ + { + "empty admin address", + func() { + req = &types.QueryAdminsRequest{} + initialAdmins := []string{"cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0", "cosmosTeStgx3kxcykszdxrk2gvrrfzchlqzfc59kx4s8"} + + adminToDelete := "" + + initErr := InitTestAdmins(keeper, sdk.UnwrapSDKContext(ctx), initialAdmins) + if initErr != nil { + t.Errorf("Error initializing admins: %s\n", initErr) + } + deleteAdminMsg := &types.MsgDeleteAdmin{Creator: initialAdmins[0], Admin: adminToDelete} + + // Actual delete admin msg function + _, err := msgServer.DeleteAdmin(ctx, deleteAdminMsg) + require.Error(t, err) + }, + false, + []string{"cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0", "cosmosTeStgx3kxcykszdxrk2gvrrfzchlqzfc59kx4s8"}, + }, + { + "non existent admin request", + func() { + req = &types.QueryAdminsRequest{} + initialAdmins := []string{"cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0", "cosmosTeStgx3kxcykszdxrk2gvrrfzchlqzfc59kx4s8"} + + adminToDelete := "cosmosnonexistentkszdxrk2gvrrfzchlqzfc59kx123" + + initErr := InitTestAdmins(keeper, sdk.UnwrapSDKContext(ctx), initialAdmins) + if initErr != nil { + t.Errorf("Error initializing admins: %s\n", initErr) + } + deleteAdminMsg := &types.MsgDeleteAdmin{Creator: initialAdmins[0], Admin: adminToDelete} + + // Actual delete admin msg function + _, err := msgServer.DeleteAdmin(ctx, deleteAdminMsg) + require.Error(t, err) + }, + false, + []string{"cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0", "cosmosTeStgx3kxcykszdxrk2gvrrfzchlqzfc59kx4s8"}, + }, + { + "valid request", + func() { + req = &types.QueryAdminsRequest{} + initialAdmins := []string{"cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0", "cosmosTeStgx3kxcykszdxrk2gvrrfzchlqzfc59kx4s8"} + + adminToDelete := initialAdmins[1] + + initErr := InitTestAdmins(keeper, sdk.UnwrapSDKContext(ctx), initialAdmins) + if initErr != nil { + t.Errorf("Error initializing admins: %s\n", initErr) + } + + deleteAdminMsg := &types.MsgDeleteAdmin{Creator: initialAdmins[0], Admin: adminToDelete} + + // Actual add admin msg function + _, err := msgServer.DeleteAdmin(ctx, deleteAdminMsg) + require.NoError(t, err) + }, + true, + []string{"cosmos1zwlgx3kxcykszdxrk2gvrrfzchlqzfc59kx3p0"}, + }, + } + + for _, testCase := range testCases { + t.Logf("Case %s", testCase.msg) + testCase.test() + + admins, _ := keeper.Admins(ctx, req) + t.Log(testCase.expRes, admins.GetAdmins()) + require.Equal(t, testCase.expRes, admins.GetAdmins()) + } +} diff --git a/x/ccv/adminmodule/keeper/msg_server_submit_proposal.go b/x/ccv/adminmodule/keeper/msg_server_submit_proposal.go new file mode 100644 index 0000000000..be919c3a21 --- /dev/null +++ b/x/ccv/adminmodule/keeper/msg_server_submit_proposal.go @@ -0,0 +1,49 @@ +package keeper + +import ( + "context" + "errors" + + "fmt" + + "github.com/cosmos/cosmos-sdk/store/prefix" + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +func (k msgServer) SubmitProposal(goCtx context.Context, msg *types.MsgSubmitProposal) (*types.MsgSubmitProposalResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.AdminKey)) + storeCreator := store.Get([]byte(msg.Proposer)) + if storeCreator == nil { + return nil, fmt.Errorf("proposer %s must be admin to submit proposals to admin-module", msg.Proposer) + } + + content := msg.GetContent() + if msg.Proposer == k.Keeper.GetProviderICAAdmin(ctx) { + if !k.Keeper.IsWhitelistedForProvider(content) { + return nil, errors.New("proposal content is not whitelisted for the provider governance") + } + } else { + if !k.Keeper.IsWhitelistedForConsumer(content) { + return nil, errors.New("proposal content is not whitelisted for the consumer governance") + } + } + + proposal, err := k.Keeper.SubmitProposal(ctx, content) + if err != nil { + return nil, err + } + + defer telemetry.IncrCounter(1, types.ModuleName, "proposal") + + submitEvent := sdk.NewEvent(types.EventTypeSubmitAdminProposal, sdk.NewAttribute(govtypes.AttributeKeyProposalType, msg.GetContent().ProposalType())) + ctx.EventManager().EmitEvent(submitEvent) + + return &types.MsgSubmitProposalResponse{ + ProposalId: proposal.ProposalId, + }, nil +} diff --git a/x/ccv/adminmodule/keeper/msg_server_test.go b/x/ccv/adminmodule/keeper/msg_server_test.go new file mode 100644 index 0000000000..d5b0869060 --- /dev/null +++ b/x/ccv/adminmodule/keeper/msg_server_test.go @@ -0,0 +1,15 @@ +package keeper_test + +import ( + "context" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/keeper" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +func setupMsgServer(t testing.TB) (types.MsgServer, context.Context, *keeper.Keeper) { + k, ctx := setupKeeper(t) + return keeper.NewMsgServerImpl(*k), sdk.WrapSDKContext(ctx), k +} diff --git a/x/ccv/adminmodule/keeper/proposal.go b/x/ccv/adminmodule/keeper/proposal.go new file mode 100644 index 0000000000..8c85d70a63 --- /dev/null +++ b/x/ccv/adminmodule/keeper/proposal.go @@ -0,0 +1,156 @@ +package keeper + +import ( + "fmt" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +// SubmitProposal create new proposal given a content +func (k Keeper) SubmitProposal(ctx sdk.Context, content govtypes.Content) (govtypes.Proposal, error) { + if !k.rtr.HasRoute(content.ProposalRoute()) { + return govtypes.Proposal{}, sdkerrors.Wrap(govtypes.ErrNoProposalHandlerExists, content.ProposalRoute()) + } + + cacheCtx, _ := ctx.CacheContext() + handler := k.rtr.GetRoute(content.ProposalRoute()) + if err := handler(cacheCtx, content); err != nil { + return govtypes.Proposal{}, sdkerrors.Wrap(govtypes.ErrInvalidProposalContent, err.Error()) + } + + proposalID, err := k.GetProposalID(ctx) + if err != nil { + return govtypes.Proposal{}, err + } + + headerTime := ctx.BlockHeader().Time + + // depositEndTime would not be used + proposal, err := govtypes.NewProposal(content, proposalID, headerTime, headerTime) + if err != nil { + return govtypes.Proposal{}, err + } + + proposal.VotingEndTime = headerTime + k.SetProposal(ctx, proposal) + // entTime is set to headerTime, because the proposal should be processed right after it is submitted + // since there is no voting + k.InsertActiveProposalQueue(ctx, proposalID, headerTime) + k.SetProposalID(ctx, proposalID+1) + + return proposal, nil +} + +// GetProposalID gets the highest proposal ID +func (k Keeper) GetProposalID(ctx sdk.Context) (proposalID uint64, err error) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ProposalIDKey) + if bz == nil { + return 0, sdkerrors.Wrap(types.ErrInvalidGenesis, "initial proposal ID hasn't been set") + } + + proposalID = types.GetProposalIDFromBytes(bz) + return proposalID, nil +} + +// SetProposalID sets the new proposal ID to the store +func (k Keeper) SetProposalID(ctx sdk.Context, proposalID uint64) { + store := ctx.KVStore(k.storeKey) + store.Set(types.ProposalIDKey, types.GetProposalIDBytes(proposalID)) +} + +// SetProposal set a proposal to store +func (k Keeper) SetProposal(ctx sdk.Context, proposal govtypes.Proposal) { + store := ctx.KVStore(k.storeKey) + + bz := k.MustMarshalProposal(proposal) + + store.Set(types.ProposalKey(proposal.ProposalId), bz) +} + +// GetProposal get proposal from store by ProposalID +func (k Keeper) GetProposal(ctx sdk.Context, proposalID uint64) (govtypes.Proposal, bool) { + store := ctx.KVStore(k.storeKey) + + bz := store.Get(types.ProposalKey(proposalID)) + if bz == nil { + return govtypes.Proposal{}, false + } + + var proposal govtypes.Proposal + k.MustUnmarshalProposal(bz, &proposal) + + return proposal, true +} + +// InsertActiveProposalQueue inserts a ProposalID into the active proposal queue at endTime +func (k Keeper) InsertActiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) { + store := ctx.KVStore(k.storeKey) + store.Set(types.ActiveProposalQueueKey(proposalID, endTime), types.GetProposalIDBytes(proposalID)) +} + +// RemoveFromActiveProposalQueue removes a proposalID from the Active Proposal Queue +func (k Keeper) RemoveFromActiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ActiveProposalQueueKey(proposalID, endTime)) +} + +// IterateActiveProposalsQueue iterates over the proposals in the active proposal queue +// and performs a callback function +func (k Keeper) IterateActiveProposalsQueue(ctx sdk.Context, endTime time.Time, cb func(proposal govtypes.Proposal) (stop bool)) { + iterator := k.ActiveProposalQueueIterator(ctx, endTime) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + proposalID, _ := types.SplitActiveProposalQueueKey(iterator.Key()) + proposal, found := k.GetProposal(ctx, proposalID) + if !found { + panic(fmt.Sprintf("proposal %d does not exist", proposalID)) + } + + if cb(proposal) { + break + } + } +} + +// ActiveProposalQueueIterator returns an sdk.Iterator for all the proposals in the Active Queue that expire by endTime +func (k Keeper) ActiveProposalQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { + store := ctx.KVStore(k.storeKey) + return store.Iterator(types.ActiveProposalQueuePrefix, sdk.PrefixEndBytes(types.ActiveProposalByTimeKey(endTime))) +} + +func (k Keeper) MarshalProposal(proposal govtypes.Proposal) ([]byte, error) { + bz, err := k.cdc.Marshal(&proposal) + if err != nil { + return nil, err + } + return bz, nil +} + +func (k Keeper) UnmarshalProposal(bz []byte, proposal *govtypes.Proposal) error { + err := k.cdc.Unmarshal(bz, proposal) + if err != nil { + return err + } + return nil +} + +func (k Keeper) MustMarshalProposal(proposal govtypes.Proposal) []byte { + bz, err := k.MarshalProposal(proposal) + if err != nil { + panic(err) + } + return bz +} + +func (k Keeper) MustUnmarshalProposal(bz []byte, proposal *govtypes.Proposal) { + err := k.UnmarshalProposal(bz, proposal) + if err != nil { + panic(err) + } +} diff --git a/x/ccv/adminmodule/keeper/proposal_archive.go b/x/ccv/adminmodule/keeper/proposal_archive.go new file mode 100644 index 0000000000..fd6f446d68 --- /dev/null +++ b/x/ccv/adminmodule/keeper/proposal_archive.go @@ -0,0 +1,34 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +func (k Keeper) GetArchivedProposals(ctx sdk.Context) []*govtypes.Proposal { + proposals := make([]*govtypes.Proposal, 0) + + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.ArchiveKey)) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var proposal govtypes.Proposal + + k.MustUnmarshalProposal(iterator.Value(), &proposal) + proposals = append(proposals, &proposal) + } + + return proposals +} + +func (k Keeper) AddToArchive(ctx sdk.Context, proposal govtypes.Proposal) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.ArchiveKey)) + + bz := k.MustMarshalProposal(proposal) + + store.Set(types.ProposalKey(proposal.ProposalId), bz) +} diff --git a/x/ccv/adminmodule/keeper/proposal_archive_test.go b/x/ccv/adminmodule/keeper/proposal_archive_test.go new file mode 100644 index 0000000000..273ff2ea21 --- /dev/null +++ b/x/ccv/adminmodule/keeper/proposal_archive_test.go @@ -0,0 +1,29 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" +) + +import ( + "testing" +) + +func TestAddToArchive(t *testing.T) { + _, ctx, keeper := setupMsgServer(t) + keeper.SetProposalID(sdk.UnwrapSDKContext(ctx), 1) + + tp := &govtypes.TextProposal{Title: "Test", Description: "Test Description"} + proposal, err := keeper.SubmitProposal(sdk.UnwrapSDKContext(ctx), tp) + require.NoError(t, err) + + keeper.AddToArchive(sdk.UnwrapSDKContext(ctx), proposal) + + proposals := keeper.GetArchivedProposals(sdk.UnwrapSDKContext(ctx)) + require.True(t, len(proposals) == 1) + + t.Log(tp, proposals[0].GetContent()) + require.Equal(t, tp, proposals[0].GetContent()) + +} diff --git a/x/ccv/adminmodule/keeper/querier.go b/x/ccv/adminmodule/keeper/querier.go new file mode 100644 index 0000000000..2af293ab61 --- /dev/null +++ b/x/ccv/adminmodule/keeper/querier.go @@ -0,0 +1,49 @@ +package keeper + +import ( + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" +) + +// NewQuerier creates a new adminmodule Querier instance +func NewQuerier(keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { + switch path[0] { + case types.QueryAdmins: + return queryAdmins(ctx, path[1:], req, keeper, legacyQuerierCdc) + + case types.QueryArchivedProposals: + return queryArchivedProposals(ctx, path[1:], req, keeper, legacyQuerierCdc) + + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) + } + } +} + +// nolint: unparam +func queryAdmins(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { + admins := keeper.GetAdmins(ctx) + + bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, admins) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return bz, nil +} + +func queryArchivedProposals(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { + proposals := keeper.GetArchivedProposals(ctx) + + bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, proposals) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return bz, nil +} diff --git a/x/ccv/adminmodule/keeper/submit_proposal_test.go b/x/ccv/adminmodule/keeper/submit_proposal_test.go new file mode 100644 index 0000000000..09c5a75bcf --- /dev/null +++ b/x/ccv/adminmodule/keeper/submit_proposal_test.go @@ -0,0 +1,59 @@ +package keeper_test + +import ( + "errors" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" + "strings" + "testing" +) + +var TestProposal = govtypes.NewTextProposal("Test", "description") + +type invalidProposalRoute struct{ govtypes.TextProposal } + +func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } + +func TestGetSetProposal(t *testing.T) { + _, ctx, keeper := setupMsgServer(t) + + // Init genesis ProposalID + keeper.SetProposalID(sdk.UnwrapSDKContext(ctx), 1) + + tp := TestProposal + proposal, err := keeper.SubmitProposal(sdk.UnwrapSDKContext(ctx), tp) + require.NoError(t, err) + proposalID := proposal.ProposalId + keeper.SetProposal(sdk.UnwrapSDKContext(ctx), proposal) + + gotProposal, ok := keeper.GetProposal(sdk.UnwrapSDKContext(ctx), proposalID) + require.True(t, ok) + require.True(t, proposal.Equal(gotProposal)) +} + +func TestSubmitProposal(t *testing.T) { + _, ctx, keeper := setupMsgServer(t) + + // Init genesis ProposalID + keeper.SetProposalID(sdk.UnwrapSDKContext(ctx), 1) + + testCases := []struct { + content govtypes.Content + expectedErr error + }{ + {&govtypes.TextProposal{Title: "title", Description: "description"}, nil}, + // Keeper does not check the validity of title and description, no error + {&govtypes.TextProposal{Title: "", Description: "description"}, nil}, + {&govtypes.TextProposal{Title: strings.Repeat("1234567890", 100), Description: "description"}, nil}, + {&govtypes.TextProposal{Title: "title", Description: ""}, nil}, + {&govtypes.TextProposal{Title: "title", Description: strings.Repeat("1234567890", 1000)}, nil}, + // error only when invalid route + {&invalidProposalRoute{}, govtypes.ErrNoProposalHandlerExists}, + } + + for i, tc := range testCases { + _, err := keeper.SubmitProposal(sdk.UnwrapSDKContext(ctx), tc.content) + require.True(t, errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) + } +} diff --git a/x/ccv/adminmodule/module.go b/x/ccv/adminmodule/module.go new file mode 100644 index 0000000000..2906d16a1d --- /dev/null +++ b/x/ccv/adminmodule/module.go @@ -0,0 +1,201 @@ +package adminmodule + +import ( + "encoding/json" + "fmt" + + // this line is used by starport scaffolding # 1 + + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/client/cli" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/keeper" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" + + // this line is used by starport scaffolding # ibc/module/import + "context" + + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + govrestclient "github.com/cosmos/cosmos-sdk/x/gov/client/rest" + "github.com/cosmos/interchain-security/x/ccv/adminmodule/client/rest" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + // this line is used by starport scaffolding # ibc/module/interface +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct { + proposalHandlers []govclient.ProposalHandler // proposal handlers which live in governance cli and rest +} + +func NewAppModuleBasic(proposalHandlers ...govclient.ProposalHandler) AppModuleBasic { + return AppModuleBasic{ + proposalHandlers: proposalHandlers, + } +} + +// Name returns the capability module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the capability module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the capability module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (a AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { + proposalRESTHandlers := make([]govrestclient.ProposalRESTHandler, 0, len(a.proposalHandlers)) + for _, proposalHandler := range a.proposalHandlers { + proposalRESTHandlers = append(proposalRESTHandlers, proposalHandler.RESTHandler(clientCtx)) + } + + rest.RegisterHandlers(clientCtx, rtr, proposalRESTHandlers) +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + panic(err) + } +} + +// GetTxCmd returns the capability module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + proposalCLIHandlers := make([]*cobra.Command, 0, len(a.proposalHandlers)) + for _, proposalHandler := range a.proposalHandlers { + proposalCLIHandlers = append(proposalCLIHandlers, proposalHandler.CLIHandler()) + } + return cli.GetTxCmd(proposalCLIHandlers) +} + +// GetQueryCmd returns the capability module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd(types.StoreKey) +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper + consumerkeeper types.ConsumerKeeper + icahostkeeper types.ICAHostKeeper + + cdc codec.Codec +} + +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, icahostkeeper types.ICAHostKeeper, + consumerkeeper types.ConsumerKeeper) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(), + keeper: keeper, + icahostkeeper: icahostkeeper, + consumerkeeper: consumerkeeper, + cdc: cdc, + } +} + +// Name returns the capability module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// Route returns the capability module's message routing key. +func (am AppModule) Route() sdk.Route { + return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) +} + +// QuerierRoute returns the capability module's query routing key. +func (AppModule) QuerierRoute() string { return types.QuerierRoute } + +// LegacyQuerierHandler returns the capability module's Querier. +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return keeper.NewQuerier(am.keeper, legacyQuerierCdc) +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// RegisterInvariants registers the capability module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the capability module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + InitGenesis(ctx, am.keeper, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock executes all ABCI BeginBlock logic respective to the capability module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) { +} + +// EndBlock executes all ABCI EndBlock logic respective to the capability module. It +// returns no validator updates. +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + EndBlocker(ctx, am.keeper, am.icahostkeeper, am.consumerkeeper) + return []abci.ValidatorUpdate{} +} diff --git a/x/ccv/adminmodule/types/codec.go b/x/ccv/adminmodule/types/codec.go new file mode 100644 index 0000000000..eb7c2fe8e5 --- /dev/null +++ b/x/ccv/adminmodule/types/codec.go @@ -0,0 +1,39 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgDeleteAdmin{}, "adminmodule/DeleteAdmin", nil) + + cdc.RegisterConcrete(&MsgAddAdmin{}, "adminmodule/AddAdmin", nil) + + cdc.RegisterConcrete(&MsgSubmitProposal{}, "adminmodule/SubmitProposal", nil) + // this line is used by starport scaffolding # 2 +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgDeleteAdmin{}, + &MsgAddAdmin{}, + &MsgSubmitProposal{}, + ) + + registry.RegisterInterface( + "cosmos.gov.v1beta1.Content", + (*govtypes.Content)(nil), + &govtypes.TextProposal{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) + // this line is used by starport scaffolding # 3 +} + +var ( + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) +) diff --git a/x/ccv/adminmodule/types/errors.go b/x/ccv/adminmodule/types/errors.go new file mode 100644 index 0000000000..3362fdd86f --- /dev/null +++ b/x/ccv/adminmodule/types/errors.go @@ -0,0 +1,13 @@ +package types + +// DONTCOVER + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// x/adminmodule module sentinel errors +var ( + ErrInvalidGenesis = sdkerrors.Register(ModuleName, 1, "invalid genesis state") + // this line is used by starport scaffolding # ibc/errors +) diff --git a/x/ccv/adminmodule/types/events.go b/x/ccv/adminmodule/types/events.go new file mode 100644 index 0000000000..9f057d3762 --- /dev/null +++ b/x/ccv/adminmodule/types/events.go @@ -0,0 +1,7 @@ +package types + +// admin module events +const ( + EventTypeAdminProposal = "admin_proposal" + EventTypeSubmitAdminProposal = "submit_admin_proposal" +) diff --git a/x/ccv/adminmodule/types/expected_keepers.go b/x/ccv/adminmodule/types/expected_keepers.go new file mode 100644 index 0000000000..245f49b6d1 --- /dev/null +++ b/x/ccv/adminmodule/types/expected_keepers.go @@ -0,0 +1,15 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type ConsumerKeeper interface { + GetProviderChannel(ctx sdk.Context) (string, bool) + GetConnectionHops(ctx sdk.Context, srcPort, srcChan string) ([]string, error) + GetProviderGovernanceAddress(ctx sdk.Context) (string, bool) +} + +type ICAHostKeeper interface { + GetInterchainAccountAddress(ctx sdk.Context, connectionID, portID string) (string, bool) +} diff --git a/x/ccv/adminmodule/types/genesis.go b/x/ccv/adminmodule/types/genesis.go new file mode 100644 index 0000000000..0e0a926924 --- /dev/null +++ b/x/ccv/adminmodule/types/genesis.go @@ -0,0 +1,30 @@ +package types + +import ( +// this line is used by starport scaffolding # genesis/types/import +// this line is used by starport scaffolding # ibc/genesistype/import + "strings" + "fmt" +) + +// DefaultIndex is the default capability global index +const DefaultIndex uint64 = 1 + +// DefaultGenesis returns the default Capability genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Admins: []string{}, + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + for _, admin := range gs.Admins { + if strings.TrimSpace(admin) == "" { + return fmt.Errorf("admin cannot be blank: %s", admin) + } + } + + return nil +} diff --git a/x/ccv/adminmodule/types/genesis.pb.go b/x/ccv/adminmodule/types/genesis.pb.go new file mode 100644 index 0000000000..fa75d6a53a --- /dev/null +++ b/x/ccv/adminmodule/types/genesis.pb.go @@ -0,0 +1,325 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: interchain_security/ccv/adminmodule/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + 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 + +// GenesisState defines the adminmodule module's genesis state. +type GenesisState struct { + Admins []string `protobuf:"bytes,1,rep,name=admins,proto3" json:"admins,omitempty"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_ad19de32f0499039, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetAdmins() []string { + if m != nil { + return m.Admins + } + return nil +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "interchain_security.ccv.adminmodule.v1.GenesisState") +} + +func init() { + proto.RegisterFile("interchain_security/ccv/adminmodule/v1/genesis.proto", fileDescriptor_ad19de32f0499039) +} + +var fileDescriptor_ad19de32f0499039 = []byte{ + // 200 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0xc9, 0xcc, 0x2b, 0x49, + 0x2d, 0x4a, 0xce, 0x48, 0xcc, 0xcc, 0x8b, 0x2f, 0x4e, 0x4d, 0x2e, 0x2d, 0xca, 0x2c, 0xa9, 0xd4, + 0x4f, 0x4e, 0x2e, 0xd3, 0x4f, 0x4c, 0xc9, 0xcd, 0xcc, 0xcb, 0xcd, 0x4f, 0x29, 0xcd, 0x49, 0xd5, + 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, + 0x17, 0x52, 0xc3, 0xa2, 0x4b, 0x2f, 0x39, 0xb9, 0x4c, 0x0f, 0x49, 0x97, 0x5e, 0x99, 0xa1, 0x94, + 0x48, 0x7a, 0x7e, 0x7a, 0x3e, 0x58, 0x8b, 0x3e, 0x88, 0x05, 0xd1, 0xad, 0xa4, 0xc6, 0xc5, 0xe3, + 0x0e, 0x31, 0x2e, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0x48, 0x8c, 0x8b, 0x0d, 0xac, 0xaf, 0x58, 0x82, + 0x51, 0x81, 0x59, 0x83, 0x33, 0x08, 0xca, 0x73, 0x0a, 0x3f, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, + 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, + 0x63, 0x39, 0x86, 0x28, 0xdb, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, + 0xe4, 0xfc, 0xe2, 0xdc, 0xfc, 0x62, 0x7d, 0x84, 0x8b, 0x74, 0xe1, 0xfe, 0xa8, 0xc0, 0xf0, 0x49, + 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0xd8, 0x1d, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x3c, 0xd6, 0xe8, 0x52, 0xfd, 0x00, 0x00, 0x00, +} + +func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Admins) > 0 { + for iNdEx := len(m.Admins) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Admins[iNdEx]) + copy(dAtA[i:], m.Admins[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Admins[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Admins) > 0 { + for _, s := range m.Admins { + l = len(s) + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) 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 ErrIntOverflowGenesis + } + 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: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admins", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admins = append(m.Admins, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(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, ErrIntOverflowGenesis + } + 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, ErrIntOverflowGenesis + } + 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, ErrIntOverflowGenesis + } + 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, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ccv/adminmodule/types/keys.go b/x/ccv/adminmodule/types/keys.go new file mode 100644 index 0000000000..f7bee5ea64 --- /dev/null +++ b/x/ccv/adminmodule/types/keys.go @@ -0,0 +1,86 @@ +package types + +import ( + "encoding/binary" + "fmt" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // ModuleName defines the module name + ModuleName = "adminmodule" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey is the message route for slashing + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key + QuerierRoute = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_adminmodule" + + AdminKey = "Admin-" + + ArchiveKey = "Archive-" + + ProviderICAAdminKey = "ProviderICAAdmin" +) + +var ( + ProposalsKeyPrefix = []byte{0x00} + ActiveProposalQueuePrefix = []byte{0x01} + ProposalIDKey = []byte{0x03} +) + +// GetProposalIDBytes returns the byte representation of the proposalID +func GetProposalIDBytes(proposalID uint64) (proposalIDBz []byte) { + proposalIDBz = make([]byte, 8) + binary.BigEndian.PutUint64(proposalIDBz, proposalID) + return +} + +// GetProposalIDFromBytes returns proposalID in uint64 format from a byte array +func GetProposalIDFromBytes(bz []byte) (proposalID uint64) { + return binary.BigEndian.Uint64(bz) +} + +// ProposalKey gets a specific proposal from the store +func ProposalKey(proposalID uint64) []byte { + return append(ProposalsKeyPrefix, GetProposalIDBytes(proposalID)...) +} + +// ActiveProposalByTimeKey gets the active proposal queue key by endTime +func ActiveProposalByTimeKey(endTime time.Time) []byte { + return append(ActiveProposalQueuePrefix, sdk.FormatTimeBytes(endTime)...) +} + +// ActiveProposalQueueKey returns the key for a proposalID in the activeProposalQueue +func ActiveProposalQueueKey(proposalID uint64, endTime time.Time) []byte { + return append(ActiveProposalByTimeKey(endTime), GetProposalIDBytes(proposalID)...) +} + +// SplitActiveProposalQueueKey split the active proposal key and returns the proposal id and endTime +func SplitActiveProposalQueueKey(key []byte) (proposalID uint64, endTime time.Time) { + return splitKeyWithTime(key) +} + +var lenTime = len(sdk.FormatTimeBytes(time.Now())) + +func splitKeyWithTime(key []byte) (proposalID uint64, endTime time.Time) { + if len(key[1:]) != 8+lenTime { + panic(fmt.Sprintf("unexpected key length (%d ≠ %d)", len(key[1:]), lenTime+8)) + } + + endTime, err := sdk.ParseTimeBytes(key[1 : 1+lenTime]) + if err != nil { + panic(err) + } + + proposalID = GetProposalIDFromBytes(key[1+lenTime:]) + return +} diff --git a/x/ccv/adminmodule/types/message_add_admin.go b/x/ccv/adminmodule/types/message_add_admin.go new file mode 100644 index 0000000000..a1ee34e03a --- /dev/null +++ b/x/ccv/adminmodule/types/message_add_admin.go @@ -0,0 +1,48 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +var _ sdk.Msg = &MsgAddAdmin{} + +func NewMsgAddAdmin(creator, admin sdk.AccAddress) *MsgAddAdmin { + return &MsgAddAdmin{ + Creator: creator.String(), + Admin: admin.String(), + } +} + +func (msg *MsgAddAdmin) Route() string { + return RouterKey +} + +func (msg *MsgAddAdmin) Type() string { + return "AddAdmin" +} + +func (msg *MsgAddAdmin) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgAddAdmin) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgAddAdmin) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) + } + _, err = sdk.AccAddressFromBech32(msg.Admin) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid admin address (%s)", err) + } + return nil +} diff --git a/x/ccv/adminmodule/types/message_delete_admin.go b/x/ccv/adminmodule/types/message_delete_admin.go new file mode 100644 index 0000000000..bb4895a78e --- /dev/null +++ b/x/ccv/adminmodule/types/message_delete_admin.go @@ -0,0 +1,48 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +var _ sdk.Msg = &MsgDeleteAdmin{} + +func NewMsgDeleteAdmin(creator, admin sdk.AccAddress) *MsgDeleteAdmin { + return &MsgDeleteAdmin{ + Creator: creator.String(), + Admin: admin.String(), + } +} + +func (msg *MsgDeleteAdmin) Route() string { + return RouterKey +} + +func (msg *MsgDeleteAdmin) Type() string { + return "DeleteAdmin" +} + +func (msg *MsgDeleteAdmin) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgDeleteAdmin) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgDeleteAdmin) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) + } + _, err = sdk.AccAddressFromBech32(msg.Admin) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid admin address (%s)", err) + } + return nil +} diff --git a/x/ccv/adminmodule/types/message_submit_proposal.go b/x/ccv/adminmodule/types/message_submit_proposal.go new file mode 100644 index 0000000000..36256e7bf5 --- /dev/null +++ b/x/ccv/adminmodule/types/message_submit_proposal.go @@ -0,0 +1,104 @@ +package types + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/gogo/protobuf/proto" + "gopkg.in/yaml.v2" +) + +var ( + _ sdk.Msg = &MsgSubmitProposal{} + _ cdctypes.UnpackInterfacesMessage = &MsgSubmitProposal{} +) + +func NewMsgSubmitProposal(content govtypes.Content, proposer sdk.AccAddress) (*MsgSubmitProposal, error) { + m := &MsgSubmitProposal{ + Proposer: proposer.String(), + } + + err := m.SetContent(content) + if err != nil { + return nil, err + } + return m, nil +} + +func (m *MsgSubmitProposal) GetContent() govtypes.Content { + content, ok := m.Content.GetCachedValue().(govtypes.Content) + if !ok { + return nil + } + return content +} + +func (m *MsgSubmitProposal) SetContent(content govtypes.Content) error { + msg, ok := content.(proto.Message) + if !ok { + return fmt.Errorf("can't proto marshal %T", msg) + } + any, err := types.NewAnyWithValue(msg) + if err != nil { + return err + } + m.Content = any + return nil +} + +func (m *MsgSubmitProposal) Route() string { + return RouterKey +} + +func (m *MsgSubmitProposal) Type() string { + return "SubmitProposal" +} + +func (m *MsgSubmitProposal) GetSigners() []sdk.AccAddress { + proposer, err := sdk.AccAddressFromBech32(m.Proposer) + if err != nil { + panic(err) + } + return []sdk.AccAddress{proposer} +} + +func (m *MsgSubmitProposal) GetSignBytes() []byte { + bz := govtypes.ModuleCdc.MustMarshalJSON(m) + return sdk.MustSortJSON(bz) +} + +// String implements the Stringer interface +func (m *MsgSubmitProposal) String() string { + out, _ := yaml.Marshal(m) + return string(out) +} + +// ValidateBasic implements Msg +func (m *MsgSubmitProposal) ValidateBasic() error { + if m.Proposer == "" { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, m.Proposer) + } + + content := m.GetContent() + if content == nil { + return sdkerrors.Wrap(govtypes.ErrInvalidProposalContent, "missing content") + } + if !govtypes.IsValidProposalType(content.ProposalType()) { + return sdkerrors.Wrap(govtypes.ErrInvalidProposalType, content.ProposalType()) + } + if err := content.ValidateBasic(); err != nil { + return err + } + + return nil +} + +func (m MsgSubmitProposal) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + var content govtypes.Content + return unpacker.UnpackAny(m.Content, &content) +} diff --git a/x/ccv/adminmodule/types/querier.go b/x/ccv/adminmodule/types/querier.go new file mode 100644 index 0000000000..333ceab578 --- /dev/null +++ b/x/ccv/adminmodule/types/querier.go @@ -0,0 +1,9 @@ +package types + +// DONTCOVER + +// query endpoints supported by the adminmodule Querier +const ( + QueryAdmins = "admins" + QueryArchivedProposals = "archivedproposals" +) diff --git a/x/ccv/adminmodule/types/query.pb.go b/x/ccv/adminmodule/types/query.pb.go new file mode 100644 index 0000000000..1721d53e66 --- /dev/null +++ b/x/ccv/adminmodule/types/query.pb.go @@ -0,0 +1,881 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: interchain_security/ccv/adminmodule/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/x/gov/types" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + 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 + +// this line is used by starport scaffolding # 3 +type QueryAdminsRequest struct { +} + +func (m *QueryAdminsRequest) Reset() { *m = QueryAdminsRequest{} } +func (m *QueryAdminsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAdminsRequest) ProtoMessage() {} +func (*QueryAdminsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_af0e5f25fc531812, []int{0} +} +func (m *QueryAdminsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAdminsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAdminsRequest.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 *QueryAdminsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAdminsRequest.Merge(m, src) +} +func (m *QueryAdminsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAdminsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAdminsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAdminsRequest proto.InternalMessageInfo + +type QueryAdminsResponse struct { + Admins []string `protobuf:"bytes,1,rep,name=admins,proto3" json:"admins,omitempty"` +} + +func (m *QueryAdminsResponse) Reset() { *m = QueryAdminsResponse{} } +func (m *QueryAdminsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAdminsResponse) ProtoMessage() {} +func (*QueryAdminsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_af0e5f25fc531812, []int{1} +} +func (m *QueryAdminsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAdminsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAdminsResponse.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 *QueryAdminsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAdminsResponse.Merge(m, src) +} +func (m *QueryAdminsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAdminsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAdminsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAdminsResponse proto.InternalMessageInfo + +func (m *QueryAdminsResponse) GetAdmins() []string { + if m != nil { + return m.Admins + } + return nil +} + +type QueryArchivedProposalsRequest struct { +} + +func (m *QueryArchivedProposalsRequest) Reset() { *m = QueryArchivedProposalsRequest{} } +func (m *QueryArchivedProposalsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryArchivedProposalsRequest) ProtoMessage() {} +func (*QueryArchivedProposalsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_af0e5f25fc531812, []int{2} +} +func (m *QueryArchivedProposalsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryArchivedProposalsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryArchivedProposalsRequest.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 *QueryArchivedProposalsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryArchivedProposalsRequest.Merge(m, src) +} +func (m *QueryArchivedProposalsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryArchivedProposalsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryArchivedProposalsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryArchivedProposalsRequest proto.InternalMessageInfo + +type QueryArchivedProposalsResponse struct { + Proposals []*types.Proposal `protobuf:"bytes,1,rep,name=proposals,proto3" json:"proposals,omitempty"` +} + +func (m *QueryArchivedProposalsResponse) Reset() { *m = QueryArchivedProposalsResponse{} } +func (m *QueryArchivedProposalsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryArchivedProposalsResponse) ProtoMessage() {} +func (*QueryArchivedProposalsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_af0e5f25fc531812, []int{3} +} +func (m *QueryArchivedProposalsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryArchivedProposalsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryArchivedProposalsResponse.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 *QueryArchivedProposalsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryArchivedProposalsResponse.Merge(m, src) +} +func (m *QueryArchivedProposalsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryArchivedProposalsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryArchivedProposalsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryArchivedProposalsResponse proto.InternalMessageInfo + +func (m *QueryArchivedProposalsResponse) GetProposals() []*types.Proposal { + if m != nil { + return m.Proposals + } + return nil +} + +func init() { + proto.RegisterType((*QueryAdminsRequest)(nil), "interchain_security.ccv.adminmodule.v1.QueryAdminsRequest") + proto.RegisterType((*QueryAdminsResponse)(nil), "interchain_security.ccv.adminmodule.v1.QueryAdminsResponse") + proto.RegisterType((*QueryArchivedProposalsRequest)(nil), "interchain_security.ccv.adminmodule.v1.QueryArchivedProposalsRequest") + proto.RegisterType((*QueryArchivedProposalsResponse)(nil), "interchain_security.ccv.adminmodule.v1.QueryArchivedProposalsResponse") +} + +func init() { + proto.RegisterFile("interchain_security/ccv/adminmodule/v1/query.proto", fileDescriptor_af0e5f25fc531812) +} + +var fileDescriptor_af0e5f25fc531812 = []byte{ + // 383 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x92, 0x4f, 0x4a, 0xc3, 0x40, + 0x14, 0xc6, 0x1b, 0x8b, 0x85, 0x8e, 0x2b, 0x47, 0x11, 0x09, 0x35, 0x4a, 0x16, 0x22, 0x48, 0x67, + 0x48, 0x0b, 0x22, 0x15, 0x05, 0x05, 0x5d, 0x6b, 0x37, 0x82, 0x08, 0x92, 0x4e, 0x87, 0x74, 0xa0, + 0xc9, 0x4b, 0x33, 0x93, 0x60, 0xb7, 0x9e, 0x40, 0xf0, 0x0c, 0x5e, 0xc1, 0x33, 0xb8, 0x2c, 0xb8, + 0x71, 0x29, 0xa9, 0x07, 0x91, 0xfc, 0x69, 0xab, 0xb4, 0x85, 0xaa, 0xbb, 0x64, 0xe6, 0xbd, 0xdf, + 0xfb, 0xbe, 0x6f, 0x1e, 0xaa, 0x09, 0x4f, 0xf1, 0x80, 0x75, 0x6c, 0xe1, 0xdd, 0x49, 0xce, 0xc2, + 0x40, 0xa8, 0x3e, 0x65, 0x2c, 0xa2, 0x76, 0xdb, 0x15, 0x9e, 0x0b, 0xed, 0xb0, 0xcb, 0x69, 0x64, + 0xd1, 0x5e, 0xc8, 0x83, 0x3e, 0xf1, 0x03, 0x50, 0x80, 0x77, 0x67, 0xf4, 0x10, 0xc6, 0x22, 0xf2, + 0xad, 0x87, 0x44, 0x96, 0x5e, 0x71, 0x00, 0x9c, 0x2e, 0xa7, 0xb6, 0x2f, 0xa8, 0xed, 0x79, 0xa0, + 0x6c, 0x25, 0xc0, 0x93, 0x19, 0x45, 0xaf, 0x30, 0x90, 0x2e, 0x48, 0xea, 0x40, 0x44, 0x23, 0xab, + 0xc5, 0x95, 0x6d, 0x25, 0xdf, 0xd9, 0xad, 0xb9, 0x8e, 0xf0, 0x55, 0x32, 0xf2, 0x34, 0x41, 0xca, + 0x26, 0xef, 0x85, 0x5c, 0x2a, 0xb3, 0x8a, 0xd6, 0x7e, 0x9c, 0x4a, 0x1f, 0x3c, 0xc9, 0xf1, 0x06, + 0x2a, 0xa5, 0xa3, 0xe5, 0xa6, 0xb6, 0x53, 0xdc, 0x2b, 0x37, 0xf3, 0x3f, 0x73, 0x1b, 0x6d, 0x65, + 0xe5, 0x01, 0xeb, 0x88, 0x88, 0xb7, 0x2f, 0x03, 0xf0, 0x41, 0xda, 0xdd, 0x31, 0xef, 0x16, 0x19, + 0xf3, 0x0a, 0x72, 0x74, 0x03, 0x95, 0xfd, 0xd1, 0x61, 0x4a, 0x5f, 0xa9, 0x55, 0x48, 0xa6, 0x9c, + 0x24, 0x6a, 0x73, 0xe5, 0x64, 0xd4, 0xd9, 0x9c, 0x94, 0xd7, 0x9e, 0x8b, 0x68, 0x39, 0xc5, 0xe3, + 0x17, 0x0d, 0x95, 0x32, 0xcd, 0xb8, 0x41, 0x16, 0x4b, 0x8f, 0x4c, 0xdb, 0xd7, 0x8f, 0xfe, 0xd4, + 0x9b, 0x39, 0x31, 0xeb, 0x0f, 0x6f, 0x9f, 0x4f, 0x4b, 0x55, 0xbc, 0x4f, 0x27, 0x90, 0xea, 0xdc, + 0x27, 0xcf, 0x12, 0xc4, 0xb1, 0x86, 0x56, 0xa7, 0xc2, 0xc1, 0xe7, 0xbf, 0xd3, 0x31, 0x27, 0x7d, + 0xfd, 0xe2, 0xbf, 0x98, 0xdc, 0xd9, 0x49, 0xea, 0xec, 0x10, 0x1f, 0x2c, 0xe6, 0x2c, 0xe7, 0x8c, + 0xdf, 0xe9, 0xec, 0xfa, 0x35, 0x36, 0xb4, 0x41, 0x6c, 0x68, 0x1f, 0xb1, 0xa1, 0x3d, 0x0e, 0x8d, + 0xc2, 0x60, 0x68, 0x14, 0xde, 0x87, 0x46, 0xe1, 0xe6, 0xd8, 0x11, 0xaa, 0x13, 0xb6, 0x08, 0x03, + 0x97, 0xe6, 0xeb, 0x3a, 0x6b, 0xc4, 0xfd, 0xd4, 0x10, 0xd5, 0xf7, 0xb9, 0x6c, 0x95, 0xd2, 0x5d, + 0xae, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0xda, 0x44, 0xcd, 0xc0, 0x65, 0x03, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Queries a list of admins items. + Admins(ctx context.Context, in *QueryAdminsRequest, opts ...grpc.CallOption) (*QueryAdminsResponse, error) + // Queries a list of archived proposals. + ArchivedProposals(ctx context.Context, in *QueryArchivedProposalsRequest, opts ...grpc.CallOption) (*QueryArchivedProposalsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Admins(ctx context.Context, in *QueryAdminsRequest, opts ...grpc.CallOption) (*QueryAdminsResponse, error) { + out := new(QueryAdminsResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.adminmodule.v1.Query/Admins", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ArchivedProposals(ctx context.Context, in *QueryArchivedProposalsRequest, opts ...grpc.CallOption) (*QueryArchivedProposalsResponse, error) { + out := new(QueryArchivedProposalsResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.adminmodule.v1.Query/ArchivedProposals", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Queries a list of admins items. + Admins(context.Context, *QueryAdminsRequest) (*QueryAdminsResponse, error) + // Queries a list of archived proposals. + ArchivedProposals(context.Context, *QueryArchivedProposalsRequest) (*QueryArchivedProposalsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Admins(ctx context.Context, req *QueryAdminsRequest) (*QueryAdminsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Admins not implemented") +} +func (*UnimplementedQueryServer) ArchivedProposals(ctx context.Context, req *QueryArchivedProposalsRequest) (*QueryArchivedProposalsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ArchivedProposals not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Admins_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAdminsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Admins(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.adminmodule.v1.Query/Admins", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Admins(ctx, req.(*QueryAdminsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ArchivedProposals_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryArchivedProposalsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ArchivedProposals(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.adminmodule.v1.Query/ArchivedProposals", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ArchivedProposals(ctx, req.(*QueryArchivedProposalsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "interchain_security.ccv.adminmodule.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Admins", + Handler: _Query_Admins_Handler, + }, + { + MethodName: "ArchivedProposals", + Handler: _Query_ArchivedProposals_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "interchain_security/ccv/adminmodule/v1/query.proto", +} + +func (m *QueryAdminsRequest) 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 *QueryAdminsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAdminsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryAdminsResponse) 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 *QueryAdminsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAdminsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Admins) > 0 { + for iNdEx := len(m.Admins) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Admins[iNdEx]) + copy(dAtA[i:], m.Admins[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Admins[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryArchivedProposalsRequest) 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 *QueryArchivedProposalsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryArchivedProposalsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryArchivedProposalsResponse) 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 *QueryArchivedProposalsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryArchivedProposalsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Proposals) > 0 { + for iNdEx := len(m.Proposals) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Proposals[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryAdminsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryAdminsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Admins) > 0 { + for _, s := range m.Admins { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryArchivedProposalsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryArchivedProposalsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Proposals) > 0 { + for _, e := range m.Proposals { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryAdminsRequest) 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 ErrIntOverflowQuery + } + 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: QueryAdminsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAdminsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAdminsResponse) 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 ErrIntOverflowQuery + } + 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: QueryAdminsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAdminsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admins", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admins = append(m.Admins, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryArchivedProposalsRequest) 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 ErrIntOverflowQuery + } + 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: QueryArchivedProposalsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryArchivedProposalsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryArchivedProposalsResponse) 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 ErrIntOverflowQuery + } + 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: QueryArchivedProposalsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryArchivedProposalsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proposals", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proposals = append(m.Proposals, &types.Proposal{}) + if err := m.Proposals[len(m.Proposals)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ccv/adminmodule/types/query.pb.gw.go b/x/ccv/adminmodule/types/query.pb.gw.go new file mode 100644 index 0000000000..3b5c75a5e5 --- /dev/null +++ b/x/ccv/adminmodule/types/query.pb.gw.go @@ -0,0 +1,218 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: interchain_security/ccv/adminmodule/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Admins_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAdminsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Admins(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Admins_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAdminsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Admins(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_ArchivedProposals_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryArchivedProposalsRequest + var metadata runtime.ServerMetadata + + msg, err := client.ArchivedProposals(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ArchivedProposals_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryArchivedProposalsRequest + var metadata runtime.ServerMetadata + + msg, err := server.ArchivedProposals(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Admins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Admins_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Admins_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ArchivedProposals_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ArchivedProposals_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ArchivedProposals_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Admins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Admins_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Admins_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ArchivedProposals_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ArchivedProposals_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ArchivedProposals_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Admins_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain-security", "ccv", "adminmodule", "admins"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ArchivedProposals_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain-security", "ccv", "adminmodule", "archivedproposals"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Admins_0 = runtime.ForwardResponseMessage + + forward_Query_ArchivedProposals_0 = runtime.ForwardResponseMessage +) diff --git a/x/ccv/adminmodule/types/tx.pb.go b/x/ccv/adminmodule/types/tx.pb.go new file mode 100644 index 0000000000..487b1defd3 --- /dev/null +++ b/x/ccv/adminmodule/types/tx.pb.go @@ -0,0 +1,1380 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: interchain_security/ccv/adminmodule/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "github.com/regen-network/cosmos-proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + 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 + +// this line is used by starport scaffolding # proto/tx/message +type MsgDeleteAdmin struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Admin string `protobuf:"bytes,2,opt,name=admin,proto3" json:"admin,omitempty"` +} + +func (m *MsgDeleteAdmin) Reset() { *m = MsgDeleteAdmin{} } +func (m *MsgDeleteAdmin) String() string { return proto.CompactTextString(m) } +func (*MsgDeleteAdmin) ProtoMessage() {} +func (*MsgDeleteAdmin) Descriptor() ([]byte, []int) { + return fileDescriptor_18ef6aa988bd6439, []int{0} +} +func (m *MsgDeleteAdmin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDeleteAdmin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDeleteAdmin.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 *MsgDeleteAdmin) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDeleteAdmin.Merge(m, src) +} +func (m *MsgDeleteAdmin) XXX_Size() int { + return m.Size() +} +func (m *MsgDeleteAdmin) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDeleteAdmin.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDeleteAdmin proto.InternalMessageInfo + +func (m *MsgDeleteAdmin) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgDeleteAdmin) GetAdmin() string { + if m != nil { + return m.Admin + } + return "" +} + +type MsgDeleteAdminResponse struct { +} + +func (m *MsgDeleteAdminResponse) Reset() { *m = MsgDeleteAdminResponse{} } +func (m *MsgDeleteAdminResponse) String() string { return proto.CompactTextString(m) } +func (*MsgDeleteAdminResponse) ProtoMessage() {} +func (*MsgDeleteAdminResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_18ef6aa988bd6439, []int{1} +} +func (m *MsgDeleteAdminResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDeleteAdminResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDeleteAdminResponse.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 *MsgDeleteAdminResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDeleteAdminResponse.Merge(m, src) +} +func (m *MsgDeleteAdminResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgDeleteAdminResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDeleteAdminResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDeleteAdminResponse proto.InternalMessageInfo + +type MsgAddAdmin struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Admin string `protobuf:"bytes,2,opt,name=admin,proto3" json:"admin,omitempty"` +} + +func (m *MsgAddAdmin) Reset() { *m = MsgAddAdmin{} } +func (m *MsgAddAdmin) String() string { return proto.CompactTextString(m) } +func (*MsgAddAdmin) ProtoMessage() {} +func (*MsgAddAdmin) Descriptor() ([]byte, []int) { + return fileDescriptor_18ef6aa988bd6439, []int{2} +} +func (m *MsgAddAdmin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddAdmin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddAdmin.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 *MsgAddAdmin) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddAdmin.Merge(m, src) +} +func (m *MsgAddAdmin) XXX_Size() int { + return m.Size() +} +func (m *MsgAddAdmin) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddAdmin.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddAdmin proto.InternalMessageInfo + +func (m *MsgAddAdmin) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgAddAdmin) GetAdmin() string { + if m != nil { + return m.Admin + } + return "" +} + +type MsgAddAdminResponse struct { +} + +func (m *MsgAddAdminResponse) Reset() { *m = MsgAddAdminResponse{} } +func (m *MsgAddAdminResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAddAdminResponse) ProtoMessage() {} +func (*MsgAddAdminResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_18ef6aa988bd6439, []int{3} +} +func (m *MsgAddAdminResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddAdminResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddAdminResponse.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 *MsgAddAdminResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddAdminResponse.Merge(m, src) +} +func (m *MsgAddAdminResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgAddAdminResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddAdminResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddAdminResponse proto.InternalMessageInfo + +// MsgSubmitProposal defines an sdk.Msg type that supports submitting arbitrary +// proposal Content. +type MsgSubmitProposal struct { + Content *types.Any `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` + Proposer string `protobuf:"bytes,2,opt,name=proposer,proto3" json:"proposer,omitempty"` +} + +func (m *MsgSubmitProposal) Reset() { *m = MsgSubmitProposal{} } +func (*MsgSubmitProposal) ProtoMessage() {} +func (*MsgSubmitProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_18ef6aa988bd6439, []int{4} +} +func (m *MsgSubmitProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitProposal.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 *MsgSubmitProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitProposal.Merge(m, src) +} +func (m *MsgSubmitProposal) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitProposal) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitProposal proto.InternalMessageInfo + +// MsgSubmitProposalResponse defines the Msg/SubmitProposal response type. +type MsgSubmitProposalResponse struct { + ProposalId uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id" yaml:"proposal_id"` +} + +func (m *MsgSubmitProposalResponse) Reset() { *m = MsgSubmitProposalResponse{} } +func (m *MsgSubmitProposalResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSubmitProposalResponse) ProtoMessage() {} +func (*MsgSubmitProposalResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_18ef6aa988bd6439, []int{5} +} +func (m *MsgSubmitProposalResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitProposalResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitProposalResponse.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 *MsgSubmitProposalResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitProposalResponse.Merge(m, src) +} +func (m *MsgSubmitProposalResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitProposalResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitProposalResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitProposalResponse proto.InternalMessageInfo + +func (m *MsgSubmitProposalResponse) GetProposalId() uint64 { + if m != nil { + return m.ProposalId + } + return 0 +} + +func init() { + proto.RegisterType((*MsgDeleteAdmin)(nil), "interchain_security.ccv.adminmodule.v1.MsgDeleteAdmin") + proto.RegisterType((*MsgDeleteAdminResponse)(nil), "interchain_security.ccv.adminmodule.v1.MsgDeleteAdminResponse") + proto.RegisterType((*MsgAddAdmin)(nil), "interchain_security.ccv.adminmodule.v1.MsgAddAdmin") + proto.RegisterType((*MsgAddAdminResponse)(nil), "interchain_security.ccv.adminmodule.v1.MsgAddAdminResponse") + proto.RegisterType((*MsgSubmitProposal)(nil), "interchain_security.ccv.adminmodule.v1.MsgSubmitProposal") + proto.RegisterType((*MsgSubmitProposalResponse)(nil), "interchain_security.ccv.adminmodule.v1.MsgSubmitProposalResponse") +} + +func init() { + proto.RegisterFile("interchain_security/ccv/adminmodule/v1/tx.proto", fileDescriptor_18ef6aa988bd6439) +} + +var fileDescriptor_18ef6aa988bd6439 = []byte{ + // 482 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0xcf, 0xcc, 0x2b, 0x49, + 0x2d, 0x4a, 0xce, 0x48, 0xcc, 0xcc, 0x8b, 0x2f, 0x4e, 0x4d, 0x2e, 0x2d, 0xca, 0x2c, 0xa9, 0xd4, + 0x4f, 0x4e, 0x2e, 0xd3, 0x4f, 0x4c, 0xc9, 0xcd, 0xcc, 0xcb, 0xcd, 0x4f, 0x29, 0xcd, 0x49, 0xd5, + 0x2f, 0x33, 0xd4, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x52, 0xc3, 0xa2, 0x41, + 0x2f, 0x39, 0xb9, 0x4c, 0x0f, 0x49, 0x83, 0x5e, 0x99, 0xa1, 0x94, 0x48, 0x7a, 0x7e, 0x7a, 0x3e, + 0x58, 0x8b, 0x3e, 0x88, 0x05, 0xd1, 0x2d, 0x25, 0x99, 0x9e, 0x9f, 0x9f, 0x9e, 0x93, 0xaa, 0x0f, + 0xe6, 0x25, 0x95, 0xa6, 0xe9, 0x27, 0xe6, 0x55, 0xc2, 0xa4, 0x92, 0xf3, 0x8b, 0x73, 0xf3, 0x8b, + 0xe3, 0x21, 0x7a, 0x20, 0x1c, 0x88, 0x94, 0x92, 0x03, 0x17, 0x9f, 0x6f, 0x71, 0xba, 0x4b, 0x6a, + 0x4e, 0x6a, 0x49, 0xaa, 0x23, 0xc8, 0x1a, 0x21, 0x09, 0x2e, 0xf6, 0xe4, 0xa2, 0xd4, 0xc4, 0x92, + 0xfc, 0x22, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x18, 0x57, 0x48, 0x84, 0x8b, 0x15, 0xec, + 0x12, 0x09, 0x26, 0xb0, 0x38, 0x84, 0xa3, 0x24, 0xc1, 0x25, 0x86, 0x6a, 0x42, 0x50, 0x6a, 0x71, + 0x41, 0x7e, 0x5e, 0x71, 0xaa, 0x92, 0x2d, 0x17, 0xb7, 0x6f, 0x71, 0xba, 0x63, 0x4a, 0x0a, 0x79, + 0x06, 0x8b, 0x72, 0x09, 0x23, 0x69, 0x87, 0x9b, 0x5a, 0xc7, 0x25, 0xe8, 0x5b, 0x9c, 0x1e, 0x5c, + 0x9a, 0x94, 0x9b, 0x59, 0x12, 0x50, 0x94, 0x5f, 0x90, 0x5f, 0x9c, 0x98, 0x23, 0x64, 0xcd, 0xc5, + 0x9e, 0x9c, 0x9f, 0x57, 0x92, 0x9a, 0x57, 0x02, 0x36, 0x9b, 0xdb, 0x48, 0x44, 0x0f, 0x12, 0x1c, + 0x7a, 0xb0, 0xe0, 0xd0, 0x73, 0xcc, 0xab, 0x74, 0xe2, 0x3e, 0xb5, 0x45, 0x97, 0xdd, 0x19, 0xa2, + 0x30, 0x08, 0xa6, 0x43, 0x48, 0x8a, 0x8b, 0xa3, 0x00, 0x6c, 0x50, 0x6a, 0x11, 0xd4, 0x05, 0x70, + 0xbe, 0x95, 0x40, 0xc7, 0x02, 0x79, 0x86, 0x19, 0x0b, 0xe4, 0x19, 0x5e, 0x2c, 0x90, 0x67, 0x68, + 0xb8, 0xa3, 0xc0, 0xa0, 0x94, 0xcc, 0x25, 0x89, 0x61, 0x3f, 0xcc, 0x71, 0x42, 0x6e, 0x5c, 0xdc, + 0x05, 0x50, 0xb1, 0xf8, 0xcc, 0x14, 0xb0, 0x5b, 0x58, 0x9c, 0x54, 0x5f, 0xdd, 0x93, 0x47, 0x16, + 0xfe, 0x74, 0x4f, 0x5e, 0xa8, 0x32, 0x31, 0x37, 0xc7, 0x4a, 0x09, 0x49, 0x50, 0x29, 0x88, 0x0b, + 0xc6, 0xf3, 0x4c, 0x31, 0x9a, 0xc3, 0xcc, 0xc5, 0xec, 0x5b, 0x9c, 0x2e, 0xd4, 0xca, 0xc8, 0xc5, + 0x8d, 0x1c, 0x39, 0x66, 0x7a, 0xc4, 0xa5, 0x11, 0x3d, 0xd4, 0x28, 0x91, 0xb2, 0x23, 0x4f, 0x1f, + 0xdc, 0x5f, 0x35, 0x5c, 0x1c, 0xf0, 0x78, 0x34, 0x26, 0xc1, 0x2c, 0x98, 0x26, 0x29, 0x6b, 0x32, + 0x34, 0xc1, 0x6d, 0xef, 0x63, 0xe4, 0xe2, 0x43, 0x8b, 0x70, 0x4b, 0x12, 0xcc, 0x43, 0xd5, 0x2a, + 0xe5, 0x48, 0xb6, 0x56, 0x98, 0x83, 0x9c, 0xc2, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, + 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, + 0x8e, 0x21, 0xca, 0x36, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x17, 0x9a, 0xd1, + 0x90, 0x8a, 0x01, 0x5d, 0x78, 0x31, 0x50, 0x81, 0x51, 0x10, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x27, + 0xb1, 0x81, 0x93, 0xab, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x41, 0x9c, 0x57, 0x99, 0x3c, 0x04, + 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + DeleteAdmin(ctx context.Context, in *MsgDeleteAdmin, opts ...grpc.CallOption) (*MsgDeleteAdminResponse, error) + AddAdmin(ctx context.Context, in *MsgAddAdmin, opts ...grpc.CallOption) (*MsgAddAdminResponse, error) + SubmitProposal(ctx context.Context, in *MsgSubmitProposal, opts ...grpc.CallOption) (*MsgSubmitProposalResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) DeleteAdmin(ctx context.Context, in *MsgDeleteAdmin, opts ...grpc.CallOption) (*MsgDeleteAdminResponse, error) { + out := new(MsgDeleteAdminResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.adminmodule.v1.Msg/DeleteAdmin", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) AddAdmin(ctx context.Context, in *MsgAddAdmin, opts ...grpc.CallOption) (*MsgAddAdminResponse, error) { + out := new(MsgAddAdminResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.adminmodule.v1.Msg/AddAdmin", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) SubmitProposal(ctx context.Context, in *MsgSubmitProposal, opts ...grpc.CallOption) (*MsgSubmitProposalResponse, error) { + out := new(MsgSubmitProposalResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.adminmodule.v1.Msg/SubmitProposal", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + DeleteAdmin(context.Context, *MsgDeleteAdmin) (*MsgDeleteAdminResponse, error) + AddAdmin(context.Context, *MsgAddAdmin) (*MsgAddAdminResponse, error) + SubmitProposal(context.Context, *MsgSubmitProposal) (*MsgSubmitProposalResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) DeleteAdmin(ctx context.Context, req *MsgDeleteAdmin) (*MsgDeleteAdminResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteAdmin not implemented") +} +func (*UnimplementedMsgServer) AddAdmin(ctx context.Context, req *MsgAddAdmin) (*MsgAddAdminResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddAdmin not implemented") +} +func (*UnimplementedMsgServer) SubmitProposal(ctx context.Context, req *MsgSubmitProposal) (*MsgSubmitProposalResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubmitProposal not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_DeleteAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgDeleteAdmin) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).DeleteAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.adminmodule.v1.Msg/DeleteAdmin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).DeleteAdmin(ctx, req.(*MsgDeleteAdmin)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_AddAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAddAdmin) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).AddAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.adminmodule.v1.Msg/AddAdmin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).AddAdmin(ctx, req.(*MsgAddAdmin)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_SubmitProposal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSubmitProposal) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SubmitProposal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.adminmodule.v1.Msg/SubmitProposal", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SubmitProposal(ctx, req.(*MsgSubmitProposal)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "interchain_security.ccv.adminmodule.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "DeleteAdmin", + Handler: _Msg_DeleteAdmin_Handler, + }, + { + MethodName: "AddAdmin", + Handler: _Msg_AddAdmin_Handler, + }, + { + MethodName: "SubmitProposal", + Handler: _Msg_SubmitProposal_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "interchain_security/ccv/adminmodule/v1/tx.proto", +} + +func (m *MsgDeleteAdmin) 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 *MsgDeleteAdmin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDeleteAdmin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintTx(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgDeleteAdminResponse) 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 *MsgDeleteAdminResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDeleteAdminResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgAddAdmin) 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 *MsgAddAdmin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAddAdmin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintTx(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgAddAdminResponse) 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 *MsgAddAdminResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAddAdminResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgSubmitProposal) 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 *MsgSubmitProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Proposer) > 0 { + i -= len(m.Proposer) + copy(dAtA[i:], m.Proposer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Proposer))) + i-- + dAtA[i] = 0x12 + } + if m.Content != nil { + { + size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSubmitProposalResponse) 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 *MsgSubmitProposalResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitProposalResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ProposalId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ProposalId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgDeleteAdmin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgDeleteAdminResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgAddAdmin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgAddAdminResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgSubmitProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Content != nil { + l = m.Content.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Proposer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgSubmitProposalResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProposalId != 0 { + n += 1 + sovTx(uint64(m.ProposalId)) + } + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgDeleteAdmin) 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 ErrIntOverflowTx + } + 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: MsgDeleteAdmin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDeleteAdmin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDeleteAdminResponse) 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 ErrIntOverflowTx + } + 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: MsgDeleteAdminResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDeleteAdminResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAddAdmin) 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 ErrIntOverflowTx + } + 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: MsgAddAdmin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddAdmin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAddAdminResponse) 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 ErrIntOverflowTx + } + 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: MsgAddAdminResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddAdminResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSubmitProposal) 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 ErrIntOverflowTx + } + 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: MsgSubmitProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Content == nil { + m.Content = &types.Any{} + } + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proposer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proposer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSubmitProposalResponse) 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 ErrIntOverflowTx + } + 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: MsgSubmitProposalResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitProposalResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalId", wireType) + } + m.ProposalId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProposalId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index 74873b96b2..a8c8f2b97f 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -107,6 +107,7 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state *consumertypes.GenesisState) // populate cross chain validators states with initial valset k.ApplyCCValidatorChanges(ctx, state.InitialValSet) + k.SetProviderGovernanceAddress(ctx, state.ProviderGovernanceAddress) return state.InitialValSet } @@ -125,6 +126,11 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt panic(fmt.Sprintf("fail to retrieve the validator set: %s", err)) } + providerGovAddr, found := k.GetProviderGovernanceAddress(ctx) + if !found { + panic("provider's governance module address is not set") + } + // export all the states created after a provider channel got established if channelID, ok := k.GetProviderChannel(ctx); ok { clientID, ok := k.GetProviderClientID(ctx) @@ -169,6 +175,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt heightToVCIDs, outstandingDowntimes, params, + providerGovAddr, ) } else { clientID, ok := k.GetProviderClientID(ctx) @@ -194,7 +201,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt panic("provider consensus state is not tendermint consensus state") } // export client states and pending slashing requests into a new chain genesis - genesis = consumertypes.NewInitialGenesisState(tmCs, tmConsState, valset, k.GetPendingSlashRequests(ctx), params) + genesis = consumertypes.NewInitialGenesisState(tmCs, tmConsState, valset, k.GetPendingSlashRequests(ctx), params, providerGovAddr) } return diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index 1818fa129e..c8e209ecb8 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -5,7 +5,10 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" testkeeper "github.com/cosmos/interchain-security/testutil/keeper" consumerkeeper "github.com/cosmos/interchain-security/x/ccv/consumer/keeper" @@ -23,6 +26,10 @@ import ( testutil "github.com/cosmos/interchain-security/testutil/keeper" ) +var ( + providerGovAddr string = authtypes.NewModuleAddress(govtypes.ModuleName).String() +) + func TestInitGenesis(t *testing.T) { // store consumer chain states in variables @@ -75,7 +82,7 @@ func TestInitGenesis(t *testing.T) { ) }, genesis: consumertypes.NewInitialGenesisState(testutil.GetClientState(""), consensusState, - []abci.ValidatorUpdate{tmtypes.TM2PB.ValidatorUpdate(validator)}, slashRequests, params), + []abci.ValidatorUpdate{tmtypes.TM2PB.ValidatorUpdate(validator)}, slashRequests, params, providerGovAddr), assertStates: func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *consumertypes.GenesisState) { require.Equal(t, gs.Params, ck.GetParams(ctx)) @@ -105,7 +112,7 @@ func TestInitGenesis(t *testing.T) { []abci.ValidatorUpdate{tmtypes.TM2PB.ValidatorUpdate(validator)}, []consumertypes.HeightToValsetUpdateID{{ValsetUpdateId: matPacket.VscId, Height: uint64(0)}}, []consumertypes.OutstandingDowntime{{ValidatorConsensusAddress: sdk.ConsAddress(validator.Bytes()).String()}}, - params, + params, providerGovAddr, ), assertStates: func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *consumertypes.GenesisState) { require.Equal(t, gs.Params, ck.GetParams(ctx)) @@ -197,6 +204,7 @@ func TestExportGenesis(t *testing.T) { ctx, slashRequests, ) + ck.SetProviderGovernanceAddress(ctx, providerGovAddr) // set the mock calls executed during the export gomock.InOrder( @@ -206,7 +214,7 @@ func TestExportGenesis(t *testing.T) { }, expGenesis: consumertypes.NewInitialGenesisState(testutil.GetClientState(""), consensusState, - []abci.ValidatorUpdate{tmtypes.TM2PB.ValidatorUpdate(validator)}, slashRequests, params), + []abci.ValidatorUpdate{tmtypes.TM2PB.ValidatorUpdate(validator)}, slashRequests, params, providerGovAddr), }, { name: "export a chain that has an established CCV channel", @@ -216,6 +224,7 @@ func TestExportGenesis(t *testing.T) { require.NoError(t, err) ck.SetCCValidator(ctx, cVal) ck.SetOutstandingDowntime(ctx, sdk.ConsAddress(validator.Address.Bytes())) + ck.SetProviderGovernanceAddress(ctx, providerGovAddr) // populate the required states to simulate a completed handshake ck.SetProviderClientID(ctx, clientID) @@ -230,7 +239,7 @@ func TestExportGenesis(t *testing.T) { []abci.ValidatorUpdate{tmtypes.TM2PB.ValidatorUpdate(validator)}, []types.HeightToValsetUpdateID{{Height: restartHeight, ValsetUpdateId: matPacket.VscId}}, []consumertypes.OutstandingDowntime{{ValidatorConsensusAddress: sdk.ConsAddress(validator.Address.Bytes()).String()}}, - params, + params, providerGovAddr, ), }, } diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index c7433ffaf0..ae5eb7374f 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -273,6 +273,22 @@ func (k Keeper) DeletePacketMaturityTime(ctx sdk.Context, vscId uint64) { store.Delete(types.PacketMaturityTimeKey(vscId)) } +// SetProviderGovernanceAddress sets provider's governance module address +func (k Keeper) SetProviderGovernanceAddress(ctx sdk.Context, providerGovAddr string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.ProviderGovernanceAddressKey(), []byte(providerGovAddr)) +} + +// GetProviderGovernanceAddress gets provider's governance module address +func (k Keeper) GetProviderGovernanceAddress(ctx sdk.Context) (string, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ProviderGovernanceAddressKey()) + if len(bz) == 0 { + return "", false + } + return string(bz), true +} + // VerifyProviderChain verifies that the chain trying to connect on the channel handshake // is the expected provider chain. func (k Keeper) VerifyProviderChain(ctx sdk.Context, connectionHops []string) error { diff --git a/x/ccv/consumer/types/genesis.go b/x/ccv/consumer/types/genesis.go index a2fdbe38a9..724034cf48 100644 --- a/x/ccv/consumer/types/genesis.go +++ b/x/ccv/consumer/types/genesis.go @@ -13,15 +13,16 @@ import ( // NewInitialGenesisState returns a consumer GenesisState for a completely new consumer chain. func NewInitialGenesisState(cs *ibctmtypes.ClientState, consState *ibctmtypes.ConsensusState, - initValSet []abci.ValidatorUpdate, slashRequests SlashRequests, params Params) *GenesisState { + initValSet []abci.ValidatorUpdate, slashRequests SlashRequests, params Params, providerGovAddr string) *GenesisState { return &GenesisState{ - Params: params, - NewChain: true, - ProviderClientState: cs, - ProviderConsensusState: consState, - InitialValSet: initValSet, - PendingSlashRequests: slashRequests, + Params: params, + NewChain: true, + ProviderClientState: cs, + ProviderConsensusState: consState, + InitialValSet: initValSet, + PendingSlashRequests: slashRequests, + ProviderGovernanceAddress: providerGovAddr, } } @@ -31,7 +32,7 @@ func NewRestartGenesisState(clientID, channelID string, initValSet []abci.ValidatorUpdate, heightToValsetUpdateIDs []HeightToValsetUpdateID, outstandingDowntimes []OutstandingDowntime, - params Params, + params Params, providerGovAddr string, ) *GenesisState { return &GenesisState{ @@ -43,6 +44,7 @@ func NewRestartGenesisState(clientID, channelID string, InitialValSet: initValSet, HeightToValsetUpdateId: heightToValsetUpdateIDs, OutstandingDowntimeSlashing: outstandingDowntimes, + ProviderGovernanceAddress: providerGovAddr, } } @@ -65,6 +67,9 @@ func (gs GenesisState) Validate() error { if err := gs.Params.Validate(); err != nil { return err } + if gs.ProviderGovernanceAddress == "" { + return sdkerrors.Wrap(ccv.ErrInvalidGenesis, "provider's governance module address is empty") + } if gs.NewChain { if gs.ProviderClientState == nil { diff --git a/x/ccv/consumer/types/genesis.pb.go b/x/ccv/consumer/types/genesis.pb.go index aa66509507..5a14ae0739 100644 --- a/x/ccv/consumer/types/genesis.pb.go +++ b/x/ccv/consumer/types/genesis.pb.go @@ -38,7 +38,7 @@ type GenesisState struct { ProviderConsensusState *types.ConsensusState `protobuf:"bytes,6,opt,name=provider_consensus_state,json=providerConsensusState,proto3" json:"provider_consensus_state,omitempty"` // MaturingPackets nil on new chain, filled on restart. MaturingPackets []MaturingVSCPacket `protobuf:"bytes,7,rep,name=maturing_packets,json=maturingPackets,proto3" json:"maturing_packets"` - // InitialValset filled in on new chain, manually filled in on restart. + // InitialValset filled in on new chain and on restart. InitialValSet []types1.ValidatorUpdate `protobuf:"bytes,8,rep,name=initial_val_set,json=initialValSet,proto3" json:"initial_val_set"` // HeightToValsetUpdateId nil on new chain, filled on restart. HeightToValsetUpdateId []HeightToValsetUpdateID `protobuf:"bytes,9,rep,name=height_to_valset_update_id,json=heightToValsetUpdateId,proto3" json:"height_to_valset_update_id"` @@ -46,6 +46,8 @@ type GenesisState struct { OutstandingDowntimeSlashing []OutstandingDowntime `protobuf:"bytes,10,rep,name=outstanding_downtime_slashing,json=outstandingDowntimeSlashing,proto3" json:"outstanding_downtime_slashing"` // PendingSlashRequests filled in on new chain, nil on restart. PendingSlashRequests SlashRequests `protobuf:"bytes,11,opt,name=pending_slash_requests,json=pendingSlashRequests,proto3" json:"pending_slash_requests"` + // Address of the provider's governance module + ProviderGovernanceAddress string `protobuf:"bytes,12,opt,name=provider_governance_address,json=providerGovernanceAddress,proto3" json:"provider_governance_address,omitempty"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -158,8 +160,15 @@ func (m *GenesisState) GetPendingSlashRequests() SlashRequests { return SlashRequests{} } -// UnbondingSequence defines the genesis information for each unbonding packet -// sequence. +func (m *GenesisState) GetProviderGovernanceAddress() string { + if m != nil { + return m.ProviderGovernanceAddress + } + return "" +} + +// MaturingVSCPacket defines the genesis information for the +// unbonding VSC packet type MaturingVSCPacket struct { VscId uint64 `protobuf:"varint,1,opt,name=vscId,proto3" json:"vscId,omitempty"` MaturityTime uint64 `protobuf:"varint,2,opt,name=maturity_time,json=maturityTime,proto3" json:"maturity_time,omitempty"` @@ -324,53 +333,55 @@ func init() { } var fileDescriptor_2db73a6057a27482 = []byte{ - // 729 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcf, 0x4f, 0x1b, 0x39, - 0x14, 0xce, 0x2c, 0x21, 0x10, 0x03, 0x0b, 0x18, 0x36, 0x9a, 0x25, 0xda, 0x6c, 0x36, 0x5c, 0x22, - 0x6d, 0x3b, 0xa3, 0xa4, 0x52, 0x55, 0xb5, 0x52, 0xa5, 0x02, 0x52, 0x9b, 0x43, 0x29, 0x9a, 0x40, - 0x0e, 0x5c, 0x46, 0x8e, 0xc7, 0x9a, 0xb1, 0x3a, 0x63, 0xa7, 0x63, 0xcf, 0x50, 0x0e, 0xbd, 0xf4, - 0x2f, 0xe8, 0x9f, 0xc5, 0xa1, 0x07, 0x8e, 0x3d, 0x55, 0x15, 0xfc, 0x23, 0xd5, 0xd8, 0xce, 0xaf, - 0x12, 0xa9, 0xb9, 0xd9, 0x7e, 0xef, 0xfb, 0xbe, 0xf7, 0xbe, 0x67, 0x1b, 0x74, 0x28, 0x93, 0x24, - 0xc5, 0x11, 0xa2, 0xcc, 0x17, 0x04, 0x67, 0x29, 0x95, 0xd7, 0x2e, 0xc6, 0xb9, 0x8b, 0x39, 0x13, - 0x59, 0x42, 0x52, 0x37, 0xef, 0xb8, 0x21, 0x61, 0x44, 0x50, 0xe1, 0x8c, 0x52, 0x2e, 0x39, 0x3c, - 0x5c, 0x00, 0x71, 0x30, 0xce, 0x9d, 0x31, 0xc4, 0xc9, 0x3b, 0x07, 0x2e, 0x1d, 0x62, 0x37, 0xa6, - 0x61, 0x24, 0x71, 0x4c, 0x09, 0x93, 0xc2, 0x95, 0x84, 0x05, 0x24, 0x4d, 0x28, 0x93, 0x05, 0xe5, - 0x74, 0xa7, 0x59, 0x0f, 0xfe, 0x2b, 0x00, 0x98, 0xa7, 0xc4, 0xc5, 0x11, 0x62, 0x8c, 0xc4, 0x45, - 0x96, 0x59, 0x9a, 0x94, 0xfd, 0x90, 0x87, 0x5c, 0x2d, 0xdd, 0x62, 0x65, 0x4e, 0xbb, 0xcb, 0x74, - 0x30, 0x29, 0x4d, 0x63, 0xea, 0x33, 0xc5, 0xa0, 0x21, 0xa6, 0xae, 0xbc, 0x1e, 0x11, 0xd3, 0x5f, - 0xeb, 0xeb, 0x1a, 0xd8, 0x7c, 0xad, 0x3b, 0xee, 0x4b, 0x24, 0x09, 0xec, 0x81, 0xca, 0x08, 0xa5, - 0x28, 0x11, 0xb6, 0xd5, 0xb4, 0xda, 0x1b, 0xdd, 0xff, 0x9d, 0x25, 0x1c, 0x70, 0xce, 0x14, 0xe4, - 0xa8, 0x7c, 0xf3, 0xfd, 0xdf, 0x92, 0x67, 0x08, 0xe0, 0x23, 0x00, 0x47, 0x29, 0xcf, 0x69, 0x40, - 0x52, 0x5f, 0x1b, 0xe3, 0xd3, 0xc0, 0xfe, 0xa3, 0x69, 0xb5, 0xab, 0xde, 0xce, 0x38, 0x72, 0xac, - 0x02, 0xbd, 0x00, 0x3a, 0x60, 0x6f, 0x9a, 0xad, 0xad, 0x28, 0xd2, 0x57, 0x54, 0xfa, 0xee, 0x24, - 0x5d, 0x47, 0x7a, 0x01, 0xac, 0x83, 0x2a, 0x23, 0x57, 0xbe, 0x2a, 0xcc, 0x2e, 0x37, 0xad, 0xf6, - 0xba, 0xb7, 0xce, 0xc8, 0xd5, 0x71, 0xb1, 0x87, 0x3e, 0xf8, 0xeb, 0x57, 0x69, 0x51, 0xb4, 0x67, - 0xaf, 0x8e, 0x9b, 0x1a, 0x62, 0x67, 0x76, 0x62, 0xce, 0xcc, 0x8c, 0xf2, 0x8e, 0xa3, 0xab, 0x52, - 0x8e, 0x78, 0x7b, 0xf3, 0xa5, 0x6a, 0x9b, 0x22, 0x60, 0x4f, 0x05, 0x38, 0x13, 0x84, 0x89, 0x4c, - 0x18, 0x8d, 0x8a, 0xd2, 0x70, 0x7e, 0xab, 0x31, 0x86, 0x69, 0x99, 0xda, 0x44, 0x66, 0xee, 0x1c, - 0x86, 0x60, 0x27, 0x41, 0x32, 0x4b, 0x29, 0x0b, 0xfd, 0x11, 0xc2, 0xef, 0x89, 0x14, 0xf6, 0x5a, - 0x73, 0xa5, 0xbd, 0xd1, 0x7d, 0xba, 0xd4, 0x68, 0xde, 0x1a, 0xf0, 0xa0, 0x7f, 0x7c, 0xa6, 0xe0, - 0x66, 0x4a, 0xdb, 0x63, 0x56, 0x7d, 0x2a, 0xe0, 0x29, 0xd8, 0xa6, 0x8c, 0x4a, 0x8a, 0x62, 0x3f, - 0x47, 0xb1, 0x2f, 0x88, 0xb4, 0xd7, 0x95, 0x4e, 0x73, 0xb6, 0xf0, 0xe2, 0x06, 0x39, 0x03, 0x14, - 0xd3, 0x00, 0x49, 0x9e, 0x5e, 0x8c, 0x02, 0x24, 0x89, 0x61, 0xdc, 0x32, 0xf0, 0x01, 0x8a, 0xfb, - 0x44, 0xc2, 0x4f, 0xe0, 0x20, 0x22, 0x45, 0xfb, 0xbe, 0xe4, 0x05, 0xa3, 0x20, 0xd2, 0xcf, 0x54, - 0x7e, 0x31, 0xd7, 0xaa, 0xa2, 0x7e, 0xb1, 0x54, 0x0b, 0x6f, 0x14, 0xcd, 0x39, 0x1f, 0x28, 0x12, - 0xad, 0xd9, 0x3b, 0x31, 0xaa, 0xb5, 0x68, 0x51, 0x34, 0x80, 0x9f, 0x2d, 0xf0, 0x0f, 0xcf, 0xa4, - 0x90, 0x88, 0x05, 0x85, 0x77, 0x01, 0xbf, 0x62, 0x92, 0x26, 0xc4, 0x17, 0x31, 0x12, 0x11, 0x65, - 0xa1, 0x0d, 0x54, 0x09, 0xcf, 0x96, 0x2a, 0xe1, 0xdd, 0x94, 0xe9, 0xc4, 0x10, 0x19, 0xfd, 0x3a, - 0x7f, 0x18, 0xea, 0x1b, 0x09, 0xc8, 0x40, 0x6d, 0x44, 0xb4, 0xbe, 0x92, 0xf5, 0x53, 0xf2, 0x21, - 0x23, 0x42, 0x0a, 0x7b, 0x43, 0x5d, 0x92, 0xee, 0x52, 0xe2, 0x8a, 0xce, 0x33, 0x48, 0x23, 0xbb, - 0x6f, 0x78, 0xe7, 0x62, 0xad, 0x53, 0xb0, 0xfb, 0x60, 0xde, 0x70, 0x1f, 0xac, 0xe6, 0x02, 0xf7, - 0x02, 0xf5, 0xa2, 0xcb, 0x9e, 0xde, 0xc0, 0x43, 0xb0, 0xa5, 0x6f, 0x80, 0xbc, 0xf6, 0x8b, 0x9a, - 0xd5, 0xc3, 0x2c, 0x7b, 0x9b, 0xe3, 0xc3, 0x73, 0x9a, 0x90, 0xd6, 0x25, 0xa8, 0x2d, 0x36, 0x1f, - 0xd6, 0x40, 0x45, 0x1b, 0x6f, 0x58, 0xcd, 0x0e, 0xb6, 0xc1, 0xce, 0x83, 0x59, 0x6b, 0xe6, 0x3f, - 0xf3, 0xb9, 0x01, 0xb5, 0x2e, 0xc0, 0xde, 0x02, 0x57, 0xe1, 0x4b, 0x50, 0xcf, 0xc7, 0xd7, 0x6b, - 0xe6, 0x69, 0xa1, 0x20, 0x48, 0x89, 0xd0, 0xbf, 0x52, 0xd5, 0xfb, 0x7b, 0x92, 0x32, 0x79, 0x2d, - 0xaf, 0x74, 0xc2, 0xd1, 0xf9, 0xcd, 0x5d, 0xc3, 0xba, 0xbd, 0x6b, 0x58, 0x3f, 0xee, 0x1a, 0xd6, - 0x97, 0xfb, 0x46, 0xe9, 0xf6, 0xbe, 0x51, 0xfa, 0x76, 0xdf, 0x28, 0x5d, 0x3e, 0x0f, 0xa9, 0x8c, - 0xb2, 0xa1, 0x83, 0x79, 0xe2, 0x62, 0x2e, 0x12, 0x2e, 0xdc, 0xa9, 0xfb, 0x8f, 0x27, 0xdf, 0xe9, - 0xc7, 0xf9, 0x0f, 0x55, 0xfd, 0x96, 0xc3, 0x8a, 0xfa, 0x2e, 0x9f, 0xfc, 0x0c, 0x00, 0x00, 0xff, - 0xff, 0x09, 0x61, 0x41, 0x6b, 0x43, 0x06, 0x00, 0x00, + // 753 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcf, 0x6f, 0xdb, 0x36, + 0x14, 0xb6, 0x16, 0xc7, 0x73, 0x98, 0x64, 0x49, 0x98, 0xcc, 0xd0, 0x62, 0xcc, 0xf3, 0x9c, 0x8b, + 0x81, 0x6d, 0x12, 0xec, 0x01, 0xc3, 0xb0, 0x01, 0x05, 0x9a, 0x04, 0x48, 0x7d, 0x68, 0x1a, 0xd8, + 0x89, 0x0f, 0xb9, 0x08, 0x34, 0x45, 0x48, 0x44, 0x25, 0xd2, 0x15, 0x29, 0xa5, 0x39, 0xf4, 0xd2, + 0x73, 0x0f, 0xfd, 0xb3, 0x72, 0xcc, 0xb1, 0xa7, 0xa2, 0x48, 0xfe, 0x91, 0x42, 0x24, 0x25, 0xdb, + 0x8d, 0x81, 0xfa, 0x46, 0xf2, 0x7d, 0xef, 0xfb, 0xde, 0x2f, 0x3e, 0xd0, 0xa3, 0x4c, 0x92, 0x04, + 0x87, 0x88, 0x32, 0x4f, 0x10, 0x9c, 0x26, 0x54, 0xde, 0xba, 0x18, 0x67, 0x2e, 0xe6, 0x4c, 0xa4, + 0x31, 0x49, 0xdc, 0xac, 0xe7, 0x06, 0x84, 0x11, 0x41, 0x85, 0x33, 0x4d, 0xb8, 0xe4, 0xf0, 0x68, + 0x89, 0x8b, 0x83, 0x71, 0xe6, 0x14, 0x2e, 0x4e, 0xd6, 0x3b, 0x74, 0xe9, 0x04, 0xbb, 0x11, 0x0d, + 0x42, 0x89, 0x23, 0x4a, 0x98, 0x14, 0xae, 0x24, 0xcc, 0x27, 0x49, 0x4c, 0x99, 0xcc, 0x29, 0x67, + 0x37, 0xcd, 0x7a, 0xf8, 0x7b, 0xee, 0x80, 0x79, 0x42, 0x5c, 0x1c, 0x22, 0xc6, 0x48, 0x94, 0xa3, + 0xcc, 0xd1, 0x40, 0x0e, 0x02, 0x1e, 0x70, 0x75, 0x74, 0xf3, 0x93, 0x79, 0xed, 0xaf, 0x92, 0x41, + 0x19, 0x9a, 0xf6, 0x69, 0xce, 0x05, 0x83, 0x26, 0x98, 0xba, 0xf2, 0x76, 0x4a, 0x4c, 0x7e, 0x9d, + 0x0f, 0x75, 0xb0, 0x75, 0xa6, 0x33, 0x1e, 0x49, 0x24, 0x09, 0x1c, 0x80, 0xda, 0x14, 0x25, 0x28, + 0x16, 0xb6, 0xd5, 0xb6, 0xba, 0x9b, 0xfd, 0x3f, 0x9c, 0x15, 0x2a, 0xe0, 0x5c, 0x28, 0x97, 0xe3, + 0xea, 0xdd, 0xe7, 0xdf, 0x2a, 0x43, 0x43, 0x00, 0xff, 0x04, 0x70, 0x9a, 0xf0, 0x8c, 0xfa, 0x24, + 0xf1, 0x74, 0x61, 0x3c, 0xea, 0xdb, 0x3f, 0xb4, 0xad, 0xee, 0xc6, 0x70, 0xb7, 0xb0, 0x9c, 0x28, + 0xc3, 0xc0, 0x87, 0x0e, 0xd8, 0x9f, 0xa1, 0x75, 0x29, 0x72, 0xf8, 0x9a, 0x82, 0xef, 0x95, 0x70, + 0x6d, 0x19, 0xf8, 0xb0, 0x09, 0x36, 0x18, 0xb9, 0xf1, 0x54, 0x60, 0x76, 0xb5, 0x6d, 0x75, 0xeb, + 0xc3, 0x3a, 0x23, 0x37, 0x27, 0xf9, 0x1d, 0x7a, 0xe0, 0xe7, 0x6f, 0xa5, 0x45, 0x9e, 0x9e, 0xbd, + 0x5e, 0x24, 0x35, 0xc1, 0xce, 0x7c, 0xc7, 0x9c, 0xb9, 0x1e, 0x65, 0x3d, 0x47, 0x47, 0xa5, 0x2a, + 0x32, 0xdc, 0x5f, 0x0c, 0x55, 0x97, 0x29, 0x04, 0xf6, 0x4c, 0x80, 0x33, 0x41, 0x98, 0x48, 0x85, + 0xd1, 0xa8, 0x29, 0x0d, 0xe7, 0xbb, 0x1a, 0x85, 0x9b, 0x96, 0x69, 0x94, 0x32, 0x0b, 0xef, 0x30, + 0x00, 0xbb, 0x31, 0x92, 0x69, 0x42, 0x59, 0xe0, 0x4d, 0x11, 0x7e, 0x4d, 0xa4, 0xb0, 0x7f, 0x6c, + 0xaf, 0x75, 0x37, 0xfb, 0xff, 0xac, 0xd4, 0x9a, 0x97, 0xc6, 0x79, 0x3c, 0x3a, 0xb9, 0x50, 0xee, + 0xa6, 0x4b, 0x3b, 0x05, 0xab, 0x7e, 0x15, 0xf0, 0x1c, 0xec, 0x50, 0x46, 0x25, 0x45, 0x91, 0x97, + 0xa1, 0xc8, 0x13, 0x44, 0xda, 0x75, 0xa5, 0xd3, 0x9e, 0x0f, 0x3c, 0x9f, 0x20, 0x67, 0x8c, 0x22, + 0xea, 0x23, 0xc9, 0x93, 0xab, 0xa9, 0x8f, 0x24, 0x31, 0x8c, 0xdb, 0xc6, 0x7d, 0x8c, 0xa2, 0x11, + 0x91, 0xf0, 0x1d, 0x38, 0x0c, 0x49, 0x9e, 0xbe, 0x27, 0x79, 0xce, 0x28, 0x88, 0xf4, 0x52, 0x85, + 0xcf, 0xfb, 0xba, 0xa1, 0xa8, 0xff, 0x5f, 0x29, 0x85, 0x17, 0x8a, 0xe6, 0x92, 0x8f, 0x15, 0x89, + 0xd6, 0x1c, 0x9c, 0x1a, 0xd5, 0x46, 0xb8, 0xcc, 0xea, 0xc3, 0xf7, 0x16, 0xf8, 0x95, 0xa7, 0x52, + 0x48, 0xc4, 0xfc, 0xbc, 0x76, 0x3e, 0xbf, 0x61, 0x92, 0xc6, 0xc4, 0x13, 0x11, 0x12, 0x21, 0x65, + 0x81, 0x0d, 0x54, 0x08, 0xff, 0xae, 0x14, 0xc2, 0xab, 0x19, 0xd3, 0xa9, 0x21, 0x32, 0xfa, 0x4d, + 0xfe, 0xd4, 0x34, 0x32, 0x12, 0x90, 0x81, 0xc6, 0x94, 0x68, 0x7d, 0x25, 0xeb, 0x25, 0xe4, 0x4d, + 0x4a, 0x84, 0x14, 0xf6, 0xa6, 0x1a, 0x92, 0xfe, 0x4a, 0xe2, 0x8a, 0x6e, 0x68, 0x3c, 0x8d, 0xec, + 0x81, 0xe1, 0x5d, 0xb0, 0xc1, 0x67, 0xa0, 0x59, 0x8e, 0x65, 0xc0, 0x33, 0x92, 0x30, 0xc4, 0x30, + 0xf1, 0x90, 0xef, 0x27, 0x44, 0x08, 0x7b, 0x4b, 0x7d, 0xa6, 0x5f, 0x0a, 0xc8, 0x59, 0x89, 0x78, + 0xae, 0x01, 0x9d, 0x73, 0xb0, 0xf7, 0x64, 0x5e, 0xe0, 0x01, 0x58, 0xcf, 0x04, 0x1e, 0xf8, 0x6a, + 0x23, 0x54, 0x87, 0xfa, 0x02, 0x8f, 0xc0, 0xb6, 0x9e, 0x20, 0x79, 0xeb, 0xe5, 0x39, 0xab, 0x8f, + 0x5d, 0x1d, 0x6e, 0x15, 0x8f, 0x97, 0x34, 0x26, 0x9d, 0x6b, 0xd0, 0x58, 0xde, 0x3c, 0xd8, 0x00, + 0x35, 0xdd, 0x38, 0xc3, 0x6a, 0x6e, 0xb0, 0x0b, 0x76, 0x9f, 0xcc, 0x8a, 0x66, 0xfe, 0x29, 0x5b, + 0x68, 0x70, 0xe7, 0x0a, 0xec, 0x2f, 0xe9, 0x4a, 0x5e, 0x82, 0xac, 0x18, 0xcf, 0xb9, 0xaf, 0x59, + 0x94, 0xc0, 0xd2, 0x25, 0x28, 0x21, 0xe5, 0x6f, 0x33, 0x25, 0x38, 0xbe, 0xbc, 0x7b, 0x68, 0x59, + 0xf7, 0x0f, 0x2d, 0xeb, 0xcb, 0x43, 0xcb, 0xfa, 0xf8, 0xd8, 0xaa, 0xdc, 0x3f, 0xb6, 0x2a, 0x9f, + 0x1e, 0x5b, 0x95, 0xeb, 0xff, 0x02, 0x2a, 0xc3, 0x74, 0xe2, 0x60, 0x1e, 0xbb, 0x98, 0x8b, 0x98, + 0x0b, 0x77, 0xd6, 0xbd, 0xbf, 0xca, 0x75, 0xfc, 0x76, 0x71, 0x21, 0xab, 0x6d, 0x3b, 0xa9, 0xa9, + 0x75, 0xfb, 0xf7, 0xd7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x53, 0xf2, 0xf5, 0x36, 0x83, 0x06, 0x00, + 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -393,6 +404,13 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ProviderGovernanceAddress) > 0 { + i -= len(m.ProviderGovernanceAddress) + copy(dAtA[i:], m.ProviderGovernanceAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ProviderGovernanceAddress))) + i-- + dAtA[i] = 0x62 + } { size, err := m.PendingSlashRequests.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -680,6 +698,10 @@ func (m *GenesisState) Size() (n int) { } l = m.PendingSlashRequests.Size() n += 1 + l + sovGenesis(uint64(l)) + l = len(m.ProviderGovernanceAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } return n } @@ -1119,6 +1141,38 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderGovernanceAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderGovernanceAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/ccv/consumer/types/genesis_test.go b/x/ccv/consumer/types/genesis_test.go index 700024ad77..0f025825df 100644 --- a/x/ccv/consumer/types/genesis_test.go +++ b/x/ccv/consumer/types/genesis_test.go @@ -14,6 +14,8 @@ import ( testutil "github.com/cosmos/interchain-security/testutil/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" ) @@ -25,8 +27,9 @@ const ( ) var ( - height = clienttypes.NewHeight(0, 4) - upgradePath = []string{"upgrade", "upgradedIBCState"} + height = clienttypes.NewHeight(0, 4) + upgradePath = []string{"upgrade", "upgradedIBCState"} + providerGovAddr = authtypes.NewModuleAddress(govtypes.ModuleName).String() ) // TestValidateInitialGenesisState tests a NewInitialGenesisState instantiation, @@ -55,29 +58,29 @@ func TestValidateInitialGenesisState(t *testing.T) { }{ { "valid new consumer genesis state", - types.NewInitialGenesisState(cs, consensusState, valUpdates, types.SlashRequests{}, params), + types.NewInitialGenesisState(cs, consensusState, valUpdates, types.SlashRequests{}, params, providerGovAddr), false, }, { "invalid new consumer genesis state: nil client state", - types.NewInitialGenesisState(nil, consensusState, valUpdates, types.SlashRequests{}, params), + types.NewInitialGenesisState(nil, consensusState, valUpdates, types.SlashRequests{}, params, providerGovAddr), true, }, { "invalid new consumer genesis state: invalid client state", types.NewInitialGenesisState(&ibctmtypes.ClientState{ChainId: "badClientState"}, - consensusState, valUpdates, types.SlashRequests{}, params), + consensusState, valUpdates, types.SlashRequests{}, params, providerGovAddr), true, }, { "invalid new consumer genesis state: nil consensus state", - types.NewInitialGenesisState(cs, nil, valUpdates, types.SlashRequests{}, params), + types.NewInitialGenesisState(cs, nil, valUpdates, types.SlashRequests{}, params, providerGovAddr), true, }, { "invalid new consumer genesis state: invalid consensus state", types.NewInitialGenesisState(cs, &ibctmtypes.ConsensusState{Timestamp: time.Now()}, - valUpdates, types.SlashRequests{}, params), + valUpdates, types.SlashRequests{}, params, providerGovAddr), true, }, { @@ -94,6 +97,7 @@ func TestValidateInitialGenesisState(t *testing.T) { nil, nil, types.SlashRequests{}, + providerGovAddr, }, true, }, @@ -111,6 +115,7 @@ func TestValidateInitialGenesisState(t *testing.T) { nil, nil, types.SlashRequests{}, + providerGovAddr, }, true, }, @@ -128,12 +133,13 @@ func TestValidateInitialGenesisState(t *testing.T) { nil, nil, types.SlashRequests{}, + providerGovAddr, }, true, }, { "invalid new consumer genesis state: nil initial validator set", - types.NewInitialGenesisState(cs, consensusState, nil, types.SlashRequests{}, params), + types.NewInitialGenesisState(cs, consensusState, nil, types.SlashRequests{}, params, providerGovAddr), true, }, { @@ -141,7 +147,7 @@ func TestValidateInitialGenesisState(t *testing.T) { types.NewInitialGenesisState( cs, ibctmtypes.NewConsensusState( time.Now(), commitmenttypes.NewMerkleRoot([]byte("apphash")), []byte("wrong_hash")), - valUpdates, types.SlashRequests{}, params), + valUpdates, types.SlashRequests{}, params, providerGovAddr), true, }, { @@ -156,7 +162,7 @@ func TestValidateInitialGenesisState(t *testing.T) { types.DefaultTransferTimeoutPeriod, types.DefaultConsumerRedistributeFrac, types.DefaultHistoricalEntries, - )), + ), providerGovAddr), true, }, } @@ -197,7 +203,7 @@ func TestValidateRestartGenesisState(t *testing.T) { }{ { "valid restart consumer genesis state: empty maturing packets", - types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, valUpdates, nil, nil, params), + types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, valUpdates, nil, nil, params, providerGovAddr), false, }, { @@ -206,31 +212,31 @@ func TestValidateRestartGenesisState(t *testing.T) { {1, uint64(time.Now().UnixNano())}, {3, uint64(time.Now().UnixNano())}, {5, uint64(time.Now().UnixNano())}, - }, valUpdates, nil, nil, params), + }, valUpdates, nil, nil, params, providerGovAddr), false, }, { "invalid restart consumer genesis state: channel id is empty", - types.NewRestartGenesisState("", "ccvchannel", nil, valUpdates, nil, nil, params), + types.NewRestartGenesisState("", "ccvchannel", nil, valUpdates, nil, nil, params, providerGovAddr), true, }, { "invalid restart consumer genesis state: channel id is empty", - types.NewRestartGenesisState("ccvclient", "", nil, valUpdates, nil, nil, params), + types.NewRestartGenesisState("ccvclient", "", nil, valUpdates, nil, nil, params, providerGovAddr), true, }, { "invalid restart consumer genesis state: maturing packet vscId is invalid", types.NewRestartGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ {0, uint64(time.Now().UnixNano())}, - }, valUpdates, nil, nil, params), + }, valUpdates, nil, nil, params, providerGovAddr), true, }, { "invalid restart consumer genesis state: maturing packet time is invalid", types.NewRestartGenesisState("ccvclient", "ccvchannel", []types.MaturingVSCPacket{ {1, 0}, - }, valUpdates, nil, nil, params), + }, valUpdates, nil, nil, params, providerGovAddr), true, }, { @@ -247,6 +253,7 @@ func TestValidateRestartGenesisState(t *testing.T) { nil, nil, types.SlashRequests{}, + providerGovAddr, }, true, }, @@ -264,12 +271,13 @@ func TestValidateRestartGenesisState(t *testing.T) { nil, nil, types.SlashRequests{}, + providerGovAddr, }, true, }, { "invalid restart consumer genesis state: nil initial validator set", - types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, nil, nil, nil, params), + types.NewRestartGenesisState("ccvclient", "ccvchannel", nil, nil, nil, nil, params, providerGovAddr), true, }, { @@ -284,7 +292,7 @@ func TestValidateRestartGenesisState(t *testing.T) { types.DefaultTransferTimeoutPeriod, types.DefaultConsumerRedistributeFrac, types.DefaultHistoricalEntries, - )), + ), providerGovAddr), true, }, } diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index 422cbd1528..0ffbc92ba7 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -65,6 +65,9 @@ const ( // CrossChainValidatorPrefix is the byte prefix that will store cross-chain validators by consensus address CrossChainValidatorBytePrefix + + // ProviderGovernanceAddressKey is the byte key that will store provider's governance module address + ProviderGovernanceAddressByteKey ) // PortKey returns the key to the port ID in the store @@ -127,6 +130,11 @@ func CrossChainValidatorKey(addr []byte) []byte { return append([]byte{CrossChainValidatorBytePrefix}, addr...) } +// ProviderGovernanceAddressKey returns the key to the provider's governance module address +func ProviderGovernanceAddressKey() []byte { + return []byte{ProviderGovernanceAddressByteKey} +} + // HistoricalInfoKey returns the key to historical info to a given block height func HistoricalInfoKey(height int64) []byte { hBytes := make([]byte, 8) diff --git a/x/ccv/icamauth/README.md b/x/ccv/icamauth/README.md new file mode 100644 index 0000000000..331e9f95c8 --- /dev/null +++ b/x/ccv/icamauth/README.md @@ -0,0 +1,8 @@ +# ICAMauth module + +This module is taken from Cosmos Hub repository. + +Interchain accounts message authentication module (ICAMauth module) is implemented according to the [interchain-accounts-demo](https://github.com/cosmos/interchain-accounts-demo) repository with some refactoring. Some minor modifications have been made, most notably renaming `intertx` to `icamauth`. All credit and thanks go to the original authors. + +## More infos +[ics-0270-interchain-accounts](https://github.com/cosmos/ibc/blob/main/spec/app/ics-027-interchain-accounts/README.md) diff --git a/x/ccv/icamauth/client/cli/flags.go b/x/ccv/icamauth/client/cli/flags.go new file mode 100644 index 0000000000..e43898cdaa --- /dev/null +++ b/x/ccv/icamauth/client/cli/flags.go @@ -0,0 +1,23 @@ +package cli + +import ( + flag "github.com/spf13/pflag" +) + +const ( + // The connection end identifier on the controller chain + FlagConnectionID = "connection-id" + // The controller chain channel version + FlagVersion = "version" +) + +// common flagsets to add to various functions +var ( + fsConnectionID = flag.NewFlagSet("", flag.ContinueOnError) + fsVersion = flag.NewFlagSet("", flag.ContinueOnError) +) + +func init() { + fsConnectionID.String(FlagConnectionID, "", "Connection ID") + fsVersion.String(FlagVersion, "", "Version") +} diff --git a/x/ccv/icamauth/client/cli/query.go b/x/ccv/icamauth/client/cli/query.go new file mode 100644 index 0000000000..8594aa9019 --- /dev/null +++ b/x/ccv/icamauth/client/cli/query.go @@ -0,0 +1,48 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/interchain-security/x/ccv/icamauth/types" + "github.com/spf13/cobra" +) + +// GetQueryCmd creates and returns the icamauth query command +func GetQueryCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the icamauth module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(getInterchainAccountCmd()) + + return cmd +} + +func getInterchainAccountCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "interchainaccounts [connection-id] [owner-account]", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.InterchainAccount(cmd.Context(), types.NewQueryInterchainAccountRequest(args[0], args[1])) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/icamauth/client/cli/tx.go b/x/ccv/icamauth/client/cli/tx.go new file mode 100644 index 0000000000..14927c3f53 --- /dev/null +++ b/x/ccv/icamauth/client/cli/tx.go @@ -0,0 +1,113 @@ +package cli + +import ( + "fmt" + "io/ioutil" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/icamauth/types" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// GetTxCmd creates and returns the icamauth tx command +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + getRegisterAccountCmd(), + getSubmitTxCmd(), + ) + + return cmd +} + +func getRegisterAccountCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "register", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgRegisterAccount( + clientCtx.GetFromAddress().String(), + viper.GetString(FlagConnectionID), + viper.GetString(FlagVersion), + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().AddFlagSet(fsConnectionID) + cmd.Flags().AddFlagSet(fsVersion) + _ = cmd.MarkFlagRequired(FlagConnectionID) + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func getSubmitTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "submit [path/to/sdk_msg.json]", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) + + var txMsg sdk.Msg + if err := cdc.UnmarshalInterfaceJSON([]byte(args[0]), &txMsg); err != nil { + + // check for file path if JSON input is not provided + contents, err := ioutil.ReadFile(args[0]) + if err != nil { + return errors.Wrap(err, "neither JSON input nor path to .json file for sdk msg were provided") + } + + if err := cdc.UnmarshalInterfaceJSON(contents, &txMsg); err != nil { + return errors.Wrap(err, "error unmarshalling sdk msg file") + } + } + + msg, err := types.NewMsgSubmitTx(txMsg, viper.GetString(FlagConnectionID), clientCtx.GetFromAddress().String()) + if err != nil { + return err + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().AddFlagSet(fsConnectionID) + _ = cmd.MarkFlagRequired(FlagConnectionID) + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/icamauth/ibc_module.go b/x/ccv/icamauth/ibc_module.go new file mode 100644 index 0000000000..0b18b16f89 --- /dev/null +++ b/x/ccv/icamauth/ibc_module.go @@ -0,0 +1,144 @@ +package icamauth + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/interchain-security/x/ccv/icamauth/keeper" + + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" +) + +var _ porttypes.IBCModule = IBCModule{} + +// IBCModule implements the ICS26 interface for interchain accounts controller chains +type IBCModule struct { + keeper keeper.Keeper +} + +// NewIBCModule creates a new IBCModule given the keeper +func NewIBCModule(k keeper.Keeper) IBCModule { + return IBCModule{ + keeper: k, + } +} + +// OnChanOpenInit implements the IBCModule interface +func (im IBCModule) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + + // Claim channel capability passed back by IBC module + if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return err + } + + return nil +} + +// OnChanOpenTry implements the IBCModule interface +func (im IBCModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + return "", nil +} + +// OnChanOpenAck implements the IBCModule interface +func (im IBCModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyChannelID string, + counterpartyVersion string, +) error { + return nil +} + +// OnChanOpenConfirm implements the IBCModule interface +func (im IBCModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +// OnChanCloseInit implements the IBCModule interface +func (im IBCModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +// OnChanCloseConfirm implements the IBCModule interface +func (im IBCModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +// OnRecvPacket implements the IBCModule interface. A successful acknowledgement +// is returned if the packet data is successfully decoded and the receive application +// logic returns without error. +func (im IBCModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) ibcexported.Acknowledgement { + return channeltypes.NewErrorAcknowledgement(fmt.Sprintf(sdkerrors.ErrInvalidRequest.Error(), "cannot receive packet via interchain accounts authentication module")) +} + +// the controller does not check the tx error in hostchain +// OnAcknowledgementPacket implements the IBCModule interface +func (im IBCModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + return nil +} + +// OnTimeoutPacket implements the IBCModule interface. +func (im IBCModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) error { + return nil +} + +// NegotiateAppVersion implements the IBCModule interface +func (im IBCModule) NegotiateAppVersion( + ctx sdk.Context, + order channeltypes.Order, + connectionID string, + portID string, + counterparty channeltypes.Counterparty, + proposedVersion string, +) (string, error) { + return "", nil +} diff --git a/x/ccv/icamauth/keeper/grpc_query.go b/x/ccv/icamauth/keeper/grpc_query.go new file mode 100644 index 0000000000..e866143926 --- /dev/null +++ b/x/ccv/icamauth/keeper/grpc_query.go @@ -0,0 +1,30 @@ +package keeper + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + sdk "github.com/cosmos/cosmos-sdk/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + + "github.com/cosmos/interchain-security/x/ccv/icamauth/types" +) + +// InterchainAccount implements the Query/InterchainAccount gRPC method +func (k Keeper) InterchainAccount(goCtx context.Context, req *types.QueryInterchainAccountRequest) (*types.QueryInterchainAccountResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + portID, err := icatypes.NewControllerPortID(req.Owner) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "could not find account: %s", err) + } + + addr, found := k.icaControllerKeeper.GetInterchainAccountAddress(ctx, req.ConnectionId, portID) + if !found { + return nil, status.Errorf(codes.NotFound, "no account found for portID %s", portID) + } + + return types.NewQueryInterchainAccountResponse(addr), nil +} diff --git a/x/ccv/icamauth/keeper/keeper.go b/x/ccv/icamauth/keeper/keeper.go new file mode 100644 index 0000000000..9b1e7acc67 --- /dev/null +++ b/x/ccv/icamauth/keeper/keeper.go @@ -0,0 +1,42 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + icacontrollerkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/keeper" + "github.com/cosmos/interchain-security/x/ccv/icamauth/types" + "github.com/tendermint/tendermint/libs/log" +) + +type Keeper struct { + cdc codec.Codec + + storeKey storetypes.StoreKey + + scopedKeeper capabilitykeeper.ScopedKeeper + icaControllerKeeper icacontrollerkeeper.Keeper +} + +func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey, iaKeeper icacontrollerkeeper.Keeper, scopedKeeper capabilitykeeper.ScopedKeeper) Keeper { + return Keeper{ + cdc: cdc, + storeKey: storeKey, + scopedKeeper: scopedKeeper, + icaControllerKeeper: iaKeeper, + } +} + +// Logger returns the application logger, scoped to the associated module +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +// ClaimCapability claims the channel capability passed via the OnOpenChanInit callback +func (k *Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { + return k.scopedKeeper.ClaimCapability(ctx, cap, name) +} diff --git a/x/ccv/icamauth/keeper/msg_server.go b/x/ccv/icamauth/keeper/msg_server.go new file mode 100644 index 0000000000..080494b8ad --- /dev/null +++ b/x/ccv/icamauth/keeper/msg_server.go @@ -0,0 +1,75 @@ +package keeper + +import ( + "context" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/interchain-security/x/ccv/icamauth/types" +) + +var _ types.MsgServer = msgServer{} + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl creates and returns a new types.MsgServer, fulfilling the icamauth Msg service interface +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +// RegisterAccount implements the Msg/RegisterAccount interface +func (k msgServer) RegisterAccount(goCtx context.Context, msg *types.MsgRegisterAccount) (*types.MsgRegisterAccountResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner); err != nil { + return nil, err + } + + return &types.MsgRegisterAccountResponse{}, nil +} + +// SubmitTx implements the Msg/SubmitTx interface +func (k msgServer) SubmitTx(goCtx context.Context, msg *types.MsgSubmitTx) (*types.MsgSubmitTxResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + portID, err := icatypes.NewControllerPortID(msg.Owner) + if err != nil { + return nil, err + } + + channelID, found := k.icaControllerKeeper.GetActiveChannelID(ctx, msg.ConnectionId, portID) + if !found { + return nil, sdkerrors.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel for port %s", portID) + } + + chanCap, found := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) + if !found { + return nil, sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + + data, err := icatypes.SerializeCosmosTx(k.cdc, []sdk.Msg{msg.GetTxMsg()}) + if err != nil { + return nil, err + } + + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + // timeoutTimestamp set to max value with the unsigned bit shifted to sastisfy hermes timestamp conversion + // it is the responsibility of the auth module developer to ensure an appropriate timeout timestamp + timeoutTimestamp := ctx.BlockTime().Add(time.Minute).UnixNano() + _, err = k.icaControllerKeeper.SendTx(ctx, chanCap, msg.ConnectionId, portID, packetData, uint64(timeoutTimestamp)) + if err != nil { + return nil, err + } + + return &types.MsgSubmitTxResponse{}, nil +} diff --git a/x/ccv/icamauth/module.go b/x/ccv/icamauth/module.go new file mode 100644 index 0000000000..68de75ce96 --- /dev/null +++ b/x/ccv/icamauth/module.go @@ -0,0 +1,152 @@ +package icamauth + +import ( + "context" + "encoding/json" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/interchain-security/x/ccv/icamauth/client/cli" + "github.com/cosmos/interchain-security/x/ccv/icamauth/keeper" + "github.com/cosmos/interchain-security/x/ccv/icamauth/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct { + cdc codec.Codec +} + +func NewAppModuleBasic(cdc codec.Codec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the capability module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the capability module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return nil +} + +// ValidateGenesis performs genesis state validation for the capability module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + return nil +} + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + panic(err) + } +} + +// GetTxCmd returns the capability module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the capability module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper +} + +// NewAppModule creates and returns a new icamauth AppModule +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + } +} + +// Name returns the capability module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// Route returns the capability module's message routing key. +func (am AppModule) Route() sdk.Route { + return sdk.NewRoute(types.RouterKey, nil) +} + +// QuerierRoute returns the capability module's query routing key. +func (AppModule) QuerierRoute() string { + return types.QuerierRoute +} + +// LegacyQuerierHandler returns the capability module's Querier. +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// RegisterInvariants registers the capability module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the capability module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + return nil +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock executes all ABCI BeginBlock logic respective to the capability module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock executes all ABCI EndBlock logic respective to the capability module. It +// returns no validator updates. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/ccv/icamauth/types/codec.go b/x/ccv/icamauth/types/codec.go new file mode 100644 index 0000000000..d1450b59d5 --- /dev/null +++ b/x/ccv/icamauth/types/codec.go @@ -0,0 +1,29 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + + // this line is used by starport scaffolding # 1 + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +var ( + amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewAminoCodec(amino) +) + +func RegisterCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(MsgRegisterAccount{}, "icamauth/MsgRegisterAccount", nil) + cdc.RegisterConcrete(MsgSubmitTx{}, "icamauth/MsgSubmitTx", nil) +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgRegisterAccount{}, + &MsgSubmitTx{}, + ) +} diff --git a/x/ccv/icamauth/types/errors.go b/x/ccv/icamauth/types/errors.go new file mode 100644 index 0000000000..1ab267cc0c --- /dev/null +++ b/x/ccv/icamauth/types/errors.go @@ -0,0 +1,10 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +var ( + ErrIBCAccountAlreadyExist = sdkerrors.Register(ModuleName, 2, "interchain account already registered") + ErrIBCAccountNotExist = sdkerrors.Register(ModuleName, 3, "interchain account not exist") +) diff --git a/x/ccv/icamauth/types/keys.go b/x/ccv/icamauth/types/keys.go new file mode 100644 index 0000000000..2cae567eaf --- /dev/null +++ b/x/ccv/icamauth/types/keys.go @@ -0,0 +1,11 @@ +package types + +const ( + ModuleName = "icamauth" + + StoreKey = ModuleName + + RouterKey = ModuleName + + QuerierRoute = ModuleName +) diff --git a/x/ccv/icamauth/types/msgs.go b/x/ccv/icamauth/types/msgs.go new file mode 100644 index 0000000000..51cb8935ec --- /dev/null +++ b/x/ccv/icamauth/types/msgs.go @@ -0,0 +1,116 @@ +package types + +import ( + fmt "fmt" + "strings" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + proto "github.com/gogo/protobuf/proto" +) + +var ( + _ sdk.Msg = &MsgRegisterAccount{} + _ sdk.Msg = &MsgSubmitTx{} + + _ codectypes.UnpackInterfacesMessage = MsgSubmitTx{} +) + +// NewMsgRegisterAccount creates a new MsgRegisterAccount instance +func NewMsgRegisterAccount(owner, connectionID, version string) *MsgRegisterAccount { + return &MsgRegisterAccount{ + Owner: owner, + ConnectionId: connectionID, + Version: version, + } +} + +// ValidateBasic implements sdk.Msg +func (msg MsgRegisterAccount) ValidateBasic() error { + if strings.TrimSpace(msg.Owner) == "" { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address") + } + + if _, err := sdk.AccAddressFromBech32(msg.Owner); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "failed to parse address: %s", msg.Owner) + } + + return nil +} + +// GetSigners implements sdk.Msg +func (msg MsgRegisterAccount) GetSigners() []sdk.AccAddress { + accAddr, err := sdk.AccAddressFromBech32(msg.Owner) + if err != nil { + panic(err) + } + + return []sdk.AccAddress{accAddr} +} + +// NewMsgSubmitTx creates and returns a new MsgSubmitTx instance +func NewMsgSubmitTx(sdkMsg sdk.Msg, connectionID, owner string) (*MsgSubmitTx, error) { + any, err := PackTxMsgAny(sdkMsg) + if err != nil { + return nil, err + } + + return &MsgSubmitTx{ + ConnectionId: connectionID, + Owner: owner, + Msg: any, + }, nil +} + +// PackTxMsgAny marshals the sdk.Msg payload to a protobuf Any type +func PackTxMsgAny(sdkMsg sdk.Msg) (*codectypes.Any, error) { + msg, ok := sdkMsg.(proto.Message) + if !ok { + return nil, fmt.Errorf("can't proto marshal %T", sdkMsg) + } + + any, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, err + } + + return any, nil +} + +// UnpackInterfaces implements codectypes.UnpackInterfacesMessage +func (msg MsgSubmitTx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + var sdkMsg sdk.Msg + + return unpacker.UnpackAny(msg.Msg, &sdkMsg) +} + +// GetTxMsg fetches the cached any message +func (msg *MsgSubmitTx) GetTxMsg() sdk.Msg { + sdkMsg, ok := msg.Msg.GetCachedValue().(sdk.Msg) + if !ok { + return nil + } + + return sdkMsg +} + +// GetSigners implements sdk.Msg +func (msg MsgSubmitTx) GetSigners() []sdk.AccAddress { + accAddr, err := sdk.AccAddressFromBech32(msg.Owner) + if err != nil { + panic(err) + } + + return []sdk.AccAddress{accAddr} +} + +// ValidateBasic implements sdk.Msg +func (msg MsgSubmitTx) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Owner) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid owner address") + } + + return nil +} diff --git a/x/ccv/icamauth/types/query.go b/x/ccv/icamauth/types/query.go new file mode 100644 index 0000000000..9778fa73a0 --- /dev/null +++ b/x/ccv/icamauth/types/query.go @@ -0,0 +1,16 @@ +package types + +// NewQueryInterchainAccountRequest creates and returns a new QueryInterchainAccountRequest +func NewQueryInterchainAccountRequest(connectionID, owner string) *QueryInterchainAccountRequest { + return &QueryInterchainAccountRequest{ + ConnectionId: connectionID, + Owner: owner, + } +} + +// NewQueryInterchainAccountResponse creates and returns a new QueryInterchainAccountResponse +func NewQueryInterchainAccountResponse(interchainAccAddr string) *QueryInterchainAccountResponse { + return &QueryInterchainAccountResponse{ + InterchainAccountAddress: interchainAccAddr, + } +} diff --git a/x/ccv/icamauth/types/query.pb.go b/x/ccv/icamauth/types/query.pb.go new file mode 100644 index 0000000000..6824ba8ac2 --- /dev/null +++ b/x/ccv/icamauth/types/query.pb.go @@ -0,0 +1,647 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: interchain_security/ccv/icamauth/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + 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 + +// QueryInterchainAccountRequest is the request type for the +// Query/InterchainAccountAddress RPC +type QueryInterchainAccountRequest struct { + Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` + ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"` +} + +func (m *QueryInterchainAccountRequest) Reset() { *m = QueryInterchainAccountRequest{} } +func (m *QueryInterchainAccountRequest) String() string { return proto.CompactTextString(m) } +func (*QueryInterchainAccountRequest) ProtoMessage() {} +func (*QueryInterchainAccountRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f9a6327305204300, []int{0} +} +func (m *QueryInterchainAccountRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryInterchainAccountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryInterchainAccountRequest.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 *QueryInterchainAccountRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryInterchainAccountRequest.Merge(m, src) +} +func (m *QueryInterchainAccountRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryInterchainAccountRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryInterchainAccountRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryInterchainAccountRequest proto.InternalMessageInfo + +func (m *QueryInterchainAccountRequest) GetOwner() string { + if m != nil { + return m.Owner + } + return "" +} + +func (m *QueryInterchainAccountRequest) GetConnectionId() string { + if m != nil { + return m.ConnectionId + } + return "" +} + +// QueryInterchainAccountResponse the response type for the +// Query/InterchainAccountAddress RPC +type QueryInterchainAccountResponse struct { + InterchainAccountAddress string `protobuf:"bytes,1,opt,name=interchain_account_address,json=interchainAccountAddress,proto3" json:"interchain_account_address,omitempty" yaml:"interchain_account_address"` +} + +func (m *QueryInterchainAccountResponse) Reset() { *m = QueryInterchainAccountResponse{} } +func (m *QueryInterchainAccountResponse) String() string { return proto.CompactTextString(m) } +func (*QueryInterchainAccountResponse) ProtoMessage() {} +func (*QueryInterchainAccountResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f9a6327305204300, []int{1} +} +func (m *QueryInterchainAccountResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryInterchainAccountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryInterchainAccountResponse.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 *QueryInterchainAccountResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryInterchainAccountResponse.Merge(m, src) +} +func (m *QueryInterchainAccountResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryInterchainAccountResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryInterchainAccountResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryInterchainAccountResponse proto.InternalMessageInfo + +func (m *QueryInterchainAccountResponse) GetInterchainAccountAddress() string { + if m != nil { + return m.InterchainAccountAddress + } + return "" +} + +func init() { + proto.RegisterType((*QueryInterchainAccountRequest)(nil), "interchain_security.ccv.icamauth.v1.QueryInterchainAccountRequest") + proto.RegisterType((*QueryInterchainAccountResponse)(nil), "interchain_security.ccv.icamauth.v1.QueryInterchainAccountResponse") +} + +func init() { + proto.RegisterFile("interchain_security/ccv/icamauth/v1/query.proto", fileDescriptor_f9a6327305204300) +} + +var fileDescriptor_f9a6327305204300 = []byte{ + // 388 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x52, 0xbf, 0x6b, 0xdb, 0x40, + 0x14, 0xb6, 0x04, 0x2e, 0xf4, 0x68, 0x87, 0x0a, 0x0f, 0x42, 0xb4, 0x72, 0xab, 0x52, 0xe8, 0x52, + 0x1d, 0x6e, 0x37, 0x43, 0x07, 0x2b, 0x93, 0xc7, 0x88, 0x4c, 0x59, 0x9c, 0xf3, 0xe9, 0x90, 0x0e, + 0xac, 0x3b, 0x59, 0x77, 0x52, 0x22, 0x8c, 0x97, 0x40, 0x32, 0x1b, 0xf2, 0x4f, 0x65, 0x34, 0x64, + 0xc9, 0x64, 0x82, 0x9d, 0xbf, 0xc0, 0x7f, 0x41, 0x90, 0x8e, 0xf8, 0x47, 0x1c, 0x07, 0x43, 0x26, + 0xe9, 0xf1, 0xbd, 0xf7, 0xbe, 0xef, 0xbe, 0xef, 0x01, 0x48, 0x99, 0x24, 0x29, 0x8e, 0x10, 0x65, + 0x3d, 0x41, 0x70, 0x96, 0x52, 0x59, 0x40, 0x8c, 0x73, 0x48, 0x31, 0x8a, 0x51, 0x26, 0x23, 0x98, + 0xb7, 0xe0, 0x30, 0x23, 0x69, 0xe1, 0x26, 0x29, 0x97, 0xdc, 0xf8, 0xf9, 0xca, 0x80, 0x8b, 0x71, + 0xee, 0x3e, 0x0f, 0xb8, 0x79, 0xcb, 0x6a, 0x84, 0x3c, 0xe4, 0x55, 0x3f, 0x2c, 0xff, 0xd4, 0xa8, + 0xf5, 0x35, 0xe4, 0x3c, 0x1c, 0x10, 0x88, 0x12, 0x0a, 0x11, 0x63, 0x5c, 0x22, 0x49, 0x39, 0x13, + 0x0a, 0x75, 0x24, 0xf8, 0x76, 0x5c, 0xf2, 0x74, 0x57, 0xfb, 0x3b, 0x18, 0xf3, 0x8c, 0x49, 0x9f, + 0x0c, 0x33, 0x22, 0xa4, 0xd1, 0x00, 0x75, 0x7e, 0xce, 0x48, 0x6a, 0x6a, 0xdf, 0xb5, 0xdf, 0x1f, + 0x7d, 0x55, 0x18, 0xff, 0xc1, 0x67, 0xcc, 0x19, 0x23, 0xb8, 0xdc, 0xd5, 0xa3, 0x81, 0xa9, 0x97, + 0xa8, 0x67, 0x2e, 0x67, 0xcd, 0x46, 0x81, 0xe2, 0x41, 0xdb, 0xd9, 0x82, 0x1d, 0xff, 0xd3, 0xba, + 0xee, 0x06, 0xce, 0x95, 0x06, 0xec, 0x7d, 0xb4, 0x22, 0xe1, 0x4c, 0x10, 0x03, 0x03, 0x6b, 0xe3, + 0xcd, 0x48, 0xa1, 0x3d, 0x14, 0x04, 0x29, 0x11, 0x42, 0x89, 0xf1, 0x7e, 0x2d, 0x67, 0xcd, 0x1f, + 0x8a, 0x6e, 0x7f, 0xaf, 0xe3, 0x9b, 0xf4, 0x25, 0x4b, 0x47, 0x41, 0x7f, 0x27, 0x3a, 0xa8, 0x57, + 0x3a, 0x8c, 0x6b, 0x1d, 0x7c, 0xd9, 0x11, 0x63, 0x78, 0xee, 0x01, 0xbe, 0xbb, 0x6f, 0x1a, 0x68, + 0x1d, 0xbd, 0x6b, 0x87, 0x72, 0xc3, 0x89, 0x2e, 0xef, 0x1e, 0x6f, 0xf4, 0xbe, 0x71, 0x76, 0xd0, + 0xe5, 0xec, 0x9a, 0x01, 0xab, 0xd8, 0xe0, 0xa8, 0xfa, 0x8c, 0xe1, 0x3a, 0x0c, 0x38, 0xda, 0x0a, + 0x6a, 0xec, 0x9d, 0xdc, 0xce, 0x6d, 0x6d, 0x3a, 0xb7, 0xb5, 0x87, 0xb9, 0xad, 0x4d, 0x16, 0x76, + 0x6d, 0xba, 0xb0, 0x6b, 0xf7, 0x0b, 0xbb, 0x76, 0xda, 0x0e, 0xa9, 0x8c, 0xb2, 0xbe, 0x8b, 0x79, + 0x0c, 0x31, 0x17, 0x31, 0x17, 0x1b, 0x44, 0x7f, 0x56, 0x62, 0x2e, 0xb6, 0xe5, 0xc8, 0x22, 0x21, + 0xa2, 0xff, 0xa1, 0xba, 0xb6, 0x7f, 0x4f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xc0, 0x62, 0xc4, + 0xf9, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // QueryInterchainAccount returns the interchain account for given owner + // address on a given connection pair + InterchainAccount(ctx context.Context, in *QueryInterchainAccountRequest, opts ...grpc.CallOption) (*QueryInterchainAccountResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) InterchainAccount(ctx context.Context, in *QueryInterchainAccountRequest, opts ...grpc.CallOption) (*QueryInterchainAccountResponse, error) { + out := new(QueryInterchainAccountResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.icamauth.v1.Query/InterchainAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // QueryInterchainAccount returns the interchain account for given owner + // address on a given connection pair + InterchainAccount(context.Context, *QueryInterchainAccountRequest) (*QueryInterchainAccountResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) InterchainAccount(ctx context.Context, req *QueryInterchainAccountRequest) (*QueryInterchainAccountResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method InterchainAccount not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_InterchainAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryInterchainAccountRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).InterchainAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.icamauth.v1.Query/InterchainAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).InterchainAccount(ctx, req.(*QueryInterchainAccountRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "interchain_security.ccv.icamauth.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "InterchainAccount", + Handler: _Query_InterchainAccount_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "interchain_security/ccv/icamauth/v1/query.proto", +} + +func (m *QueryInterchainAccountRequest) 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 *QueryInterchainAccountRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryInterchainAccountRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConnectionId) > 0 { + i -= len(m.ConnectionId) + copy(dAtA[i:], m.ConnectionId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConnectionId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Owner) > 0 { + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryInterchainAccountResponse) 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 *QueryInterchainAccountResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryInterchainAccountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.InterchainAccountAddress) > 0 { + i -= len(m.InterchainAccountAddress) + copy(dAtA[i:], m.InterchainAccountAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.InterchainAccountAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryInterchainAccountRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Owner) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ConnectionId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryInterchainAccountResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.InterchainAccountAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryInterchainAccountRequest) 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 ErrIntOverflowQuery + } + 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: QueryInterchainAccountRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryInterchainAccountRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnectionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryInterchainAccountResponse) 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 ErrIntOverflowQuery + } + 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: QueryInterchainAccountResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryInterchainAccountResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InterchainAccountAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InterchainAccountAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ccv/icamauth/types/query.pb.gw.go b/x/ccv/icamauth/types/query.pb.gw.go new file mode 100644 index 0000000000..14cfca64ae --- /dev/null +++ b/x/ccv/icamauth/types/query.pb.gw.go @@ -0,0 +1,211 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: interchain_security/ccv/icamauth/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_InterchainAccount_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryInterchainAccountRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["owner"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "owner") + } + + protoReq.Owner, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "owner", err) + } + + val, ok = pathParams["connection_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "connection_id") + } + + protoReq.ConnectionId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "connection_id", err) + } + + msg, err := client.InterchainAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_InterchainAccount_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryInterchainAccountRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["owner"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "owner") + } + + protoReq.Owner, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "owner", err) + } + + val, ok = pathParams["connection_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "connection_id") + } + + protoReq.ConnectionId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "connection_id", err) + } + + msg, err := server.InterchainAccount(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_InterchainAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_InterchainAccount_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_InterchainAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_InterchainAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_InterchainAccount_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_InterchainAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_InterchainAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"interchain_security", "ccv", "icamauth", "v1", "interchain_account", "owner", "connection", "connection_id"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_InterchainAccount_0 = runtime.ForwardResponseMessage +) diff --git a/x/ccv/icamauth/types/tx.pb.go b/x/ccv/icamauth/types/tx.pb.go new file mode 100644 index 0000000000..4a3ff643b5 --- /dev/null +++ b/x/ccv/icamauth/types/tx.pb.go @@ -0,0 +1,1042 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: interchain_security/ccv/icamauth/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + 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 + +// MsgRegisterAccount defines the payload for Msg/RegisterAccount +type MsgRegisterAccount struct { + Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` + ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` +} + +func (m *MsgRegisterAccount) Reset() { *m = MsgRegisterAccount{} } +func (m *MsgRegisterAccount) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterAccount) ProtoMessage() {} +func (*MsgRegisterAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_d5338b4997f93958, []int{0} +} +func (m *MsgRegisterAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterAccount.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 *MsgRegisterAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterAccount.Merge(m, src) +} +func (m *MsgRegisterAccount) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterAccount) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterAccount proto.InternalMessageInfo + +// MsgRegisterAccountResponse defines the response for Msg/RegisterAccount +type MsgRegisterAccountResponse struct { +} + +func (m *MsgRegisterAccountResponse) Reset() { *m = MsgRegisterAccountResponse{} } +func (m *MsgRegisterAccountResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterAccountResponse) ProtoMessage() {} +func (*MsgRegisterAccountResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d5338b4997f93958, []int{1} +} +func (m *MsgRegisterAccountResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterAccountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterAccountResponse.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 *MsgRegisterAccountResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterAccountResponse.Merge(m, src) +} +func (m *MsgRegisterAccountResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterAccountResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterAccountResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterAccountResponse proto.InternalMessageInfo + +// MsgSubmitTx defines the payload for Msg/SubmitTx +type MsgSubmitTx struct { + Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` + ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"` + Msg *types.Any `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (m *MsgSubmitTx) Reset() { *m = MsgSubmitTx{} } +func (m *MsgSubmitTx) String() string { return proto.CompactTextString(m) } +func (*MsgSubmitTx) ProtoMessage() {} +func (*MsgSubmitTx) Descriptor() ([]byte, []int) { + return fileDescriptor_d5338b4997f93958, []int{2} +} +func (m *MsgSubmitTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitTx.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 *MsgSubmitTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitTx.Merge(m, src) +} +func (m *MsgSubmitTx) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitTx) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitTx.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitTx proto.InternalMessageInfo + +// MsgSubmitTxResponse defines the response for Msg/SubmitTx +type MsgSubmitTxResponse struct { +} + +func (m *MsgSubmitTxResponse) Reset() { *m = MsgSubmitTxResponse{} } +func (m *MsgSubmitTxResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSubmitTxResponse) ProtoMessage() {} +func (*MsgSubmitTxResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d5338b4997f93958, []int{3} +} +func (m *MsgSubmitTxResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitTxResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitTxResponse.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 *MsgSubmitTxResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitTxResponse.Merge(m, src) +} +func (m *MsgSubmitTxResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitTxResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitTxResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitTxResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgRegisterAccount)(nil), "interchain_security.ccv.icamauth.v1.MsgRegisterAccount") + proto.RegisterType((*MsgRegisterAccountResponse)(nil), "interchain_security.ccv.icamauth.v1.MsgRegisterAccountResponse") + proto.RegisterType((*MsgSubmitTx)(nil), "interchain_security.ccv.icamauth.v1.MsgSubmitTx") + proto.RegisterType((*MsgSubmitTxResponse)(nil), "interchain_security.ccv.icamauth.v1.MsgSubmitTxResponse") +} + +func init() { + proto.RegisterFile("interchain_security/ccv/icamauth/v1/tx.proto", fileDescriptor_d5338b4997f93958) +} + +var fileDescriptor_d5338b4997f93958 = []byte{ + // 409 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0x4f, 0x8b, 0xd3, 0x40, + 0x18, 0xc6, 0x33, 0x2d, 0x6a, 0x9d, 0x2a, 0x42, 0x8c, 0x10, 0x83, 0xa4, 0x12, 0x41, 0x3c, 0xe8, + 0x8c, 0xad, 0x07, 0xa5, 0x20, 0xd2, 0xde, 0x3c, 0xf4, 0x12, 0x7b, 0xf2, 0x52, 0x92, 0xe9, 0x38, + 0x1d, 0x68, 0x66, 0x4a, 0x66, 0x12, 0x9b, 0x6f, 0x20, 0x14, 0xc1, 0x83, 0x1f, 0xa0, 0x1f, 0x67, + 0x8f, 0x3d, 0xee, 0x69, 0x59, 0xda, 0xcb, 0x9e, 0xf7, 0x13, 0x2c, 0x4d, 0x48, 0xff, 0x6c, 0xf7, + 0xd0, 0x5d, 0xd8, 0xdb, 0x3c, 0xbc, 0xcf, 0x33, 0xf3, 0xe3, 0x19, 0x5e, 0xf8, 0x9e, 0x0b, 0x4d, + 0x63, 0x32, 0x0a, 0xb8, 0x18, 0x28, 0x4a, 0x92, 0x98, 0xeb, 0x0c, 0x13, 0x92, 0x62, 0x4e, 0x82, + 0x28, 0x48, 0xf4, 0x08, 0xa7, 0x4d, 0xac, 0xa7, 0x68, 0x12, 0x4b, 0x2d, 0xcd, 0x37, 0x37, 0xb8, + 0x11, 0x21, 0x29, 0x2a, 0xdd, 0x28, 0x6d, 0x3a, 0x16, 0x93, 0x4c, 0xe6, 0x7e, 0xbc, 0x3e, 0x15, + 0x51, 0xe7, 0x25, 0x93, 0x92, 0x8d, 0x29, 0xce, 0x55, 0x98, 0xfc, 0xc2, 0x81, 0xc8, 0x8a, 0x91, + 0xf7, 0x17, 0x40, 0xb3, 0xa7, 0x98, 0x4f, 0x19, 0x57, 0x9a, 0xc6, 0x1d, 0x42, 0x64, 0x22, 0xb4, + 0x69, 0xc1, 0x07, 0xf2, 0xb7, 0xa0, 0xb1, 0x0d, 0x5e, 0x83, 0x77, 0x8f, 0xfd, 0x42, 0x98, 0x5f, + 0xe1, 0x53, 0x22, 0x85, 0xa0, 0x44, 0x73, 0x29, 0x06, 0x7c, 0x68, 0x57, 0xd6, 0xd3, 0xae, 0x7d, + 0x79, 0xd6, 0xb0, 0xb2, 0x20, 0x1a, 0xb7, 0xbd, 0xbd, 0xb1, 0xe7, 0x3f, 0xd9, 0xea, 0xef, 0x43, + 0xd3, 0x86, 0x8f, 0x52, 0x1a, 0x2b, 0x2e, 0x85, 0x5d, 0xcd, 0xaf, 0x2d, 0x65, 0xbb, 0xf6, 0x67, + 0xde, 0x30, 0x2e, 0xe6, 0x0d, 0xc3, 0x7b, 0x05, 0x9d, 0x43, 0x1c, 0x9f, 0xaa, 0x89, 0x14, 0x8a, + 0x7a, 0xff, 0x01, 0xac, 0xf7, 0x14, 0xfb, 0x91, 0x84, 0x11, 0xd7, 0xfd, 0xe9, 0xfd, 0x60, 0xbe, + 0x85, 0xd5, 0x48, 0xb1, 0x1c, 0xb1, 0xde, 0xb2, 0x50, 0xd1, 0x1d, 0x2a, 0xbb, 0x43, 0x1d, 0x91, + 0xf9, 0x6b, 0xc3, 0x0e, 0xf4, 0x0b, 0xf8, 0x7c, 0x87, 0xaa, 0xa4, 0x6d, 0xcd, 0x2a, 0xb0, 0xda, + 0x53, 0xcc, 0x9c, 0x01, 0xf8, 0xec, 0x7a, 0xc1, 0x9f, 0xd1, 0x11, 0xdf, 0x89, 0x0e, 0xab, 0x70, + 0xbe, 0xdd, 0x31, 0x58, 0x52, 0x99, 0x29, 0xac, 0x6d, 0xfa, 0xfb, 0x78, 0xec, 0x65, 0x65, 0xc2, + 0xf9, 0x72, 0xdb, 0x44, 0xf9, 0x6e, 0xb7, 0x7f, 0xb2, 0x74, 0xc1, 0x62, 0xe9, 0x82, 0xf3, 0xa5, + 0x0b, 0xfe, 0xad, 0x5c, 0x63, 0xb1, 0x72, 0x8d, 0xd3, 0x95, 0x6b, 0xfc, 0x6c, 0x33, 0xae, 0x47, + 0x49, 0x88, 0x88, 0x8c, 0x30, 0x91, 0x2a, 0x92, 0x0a, 0x6f, 0x1f, 0xf9, 0xb0, 0xd9, 0x8c, 0xe9, + 0xfe, 0x6e, 0xe8, 0x6c, 0x42, 0x55, 0xf8, 0x30, 0xff, 0x97, 0x4f, 0x57, 0x01, 0x00, 0x00, 0xff, + 0xff, 0xf8, 0xf8, 0xca, 0x50, 0x4c, 0x03, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // Register defines a rpc handler for MsgRegisterAccount + RegisterAccount(ctx context.Context, in *MsgRegisterAccount, opts ...grpc.CallOption) (*MsgRegisterAccountResponse, error) + // SubmitTx defines a rpc handler for MsgSubmitTx + SubmitTx(ctx context.Context, in *MsgSubmitTx, opts ...grpc.CallOption) (*MsgSubmitTxResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) RegisterAccount(ctx context.Context, in *MsgRegisterAccount, opts ...grpc.CallOption) (*MsgRegisterAccountResponse, error) { + out := new(MsgRegisterAccountResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.icamauth.v1.Msg/RegisterAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) SubmitTx(ctx context.Context, in *MsgSubmitTx, opts ...grpc.CallOption) (*MsgSubmitTxResponse, error) { + out := new(MsgSubmitTxResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.icamauth.v1.Msg/SubmitTx", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // Register defines a rpc handler for MsgRegisterAccount + RegisterAccount(context.Context, *MsgRegisterAccount) (*MsgRegisterAccountResponse, error) + // SubmitTx defines a rpc handler for MsgSubmitTx + SubmitTx(context.Context, *MsgSubmitTx) (*MsgSubmitTxResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) RegisterAccount(ctx context.Context, req *MsgRegisterAccount) (*MsgRegisterAccountResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterAccount not implemented") +} +func (*UnimplementedMsgServer) SubmitTx(ctx context.Context, req *MsgSubmitTx) (*MsgSubmitTxResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubmitTx not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_RegisterAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRegisterAccount) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RegisterAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.icamauth.v1.Msg/RegisterAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RegisterAccount(ctx, req.(*MsgRegisterAccount)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_SubmitTx_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSubmitTx) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SubmitTx(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.icamauth.v1.Msg/SubmitTx", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SubmitTx(ctx, req.(*MsgSubmitTx)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "interchain_security.ccv.icamauth.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "RegisterAccount", + Handler: _Msg_RegisterAccount_Handler, + }, + { + MethodName: "SubmitTx", + Handler: _Msg_SubmitTx_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "interchain_security/ccv/icamauth/v1/tx.proto", +} + +func (m *MsgRegisterAccount) 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 *MsgRegisterAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintTx(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0x1a + } + if len(m.ConnectionId) > 0 { + i -= len(m.ConnectionId) + copy(dAtA[i:], m.ConnectionId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ConnectionId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Owner) > 0 { + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = encodeVarintTx(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRegisterAccountResponse) 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 *MsgRegisterAccountResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterAccountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgSubmitTx) 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 *MsgSubmitTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Msg != nil { + { + size, err := m.Msg.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if len(m.ConnectionId) > 0 { + i -= len(m.ConnectionId) + copy(dAtA[i:], m.ConnectionId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ConnectionId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Owner) > 0 { + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = encodeVarintTx(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSubmitTxResponse) 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 *MsgSubmitTxResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitTxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgRegisterAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Owner) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ConnectionId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Version) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRegisterAccountResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgSubmitTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Owner) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ConnectionId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Msg != nil { + l = m.Msg.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgSubmitTxResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgRegisterAccount) 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 ErrIntOverflowTx + } + 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: MsgRegisterAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnectionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRegisterAccountResponse) 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 ErrIntOverflowTx + } + 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: MsgRegisterAccountResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterAccountResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSubmitTx) 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 ErrIntOverflowTx + } + 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: MsgSubmitTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnectionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Msg == nil { + m.Msg = &types.Any{} + } + if err := m.Msg.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSubmitTxResponse) 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 ErrIntOverflowTx + } + 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: MsgSubmitTxResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitTxResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ccv/provider/client/proposal_handler.go b/x/ccv/provider/client/proposal_handler.go index 345001c64a..86bf0fa9fd 100644 --- a/x/ccv/provider/client/proposal_handler.go +++ b/x/ccv/provider/client/proposal_handler.go @@ -4,12 +4,15 @@ import ( "encoding/json" "io/ioutil" "net/http" + "os" "time" "path/filepath" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" + sdkcodec "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" govclient "github.com/cosmos/cosmos-sdk/x/gov/client" @@ -17,11 +20,18 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" "github.com/cosmos/interchain-security/x/ccv/provider/types" + "github.com/golang/protobuf/proto" "github.com/spf13/cobra" ) // ProposalHandler is the param change proposal handler. var ProposalHandler = govclient.NewProposalHandler(SubmitConsumerAdditionPropTxCmd, ProposalRESTHandler) +var ConsumerGovernanceHandler = govclient.NewProposalHandler(SubmitConsumerGovernancePropTxCmd, ConsumerGovernanceProposalRESTHandler) + +const ( + FlagUpgradeHeight = "upgrade-height" + FlagUpgradeInfo = "upgrade-info" +) // SubmitConsumerAdditionPropTxCmd returns a CLI command handler for submitting // a consumer addition proposal via a transaction. @@ -85,6 +95,22 @@ Where proposal.json contains: } } +// ConsumerGovernanceProposalJSON defines the new Msg-based proposal. +type ConsumerGovernanceProposalJSON struct { + Content json.RawMessage `json:"content"` + ConnectionId string `json:"connection_id"` + Deposit string `json:"deposit"` +} + +type ConsumerGovernanceProposalReq struct { + BaseReq rest.BaseReq `json:"base_req"` + Proposer sdk.AccAddress `json:"proposer"` + + Content json.RawMessage `json:"content"` + ConnectionId string `json:"connection_id"` + Deposit sdk.Coins `json:"deposit"` +} + type ConsumerAdditionProposalJSON struct { Title string `json:"title"` Description string `json:"description"` @@ -162,3 +188,122 @@ func postProposalHandlerFn(clientCtx client.Context) http.HandlerFunc { tx.WriteGeneratedTxResponse(clientCtx, w, req.BaseReq, msg) } } + +// SubmitConsumerGovernancePropTxCmd returns a CLI command handler for submitting +// a consumer governance proposal via a transaction. +func SubmitConsumerGovernancePropTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "consumer-governance path/to/proposal.json", + Args: cobra.ExactArgs(1), + Short: "Submit a consumer chain governance proposal", + Long: ` +Submit a consumer chain governance proposal along with an initial deposit. + +Example: +$ interchain-security-pd tx gov submit-proposal consumer-governance path/to/proposal.json --from=`, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + proposalPath := args[0] + connectionId, content, deposit, err := parseSubmitProposal(clientCtx.Codec, proposalPath) + if err != nil { + return err + } + + any, err := codectypes.NewAnyWithValue(content.(proto.Message)) + if err != nil { + return err + } + + consumerProposal := types.ConsumerGovernanceProposal{ + ConnectionId: connectionId, + Content: any, + } + + msg, err := govtypes.NewMsgSubmitProposal(&consumerProposal, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + return cmd +} + +func ConsumerGovernanceProposalRESTHandler(clientCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "propose_consumer_governance", + Handler: postProposalGovernanceHandlerFn(clientCtx), + } +} + +func postProposalGovernanceHandlerFn(clientCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req ConsumerGovernanceProposalReq + if !rest.ReadRESTReq(w, r, clientCtx.LegacyAmino, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + var content govtypes.Content + err := clientCtx.Codec.UnmarshalInterfaceJSON(req.Content, &content) + if err != nil { + return + } + any, err := codectypes.NewAnyWithValue(content.(proto.Message)) + if err != nil { + return + } + consumerProposal := types.ConsumerGovernanceProposal{ + ConnectionId: req.ConnectionId, + Content: any, + } + + msg, err := govtypes.NewMsgSubmitProposal(&consumerProposal, req.Deposit, req.Proposer) + if rest.CheckBadRequestError(w, err) { + return + } + + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + tx.WriteGeneratedTxResponse(clientCtx, w, req.BaseReq, msg) + } +} + +func parseSubmitProposal(cdc sdkcodec.Codec, path string) (string, govtypes.Content, sdk.Coins, error) { + var proposal ConsumerGovernanceProposalJSON + + proposalJson, err := os.ReadFile(filepath.Clean(path)) + if err != nil { + return "", nil, nil, err + } + + err = json.Unmarshal(proposalJson, &proposal) + if err != nil { + return "", nil, nil, err + } + + var content govtypes.Content + err = cdc.UnmarshalInterfaceJSON(proposal.Content, &content) + if err != nil { + return "", nil, nil, err + } + + deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit) + if err != nil { + return "", nil, nil, err + } + + return proposal.ConnectionId, content, deposit, nil +} diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go index 8792236d14..c7fb2c6c62 100644 --- a/x/ccv/provider/ibc_module.go +++ b/x/ccv/provider/ibc_module.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v3/modules/core/24-host" @@ -143,6 +144,18 @@ func (am AppModule) OnChanOpenConfirm( if err != nil { return err } + + connHops, err := am.keeper.GetConnectionHops(ctx, portID, channelID) + if err != nil { + return err + } + + govAddress := am.accountKeeper.GetModuleAddress(govtypes.ModuleName) + err = am.icaControllerKeeper.RegisterInterchainAccount(ctx, connHops[0], govAddress.String()) + if err != nil { + return err + } + return nil } diff --git a/x/ccv/provider/ibc_module_test.go b/x/ccv/provider/ibc_module_test.go index c2ebbe636f..97675d9e12 100644 --- a/x/ccv/provider/ibc_module_test.go +++ b/x/ccv/provider/ibc_module_test.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" conntypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v3/modules/core/24-host" @@ -25,10 +26,10 @@ import ( // Spec Tag: [CCV-PCF-COINIT.1] func TestOnChanOpenInit(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx( + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx( t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - providerModule := provider.NewAppModule(&providerKeeper) + providerModule := provider.NewAppModule(&providerKeeper, mocks.MockAccountKeeper, mocks.MockICAControllerKeeper) // OnChanOpenInit must error for provider even with correct arguments err := providerModule.OnChanOpenInit( @@ -116,7 +117,7 @@ func TestOnChanOpenTry(t *testing.T) { // Setup providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx( t, testkeeper.NewInMemKeeperParams(t)) - providerModule := provider.NewAppModule(&providerKeeper) + providerModule := provider.NewAppModule(&providerKeeper, mocks.MockAccountKeeper, mocks.MockICAControllerKeeper) providerKeeper.SetPort(ctx, ccv.ProviderPortID) providerKeeper.SetConsumerClientId(ctx, "consumerChainID", "clientIDToConsumer") @@ -183,10 +184,10 @@ func TestOnChanOpenTry(t *testing.T) { // See: https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/methods.md#ccv-pcf-coack1 // Spec tag: [CCV-PCF-COACK.1] func TestOnChanOpenAck(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx( + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx( t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - providerModule := provider.NewAppModule(&providerKeeper) + providerModule := provider.NewAppModule(&providerKeeper, mocks.MockAccountKeeper, mocks.MockICAControllerKeeper) // OnChanOpenAck must error for provider even with correct arguments err := providerModule.OnChanOpenAck( @@ -290,8 +291,16 @@ func TestOnChanOpenConfirm(t *testing.T) { { name: "success", mockExpectations: func(ctx sdk.Context, mocks testkeeper.MockedKeepers) []*gomock.Call { + govModuleAddress := authtypes.NewModuleAddress(govtypes.ModuleName) + var chann channeltypes.Channel = channeltypes.Channel{ + ConnectionHops: []string{"connection-0"}, + } + // Full SetConsumerChain method should run without error, hitting all expected mocks - return testkeeper.GetMocksForSetConsumerChain(ctx, &mocks, "consumerChainID") + return append(testkeeper.GetMocksForSetConsumerChain(ctx, &mocks, "consumerChainID"), + mocks.MockChannelKeeper.EXPECT().GetChannel(ctx, "providerPortID", "channelID").Return(chann, true).Times(1), + mocks.MockAccountKeeper.EXPECT().GetModuleAddress(govtypes.ModuleName).Return(govModuleAddress).Times(1), + mocks.MockICAControllerKeeper.EXPECT().RegisterInterchainAccount(ctx, "connection-0", govModuleAddress.String()).Return(nil).Times(1)) }, expPass: true, }, @@ -308,7 +317,7 @@ func TestOnChanOpenConfirm(t *testing.T) { providerKeeper.SetChainToChannel(ctx, "consumerChainID", "existingChannelID") } - providerModule := provider.NewAppModule(&providerKeeper) + providerModule := provider.NewAppModule(&providerKeeper, mocks.MockAccountKeeper, mocks.MockICAControllerKeeper) err := providerModule.OnChanOpenConfirm(ctx, "providerPortID", "channelID") diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go index 2a0f392b91..b5d3d08f99 100644 --- a/x/ccv/provider/keeper/keeper.go +++ b/x/ccv/provider/keeper/keeper.go @@ -29,18 +29,20 @@ import ( // Keeper defines the Cross-Chain Validation Provider Keeper type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryCodec - paramSpace paramtypes.Subspace - scopedKeeper ccv.ScopedKeeper - channelKeeper ccv.ChannelKeeper - portKeeper ccv.PortKeeper - connectionKeeper ccv.ConnectionKeeper - accountKeeper ccv.AccountKeeper - clientKeeper ccv.ClientKeeper - stakingKeeper ccv.StakingKeeper - slashingKeeper ccv.SlashingKeeper - feeCollectorName string + storeKey sdk.StoreKey + cdc codec.BinaryCodec + paramSpace paramtypes.Subspace + scopedKeeper ccv.ScopedKeeper + channelKeeper ccv.ChannelKeeper + portKeeper ccv.PortKeeper + connectionKeeper ccv.ConnectionKeeper + accountKeeper ccv.AccountKeeper + clientKeeper ccv.ClientKeeper + stakingKeeper ccv.StakingKeeper + slashingKeeper ccv.SlashingKeeper + icaControllerKeeper ccv.ICAControllerKeeper + icaScopedKeeper ccv.ScopedKeeper + feeCollectorName string } // NewKeeper creates a new provider Keeper instance @@ -49,7 +51,8 @@ func NewKeeper( channelKeeper ccv.ChannelKeeper, portKeeper ccv.PortKeeper, connectionKeeper ccv.ConnectionKeeper, clientKeeper ccv.ClientKeeper, stakingKeeper ccv.StakingKeeper, slashingKeeper ccv.SlashingKeeper, - accountKeeper ccv.AccountKeeper, feeCollectorName string, + accountKeeper ccv.AccountKeeper, icaControllerKeeper ccv.ICAControllerKeeper, + icaScopedKeeper ccv.ScopedKeeper, feeCollectorName string, ) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { @@ -57,18 +60,20 @@ func NewKeeper( } return Keeper{ - cdc: cdc, - storeKey: key, - paramSpace: paramSpace, - scopedKeeper: scopedKeeper, - channelKeeper: channelKeeper, - portKeeper: portKeeper, - connectionKeeper: connectionKeeper, - accountKeeper: accountKeeper, - clientKeeper: clientKeeper, - stakingKeeper: stakingKeeper, - slashingKeeper: slashingKeeper, - feeCollectorName: feeCollectorName, + cdc: cdc, + storeKey: key, + paramSpace: paramSpace, + scopedKeeper: scopedKeeper, + channelKeeper: channelKeeper, + portKeeper: portKeeper, + connectionKeeper: connectionKeeper, + accountKeeper: accountKeeper, + clientKeeper: clientKeeper, + stakingKeeper: stakingKeeper, + slashingKeeper: slashingKeeper, + icaControllerKeeper: icaControllerKeeper, + icaScopedKeeper: icaScopedKeeper, + feeCollectorName: feeCollectorName, } } @@ -826,3 +831,16 @@ func (k Keeper) DeleteConsumerClientId(ctx sdk.Context, chainID string) { store := ctx.KVStore(k.storeKey) store.Delete(types.ChainToClientKey(chainID)) } + +func (k Keeper) GetConnectionHops(ctx sdk.Context, portID, channelID string) ([]string, error) { + channel, ok := k.channelKeeper.GetChannel(ctx, portID, channelID) + if !ok { + return []string{}, sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "channel not found for channel ID: %s", channelID) + } + + if len(channel.ConnectionHops) == 0 { + return []string{}, sdkerrors.Wrap(channeltypes.ErrTooManyConnectionHops, "no connection hops") + } + + return channel.ConnectionHops, nil +} diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index b66aa47812..4e306f29c6 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -1,6 +1,7 @@ package keeper import ( + "errors" "fmt" "time" @@ -17,6 +18,10 @@ import ( utils "github.com/cosmos/interchain-security/x/ccv/utils" abci "github.com/tendermint/tendermint/abci/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + adminmodulemoduletypes "github.com/cosmos/interchain-security/x/ccv/adminmodule/types" consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" ) @@ -108,6 +113,58 @@ func (k Keeper) HandleConsumerRemovalProposal(ctx sdk.Context, p *types.Consumer return nil } +func (k Keeper) HandleConsumerGovernanceProposal(ctx sdk.Context, p *types.ConsumerGovernanceProposal) error { + govAddress := k.accountKeeper.GetModuleAddress(govtypes.ModuleName).String() + portID, err := icatypes.NewControllerPortID(govAddress) + if err != nil { + return err + } + + govICAAccount, found := k.icaControllerKeeper.GetInterchainAccountAddress(ctx, p.ConnectionId, portID) + if !found { + return fmt.Errorf("governance module interchain account for port id %s doesn't exist", portID) + } + + cached := p.Content.GetCachedValue() + if cached == nil || cached.(govtypes.Content) == nil { + return errors.New("consumer governance content is not valid") + } + + channelID, found := k.icaControllerKeeper.GetActiveChannelID(ctx, p.ConnectionId, portID) + if !found { + return sdkerrors.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel for port %s", portID) + } + + // ICA authentication module owns channel capability + chanCap, found := k.icaScopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) + if !found { + return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + + msg := adminmodulemoduletypes.MsgSubmitProposal{ + Content: p.Content, + Proposer: govICAAccount, + } + + data, err := icatypes.SerializeCosmosTx(k.cdc, []sdk.Msg{&msg}) + if err != nil { + return err + } + + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + timeoutTimestamp := ctx.BlockTime().Add(time.Minute).UnixNano() + _, err = k.icaControllerKeeper.SendTx(ctx, chanCap, p.ConnectionId, portID, packetData, uint64(timeoutTimestamp)) + if err != nil { + return err + } + + return nil +} + // StopConsumerChain cleans up the states for the given consumer chain ID and, if the given lockUbd is false, // it completes the outstanding unbonding operations lock by the consumer chain. // @@ -243,6 +300,7 @@ func (k Keeper) MakeConsumerGenesis(ctx sdk.Context) (gen consumertypes.GenesisS } gen.InitialValSet = updates + gen.ProviderGovernanceAddress = k.accountKeeper.GetModuleAddress(govtypes.ModuleName).String() return gen, nil } diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 278f81e43b..d265edd253 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -641,7 +641,7 @@ func TestMakeConsumerGenesis(t *testing.T) { actualGenesis, err := providerKeeper.MakeConsumerGenesis(ctx) require.NoError(t, err) - jsonString := `{"params":{"enabled":true, "blocks_per_distribution_transmission":1000, "ccv_timeout_period":2419200000000000, "transfer_timeout_period": 3600000000000, "consumer_redistribution_fraction":"0.75", "historical_entries":10000},"new_chain":true,"provider_client_state":{"chain_id":"testchain1","trust_level":{"numerator":1,"denominator":3},"trusting_period":907200000000000,"unbonding_period":1814400000000000,"max_clock_drift":10000000000,"frozen_height":{},"latest_height":{"revision_height":5},"proof_specs":[{"leaf_spec":{"hash":1,"prehash_value":1,"length":1,"prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":33,"min_prefix_length":4,"max_prefix_length":12,"hash":1}},{"leaf_spec":{"hash":1,"prehash_value":1,"length":1,"prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":32,"min_prefix_length":1,"max_prefix_length":1,"hash":1}}],"upgrade_path":["upgrade","upgradedIBCState"],"allow_update_after_expiry":true,"allow_update_after_misbehaviour":true},"provider_consensus_state":{"timestamp":"2020-01-02T00:00:10Z","root":{"hash":"LpGpeyQVLUo9HpdsgJr12NP2eCICspcULiWa5u9udOA="},"next_validators_hash":"E30CE736441FB9101FADDAF7E578ABBE6DFDB67207112350A9A904D554E1F5BE"},"unbonding_sequences":null,"initial_val_set":[{"pub_key":{"type":"tendermint/PubKeyEd25519","value":"dcASx5/LIKZqagJWN0frOlFtcvz91frYmj/zmoZRWro="},"power":1}]}` + jsonString := `{"params":{"enabled":true, "blocks_per_distribution_transmission":1000, "ccv_timeout_period":2419200000000000, "transfer_timeout_period": 3600000000000, "consumer_redistribution_fraction":"0.75", "historical_entries":10000},"new_chain":true,"provider_client_state":{"chain_id":"testchain1","trust_level":{"numerator":1,"denominator":3},"trusting_period":907200000000000,"unbonding_period":1814400000000000,"max_clock_drift":10000000000,"frozen_height":{},"latest_height":{"revision_height":5},"proof_specs":[{"leaf_spec":{"hash":1,"prehash_value":1,"length":1,"prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":33,"min_prefix_length":4,"max_prefix_length":12,"hash":1}},{"leaf_spec":{"hash":1,"prehash_value":1,"length":1,"prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":32,"min_prefix_length":1,"max_prefix_length":1,"hash":1}}],"upgrade_path":["upgrade","upgradedIBCState"],"allow_update_after_expiry":true,"allow_update_after_misbehaviour":true},"provider_consensus_state":{"timestamp":"2020-01-02T00:00:10Z","root":{"hash":"LpGpeyQVLUo9HpdsgJr12NP2eCICspcULiWa5u9udOA="},"next_validators_hash":"E30CE736441FB9101FADDAF7E578ABBE6DFDB67207112350A9A904D554E1F5BE"},"unbonding_sequences":null,"initial_val_set":[{"pub_key":{"type":"tendermint/PubKeyEd25519","value":"dcASx5/LIKZqagJWN0frOlFtcvz91frYmj/zmoZRWro="},"power":1}],"provider_governance_address": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn"}` var expectedGenesis consumertypes.GenesisState err = json.Unmarshal([]byte(jsonString), &expectedGenesis) diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index 8b6721f3d4..98e36c001b 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -21,6 +21,8 @@ import ( "github.com/cosmos/interchain-security/x/ccv/provider/client/cli" "github.com/cosmos/interchain-security/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" + + ccv "github.com/cosmos/interchain-security/x/ccv/types" ) var ( @@ -92,13 +94,17 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { // AppModule represents the AppModule for this module type AppModule struct { AppModuleBasic - keeper *keeper.Keeper + keeper *keeper.Keeper + accountKeeper ccv.AccountKeeper + icaControllerKeeper ccv.ICAControllerKeeper } // NewAppModule creates a new provider module -func NewAppModule(k *keeper.Keeper) AppModule { +func NewAppModule(k *keeper.Keeper, accountKeeper ccv.AccountKeeper, icaControllerKeeper ccv.ICAControllerKeeper) AppModule { return AppModule{ - keeper: k, + keeper: k, + accountKeeper: accountKeeper, + icaControllerKeeper: icaControllerKeeper, } } diff --git a/x/ccv/provider/module_test.go b/x/ccv/provider/module_test.go index c8ab78de94..3ba84e0627 100644 --- a/x/ccv/provider/module_test.go +++ b/x/ccv/provider/module_test.go @@ -94,7 +94,7 @@ func TestInitGenesis(t *testing.T) { keeperParams := testkeeper.NewInMemKeeperParams(t) providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, keeperParams) - appModule := provider.NewAppModule(&providerKeeper) + appModule := provider.NewAppModule(&providerKeeper, mocks.MockAccountKeeper, mocks.MockICAControllerKeeper) genState := types.NewGenesisState( providerKeeper.GetValidatorSetUpdateId(ctx), nil, diff --git a/x/ccv/provider/proposal_handler.go b/x/ccv/provider/proposal_handler.go index 55c97a26c1..20b348cb39 100644 --- a/x/ccv/provider/proposal_handler.go +++ b/x/ccv/provider/proposal_handler.go @@ -16,6 +16,8 @@ func NewConsumerChainProposalHandler(k keeper.Keeper) govtypes.Handler { return k.HandleConsumerAdditionProposal(ctx, c) case *types.ConsumerRemovalProposal: return k.HandleConsumerRemovalProposal(ctx, c) + case *types.ConsumerGovernanceProposal: + return k.HandleConsumerGovernanceProposal(ctx, c) default: return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized ccv proposal content type: %T", c) } diff --git a/x/ccv/provider/types/codec.go b/x/ccv/provider/types/codec.go index 25250f68c1..a8c7ae1884 100644 --- a/x/ccv/provider/types/codec.go +++ b/x/ccv/provider/types/codec.go @@ -17,6 +17,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations( (*govtypes.Content)(nil), &ConsumerAdditionProposal{}, + &ConsumerGovernanceProposal{}, ) } diff --git a/x/ccv/provider/types/errors.go b/x/ccv/provider/types/errors.go index decd79474b..4c84776a9b 100644 --- a/x/ccv/provider/types/errors.go +++ b/x/ccv/provider/types/errors.go @@ -10,4 +10,5 @@ var ( ErrInvalidConsumerRemovalProp = sdkerrors.Register(ModuleName, 2, "invalid consumer removal proposal") ErrUnknownConsumerChainId = sdkerrors.Register(ModuleName, 3, "no consumer chain with this chain id") ErrUnknownConsumerChannelId = sdkerrors.Register(ModuleName, 4, "no consumer chain with this channel id") + ErrInvalidConsumerGovernanceProposal = sdkerrors.Register(ModuleName, 5, "invalid consumer governance proposal") ) diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index 9283d01754..cd64a661b8 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -27,20 +27,19 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the CCV provider chain genesis state type GenesisState struct { - // empty for a completely new chain + // empty for a new chain ValsetUpdateId uint64 `protobuf:"varint,1,opt,name=valset_update_id,json=valsetUpdateId,proto3" json:"valset_update_id,omitempty"` - // empty for a completely new chain + // empty for a new chain ConsumerStates []ConsumerState `protobuf:"bytes,2,rep,name=consumer_states,json=consumerStates,proto3" json:"consumer_states" yaml:"consumer_states"` - // UnbondingOps defines the consumer chains that are still unbonding - // empty for a completely new chain + // empty for a new chain UnbondingOps []types.UnbondingOp `protobuf:"bytes,3,rep,name=unbonding_ops,json=unbondingOps,proto3" json:"unbonding_ops"` - // empty for a completely new chain + // empty for a new chain MatureUnbondingOps *types.MaturedUnbondingOps `protobuf:"bytes,4,opt,name=mature_unbonding_ops,json=matureUnbondingOps,proto3" json:"mature_unbonding_ops,omitempty"` - // empty for a completely new chain + // empty for a new chain ValsetUpdateIdToHeight []ValsetUpdateIdToHeight `protobuf:"bytes,5,rep,name=valset_update_id_to_height,json=valsetUpdateIdToHeight,proto3" json:"valset_update_id_to_height"` - // empty for a completely new chain + // empty for a new chain ConsumerAdditionProposals []ConsumerAdditionProposal `protobuf:"bytes,6,rep,name=consumer_addition_proposals,json=consumerAdditionProposals,proto3" json:"consumer_addition_proposals"` - // empty for a completely new chain + // empty for a new chain ConsumerRemovalProposals []ConsumerRemovalProposal `protobuf:"bytes,7,rep,name=consumer_removal_proposals,json=consumerRemovalProposals,proto3" json:"consumer_removal_proposals"` Params Params `protobuf:"bytes,8,opt,name=params,proto3" json:"params"` } @@ -136,19 +135,21 @@ func (m *GenesisState) GetParams() Params { // consumer chain type ConsumerState struct { - // The provider's identifier for this consumer chain. - ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - // The provider's channel identifier to this consumer chain. + // ChannelID defines the chain ID for the consumer chain + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // ChannelID defines the IBC channel ID for the consumer chain ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` // ClientID defines the IBC client ID for the consumer chain - ClientId string `protobuf:"bytes,3,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + ClientId string `protobuf:"bytes,3,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + // InitalHeight defines the initial block height for the consumer chain InitialHeight uint64 `protobuf:"varint,4,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height,omitempty"` - // LockUnbondingOnTimeout defines whether the unbonding funds should be released for this - // chain in case of a IBC channel timeout + // LockUnbondingOnTimeout defines whether the unbonding funds should be + // released for this chain in case of a IBC channel timeout LockUnbondingOnTimeout bool `protobuf:"varint,5,opt,name=lock_unbonding_on_timeout,json=lockUnbondingOnTimeout,proto3" json:"lock_unbonding_on_timeout,omitempty"` // ConsumerGenesis defines the initial consumer chain genesis states ConsumerGenesis types1.GenesisState `protobuf:"bytes,6,opt,name=consumer_genesis,json=consumerGenesis,proto3" json:"consumer_genesis"` - // PendingValsetChanges defines the pending validator set changes for the consumer chain + // PendingValsetChanges defines the pending validator set changes for the + // consumer chain PendingValsetChanges []types.ValidatorSetChangePacketData `protobuf:"bytes,7,rep,name=pending_valset_changes,json=pendingValsetChanges,proto3" json:"pending_valset_changes"` SlashDowntimeAck []string `protobuf:"bytes,8,rep,name=slash_downtime_ack,json=slashDowntimeAck,proto3" json:"slash_downtime_ack,omitempty"` // UnbondingOpsIndex defines the unbonding operations on the consumer chain @@ -251,8 +252,8 @@ func (m *ConsumerState) GetUnbondingOpsIndex() []UnbondingOpIndex { return nil } -// UnbondingOpIndex defines the genesis information for each unbonding operations index -// referenced by chain id and valset udpate id +// UnbondingOpIndex defines the genesis information for each unbonding +// operations index referenced by chain id and valset udpate id type UnbondingOpIndex struct { ValsetUpdateId uint64 `protobuf:"varint,1,opt,name=valset_update_id,json=valsetUpdateId,proto3" json:"valset_update_id,omitempty"` UnbondingOpIndex []uint64 `protobuf:"varint,2,rep,packed,name=unbonding_op_index,json=unbondingOpIndex,proto3" json:"unbonding_op_index,omitempty"` diff --git a/x/ccv/provider/types/proposal.go b/x/ccv/provider/types/proposal.go index 7462115b9a..07c149e04c 100644 --- a/x/ccv/provider/types/proposal.go +++ b/x/ccv/provider/types/proposal.go @@ -5,22 +5,27 @@ import ( "strings" time "time" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" ) const ( - ProposalTypeConsumerAddition = "ConsumerAddition" - ProposalTypeConsumerRemoval = "ConsumerRemoval" + ProposalTypeConsumerAddition = "ConsumerAddition" + ProposalTypeConsumerRemoval = "ConsumerRemoval" + ProposalTypeConsumerGovernance = "ConsumerGovernance" ) var ( - _ govtypes.Content = &ConsumerAdditionProposal{} + _ govtypes.Content = &ConsumerAdditionProposal{} + _ govtypes.Content = &ConsumerGovernanceProposal{} + _ cdctypes.UnpackInterfacesMessage = &ConsumerGovernanceProposal{} ) func init() { govtypes.RegisterProposalType(ProposalTypeConsumerAddition) + govtypes.RegisterProposalType(ProposalTypeConsumerGovernance) } // NewConsumerAdditionProposal creates a new consumer addition proposal. @@ -120,3 +125,69 @@ func (sccp *ConsumerRemovalProposal) ValidateBasic() error { } return nil } + +// GetTitle returns the title of a consumer governance proposal. +func (cgp *ConsumerGovernanceProposal) GetTitle() string { + content := cgp.getInnerContent() + if content != nil { + return content.GetTitle() + } + + return "" +} + +// GetDescription returns the description of a consumer governance proposal. +func (cgp *ConsumerGovernanceProposal) GetDescription() string { + content := cgp.getInnerContent() + if content != nil { + return content.GetDescription() + } + + return "" +} + +// ProposalRoute returns the routing key of a consumer governance proposal. +func (cgp *ConsumerGovernanceProposal) ProposalRoute() string { return RouterKey } + +// ProposalType returns the type of a consumer governance proposal. +func (cgp *ConsumerGovernanceProposal) ProposalType() string { + return ProposalTypeConsumerGovernance +} + +// ValidateBasic runs basic stateless validity checks +func (cgp *ConsumerGovernanceProposal) ValidateBasic() error { + if err := govtypes.ValidateAbstract(cgp); err != nil { + return err + } + + if cgp.Content == nil || cgp.Content.GetCachedValue() == nil { + return sdkerrors.Wrap(ErrInvalidConsumerGovernanceProposal, "content must be set") + } + + if cgp.Content.GetCachedValue().(govtypes.Content) == nil { + return sdkerrors.Wrap(ErrInvalidConsumerGovernanceProposal, "content is not valid") + } + + if strings.TrimSpace(cgp.ConnectionId) == "" { + return sdkerrors.Wrap(ErrInvalidConsumerGovernanceProposal, "consumer connection id must not be blank") + } + + if !strings.HasPrefix(strings.TrimSpace(cgp.ConnectionId), "connection-") { + return sdkerrors.Wrap(ErrInvalidConsumerGovernanceProposal, "consumer connection id must start with 'connection-'") + } + + return nil +} + +func (cgp ConsumerGovernanceProposal) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + var content govtypes.Content + return unpacker.UnpackAny(cgp.Content, &content) +} + +func (cgp *ConsumerGovernanceProposal) getInnerContent() govtypes.Content { + cachedValue := cgp.Content.GetCachedValue() + if cachedValue == nil { + return nil + } + return cachedValue.(govtypes.Content) +} diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index 93464a51f1..d294ebb0f9 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -5,11 +5,13 @@ package types import ( fmt "fmt" + types2 "github.com/cosmos/cosmos-sdk/codec/types" types "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" types1 "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + _ "github.com/regen-network/cosmos-proto" _ "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" @@ -30,26 +32,31 @@ var _ = time.Kitchen // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// ConsumerAdditionProposal is a governance proposal on the provider chain to spawn a new consumer chain. -// If it passes, then all validators on the provider chain are expected to validate the consumer chain at spawn time -// or get slashed. It is recommended that spawn time occurs after the proposal end time. +// ConsumerAdditionProposal is a governance proposal on the provider chain to +// spawn a new consumer chain. If it passes, then all validators on the provider +// chain are expected to validate the consumer chain at spawn time or get +// slashed. It is recommended that spawn time occurs after the proposal end +// time. type ConsumerAdditionProposal struct { // the title of the proposal Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` // the description of the proposal Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // the proposed chain-id of the new consumer chain, must be different from all other consumer chain ids of the executing - // provider chain. + // the proposed chain-id of the new consumer chain, must be different from all + // other consumer chain ids of the executing provider chain. ChainId string `protobuf:"bytes,3,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` // the proposed initial height of new consumer chain. - // For a completely new chain, this will be {0,1}. However, it may be different if this is a chain that is converting to a consumer chain. + // For a completely new chain, this will be {0,1}. However, it may be + // different if this is a chain that is converting to a consumer chain. InitialHeight types.Height `protobuf:"bytes,4,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height"` // genesis hash with no staking information included. GenesisHash []byte `protobuf:"bytes,5,opt,name=genesis_hash,json=genesisHash,proto3" json:"genesis_hash,omitempty"` - // binary hash is the hash of the binary that should be used by validators on chain initialization. + // binary hash is the hash of the binary that should be used by validators on + // chain initialization. BinaryHash []byte `protobuf:"bytes,6,opt,name=binary_hash,json=binaryHash,proto3" json:"binary_hash,omitempty"` - // spawn time is the time on the provider chain at which the consumer chain genesis is finalized and all validators - // will be responsible for starting their consumer chain validator node. + // spawn time is the time on the provider chain at which the consumer chain + // genesis is finalized and all validators will be responsible for starting + // their consumer chain validator node. SpawnTime time.Time `protobuf:"bytes,7,opt,name=spawn_time,json=spawnTime,proto3,stdtime" json:"spawn_time"` // Indicates whether the outstanding unbonding operations should be released // in case of a channel time-outs. When set to true, a governance proposal @@ -89,9 +96,11 @@ func (m *ConsumerAdditionProposal) XXX_DiscardUnknown() { var xxx_messageInfo_ConsumerAdditionProposal proto.InternalMessageInfo -// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain. -// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding -// operation funds are released if the LockUnbondingOnTimeout parameter is set to false for the consumer chain ID. +// ConsumerRemovalProposal is a governance proposal on the provider chain to +// remove (and stop) a consumer chain. If it passes, all the consumer chain's +// state is removed from the provider chain. The outstanding unbonding operation +// funds are released if the LockUnbondingOnTimeout parameter is set to false +// for the consumer chain ID. type ConsumerRemovalProposal struct { // the title of the proposal Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` @@ -99,7 +108,8 @@ type ConsumerRemovalProposal struct { Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` // the chain-id of the consumer chain to be stopped ChainId string `protobuf:"bytes,3,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - // the time on the provider chain at which all validators are responsible to stop their consumer chain validator node + // the time on the provider chain at which all validators are responsible to + // stop their consumer chain validator node StopTime time.Time `protobuf:"bytes,4,opt,name=stop_time,json=stopTime,proto3,stdtime" json:"stop_time"` } @@ -169,7 +179,8 @@ type Params struct { TemplateClient *types1.ClientState `protobuf:"bytes,1,opt,name=template_client,json=templateClient,proto3" json:"template_client,omitempty"` // Sent IBC packets will timeout after this duration CcvTimeoutPeriod time.Duration `protobuf:"bytes,2,opt,name=ccv_timeout_period,json=ccvTimeoutPeriod,proto3,stdduration" json:"ccv_timeout_period"` - // TrustingPeriodFraction is used to compute the consumer and provider IBC client's TrustingPeriod + // TrustingPeriodFraction is used to compute the consumer and provider IBC + // client's TrustingPeriod TrustingPeriodFraction int64 `protobuf:"varint,3,opt,name=trusting_period_fraction,json=trustingPeriodFraction,proto3" json:"trusting_period_fraction,omitempty"` } @@ -325,12 +336,71 @@ func (m *SlashAcks) GetAddresses() []string { return nil } +// ConsumerGovernanceProposal contains a proposal that will be submitted to the +// consumer chain if voting pass successfully on the provider side. +type ConsumerGovernanceProposal struct { + // IBC connection identifier of the consumer chain for which the proposal is + // submitted + ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` + // An arbitrary proposal content which satisfies Content interface of the + // governance module + Content *types2.Any `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` +} + +func (m *ConsumerGovernanceProposal) Reset() { *m = ConsumerGovernanceProposal{} } +func (m *ConsumerGovernanceProposal) String() string { return proto.CompactTextString(m) } +func (*ConsumerGovernanceProposal) ProtoMessage() {} +func (*ConsumerGovernanceProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_f22ec409a72b7b72, []int{5} +} +func (m *ConsumerGovernanceProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConsumerGovernanceProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConsumerGovernanceProposal.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 *ConsumerGovernanceProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsumerGovernanceProposal.Merge(m, src) +} +func (m *ConsumerGovernanceProposal) XXX_Size() int { + return m.Size() +} +func (m *ConsumerGovernanceProposal) XXX_DiscardUnknown() { + xxx_messageInfo_ConsumerGovernanceProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_ConsumerGovernanceProposal proto.InternalMessageInfo + +func (m *ConsumerGovernanceProposal) GetConnectionId() string { + if m != nil { + return m.ConnectionId + } + return "" +} + +func (m *ConsumerGovernanceProposal) GetContent() *types2.Any { + if m != nil { + return m.Content + } + return nil +} + func init() { proto.RegisterType((*ConsumerAdditionProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerAdditionProposal") proto.RegisterType((*ConsumerRemovalProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerRemovalProposal") proto.RegisterType((*Params)(nil), "interchain_security.ccv.provider.v1.Params") proto.RegisterType((*HandshakeMetadata)(nil), "interchain_security.ccv.provider.v1.HandshakeMetadata") proto.RegisterType((*SlashAcks)(nil), "interchain_security.ccv.provider.v1.SlashAcks") + proto.RegisterType((*ConsumerGovernanceProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerGovernanceProposal") } func init() { @@ -338,52 +408,57 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 712 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xbf, 0x73, 0xd3, 0x30, - 0x14, 0x8e, 0x49, 0x7f, 0x24, 0x4a, 0x29, 0x60, 0x7a, 0xc5, 0xed, 0x71, 0x49, 0x08, 0x4b, 0x38, - 0x0e, 0xfb, 0x92, 0x2e, 0xd0, 0x2d, 0x2d, 0x57, 0xca, 0xc0, 0x11, 0xdc, 0xb2, 0xb0, 0xf8, 0x64, - 0x49, 0xb5, 0x75, 0xb5, 0x2d, 0x9f, 0x24, 0x1b, 0xba, 0x33, 0x30, 0x76, 0xec, 0xd8, 0xff, 0x80, - 0x7f, 0xa3, 0x63, 0x47, 0x26, 0xe0, 0xda, 0x91, 0x7f, 0x82, 0x93, 0x64, 0x37, 0xe5, 0xc7, 0xc2, - 0xc0, 0xa6, 0xf7, 0xde, 0xf7, 0x3d, 0x7f, 0xef, 0x7d, 0x96, 0xc0, 0x98, 0x66, 0x92, 0x70, 0x14, - 0x43, 0x9a, 0x05, 0x82, 0xa0, 0x82, 0x53, 0x79, 0xe4, 0x21, 0x54, 0x7a, 0x39, 0x67, 0x25, 0xc5, - 0x84, 0x7b, 0xe5, 0xe8, 0xea, 0xec, 0xe6, 0x9c, 0x49, 0x66, 0x3f, 0xfc, 0x0b, 0xc7, 0x45, 0xa8, - 0x74, 0xaf, 0x70, 0xe5, 0x68, 0x7d, 0x25, 0x62, 0x11, 0xd3, 0x78, 0x4f, 0x9d, 0x0c, 0x75, 0xbd, - 0x17, 0x31, 0x16, 0x25, 0xc4, 0xd3, 0x51, 0x58, 0x1c, 0x78, 0x92, 0xa6, 0x44, 0x48, 0x98, 0xe6, - 0x15, 0xa0, 0xfb, 0x3b, 0x00, 0x17, 0x1c, 0x4a, 0xca, 0xb2, 0xba, 0x01, 0x0d, 0x91, 0x87, 0x18, - 0x27, 0x1e, 0x4a, 0x28, 0xc9, 0xa4, 0x92, 0x67, 0x4e, 0x15, 0xc0, 0x53, 0x80, 0x84, 0x46, 0xb1, - 0x34, 0x69, 0xe1, 0x49, 0x92, 0x61, 0xc2, 0x53, 0x6a, 0xc0, 0xb3, 0xc8, 0x10, 0x06, 0x1f, 0x9b, - 0xc0, 0xd9, 0x66, 0x99, 0x28, 0x52, 0xc2, 0x27, 0x18, 0x53, 0xf5, 0xb1, 0x29, 0x67, 0x39, 0x13, - 0x30, 0xb1, 0x57, 0xc0, 0xbc, 0xa4, 0x32, 0x21, 0x8e, 0xd5, 0xb7, 0x86, 0x6d, 0xdf, 0x04, 0x76, - 0x1f, 0x74, 0x30, 0x11, 0x88, 0xd3, 0x5c, 0x81, 0x9d, 0x1b, 0xba, 0x76, 0x3d, 0x65, 0xaf, 0x81, - 0x96, 0xd9, 0x0f, 0xc5, 0x4e, 0x53, 0x97, 0x17, 0x75, 0xfc, 0x12, 0xdb, 0x2f, 0xc0, 0x32, 0xcd, - 0xa8, 0xa4, 0x30, 0x09, 0x62, 0xa2, 0x74, 0x3a, 0x73, 0x7d, 0x6b, 0xd8, 0x19, 0xaf, 0xbb, 0x34, - 0x44, 0xae, 0x1a, 0xcd, 0xad, 0x06, 0x2a, 0x47, 0xee, 0xae, 0x46, 0x6c, 0xcd, 0x9d, 0x7d, 0xed, - 0x35, 0xfc, 0x9b, 0x15, 0xcf, 0x24, 0xed, 0x07, 0x60, 0x29, 0x22, 0x19, 0x11, 0x54, 0x04, 0x31, - 0x14, 0xb1, 0x33, 0xdf, 0xb7, 0x86, 0x4b, 0x7e, 0xa7, 0xca, 0xed, 0x42, 0x11, 0xdb, 0x3d, 0xd0, - 0x09, 0x69, 0x06, 0xf9, 0x91, 0x41, 0x2c, 0x68, 0x04, 0x30, 0x29, 0x0d, 0xd8, 0x06, 0x40, 0xe4, - 0xf0, 0x7d, 0x16, 0x28, 0x1f, 0x9c, 0xc5, 0x4a, 0x88, 0xf1, 0xc0, 0xad, 0x3d, 0x70, 0xf7, 0x6b, - 0x93, 0xb6, 0x5a, 0x4a, 0xc8, 0xf1, 0xb7, 0x9e, 0xe5, 0xb7, 0x35, 0x4f, 0x55, 0xec, 0x67, 0x60, - 0x2d, 0x61, 0xe8, 0x30, 0x28, 0xb2, 0x90, 0x65, 0x98, 0x66, 0x51, 0xc0, 0x4c, 0x43, 0x56, 0x48, - 0xa7, 0xd5, 0xb7, 0x86, 0x2d, 0x7f, 0x55, 0x01, 0xde, 0xd6, 0xf5, 0xd7, 0x9a, 0xc7, 0x0a, 0xb9, - 0xd9, 0xfa, 0x74, 0xda, 0x6b, 0x9c, 0x9c, 0xf6, 0x1a, 0x83, 0xcf, 0x16, 0xb8, 0x57, 0xdb, 0xe0, - 0x93, 0x94, 0x95, 0x30, 0xf9, 0x9f, 0x2e, 0x4c, 0x40, 0x5b, 0x48, 0x96, 0x9b, 0xb9, 0xe7, 0xfe, - 0x61, 0xee, 0x96, 0xa2, 0xa9, 0xc2, 0xe0, 0x87, 0x05, 0x16, 0xa6, 0x90, 0xc3, 0x54, 0xd8, 0xfb, - 0xe0, 0x96, 0x24, 0x69, 0x9e, 0x40, 0x49, 0x02, 0x63, 0x9e, 0x96, 0xda, 0x19, 0x3f, 0xd6, 0xa6, - 0x5e, 0xff, 0x1d, 0xdd, 0x6b, 0x3f, 0x60, 0x39, 0x72, 0xb7, 0x75, 0x76, 0x4f, 0x42, 0x49, 0xfc, - 0xe5, 0xba, 0x87, 0x49, 0xda, 0x6f, 0x80, 0x8d, 0x50, 0x59, 0x6f, 0x32, 0xc8, 0x09, 0xa7, 0x0c, - 0xeb, 0x39, 0x3b, 0xe3, 0xb5, 0x3f, 0xc4, 0x3e, 0xaf, 0x2e, 0x8a, 0xd1, 0x7a, 0xa2, 0xb4, 0xde, - 0x46, 0xa8, 0xac, 0x36, 0x3d, 0xd5, 0x64, 0xfb, 0x29, 0x70, 0x24, 0x2f, 0x84, 0x54, 0x26, 0x99, - 0x7e, 0xc1, 0x01, 0x87, 0x48, 0x2f, 0x50, 0x6d, 0xa8, 0xe9, 0xaf, 0xd6, 0x75, 0xc3, 0xd8, 0xa9, - 0xaa, 0x83, 0x10, 0xdc, 0xd9, 0x85, 0x19, 0x16, 0x31, 0x3c, 0x24, 0xaf, 0x88, 0x84, 0x18, 0x4a, - 0x68, 0x6f, 0x80, 0xd5, 0xfa, 0xce, 0x07, 0x07, 0x84, 0x04, 0x39, 0x63, 0x49, 0x00, 0x31, 0xe6, - 0x95, 0x53, 0x77, 0xeb, 0xea, 0x0e, 0x21, 0x53, 0xc6, 0x92, 0x09, 0xc6, 0xdc, 0x76, 0xc0, 0x62, - 0x49, 0xb8, 0x98, 0x79, 0x56, 0x87, 0x83, 0x47, 0xa0, 0xbd, 0x97, 0x40, 0x11, 0x4f, 0xd0, 0xa1, - 0xb0, 0xef, 0x83, 0xb6, 0xea, 0x44, 0x84, 0x20, 0xc2, 0xb1, 0xfa, 0xcd, 0x61, 0xdb, 0x9f, 0x25, - 0xb6, 0xf6, 0xcf, 0x2e, 0xba, 0xd6, 0xf9, 0x45, 0xd7, 0xfa, 0x7e, 0xd1, 0xb5, 0x8e, 0x2f, 0xbb, - 0x8d, 0xf3, 0xcb, 0x6e, 0xe3, 0xcb, 0x65, 0xb7, 0xf1, 0x6e, 0x33, 0xa2, 0x32, 0x2e, 0x42, 0x17, - 0xb1, 0xd4, 0x43, 0x4c, 0xa4, 0x4c, 0x78, 0xb3, 0xf7, 0xea, 0xc9, 0xd5, 0x1b, 0xf7, 0xe1, 0xd7, - 0x57, 0x4e, 0x1e, 0xe5, 0x44, 0x84, 0x0b, 0x7a, 0x9b, 0x1b, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, - 0xb7, 0x64, 0x3e, 0xb7, 0x16, 0x05, 0x00, 0x00, + // 793 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0x31, 0x73, 0x1b, 0x45, + 0x14, 0xd6, 0x61, 0xc7, 0x92, 0x56, 0x4e, 0x80, 0xc5, 0x63, 0xce, 0x1e, 0x46, 0x12, 0x4a, 0x23, + 0x86, 0xc9, 0xdd, 0xd8, 0x69, 0x20, 0x54, 0xb2, 0x99, 0xc4, 0x29, 0x18, 0xcc, 0xc5, 0x34, 0x34, + 0x37, 0xab, 0xdd, 0xe7, 0xbb, 0x1d, 0xdf, 0xed, 0xde, 0xec, 0xee, 0x1d, 0xa8, 0xa1, 0xa2, 0xa0, + 0x4c, 0x99, 0x32, 0xff, 0x80, 0x86, 0x1f, 0x91, 0xa1, 0x4a, 0x49, 0x05, 0x8c, 0x5d, 0xf2, 0x27, + 0x98, 0xdd, 0xbd, 0xb3, 0x4c, 0x4c, 0x43, 0x91, 0xee, 0xde, 0xfb, 0xbe, 0xf7, 0xf4, 0xbd, 0xf7, + 0xad, 0x1e, 0x3a, 0xe4, 0xc2, 0x80, 0xa2, 0x39, 0xe1, 0x22, 0xd5, 0x40, 0x6b, 0xc5, 0xcd, 0x2a, + 0xa6, 0xb4, 0x89, 0x2b, 0x25, 0x1b, 0xce, 0x40, 0xc5, 0xcd, 0xc1, 0xf5, 0x77, 0x54, 0x29, 0x69, + 0x24, 0xbe, 0xff, 0x1f, 0x35, 0x11, 0xa5, 0x4d, 0x74, 0xcd, 0x6b, 0x0e, 0xf6, 0x77, 0x32, 0x99, + 0x49, 0xc7, 0x8f, 0xed, 0x97, 0x2f, 0xdd, 0xdf, 0xcb, 0xa4, 0xcc, 0x0a, 0x88, 0x5d, 0xb4, 0xac, + 0xcf, 0x63, 0x22, 0x56, 0x2d, 0x34, 0x79, 0x13, 0x32, 0xbc, 0x04, 0x6d, 0x48, 0x59, 0xb5, 0x84, + 0xf1, 0x9b, 0x04, 0x56, 0x2b, 0x62, 0xb8, 0x14, 0x5d, 0x03, 0xbe, 0xa4, 0x31, 0x95, 0x0a, 0x62, + 0x5a, 0x70, 0x10, 0xc6, 0x2a, 0xf7, 0x5f, 0x2d, 0x21, 0xb6, 0x84, 0x82, 0x67, 0xb9, 0xf1, 0x69, + 0x1d, 0x1b, 0x10, 0x0c, 0x54, 0xc9, 0x3d, 0x79, 0x1d, 0x75, 0x6a, 0xa9, 0xd4, 0xa5, 0xd4, 0xa9, + 0x1f, 0xc3, 0x07, 0x1e, 0x9a, 0xfd, 0xb4, 0x81, 0xc2, 0x63, 0x29, 0x74, 0x5d, 0x82, 0x5a, 0x30, + 0xc6, 0xad, 0x8e, 0x53, 0x25, 0x2b, 0xa9, 0x49, 0x81, 0x77, 0xd0, 0x1d, 0xc3, 0x4d, 0x01, 0x61, + 0x30, 0x0d, 0xe6, 0xc3, 0xc4, 0x07, 0x78, 0x8a, 0x46, 0x0c, 0x34, 0x55, 0xbc, 0xb2, 0xe4, 0xf0, + 0x1d, 0x87, 0xdd, 0x4c, 0xe1, 0x3d, 0x34, 0xf0, 0x5b, 0xe5, 0x2c, 0xdc, 0x70, 0x70, 0xdf, 0xc5, + 0x4f, 0x19, 0x7e, 0x82, 0xee, 0x71, 0xc1, 0x0d, 0x27, 0x45, 0x9a, 0x83, 0x1d, 0x21, 0xdc, 0x9c, + 0x06, 0xf3, 0xd1, 0xe1, 0x7e, 0xc4, 0x97, 0x34, 0xb2, 0x53, 0x47, 0xed, 0xac, 0xcd, 0x41, 0x74, + 0xe2, 0x18, 0x47, 0x9b, 0xaf, 0xfe, 0x98, 0xf4, 0x92, 0xbb, 0x6d, 0x9d, 0x4f, 0xe2, 0x8f, 0xd1, + 0x76, 0x06, 0x02, 0x34, 0xd7, 0x69, 0x4e, 0x74, 0x1e, 0xde, 0x99, 0x06, 0xf3, 0xed, 0x64, 0xd4, + 0xe6, 0x4e, 0x88, 0xce, 0xf1, 0x04, 0x8d, 0x96, 0x5c, 0x10, 0xb5, 0xf2, 0x8c, 0x2d, 0xc7, 0x40, + 0x3e, 0xe5, 0x08, 0xc7, 0x08, 0xe9, 0x8a, 0x7c, 0x2f, 0x52, 0x6b, 0x51, 0xd8, 0x6f, 0x85, 0x78, + 0x7b, 0xa2, 0xce, 0x9e, 0xe8, 0xac, 0xf3, 0xef, 0x68, 0x60, 0x85, 0x3c, 0xff, 0x73, 0x12, 0x24, + 0x43, 0x57, 0x67, 0x11, 0xfc, 0x39, 0xda, 0x2b, 0x24, 0xbd, 0x48, 0x6b, 0xb1, 0x94, 0x82, 0x71, + 0x91, 0xa5, 0xd2, 0x37, 0x94, 0xb5, 0x09, 0x07, 0xd3, 0x60, 0x3e, 0x48, 0x76, 0x2d, 0xe1, 0xdb, + 0x0e, 0xff, 0xda, 0xd5, 0xc9, 0xda, 0x3c, 0x1a, 0xfc, 0xfc, 0x72, 0xd2, 0x7b, 0xf1, 0x72, 0xd2, + 0x9b, 0xfd, 0x12, 0xa0, 0x0f, 0x3b, 0x1b, 0x12, 0x28, 0x65, 0x43, 0x8a, 0xb7, 0xe9, 0xc2, 0x02, + 0x0d, 0xb5, 0x91, 0x95, 0x9f, 0x7b, 0xf3, 0x7f, 0xcc, 0x3d, 0xb0, 0x65, 0x16, 0x98, 0xfd, 0x1d, + 0xa0, 0xad, 0x53, 0xa2, 0x48, 0xa9, 0xf1, 0x19, 0x7a, 0xd7, 0x40, 0x59, 0x15, 0xc4, 0x40, 0xea, + 0xcd, 0x73, 0x52, 0x47, 0x87, 0x9f, 0x3a, 0x53, 0x6f, 0xbe, 0xd4, 0xe8, 0xc6, 0xdb, 0x6c, 0x0e, + 0xa2, 0x63, 0x97, 0x7d, 0x66, 0x88, 0x81, 0xe4, 0x5e, 0xd7, 0xc3, 0x27, 0xf1, 0x37, 0x08, 0x53, + 0xda, 0x74, 0x9b, 0x4c, 0x2b, 0x50, 0x5c, 0x32, 0x37, 0xe7, 0xe8, 0x70, 0xef, 0x96, 0xd8, 0x2f, + 0xdb, 0xff, 0x90, 0xd7, 0xfa, 0xc2, 0x6a, 0x7d, 0x8f, 0xd2, 0xa6, 0xdd, 0xf4, 0xa9, 0x2b, 0xc6, + 0x9f, 0xa1, 0xd0, 0xa8, 0x5a, 0x1b, 0x6b, 0x92, 0xef, 0x97, 0x9e, 0x2b, 0x42, 0xdd, 0x02, 0xed, + 0x86, 0x36, 0x92, 0xdd, 0x0e, 0xf7, 0x15, 0x8f, 0x5b, 0x74, 0xb6, 0x44, 0xef, 0x9f, 0x10, 0xc1, + 0x74, 0x4e, 0x2e, 0xe0, 0x2b, 0x30, 0x84, 0x11, 0x43, 0xf0, 0x43, 0xb4, 0xdb, 0x5d, 0x8a, 0xf4, + 0x1c, 0x20, 0xad, 0xa4, 0x2c, 0x52, 0xc2, 0x98, 0x6a, 0x9d, 0xfa, 0xa0, 0x43, 0x1f, 0x03, 0x9c, + 0x4a, 0x59, 0x2c, 0x18, 0x53, 0x38, 0x44, 0xfd, 0x06, 0x94, 0x5e, 0x7b, 0xd6, 0x85, 0xb3, 0x4f, + 0xd0, 0xf0, 0x59, 0x41, 0x74, 0xbe, 0xa0, 0x17, 0x1a, 0x7f, 0x84, 0x86, 0xb6, 0x13, 0x68, 0x0d, + 0x3a, 0x0c, 0xa6, 0x1b, 0xf3, 0x61, 0xb2, 0x4e, 0xcc, 0x7e, 0x44, 0xfb, 0xdd, 0x6b, 0x79, 0x22, + 0x1b, 0x50, 0x82, 0x08, 0x0a, 0xd7, 0x0f, 0xe6, 0x3e, 0xba, 0x4b, 0xa5, 0x10, 0xe0, 0xa4, 0x5b, + 0xf7, 0xbd, 0x9c, 0xed, 0x75, 0xf2, 0x29, 0xc3, 0x5f, 0xa0, 0x3e, 0x95, 0xc2, 0x58, 0xb3, 0xfc, + 0x4e, 0x77, 0x6e, 0xed, 0x74, 0x21, 0x56, 0x47, 0xa3, 0xdf, 0x7e, 0x7d, 0xd0, 0x3f, 0xf6, 0xc4, + 0xa4, 0xab, 0x38, 0x3a, 0x7b, 0x75, 0x39, 0x0e, 0x5e, 0x5f, 0x8e, 0x83, 0xbf, 0x2e, 0xc7, 0xc1, + 0xf3, 0xab, 0x71, 0xef, 0xf5, 0xd5, 0xb8, 0xf7, 0xfb, 0xd5, 0xb8, 0xf7, 0xdd, 0xa3, 0x8c, 0x9b, + 0xbc, 0x5e, 0x46, 0x54, 0x96, 0xed, 0xa1, 0x89, 0xd7, 0x57, 0xf6, 0xc1, 0xf5, 0x65, 0xfe, 0xe1, + 0xdf, 0xb7, 0xd9, 0xac, 0x2a, 0xd0, 0xcb, 0x2d, 0xf7, 0xcb, 0x0f, 0xff, 0x09, 0x00, 0x00, 0xff, + 0xff, 0xd8, 0x78, 0xc9, 0xae, 0xcc, 0x05, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -641,6 +716,48 @@ func (m *SlashAcks) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ConsumerGovernanceProposal) 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 *ConsumerGovernanceProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsumerGovernanceProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Content != nil { + { + size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProvider(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.ConnectionId) > 0 { + i -= len(m.ConnectionId) + copy(dAtA[i:], m.ConnectionId) + i = encodeVarintProvider(dAtA, i, uint64(len(m.ConnectionId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintProvider(dAtA []byte, offset int, v uint64) int { offset -= sovProvider(v) base := offset @@ -761,6 +878,23 @@ func (m *SlashAcks) Size() (n int) { return n } +func (m *ConsumerGovernanceProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ConnectionId) + if l > 0 { + n += 1 + l + sovProvider(uint64(l)) + } + if m.Content != nil { + l = m.Content.Size() + n += 1 + l + sovProvider(uint64(l)) + } + return n +} + func sovProvider(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1580,6 +1714,124 @@ func (m *SlashAcks) Unmarshal(dAtA []byte) error { } return nil } +func (m *ConsumerGovernanceProposal) 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 ErrIntOverflowProvider + } + 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: ConsumerGovernanceProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsumerGovernanceProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProvider + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnectionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProvider + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Content == nil { + m.Content = &types2.Any{} + } + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProvider(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProvider + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipProvider(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/types/ccv.pb.go b/x/ccv/types/ccv.pb.go index f5ae919aa0..9f6c17e553 100644 --- a/x/ccv/types/ccv.pb.go +++ b/x/ccv/types/ccv.pb.go @@ -302,7 +302,8 @@ func (m *UnbondingOpsIndex) GetIds() []uint64 { return nil } -// MaturedUnbondingOps defines a list of ids corresponding to ids of matured unbonding operations. +// MaturedUnbondingOps defines a list of ids corresponding to ids of matured +// unbonding operations. type MaturedUnbondingOps struct { Ids []uint64 `protobuf:"varint,1,rep,packed,name=ids,proto3" json:"ids,omitempty"` } diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index e792fd2c7d..ae9a2481cd 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -9,6 +9,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" conntypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -89,6 +90,7 @@ type BankKeeper interface { // AccountKeeper defines the expected account keeper used for simulations type AccountKeeper interface { GetModuleAccount(ctx sdk.Context, name string) auth.ModuleAccountI + GetModuleAddress(moduleName string) sdk.AccAddress } // IBCTransferKeeper defines the expected interface needed for distribution transfer @@ -120,3 +122,10 @@ type ScopedKeeper interface { AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error } + +type ICAControllerKeeper interface { + GetInterchainAccountAddress(ctx sdk.Context, connectionID, portID string) (string, bool) + GetActiveChannelID(ctx sdk.Context, connectionID, portID string) (string, bool) + RegisterInterchainAccount(ctx sdk.Context, connectionID, owner string) error + SendTx(ctx sdk.Context, chanCap *capabilitytypes.Capability, connectionID, portID string, icaPacketData icatypes.InterchainAccountPacketData, timeoutTimestamp uint64) (uint64, error) +}