From 5c6a797c11909384d1b253f6e4bd621ac53e4583 Mon Sep 17 00:00:00 2001 From: Rootul P Date: Tue, 14 May 2024 08:53:01 -0400 Subject: [PATCH] fix: export command (#3450) Closes https://github.com/celestiaorg/celestia-app/issues/3392 Opens https://github.com/celestiaorg/celestia-app/issues/3472 Fixes a few bugs: 1. Previously all modules had `ExportGenesis` invoked on them even if they weren't supported by the current app version. Now we only call `ExportGenesis` for the modules that are supported by the current app version 2. The export command wasn't updated to account for the changes in https://github.com/celestiaorg/celestia-app/pull/3320 which force us to mount stores after `app.New()` based on the current app version 3. The minfee module couldn't be exported b/c it didn't register a key table in `ExportGenesis` ## Testing I could export an app on app version 1 and 2. See [output](https://gist.github.com/rootulp/dfea2b5b40f7366b03706fc39321ceee) --- app/ante/min_fee_test.go | 2 +- app/app.go | 58 +++++++++++++++------- app/app_test.go | 3 ++ app/export.go | 49 +++++++++++++------ app/module/manager.go | 10 +++- app/module/manager_test.go | 91 ++++++++++++++++++++++++----------- app/test/export_test.go | 56 +++++++++++++++++++++ cmd/celestia-appd/cmd/root.go | 22 ++++----- scripts/single-node.sh | 9 +++- test/tokenfilter/setup.go | 2 +- x/minfee/genesis.go | 11 +++-- x/minfee/module.go | 2 +- x/minfee/params.go | 9 ++-- 13 files changed, 237 insertions(+), 87 deletions(-) create mode 100644 app/test/export_test.go diff --git a/app/ante/min_fee_test.go b/app/ante/min_fee_test.go index 560b09ac96..fa3eff573b 100644 --- a/app/ante/min_fee_test.go +++ b/app/ante/min_fee_test.go @@ -147,7 +147,7 @@ func TestCheckTxFeeWithGlobalMinGasPrices(t *testing.T) { require.NoError(t, err) subspace, _ := paramsKeeper.GetSubspace(minfee.ModuleName) - minfee.RegisterMinFeeParamTable(subspace) + subspace = minfee.RegisterMinFeeParamTable(subspace) subspace.Set(ctx, minfee.KeyGlobalMinGasPrice, globalminGasPriceDec) _, _, err = ante.ValidateTxFee(ctx, tx, paramsKeeper) diff --git a/app/app.go b/app/app.go index 5a9dd7849d..7866687e13 100644 --- a/app/app.go +++ b/app/app.go @@ -169,11 +169,12 @@ type App struct { MsgGateKeeper *ante.MsgVersioningGateKeeper } -// New returns a reference to an initialized celestia app. +// New returns a reference to an uninitialized app. Callers must subsequently +// call app.Info or app.InitChain to initialize the baseapp. // -// NOTE: upgradeHeight refers specifically to the height that -// a node will upgrade from v1 to v2. It will be deprecated in v3 -// in place for a dynamically signalling scheme +// NOTE: upgradeHeightV2 refers specifically to the height that a node will +// upgrade from v1 to v2. It will be deprecated in v3 in place for a dynamically +// signalling scheme func New( logger log.Logger, db dbm.DB, @@ -449,7 +450,7 @@ func (app *App) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.R return app.mm.BeginBlock(ctx, req) } -// EndBlocker application updates every end block +// EndBlocker executes application updates at the end of every block. func (app *App) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { res := app.mm.EndBlock(ctx, req) currentVersion := app.AppVersion() @@ -504,8 +505,11 @@ func (app *App) migrateModules(ctx sdk.Context, fromVersion, toVersion uint64) e return app.mm.RunMigrations(ctx, app.configurator, fromVersion, toVersion) } -// We wrap Info around baseapp so we can take the app version and -// setup the multicommit store. +// Info implements the ABCI interface. This method is a wrapper around baseapp's +// Info command so that it can take the app version and setup the multicommit +// store. +// +// Side-effect: calls baseapp.Init() func (app *App) Info(req abci.RequestInfo) abci.ResponseInfo { if height := app.LastBlockHeight(); height > 0 { ctx, err := app.CreateQueryContext(height, false) @@ -523,16 +527,16 @@ func (app *App) Info(req abci.RequestInfo) abci.ResponseInfo { resp := app.BaseApp.Info(req) // mount the stores for the provided app version if resp.AppVersion > 0 && !app.IsSealed() { - app.MountKVStores(app.versionedKeys(resp.AppVersion)) - if err := app.LoadLatestVersion(); err != nil { - panic(fmt.Sprintf("loading latest version: %s", err.Error())) - } + app.mountKeysAndInit(resp.AppVersion) } return resp } -// We wrap InitChain around baseapp so we can take the app version and -// setup the multicommit store. +// InitChain implements the ABCI interface. This method is a wrapper around +// baseapp's InitChain so we can take the app version and setup the multicommit +// store. +// +// Side-effect: calls baseapp.Init() func (app *App) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain) { // genesis must always contain the consensus params. The validator set however is derived from the // initial genesis state. The genesis must always contain a non zero app version which is the initial @@ -546,16 +550,24 @@ func (app *App) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain // mount the stores for the provided app version if it has not already been mounted if app.AppVersion() == 0 && !app.IsSealed() { - app.MountKVStores(app.versionedKeys(req.ConsensusParams.Version.AppVersion)) - if err := app.LoadLatestVersion(); err != nil { - panic(fmt.Sprintf("loading latest version: %s", err.Error())) - } + app.mountKeysAndInit(req.ConsensusParams.Version.AppVersion) } return app.BaseApp.InitChain(req) } -// InitChainer application update at chain initialization +// mountKeysAndInit mounts the keys for the provided app version and then +// invokes baseapp.Init(). +func (app *App) mountKeysAndInit(appVersion uint64) { + app.MountKVStores(app.versionedKeys(appVersion)) + + // Invoke load latest version for it's side-effect of invoking baseapp.Init() + if err := app.LoadLatestVersion(); err != nil { + panic(fmt.Sprintf("loading latest version: %s", err.Error())) + } +} + +// InitChainer is middleware that gets invoked part-way through the baseapp's InitChain invocation. func (app *App) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { var genesisState GenesisState if err := tmjson.Unmarshal(req.AppStateBytes, &genesisState); err != nil { @@ -749,3 +761,13 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino return paramsKeeper } + +func (app *App) InitializeAppVersion(ctx sdk.Context) { + appVersion := app.GetAppVersionFromParamStore(ctx) + if appVersion == 0 { + // if the param store does not have an app version set, default to v1 + app.SetAppVersion(ctx, v1) + } else { + app.SetAppVersion(ctx, appVersion) + } +} diff --git a/app/app_test.go b/app/app_test.go index b2aa6ca064..88c9c2927d 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -36,6 +36,9 @@ func TestNew(t *testing.T) { // will panic. assert.Panics(t, func() { got.StakingKeeper.SetHooks(nil) }) }) + t.Run("should not have sealed the baseapp", func(t *testing.T) { + assert.False(t, got.IsSealed()) + }) } // NoopWriter is a no-op implementation of a writer. diff --git a/app/export.go b/app/export.go index 7f75f274f2..9885a6c43a 100644 --- a/app/export.go +++ b/app/export.go @@ -4,8 +4,6 @@ import ( "encoding/json" "log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" @@ -13,19 +11,27 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// ExportAppStateAndValidators exports the state of the application for a genesis -// file. -func (app *App) ExportAppStateAndValidators( - forZeroHeight bool, jailAllowedAddrs []string, -) (servertypes.ExportedApp, error) { - // as if they could withdraw from the start of the next block - ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) +// ExportAppStateAndValidators exports the state of the application for a +// genesis file. +func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs []string) (servertypes.ExportedApp, error) { + ctx, err := app.CreateQueryContext(app.LastBlockHeight(), false) + if err != nil { + return servertypes.ExportedApp{}, err + } + + app.InitializeAppVersion(ctx) + if !app.IsSealed() { + app.mountKeysAndInit(app.AppVersion()) + } + + // Create a new context so that the commit multi-store reflects the store + // key mounting performed above. + ctx, err = app.CreateQueryContext(app.LastBlockHeight(), false) + if err != nil { + return servertypes.ExportedApp{}, err + } - // We export at last height + 1, because that's the height at which - // Tendermint will start InitChain. - height := app.LastBlockHeight() + 1 if forZeroHeight { - height = 0 app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs) } @@ -36,12 +42,25 @@ func (app *App) ExportAppStateAndValidators( } validators, err := staking.WriteValidators(ctx, app.StakingKeeper) + if err != nil { + return servertypes.ExportedApp{}, err + } + return servertypes.ExportedApp{ AppState: appState, Validators: validators, - Height: height, + Height: app.getExportHeight(forZeroHeight), ConsensusParams: app.BaseApp.GetConsensusParams(ctx), - }, err + }, nil +} + +func (app *App) getExportHeight(forZeroHeight bool) int64 { + if forZeroHeight { + return 0 + } + // We export at last height + 1, because that's the height at which + // Tendermint will start InitChain. + return app.LastBlockHeight() + 1 } // prepForZeroHeightGenesis preps for fresh start at zero height. Zero height diff --git a/app/module/manager.go b/app/module/manager.go index 30f052d2d6..f78ae752a8 100644 --- a/app/module/manager.go +++ b/app/module/manager.go @@ -179,11 +179,17 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData } } -// ExportGenesis performs export genesis functionality for modules +// ExportGenesis performs export genesis functionality for the modules supported +// in a particular version. func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec, version uint64) map[string]json.RawMessage { genesisData := make(map[string]json.RawMessage) modules := m.versionedModules[version] - for _, moduleName := range m.OrderExportGenesis { + moduleNamesForVersion := m.ModuleNames(version) + moduleNamesToExport := filter(m.OrderExportGenesis, func(moduleName string) bool { + // filter out modules that are not supported by this version + return slices.Contains(moduleNamesForVersion, moduleName) + }) + for _, moduleName := range moduleNamesToExport { genesisData[moduleName] = modules[moduleName].ExportGenesis(ctx, cdc) } diff --git a/app/module/manager_test.go b/app/module/manager_test.go index a12f5c27ec..2e8b3e4132 100644 --- a/app/module/manager_test.go +++ b/app/module/manager_test.go @@ -146,34 +146,71 @@ func TestManager_InitGenesis(t *testing.T) { } func TestManager_ExportGenesis(t *testing.T) { - mockCtrl := gomock.NewController(t) - t.Cleanup(mockCtrl.Finish) - - mockAppModule1 := mocks.NewMockAppModule(mockCtrl) - mockAppModule2 := mocks.NewMockAppModule(mockCtrl) - mockAppModule1.EXPECT().Name().Times(2).Return("module1") - mockAppModule1.EXPECT().ConsensusVersion().Times(1).Return(uint64(1)) - mockAppModule2.EXPECT().Name().Times(2).Return("module2") - mockAppModule2.EXPECT().ConsensusVersion().Times(1).Return(uint64(1)) - mm, err := module.NewManager([]module.VersionedModule{ - {Module: mockAppModule1, FromVersion: 1, ToVersion: 1}, - {Module: mockAppModule2, FromVersion: 1, ToVersion: 1}, + t.Run("export genesis with two modules at version 1", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mocks.NewMockAppModule(mockCtrl) + mockAppModule2 := mocks.NewMockAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule1.EXPECT().ConsensusVersion().Times(1).Return(uint64(1)) + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mockAppModule2.EXPECT().ConsensusVersion().Times(1).Return(uint64(1)) + mm, err := module.NewManager([]module.VersionedModule{ + {Module: mockAppModule1, FromVersion: 1, ToVersion: 1}, + {Module: mockAppModule2, FromVersion: 1, ToVersion: 1}, + }) + require.NoError(t, err) + require.NotNil(t, mm) + require.Equal(t, 2, len(mm.ModuleNames(1))) + + ctx := sdk.Context{} + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + mockAppModule1.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key1": "value1"}`)) + mockAppModule2.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key2": "value2"}`)) + + want := map[string]json.RawMessage{ + "module1": json.RawMessage(`{"key1": "value1"}`), + "module2": json.RawMessage(`{"key2": "value2"}`), + } + require.Equal(t, want, mm.ExportGenesis(ctx, cdc, 1)) + }) + t.Run("export genesis with one modules at version 1, one modules at version 2", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockAppModule1 := mocks.NewMockAppModule(mockCtrl) + mockAppModule2 := mocks.NewMockAppModule(mockCtrl) + mockAppModule1.EXPECT().Name().Times(2).Return("module1") + mockAppModule1.EXPECT().ConsensusVersion().Times(2).Return(uint64(1)) + mockAppModule2.EXPECT().Name().Times(2).Return("module2") + mockAppModule2.EXPECT().ConsensusVersion().Times(2).Return(uint64(1)) + mm, err := module.NewManager([]module.VersionedModule{ + {Module: mockAppModule1, FromVersion: 1, ToVersion: 1}, + {Module: mockAppModule2, FromVersion: 2, ToVersion: 2}, + }) + require.NoError(t, err) + require.NotNil(t, mm) + require.Equal(t, 1, len(mm.ModuleNames(1))) + require.Equal(t, 1, len(mm.ModuleNames(2))) + + ctx := sdk.Context{} + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + mockAppModule1.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key1": "value1"}`)) + mockAppModule2.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key2": "value2"}`)) + + want := map[string]json.RawMessage{ + "module1": json.RawMessage(`{"key1": "value1"}`), + } + assert.Equal(t, want, mm.ExportGenesis(ctx, cdc, 1)) + + want2 := map[string]json.RawMessage{ + "module2": json.RawMessage(`{"key2": "value2"}`), + } + assert.Equal(t, want2, mm.ExportGenesis(ctx, cdc, 2)) }) - require.NoError(t, err) - require.NotNil(t, mm) - require.Equal(t, 2, len(mm.ModuleNames(1))) - - ctx := sdk.Context{} - interfaceRegistry := types.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(interfaceRegistry) - mockAppModule1.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key1": "value1"}`)) - mockAppModule2.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).Times(1).Return(json.RawMessage(`{"key2": "value2"}`)) - - want := map[string]json.RawMessage{ - "module1": json.RawMessage(`{"key1": "value1"}`), - "module2": json.RawMessage(`{"key2": "value2"}`), - } - require.Equal(t, want, mm.ExportGenesis(ctx, cdc, 1)) } func TestManager_BeginBlock(t *testing.T) { diff --git a/app/test/export_test.go b/app/test/export_test.go new file mode 100644 index 0000000000..d224176faa --- /dev/null +++ b/app/test/export_test.go @@ -0,0 +1,56 @@ +package app_test + +import ( + "testing" + + "github.com/celestiaorg/celestia-app/v2/app" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmversion "github.com/tendermint/tendermint/proto/tendermint/version" +) + +func TestExportAppStateAndValidators(t *testing.T) { + t.Run("should return exported app for version 1", func(t *testing.T) { + forZeroHeight := true + jailAllowedAddrs := []string{} + testApp, _ := SetupTestAppWithUpgradeHeight(t, 3) + + exported, err := testApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) + require.NoError(t, err) + assert.NotNil(t, exported) + assert.Equal(t, uint64(1), exported.ConsensusParams.Version.AppVersion) + }) + t.Run("should return exported app for version 2", func(t *testing.T) { + forZeroHeight := false + jailAllowedAddrs := []string{} + + testApp, _ := SetupTestAppWithUpgradeHeight(t, 3) + upgradeToV2(t, testApp) + + exported, err := testApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) + require.NoError(t, err) + assert.NotNil(t, exported) + // TODO: the following assertion is commented out because the exported app does not populate consensus params.version + // assert.Equal(t, uint64(2), exported.ConsensusParams.Version.AppVersion) + }) +} + +func upgradeToV2(t *testing.T, testApp *app.App) { + testApp.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{ + Height: 2, + Version: tmversion.Consensus{App: 1}, + }}) + // Upgrade from v1 -> v2 + testApp.EndBlock(abci.RequestEndBlock{Height: 2}) + testApp.Commit() + require.EqualValues(t, 2, testApp.AppVersion()) + testApp.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{ + Height: 3, + Version: tmversion.Consensus{App: 2}, + }}) + testApp.EndBlock(abci.RequestEndBlock{Height: 3}) + testApp.Commit() + require.EqualValues(t, 3, testApp.LastBlockHeight()) +} diff --git a/cmd/celestia-appd/cmd/root.go b/cmd/celestia-appd/cmd/root.go index 61dc7e3265..c3212ad447 100644 --- a/cmd/celestia-appd/cmd/root.go +++ b/cmd/celestia-appd/cmd/root.go @@ -9,7 +9,6 @@ import ( "github.com/celestiaorg/celestia-app/v2/app" "github.com/celestiaorg/celestia-app/v2/app/encoding" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/simd/cmd" "github.com/cosmos/cosmos-sdk/x/crisis" "github.com/tendermint/tendermint/cmd/cometbft/commands" @@ -255,23 +254,22 @@ func NewAppServer(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts se } func createAppAndExport( - logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string, + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + height int64, + forZeroHeight bool, + jailWhiteList []string, appOpts servertypes.AppOptions, ) (servertypes.ExportedApp, error) { - encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) // Ideally, we would reuse the one created by NewRootCmd. - encCfg.Codec = codec.NewProtoCodec(encCfg.InterfaceRegistry) - var capp *app.App + config := encoding.MakeConfig(app.ModuleEncodingRegisters...) + celestiaApp := app.New(logger, db, traceStore, uint(1), config, 0, appOpts) if height != -1 { - capp = app.New(logger, db, traceStore, uint(1), encCfg, 0, appOpts) - - if err := capp.LoadHeight(height); err != nil { + if err := celestiaApp.LoadHeight(height); err != nil { return servertypes.ExportedApp{}, err } - } else { - capp = app.New(logger, db, traceStore, uint(1), encCfg, 0, appOpts) } - - return capp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) + return celestiaApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) } // replaceLogger optionally replaces the logger with a file logger if the flag diff --git a/scripts/single-node.sh b/scripts/single-node.sh index a4596daffc..3aade729b9 100755 --- a/scripts/single-node.sh +++ b/scripts/single-node.sh @@ -82,13 +82,20 @@ sed -i'.bak' 's#"null"#"kv"#g' "${CELESTIA_APP_HOME}"/config/config.toml # Persist ABCI responses sed -i'.bak' 's#discard_abci_responses = true#discard_abci_responses = false#g' "${CELESTIA_APP_HOME}"/config/config.toml +# Override the log level to debug +# sed -i'.bak' 's#log_level = "info"#log_level = "debug"#g' "${CELESTIA_APP_HOME}"/config/config.toml + # Override the VotingPeriod from 1 week to 1 minute sed -i'.bak' 's#"604800s"#"60s"#g' "${CELESTIA_APP_HOME}"/config/genesis.json +# Override the genesis to use app version 1 and then upgrade to app version 2 later. +sed -i'.bak' 's#"app_version": "2"#"app_version": "1"#g' "${CELESTIA_APP_HOME}"/config/genesis.json + # Start celestia-app echo "Starting celestia-app..." celestia-appd start \ --home "${CELESTIA_APP_HOME}" \ --api.enable \ --grpc.enable \ - --grpc-web.enable + --grpc-web.enable \ + --v2-upgrade-height 3 diff --git a/test/tokenfilter/setup.go b/test/tokenfilter/setup.go index 648081c70e..fcc68cce3a 100644 --- a/test/tokenfilter/setup.go +++ b/test/tokenfilter/setup.go @@ -244,7 +244,7 @@ func SetupWithGenesisValSet(t testing.TB, valSet *tmtypes.ValidatorSet, genAccs // do not require a network fee for this test subspace := app.GetSubspace(minfee.ModuleName) - minfee.RegisterMinFeeParamTable(subspace) + subspace = minfee.RegisterMinFeeParamTable(subspace) ctx := sdk.NewContext(app.CommitMultiStore(), tmproto.Header{}, false, log.NewNopLogger()) subspace.Set(ctx, minfee.KeyGlobalMinGasPrice, sdk.NewDec(0)) diff --git a/x/minfee/genesis.go b/x/minfee/genesis.go index c7748c45e4..7a3bc92204 100644 --- a/x/minfee/genesis.go +++ b/x/minfee/genesis.go @@ -25,13 +25,14 @@ func ValidateGenesis(genesis *GenesisState) error { // ExportGenesis returns the minfee module's exported genesis. func ExportGenesis(ctx sdk.Context, k params.Keeper) *GenesisState { - globalMinGasPrice, exists := k.GetSubspace(ModuleName) - - var minGasPrice sdk.Dec - globalMinGasPrice.Get(ctx, KeyGlobalMinGasPrice, &minGasPrice) + subspace, exists := k.GetSubspace(ModuleName) if !exists { panic("minfee subspace not set") } + subspace = RegisterMinFeeParamTable(subspace) + + var globalMinGasPrice sdk.Dec + subspace.Get(ctx, KeyGlobalMinGasPrice, &globalMinGasPrice) - return &GenesisState{GlobalMinGasPrice: minGasPrice} + return &GenesisState{GlobalMinGasPrice: globalMinGasPrice} } diff --git a/x/minfee/module.go b/x/minfee/module.go index 04695e7938..fd5afceb79 100644 --- a/x/minfee/module.go +++ b/x/minfee/module.go @@ -114,7 +114,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.Ra panic("minfee subspace not set") } - RegisterMinFeeParamTable(subspace) + subspace = RegisterMinFeeParamTable(subspace) // Set the global min gas price initial value globalMinGasPriceDec, err := sdk.NewDecFromStr(fmt.Sprintf("%f", genesisState.GlobalMinGasPrice)) diff --git a/x/minfee/params.go b/x/minfee/params.go index 58fa646d57..9d0957ab28 100644 --- a/x/minfee/params.go +++ b/x/minfee/params.go @@ -29,11 +29,12 @@ type Params struct { GlobalMinGasPrice sdk.Dec } -// RegisterMinFeeParamTable attaches a key table to the provided subspace if it doesn't have one -func RegisterMinFeeParamTable(ps paramtypes.Subspace) { - if !ps.HasKeyTable() { - ps.WithKeyTable(ParamKeyTable()) +// RegisterMinFeeParamTable returns a subspace with a key table attached. +func RegisterMinFeeParamTable(subspace paramtypes.Subspace) paramtypes.Subspace { + if subspace.HasKeyTable() { + return subspace } + return subspace.WithKeyTable(ParamKeyTable()) } // ParamKeyTable returns the param key table for the global min gas price module