diff --git a/CHANGELOG.md b/CHANGELOG.md index db41a1eda64a..602badd0cc65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,9 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * (client) [#19905](https://github.com/cosmos/cosmos-sdk/pull/19905) Add grpc client config to `client.toml`. * (genutil) [#19971](https://github.com/cosmos/cosmos-sdk/pull/19971) Allow manually setting the consensus key type in genesis * (runtime) [#19953](https://github.com/cosmos/cosmos-sdk/pull/19953) Implement `core/transaction.Service` in runtime. +* (runtime) [#18475](https://github.com/cosmos/cosmos-sdk/pull/18475) Adds an implementation for `core.branch.Service`. +* (runtime) [#19004](https://github.com/cosmos/cosmos-sdk/pull/19004) Adds an implementation for `core/header.Service` in runtime. +* (runtime) [#20238](https://github.com/cosmos/cosmos-sdk/pull/20238) Adds an implementation for `core/comet.Service` in runtime. * (tests) [#20013](https://github.com/cosmos/cosmos-sdk/pull/20013) Introduce system tests to run multi node local testnet in CI * (crypto/keyring) [#20212](https://github.com/cosmos/cosmos-sdk/pull/20212) Expose the db keyring used in the keystore. * (client/tx) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Add `timeout-timestamp` field for tx body defines time based timeout.Add `WithTimeoutTimestamp` to tx factory. Increased gas cost for processing newly added timeout timestamp field in tx body. diff --git a/UPGRADING.md b/UPGRADING.md index 7218b4e5161b..a6cab531955a 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -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, + ) +``` + +
+Step-by-step Wiring +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. @@ -184,6 +198,8 @@ transactions in your application: } ``` +
+ 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 diff --git a/api/cosmos/base/abci/v1beta1/abci.pulsar.go b/api/cosmos/base/abci/v1beta1/abci.pulsar.go index 234e7c3bdfd5..824ceb18f855 100644 --- a/api/cosmos/base/abci/v1beta1/abci.pulsar.go +++ b/api/cosmos/base/abci/v1beta1/abci.pulsar.go @@ -7317,8 +7317,6 @@ type TxResponse struct { // these events include those emitted by processing all the messages and those // emitted from the ante. Whereas Logs contains the events, with // additional metadata, emitted only by processing the messages. - // - // Since: cosmos-sdk 0.42.11, 0.44.5, 0.45 Events []*v1.Event `protobuf:"bytes,13,rep,name=events,proto3" json:"events,omitempty"` } diff --git a/proto/cosmos/base/abci/v1beta1/abci.proto b/proto/cosmos/base/abci/v1beta1/abci.proto index 5a8fe6227169..63a09e73091e 100644 --- a/proto/cosmos/base/abci/v1beta1/abci.proto +++ b/proto/cosmos/base/abci/v1beta1/abci.proto @@ -45,8 +45,6 @@ message TxResponse { // these events include those emitted by processing all the messages and those // emitted from the ante. Whereas Logs contains the events, with // additional metadata, emitted only by processing the messages. - // - // Since: cosmos-sdk 0.42.11, 0.44.5, 0.45 repeated cometbft.abci.v1.Event events = 13 [(gogoproto.nullable) = false, (cosmos_proto.field_added_in) = "cosmos-sdk 0.45"]; } diff --git a/runtime/app.go b/runtime/app.go index 2481da380995..dd5da8580779 100644 --- a/runtime/app.go +++ b/runtime/app.go @@ -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" @@ -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 @@ -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) @@ -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) } } @@ -247,11 +262,6 @@ 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) { @@ -259,6 +269,23 @@ func (a *App) SetInitChainer(initChainer sdk.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. diff --git a/runtime/builder.go b/runtime/builder.go index c96af6ecd6ee..73fcb3f73f6b 100644 --- a/runtime/builder.go +++ b/runtime/builder.go @@ -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" ) @@ -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. @@ -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 +} diff --git a/runtime/environment.go b/runtime/environment.go index 3fc3c863958a..cfe70414f169 100644 --- a/runtime/environment.go +++ b/runtime/environment.go @@ -64,7 +64,7 @@ func EnvWithMemStoreService(memStoreService store.MemoryStoreService) EnvOption } // failingMsgRouter is a message router that panics when accessed -// this is to ensure all fields are set by in environment +// this is to ensure all fields are set in environment type failingMsgRouter struct { baseapp.MessageRouter } @@ -86,7 +86,7 @@ func (failingMsgRouter) HybridHandlerByMsgName(msgName string) func(ctx context. } // failingQueryRouter is a query router that panics when accessed -// this is to ensure all fields are set by in environment +// this is to ensure all fields are set in environment type failingQueryRouter struct { baseapp.QueryRouter } @@ -112,7 +112,7 @@ func (failingQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.Inte } // failingMemStore is a memstore that panics when accessed -// this is to ensure all fields are set by in environment +// this is to ensure all fields are set in environment type failingMemStore struct { store.MemoryStoreService } diff --git a/runtime/module.go b/runtime/module.go index 99d4ff53dafd..f8883e0e8e27 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -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" @@ -120,7 +121,6 @@ func ProvideApp( appmodule.AppModule, protodesc.Resolver, protoregistry.MessageTypeResolver, - error, ) { protoFiles := proto.HybridResolver protoTypes := protoregistry.GlobalTypes @@ -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 { @@ -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) { @@ -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) { diff --git a/runtime/router.go b/runtime/router.go index 86ba89289d47..ff873f271738 100644 --- a/runtime/router.go +++ b/runtime/router.go @@ -15,7 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" ) -// NewMsgRouterService implements router.Service. +// NewMsgRouterService return new implementation of router.Service. func NewMsgRouterService(msgRouter baseapp.MessageRouter) router.Service { return &msgRouterService{ router: msgRouter, @@ -75,7 +75,7 @@ func (m *msgRouterService) Invoke(ctx context.Context, msg gogoproto.Message) (g return msgResp, nil } -// NewQueryRouterService implements router.Service. +// NewQueryRouterService return new implementation of router.Service. func NewQueryRouterService(queryRouter baseapp.QueryRouter) router.Service { return &queryRouterService{ router: queryRouter, diff --git a/runtime/store.go b/runtime/store.go index 817d9719a64a..32097fb41bbe 100644 --- a/runtime/store.go +++ b/runtime/store.go @@ -63,34 +63,32 @@ func (failingStoreService) OpenTransientStore(ctx context.Context) store.KVStore } // CoreKVStore is a wrapper of Core/Store kvstore interface -// Remove after https://github.com/cosmos/cosmos-sdk/issues/14714 is closed type coreKVStore struct { kvStore storetypes.KVStore } // NewKVStore returns a wrapper of Core/Store kvstore interface -// Remove once store migrates to core/store kvstore interface func newKVStore(store storetypes.KVStore) store.KVStore { return coreKVStore{kvStore: store} } -// Get returns nil iff key doesn't exist. Errors on nil key. +// Get returns value corresponding to the key. Panics on nil key. func (store coreKVStore) Get(key []byte) ([]byte, error) { return store.kvStore.Get(key), nil } -// Has checks if a key exists. Errors on nil key. +// Has checks if a key exists. Panics on nil key. func (store coreKVStore) Has(key []byte) (bool, error) { return store.kvStore.Has(key), nil } -// Set sets the key. Errors on nil key or value. +// Set sets the key. Panics on nil key or value. func (store coreKVStore) Set(key, value []byte) error { store.kvStore.Set(key, value) return nil } -// Delete deletes the key. Errors on nil key. +// Delete deletes the key. Panics on nil key. func (store coreKVStore) Delete(key []byte) error { store.kvStore.Delete(key) return nil diff --git a/runtime/v2/app.go b/runtime/v2/app.go index ff888039be57..1fdbd2aa0b65 100644 --- a/runtime/v2/app.go +++ b/runtime/v2/app.go @@ -110,11 +110,6 @@ func (a *App[T]) GetStore() Store { return a.db } -// GetLogger returns the app logger. -func (a *App[T]) GetLogger() log.Logger { - return a.logger -} - func (a *App[T]) GetAppManager() *appmanager.AppManager[T] { return a.AppManager } diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 578cd9934a6e..33e4f46bb77a 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -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) + return nil, fmt.Errorf("failed to unmarshal 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) } diff --git a/runtime/v2/manager.go b/runtime/v2/manager.go index bdeaf02afe36..ddec8015fe21 100644 --- a/runtime/v2/manager.go +++ b/runtime/v2/manager.go @@ -217,7 +217,7 @@ func (m *MM[T]) ExportGenesisForModules( if module, hasGenesis := mod.(appmodulev2.HasGenesis); hasGenesis { moduleI = module.(ModuleI) - } else if module, hasABCIGenesis := mod.(appmodulev2.HasGenesis); hasABCIGenesis { + } else if module, hasABCIGenesis := mod.(appmodulev2.HasABCIGenesis); hasABCIGenesis { moduleI = module.(ModuleI) } else { continue @@ -357,8 +357,56 @@ func (m *MM[T]) TxValidators() func(ctx context.Context, tx T) error { } } -// TODO write as descriptive godoc as module manager v1. -// TODO include feedback from https://github.com/cosmos/cosmos-sdk/issues/15120 +// RunMigrations performs in-place store migrations for all modules. This +// function MUST be called inside an x/upgrade UpgradeHandler. +// +// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from +// x/upgrade's store, and the function needs to return the target VersionMap +// that will in turn be persisted to the x/upgrade's store. In general, +// returning RunMigrations should be enough: +// +// Example: +// +// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM appmodule.VersionMap) (appmodule.VersionMap, error) { +// return app.ModuleManager().RunMigrations(ctx, fromVM) +// }) +// +// Internally, RunMigrations will perform the following steps: +// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion +// - if module implements `HasConsensusVersion` interface get the consensus version as `toVersion`, +// if not `toVersion` is set to 0. +// - get `fromVersion` from `fromVM` with module's name. +// - if the module's name exists in `fromVM` map, then run in-place store migrations +// for that module between `fromVersion` and `toVersion`. +// - if the module does not exist in the `fromVM` (which means that it's a new module, +// because it was not in the previous x/upgrade's store), then run +// `InitGenesis` on that module. +// +// - return the `updatedVM` to be persisted in the x/upgrade's store. +// +// Migrations are run in an order defined by `mm.config.OrderMigrations`. +// +// As an app developer, if you wish to skip running InitGenesis for your new +// module "foo", you need to manually pass a `fromVM` argument to this function +// foo's module version set to its latest ConsensusVersion. That way, the diff +// between the function's `fromVM` and `udpatedVM` will be empty, hence not +// running anything for foo. +// +// Example: +// +// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { +// // Assume "foo" is a new module. +// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist +// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default +// // run InitGenesis on foo. +// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest +// // consensus version: +// fromVM["foo"] = foo.AppModule{}.ConsensusVersion() +// +// return app.ModuleManager().RunMigrations(ctx, fromVM) +// }) +// +// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information. func (m *MM[T]) RunMigrations(ctx context.Context, fromVM appmodulev2.VersionMap) (appmodulev2.VersionMap, error) { updatedVM := appmodulev2.VersionMap{} for _, moduleName := range m.config.OrderMigrations { @@ -443,8 +491,8 @@ func (m *MM[T]) RegisterServices(app *App[T]) error { func (m *MM[T]) validateConfig() error { if err := m.assertNoForgottenModules("PreBlockers", m.config.PreBlockers, func(moduleName string) bool { module := m.modules[moduleName] - _, hasBlock := module.(appmodulev2.HasPreBlocker) - return !hasBlock + _, hasPreBlock := module.(appmodulev2.HasPreBlocker) + return !hasPreBlock }); err != nil { return err } diff --git a/runtime/v2/migrations.go b/runtime/v2/migrations.go index c0d4d9710017..25597448d926 100644 --- a/runtime/v2/migrations.go +++ b/runtime/v2/migrations.go @@ -14,7 +14,7 @@ type migrationRegistrar struct { migrations map[string]map[uint64]appmodulev2.MigrationHandler } -// newMigrationRegistrar is constructor for registering in-place store migrations for modules. +// newMigrationRegistrar is a constructor for registering in-place store migrations for modules. func newMigrationRegistrar() *migrationRegistrar { return &migrationRegistrar{ migrations: make(map[string]map[uint64]appmodulev2.MigrationHandler), diff --git a/runtime/v2/module.go b/runtime/v2/module.go index b2c6de11d78a..6ae735505d02 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -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) { diff --git a/runtime/v2/store.go b/runtime/v2/store.go index e40467fa3bf2..78223d4fdf24 100644 --- a/runtime/v2/store.go +++ b/runtime/v2/store.go @@ -23,7 +23,7 @@ type Store interface { StateLatest() (uint64, store.ReaderMap, error) // StateAt returns a readonly view over the provided - // state. Must error when the version does not exist. + // version. Must error when the version does not exist. StateAt(version uint64) (store.ReaderMap, error) // SetInitialVersion sets the initial version of the store. @@ -52,5 +52,6 @@ type Store interface { // latest version implicitly. LoadLatestVersion() error + // LastCommitID returns the latest commit ID LastCommitID() (proof.CommitID, error) } diff --git a/runtime/v2/types.go b/runtime/v2/types.go index 0138dd802c82..baa20182b512 100644 --- a/runtime/v2/types.go +++ b/runtime/v2/types.go @@ -17,7 +17,7 @@ const ( FlagHome = "home" ) -// ValidateProtoAnnotations validates that the proto annotations are correct. +// validateProtoAnnotations validates that the proto annotations are correct. // More specifically, it verifies: // - all services named "Msg" have `(cosmos.msg.v1.service) = true`, // diff --git a/server/util.go b/server/util.go index 5e77127b5a04..d55550d18027 100644 --- a/server/util.go +++ b/server/util.go @@ -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 diff --git a/simapp/CHANGELOG.md b/simapp/CHANGELOG.md index 7ef5486f7cb0..b2b2ee639cc1 100644 --- a/simapp/CHANGELOG.md +++ b/simapp/CHANGELOG.md @@ -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. diff --git a/simapp/ante.go b/simapp/ante.go index 6a12eabecfd5..8fd68c613076 100644 --- a/simapp/ante.go +++ b/simapp/ante.go @@ -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 @@ -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), diff --git a/simapp/app.go b/simapp/app.go index eaf61f253d2c..eff341e424f3 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -637,9 +637,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 { @@ -661,9 +661,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() } diff --git a/simapp/app_config.go b/simapp/app_config.go index ecf2fdf3714a..8d2172e44b41 100644 --- a/simapp/app_config.go +++ b/simapp/app_config.go @@ -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 ( diff --git a/simapp/app_di.go b/simapp/app_di.go index bf7c2a172718..dfd95e19a951 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -6,17 +6,14 @@ import ( _ "embed" "fmt" "io" - "path/filepath" dbm "github.com/cosmos/cosmos-db" - "github.com/spf13/cast" clienthelpers "cosmossdk.io/client/v2/helpers" "cosmossdk.io/core/appmodule" "cosmossdk.io/core/legacy" "cosmossdk.io/depinject" "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" "cosmossdk.io/x/accounts" "cosmossdk.io/x/auth" "cosmossdk.io/x/auth/ante" @@ -44,7 +41,6 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" @@ -74,8 +70,6 @@ type SimApp struct { txConfig client.TxConfig interfaceRegistry codectypes.InterfaceRegistry - UnorderedTxManager *unorderedtx.Manager - // keepers AccountsKeeper accounts.Keeper AuthKeeper authkeeper.AccountKeeper @@ -244,23 +238,6 @@ func NewSimApp( app.App = appBuilder.Build(db, traceStore, baseAppOptions...) - if indexerOpts := appOpts.Get("indexer"); indexerOpts != nil { - // if we have indexer options in app.toml, then enable the built-in indexer framework - moduleSet := map[string]any{} - for modName, mod := range appModules { - moduleSet[modName] = mod - } - err := app.EnableIndexer(indexerOpts, app.kvStoreKeys(), moduleSet) - if err != nil { - panic(err) - } - } else { - // register legacy streaming services if we don't have the built-in indexer enabled - if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil { - panic(err) - } - } - /**** Module Options ****/ // RegisterUpgradeHandlers is used for registering any on-chain upgrades. @@ -286,26 +263,16 @@ func NewSimApp( // However, when registering a module manually (i.e. that does not support app wiring), the module version map // must be set manually as follow. The upgrade module will de-duplicate the module version map. // - // app.SetInitChainer(func(ctx sdk.Context, req *abci.RequestInitChain) (*abci.InitChainResponse, error) { + // app.SetInitChainer(func(ctx sdk.Context, req *abci.InitChainRequest) (*abci.InitChainResponse, error) { // app.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap()) // return app.App.InitChainer(ctx, req) // }) - // create, start, and load the unordered tx manager - utxDataDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data") - app.UnorderedTxManager = unorderedtx.NewManager(utxDataDir) - app.UnorderedTxManager.Start() - - if err := app.UnorderedTxManager.OnInit(); err != nil { - panic(fmt.Errorf("failed to initialize unordered tx manager: %w", err)) - } - // register custom snapshot extensions (if any) if manager := app.SnapshotManager(); manager != nil { - err := manager.RegisterExtensions( + if err := manager.RegisterExtensions( unorderedtx.NewSnapshotter(app.UnorderedTxManager), - ) - if err != nil { + ); err != nil { panic(fmt.Errorf("failed to register snapshot extension: %w", err)) } } @@ -326,15 +293,15 @@ func (app *SimApp) setCustomAnteHandler() { anteHandler, err := NewAnteHandler( HandlerOptions{ ante.HandlerOptions{ - AccountKeeper: app.AuthKeeper, - BankKeeper: app.BankKeeper, - SignModeHandler: app.txConfig.SignModeHandler(), - FeegrantKeeper: app.FeeGrantKeeper, - SigGasConsumer: ante.DefaultSigVerificationGasConsumer, - Environment: app.AuthKeeper.Environment, + AccountKeeper: app.AuthKeeper, + BankKeeper: app.BankKeeper, + SignModeHandler: app.txConfig.SignModeHandler(), + FeegrantKeeper: app.FeeGrantKeeper, + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + UnorderedTxManager: app.UnorderedTxManager, + Environment: app.AuthKeeper.Environment, }, &app.CircuitBreakerKeeper, - app.UnorderedTxManager, }, ) if err != nil { @@ -345,12 +312,6 @@ func (app *SimApp) setCustomAnteHandler() { app.SetAnteHandler(anteHandler) } -// Close implements the Application interface and closes all necessary application -// resources. -func (app *SimApp) Close() error { - return app.UnorderedTxManager.Close() -} - // LegacyAmino returns SimApp's amino codec. // // NOTE: This is solely to be used for testing purposes as it may be desirable @@ -382,29 +343,6 @@ func (app *SimApp) TxConfig() client.TxConfig { return app.txConfig } -// GetKey returns the KVStoreKey for the provided store key. -// -// NOTE: This is solely to be used for testing purposes. -func (app *SimApp) GetKey(storeKey string) *storetypes.KVStoreKey { - sk := app.UnsafeFindStoreKey(storeKey) - kvStoreKey, ok := sk.(*storetypes.KVStoreKey) - if !ok { - return nil - } - return kvStoreKey -} - -func (app *SimApp) kvStoreKeys() map[string]*storetypes.KVStoreKey { - keys := make(map[string]*storetypes.KVStoreKey) - for _, k := range app.GetStoreKeys() { - if kv, ok := k.(*storetypes.KVStoreKey); ok { - keys[kv.Name()] = kv - } - } - - return keys -} - // SimulationManager implements the SimulationApp interface func (app *SimApp) SimulationManager() *module.SimulationManager { return app.sm diff --git a/simapp/simd/cmd/config.go b/simapp/simd/cmd/config.go index 3d551c227666..a87875836fd9 100644 --- a/simapp/simd/cmd/config.go +++ b/simapp/simd/cmd/config.go @@ -103,7 +103,6 @@ func initAppConfig() (string, interface{}) { // // In simapp, we set the min gas prices to 0. srvCfg.MinGasPrices = "0stake" - // srvCfg.BaseConfig.IAVLDisableFastNode = true // disable fastnode by default // Now we set the custom config default values. customAppConfig := CustomAppConfig{ diff --git a/simapp/v2/app_config.go b/simapp/v2/app_config.go index 5b4ccc4c2682..c126d1dcfa90 100644 --- a/simapp/v2/app_config.go +++ b/simapp/v2/app_config.go @@ -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 ( diff --git a/testutil/network/network.go b/testutil/network/network.go index cd59d0b08502..9fde8e26937b 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -49,6 +49,7 @@ import ( srvconfig "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/testutil" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" @@ -210,7 +211,10 @@ func DefaultConfigWithAppConfig(appConfig depinject.Config, baseappOpts ...func( if err := depinject.Inject( depinject.Configs( appConfig, - depinject.Supply(val.GetLogger()), + depinject.Supply( + val.GetLogger(), + simtestutil.NewAppOptionsWithFlagHome(val.GetViper().GetString(flags.FlagHome)), + ), ), &appBuilder); err != nil { panic(err) diff --git a/types/abci.pb.go b/types/abci.pb.go index 2d7c0f59a582..b4dadfb2d040 100644 --- a/types/abci.pb.go +++ b/types/abci.pb.go @@ -63,8 +63,6 @@ type TxResponse struct { // these events include those emitted by processing all the messages and those // emitted from the ante. Whereas Logs contains the events, with // additional metadata, emitted only by processing the messages. - // - // Since: cosmos-sdk 0.42.11, 0.44.5, 0.45 Events []v1.Event `protobuf:"bytes,13,rep,name=events,proto3" json:"events"` } diff --git a/types/address_test.go b/types/address_test.go index 394dc46a423d..04edc6d6075f 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -22,14 +22,6 @@ import ( "github.com/cosmos/cosmos-sdk/types/bech32/legacybech32" //nolint:staticcheck // we're using this to support the legacy way of dealing with bech32 ) -const ( - pubStr = "pub" - valoper = "valoper" - valoperpub = "valoperpub" - valcons = "valcons" - valconspub = "valconspub" -) - type addressTestSuite struct { suite.Suite } @@ -42,17 +34,22 @@ func (s *addressTestSuite) SetupSuite() { s.T().Parallel() } -var invalidStrs = []string{ - "hello, world!", - "0xAA", - "AAA", - types.Bech32PrefixAccAddr + "AB0C", - types.Bech32PrefixAccPub + "1234", - types.Bech32PrefixValAddr + "5678", - types.Bech32PrefixValPub + "BBAB", - types.Bech32PrefixConsAddr + "FF04", - types.Bech32PrefixConsPub + "6789", -} +var ( + invalidStrs = []string{ + "hello, world!", + "0xAA", + "AAA", + types.Bech32PrefixAccAddr + "AB0C", + types.Bech32PrefixAccPub + "1234", + types.Bech32PrefixValAddr + "5678", + types.Bech32PrefixValPub + "BBAB", + types.Bech32PrefixConsAddr + "FF04", + types.Bech32PrefixConsPub + "6789", + } + + addr10byte = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + addr20byte = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} +) func (s *addressTestSuite) testMarshal(original, res interface{}, marshal func() ([]byte, error), unmarshal func([]byte) error) { bz, err := marshal() @@ -161,6 +158,12 @@ func (s *addressTestSuite) TestUnmarshalYAMLWithInvalidInput() { s.Require().Equal(types.ErrEmptyHexAddress, err) } +func setConfigWithPrefix(conf *types.Config, prefix string) { + conf.SetBech32PrefixForAccount(prefix, types.GetBech32PrefixAccPub(prefix)) + conf.SetBech32PrefixForValidator(types.GetBech32PrefixValAddr(prefix), types.GetBech32PrefixValPub(prefix)) + conf.SetBech32PrefixForConsensusNode(types.GetBech32PrefixConsAddr(prefix), types.GetBech32PrefixConsPub(prefix)) +} + // Test that the account address cache ignores the bech32 prefix setting, retrieving bech32 addresses from the cache. // This will cause the AccAddress.String() to print out unexpected prefixes if the config was changed between bech32 lookups. // See https://github.com/cosmos/cosmos-sdk/issues/15317. @@ -173,18 +176,14 @@ func (s *addressTestSuite) TestAddrCache() { // Set SDK bech32 prefixes to 'osmo' prefix := "osmo" conf := types.GetConfig() - conf.SetBech32PrefixForAccount(prefix, prefix+pubStr) - conf.SetBech32PrefixForValidator(prefix+valoper, prefix+valoperpub) - conf.SetBech32PrefixForConsensusNode(prefix+valcons, prefix+valconspub) + setConfigWithPrefix(conf, prefix) acc := types.AccAddress(pub.Address()) osmoAddrBech32 := acc.String() // Set SDK bech32 to 'cosmos' prefix = "cosmos" - conf.SetBech32PrefixForAccount(prefix, prefix+pubStr) - conf.SetBech32PrefixForValidator(prefix+valoper, prefix+valoperpub) - conf.SetBech32PrefixForConsensusNode(prefix+valcons, prefix+valconspub) + setConfigWithPrefix(conf, prefix) // We name this 'addrCosmos' to prove a point, but the bech32 address will still begin with 'osmo' due to the cache behavior. addrCosmos := types.AccAddress(pub.Address()) @@ -210,18 +209,14 @@ func (s *addressTestSuite) TestAddrCacheDisabled() { // Set SDK bech32 prefixes to 'osmo' prefix := "osmo" conf := types.GetConfig() - conf.SetBech32PrefixForAccount(prefix, prefix+pubStr) - conf.SetBech32PrefixForValidator(prefix+valoper, prefix+valoperpub) - conf.SetBech32PrefixForConsensusNode(prefix+valcons, prefix+valconspub) + setConfigWithPrefix(conf, prefix) acc := types.AccAddress(pub.Address()) osmoAddrBech32 := acc.String() // Set SDK bech32 to 'cosmos' prefix = "cosmos" - conf.SetBech32PrefixForAccount(prefix, prefix+pubStr) - conf.SetBech32PrefixForValidator(prefix+valoper, prefix+valoperpub) - conf.SetBech32PrefixForConsensusNode(prefix+valcons, prefix+valconspub) + setConfigWithPrefix(conf, prefix) addrCosmos := types.AccAddress(pub.Address()) cosmosAddrBech32 := addrCosmos.String() @@ -409,8 +404,6 @@ func (s *addressTestSuite) TestAddressInterface() { } func (s *addressTestSuite) TestBech32ifyAddressBytes() { - addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} - addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} type args struct { prefix string bs []byte @@ -442,8 +435,6 @@ func (s *addressTestSuite) TestBech32ifyAddressBytes() { } func (s *addressTestSuite) TestMustBech32ifyAddressBytes() { - addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} - addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} type args struct { prefix string bs []byte @@ -536,7 +527,7 @@ func (s *addressTestSuite) TestGetFromBech32() { } func (s *addressTestSuite) TestMustValAddressFromBech32() { - valAddress1 := types.ValAddress([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) + valAddress1 := types.ValAddress(addr20byte) valAddress2 := types.MustValAddressFromBech32(valAddress1.String()) s.Require().Equal(valAddress1, valAddress2) @@ -589,7 +580,7 @@ func (s *addressTestSuite) TestGetBech32PrefixConsPub() { } func (s *addressTestSuite) TestMustAccAddressFromBech32() { - accAddress1 := types.AccAddress([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) + accAddress1 := types.AccAddress(addr20byte) accAddress2 := types.MustAccAddressFromBech32(accAddress1.String()) s.Require().Equal(accAddress1, accAddress2) } @@ -628,10 +619,9 @@ func (s *addressTestSuite) TestUnmarshalYAMLAccAddressWithEmptyString() { } func (s *addressTestSuite) TestFormatAccAddressAsString() { - addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} accAddr := types.AccAddress(addr20byte) - actual := fmt.Sprintf("%s", accAddr) // this will call internally the method AccAddress.Format + actual := fmt.Sprintf("%s", accAddr) // this will internally calls AccAddress.Format method hrp := types.GetConfig().GetBech32AccountAddrPrefix() expected, err := bech32.ConvertAndEncode(hrp, addr20byte) @@ -640,9 +630,9 @@ func (s *addressTestSuite) TestFormatAccAddressAsString() { } func (s *addressTestSuite) TestFormatAccAddressAsPointer() { - accAddr := types.AccAddress([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) + accAddr := types.AccAddress(addr20byte) ptrAddr := &accAddr - actual := fmt.Sprintf("%p", ptrAddr) // this will call internally the method AccAddress.Format + actual := fmt.Sprintf("%p", ptrAddr) // this will internally calls AccAddress.Format method expected := fmt.Sprintf("0x%x", uintptr(unsafe.Pointer(&accAddr))) s.Require().Equal(expected, actual) } @@ -684,7 +674,6 @@ func (s *addressTestSuite) TestUnmarshalYAMLValAddressWithEmptyString() { } func (s *addressTestSuite) TestFormatValAddressAsString() { - addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} accAddr := types.ValAddress(addr20byte) actual := fmt.Sprintf("%s", accAddr) @@ -696,7 +685,7 @@ func (s *addressTestSuite) TestFormatValAddressAsString() { } func (s *addressTestSuite) TestFormatValAddressAsPointer() { - accAddr := types.AccAddress([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) + accAddr := types.AccAddress(addr20byte) ptrAddr := &accAddr actual := fmt.Sprintf("%p", ptrAddr) expected := uintptr(unsafe.Pointer(&accAddr)) @@ -704,7 +693,7 @@ func (s *addressTestSuite) TestFormatValAddressAsPointer() { } func (s *addressTestSuite) TestFormatValAddressWhenVerbIsDifferentFromSOrP() { - myAddr := types.ValAddress([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) + myAddr := types.ValAddress(addr20byte) exp := "000102030405060708090A0B0C0D0E0F10111213" spec := []string{"%v", "%#v", "%t", "%b", "%c", "%d", "%o", "%O", "%x", "%X", "%U", "%e", "%E", "%f", "%F", "%g", "%G"} for _, v := range spec { @@ -740,7 +729,7 @@ func (s *addressTestSuite) TestUnmarshalYAMLConsAddressWithEmptyString() { } func (s *addressTestSuite) TestFormatConsAddressAsString() { - consAddr := types.ConsAddress([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) + consAddr := types.ConsAddress(addr20byte) actual := fmt.Sprintf("%s", consAddr) hrp := types.GetConfig().GetBech32ConsensusAddrPrefix() @@ -750,7 +739,7 @@ func (s *addressTestSuite) TestFormatConsAddressAsString() { } func (s *addressTestSuite) TestFormatConsAddressAsPointer() { - consAddr := types.ConsAddress([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) + consAddr := types.ConsAddress(addr20byte) ptrAddr := &consAddr actual := fmt.Sprintf("%p", ptrAddr) @@ -759,7 +748,7 @@ func (s *addressTestSuite) TestFormatConsAddressAsPointer() { } func (s *addressTestSuite) TestFormatConsAddressWhenVerbIsDifferentFromSOrP() { - myAddr := types.ConsAddress([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) + myAddr := types.ConsAddress(addr20byte) exp := "000102030405060708090A0B0C0D0E0F10111213" spec := []string{"%v", "%#v", "%t", "%b", "%c", "%d", "%o", "%O", "%x", "%X", "%U", "%e", "%E", "%f", "%F", "%g", "%G"} for _, v := range spec { diff --git a/types/coin.go b/types/coin.go index 99e74ee65df9..702d8591ddb0 100644 --- a/types/coin.go +++ b/types/coin.go @@ -285,7 +285,7 @@ func (coins Coins) Validate() error { } } -// IsSorted returns true when coins are order ASC sorted with denoms. +// IsSorted returns true when coins are sorted in ASC order by denoms. func (coins Coins) IsSorted() bool { for i := 1; i < len(coins); i++ { if coins[i-1].Denom > coins[i].Denom { diff --git a/types/context.go b/types/context.go index 04b74c19d8ce..3f5778c638f1 100644 --- a/types/context.go +++ b/types/context.go @@ -45,11 +45,11 @@ type Context struct { chainID string // Deprecated: Use HeaderService for chainID and CometService for the rest txBytes []byte logger log.Logger - voteInfo []abci.VoteInfo // Deprecated: use Cometinfo.LastCommit.Votes instead, will be removed after 0.51 + voteInfo []abci.VoteInfo // Deprecated: use Cometinfo.LastCommit.Votes instead, will be removed after 0.52 gasMeter storetypes.GasMeter blockGasMeter storetypes.GasMeter - checkTx bool // Deprecated: use execMode instead, will be removed after 0.51 - recheckTx bool // if recheckTx == true, then checkTx must also be true // Deprecated: use execMode instead, will be removed after 0.51 + checkTx bool // Deprecated: use execMode instead, will be removed after 0.52 + recheckTx bool // if recheckTx == true, then checkTx must also be true // Deprecated: use execMode instead, will be removed after 0.52 sigverifyTx bool // when run simulation, because the private key corresponding to the account in the genesis.json randomly generated, we must skip the sigverify. execMode ExecMode minGasPrice DecCoins @@ -102,7 +102,7 @@ func (c Context) HeaderHash() []byte { return hash } -// Deprecated: getting consensus params from the context is deprecated and will be removed after 0.51 +// Deprecated: getting consensus params from the context is deprecated and will be removed after 0.52 // Querying the consensus module for the parameters is required in server/v2 func (c Context) ConsensusParams() cmtproto.ConsensusParams { return c.consParams @@ -138,7 +138,7 @@ func NewContext(ms storetypes.MultiStore, isCheckTx bool, logger log.Logger) Con kvGasConfig: storetypes.KVGasConfig(), transientKVGasConfig: storetypes.TransientGasConfig(), headerInfo: header.Info{ - Time: h.Time.UTC(), + Time: h.Time, }, } } @@ -161,7 +161,7 @@ func (c Context) WithBlockHeader(header cmtproto.Header) Context { header.Time = header.Time.UTC() c.header = header - // when calling withBlockheader on a new context chainID in the struct is empty + // when calling withBlockheader on a new context, chainID in the struct will be empty c.chainID = header.ChainID return c } @@ -208,7 +208,7 @@ func (c Context) WithLogger(logger log.Logger) Context { } // WithVoteInfos returns a Context with an updated consensus VoteInfo. -// Deprecated: use WithCometinfo() instead, will be removed after 0.51 +// Deprecated: use WithCometinfo() instead, will be removed after 0.52 func (c Context) WithVoteInfos(voteInfo []abci.VoteInfo) Context { c.voteInfo = voteInfo return c diff --git a/types/context_test.go b/types/context_test.go index 81edab5274ba..8975c048f01e 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -10,6 +10,7 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" + "cosmossdk.io/core/comet" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -231,3 +232,120 @@ func (s *contextTestSuite) TestUnwrapSDKContext() { sdkCtx2 = types.UnwrapSDKContext(ctx) s.Require().Equal(sdkCtx, sdkCtx2) } + +func (s *contextTestSuite) TestTryUnwrapSDKContext() { + sdkCtx := types.NewContext(nil, false, nil) + ctx := types.WrapSDKContext(sdkCtx) + unwrappedCtx, ok := types.TryUnwrapSDKContext(ctx) + s.Require().True(ok) + s.Require().Equal(sdkCtx, unwrappedCtx) + + // test case where context doesn't have sdk.Context + ctxWithoutSDK := context.Background() + unwrappedCtx, ok = types.TryUnwrapSDKContext(ctxWithoutSDK) + s.Require().False(ok) + s.Require().Equal(types.Context{}, unwrappedCtx) + + // test try unwrapping when we've used context.WithValue + ctx = context.WithValue(sdkCtx, dummyCtxKey{}, "bar") + unwrappedCtx, ok = types.TryUnwrapSDKContext(ctx) + s.Require().True(ok) + s.Require().Equal(sdkCtx, unwrappedCtx) +} + +func (s *contextTestSuite) TestToSDKEvidence() { + misbehaviors := []abci.Misbehavior{ + { + Type: abci.MisbehaviorType(1), + Height: 100, + Time: time.Now(), + TotalVotingPower: 10, + Validator: abci.Validator{ + Address: []byte("address1"), + Power: 5, + }, + }, + } + + expEvidences := []comet.Evidence{ + { + Type: comet.MisbehaviorType(1), + Height: 100, + Time: misbehaviors[0].Time, + TotalVotingPower: 10, + Validator: comet.Validator{ + Address: []byte("address1"), + Power: 5, + }, + }, + } + + // test ToSDKEvidence method + evidence := types.ToSDKEvidence(misbehaviors) + s.Require().Len(evidence, len(misbehaviors)) + s.Require().Equal(expEvidences, evidence) +} + +func (s *contextTestSuite) TestToSDKCommitInfo() { + commitInfo := abci.CommitInfo{ + Round: 1, + Votes: []abci.VoteInfo{ + { + Validator: abci.Validator{ + Address: []byte("address1"), + Power: 5, + }, + BlockIdFlag: cmtproto.BlockIDFlagCommit, + }, + }, + } + + expCommit := comet.CommitInfo{ + Round: 1, + Votes: []comet.VoteInfo{ + { + Validator: comet.Validator{ + Address: []byte("address1"), + Power: 5, + }, + BlockIDFlag: comet.BlockIDFlagCommit, + }, + }, + } + + // test ToSDKCommitInfo method + commit := types.ToSDKCommitInfo(commitInfo) + s.Require().Equal(expCommit, commit) +} + +func (s *contextTestSuite) TestToSDKExtendedCommitInfo() { + extendedCommitInfo := abci.ExtendedCommitInfo{ + Round: 1, + Votes: []abci.ExtendedVoteInfo{ + { + Validator: abci.Validator{ + Address: []byte("address1"), + Power: 5, + }, + BlockIdFlag: cmtproto.BlockIDFlagCommit, + }, + }, + } + + expCommitInfo := comet.CommitInfo{ + Round: 1, + Votes: []comet.VoteInfo{ + { + Validator: comet.Validator{ + Address: []byte("address1"), + Power: 5, + }, + BlockIDFlag: comet.BlockIDFlagCommit, + }, + }, + } + + // test ToSDKExtendedCommitInfo + commitInfo := types.ToSDKExtendedCommitInfo(extendedCommitInfo) + s.Require().Equal(expCommitInfo, commitInfo) +} diff --git a/x/auth/ante/ante.go b/x/auth/ante/ante.go index c81070242ed5..b052f943b624 100644 --- a/x/auth/ante/ante.go +++ b/x/auth/ante/ante.go @@ -4,6 +4,7 @@ import ( "cosmossdk.io/core/appmodule" "cosmossdk.io/core/gas" errorsmod "cosmossdk.io/errors" + "cosmossdk.io/x/auth/ante/unorderedtx" "cosmossdk.io/x/auth/types" txsigning "cosmossdk.io/x/tx/signing" @@ -23,6 +24,7 @@ type HandlerOptions struct { SignModeHandler *txsigning.HandlerMap SigGasConsumer func(meter gas.Meter, sig signing.SignatureV2, params types.Params) error TxFeeChecker TxFeeChecker + UnorderedTxManager *unorderedtx.Manager } // NewAnteHandler returns an AnteHandler that checks and increments sequence @@ -53,5 +55,9 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler, options.SigGasConsumer, options.AccountAbstractionKeeper), } + if options.UnorderedTxManager != nil { + anteDecorators = append(anteDecorators, NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, options.UnorderedTxManager, options.Environment, DefaultSha256Cost)) + } + return sdk.ChainAnteDecorators(anteDecorators...), nil } diff --git a/x/auth/tx/config/depinject.go b/x/auth/tx/config/depinject.go index bdf3879efbc0..09c49fd4e937 100644 --- a/x/auth/tx/config/depinject.go +++ b/x/auth/tx/config/depinject.go @@ -20,6 +20,7 @@ import ( "cosmossdk.io/depinject" "cosmossdk.io/depinject/appconfig" "cosmossdk.io/x/auth/ante" + "cosmossdk.io/x/auth/ante/unorderedtx" "cosmossdk.io/x/auth/posthandler" "cosmossdk.io/x/auth/tx" authtypes "cosmossdk.io/x/auth/types" @@ -58,6 +59,7 @@ type ModuleInputs struct { AccountAbstractionKeeper ante.AccountAbstractionKeeper `optional:"true"` CustomSignModeHandlers func() []txsigning.SignModeHandler `optional:"true"` CustomGetSigners []txsigning.CustomGetSigner `optional:"true"` + UnorderedTxManager *unorderedtx.Manager `optional:"true"` } type ModuleOutputs struct { @@ -162,12 +164,13 @@ func newAnteHandler(txConfig client.TxConfig, in ModuleInputs) (sdk.AnteHandler, anteHandler, err := ante.NewAnteHandler( ante.HandlerOptions{ - AccountKeeper: in.AccountKeeper, - BankKeeper: in.BankKeeper, - SignModeHandler: txConfig.SignModeHandler(), - FeegrantKeeper: in.FeeGrantKeeper, - SigGasConsumer: ante.DefaultSigVerificationGasConsumer, - Environment: in.Environment, + Environment: in.Environment, + AccountKeeper: in.AccountKeeper, + BankKeeper: in.BankKeeper, + SignModeHandler: txConfig.SignModeHandler(), + FeegrantKeeper: in.FeeGrantKeeper, + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + UnorderedTxManager: in.UnorderedTxManager, }, ) if err != nil { diff --git a/x/consensus/README.md b/x/consensus/README.md index 492d58ea9b7a..2af97a6a32db 100644 --- a/x/consensus/README.md +++ b/x/consensus/README.md @@ -31,7 +31,7 @@ it can be updated with governance or the address with authority. * Params: `0x05 | ProtocolBuffer(cometbft.ConsensusParams)` ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/381de6452693a9338371223c232fba0c42773a4b/proto/cosmos/consensus/v1/consensus.proto#L11-L18 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/consensus/proto/cosmos/consensus/v1/consensus.proto#L9-L15 ``` ## Keepers @@ -45,7 +45,7 @@ The consensus module provides methods to Set and Get consensus params. It is rec Update consensus params. ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/381de6452693a9338371223c232fba0c42773a4b/proto/cosmos/consensus/v1/tx.proto#L12-L47 +https://github.com/cosmos/cosmos-sdk/blob/release/v0.52.x/x/consensus/proto/cosmos/consensus/v1/tx.proto#L23-L44 ``` The message will fail under the following conditions: @@ -53,14 +53,6 @@ The message will fail under the following conditions: * The signer is not the set authority * Not all values are set -## Consensus Messages - -The consensus module has a consensus message that is used to set the consensus params when the chain initializes. It is similar to the `UpdateParams` message but it is only used once at the start of the chain. - -```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/381de6452693a9338371223c232fba0c42773a4b/proto/cosmos/consensus/v1/consensus.proto#L9-L24 -``` - ## Events The consensus module emits the following events: diff --git a/x/consensus/exported/exported.go b/x/consensus/exported/exported.go index c3bf5804f90c..91dfabb451e2 100644 --- a/x/consensus/exported/exported.go +++ b/x/consensus/exported/exported.go @@ -6,13 +6,10 @@ import ( cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" ) -type ( - - // ConsensusParamSetter defines the interface fulfilled by BaseApp's - // ParamStore which allows setting its appVersion field. - ConsensusParamSetter interface { - Get(ctx context.Context) (cmtproto.ConsensusParams, error) - Has(ctx context.Context) (bool, error) - Set(ctx context.Context, cp cmtproto.ConsensusParams) error - } -) +// ConsensusParamSetter defines the interface fulfilled by BaseApp's +// ParamStore which allows setting its appVersion field. +type ConsensusParamSetter interface { + Get(ctx context.Context) (cmtproto.ConsensusParams, error) + Has(ctx context.Context) (bool, error) + Set(ctx context.Context, cp cmtproto.ConsensusParams) error +} diff --git a/x/consensus/keeper/keeper.go b/x/consensus/keeper/keeper.go index 548bf61d9337..958d50072c1a 100644 --- a/x/consensus/keeper/keeper.go +++ b/x/consensus/keeper/keeper.go @@ -29,6 +29,7 @@ type Keeper struct { var _ exported.ConsensusParamSetter = Keeper{}.ParamsStore +// NewKeeper creates a new Keeper instance. func NewKeeper(cdc codec.BinaryCodec, env appmodule.Environment, authority string) Keeper { sb := collections.NewSchemaBuilder(env.KVStoreService) return Keeper{ @@ -38,6 +39,8 @@ func NewKeeper(cdc codec.BinaryCodec, env appmodule.Environment, authority strin } } +// GetAuthority returns the authority address for the consensus module. +// This address has the permission to update consensus parameters. func (k *Keeper) GetAuthority() string { return k.authority } @@ -45,14 +48,10 @@ func (k *Keeper) GetAuthority() string { // InitGenesis initializes the initial state of the module func (k *Keeper) InitGenesis(ctx context.Context) error { value, ok := ctx.Value(corecontext.InitInfoKey).(*types.MsgUpdateParams) - if !ok { + if !ok || value == nil { // no error for appv1 and appv2 return nil } - if value == nil { - // no error for appv1 - return nil - } consensusParams, err := value.ToProtoConsensusParams() if err != nil { @@ -85,6 +84,7 @@ func (k Keeper) Params(ctx context.Context, _ *types.QueryParamsRequest) (*types var _ types.MsgServer = Keeper{} +// UpdateParams updates the consensus parameters. func (k Keeper) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { if k.GetAuthority() != msg.Authority { return nil, fmt.Errorf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) @@ -116,17 +116,15 @@ func (k Keeper) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (* // paramCheck validates the consensus params func (k Keeper) paramCheck(ctx context.Context, consensusParams cmtproto.ConsensusParams) (*cmttypes.ConsensusParams, error) { - paramsProto, err := k.ParamsStore.Get(ctx) - var params cmttypes.ConsensusParams - if err != nil { - if errors.Is(err, collections.ErrNotFound) { - params = cmttypes.ConsensusParams{} - } else { - return nil, err - } - } else { + + paramsProto, err := k.ParamsStore.Get(ctx) + if err == nil { params = cmttypes.ConsensusParamsFromProto(paramsProto) + } else if errors.Is(err, collections.ErrNotFound) { + params = cmttypes.ConsensusParams{} + } else { + return nil, err } nextParams := params.Update(&consensusParams) diff --git a/x/consensus/keeper/keeper_test.go b/x/consensus/keeper/keeper_test.go index ed2bee648a70..1fb534674ba4 100644 --- a/x/consensus/keeper/keeper_test.go +++ b/x/consensus/keeper/keeper_test.go @@ -152,8 +152,6 @@ func (s *KeeperTestSuite) TestGRPCQueryConsensusParams() { } for _, tc := range testCases { - tc := tc - s.Run(tc.msg, func() { s.SetupTest(false) // reset @@ -189,8 +187,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { Validator: defaultConsensusParams.Validator, Evidence: defaultConsensusParams.Evidence, }, - expErr: false, - expErrMsg: "", }, { name: "invalid params", @@ -258,8 +254,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { VoteExtensionsEnableHeight: &gogotypes.Int64Value{Value: 300}, }, }, - expErr: false, - expErrMsg: "", }, { name: "valid Feature update - pbts", @@ -272,8 +266,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { PbtsEnableHeight: &gogotypes.Int64Value{Value: 150}, }, }, - expErr: false, - expErrMsg: "", }, { name: "valid Feature update - vote extensions + pbts", @@ -287,8 +279,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { PbtsEnableHeight: &gogotypes.Int64Value{Value: 110}, }, }, - expErr: false, - expErrMsg: "", }, { name: "valid noop Feature update - vote extensions + pbts (enabled feature)", @@ -303,8 +293,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { PbtsEnableHeight: &gogotypes.Int64Value{Value: 5}, }, }, - expErr: false, - expErrMsg: "", }, { name: "valid (deprecated) ABCI update", @@ -317,8 +305,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { VoteExtensionsEnableHeight: 90, }, }, - expErr: false, - expErrMsg: "", }, { name: "invalid Feature + (deprecated) ABCI vote extensions update", @@ -462,8 +448,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { Precision: getDuration(3 * time.Second), }, }, - expErr: false, - expErrMsg: "", }, { name: "valid Synchrony update - delay", @@ -476,8 +460,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { MessageDelay: getDuration(10 * time.Second), }, }, - expErr: false, - expErrMsg: "", }, { name: "valid Synchrony update - precision + delay", @@ -491,8 +473,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { MessageDelay: getDuration(11 * time.Second), }, }, - expErr: false, - expErrMsg: "", }, { name: "valid Synchrony update - 0 precision", @@ -505,8 +485,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { Precision: getDuration(0), }, }, - expErr: false, - expErrMsg: "", }, { name: "valid Synchrony update - 0 delay", @@ -519,8 +497,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { MessageDelay: getDuration(0), }, }, - expErr: false, - expErrMsg: "", }, { name: "invalid Synchrony update - 0 precision with PBTS set", @@ -559,7 +535,6 @@ func (s *KeeperTestSuite) TestUpdateParams() { } for _, tc := range testCases { - tc := tc s.Run(tc.name, func() { s.SetupTest(tc.enabledFeatures) _, err := s.consensusParamsKeeper.UpdateParams(s.ctx, tc.input) diff --git a/x/consensus/types/codec.go b/x/consensus/types/codec.go index 2573b41d4beb..e814aedef617 100644 --- a/x/consensus/types/codec.go +++ b/x/consensus/types/codec.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/msgservice" ) +// RegisterInterfaces registers the interfaces types with the interface registry. func RegisterInterfaces(registrar registry.InterfaceRegistrar) { registrar.RegisterImplementations( (*coretransaction.Msg)(nil), diff --git a/x/consensus/types/msgs.go b/x/consensus/types/msgs.go index 832658049d2c..f6556cc28dbb 100644 --- a/x/consensus/types/msgs.go +++ b/x/consensus/types/msgs.go @@ -8,6 +8,9 @@ import ( "github.com/cosmos/gogoproto/types" ) +// ToProtoConsensusParams converts MsgUpdateParams to cmtproto.ConsensusParams. +// It returns an error if any required parameters are missing or if there's a conflict +// between ABCI and Feature parameters. func (msg MsgUpdateParams) ToProtoConsensusParams() (cmtproto.ConsensusParams, error) { if msg.Evidence == nil || msg.Block == nil || msg.Validator == nil { return cmtproto.ConsensusParams{}, errors.New("all parameters must be present")