@@ -12,19 +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+ memoCostPerByte sdk.Gas = 1
16+ ed25519VerifyCost = 59
17+ secp256k1VerifyCost = 100
18+ maxMemoCharacters = 100
19+ // how much gas = 1 atom
20+ gasPerUnitCost = 1000
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.
2626func NewAnteHandler (am AccountMapper , fck FeeCollectionKeeper ) sdk.AnteHandler {
27-
2827 return func (
2928 ctx sdk.Context , tx sdk.Tx , simulate bool ,
3029 ) (newCtx sdk.Context , res sdk.Result , abort bool ) {
@@ -35,13 +34,17 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
3534 return ctx , sdk .ErrInternal ("tx must be StdTx" ).Result (), true
3635 }
3736
38- // set the gas meter
39- if simulate {
40- newCtx = ctx .WithGasMeter (sdk .NewInfiniteGasMeter ())
41- } else {
42- 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 only for local 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+ }
4344 }
4445
46+ newCtx = setGasMeter (simulate , ctx , stdTx )
47+
4548 // AnteHandlers must have their own defer/recover in order
4649 // for the BaseApp to know how much gas was used!
4750 // This is because the GasMeter is created in the AnteHandler,
@@ -65,64 +68,49 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
6568 if err != nil {
6669 return newCtx , err .Result (), true
6770 }
68-
69- sigs := stdTx .GetSignatures () // When simulating, this would just be a 0-length slice.
70- signerAddrs := stdTx .GetSigners ()
71- msgs := tx .GetMsgs ()
72-
7371 // charge gas for the memo
7472 newCtx .GasMeter ().ConsumeGas (memoCostPerByte * sdk .Gas (len (stdTx .GetMemo ())), "memo" )
7573
76- // Get the sign bytes (requires all account & sequence numbers and the fee)
77- sequences := make ([]int64 , len (sigs ))
78- accNums := make ([]int64 , len (sigs ))
79- for i := 0 ; i < len (sigs ); i ++ {
80- sequences [i ] = sigs [i ].Sequence
81- accNums [i ] = sigs [i ].AccountNumber
82- }
83- fee := stdTx .Fee
74+ // stdSigs contains the sequence number, account number, and signatures
75+ stdSigs := stdTx .GetSignatures () // When simulating, this would just be a 0-length slice.
76+ signerAddrs := stdTx .GetSigners ()
8477
85- // Check sig and nonce and collect signer accounts.
86- var signerAccs = make ([]Account , len (signerAddrs ))
87- for i := 0 ; i < len (sigs ); i ++ {
88- signerAddr , sig := signerAddrs [i ], sigs [i ]
78+ // create the list of all sign bytes
79+ signBytesList := getSignBytesList (newCtx .ChainID (), stdTx , stdSigs )
80+ signerAccs , res := getSignerAccs (newCtx , am , signerAddrs )
81+ if ! res .IsOK () {
82+ return newCtx , res , true
83+ }
84+ res = validateAccNumAndSequence (signerAccs , stdSigs )
85+ if ! res .IsOK () {
86+ return newCtx , res , true
87+ }
8988
90- // check signature, return account with incremented nonce
91- signBytes := StdSignBytes (newCtx .ChainID (), accNums [i ], sequences [i ], fee , msgs , stdTx .GetMemo ())
92- signerAcc , res := processSig (newCtx , am , signerAddr , sig , signBytes , simulate )
89+ // first sig pays the fees
90+ if ! stdTx .Fee .Amount .IsZero () {
91+ // signerAccs[0] is the fee payer
92+ signerAccs [0 ], res = deductFees (signerAccs [0 ], stdTx .Fee )
9393 if ! res .IsOK () {
9494 return newCtx , res , true
9595 }
96+ fck .addCollectedFees (newCtx , stdTx .Fee .Amount )
97+ }
9698
97- requiredFees := adjustFeesByGas (ctx .MinimumFees (), fee .Gas )
98- // fees must be greater than the minimum set by the validator adjusted by gas
99- if ctx .IsCheckTx () && ! simulate && ! ctx .MinimumFees ().IsZero () && fee .Amount .IsLT (requiredFees ) {
100- // validators reject any tx from the mempool with less than the minimum fee per gas * gas factor
101- return newCtx , sdk .ErrInsufficientFee (fmt .Sprintf (
102- "insufficient fee, got: %q required: %q" , fee .Amount , requiredFees )).Result (), true
103- }
104-
105- // first sig pays the fees
106- // Can this function be moved outside of the loop?
107- if i == 0 && ! fee .Amount .IsZero () {
108- newCtx .GasMeter ().ConsumeGas (deductFeesCost , "deductFees" )
109- signerAcc , res = deductFees (signerAcc , fee )
110- if ! res .IsOK () {
111- return newCtx , res , true
112- }
113- fck .addCollectedFees (newCtx , fee .Amount )
99+ for i := 0 ; i < len (stdSigs ); i ++ {
100+ // check signature, return account with incremented nonce
101+ signerAccs [i ], res = processSig (newCtx , signerAccs [i ], stdSigs [i ], signBytesList [i ], simulate )
102+ if ! res .IsOK () {
103+ return newCtx , res , true
114104 }
115105
116106 // Save the account.
117- am .SetAccount (newCtx , signerAcc )
118- signerAccs [i ] = signerAcc
107+ am .SetAccount (newCtx , signerAccs [i ])
119108 }
120109
121110 // cache the signer accounts in the context
122111 newCtx = WithSigners (newCtx , signerAccs )
123112
124113 // TODO: tx tags (?)
125-
126114 return newCtx , sdk.Result {GasWanted : stdTx .Fee .Gas }, false // continue...
127115 }
128116}
@@ -150,42 +138,45 @@ func validateBasic(tx StdTx) (err sdk.Error) {
150138 return nil
151139}
152140
153- // verify the signature and increment the sequence.
154- // if the account doesn't have a pubkey, set it.
155- func processSig (
156- ctx sdk.Context , am AccountMapper ,
157- addr sdk.AccAddress , sig StdSignature , signBytes []byte , simulate bool ) (
158- acc Account , res sdk.Result ) {
159- // Get the account.
160- acc = am .GetAccount (ctx , addr )
161- if acc == nil {
162- return nil , sdk .ErrUnknownAddress (addr .String ()).Result ()
141+ func getSignerAccs (ctx sdk.Context , am AccountMapper , addrs []sdk.AccAddress ) (accs []Account , res sdk.Result ) {
142+ accs = make ([]Account , len (addrs ))
143+ for i := 0 ; i < len (accs ); i ++ {
144+ accs [i ] = am .GetAccount (ctx , addrs [i ])
145+ if accs [i ] == nil {
146+ return nil , sdk .ErrUnknownAddress (addrs [i ].String ()).Result ()
147+ }
163148 }
149+ return
150+ }
164151
165- accnum := acc .GetAccountNumber ()
166- seq := acc .GetSequence ()
152+ func validateAccNumAndSequence (accs []Account , sigs []StdSignature ) sdk.Result {
153+ for i := 0 ; i < len (accs ); i ++ {
154+ accnum := accs [i ].GetAccountNumber ()
155+ seq := accs [i ].GetSequence ()
156+ // Check account number.
157+ if accnum != sigs [i ].AccountNumber {
158+ return sdk .ErrInvalidSequence (
159+ fmt .Sprintf ("Invalid account number. Got %d, expected %d" , sigs [i ].AccountNumber , accnum )).Result ()
160+ }
167161
168- // Check account number.
169- if accnum != sig .AccountNumber {
170- return nil , sdk .ErrInvalidSequence (
171- fmt .Sprintf ("Invalid account number. Got %d, expected %d" , sig .AccountNumber , accnum )).Result ()
162+ // Check sequence number.
163+ if seq != sigs [i ].Sequence {
164+ return sdk .ErrInvalidSequence (
165+ fmt .Sprintf ("Invalid sequence. Got %d, expected %d" , sigs [i ].Sequence , seq )).Result ()
166+ }
172167 }
168+ return sdk.Result {}
169+ }
173170
174- // Check sequence number.
175- if seq != sig .Sequence {
176- return nil , sdk .ErrInvalidSequence (
177- fmt .Sprintf ("Invalid sequence. Got %d, expected %d" , sig .Sequence , seq )).Result ()
178- }
179- err := acc .SetSequence (seq + 1 )
180- if err != nil {
181- // Handle w/ #870
182- panic (err )
183- }
171+ // verify the signature and increment the sequence.
172+ // if the account doesn't have a pubkey, set it.
173+ func processSig (ctx sdk.Context ,
174+ acc Account , sig StdSignature , signBytes []byte , simulate bool ) (updatedAcc Account , res sdk.Result ) {
184175 pubKey , res := processPubKey (acc , sig , simulate )
185176 if ! res .IsOK () {
186177 return nil , res
187178 }
188- err = acc .SetPubKey (pubKey )
179+ err : = acc .SetPubKey (pubKey )
189180 if err != nil {
190181 return nil , sdk .ErrInternal ("setting PubKey on signer's account" ).Result ()
191182 }
@@ -195,7 +186,14 @@ func processSig(
195186 return nil , sdk .ErrUnauthorized ("signature verification failed" ).Result ()
196187 }
197188
198- return
189+ // increment the sequence number
190+ err = acc .SetSequence (acc .GetSequence () + 1 )
191+ if err != nil {
192+ // Handle w/ #870
193+ panic (err )
194+ }
195+
196+ return acc , res
199197}
200198
201199var dummySecp256k1Pubkey secp256k1.PubKeySecp256k1
@@ -244,8 +242,9 @@ func consumeSignatureVerificationGas(meter sdk.GasMeter, pubkey crypto.PubKey) {
244242}
245243
246244func adjustFeesByGas (fees sdk.Coins , gas int64 ) sdk.Coins {
247- gasCost := int64 ( float64 ( gas ) * feeDeductionGasFactor )
245+ gasCost := gas / gasPerUnitCost
248246 gasFees := make (sdk.Coins , len (fees ))
247+ // TODO: Make this not price all coins in the same way
249248 for i := 0 ; i < len (fees ); i ++ {
250249 gasFees [i ] = sdk .NewInt64Coin (fees [i ].Denom , gasCost )
251250 }
@@ -272,5 +271,37 @@ func deductFees(acc Account, fee StdFee) (Account, sdk.Result) {
272271 return acc , sdk.Result {}
273272}
274273
274+ func ensureSufficientMempoolFees (ctx sdk.Context , stdTx StdTx ) sdk.Result {
275+ // currently we use a very primitive gas pricing model with a constant gasPrice.
276+ // adjustFeesByGas handles calculating the amount of fees required based on the provided gas.
277+ // TODO: Make the gasPrice not a constant, and account for tx size.
278+ requiredFees := adjustFeesByGas (ctx .MinimumFees (), stdTx .Fee .Gas )
279+
280+ if ! ctx .MinimumFees ().IsZero () && stdTx .Fee .Amount .IsLT (requiredFees ) {
281+ // validators reject any tx from the mempool with less than the minimum fee per gas * gas factor
282+ return sdk .ErrInsufficientFee (fmt .Sprintf (
283+ "insufficient fee, got: %q required: %q" , stdTx .Fee .Amount , requiredFees )).Result ()
284+ }
285+ return sdk.Result {}
286+ }
287+
288+ func setGasMeter (simulate bool , ctx sdk.Context , stdTx StdTx ) sdk.Context {
289+ // set the gas meter
290+ if simulate {
291+ return ctx .WithGasMeter (sdk .NewInfiniteGasMeter ())
292+ }
293+ return ctx .WithGasMeter (sdk .NewGasMeter (stdTx .Fee .Gas ))
294+ }
295+
296+ func getSignBytesList (chainID string , stdTx StdTx , stdSigs []StdSignature ) (signatureBytesList [][]byte ) {
297+ signatureBytesList = make ([][]byte , len (stdSigs ))
298+ for i := 0 ; i < len (stdSigs ); i ++ {
299+ signatureBytesList [i ] = StdSignBytes (chainID ,
300+ stdSigs [i ].AccountNumber , stdSigs [i ].Sequence ,
301+ stdTx .Fee , stdTx .Msgs , stdTx .Memo )
302+ }
303+ return
304+ }
305+
275306// BurnFeeHandler burns all fees (decreasing total supply)
276307func BurnFeeHandler (_ sdk.Context , _ sdk.Tx , _ sdk.Coins ) {}
0 commit comments