From 3a0df2791ff3f1f171a85c4e7a70b81c9e419308 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 26 Aug 2024 23:48:08 +0200 Subject: [PATCH 1/3] feat(x/auth/tx): extend app module + docs --- x/auth/module.go | 2 +- x/auth/tx/README.md | 10 +++++++ x/auth/tx/config/depinject.go | 35 ++++++----------------- x/auth/tx/config/module.go | 53 +++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 x/auth/tx/config/module.go diff --git a/x/auth/module.go b/x/auth/module.go index 3a8aed7b696a..49a358a1bf24 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -51,7 +51,7 @@ type AppModule struct { // IsAppModule implements the appmodule.AppModule interface. func (am AppModule) IsAppModule() {} -// NewAppModule creates a new AppModule object +// NewAppModule creates a new AppModule object. func NewAppModule( cdc codec.Codec, accountKeeper keeper.AccountKeeper, diff --git a/x/auth/tx/README.md b/x/auth/tx/README.md index 4fba6e3f7c3d..981f375dc0de 100644 --- a/x/auth/tx/README.md +++ b/x/auth/tx/README.md @@ -17,12 +17,15 @@ This document specifies the `x/auth/tx` package of the Cosmos SDK. This package represents the Cosmos SDK implementation of the `client.TxConfig`, `client.TxBuilder`, `client.TxEncoder` and `client.TxDecoder` interfaces. +It contains as well a depinject module and app module the registration of ante/post handler via `runtime` and tx validator via `runtime/v2`. + ## Contents * [Transactions](#transactions) * [`TxConfig`](#txconfig) * [`TxBuilder`](#txbuilder) * [`TxEncoder`/ `TxDecoder`](#txencoder-txdecoder) +* [Depinject \& App Module](#depinject--app-module) * [Client](#client) * [CLI](#cli) * [gRPC](#grpc) @@ -57,6 +60,13 @@ A `client.TxBuilder` can be accessed with `TxConfig.NewTxBuilder()`. More information about `TxEncoder` and `TxDecoder` can be found [here](https://docs.cosmos.network/main/core/encoding#transaction-encoding). +## Depinject & App Module + +The `x/auth/tx/config` contains a depinject module and app module. +The depinject module is there to setup ante/post handlers on an runtime app (via baseapp options) and the tx validator on the runtime/v2 app (via app module). It as well outputs the `TxConfig` and `TxConfigOptions` for the app. + +The app module is purely there for registering tx validators, due to the design of tx validators (tx validator belong to modules). + ## Client ### CLI diff --git a/x/auth/tx/config/depinject.go b/x/auth/tx/config/depinject.go index bdf3879efbc0..19ad53262324 100644 --- a/x/auth/tx/config/depinject.go +++ b/x/auth/tx/config/depinject.go @@ -15,8 +15,6 @@ import ( txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1" "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" - appmodulev2 "cosmossdk.io/core/appmodule/v2" - "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" "cosmossdk.io/depinject/appconfig" "cosmossdk.io/x/auth/ante" @@ -58,15 +56,16 @@ type ModuleInputs struct { AccountAbstractionKeeper ante.AccountAbstractionKeeper `optional:"true"` CustomSignModeHandlers func() []txsigning.SignModeHandler `optional:"true"` CustomGetSigners []txsigning.CustomGetSigner `optional:"true"` + ExtraTxValidators []TxValidator `optional:"true"` } type ModuleOutputs struct { depinject.Out + Module appmodule.AppModule // This is only useful for chains using server/v2. It setup tx validators that don't belong to other modules. + BaseAppOption runtime.BaseAppOption // This is only useful for chains using baseapp. Server/v2 chains use TxValidator. TxConfig client.TxConfig TxConfigOptions tx.ConfigOptions - BaseAppOption runtime.BaseAppOption // This is only useful for chains using baseapp. Server/v2 chains use TxValidator. - Module appmodule.AppModule } func ProvideProtoRegistry() txsigning.ProtoFileResolver { @@ -150,9 +149,13 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { ante.DefaultSigVerificationGasConsumer, in.AccountAbstractionKeeper, ) - appModule := AppModule{svd} - return ModuleOutputs{TxConfig: txConfig, TxConfigOptions: txConfigOptions, BaseAppOption: baseAppOption, Module: appModule} + return ModuleOutputs{ + Module: NewAppModule(svd, in.ExtraTxValidators...), + TxConfig: txConfig, + TxConfigOptions: txConfigOptions, + BaseAppOption: baseAppOption, + } } func newAnteHandler(txConfig client.TxConfig, in ModuleInputs) (sdk.AnteHandler, error) { @@ -232,23 +235,3 @@ func metadataExists(err error) error { return err } - -var ( - _ appmodulev2.AppModule = AppModule{} - _ appmodulev2.HasTxValidator[transaction.Tx] = AppModule{} -) - -type AppModule struct { - sigVerification ante.SigVerificationDecorator -} - -// TxValidator implements appmodule.HasTxValidator. -func (a AppModule) TxValidator(ctx context.Context, tx transaction.Tx) error { - return a.sigVerification.ValidateTx(ctx, tx) -} - -// IsAppModule implements appmodule.AppModule. -func (a AppModule) IsAppModule() {} - -// IsOnePerModuleType implements appmodule.AppModule. -func (a AppModule) IsOnePerModuleType() {} diff --git a/x/auth/tx/config/module.go b/x/auth/tx/config/module.go new file mode 100644 index 000000000000..d944b5a125eb --- /dev/null +++ b/x/auth/tx/config/module.go @@ -0,0 +1,53 @@ +package tx + +import ( + "context" + + appmodulev2 "cosmossdk.io/core/appmodule/v2" + "cosmossdk.io/core/transaction" + "cosmossdk.io/x/auth/ante" +) + +// TxValidator is appmodulev2.HasTxValidator without the AppModule requirement. +type TxValidator = func(context.Context, transaction.Tx) error + +var ( + _ appmodulev2.AppModule = AppModule{} + _ appmodulev2.HasTxValidator[transaction.Tx] = AppModule{} +) + +type AppModule struct { + sigVerification ante.SigVerificationDecorator + // txValidators contains tx validator that can be injected into the module via depinject. + // tx validators should be module based, but it can happen that you do not want to create a new module + // and simply depinject-it. + txValidators []TxValidator +} + +// NewAppModule creates a new AppModule object. +func NewAppModule( + sigVerification ante.SigVerificationDecorator, + txValidators ...TxValidator, +) AppModule { + return AppModule{ + sigVerification: sigVerification, + txValidators: txValidators, + } +} + +// IsAppModule implements appmodule.AppModule. +func (a AppModule) IsAppModule() {} + +// IsOnePerModuleType implements appmodule.AppModule. +func (a AppModule) IsOnePerModuleType() {} + +// TxValidator implements appmodule.HasTxValidator. +func (a AppModule) TxValidator(ctx context.Context, tx transaction.Tx) error { + for _, validator := range a.txValidators { + if err := validator(ctx, tx); err != nil { + return err + } + } + + return a.sigVerification.ValidateTx(ctx, tx) +} From 0a0bfc528bacc37654705814708d29ea3b2cce86 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 26 Aug 2024 23:52:41 +0200 Subject: [PATCH 2/3] doc update --- x/auth/tx/config/module.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/auth/tx/config/module.go b/x/auth/tx/config/module.go index d944b5a125eb..b62baa68fab8 100644 --- a/x/auth/tx/config/module.go +++ b/x/auth/tx/config/module.go @@ -16,6 +16,10 @@ var ( _ appmodulev2.HasTxValidator[transaction.Tx] = AppModule{} ) +// AppModule is a module that only implements tx validators. +// The goal of this module is to allow extensible registration of tx validators provided by chains without requiring a new modules. +// Additionally, it registers tx validators that do not really have a place in other modules. +// This module is only useful for chains using server/v2. Ante/Post handlers are setup via baseapp options in depinject. type AppModule struct { sigVerification ante.SigVerificationDecorator // txValidators contains tx validator that can be injected into the module via depinject. From 02cce3982c70259faa733c2e2b9899cbfe918ba5 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 27 Aug 2024 19:46:56 +0200 Subject: [PATCH 3/3] use correct interface --- x/auth/tx/config/depinject.go | 21 +++++++++++---------- x/auth/tx/config/module.go | 11 ++++------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/x/auth/tx/config/depinject.go b/x/auth/tx/config/depinject.go index c6947c1a34cb..bb573f044f6a 100644 --- a/x/auth/tx/config/depinject.go +++ b/x/auth/tx/config/depinject.go @@ -14,7 +14,8 @@ import ( bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1" "cosmossdk.io/core/address" - "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/appmodule/v2" + "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" "cosmossdk.io/depinject/appconfig" "cosmossdk.io/x/auth/ante" @@ -50,15 +51,15 @@ type ModuleInputs struct { ProtoFileResolver txsigning.ProtoFileResolver Environment appmodule.Environment // BankKeeper is the expected bank keeper to be passed to AnteHandlers - BankKeeper authtypes.BankKeeper `optional:"true"` - MetadataBankKeeper BankKeeper `optional:"true"` - AccountKeeper ante.AccountKeeper `optional:"true"` - FeeGrantKeeper ante.FeegrantKeeper `optional:"true"` - AccountAbstractionKeeper ante.AccountAbstractionKeeper `optional:"true"` - CustomSignModeHandlers func() []txsigning.SignModeHandler `optional:"true"` - CustomGetSigners []txsigning.CustomGetSigner `optional:"true"` - UnorderedTxManager *unorderedtx.Manager `optional:"true"` - ExtraTxValidators []TxValidator `optional:"true"` + BankKeeper authtypes.BankKeeper `optional:"true"` + MetadataBankKeeper BankKeeper `optional:"true"` + AccountKeeper ante.AccountKeeper `optional:"true"` + FeeGrantKeeper ante.FeegrantKeeper `optional:"true"` + AccountAbstractionKeeper ante.AccountAbstractionKeeper `optional:"true"` + CustomSignModeHandlers func() []txsigning.SignModeHandler `optional:"true"` + CustomGetSigners []txsigning.CustomGetSigner `optional:"true"` + UnorderedTxManager *unorderedtx.Manager `optional:"true"` + ExtraTxValidators []appmodule.TxValidator[transaction.Tx] `optional:"true"` } type ModuleOutputs struct { diff --git a/x/auth/tx/config/module.go b/x/auth/tx/config/module.go index b62baa68fab8..6e94e0e8cfac 100644 --- a/x/auth/tx/config/module.go +++ b/x/auth/tx/config/module.go @@ -8,9 +8,6 @@ import ( "cosmossdk.io/x/auth/ante" ) -// TxValidator is appmodulev2.HasTxValidator without the AppModule requirement. -type TxValidator = func(context.Context, transaction.Tx) error - var ( _ appmodulev2.AppModule = AppModule{} _ appmodulev2.HasTxValidator[transaction.Tx] = AppModule{} @@ -25,13 +22,13 @@ type AppModule struct { // txValidators contains tx validator that can be injected into the module via depinject. // tx validators should be module based, but it can happen that you do not want to create a new module // and simply depinject-it. - txValidators []TxValidator + txValidators []appmodulev2.TxValidator[transaction.Tx] } // NewAppModule creates a new AppModule object. func NewAppModule( sigVerification ante.SigVerificationDecorator, - txValidators ...TxValidator, + txValidators ...appmodulev2.TxValidator[transaction.Tx], ) AppModule { return AppModule{ sigVerification: sigVerification, @@ -47,8 +44,8 @@ func (a AppModule) IsOnePerModuleType() {} // TxValidator implements appmodule.HasTxValidator. func (a AppModule) TxValidator(ctx context.Context, tx transaction.Tx) error { - for _, validator := range a.txValidators { - if err := validator(ctx, tx); err != nil { + for _, txValidator := range a.txValidators { + if err := txValidator.ValidateTx(ctx, tx); err != nil { return err } }