From d31f2964b030583c1e12416995105f53d76fcebc Mon Sep 17 00:00:00 2001 From: Marko Date: Wed, 3 May 2023 10:58:58 +0200 Subject: [PATCH] feat!: Define Genesis state transition (#15999) --- CHANGELOG.md | 1 + baseapp/genesis.go | 22 ++++++++++++++ core/CHANGELOG.md | 6 +++- core/genesis/txhandler.go | 6 ++++ docs/docs/building-modules/08-genesis.md | 8 +++++ runtime/module.go | 11 +++---- simapp/app.go | 2 +- tests/integration/genutil/gentx_test.go | 4 +-- tools/rosetta/go.mod | 2 +- tools/rosetta/go.sum | 2 -- x/genutil/genesis.go | 3 +- x/genutil/gentx.go | 11 ++++--- x/genutil/gentx_test.go | 38 +++++++++++------------- x/genutil/module.go | 7 +++-- 14 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 baseapp/genesis.go create mode 100644 core/genesis/txhandler.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 799a8d52f7..e3d49a8a08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -180,6 +180,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * The signature of `NewSigVerificationDecorator` has been changed to accept a `x/tx/signing.HandlerMap`. * The signature of `VerifySignature` has been changed to accept a `x/tx/signing.HandlerMap` and other structs from `x/tx` as arguments. * The signature of `NewTxConfigWithTextual` has been deprecated and its signature changed to accept a `SignModeOptions`. +* (x/genutil) [#15999](https://github.com/cosmos/cosmos-sdk/pull/15999) Genutil now takes the `GenesisTxHanlder` interface instead of deliverTx. The interface is implemented on baseapp ### Client Breaking Changes diff --git a/baseapp/genesis.go b/baseapp/genesis.go new file mode 100644 index 0000000000..1384222239 --- /dev/null +++ b/baseapp/genesis.go @@ -0,0 +1,22 @@ +package baseapp + +import ( + "errors" + + "cosmossdk.io/core/genesis" + "github.com/cometbft/cometbft/abci/types" +) + +var _ genesis.TxHandler = (*BaseApp)(nil) + +// ExecuteGenesisTx implements genesis.GenesisState from +// cosmossdk.io/core/genesis to set initial state in genesis +func (ba BaseApp) ExecuteGenesisTx(tx []byte) error { + res := ba.DeliverTx(types.RequestDeliverTx{Tx: tx}) + + if res.Code != types.CodeTypeOK { + return errors.New(res.Log) + } + + return nil +} diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 30e15e1650..fe5221cb3a 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -38,4 +38,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API-Breaking Changes -- (store)[14635](https://github.com/cosmos/cosmos-sdk/pull/14635) Add error handling to all methods on the `KVStore` interface +* (store)[14635](https://github.com/cosmos/cosmos-sdk/pull/14635) Add error handling to all methods on the `KVStore` interface + +### Features + +* (genesis) [#15999](https://github.com/cosmos/cosmos-sdk/pull/15999) Add `GenesisTxHandler` interface diff --git a/core/genesis/txhandler.go b/core/genesis/txhandler.go new file mode 100644 index 0000000000..cd76517476 --- /dev/null +++ b/core/genesis/txhandler.go @@ -0,0 +1,6 @@ +package genesis + +// TxHandler is an interface that modules can implement to provide genesis state transitions +type TxHandler interface { + ExecuteGenesisTx([]byte) error +} diff --git a/docs/docs/building-modules/08-genesis.md b/docs/docs/building-modules/08-genesis.md index a63c8b1192..2221097bff 100644 --- a/docs/docs/building-modules/08-genesis.md +++ b/docs/docs/building-modules/08-genesis.md @@ -70,3 +70,11 @@ See an example of `ExportGenesis` from the `auth` module. ```go reference https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/x/auth/keeper/genesis.go#L37-L49 ``` + +### GenesisTxHandler + +`GenesisTxHandler` is a way for modules to submit state transitions prior to the first block. This is used by `x/genutil` to submit the genesis transactions for the validators to be added to staking. + +```go reference +https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/core/genesis/txhandler.go#L3-L6 +``` diff --git a/runtime/module.go b/runtime/module.go index 09a0f0b8b7..501bd93f4d 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -4,14 +4,13 @@ import ( "fmt" "os" + "cosmossdk.io/core/genesis" "cosmossdk.io/core/store" "cosmossdk.io/log" "github.com/cosmos/gogoproto/proto" "google.golang.org/protobuf/reflect/protodesc" "google.golang.org/protobuf/reflect/protoregistry" - abci "github.com/cometbft/cometbft/abci/types" - runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" "cosmossdk.io/core/appmodule" @@ -62,7 +61,7 @@ func init() { ProvideKVStoreKey, ProvideTransientStoreKey, ProvideMemoryStoreKey, - ProvideDeliverTx, + ProvideGenesisTxHandler, ProvideKVStoreService, ProvideMemoryStoreService, ProvideTransientStoreService, @@ -211,10 +210,8 @@ func ProvideMemoryStoreKey(key depinject.ModuleKey, app *AppBuilder) *storetypes return storeKey } -func ProvideDeliverTx(appBuilder *AppBuilder) func(abci.RequestDeliverTx) abci.ResponseDeliverTx { - return func(tx abci.RequestDeliverTx) abci.ResponseDeliverTx { - return appBuilder.app.BaseApp.DeliverTx(tx) - } +func ProvideGenesisTxHandler(appBuilder *AppBuilder) genesis.TxHandler { + return appBuilder.app } func ProvideKVStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) store.KVStoreService { diff --git a/simapp/app.go b/simapp/app.go index 29e3c73a6d..aee3169b05 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -358,7 +358,7 @@ func NewSimApp( // must be passed by reference here. app.ModuleManager = module.NewManager( genutil.NewAppModule( - app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx, + app.AccountKeeper, app.StakingKeeper, app, encodingConfig.TxConfig, ), auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), diff --git a/tests/integration/genutil/gentx_test.go b/tests/integration/genutil/gentx_test.go index 24f3072345..2ee90a51fb 100644 --- a/tests/integration/genutil/gentx_test.go +++ b/tests/integration/genutil/gentx_test.go @@ -305,13 +305,13 @@ func TestDeliverGenTxs(t *testing.T) { if tc.expPass { require.NotPanics(t, func() { genutil.DeliverGenTxs( - f.ctx, genTxs, f.stakingKeeper, f.baseApp.DeliverTx, + f.ctx, genTxs, f.stakingKeeper, f.baseApp, f.encodingConfig.TxConfig, ) }) } else { _, err := genutil.DeliverGenTxs( - f.ctx, genTxs, f.stakingKeeper, f.baseApp.DeliverTx, + f.ctx, genTxs, f.stakingKeeper, f.baseApp, f.encodingConfig.TxConfig, ) diff --git a/tools/rosetta/go.mod b/tools/rosetta/go.mod index cbefbd6df1..b0540668f1 100644 --- a/tools/rosetta/go.mod +++ b/tools/rosetta/go.mod @@ -141,8 +141,8 @@ require ( // TODO: remove after merge of https://github.com/cosmos/cosmos-sdk/pull/15873 and tagging releases replace ( + cosmossdk.io/core => ../../core cosmossdk.io/store => ../../store cosmossdk.io/x/tx => ../../x/tx - cosmossdk.io/core => ../../core github.com/cosmos/cosmos-sdk => ../.. ) diff --git a/tools/rosetta/go.sum b/tools/rosetta/go.sum index 3f8bef5da1..636e219aac 100644 --- a/tools/rosetta/go.sum +++ b/tools/rosetta/go.sum @@ -39,8 +39,6 @@ cosmossdk.io/api v0.4.1 h1:0ikaYM6GyxTYYcfBiyR8YnLCfhNnhKpEFnaSepCTmqg= cosmossdk.io/api v0.4.1/go.mod h1:jR7k5ok90LxW2lFUXvd8Vpo/dr4PpiyVegxdm7b1ZdE= cosmossdk.io/collections v0.1.0 h1:nzJGeiq32KnZroSrhB6rPifw4I85Cgmzw/YAmr4luv8= cosmossdk.io/collections v0.1.0/go.mod h1:xbauc0YsbUF8qKMVeBZl0pFCunxBIhKN/WlxpZ3lBuo= -cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s= -cosmossdk.io/core v0.6.1/go.mod h1:g3MMBCBXtxbDWBURDVnJE7XML4BG5qENhs0gzkcpuFA= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= diff --git a/x/genutil/genesis.go b/x/genutil/genesis.go index 9be0f21bff..97f71bd36a 100644 --- a/x/genutil/genesis.go +++ b/x/genutil/genesis.go @@ -1,6 +1,7 @@ package genutil import ( + "cosmossdk.io/core/genesis" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/client" @@ -11,7 +12,7 @@ import ( // InitGenesis - initialize accounts and deliver genesis transactions func InitGenesis( ctx sdk.Context, stakingKeeper types.StakingKeeper, - deliverTx deliverTxfn, genesisState types.GenesisState, + deliverTx genesis.TxHandler, genesisState types.GenesisState, txEncodingConfig client.TxEncodingConfig, ) (validators []abci.ValidatorUpdate, err error) { if len(genesisState.GenTxs) > 0 { diff --git a/x/genutil/gentx.go b/x/genutil/gentx.go index 49eb5349bb..31e3c78afa 100644 --- a/x/genutil/gentx.go +++ b/x/genutil/gentx.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" + "cosmossdk.io/core/genesis" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/client" @@ -84,14 +85,12 @@ func ValidateAccountInGenesis( return nil } -type deliverTxfn func(abci.RequestDeliverTx) abci.ResponseDeliverTx - // DeliverGenTxs iterates over all genesis txs, decodes each into a Tx and // invokes the provided deliverTxfn with the decoded Tx. It returns the result // of the staking module's ApplyAndReturnValidatorSetUpdates. func DeliverGenTxs( ctx sdk.Context, genTxs []json.RawMessage, - stakingKeeper types.StakingKeeper, deliverTx deliverTxfn, + stakingKeeper types.StakingKeeper, deliverTx genesis.TxHandler, txEncodingConfig client.TxEncodingConfig, ) ([]abci.ValidatorUpdate, error) { for _, genTx := range genTxs { @@ -105,9 +104,9 @@ func DeliverGenTxs( return nil, fmt.Errorf("failed to encode GenTx '%s': %s", genTx, err) } - res := deliverTx(abci.RequestDeliverTx{Tx: bz}) - if !res.IsOK() { - return nil, fmt.Errorf("failed to execute DeliverTx for '%s': %s", genTx, res.Log) + err = deliverTx.ExecuteGenesisTx(bz) + if err != nil { + return nil, fmt.Errorf("failed to execute DeliverTx for '%s': %s", genTx, err) } } diff --git a/x/genutil/gentx_test.go b/x/genutil/gentx_test.go index 897c1c7971..76b459a3a5 100644 --- a/x/genutil/gentx_test.go +++ b/x/genutil/gentx_test.go @@ -2,15 +2,16 @@ package genutil_test import ( "encoding/json" + "errors" "fmt" "math/rand" "testing" "time" + "cosmossdk.io/core/genesis" "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" - abci "github.com/cometbft/cometbft/abci/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" @@ -18,7 +19,6 @@ import ( "github.com/cosmos/cosmos-sdk/testutil" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/genutil" @@ -246,7 +246,7 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { testCases := []struct { msg string malleate func() - deliverTxFn func(abci.RequestDeliverTx) abci.ResponseDeliverTx + deliverTxFn genesis.TxHandler expPass bool }{ { @@ -260,14 +260,7 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { suite.Require().NoError(err) genTxs[0] = tx }, - func(_ abci.RequestDeliverTx) abci.ResponseDeliverTx { - return abci.ResponseDeliverTx{ - Code: sdkerrors.ErrNoSignatures.ABCICode(), - GasWanted: int64(10000000), - GasUsed: int64(41913), - Log: "no signatures supplied", - } - }, + GenesisState1{}, false, }, { @@ -293,15 +286,7 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { suite.Require().NoError(err) genTxs[0] = genTx }, - func(tx abci.RequestDeliverTx) abci.ResponseDeliverTx { - return abci.ResponseDeliverTx{ - Code: sdkerrors.ErrUnauthorized.ABCICode(), - GasWanted: int64(10000000), - GasUsed: int64(41353), - Log: "signature verification failed; please verify account number (4) and chain-id (): unauthorized", - Codespace: "sdk", - } - }, + GenesisState2{}, true, }, } @@ -313,6 +298,7 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { tc.malleate() if tc.expPass { + suite.stakingKeeper.EXPECT().ApplyAndReturnValidatorSetUpdates(gomock.Any()).Return(nil, nil).AnyTimes() suite.Require().NotPanics(func() { genutil.DeliverGenTxs( suite.ctx, genTxs, suite.stakingKeeper, tc.deliverTxFn, @@ -334,3 +320,15 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { func TestGenTxTestSuite(t *testing.T) { suite.Run(t, new(GenTxTestSuite)) } + +type GenesisState1 struct{} + +func (GenesisState1) ExecuteGenesisTx(_ []byte) error { + return errors.New("no signatures supplied") +} + +type GenesisState2 struct{} + +func (GenesisState2) ExecuteGenesisTx(tx []byte) error { + return nil +} diff --git a/x/genutil/module.go b/x/genutil/module.go index 85d70d39eb..71cc30369b 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -10,6 +10,7 @@ import ( modulev1 "cosmossdk.io/api/cosmos/genutil/module/v1" "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/genesis" "cosmossdk.io/depinject" @@ -80,13 +81,13 @@ type AppModule struct { accountKeeper types.AccountKeeper stakingKeeper types.StakingKeeper - deliverTx deliverTxfn + deliverTx genesis.TxHandler txEncodingConfig client.TxEncodingConfig } // NewAppModule creates a new AppModule object func NewAppModule(accountKeeper types.AccountKeeper, - stakingKeeper types.StakingKeeper, deliverTx deliverTxfn, + stakingKeeper types.StakingKeeper, deliverTx genesis.TxHandler, txEncodingConfig client.TxEncodingConfig, ) module.GenesisOnlyAppModule { return module.NewGenesisOnlyAppModule(AppModule{ @@ -138,7 +139,7 @@ type ModuleInputs struct { AccountKeeper types.AccountKeeper StakingKeeper types.StakingKeeper - DeliverTx func(abci.RequestDeliverTx) abci.ResponseDeliverTx + DeliverTx genesis.TxHandler Config client.TxConfig }