mirror of
https://github.com/LBRYFoundation/lbcd.git
synced 2025-08-23 17:47:24 +00:00
Fix the mempool rate limiter.
Before, btcd was rate limiting all transactions that had a minimum fee of zero. Now, btcd only rate limits transactions that contain a fee less than the calculated fee based on size. Closes #163
This commit is contained in:
parent
e720e398a1
commit
61a53adccd
1 changed files with 29 additions and 23 deletions
52
mempool.go
52
mempool.go
|
@ -370,9 +370,29 @@ func checkInputsStandard(tx *btcutil.Tx, txStore btcchain.TxStore) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calcTxFee returns the minimum transaction fee required for the passed
|
||||||
|
// transaction.
|
||||||
|
func calcTxFee(size int) int64 {
|
||||||
|
// Calculate the minimum fee for a transaction to be allowed into the
|
||||||
|
// mempool and relayed by scaling the base fee (which is the minimum
|
||||||
|
// free transaction relay fee). minTxRelayFee is in Satoshi/KB, so
|
||||||
|
// divide the transaction size by 1000 to convert to kilobytes. Also,
|
||||||
|
// integer division is used so fees only increase on full kilobyte
|
||||||
|
// boundaries.
|
||||||
|
minFee := (1 + size/1000) * minTxRelayFee
|
||||||
|
|
||||||
|
// Set the minimum fee to the maximum possible value if the calculated
|
||||||
|
// fee is not in the valid range for monetary amounts.
|
||||||
|
if minFee < 0 || minFee > btcutil.MaxSatoshi {
|
||||||
|
minFee = btcutil.MaxSatoshi
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(minFee)
|
||||||
|
}
|
||||||
|
|
||||||
// calcMinRelayFee retuns the minimum transaction fee required for the passed
|
// calcMinRelayFee retuns the minimum transaction fee required for the passed
|
||||||
// transaction to be accepted into the memory pool and relayed.
|
// transaction to be accepted into the memory pool and relayed.
|
||||||
func calcMinRelayFee(tx *btcutil.Tx) int64 {
|
func calcMinTxRelayFee(size int) int64 {
|
||||||
// Most miners allow a free transaction area in blocks they mine to go
|
// Most miners allow a free transaction area in blocks they mine to go
|
||||||
// alongside the area used for high-priority transactions as well as
|
// alongside the area used for high-priority transactions as well as
|
||||||
// transactions with fees. A transaction size of up to 1000 bytes is
|
// transactions with fees. A transaction size of up to 1000 bytes is
|
||||||
|
@ -382,26 +402,11 @@ func calcMinRelayFee(tx *btcutil.Tx) int64 {
|
||||||
// which is more desirable. Therefore, as long as the size of the
|
// which is more desirable. Therefore, as long as the size of the
|
||||||
// transaction does not exceeed 1000 less than the reserved space for
|
// transaction does not exceeed 1000 less than the reserved space for
|
||||||
// high-priority transactions, don't require a fee for it.
|
// high-priority transactions, don't require a fee for it.
|
||||||
serializedLen := int64(tx.MsgTx().SerializeSize())
|
if size < (defaultBlockPrioritySize - 1000) {
|
||||||
if serializedLen < (defaultBlockPrioritySize - 1000) {
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the minimum fee for a transaction to be allowed into the
|
return calcTxFee(size)
|
||||||
// mempool and relayed by scaling the base fee (which is the minimum
|
|
||||||
// free transaction relay fee). minTxRelayFee is in Satoshi/KB, so
|
|
||||||
// divide the transaction size by 1000 to convert to kilobytes. Also,
|
|
||||||
// integer division is used so fees only increase on full kilobyte
|
|
||||||
// boundaries.
|
|
||||||
minFee := (1 + serializedLen/1000) * minTxRelayFee
|
|
||||||
|
|
||||||
// Set the minimum fee to the maximum possible value if the calculated
|
|
||||||
// fee is not in the valid range for monetary amounts.
|
|
||||||
if minFee < 0 || minFee > btcutil.MaxSatoshi {
|
|
||||||
minFee = btcutil.MaxSatoshi
|
|
||||||
}
|
|
||||||
|
|
||||||
return minFee
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeOrphan removes the passed orphan transaction from the orphan pool and
|
// removeOrphan removes the passed orphan transaction from the orphan pool and
|
||||||
|
@ -890,7 +895,8 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isOrphan *bool, isNe
|
||||||
// reasonable number of ECDSA signature verifications.
|
// reasonable number of ECDSA signature verifications.
|
||||||
|
|
||||||
// Don't allow transactions with fees too low to get into a mined block.
|
// Don't allow transactions with fees too low to get into a mined block.
|
||||||
minRequiredFee := calcMinRelayFee(tx)
|
serializedSize := tx.MsgTx().SerializeSize()
|
||||||
|
minRequiredFee := calcMinTxRelayFee(serializedSize)
|
||||||
if txFee < minRequiredFee {
|
if txFee < minRequiredFee {
|
||||||
str := fmt.Sprintf("transaction %v has %d fees which is under "+
|
str := fmt.Sprintf("transaction %v has %d fees which is under "+
|
||||||
"the required amount of %d", txHash, txFee,
|
"the required amount of %d", txHash, txFee,
|
||||||
|
@ -900,7 +906,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isOrphan *bool, isNe
|
||||||
|
|
||||||
// Free-to-relay transactions are rate limited here to prevent
|
// Free-to-relay transactions are rate limited here to prevent
|
||||||
// penny-flooding with tiny transactions as a form of attack.
|
// penny-flooding with tiny transactions as a form of attack.
|
||||||
if rateLimit && minRequiredFee == 0 {
|
if rateLimit && txFee < calcTxFee(serializedSize) {
|
||||||
nowUnix := time.Now().Unix()
|
nowUnix := time.Now().Unix()
|
||||||
// we decay passed data with an exponentially decaying ~10
|
// we decay passed data with an exponentially decaying ~10
|
||||||
// minutes window - matches bitcoind handling.
|
// minutes window - matches bitcoind handling.
|
||||||
|
@ -910,13 +916,13 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isOrphan *bool, isNe
|
||||||
|
|
||||||
// Are we still over the limit?
|
// Are we still over the limit?
|
||||||
if mp.pennyTotal >= cfg.FreeTxRelayLimit*10*1000 {
|
if mp.pennyTotal >= cfg.FreeTxRelayLimit*10*1000 {
|
||||||
str := fmt.Sprintf("transaction %v has 0 fees and has "+
|
str := fmt.Sprintf("transaction %v has been rejected "+
|
||||||
"been rejected by the rate limiter", txHash)
|
"by the rate limiter due to low fees", txHash)
|
||||||
return txRuleError(btcwire.RejectInsufficientFee, str)
|
return txRuleError(btcwire.RejectInsufficientFee, str)
|
||||||
}
|
}
|
||||||
oldTotal := mp.pennyTotal
|
oldTotal := mp.pennyTotal
|
||||||
|
|
||||||
mp.pennyTotal += float64(tx.MsgTx().SerializeSize())
|
mp.pennyTotal += float64(serializedSize)
|
||||||
txmpLog.Tracef("rate limit: curTotal %v, nextTotal: %v, "+
|
txmpLog.Tracef("rate limit: curTotal %v, nextTotal: %v, "+
|
||||||
"limit %v", oldTotal, mp.pennyTotal,
|
"limit %v", oldTotal, mp.pennyTotal,
|
||||||
cfg.FreeTxRelayLimit*10*1000)
|
cfg.FreeTxRelayLimit*10*1000)
|
||||||
|
|
Loading…
Add table
Reference in a new issue