Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions mempool/estimatefee.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,3 +756,6 @@ func RestoreFeeEstimator(data FeeEstimatorState) (*FeeEstimator, error) {

return ef, nil
}

// Ensure FeeEstimator implements the TxFeeEstimator interface.
var _ TxFeeEstimator = (*FeeEstimator)(nil)
121 changes: 24 additions & 97 deletions mempool/mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -1558,36 +1558,10 @@ func (mp *TxPool) checkMempoolAcceptance(tx *btcutil.Tx,
// validateSegWitDeployment checks that when a transaction has witness data,
// segwit must be active.
func (mp *TxPool) validateSegWitDeployment(tx *btcutil.Tx) error {
// Exit early if this transaction doesn't have witness data.
if !tx.MsgTx().HasWitness() {
return nil
}

// If a transaction has witness data, and segwit isn't active yet, then
// we won't accept it into the mempool as it can't be mined yet.
segwitActive, err := mp.cfg.IsDeploymentActive(
chaincfg.DeploymentSegwit,
return CheckSegWitDeployment(
tx, mp.cfg.IsDeploymentActive, mp.cfg.ChainParams,
mp.cfg.BestHeight(),
)
if err != nil {
return err
}

// Exit early if segwit is active.
if segwitActive {
return nil
}

simnetHint := ""
if mp.cfg.ChainParams.Net == wire.SimNet {
bestHeight := mp.cfg.BestHeight()
simnetHint = fmt.Sprintf(" (The threshold for segwit "+
"activation is 300 blocks on simnet, current best "+
"height is %d)", bestHeight)
}
str := fmt.Sprintf("transaction %v has witness data, "+
"but segwit isn't active yet%s", tx.Hash(), simnetHint)

return txRuleError(wire.RejectNonstandard, str)
}

// validateStandardness checks the transaction passes both transaction standard
Expand Down Expand Up @@ -1647,31 +1621,8 @@ func (mp *TxPool) validateStandardness(tx *btcutil.Tx, nextBlockHeight int32,
func (mp *TxPool) validateSigCost(tx *btcutil.Tx,
utxoView *blockchain.UtxoViewpoint) error {

// Since the coinbase address itself can contain signature operations,
// the maximum allowed signature operations per transaction is less
// than the maximum allowed signature operations per block.
//
// TODO(roasbeef): last bool should be conditional on segwit activation
sigOpCost, err := blockchain.GetSigOpCost(
tx, false, utxoView, true, true,
)
if err != nil {
if cerr, ok := err.(blockchain.RuleError); ok {
return chainRuleError(cerr)
}

return err
}

// Exit early if the sig cost is under limit.
if sigOpCost <= mp.cfg.Policy.MaxSigOpCostPerTx {
return nil
}

str := fmt.Sprintf("transaction %v sigop cost is too high: %d > %d",
tx.Hash(), sigOpCost, mp.cfg.Policy.MaxSigOpCostPerTx)

return txRuleError(wire.RejectNonstandard, str)
// Use the standalone CheckTransactionSigCost function.
return CheckTransactionSigCost(tx, utxoView, mp.cfg.Policy.MaxSigOpCostPerTx)
}

// validateRelayFeeMet checks that the min relay fee is covered by this
Expand All @@ -1680,56 +1631,32 @@ func (mp *TxPool) validateRelayFeeMet(tx *btcutil.Tx, txFee, txSize int64,
utxoView *blockchain.UtxoViewpoint, nextBlockHeight int32,
isNew, rateLimit bool) error {

txHash := tx.Hash()

// Most miners allow a free transaction area in blocks they mine to go
// alongside the area used for high-priority transactions as well as
// transactions with fees. A transaction size of up to 1000 bytes is
// considered safe to go into this section. Further, the minimum fee
// calculated below on its own would encourage several small
// transactions to avoid fees rather than one single larger transaction
// which is more desirable. Therefore, as long as the size of the
// transaction does not exceed 1000 less than the reserved space for
// high-priority transactions, don't require a fee for it.
minFee := calcMinRequiredTxRelayFee(txSize, mp.cfg.Policy.MinRelayTxFee)

if txSize >= (DefaultBlockPrioritySize-1000) && txFee < minFee {
str := fmt.Sprintf("transaction %v has %d fees which is under "+
"the required amount of %d", txHash, txFee, minFee)

return txRuleError(wire.RejectInsufficientFee, str)
// Use the standalone CheckRelayFee function for min fee and priority
// checks.
err := CheckRelayFee(
tx, txFee, txSize, utxoView, nextBlockHeight,
mp.cfg.Policy.MinRelayTxFee,
mp.cfg.Policy.DisableRelayPriority, isNew,
)
if err != nil {
return err
}

// Exit early if the min relay fee is met.
if txFee >= minFee {
// Exit early if rate limiting is not requested.
if !rateLimit {
return nil
}

// Exit early if this is neither a new tx or rate limited.
if !isNew && !rateLimit {
return nil
}
// Calculate minimum required fee to determine if rate limiting applies.
minFee := calcMinRequiredTxRelayFee(txSize, mp.cfg.Policy.MinRelayTxFee)

// Require that free transactions have sufficient priority to be mined
// in the next block. Transactions which are being added back to the
// memory pool from blocks that have been disconnected during a reorg
// are exempted.
if isNew && !mp.cfg.Policy.DisableRelayPriority {
currentPriority := mining.CalcPriority(
tx.MsgTx(), utxoView, nextBlockHeight,
)
if currentPriority <= mining.MinHighPriority {
str := fmt.Sprintf("transaction %v has insufficient "+
"priority (%g <= %g)", txHash,
currentPriority, mining.MinHighPriority)

return txRuleError(wire.RejectInsufficientFee, str)
}
// If the fee meets the minimum, no rate limiting needed.
if txFee >= minFee {
return nil
}

// We can only end up here when the rateLimit is true. Free-to-relay
// transactions are rate limited here to prevent penny-flooding with
// tiny transactions as a form of attack.
// Free-to-relay transactions are rate limited here to prevent
// penny-flooding with tiny transactions as a form of attack.
nowUnix := time.Now().Unix()

// Decay passed data with an exponentially decaying ~10 minute window -
Expand All @@ -1742,7 +1669,7 @@ func (mp *TxPool) validateRelayFeeMet(tx *btcutil.Tx, txFee, txSize int64,
// Are we still over the limit?
if mp.pennyTotal >= mp.cfg.Policy.FreeTxRelayLimit*10*1000 {
str := fmt.Sprintf("transaction %v has been rejected "+
"by the rate limiter due to low fees", txHash)
"by the rate limiter due to low fees", tx.Hash())

return txRuleError(wire.RejectInsufficientFee, str)
}
Expand Down
Loading
Loading