Skip to content

Commit

Permalink
refactor(simapp,runtime): audit changes (#21310)
Browse files Browse the repository at this point in the history
  • Loading branch information
julienrbrt authored Aug 27, 2024
1 parent 8e0efbd commit 03d3a93
Show file tree
Hide file tree
Showing 17 changed files with 183 additions and 110 deletions.
20 changes: 18 additions & 2 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,22 @@ need to remove them both from your app.go code, they will yield to unresolvable

The Cosmos SDK now supports unordered transactions. This means that transactions
can be executed in any order and doesn't require the client to deal with or manage
nonces. This also means the order of execution is not guaranteed. To enable unordered
transactions in your application:
nonces. This also means the order of execution is not guaranteed.

Unordered transactions are automatically enabled when using `depinject` / app di, simply supply the `servertypes.AppOptions` in `app.go`:

```diff
depinject.Supply(
+ // supply the application options
+ appOpts,
// supply the logger
logger,
)
```

<details>
<summary>Step-by-step Wiring </summary>
If you are still using the legacy wiring, you must enable unordered transactions manually:

* Update the `App` constructor to create, load, and save the unordered transaction
manager.
Expand Down Expand Up @@ -184,6 +198,8 @@ transactions in your application:
}
```

</details>

To submit an unordered transaction, the client must set the `unordered` flag to
`true` and ensure a reasonable `timeout_height` is set. The `timeout_height` is
used as a TTL for the transaction and is used to provide replay protection. See
Expand Down
47 changes: 37 additions & 10 deletions runtime/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"cosmossdk.io/core/legacy"
"cosmossdk.io/log"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/auth/ante/unorderedtx"
authtx "cosmossdk.io/x/auth/tx"

"github.com/cosmos/cosmos-sdk/baseapp"
Expand Down Expand Up @@ -41,7 +42,9 @@ import (
type App struct {
*baseapp.BaseApp

ModuleManager *module.Manager
ModuleManager *module.Manager
UnorderedTxManager *unorderedtx.Manager

configurator module.Configurator // nolint:staticcheck // SA1019: Configurator is deprecated but still used in runtime v1.
config *runtimev1alpha1.Module
storeKeys []storetypes.StoreKey
Expand Down Expand Up @@ -154,6 +157,20 @@ func (a *App) Load(loadLatest bool) error {
return nil
}

// Close closes all necessary application resources.
// It implements servertypes.Application.
func (a *App) Close() error {
// the unordered tx manager could be nil (unlikely but possible)
// if the app has no app options supplied.
if a.UnorderedTxManager != nil {
if err := a.UnorderedTxManager.Close(); err != nil {
return err
}
}

return a.BaseApp.Close()
}

// PreBlocker application updates every pre block
func (a *App) PreBlocker(ctx sdk.Context, _ *abci.FinalizeBlockRequest) error {
return a.ModuleManager.PreBlock(ctx)
Expand All @@ -171,16 +188,14 @@ func (a *App) EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) {

// Precommiter application updates every commit
func (a *App) Precommiter(ctx sdk.Context) {
err := a.ModuleManager.Precommit(ctx)
if err != nil {
if err := a.ModuleManager.Precommit(ctx); err != nil {
panic(err)
}
}

// PrepareCheckStater application updates every commit
func (a *App) PrepareCheckStater(ctx sdk.Context) {
err := a.ModuleManager.PrepareCheckState(ctx)
if err != nil {
if err := a.ModuleManager.PrepareCheckState(ctx); err != nil {
panic(err)
}
}
Expand Down Expand Up @@ -247,18 +262,30 @@ func (a *App) DefaultGenesis() map[string]json.RawMessage {
return a.ModuleManager.DefaultGenesis()
}

// GetStoreKeys returns all the stored store keys.
func (a *App) GetStoreKeys() []storetypes.StoreKey {
return a.storeKeys
}

// SetInitChainer sets the init chainer function
// It wraps `BaseApp.SetInitChainer` to allow setting a custom init chainer from an app.
func (a *App) SetInitChainer(initChainer sdk.InitChainer) {
a.initChainer = initChainer
a.BaseApp.SetInitChainer(initChainer)
}

// GetStoreKeys returns all the stored store keys.
func (a *App) GetStoreKeys() []storetypes.StoreKey {
return a.storeKeys
}

// GetKey returns the KVStoreKey for the provided store key.
//
// NOTE: This should only be used in testing.
func (a *App) GetKey(storeKey string) *storetypes.KVStoreKey {
sk := a.UnsafeFindStoreKey(storeKey)
kvStoreKey, ok := sk.(*storetypes.KVStoreKey)
if !ok {
return nil
}
return kvStoreKey
}

// UnsafeFindStoreKey fetches a registered StoreKey from the App in linear time.
//
// NOTE: This should only be used in testing.
Expand Down
64 changes: 64 additions & 0 deletions runtime/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ package runtime

import (
"encoding/json"
"fmt"
"io"
"path/filepath"

dbm "github.com/cosmos/cosmos-db"
"github.com/spf13/cast"

storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/auth/ante/unorderedtx"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client/flags"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version"
)
Expand All @@ -16,6 +24,8 @@ import (
// the existing app.go initialization conventions.
type AppBuilder struct {
app *App

appOptions servertypes.AppOptions
}

// DefaultGenesis returns a default genesis from the registered modules.
Expand All @@ -40,9 +50,63 @@ func (a *AppBuilder) Build(db dbm.DB, traceStore io.Writer, baseAppOptions ...fu
a.app.BaseApp = bApp
a.app.configurator = module.NewConfigurator(a.app.cdc, a.app.MsgServiceRouter(), a.app.GRPCQueryRouter())

if a.appOptions != nil {
// register unordered tx manager
if err := a.registerUnorderedTxManager(); err != nil {
panic(err)
}

// register indexer if enabled
if err := a.registerIndexer(); err != nil {
panic(err)
}
}

// register services
if err := a.app.ModuleManager.RegisterServices(a.app.configurator); err != nil {
panic(err)
}

return a.app
}

// register unordered tx manager
func (a *AppBuilder) registerUnorderedTxManager() error {
// create, start, and load the unordered tx manager
utxDataDir := filepath.Join(cast.ToString(a.appOptions.Get(flags.FlagHome)), "data")
a.app.UnorderedTxManager = unorderedtx.NewManager(utxDataDir)
a.app.UnorderedTxManager.Start()

if err := a.app.UnorderedTxManager.OnInit(); err != nil {
return fmt.Errorf("failed to initialize unordered tx manager: %w", err)
}

return nil
}

// register indexer
func (a *AppBuilder) registerIndexer() error {
// if we have indexer options in app.toml, then enable the built-in indexer framework
if indexerOpts := a.appOptions.Get("indexer"); indexerOpts != nil {
moduleSet := map[string]any{}
for modName, mod := range a.app.ModuleManager.Modules {
moduleSet[modName] = mod
}

return a.app.EnableIndexer(indexerOpts, a.kvStoreKeys(), moduleSet)
}

// register legacy streaming services if we don't have the built-in indexer enabled
return a.app.RegisterStreamingServices(a.appOptions, a.kvStoreKeys())
}

func (a *AppBuilder) kvStoreKeys() map[string]*storetypes.KVStoreKey {
keys := make(map[string]*storetypes.KVStoreKey)
for _, k := range a.app.GetStoreKeys() {
if kv, ok := k.(*storetypes.KVStoreKey); ok {
keys[kv.Name()] = kv
}
}

return keys
}
11 changes: 8 additions & 3 deletions runtime/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/std"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/types/msgservice"
Expand Down Expand Up @@ -120,7 +121,6 @@ func ProvideApp(
appmodule.AppModule,
protodesc.Resolver,
protoregistry.MessageTypeResolver,
error,
) {
protoFiles := proto.HybridResolver
protoTypes := protoregistry.GlobalTypes
Expand All @@ -145,9 +145,9 @@ func ProvideApp(
msgServiceRouter: msgServiceRouter,
grpcQueryRouter: grpcQueryRouter,
}
appBuilder := &AppBuilder{app}
appBuilder := &AppBuilder{app: app}

return appBuilder, msgServiceRouter, grpcQueryRouter, appModule{app}, protoFiles, protoTypes, nil
return appBuilder, msgServiceRouter, grpcQueryRouter, appModule{app}, protoFiles, protoTypes
}

type AppInputs struct {
Expand All @@ -160,6 +160,7 @@ type AppInputs struct {
BaseAppOptions []BaseAppOption
InterfaceRegistry codectypes.InterfaceRegistry
LegacyAmino legacy.Amino
AppOptions servertypes.AppOptions `optional:"true"` // can be nil in client wiring
}

func SetupAppBuilder(inputs AppInputs) {
Expand All @@ -170,6 +171,10 @@ func SetupAppBuilder(inputs AppInputs) {
app.ModuleManager = inputs.ModuleManager
app.ModuleManager.RegisterInterfaces(inputs.InterfaceRegistry)
app.ModuleManager.RegisterLegacyAminoCodec(inputs.LegacyAmino)

if inputs.AppOptions != nil {
inputs.AppBuilder.appOptions = inputs.AppOptions
}
}

func registerStoreKey(wrapper *AppBuilder, key storetypes.StoreKey) {
Expand Down
8 changes: 3 additions & 5 deletions runtime/v2/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,15 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) {
}
a.app.stf = stf

v := a.viper
home := v.GetString(FlagHome)

storeOpts := rootstore.DefaultStoreOptions()
if s := v.Sub("store.options"); s != nil {
if s := a.viper.Sub("store.options"); s != nil {
if err := s.Unmarshal(&storeOpts); err != nil {
return nil, fmt.Errorf("failed to store options: %w", err)
}
}

scRawDb, err := db.NewDB(db.DBType(v.GetString("store.app-db-backend")), "application", filepath.Join(home, "data"), nil)
home := a.viper.GetString(FlagHome)
scRawDb, err := db.NewDB(db.DBType(a.viper.GetString("store.app-db-backend")), "application", filepath.Join(home, "data"), nil)
if err != nil {
panic(err)
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/v2/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ type AppInputs struct {
InterfaceRegistrar registry.InterfaceRegistrar
LegacyAmino legacy.Amino
Logger log.Logger
Viper *viper.Viper `optional:"true"`
Viper *viper.Viper `optional:"true"` // can be nil in client wiring
}

func SetupAppBuilder(inputs AppInputs) {
Expand Down
5 changes: 3 additions & 2 deletions server/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ import (
// a command's Context.
const ServerContextKey = sdk.ContextKey("server.context")

// Context server context
// Deprecated: Do not use since we use viper to track all config
// Context is the server context.
// Prefer using we use viper a it tracks track all config.
// See core/context/server_context.go.
type Context struct {
Viper *viper.Viper
Config *cmtcfg.Config
Expand Down
9 changes: 9 additions & 0 deletions simapp/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,19 @@ It is an exautive list of changes that completes the SimApp section in the [UPGR

Always refer to the [UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/main/UPGRADING.md) to understand the changes.

* Update module path to new vanity url.
* Wire new SDK modules (`epochs`, `accounts`, `protocolpool`).
* Remove the crisis module from simapp.
* Update `export` function to make use of the new module collections API.
* Add example of how to define a custom mint function in `simapp/mint_fn.go`.
* Add address codec in client context and signing context.
* Update testnet command to match new module APIs.
* [#20409](https://github.com/cosmos/cosmos-sdk/pull/20409) Add `tx` as `SkipStoreKeys` in `app_config.go`.
* [#20485](https://github.com/cosmos/cosmos-sdk/pull/20485) The signature of `x/upgrade/types.UpgradeHandler` has changed to accept `appmodule.VersionMap` from `module.VersionMap`. These types are interchangeable, but usages of `UpradeKeeper.SetUpgradeHandler` may need to adjust their usages to match the new signature.
* [#20740](https://github.com/cosmos/cosmos-sdk/pull/20740) Update `genutilcli.Commands` to use the genutil modules from the module manager.
* [#20771](https://github.com/cosmos/cosmos-sdk/pull/20771) Use client/v2 `GetNodeHomeDirectory` helper in `app.go` and use the `DefaultNodeHome` constant everywhere in the app.
* [#20490](https://github.com/cosmos/cosmos-sdk/pull/20490) Refactor simulations to make use of `testutil/sims` instead of `runsims`.
* [#19726](https://github.com/cosmos/cosmos-sdk/pull/19726) Update APIs to match CometBFT v1.

<!-- TODO: move changelog.md elements to here -->

Expand Down
3 changes: 1 addition & 2 deletions simapp/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
type HandlerOptions struct {
ante.HandlerOptions
CircuitKeeper circuitante.CircuitBreaker
TxManager *unorderedtx.Manager
}

// NewAnteHandler returns an AnteHandler that checks and increments sequence
Expand All @@ -39,7 +38,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
ante.NewValidateBasicDecorator(options.Environment),
ante.NewTxTimeoutHeightDecorator(options.Environment),
ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, options.TxManager, options.Environment, ante.DefaultSha256Cost),
ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, options.UnorderedTxManager, options.Environment, ante.DefaultSha256Cost),
ante.NewValidateMemoDecorator(options.AccountKeeper),
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
Expand Down
10 changes: 7 additions & 3 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -638,9 +638,9 @@ func (app *SimApp) setAnteHandler(txConfig client.TxConfig) {
SignModeHandler: txConfig.SignModeHandler(),
FeegrantKeeper: app.FeeGrantKeeper,
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
UnorderedTxManager: app.UnorderedTxManager,
},
&app.CircuitKeeper,
app.UnorderedTxManager,
},
)
if err != nil {
Expand All @@ -662,9 +662,13 @@ func (app *SimApp) setPostHandler() {
app.SetPostHandler(postHandler)
}

// Close implements the Application interface and closes all necessary application
// resources.
// Close closes all necessary application resources.
// It implements servertypes.Application.
func (app *SimApp) Close() error {
if err := app.BaseApp.Close(); err != nil {
return err
}

return app.UnorderedTxManager.Close()
}

Expand Down
2 changes: 1 addition & 1 deletion simapp/app_config.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//nolint:unused,nolintlint // ignore unused code linting and directive `//nolint:unused // ignore unused code linting` is unused for linter "unused"
//nolint:unused,nolintlint // ignore unused code linting
package simapp

import (
Expand Down
Loading

0 comments on commit 03d3a93

Please sign in to comment.