feat: decouple `x/capability` from simapp (#12256)

This commit is contained in:
Julien Robert 2022-06-17 00:47:38 +02:00 committed by GitHub
parent 8fa2faba47
commit aba9bdc24c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 202 additions and 103 deletions

View File

@ -157,7 +157,7 @@ func (a *App) Configurator() module.Configurator {
return a.configurator
}
// UnsafeFindStoreKey FindStoreKey fetches a registered StoreKey from the App in linear time.
// UnsafeFindStoreKey fetches a registered StoreKey from the App in linear time.
//
// NOTE: This should only be used in testing.
func (a *App) UnsafeFindStoreKey(storeKey string) storetypes.StoreKey {

View File

@ -159,9 +159,7 @@ type SimApp struct {
invCheckPeriod uint
// keys to access the substores
keys map[string]*storetypes.KVStoreKey
tkeys map[string]*storetypes.TransientStoreKey
memKeys map[string]*storetypes.MemoryStoreKey
keys map[string]*storetypes.KVStoreKey
// keepers
AccountKeeper authkeeper.AccountKeeper
@ -239,9 +237,6 @@ func NewSimApp(
govtypes.StoreKey,
upgradetypes.StoreKey,
)
// NOTE: The testingkey is just mounted for testing purposes. Actual applications should
// not include this key.
app.memKeys = sdk.NewMemoryStoreKeys("testingkey")
// configure state listening capabilities using AppOptions
// we are doing nothing with the returned streamingServices and waitGroup in this case
@ -322,13 +317,13 @@ func NewSimApp(
app.ModuleManager.SetOrderExportGenesis(genesisModuleOrder...)
// Uncomment if you want to set a custom migration order here.
// app.mm.SetOrderMigrations(custom order)
// app.ModuleManager.SetOrderMigrations(custom order)
app.ModuleManager.RegisterInvariants(&app.CrisisKeeper)
app.ModuleManager.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino)
// RegisterUpgradeHandlers is used for registering any on-chain upgrades.
// Make sure it's called after `app.mm` and `app.configurator` are set.
// Make sure it's called after `app.ModuleManager` and `app.configurator` are set.
app.RegisterUpgradeHandlers()
// add test gRPC service for testing gRPC queries in isolation
@ -347,7 +342,6 @@ func NewSimApp(
// initialize stores
app.MountKVStores(app.keys)
app.MountMemoryStores(app.memKeys)
// initialize BaseApp
app.SetInitChainer(app.InitChainer)
@ -411,31 +405,6 @@ func (app *SimApp) GetKey(storeKey string) *storetypes.KVStoreKey {
return kvStoreKey
}
// GetTKey returns the TransientStoreKey for the provided store key.
//
// NOTE: This is solely to be used for testing purposes.
func (app *SimApp) GetTKey(storeKey string) *storetypes.TransientStoreKey {
return app.tkeys[storeKey]
}
// GetMemKey returns the MemStoreKey for the provided mem key.
//
// NOTE: This is solely used for testing purposes.
func (app *SimApp) GetMemKey(storeKey string) *storetypes.MemoryStoreKey {
msk := app.memKeys[storeKey]
if msk != nil {
return msk
}
sk := app.UnsafeFindStoreKey(storeKey)
memStoreKey, ok := sk.(*storetypes.MemoryStoreKey)
if !ok {
return nil
}
return memStoreKey
}
// GetSubspace returns a param subspace for a given module name.
//
// NOTE: This is solely to be used for testing purposes.

View File

@ -55,11 +55,30 @@ var DefaultConsensusParams = &tmproto.ConsensusParams{
// appConfig usually load from a `app.yaml` with `appconfig.LoadYAML`, defines the application configuration.
// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject).
func Setup(appConfig depinject.Config, extraOutputs ...interface{}) (*runtime.App, error) {
return SetupWithBaseAppOption(appConfig, nil, false, extraOutputs...)
}
// SetupAtGenesis initializes a new runtime.App at genesis. A Nop logger is set in runtime.App.
// appConfig usually load from a `app.yaml` with `appconfig.LoadYAML`, defines the application configuration.
// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject).
func SetupAtGenesis(appConfig depinject.Config, extraOutputs ...interface{}) (*runtime.App, error) {
return SetupWithBaseAppOption(appConfig, nil, true, extraOutputs...)
}
// SetupWithBaseAppOption initializes a new runtime.App. A Nop logger is set in runtime.App.
// appConfig usually load from a `app.yaml` with `appconfig.LoadYAML`, defines the application configuration.
// baseAppOption defines the additional operations that must be run on baseapp before app start.
// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject).
// genesis defines if the app started should already have produced block or not.
func SetupWithBaseAppOption(appConfig depinject.Config, baseAppOption runtime.BaseAppOption, genesis bool, extraOutputs ...interface{}) (*runtime.App, error) {
//
// create app
//
var appBuilder *runtime.AppBuilder
var codec codec.Codec
var (
app *runtime.App
appBuilder *runtime.AppBuilder
codec codec.Codec
)
if err := depinject.Inject(
appConfig,
@ -68,7 +87,11 @@ func Setup(appConfig depinject.Config, extraOutputs ...interface{}) (*runtime.Ap
return nil, fmt.Errorf("failed to inject dependencies: %w", err)
}
app := appBuilder.Build(log.NewNopLogger(), dbm.NewMemDB(), nil)
if baseAppOption != nil {
app = appBuilder.Build(log.NewNopLogger(), dbm.NewMemDB(), nil, baseAppOption)
} else {
app = appBuilder.Build(log.NewNopLogger(), dbm.NewMemDB(), nil)
}
if err := app.Load(true); err != nil {
return nil, fmt.Errorf("failed to load app: %w", err)
}
@ -114,6 +137,17 @@ func Setup(appConfig depinject.Config, extraOutputs ...interface{}) (*runtime.Ap
},
)
// commit genesis changes
if !genesis {
app.Commit()
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{
Height: app.LastBlockHeight() + 1,
AppHash: app.LastCommitID().Hash,
ValidatorsHash: valSet.Hash(),
NextValidatorsHash: valSet.Hash(),
}})
}
return app, nil
}

View File

@ -7,39 +7,44 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/runtime"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/capability"
"github.com/cosmos/cosmos-sdk/x/capability/keeper"
"github.com/cosmos/cosmos-sdk/x/capability/testutil"
"github.com/cosmos/cosmos-sdk/x/capability/types"
)
type CapabilityTestSuite struct {
suite.Suite
app *runtime.App
cdc codec.Codec
ctx sdk.Context
app *simapp.SimApp
keeper *keeper.Keeper
module module.AppModule
memKey *storetypes.MemoryStoreKey
}
func (suite *CapabilityTestSuite) SetupTest() {
checkTx := false
app := simapp.Setup(suite.T(), checkTx)
cdc := app.AppCodec()
suite.memKey = storetypes.NewMemoryStoreKey("testingkey")
// create new keeper so we can define custom scoping before init and seal
keeper := keeper.NewKeeper(cdc, app.GetKey(types.StoreKey), app.GetMemKey(types.MemStoreKey))
app, err := simtestutil.SetupWithBaseAppOption(testutil.AppConfig,
func(ba *baseapp.BaseApp) {
ba.MountStores(suite.memKey)
},
false,
&suite.cdc,
&suite.keeper,
)
suite.Require().NoError(err)
suite.app = app
suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1})
suite.keeper = keeper
suite.cdc = cdc
suite.module = capability.NewAppModule(cdc, *keeper, true)
suite.ctx = app.BaseApp.NewContext(false, tmproto.Header{Height: 1})
}
// The following test case mocks a specific bug discovered in https://github.com/cosmos/cosmos-sdk/issues/9800
@ -52,7 +57,7 @@ func (suite *CapabilityTestSuite) TestInitializeMemStore() {
suite.Require().NotNil(cap1)
// mock statesync by creating new keeper that shares persistent state but loses in-memory map
newKeeper := keeper.NewKeeper(suite.cdc, suite.app.GetKey(types.StoreKey), suite.app.GetMemKey("testingkey"))
newKeeper := keeper.NewKeeper(suite.cdc, suite.app.UnsafeFindStoreKey(types.StoreKey).(*storetypes.KVStoreKey), suite.memKey)
newSk1 := newKeeper.ScopeToModule(banktypes.ModuleName)
// Mock App startup

View File

@ -1,16 +1,14 @@
package capability_test
import (
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/simapp"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/capability"
"github.com/cosmos/cosmos-sdk/x/capability/keeper"
"github.com/cosmos/cosmos-sdk/x/capability/types"
"github.com/cosmos/cosmos-sdk/x/capability/testutil"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
@ -33,11 +31,10 @@ func (suite *CapabilityTestSuite) TestGenesis() {
// create new app that does not share persistent or in-memory state
// and initialize app from exported genesis state above.
db := dbm.NewMemDB()
encCdc := simapp.MakeTestEncodingConfig()
newApp := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encCdc, simapp.EmptyAppOptions{})
var newKeeper *keeper.Keeper
newApp, err := simtestutil.SetupAtGenesis(testutil.AppConfig, &newKeeper)
suite.Require().NoError(err)
newKeeper := keeper.NewKeeper(suite.cdc, newApp.GetKey(types.StoreKey), newApp.GetMemKey(types.MemStoreKey))
newSk1 := newKeeper.ScopeToModule(banktypes.ModuleName)
newSk2 := newKeeper.ScopeToModule(stakingtypes.ModuleName)
deliverCtx, _ := newApp.BaseApp.NewUncachedContext(false, tmproto.Header{}).WithBlockGasMeter(sdk.NewInfiniteGasMeter()).CacheContext()

View File

@ -7,10 +7,11 @@ import (
"github.com/stretchr/testify/suite"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/simapp"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/capability/keeper"
"github.com/cosmos/cosmos-sdk/x/capability/testutil"
"github.com/cosmos/cosmos-sdk/x/capability/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
@ -19,21 +20,16 @@ type KeeperTestSuite struct {
suite.Suite
ctx sdk.Context
app *simapp.SimApp
keeper *keeper.Keeper
}
func (suite *KeeperTestSuite) SetupTest() {
checkTx := false
app := simapp.Setup(suite.T(), checkTx)
cdc := app.AppCodec()
app, err := simtestutil.Setup(testutil.AppConfig,
&suite.keeper,
)
suite.Require().NoError(err)
// create new keeper so we can define custom scoping before init and seal
keeper := keeper.NewKeeper(cdc, app.GetKey(types.StoreKey), app.GetMemKey(types.MemStoreKey))
suite.app = app
suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1})
suite.keeper = keeper
suite.ctx = app.BaseApp.NewContext(false, tmproto.Header{Height: 1})
}
func (suite *KeeperTestSuite) TestSeal() {

View File

@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/depinject"
"github.com/cosmos/cosmos-sdk/runtime"
store "github.com/cosmos/cosmos-sdk/store/types"
"github.com/cosmos/cosmos-sdk/telemetry"
@ -165,29 +166,6 @@ func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.Valid
return []abci.ValidatorUpdate{}
}
func init() {
appmodule.Register(&modulev1.Module{},
appmodule.Provide(
provideModuleBasic,
provideModule,
))
}
func provideModuleBasic() runtime.AppModuleBasicWrapper {
return runtime.WrapAppModuleBasic(AppModuleBasic{})
}
func provideModule(
kvStoreKey *store.KVStoreKey,
memStoreKey *store.MemoryStoreKey,
cdc codec.Codec,
config *modulev1.Module,
) (*keeper.Keeper, runtime.AppModuleWrapper) {
k := keeper.NewKeeper(cdc, kvStoreKey, memStoreKey)
m := NewAppModule(cdc, *k, config.SealKeeper)
return k, runtime.WrapAppModule(m)
}
// GenerateGenesisState creates a randomized GenState of the capability module.
func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
@ -212,3 +190,46 @@ func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
return nil
}
//
// New App Wiring Setup
//
func init() {
appmodule.Register(&modulev1.Module{},
appmodule.Provide(
provideModuleBasic,
provideModule,
))
}
func provideModuleBasic() runtime.AppModuleBasicWrapper {
return runtime.WrapAppModuleBasic(AppModuleBasic{})
}
type capabilityInputs struct {
depinject.In
Config *modulev1.Module
KvStoreKey *store.KVStoreKey
MemStoreKey *store.MemoryStoreKey
Cdc codec.Codec
}
type capabilityOutputs struct {
depinject.Out
CapabilityKeeper *keeper.Keeper
Module runtime.AppModuleWrapper
}
func provideModule(in capabilityInputs) capabilityOutputs {
k := keeper.NewKeeper(in.Cdc, in.KvStoreKey, in.MemStoreKey)
m := NewAppModule(in.Cdc, *k, in.Config.SealKeeper)
return capabilityOutputs{
CapabilityKeeper: k,
Module: runtime.WrapAppModule(m),
}
}

View File

@ -6,15 +6,20 @@ import (
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/depinject"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/cosmos/cosmos-sdk/x/capability/simulation"
"github.com/cosmos/cosmos-sdk/x/capability/testutil"
"github.com/cosmos/cosmos-sdk/x/capability/types"
)
func TestDecodeStore(t *testing.T) {
cdc := simapp.MakeTestEncodingConfig().Codec
var cdc codec.Codec
err := depinject.Inject(testutil.AppConfig, &cdc)
require.NoError(t, err)
dec := simulation.NewDecodeStore(cdc)
capOwners := types.CapabilityOwners{

View File

@ -0,0 +1,5 @@
# App Wiring
The minimal app-wiring configuration for `x/capability` is as follows:
+++ https://github.com/cosmos/cosmos-sdk/blob/main/x/capability/testutil/app.yaml

View File

@ -75,3 +75,4 @@ func NewApp(...) *App {
1. **[Concepts](01_concepts.md)**
1. **[State](02_state.md)**
1. **[App Wiring](03_app_wiring.md)**

View File

@ -0,0 +1,46 @@
modules:
- name: runtime
config:
"@type": cosmos.app.runtime.v1alpha1.Module
app_name: CapabilityApp
begin_blockers: [capability, staking, auth, bank, genutil, params]
end_blockers: [staking, capability, auth, bank, genutil, params]
init_genesis: [capability, auth, bank, staking, genutil, params]
- name: auth
config:
"@type": cosmos.auth.module.v1.Module
bech32_prefix: cosmos
module_account_permissions:
- account: fee_collector
- account: bonded_tokens_pool
permissions: [burner, staking]
- account: not_bonded_tokens_pool
permissions: [burner, staking]
- name: bank
config:
"@type": cosmos.bank.module.v1.Module
- name: params
config:
"@type": cosmos.params.module.v1.Module
- name: tx
config:
"@type": cosmos.tx.module.v1.Module
- name: staking
config:
"@type": cosmos.staking.module.v1.Module
- name: genutil
config:
"@type": cosmos.genutil.module.v1.Module
- name: capability
config:
"@type": cosmos.capability.module.v1.Module
seal_keeper: true

View File

@ -0,0 +1,19 @@
package testutil
import (
_ "embed"
"cosmossdk.io/core/appconfig"
_ "github.com/cosmos/cosmos-sdk/x/auth"
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/module"
_ "github.com/cosmos/cosmos-sdk/x/bank"
_ "github.com/cosmos/cosmos-sdk/x/capability"
_ "github.com/cosmos/cosmos-sdk/x/genutil"
_ "github.com/cosmos/cosmos-sdk/x/params"
_ "github.com/cosmos/cosmos-sdk/x/staking"
)
//go:embed app.yaml
var appConfig []byte
var AppConfig = appconfig.LoadYAML(appConfig)

View File

@ -54,13 +54,6 @@ func (suite *SimTestSuite) SetupTest() {
suite.app = app
suite.ctx = app.BaseApp.NewContext(false, tmproto.Header{})
suite.app.BeginBlock(abci.RequestBeginBlock{
Header: tmproto.Header{
Height: suite.app.LastBlockHeight() + 1,
AppHash: suite.app.LastCommitID().Hash,
},
})
}
func (suite *SimTestSuite) TestWeightedOperations() {
@ -122,6 +115,14 @@ func (suite *SimTestSuite) TestSimulateMsgSend() {
blockTime := time.Now().UTC()
ctx := suite.ctx.WithBlockTime(blockTime)
// begin new block
suite.app.BeginBlock(abci.RequestBeginBlock{
Header: tmproto.Header{
Height: suite.app.LastBlockHeight() + 1,
AppHash: suite.app.LastCommitID().Hash,
},
})
// execute operation
registry := suite.interfaceRegistry
op := simulation.SimulateMsgSend(codec.NewProtoCodec(registry), suite.accountKeeper, suite.bankKeeper, suite.nftKeeper)