@@ -12,20 +12,18 @@ import (
1212)
1313
1414const (
15- deductFeesCost sdk.Gas = 10
16- memoCostPerByte sdk.Gas = 1
17- ed25519VerifyCost = 59
18- secp256k1VerifyCost = 100
19- maxMemoCharacters = 100
20- feeDeductionGasFactor = 0.001
15+ deductFeesCost sdk.Gas = 10
16+ memoCostPerByte sdk.Gas = 1
17+ ed25519VerifyCost = 59
18+ secp256k1VerifyCost = 100
19+ maxMemoCharacters = 100
20+ gasPrice = 0.001
2121)
2222
2323// NewAnteHandler returns an AnteHandler that checks
2424// and increments sequence numbers, checks signatures & account numbers,
2525// and deducts fees from the first signer.
26- // nolint: gocyclo
2726func NewAnteHandler (am AccountMapper , fck FeeCollectionKeeper ) sdk.AnteHandler {
28-
2927 return func (
3028 ctx sdk.Context , tx sdk.Tx , simulate bool ,
3129 ) (newCtx sdk.Context , res sdk.Result , abort bool ) {
@@ -36,13 +34,17 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
3634 return ctx , sdk .ErrInternal ("tx must be StdTx" ).Result (), true
3735 }
3836
39- // set the gas meter
40- if simulate {
41- newCtx = ctx .WithGasMeter (sdk .NewInfiniteGasMeter ())
42- } else {
43- newCtx = ctx .WithGasMeter (sdk .NewGasMeter (stdTx .Fee .Gas ))
37+ // Ensure that the provided fees meet a minimum threshold for the validator, if this is a CheckTx.
38+ // This is for mempool purposes, and thus is only ran on check tx.
39+ if ctx .IsCheckTx () && ! simulate {
40+ res := ensureSufficientMempoolFees (ctx , stdTx )
41+ if ! res .IsOK () {
42+ return newCtx , res , true
43+ }
4444 }
4545
46+ newCtx = setGasMeter (simulate , ctx , stdTx )
47+
4648 // AnteHandlers must have their own defer/recover in order
4749 // for the BaseApp to know how much gas was used!
4850 // This is because the GasMeter is created in the AnteHandler,
@@ -66,52 +68,37 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
6668 if err != nil {
6769 return newCtx , err .Result (), true
6870 }
71+ // charge gas for the memo
72+ newCtx .GasMeter ().ConsumeGas (memoCostPerByte * sdk .Gas (len (stdTx .GetMemo ())), "memo" )
6973
70- sigs := stdTx .GetSignatures () // When simulating, this would just be a 0-length slice.
74+ // stdSigs contains the sequence number, account number, and signatures
75+ stdSigs := stdTx .GetSignatures () // When simulating, this would just be a 0-length slice.
7176 signerAddrs := stdTx .GetSigners ()
72- msgs := tx .GetMsgs ()
7377
74- // charge gas for the memo
75- newCtx .GasMeter (). ConsumeGas ( memoCostPerByte * sdk . Gas ( len ( stdTx . GetMemo ())), "memo" )
78+ // create the list of all sign bytes
79+ signBytesList := getSignBytesList ( newCtx .ChainID (), stdTx , stdSigs )
7680
7781 // Get the sign bytes (requires all account & sequence numbers and the fee)
78- sequences := make ([]int64 , len (sigs ))
79- accNums := make ([]int64 , len (sigs ))
80- for i := 0 ; i < len (sigs ); i ++ {
81- sequences [i ] = sigs [i ].Sequence
82- accNums [i ] = sigs [i ].AccountNumber
83- }
84- fee := stdTx .Fee
85-
8682 // Check sig and nonce and collect signer accounts.
8783 var signerAccs = make ([]Account , len (signerAddrs ))
88- for i := 0 ; i < len (sigs ); i ++ {
89- signerAddr , sig := signerAddrs [i ], sigs [i ]
84+ for i := 0 ; i < len (stdSigs ); i ++ {
85+ signerAddr , sig := signerAddrs [i ], stdSigs [i ]
9086
9187 // check signature, return account with incremented nonce
92- signBytes := StdSignBytes (newCtx .ChainID (), accNums [i ], sequences [i ], fee , msgs , stdTx .GetMemo ())
93- signerAcc , res := processSig (newCtx , am , signerAddr , sig , signBytes , simulate )
88+ signerAcc , res := processSig (newCtx , am , signerAddr , sig , signBytesList [i ], simulate )
9489 if ! res .IsOK () {
9590 return newCtx , res , true
9691 }
9792
98- requiredFees := adjustFeesByGas (ctx .MinimumFees (), fee .Gas )
99- // fees must be greater than the minimum set by the validator adjusted by gas
100- if ctx .IsCheckTx () && ! simulate && ! ctx .MinimumFees ().IsZero () && fee .Amount .IsLT (requiredFees ) {
101- // validators reject any tx from the mempool with less than the minimum fee per gas * gas factor
102- return newCtx , sdk .ErrInsufficientFee (fmt .Sprintf (
103- "insufficient fee, got: %q required: %q" , fee .Amount , requiredFees )).Result (), true
104- }
105-
10693 // first sig pays the fees
107- // Can this function be moved outside of the loop?
108- if i == 0 && ! fee .Amount .IsZero () {
94+ // TODO: move outside of the loop
95+ if i == 0 && ! stdTx . Fee .Amount .IsZero () {
10996 newCtx .GasMeter ().ConsumeGas (deductFeesCost , "deductFees" )
110- signerAcc , res = deductFees (signerAcc , fee )
97+ signerAcc , res = deductFees (signerAcc , stdTx . Fee )
11198 if ! res .IsOK () {
11299 return newCtx , res , true
113100 }
114- fck .addCollectedFees (newCtx , fee .Amount )
101+ fck .addCollectedFees (newCtx , stdTx . Fee .Amount )
115102 }
116103
117104 // Save the account.
@@ -153,6 +140,7 @@ func validateBasic(tx StdTx) (err sdk.Error) {
153140
154141// verify the signature and increment the sequence.
155142// if the account doesn't have a pubkey, set it.
143+ // TODO: Change this function to already take in the account
156144func processSig (
157145 ctx sdk.Context , am AccountMapper ,
158146 addr sdk.AccAddress , sig StdSignature , signBytes []byte , simulate bool ) (
@@ -245,8 +233,9 @@ func consumeSignatureVerificationGas(meter sdk.GasMeter, pubkey crypto.PubKey) {
245233}
246234
247235func adjustFeesByGas (fees sdk.Coins , gas int64 ) sdk.Coins {
248- gasCost := int64 (float64 (gas ) * feeDeductionGasFactor )
236+ gasCost := int64 (float64 (gas ) * gasPrice )
249237 gasFees := make (sdk.Coins , len (fees ))
238+ // TODO: Make this not price all coins in the same way
250239 for i := 0 ; i < len (fees ); i ++ {
251240 gasFees [i ] = sdk .NewInt64Coin (fees [i ].Denom , gasCost )
252241 }
@@ -273,5 +262,38 @@ func deductFees(acc Account, fee StdFee) (Account, sdk.Result) {
273262 return acc , sdk.Result {}
274263}
275264
265+ func ensureSufficientMempoolFees (ctx sdk.Context , stdTx StdTx ) sdk.Result {
266+ // currently we use a very primitive gas pricing model with a constant gasPrice.
267+ // adjustFeesByGas handles calculating the amount of fees required based on the provided gas.
268+ // TODO: Make the gasPrice not a constant, and account for tx size.
269+ requiredFees := adjustFeesByGas (ctx .MinimumFees (), stdTx .Fee .Gas )
270+
271+ if ! ctx .MinimumFees ().IsZero () && stdTx .Fee .Amount .IsLT (requiredFees ) {
272+ // validators reject any tx from the mempool with less than the minimum fee per gas * gas factor
273+ return sdk .ErrInsufficientFee (fmt .Sprintf (
274+ "insufficient fee, got: %q required: %q" , stdTx .Fee .Amount , requiredFees )).Result ()
275+ }
276+ return sdk.Result {}
277+ }
278+
279+ func setGasMeter (simulate bool , ctx sdk.Context , stdTx StdTx ) sdk.Context {
280+ // set the gas meter
281+ if simulate {
282+ return ctx .WithGasMeter (sdk .NewInfiniteGasMeter ())
283+ }
284+ return ctx .WithGasMeter (sdk .NewGasMeter (stdTx .Fee .Gas ))
285+ }
286+
287+ func getSignBytesList (chainID string , stdTx StdTx , stdSigs []StdSignature ) (
288+ signatureBytesList [][]byte ) {
289+ signatureBytesList = make ([][]byte , len (stdSigs ))
290+ for i := 0 ; i < len (stdSigs ); i ++ {
291+ signatureBytesList [i ] = StdSignBytes (chainID ,
292+ stdSigs [i ].AccountNumber , stdSigs [i ].Sequence ,
293+ stdTx .Fee , stdTx .Msgs , stdTx .Memo )
294+ }
295+ return
296+ }
297+
276298// BurnFeeHandler burns all fees (decreasing total supply)
277299func BurnFeeHandler (_ sdk.Context , _ sdk.Tx , _ sdk.Coins ) {}
0 commit comments