wip: trying to add antehandler to e2e test setup, jump to last commit for working TestAttestMachine w/o ante handler in place

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
This commit is contained in:
Lorenz Herzberger 2024-06-25 13:12:39 +02:00
parent a67ba84b70
commit 1a144ee5de
No known key found for this signature in database
GPG Key ID: FA5EE906EB55316A
11 changed files with 693 additions and 3 deletions

77
app/ante/ante.go Normal file
View File

@ -0,0 +1,77 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
ante "github.com/cosmos/cosmos-sdk/x/auth/ante"
// authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authsigning "cosmossdk.io/x/tx/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// HandlerOptions are the options required for constructing a default SDK AnteHandler.
type HandlerOptions struct {
AccountKeeper AccountKeeper
BankKeeper BankKeeper
ExtensionOptionChecker ante.ExtensionOptionChecker
FeegrantKeeper FeegrantKeeper
SignModeHandler authsigning.SignModeHandler
SigGasConsumer func(meter storetypes.GasMeter, sig signing.SignatureV2, params authtypes.Params) error
TxFeeChecker TxFeeChecker
MachineKeeper MachineKeeper
// DaoKeeper DaoKeeper
StakingKeeper StakingKeeper
}
// NewAnteHandler returns an AnteHandler that checks and increments sequence
// numbers, checks signatures & account numbers, and deducts fees from the first
// signer.
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
if options.AccountKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder")
}
if options.BankKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder")
}
if options.SignModeHandler == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
}
if options.MachineKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "machine keeper is required for ante builder")
}
// if options.DaoKeeper == nil {
// return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "dao keeper is required for ante builder")
// }
if options.StakingKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "staking keeper is required for ante builder")
}
anteDecorators := []sdk.AnteDecorator{
// NewSetUpContextDecorator(options.DaoKeeper), // outermost AnteDecorator. SetUpContext must be called first
NewSetUpContextDecorator(),
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
NewGasKVCostDecorator(options.StakingKeeper),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
ante.NewValidateMemoDecorator(options.AccountKeeper),
NewCheckValidatorDecorator(options.StakingKeeper),
NewCheckMachineDecorator(options.MachineKeeper),
// NewCheckMintAddressDecorator(options.DaoKeeper),
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
ante.NewValidateSigCountDecorator(options.AccountKeeper),
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
}
return sdk.ChainAnteDecorators(anteDecorators...), nil
}

View File

@ -0,0 +1,80 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
// assettypes "github.com/planetmint/planetmint-go/x/asset/types"
// daotypes "github.com/planetmint/planetmint-go/x/dao/types"
machinetypes "github.com/planetmint/planetmint-go/x/machine/types"
)
type CheckMachineDecorator struct {
mk MachineKeeper
}
func NewCheckMachineDecorator(mk MachineKeeper) CheckMachineDecorator {
return CheckMachineDecorator{
mk: mk,
}
}
func (cm CheckMachineDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (_ sdk.Context, err error) {
for _, msg := range tx.GetMsgs() {
switch sdk.MsgTypeURL(msg) {
// case "/planetmintgo.asset.MsgNotarizeAsset":
// notarizeMsg, ok := msg.(*assettypes.MsgNotarizeAsset)
// if ok {
// ctx, err = cm.handleNotarizeAsset(ctx, notarizeMsg)
// }
case "/planetmintgo.machine.MsgAttestMachine":
attestMsg, ok := msg.(*machinetypes.MsgAttestMachine)
if ok {
ctx, err = cm.handleAttestMachine(ctx, attestMsg)
}
// case "planetmintgo.dao.MsgReportPoPResult":
// popMsg, ok := msg.(*daotypes.MsgReportPopResult)
// if ok {
// ctx, err = cm.handlePopResult(ctx, popMsg)
// }
default:
continue
}
}
if err != nil {
return ctx, err
}
return next(ctx, tx, simulate)
}
// func (cm CheckMachineDecorator) handleNotarizeAsset(ctx sdk.Context, notarizeMsg *assettypes.MsgNotarizeAsset) (sdk.Context, error) {
// _, found := cm.mk.GetMachineIndexByAddress(ctx, notarizeMsg.GetCreator())
// if !found {
// return ctx, errorsmod.Wrapf(machinetypes.ErrMachineNotFound, ErrorAnteContext)
// }
// return ctx, nil
// }
func (cm CheckMachineDecorator) handleAttestMachine(ctx sdk.Context, attestMsg *machinetypes.MsgAttestMachine) (sdk.Context, error) {
if attestMsg.GetCreator() != attestMsg.Machine.GetAddress() {
return ctx, errorsmod.Wrapf(machinetypes.ErrMachineIsNotCreator, ErrorAnteContext)
}
_, activated, found := cm.mk.GetTrustAnchor(ctx, attestMsg.Machine.MachineId)
if !found {
return ctx, errorsmod.Wrapf(machinetypes.ErrTrustAnchorNotFound, ErrorAnteContext)
}
if activated {
return ctx, errorsmod.Wrapf(machinetypes.ErrTrustAnchorAlreadyInUse, ErrorAnteContext)
}
return ctx, nil
}
// func (cm CheckMachineDecorator) handlePopResult(ctx sdk.Context, popMsg *daotypes.MsgReportPopResult) (sdk.Context, error) {
// _, found := cm.mk.GetMachineIndexByAddress(ctx, popMsg.GetCreator())
// if !found {
// return ctx, errorsmod.Wrapf(machinetypes.ErrMachineNotFound, ErrorAnteContext)
// }
// return ctx, nil
// }

View File

@ -0,0 +1,38 @@
package ante
// import (
// errorsmod "cosmossdk.io/errors"
// sdk "github.com/cosmos/cosmos-sdk/types"
// daotypes "github.com/planetmint/planetmint-go/x/dao/types"
// )
// type CheckMintAddressDecorator struct {
// dk DaoKeeper
// }
// func NewCheckMintAddressDecorator(dk DaoKeeper) CheckMintAddressDecorator {
// return CheckMintAddressDecorator{
// dk: dk,
// }
// }
// func (cmad CheckMintAddressDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// for _, msg := range tx.GetMsgs() {
// if sdk.MsgTypeURL(msg) != "/planetmintgo.dao.MsgMintToken" {
// continue
// }
// mintMsg, ok := msg.(*daotypes.MsgMintToken)
// if !ok {
// continue
// }
// if mintMsg.Creator != cmad.dk.GetMintAddress(ctx) {
// return ctx, errorsmod.Wrapf(daotypes.ErrInvalidMintAddress, "expected: %s; got: %s", cmad.dk.GetMintAddress(ctx), mintMsg.Creator)
// }
// _, found := cmad.dk.GetMintRequestByHash(ctx, mintMsg.GetMintRequest().GetLiquidTxHash())
// if found {
// return ctx, errorsmod.Wrapf(daotypes.ErrAlreadyMinted, "liquid tx hash %s has already been minted", mintMsg.GetMintRequest().GetLiquidTxHash())
// }
// }
// return next(ctx, tx, simulate)
// }

View File

@ -0,0 +1,64 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
// "github.com/planetmint/planetmint-go/x/dao/types"
)
type CheckValidatorDecorator struct {
sk StakingKeeper
}
func NewCheckValidatorDecorator(sk StakingKeeper) CheckValidatorDecorator {
return CheckValidatorDecorator{sk: sk}
}
func (cv CheckValidatorDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (_ sdk.Context, err error) {
if simulate || ctx.BlockHeight() == 0 {
return next(ctx, tx, simulate)
}
for _, msg := range tx.GetMsgs() {
switch sdk.MsgTypeURL(msg) {
case "/planetmintgo.dao.MsgInitPop":
fallthrough
case "/planetmintgo.dao.MsgDistributionRequest":
fallthrough
case "/planetmintgo.dao.MsgDistributionResult":
fallthrough
case "/planetmintgo.dao.MsgReissueRDDLProposal":
fallthrough
case "/planetmintgo.dao.MsgReissueRDDLResult":
fallthrough
case "/planetmintgo.dao.MsgUpdateRedeemClaim":
fallthrough
case "/planetmintgo.machine.MsgNotarizeLiquidAsset":
fallthrough
case "/planetmintgo.machine.MsgRegisterTrustAnchor":
ctx, err = cv.handleMsg(ctx, msg)
default:
continue
}
}
if err != nil {
return ctx, err
}
return next(ctx, tx, simulate)
}
func (cv CheckValidatorDecorator) handleMsg(ctx sdk.Context, msg sdk.Msg) (_ sdk.Context, err error) {
signatureMsg, ok := msg.(sdk.Signature)
if !ok {
return ctx, errorsmod.Error{}
}
signer := signatureMsg.GetPubKey().Address()
_, found := cv.sk.GetValidator(ctx, sdk.ValAddress(signer))
if !found {
return ctx, errorsmod.Error{}
// return ctx, errorsmod.Wrapf(types.ErrRestrictedMsg, ErrorAnteContext)
}
return ctx, nil
}

View File

@ -0,0 +1,175 @@
package ante
import (
"bytes"
"fmt"
"slices"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// TxFeeChecker check if the provided fee is enough and returns the effective fee and tx priority,
// the effective fee should be deducted later, and the priority should be returned in abci response.
type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, error)
// DeductFeeDecorator deducts fees from the fee payer. The fee payer is the fee granter (if specified) or first signer of the tx.
// If the fee payer does not have the funds to pay for the fees, return an InsufficientFunds error.
// Call next AnteHandler if fees successfully deducted.
// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator
type DeductFeeDecorator struct {
accountKeeper AccountKeeper
bankKeeper authtypes.BankKeeper
feegrantKeeper FeegrantKeeper
txFeeChecker TxFeeChecker
}
func NewDeductFeeDecorator(ak AccountKeeper, bk authtypes.BankKeeper, fk FeegrantKeeper, tfc TxFeeChecker) DeductFeeDecorator {
if tfc == nil {
tfc = checkTxFee
}
return DeductFeeDecorator{
accountKeeper: ak,
bankKeeper: bk,
feegrantKeeper: fk,
txFeeChecker: tfc,
}
}
func checkTxFee(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, ErrorTxFeeTx)
}
feeCoins := feeTx.GetFee()
if !ctx.IsCheckTx() {
return feeCoins, nil
}
minGasPrices := ctx.MinGasPrices()
if minGasPrices.IsZero() {
return feeCoins, nil
}
feeDenoms := feeCoins.Denoms()
if len(feeDenoms) != 1 {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidCoins, "fee must be exactly one coin; got: %s", feeDenoms)
}
gasDenom := minGasPrices.GetDenomByIndex(0)
if slices.Contains(feeDenoms, gasDenom) {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidCoins, "received wrong fee denom; got: %s required: %s", feeDenoms[0], gasDenom)
}
requiredFees := sdk.Coins{sdk.NewInt64Coin(gasDenom, 1)}
if !feeCoins.IsAnyGTE(requiredFees) {
return nil, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
}
return feeCoins, nil
}
func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, ErrorTxFeeTx)
}
if !simulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 {
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas")
}
var (
err error
)
msgs := tx.GetMsgs()
if len(msgs) == 1 && sdk.MsgTypeURL(msgs[0]) == "/planetmintgo.machine.MsgAttestMachine" {
return next(ctx, tx, simulate)
}
fee := feeTx.GetFee()
if !simulate {
fee, err = dfd.txFeeChecker(ctx, tx)
if err != nil {
return ctx, err
}
}
if err := dfd.checkDeductFee(ctx, tx, fee); err != nil {
return ctx, err
}
return next(ctx, tx, simulate)
}
func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.Coins) error {
feeTx, ok := sdkTx.(sdk.FeeTx)
if !ok {
return errorsmod.Wrap(sdkerrors.ErrTxDecode, ErrorTxFeeTx)
}
if addr := dfd.accountKeeper.GetModuleAddress(authtypes.FeeCollectorName); addr == nil {
return fmt.Errorf("fee collector module account (%s) has not been set", authtypes.FeeCollectorName)
}
feePayer := feeTx.FeePayer()
feeGranter := feeTx.FeeGranter()
deductFeesFrom := feePayer
// if feegranter set deduct fee from feegranter account.
// this works with only when feegrant enabled.
if feeGranter != nil {
if dfd.feegrantKeeper == nil {
return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled")
} else if !bytes.Equal(feeGranter, feePayer) {
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, sdkTx.GetMsgs())
if err != nil {
return errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer)
}
}
deductFeesFrom = feeGranter
}
deductFeesFromAcc := dfd.accountKeeper.GetAccount(ctx, deductFeesFrom)
if deductFeesFromAcc == nil {
return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom)
}
// deduct the fees
if !fee.IsZero() {
err := dfd.deductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee)
if err != nil {
return err
}
}
events := sdk.Events{
sdk.NewEvent(
sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()),
sdk.NewAttribute(sdk.AttributeKeyFeePayer, sdk.AccAddress(deductFeesFrom).String()),
),
}
ctx.EventManager().EmitEvents(events)
return nil
}
// DeductFees deducts fees from the given account.
func (dfd DeductFeeDecorator) deductFees(bankKeeper authtypes.BankKeeper, ctx sdk.Context, acc authtypes.AccountI, fees sdk.Coins) error {
// check if exactly one fee is provided and is greater than 0
if !fees.IsValid() && len(fees) == 1 {
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees)
}
err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authtypes.FeeCollectorName, fees)
if err != nil {
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
}
return nil
}

6
app/ante/error.go Normal file
View File

@ -0,0 +1,6 @@
package ante
var (
ErrorAnteContext = "error during CheckTx or ReCheckTx"
ErrorTxFeeTx = "Tx must be a FeeTx"
)

View File

@ -0,0 +1,51 @@
package ante
import (
"github.com/planetmint/planetmint-go/x/machine/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
// daotypes "github.com/planetmint/planetmint-go/x/dao/types"
)
type MachineKeeper interface {
GetMachineIndexByPubKey(ctx sdk.Context, pubKey string) (val types.MachineIndex, found bool)
GetMachineIndexByAddress(ctx sdk.Context, address string) (val types.MachineIndex, found bool)
GetTrustAnchor(ctx sdk.Context, pubKey string) (val types.TrustAnchor, activated bool, found bool)
}
// AccountKeeper defines the contract needed for AccountKeeper related APIs.
// Interface provides support to use non-sdk AccountKeeper for AnteHandler's decorators.
type AccountKeeper interface {
GetParams(ctx sdk.Context) (params authtypes.Params)
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
SetAccount(ctx sdk.Context, acc authtypes.AccountI)
GetModuleAddress(moduleName string) sdk.AccAddress
}
// FeegrantKeeper defines the expected feegrant keeper.
type FeegrantKeeper interface {
UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error
}
type BankKeeper interface {
IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error
SendCoins(ctx sdk.Context, from, to sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
}
// type DaoKeeper interface {
// GetMintRequestByHash(ctx sdk.Context, hash string) (val daotypes.MintRequest, found bool)
// GetMintAddress(ctx sdk.Context) (mintAddress string)
// GetTxGasLimit(ctx sdk.Context) (txGasLimit uint64)
// GetClaimAddress(ctx sdk.Context) (claimAddress string)
// IsValidReissuanceProposal(ctx sdk.Context, msg *daotypes.MsgReissueRDDLProposal) (isValid bool)
// GetRedeemClaim(ctx sdk.Context, benficiary string, id uint64) (val daotypes.RedeemClaim, found bool)
// GetParams(ctx sdk.Context) (params daotypes.Params)
// }
type StakingKeeper interface {
GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, found bool)
}

View File

@ -0,0 +1,50 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
type GasKVCostDecorator struct {
sk StakingKeeper
}
func NewGasKVCostDecorator(sk StakingKeeper) GasKVCostDecorator {
return GasKVCostDecorator{sk: sk}
}
func (gc GasKVCostDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (_ sdk.Context, err error) {
if simulate || ctx.BlockHeight() == 0 {
return next(ctx, tx, simulate)
}
msgs := tx.GetMsgs()
signatureMsg, ok := msgs[0].(sdk.Signature)
if !ok {
return ctx, errorsmod.Error{}
}
signer := signatureMsg.GetPubKey().Address()
// signers := msgs[0].GetSigners()
// signer := signers[0]
valAddr := sdk.ValAddress(signer)
_, found := gc.sk.GetValidator(ctx, valAddr)
if !found {
return next(ctx, tx, simulate)
}
ctx = ctx.WithKVGasConfig(storetypes.GasConfig{
HasCost: 0,
DeleteCost: 0,
ReadCostFlat: 0,
ReadCostPerByte: 0,
WriteCostFlat: 0,
WriteCostPerByte: 0,
IterNextCostFlat: 0,
})
return next(ctx, tx, simulate)
}

View File

@ -0,0 +1,92 @@
package ante
import (
"fmt"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// GasTx defines a Tx with a GetGas() method which is needed to use SetUpContextDecorator
type GasTx interface {
sdk.Tx
GetGas() uint64
}
// SetUpContextDecorator 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.
// CONTRACT: Must be first decorator in the chain
// CONTRACT: Tx must implement GasTx interface
type SetUpContextDecorator struct {
// dk DaoKeeper
}
// func NewSetUpContextDecorator(dk DaoKeeper) SetUpContextDecorator {
func NewSetUpContextDecorator() SetUpContextDecorator {
return SetUpContextDecorator{
// dk: dk,
}
}
func (sud SetUpContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// 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, errorsmod.Wrapf(sdkerrors.ErrTxDecode, "Tx must be GasTx")
}
// gasLimit := sud.dk.GetTxGasLimit(ctx)
// if gasLimit == 0 {
// gasLimit = gasTx.GetGas()
// }
gasLimit := gasTx.GetGas()
newCtx = SetGasMeter(simulate, ctx, gasLimit)
if cp := ctx.ConsensusParams(); cp != nil && cp.Block != nil {
// If there exists a maximum block gas limit, we must ensure that the tx
// does not exceed it.
if cp.Block.MaxGas > 0 && gasTx.GetGas() > uint64(cp.Block.MaxGas) {
return newCtx, errorsmod.Wrapf(sdkerrors.ErrInvalidGasLimit, "tx gas limit %d exceeds block max gas %d", gasTx.GetGas(), cp.Block.MaxGas)
}
}
// Decorator will catch an OutOfGasPanic caused in the next antehandler
// AnteHandlers must have their own defer/recover in order for the BaseApp
// to know how much gas was used! This is because the GasMeter is created in
// the AnteHandler, but if it panics the context won't be set properly in
// runTx's recover call.
defer func() {
if r := recover(); r != nil {
switch rType := r.(type) {
case storetypes.ErrorOutOfGas:
log := fmt.Sprintf(
"out of gas in location: %v; gasWanted: %d, gasUsed: %d",
rType.Descriptor, gasTx.GetGas(), newCtx.GasMeter().GasConsumed())
err = errorsmod.Wrapf(sdkerrors.ErrOutOfGas, log)
default:
panic(r)
}
}
}()
return next(newCtx, tx, simulate)
}
// SetGasMeter returns a new context with a gas meter set from a given context.
func SetGasMeter(simulate bool, ctx sdk.Context, gasLimit uint64) sdk.Context {
// In various cases such as simulation and during the genesis block, we do not
// meter any gas utilization.
if simulate || ctx.BlockHeight() == 0 {
return ctx.WithGasMeter(storetypes.NewInfiniteGasMeter())
}
return ctx.WithGasMeter(storetypes.NewGasMeter(gasLimit))
}

View File

@ -242,7 +242,9 @@ var (
},
{
Name: "tx",
Config: appconfig.WrapAny(&txconfigv1.Config{}),
Config: appconfig.WrapAny(&txconfigv1.Config{
SkipAnteHandler: true,
}),
},
{
Name: genutiltypes.ModuleName,

View File

@ -3,17 +3,72 @@ package machine
import (
"testing"
"cosmossdk.io/depinject"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
"github.com/planetmint/planetmint-go/app"
"github.com/planetmint/planetmint-go/app/ante"
"github.com/stretchr/testify/suite"
pruningtypes "cosmossdk.io/store/pruning/types"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
)
var (
cfg network.Config
appConfig depinject.Config
)
func TestE2EMachineTestSuite(t *testing.T) {
cfg, err := network.DefaultConfigWithAppConfig(app.AppConfig())
appConfig = app.AppConfig()
var err error
cfg, err = network.DefaultConfigWithAppConfig(appConfig)
if err != nil {
panic("error while setting up application config")
}
cfg.NumValidators = 3
cfg.MinGasPrices = "0.000003stake"
cfg.AppConstructor = appConstructor
suite.Run(t, NewE2ETestSuite(cfg))
}
func appConstructor(val network.ValidatorI) servertypes.Application {
// we build a unique app instance for every validator here
var appBuilder *runtime.AppBuilder
if err := depinject.Inject(
depinject.Configs(
appConfig,
depinject.Supply(val.GetCtx().Logger),
),
&appBuilder); err != nil {
panic(err)
}
app := appBuilder.Build(
dbm.NewMemDB(),
nil,
baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)),
baseapp.SetMinGasPrices(val.GetAppConfig().MinGasPrices),
baseapp.SetChainID(cfg.ChainID),
)
testdata.RegisterQueryServer(app.GRPCQueryRouter(), testdata.QueryImpl{})
if err := app.Load(true); err != nil {
panic(err)
}
anteOpts := ante.HandlerOptions{}
anteHandler, err := ante.NewAnteHandler(anteOpts)
if err != nil {
panic(err)
}
app.SetAnteHandler(anteHandler)
return app
}