From 243b819c5eb8593455515bca0e084ae167721f58 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 10:17:42 +0000 Subject: [PATCH] refactor(x/auth/tx): Implement `UnorderedTxManager` tx validator (backport #21426) (#21456) Co-authored-by: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> --- x/auth/ante/unordered.go | 34 ++++++++++++++++++++++++---------- x/auth/tx/config/depinject.go | 11 ++++++++--- x/auth/tx/config/module.go | 19 ++++++++++++++----- 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/x/auth/ante/unordered.go b/x/auth/ante/unordered.go index b97774ef6118..5cae688156b9 100644 --- a/x/auth/ante/unordered.go +++ b/x/auth/ante/unordered.go @@ -2,8 +2,10 @@ package ante import ( "bytes" + "context" "crypto/sha256" "encoding/binary" + "fmt" "sync" "time" @@ -69,29 +71,41 @@ func (d *UnorderedTxDecorator) AnteHandle( _ bool, next sdk.AnteHandler, ) (sdk.Context, error) { + if err := d.ValidateTx(ctx, tx); err != nil { + return ctx, err + } + return next(ctx, tx, false) +} + +func (d *UnorderedTxDecorator) ValidateTx(ctx context.Context, tx transaction.Tx) error { + sdkTx, ok := tx.(sdk.Tx) + if !ok { + return fmt.Errorf("invalid tx type %T, expected sdk.Tx", tx) + } + unorderedTx, ok := tx.(sdk.TxWithUnordered) if !ok || !unorderedTx.GetUnordered() { // If the transaction does not implement unordered capabilities or has the // unordered value as false, we bypass. - return next(ctx, tx, false) + return nil } headerInfo := d.env.HeaderService.HeaderInfo(ctx) timeoutTimestamp := unorderedTx.GetTimeoutTimeStamp() if timeoutTimestamp.IsZero() || timeoutTimestamp.Unix() == 0 { - return ctx, errorsmod.Wrap( + return errorsmod.Wrap( sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_timestamp set", ) } if timeoutTimestamp.Before(headerInfo.Time) { - return ctx, errorsmod.Wrap( + return errorsmod.Wrap( sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_timestamp that has already passed", ) } if timeoutTimestamp.After(headerInfo.Time.Add(d.maxTimeoutDuration)) { - return ctx, errorsmod.Wrapf( + return errorsmod.Wrapf( sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %s", d.maxTimeoutDuration.String(), @@ -100,24 +114,24 @@ func (d *UnorderedTxDecorator) AnteHandle( // consume gas in all exec modes to avoid gas estimation discrepancies if err := d.env.GasService.GasMeter(ctx).Consume(d.sha256Cost, "consume gas for calculating tx hash"); err != nil { - return ctx, errorsmod.Wrap(sdkerrors.ErrOutOfGas, "out of gas") + return errorsmod.Wrap(sdkerrors.ErrOutOfGas, "out of gas") } // Avoid checking for duplicates and creating the identifier in simulation mode // This is done to avoid sha256 computation in simulation mode if d.env.TransactionService.ExecMode(ctx) == transaction.ExecModeSimulate { - return next(ctx, tx, false) + return nil } // calculate the tx hash - txHash, err := TxIdentifier(uint64(timeoutTimestamp.Unix()), tx) + txHash, err := TxIdentifier(uint64(timeoutTimestamp.Unix()), sdkTx) if err != nil { - return ctx, err + return err } // check for duplicates if d.txManager.Contains(txHash) { - return ctx, errorsmod.Wrap( + return errorsmod.Wrap( sdkerrors.ErrInvalidRequest, "tx %X is duplicated", ) @@ -127,7 +141,7 @@ func (d *UnorderedTxDecorator) AnteHandle( d.txManager.Add(txHash, timeoutTimestamp) } - return next(ctx, tx, false) + return nil } // TxIdentifier returns a unique identifier for a transaction that is intended to be unordered. diff --git a/x/auth/tx/config/depinject.go b/x/auth/tx/config/depinject.go index e4e43ac3d80f..d371bc713e47 100644 --- a/x/auth/tx/config/depinject.go +++ b/x/auth/tx/config/depinject.go @@ -121,8 +121,9 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { ) var ( - minGasPrices sdk.DecCoins - feeTxValidator *ante.DeductFeeDecorator + minGasPrices sdk.DecCoins + feeTxValidator *ante.DeductFeeDecorator + unorderedTxValidator *ante.UnorderedTxDecorator ) if in.AccountKeeper != nil && in.BankKeeper != nil && in.Viper != nil { minGasPricesStr := in.Viper.GetString(flagMinGasPricesV2) @@ -135,8 +136,12 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { feeTxValidator.SetMinGasPrices(minGasPrices) // set min gas price in deduct fee decorator } + if in.UnorderedTxManager != nil { + unorderedTxValidator = ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, in.UnorderedTxManager, in.Environment, ante.DefaultSha256Cost) + } + return ModuleOutputs{ - Module: NewAppModule(svd, feeTxValidator, in.ExtraTxValidators...), + Module: NewAppModule(svd, feeTxValidator, unorderedTxValidator, in.ExtraTxValidators...), BaseAppOption: newBaseAppOption(txConfig, in), TxConfig: txConfig, TxConfigOptions: txConfigOptions, diff --git a/x/auth/tx/config/module.go b/x/auth/tx/config/module.go index f4a1207fa7b1..1d36738e57cf 100644 --- a/x/auth/tx/config/module.go +++ b/x/auth/tx/config/module.go @@ -18,8 +18,9 @@ var ( // 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 - feeTxValidator *ante.DeductFeeDecorator + sigVerification ante.SigVerificationDecorator + feeTxValidator *ante.DeductFeeDecorator + unorderTxValidator *ante.UnorderedTxDecorator // 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. @@ -30,12 +31,14 @@ type AppModule struct { func NewAppModule( sigVerification ante.SigVerificationDecorator, feeTxValidator *ante.DeductFeeDecorator, + unorderTxValidator *ante.UnorderedTxDecorator, txValidators ...appmodulev2.TxValidator[transaction.Tx], ) AppModule { return AppModule{ - sigVerification: sigVerification, - feeTxValidator: feeTxValidator, - txValidators: txValidators, + sigVerification: sigVerification, + feeTxValidator: feeTxValidator, + unorderTxValidator: unorderTxValidator, + txValidators: txValidators, } } @@ -57,5 +60,11 @@ func (a AppModule) TxValidator(ctx context.Context, tx transaction.Tx) error { return err } + if a.unorderTxValidator != nil { + if err := a.unorderTxValidator.ValidateTx(ctx, tx); err != nil { + return err + } + } + return a.sigVerification.ValidateTx(ctx, tx) }