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

AnteDecorator #5006

Merged
merged 42 commits into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
1960993
start decorator changes
AdityaSripal Aug 28, 2019
12244c5
start replacing ante logic with decorators
AdityaSripal Aug 30, 2019
5a46ceb
Fix build errors
AdityaSripal Sep 5, 2019
bdcf294
Merge branch 'master' of https://github.com/cosmos/cosmos-sdk into ad…
AdityaSripal Sep 5, 2019
ac19f18
fix some tests
AdityaSripal Sep 6, 2019
9a0eac7
fix baseapp tests
AdityaSripal Sep 9, 2019
725f5cf
fix auth tests
AdityaSripal Sep 12, 2019
ff5f1f7
start individual decorator tests
AdityaSripal Sep 14, 2019
73e2739
add signature tests
AdityaSripal Sep 17, 2019
77bc7c6
complete sig tests
AdityaSripal Sep 17, 2019
baf5bfb
fix all test errors
AdityaSripal Sep 17, 2019
71e07ce
remove unnecessary &
AdityaSripal Sep 18, 2019
3b3a74f
fix linter errors
AdityaSripal Sep 18, 2019
6303bec
Merge branch 'master' of https://github.com/cosmos/cosmos-sdk into ad…
AdityaSripal Sep 18, 2019
e52e89d
interface all decorators except sigs
AdityaSripal Sep 18, 2019
ac8209d
check signer lenght in sigverify
AdityaSripal Sep 19, 2019
b93ca36
Apply suggestions from bez code review
AdityaSripal Sep 22, 2019
5825e81
complete bez suggestions
AdityaSripal Sep 29, 2019
441c050
fix merge conflicts
AdityaSripal Sep 29, 2019
2f22251
create sigTx interface
AdityaSripal Oct 1, 2019
975ad0e
linting
AdityaSripal Oct 1, 2019
c5ede73
finish linting except TODO
AdityaSripal Oct 1, 2019
9a5cb61
make auth tx interfaces extend sdk.Tx
AdityaSripal Oct 1, 2019
e7ec478
Merge branch 'master' into aditya/ante-decorator
alexanderbez Oct 2, 2019
634c1aa
test docs, replace FeeCoins with GetFee
AdityaSripal Oct 2, 2019
66144bf
Merge branch 'aditya/ante-decorator' of https://github.com/cosmos/cos…
AdityaSripal Oct 2, 2019
0c39cd9
Apply suggestions from fede code review
AdityaSripal Oct 2, 2019
29e85bf
address tim comments
AdityaSripal Oct 3, 2019
f1964cf
Merge branch 'aditya/ante-decorator' of https://github.com/cosmos/cos…
AdityaSripal Oct 3, 2019
b6d9166
Merge branch 'master' into aditya/ante-decorator
fedekunze Oct 8, 2019
0fd1234
add order comments
AdityaSripal Oct 8, 2019
aad9673
Add Schwarzenegger art
AdityaSripal Oct 8, 2019
5ce99da
add assertions that StdTx implements all necessary decorator interfaces
AdityaSripal Oct 8, 2019
bd79e58
Merge branch 'aditya/ante-decorator' of https://github.com/cosmos/cos…
AdityaSripal Oct 8, 2019
2f54876
documentation and CHANGELOG
AdityaSripal Oct 9, 2019
a4ef3ec
Run goimports
alexanderbez Oct 9, 2019
33cc17a
Update ChainAnteDecorators godoc
alexanderbez Oct 10, 2019
882fac5
Changelog entries cleanup
alexanderbez Oct 10, 2019
163da7f
Changelog entries cleanup
alexanderbez Oct 10, 2019
492cf0d
Merge branch 'master' into aditya/ante-decorator
alexanderbez Oct 10, 2019
1b1a779
Fix formatter
alexanderbez Oct 10, 2019
440a05c
Merge branch 'master' into aditya/ante-decorator
alexanderbez Oct 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
interface all decorators except sigs
  • Loading branch information
AdityaSripal committed Sep 18, 2019
commit e52e89db65000921fcaafddf1d84a53d4d35b6c7
14 changes: 10 additions & 4 deletions x/auth/ante/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
errs "github.com/cosmos/cosmos-sdk/types/errors"
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

"github.com/cosmos/cosmos-sdk/x/auth/keeper"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)

// ValidateBasicDecorator will call tx.ValidateBasic and return any non-nil error
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -25,8 +24,15 @@ func (vbd ValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat
return next(ctx, tx, simulate)
}

// Tx must have GetMemo() method to use ValidateMemoDecorator
type TxWithMemo interface {
sdk.Tx
GetMemo() string
}

// ValidateMemoDecorator will validate memo given the parameters passed in
// If memo is too large decorator returns with error, otherwise call next AnteHandler
// CONTRACT: Tx must implement TxWithMemo interface
type ValidateMemoDecorator struct {
ak keeper.AccountKeeper
}
Expand All @@ -38,14 +44,14 @@ func NewValidateMemoDecorator(ak keeper.AccountKeeper) ValidateMemoDecorator {
}

func (vmd ValidateMemoDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
stdTx, ok := tx.(types.StdTx)
memoTx, ok := tx.(TxWithMemo)
if !ok {
return ctx, errs.Wrap(errs.ErrTxDecode, "Tx must be a StdTx")
return ctx, errs.Wrap(errs.ErrTxDecode, "Tx must have a GetMemo method")
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
}

params := vmd.ak.GetParams(ctx)

memoLength := len(stdTx.GetMemo())
memoLength := len(memoTx.GetMemo())
if uint64(memoLength) > params.MaxMemoCharacters {
return ctx, err.Wrapf(err.ErrMemoTooLarge,
"maximum number of characters is %d but received %d characters",
Expand Down
42 changes: 24 additions & 18 deletions x/auth/ante/fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,32 @@ import (
errs "github.com/cosmos/cosmos-sdk/types/errors"
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
)

// Tx must implement FeeTx interface to use the FeeDecorators
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
type FeeTx interface {
sdk.Tx
Gas() uint64
FeeCoins() sdk.Coins
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FeeCoins() sdk.Coins
Fee() sdk.Coins

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StdTx already has a field called Fee so we can't implement a method called Fee on it.

I could change the name of that field, but i tried to minimize breaking changes. Also open to changing it from FeeCoins to something else, FeeAmount for example?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohhh, maybe GetFee?

FeePayer() sdk.AccAddress
}

// MempoolFeeDecorator will check if the transaction's fee is at least as large the local validator's minimum gasFee (defined in validator config).
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
// If fee is too low, decorator returns error and tx is rejected from mempool.
// Note this only applies when ctx.CheckTx = true
// If fee is high enough or not CheckTx, then call next AnteHandler
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
type MempoolFeeDecorator struct{}

func NewMempoolFeeDecorator() MempoolFeeDecorator {
return MempoolFeeDecorator{}
}

func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
stdTx, ok := tx.(types.StdTx)
feeTx, ok := tx.(FeeTx)
if !ok {
return ctx, errs.Wrap(errs.ErrTxDecode, "Tx must be a StdTx")
return ctx, errs.Wrap(errs.ErrTxDecode, "Tx must be a FeeTx")
}
stdFee := stdTx.Fee
feeCoins := feeTx.FeeCoins()
gas := feeTx.Gas()

// Ensure that the provided fees meet a minimum threshold for the validator,
// if this is a CheckTx. This is only for local mempool purposes, and thus
Expand All @@ -38,13 +48,15 @@ func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b

// Determine the required fees by multiplying each required minimum gas
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit).
glDec := sdk.NewDec(int64(stdFee.Gas))
glDec := sdk.NewDec(int64(gas))
for i, gp := range minGasPrices {
fee := gp.Amount.Mul(glDec)
requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
}

return ctx, errs.Wrapf(errs.ErrInsufficientFee, "insufficient fees; got: %q required: %q", stdFee.Amount, requiredFees)
if !feeCoins.IsAnyGTE(requiredFees) {
return ctx, errs.Wrapf(errs.ErrInsufficientFee, "insufficient fees; got: %q required: %q", feeCoins, requiredFees)
}
}
}

Expand All @@ -54,6 +66,7 @@ func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b
// DeductFeeDecorator deducts fees from the first signer of the tx
// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error
// Call next AnteHandler if fees successfully deducted
// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator
type DeductFeeDecorator struct {
ak keeper.AccountKeeper
supplyKeeper types.SupplyKeeper
Expand All @@ -67,28 +80,21 @@ func NewDeductFeeDecorator(ak keeper.AccountKeeper, sk types.SupplyKeeper) Deduc
}

func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
stdTx, ok := tx.(types.StdTx)
feeTx, ok := tx.(FeeTx)
if !ok {
return ctx, errs.Wrap(errs.ErrTxDecode, "Tx must be a StdTx")
return ctx, errs.Wrap(errs.ErrTxDecode, "Tx must be a FeeTx")
}

if addr := dfd.supplyKeeper.GetModuleAddress(types.FeeCollectorName); addr == nil {
panic(fmt.Sprintf("%s module account has not been set", types.FeeCollectorName))
}

// stdSigs contains the sequence number, account number, and signatures.
// When simulating, this would just be a 0-length slice.
signerAddrs := stdTx.GetSigners()

// fetch first signer, who's going to pay the fees
feePayer, err := GetSignerAcc(ctx, dfd.ak, signerAddrs[0])
if err != nil {
return ctx, err
}
feePayer := feeTx.FeePayer()
feePayerAcc := dfd.ak.GetAccount(ctx, feePayer)

// deduct the fees
if !stdTx.Fee.Amount.IsZero() {
err = DeductFees(dfd.supplyKeeper, ctx, feePayer, stdTx.Fee.Amount)
if !feeTx.FeeCoins().IsZero() {
err = DeductFees(dfd.supplyKeeper, ctx, feePayerAcc, feeTx.FeeCoins())
if err != nil {
return ctx, err
}
Expand Down
19 changes: 12 additions & 7 deletions x/auth/ante/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,35 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
errs "github.com/cosmos/cosmos-sdk/types/errors"
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
"github.com/cosmos/cosmos-sdk/x/auth/types"
)

// Tx with a Gas() method is needed to use SetupDecorator
type GasTx interface {
Gas() uint64
}

// SetUpDecorator sets the GasMeter in the Context and wraps the next AnteHandler with a defer clause
// to recover from any downstream OutOfGas panics in the AnteHandler chain to return an error with information
// on gas provided and gas used.
// Should be the first decorator in the chain
// CONTRACT: Must be first decorator in the chain
// CONTRACT: Tx must implement GasTx interface
type SetUpDecorator struct{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto on providing a slightly better and more descriptive name...


func NewSetupDecorator() SetUpDecorator {
return SetUpDecorator{}
}

func (sud SetUpDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// all transactions must be of type auth.StdTx
stdTx, ok := tx.(types.StdTx)
// all transactions must implement GasTx
gasTx, ok := tx.(GasTx)
if !ok {
// Set a gas meter with limit 0 as to prevent an infinite gas meter attack
// during runTx.
newCtx = SetGasMeter(simulate, ctx, 0)
return newCtx, errs.Wrap(errs.ErrTxDecode, "Tx must be auth.StdTx")
return newCtx, errs.Wrap(errs.ErrTxDecode, "Tx must be GasTx")
}

newCtx = SetGasMeter(simulate, ctx, stdTx.Fee.Gas)
newCtx = SetGasMeter(simulate, ctx, gasTx.Gas())

// Decorator will catch an OutOfGasPanic caused in the next antehandler
// AnteHandlers must have their own defer/recover in order for the BaseApp
Expand All @@ -41,7 +46,7 @@ func (sud SetUpDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool,
case sdk.ErrorOutOfGas:
log := fmt.Sprintf(
"out of gas in location: %v; gasWanted: %d, gasUsed: %d",
rType.Descriptor, stdTx.Fee.Gas, newCtx.GasMeter().GasConsumed())
rType.Descriptor, gasTx.Gas(), newCtx.GasMeter().GasConsumed())

err = errs.Wrap(errs.ErrOutOfGas, log)
// TODO: figure out how to return Context, error so that baseapp can recover gasWanted/gasUsed
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
12 changes: 12 additions & 0 deletions x/auth/types/stdtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ func (tx StdTx) GetMemo() string { return tx.Memo }
// .Empty().
func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures }

// Gas returns the Gas in StdFee
func (tx StdTx) Gas() uint64 { return tx.Fee.Gas }

// FeeCoins returns the FeeAmount in StdFee
func (tx StdTx) FeeCoins() sdk.Coins { return tx.Fee.Amount }

// FeePayer returns the address that is responsible for paying fee
// StdTx returns the first signer as the fee payer
func (tx StdTx) FeePayer() sdk.AccAddress {
return tx.GetMsgs()[0].GetSigners()[0]
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
}

//__________________________________________________________

// StdFee includes the amount of coins paid in fees and the maximum
Expand Down