Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(x/auth/tx): Implement UnorderedTxManager tx validator #21426

Merged
merged 13 commits into from
Aug 29, 2024
28 changes: 18 additions & 10 deletions x/auth/ante/unordered.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ante

import (
"bytes"
"context"
"crypto/sha256"
"encoding/binary"
"sync"
Expand Down Expand Up @@ -69,29 +70,36 @@ 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 {
hieuvubk marked this conversation as resolved.
Show resolved Hide resolved
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(),
Expand All @@ -100,24 +108,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()), tx.(sdk.Tx))
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
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",
)
Expand All @@ -127,7 +135,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.
Expand Down
4 changes: 4 additions & 0 deletions x/auth/tx/config/depinject.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ func ProvideModule(in ModuleInputs) ModuleOutputs {
in.AccountAbstractionKeeper,
)

if in.UnorderedTxManager != nil {
in.ExtraTxValidators = append(in.ExtraTxValidators, ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, in.UnorderedTxManager, in.Environment, ante.DefaultSha256Cost))
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
}

return ModuleOutputs{
Module: NewAppModule(svd, in.ExtraTxValidators...),
TxConfig: txConfig,
Expand Down
Loading