Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 518 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, dPriority, | CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, dPriority, | ||||
chainActive.Height(), inChainInputValue, | chainActive.Height(), inChainInputValue, | ||||
fSpendsCoinbase, nSigOpsCount, lp); | fSpendsCoinbase, nSigOpsCount, lp); | ||||
unsigned int nSize = entry.GetTxSize(); | unsigned int nSize = entry.GetTxSize(); | ||||
size_t feeSize = tx.GetBillableSize(); | |||||
// Check that the transaction doesn't have an excessive number of | // Check that the transaction doesn't have an excessive number of | ||||
// sigops, making it impossible to mine. Since the coinbase transaction | // sigops, making it impossible to mine. Since the coinbase transaction | ||||
// itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than | // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than | ||||
// MAX_BLOCK_SIGOPS_PER_MB; we still consider this an invalid rather | // MAX_BLOCK_SIGOPS_PER_MB; we still consider this an invalid rather | ||||
// than merely non-standard transaction. | // than merely non-standard transaction. | ||||
if (nSigOpsCount > MAX_STANDARD_TX_SIGOPS) { | if (nSigOpsCount > MAX_STANDARD_TX_SIGOPS) { | ||||
return state.DoS(0, false, REJECT_NONSTANDARD, | return state.DoS(0, false, REJECT_NONSTANDARD, | ||||
"bad-txns-too-many-sigops", false, | "bad-txns-too-many-sigops", false, | ||||
strprintf("%d", nSigOpsCount)); | strprintf("%d", nSigOpsCount)); | ||||
} | } | ||||
CFeeRate minRelayTxFee = config.GetMinFeePerKB(); | CFeeRate minRelayTxFee = config.GetMinFeePerKB(); | ||||
Amount mempoolRejectFee = | Amount mempoolRejectFee = | ||||
pool.GetMinFee( | pool.GetMinFee( | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | ||||
1000000) | 1000000) | ||||
.GetFee(nSize); | .GetFee(feeSize); | ||||
if (mempoolRejectFee > Amount::zero() && | if (mempoolRejectFee > Amount::zero() && | ||||
nModifiedFees < mempoolRejectFee) { | nModifiedFees < mempoolRejectFee) { | ||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | ||||
"mempool min fee not met", false, | "mempool min fee not met", false, | ||||
strprintf("%d < %d", nFees, mempoolRejectFee)); | strprintf("%d < %d", nFees, mempoolRejectFee)); | ||||
} | } | ||||
if (gArgs.GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && | if (gArgs.GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && | ||||
nModifiedFees < minRelayTxFee.GetFee(nSize) && | nModifiedFees < minRelayTxFee.GetFee(feeSize) && | ||||
!AllowFree(entry.GetPriority(chainActive.Height() + 1))) { | !AllowFree(entry.GetPriority(chainActive.Height() + 1))) { | ||||
// Require that free transactions have sufficient priority to be | // Require that free transactions have sufficient priority to be | ||||
// mined in the next block. | // mined in the next block. | ||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | ||||
"insufficient priority"); | "insufficient priority"); | ||||
} | } | ||||
// Continuously rate-limit free (really, very-low-fee) transactions. | // Continuously rate-limit free (really, very-low-fee) transactions. | ||||
// This mitigates 'penny-flooding' -- sending thousands of free | // This mitigates 'penny-flooding' -- sending thousands of free | ||||
// transactions just to be annoying or make others' transactions take | // transactions just to be annoying or make others' transactions take | ||||
// longer to confirm. | // longer to confirm. | ||||
if (fLimitFree && nModifiedFees < minRelayTxFee.GetFee(nSize)) { | if (fLimitFree && nModifiedFees < minRelayTxFee.GetFee(feeSize)) { | ||||
static CCriticalSection csFreeLimiter; | static CCriticalSection csFreeLimiter; | ||||
static double dFreeCount; | static double dFreeCount; | ||||
static int64_t nLastTime; | static int64_t nLastTime; | ||||
int64_t nNow = GetTime(); | int64_t nNow = GetTime(); | ||||
LOCK(csFreeLimiter); | LOCK(csFreeLimiter); | ||||
// Use an exponentially decaying ~10-minute window: | // Use an exponentially decaying ~10-minute window: | ||||
dFreeCount *= pow(1.0 - 1.0 / 600.0, double(nNow - nLastTime)); | dFreeCount *= pow(1.0 - 1.0 / 600.0, double(nNow - nLastTime)); | ||||
nLastTime = nNow; | nLastTime = nNow; | ||||
// -limitfreerelay unit is thousand-bytes-per-minute | // -limitfreerelay unit is thousand-bytes-per-minute | ||||
// At default rate it would take over a month to fill 1GB | // At default rate it would take over a month to fill 1GB | ||||
// NOTE: Use the actual size here, and not the fee size since this | |||||
// is counting real size for the rate limiter. | |||||
if (dFreeCount + nSize >= | if (dFreeCount + nSize >= | ||||
gArgs.GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * | gArgs.GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * | ||||
1000) { | 1000) { | ||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | ||||
"rate limited free transaction"); | "rate limited free transaction"); | ||||
} | } | ||||
LogPrint(BCLog::MEMPOOL, "Rate limit dFreeCount: %g => %g\n", | LogPrint(BCLog::MEMPOOL, "Rate limit dFreeCount: %g => %g\n", | ||||
▲ Show 20 Lines • Show All 4,556 Lines • Show Last 20 Lines |