github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/ante/basic.go (about) 1 package ante 2 3 import ( 4 errorsmod "cosmossdk.io/errors" 5 storetypes "cosmossdk.io/store/types" 6 7 "github.com/cosmos/cosmos-sdk/codec/legacy" 8 "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" 9 cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 10 sdk "github.com/cosmos/cosmos-sdk/types" 11 sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" 12 "github.com/cosmos/cosmos-sdk/types/tx/signing" 13 "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" 14 authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" 15 ) 16 17 // ValidateBasicDecorator will call tx.ValidateBasic and return any non-nil error. 18 // If ValidateBasic passes, decorator calls next AnteHandler in chain. Note, 19 // ValidateBasicDecorator decorator will not get executed on ReCheckTx since it 20 // is not dependent on application state. 21 type ValidateBasicDecorator struct{} 22 23 func NewValidateBasicDecorator() ValidateBasicDecorator { 24 return ValidateBasicDecorator{} 25 } 26 27 func (vbd ValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { 28 // no need to validate basic on recheck tx, call next antehandler 29 if ctx.IsReCheckTx() { 30 return next(ctx, tx, simulate) 31 } 32 33 if validateBasic, ok := tx.(sdk.HasValidateBasic); ok { 34 if err := validateBasic.ValidateBasic(); err != nil { 35 return ctx, err 36 } 37 } 38 39 return next(ctx, tx, simulate) 40 } 41 42 // ValidateMemoDecorator will validate memo given the parameters passed in 43 // If memo is too large decorator returns with error, otherwise call next AnteHandler 44 // CONTRACT: Tx must implement TxWithMemo interface 45 type ValidateMemoDecorator struct { 46 ak AccountKeeper 47 } 48 49 func NewValidateMemoDecorator(ak AccountKeeper) ValidateMemoDecorator { 50 return ValidateMemoDecorator{ 51 ak: ak, 52 } 53 } 54 55 func (vmd ValidateMemoDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { 56 memoTx, ok := tx.(sdk.TxWithMemo) 57 if !ok { 58 return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type") 59 } 60 61 memoLength := len(memoTx.GetMemo()) 62 if memoLength > 0 { 63 params := vmd.ak.GetParams(ctx) 64 if uint64(memoLength) > params.MaxMemoCharacters { 65 return ctx, errorsmod.Wrapf(sdkerrors.ErrMemoTooLarge, 66 "maximum number of characters is %d but received %d characters", 67 params.MaxMemoCharacters, memoLength, 68 ) 69 } 70 } 71 72 return next(ctx, tx, simulate) 73 } 74 75 // ConsumeTxSizeGasDecorator will take in parameters and consume gas proportional 76 // to the size of tx before calling next AnteHandler. Note, the gas costs will be 77 // slightly over estimated due to the fact that any given signing account may need 78 // to be retrieved from state. 79 // 80 // CONTRACT: If simulate=true, then signatures must either be completely filled 81 // in or empty. 82 // CONTRACT: To use this decorator, signatures of transaction must be represented 83 // as legacytx.StdSignature otherwise simulate mode will incorrectly estimate gas cost. 84 type ConsumeTxSizeGasDecorator struct { 85 ak AccountKeeper 86 } 87 88 func NewConsumeGasForTxSizeDecorator(ak AccountKeeper) ConsumeTxSizeGasDecorator { 89 return ConsumeTxSizeGasDecorator{ 90 ak: ak, 91 } 92 } 93 94 func (cgts ConsumeTxSizeGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { 95 sigTx, ok := tx.(authsigning.SigVerifiableTx) 96 if !ok { 97 return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid tx type") 98 } 99 params := cgts.ak.GetParams(ctx) 100 101 ctx.GasMeter().ConsumeGas(params.TxSizeCostPerByte*storetypes.Gas(len(ctx.TxBytes())), "txSize") 102 103 // simulate gas cost for signatures in simulate mode 104 if simulate { 105 // in simulate mode, each element should be a nil signature 106 sigs, err := sigTx.GetSignaturesV2() 107 if err != nil { 108 return ctx, err 109 } 110 n := len(sigs) 111 112 signers, err := sigTx.GetSigners() 113 if err != nil { 114 return sdk.Context{}, err 115 } 116 117 for i, signer := range signers { 118 // if signature is already filled in, no need to simulate gas cost 119 if i < n && !isIncompleteSignature(sigs[i].Data) { 120 continue 121 } 122 123 var pubkey cryptotypes.PubKey 124 125 acc := cgts.ak.GetAccount(ctx, signer) 126 127 // use placeholder simSecp256k1Pubkey if sig is nil 128 if acc == nil || acc.GetPubKey() == nil { 129 pubkey = simSecp256k1Pubkey 130 } else { 131 pubkey = acc.GetPubKey() 132 } 133 134 // use stdsignature to mock the size of a full signature 135 simSig := legacytx.StdSignature{ //nolint:staticcheck // SA1019: legacytx.StdSignature is deprecated 136 Signature: simSecp256k1Sig[:], 137 PubKey: pubkey, 138 } 139 140 sigBz := legacy.Cdc.MustMarshal(simSig) 141 cost := storetypes.Gas(len(sigBz) + 6) 142 143 // If the pubkey is a multi-signature pubkey, then we estimate for the maximum 144 // number of signers. 145 if _, ok := pubkey.(*multisig.LegacyAminoPubKey); ok { 146 cost *= params.TxSigLimit 147 } 148 149 ctx.GasMeter().ConsumeGas(params.TxSizeCostPerByte*cost, "txSize") 150 } 151 } 152 153 return next(ctx, tx, simulate) 154 } 155 156 // isIncompleteSignature tests whether SignatureData is fully filled in for simulation purposes 157 func isIncompleteSignature(data signing.SignatureData) bool { 158 if data == nil { 159 return true 160 } 161 162 switch data := data.(type) { 163 case *signing.SingleSignatureData: 164 return len(data.Signature) == 0 165 case *signing.MultiSignatureData: 166 if len(data.Signatures) == 0 { 167 return true 168 } 169 for _, s := range data.Signatures { 170 if isIncompleteSignature(s) { 171 return true 172 } 173 } 174 } 175 176 return false 177 } 178 179 type ( 180 // TxTimeoutHeightDecorator defines an AnteHandler decorator that checks for a 181 // tx height timeout. 182 TxTimeoutHeightDecorator struct{} 183 184 // TxWithTimeoutHeight defines the interface a tx must implement in order for 185 // TxHeightTimeoutDecorator to process the tx. 186 TxWithTimeoutHeight interface { 187 sdk.Tx 188 189 GetTimeoutHeight() uint64 190 } 191 ) 192 193 // TxTimeoutHeightDecorator defines an AnteHandler decorator that checks for a 194 // tx height timeout. 195 func NewTxTimeoutHeightDecorator() TxTimeoutHeightDecorator { 196 return TxTimeoutHeightDecorator{} 197 } 198 199 // AnteHandle implements an AnteHandler decorator for the TxHeightTimeoutDecorator 200 // type where the current block height is checked against the tx's height timeout. 201 // If a height timeout is provided (non-zero) and is less than the current block 202 // height, then an error is returned. 203 func (txh TxTimeoutHeightDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { 204 timeoutTx, ok := tx.(TxWithTimeoutHeight) 205 if !ok { 206 return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "expected tx to implement TxWithTimeoutHeight") 207 } 208 209 timeoutHeight := timeoutTx.GetTimeoutHeight() 210 if timeoutHeight > 0 && uint64(ctx.BlockHeight()) > timeoutHeight { 211 return ctx, errorsmod.Wrapf( 212 sdkerrors.ErrTxTimeoutHeight, "block height: %d, timeout height: %d", ctx.BlockHeight(), timeoutHeight, 213 ) 214 } 215 216 return next(ctx, tx, simulate) 217 }