Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 533 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
assert(coinFromDisk.GetTxOut() == coin.GetTxOut()); | assert(coinFromDisk.GetTxOut() == coin.GetTxOut()); | ||||
} | } | ||||
} | } | ||||
return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, | return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, | ||||
txdata); | txdata); | ||||
} | } | ||||
static bool AcceptToMemoryPoolWorker( | static bool | ||||
const Config &config, CTxMemPool &pool, CValidationState &state, | AcceptToMemoryPoolWorker(const Config &config, CTxMemPool &pool, | ||||
const CTransactionRef &ptx, bool fLimitFree, bool *pfMissingInputs, | CValidationState &state, const CTransactionRef &ptx, | ||||
int64_t nAcceptTime, bool fOverrideMempoolLimit, const Amount nAbsurdFee, | bool *pfMissingInputs, int64_t nAcceptTime, | ||||
std::vector<COutPoint> &coins_to_uncache, bool test_accept) | bool fOverrideMempoolLimit, const Amount nAbsurdFee, | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | std::vector<COutPoint> &coins_to_uncache, | ||||
bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
const Consensus::Params &consensusParams = | const Consensus::Params &consensusParams = | ||||
config.GetChainParams().GetConsensus(); | config.GetChainParams().GetConsensus(); | ||||
const CTransaction &tx = *ptx; | const CTransaction &tx = *ptx; | ||||
const TxId txid = tx.GetId(); | const TxId txid = tx.GetId(); | ||||
▲ Show 20 Lines • Show All 151 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
// 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)); | ||||
} | } | ||||
// No transactions are allowed below minRelayTxFee except from | |||||
// disconnected blocks | |||||
if (!fOverrideMempoolLimit && | |||||
nModifiedFees < minRelayTxFee.GetFee(nSize)) { | |||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | |||||
"min relay fee not met"); | |||||
} | |||||
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(nSize); | ||||
if (mempoolRejectFee > Amount::zero() && | if (!fOverrideMempoolLimit && mempoolRejectFee > Amount::zero() && | ||||
nModifiedFees < mempoolRejectFee) { | nModifiedFees < mempoolRejectFee) { | ||||
return state.DoS( | return state.DoS( | ||||
0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", | 0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", | ||||
false, strprintf("%d < %d", nModifiedFees, mempoolRejectFee)); | false, strprintf("%d < %d", nModifiedFees, mempoolRejectFee)); | ||||
} | } | ||||
if (gArgs.GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && | |||||
nModifiedFees < minRelayTxFee.GetFee(nSize) && | |||||
!AllowFree(entry.GetPriority(chainActive.Height() + 1))) { | |||||
// Require that free transactions have sufficient priority to be | |||||
// mined in the next block. | |||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | |||||
"insufficient priority"); | |||||
} | |||||
// Continuously rate-limit free (really, very-low-fee) transactions. | |||||
// This mitigates 'penny-flooding' -- sending thousands of free | |||||
// transactions just to be annoying or make others' transactions take | |||||
// longer to confirm. | |||||
if (fLimitFree && nModifiedFees < minRelayTxFee.GetFee(nSize)) { | |||||
static CCriticalSection csFreeLimiter; | |||||
static double dFreeCount; | |||||
static int64_t nLastTime; | |||||
int64_t nNow = GetTime(); | |||||
LOCK(csFreeLimiter); | |||||
// Use an exponentially decaying ~10-minute window: | |||||
dFreeCount *= pow(1.0 - 1.0 / 600.0, double(nNow - nLastTime)); | |||||
nLastTime = nNow; | |||||
// -limitfreerelay unit is thousand-bytes-per-minute | |||||
// 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 >= | |||||
gArgs.GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * | |||||
1000) { | |||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | |||||
"rate limited free transaction"); | |||||
} | |||||
LogPrint(BCLog::MEMPOOL, "Rate limit dFreeCount: %g => %g\n", | |||||
dFreeCount, dFreeCount + nSize); | |||||
dFreeCount += nSize; | |||||
} | |||||
if (nAbsurdFee != Amount::zero() && nFees > nAbsurdFee) { | if (nAbsurdFee != Amount::zero() && nFees > nAbsurdFee) { | ||||
return state.Invalid(false, REJECT_HIGHFEE, "absurdly-high-fee", | return state.Invalid(false, REJECT_HIGHFEE, "absurdly-high-fee", | ||||
strprintf("%d > %d", nFees, nAbsurdFee)); | strprintf("%d > %d", nFees, nAbsurdFee)); | ||||
} | } | ||||
// Calculate in-mempool ancestors, up to a limit. | // Calculate in-mempool ancestors, up to a limit. | ||||
CTxMemPool::setEntries setAncestors; | CTxMemPool::setEntries setAncestors; | ||||
size_t nLimitAncestors = | size_t nLimitAncestors = | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | AcceptToMemoryPoolWorker(const Config &config, CTxMemPool &pool, | ||||
GetMainSignals().TransactionAddedToMempool(ptx); | GetMainSignals().TransactionAddedToMempool(ptx); | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* (try to) add transaction to memory pool with a specified acceptance time. | * (try to) add transaction to memory pool with a specified acceptance time. | ||||
*/ | */ | ||||
static bool AcceptToMemoryPoolWithTime( | static bool | ||||
const Config &config, CTxMemPool &pool, CValidationState &state, | AcceptToMemoryPoolWithTime(const Config &config, CTxMemPool &pool, | ||||
const CTransactionRef &tx, bool fLimitFree, bool *pfMissingInputs, | CValidationState &state, const CTransactionRef &tx, | ||||
int64_t nAcceptTime, bool fOverrideMempoolLimit, const Amount nAbsurdFee, | bool *pfMissingInputs, int64_t nAcceptTime, | ||||
bool fOverrideMempoolLimit, const Amount nAbsurdFee, | |||||
bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
std::vector<COutPoint> coins_to_uncache; | std::vector<COutPoint> coins_to_uncache; | ||||
bool res = AcceptToMemoryPoolWorker( | bool res = AcceptToMemoryPoolWorker( | ||||
config, pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, | config, pool, state, tx, pfMissingInputs, nAcceptTime, | ||||
fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache, test_accept); | fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache, test_accept); | ||||
if (!res) { | if (!res) { | ||||
for (const COutPoint &outpoint : coins_to_uncache) { | for (const COutPoint &outpoint : coins_to_uncache) { | ||||
pcoinsTip->Uncache(outpoint); | pcoinsTip->Uncache(outpoint); | ||||
} | } | ||||
} | } | ||||
// After we've (potentially) uncached entries, ensure our coins cache is | // After we've (potentially) uncached entries, ensure our coins cache is | ||||
// still within its size limits | // still within its size limits | ||||
CValidationState stateDummy; | CValidationState stateDummy; | ||||
FlushStateToDisk(config.GetChainParams(), stateDummy, | FlushStateToDisk(config.GetChainParams(), stateDummy, | ||||
FlushStateMode::PERIODIC); | FlushStateMode::PERIODIC); | ||||
return res; | return res; | ||||
} | } | ||||
bool AcceptToMemoryPool(const Config &config, CTxMemPool &pool, | bool AcceptToMemoryPool(const Config &config, CTxMemPool &pool, | ||||
CValidationState &state, const CTransactionRef &tx, | CValidationState &state, const CTransactionRef &tx, | ||||
bool fLimitFree, bool *pfMissingInputs, | bool *pfMissingInputs, bool fOverrideMempoolLimit, | ||||
bool fOverrideMempoolLimit, const Amount nAbsurdFee, | const Amount nAbsurdFee, bool test_accept) { | ||||
bool test_accept) { | return AcceptToMemoryPoolWithTime(config, pool, state, tx, pfMissingInputs, | ||||
return AcceptToMemoryPoolWithTime( | GetTime(), fOverrideMempoolLimit, | ||||
config, pool, state, tx, fLimitFree, pfMissingInputs, GetTime(), | nAbsurdFee, test_accept); | ||||
fOverrideMempoolLimit, nAbsurdFee, test_accept); | |||||
} | } | ||||
/** | /** | ||||
* Return transaction in txOut, and if it was found inside a block, its hash is | * Return transaction in txOut, and if it was found inside a block, its hash is | ||||
* placed in hashBlock. If blockIndex is provided, the transaction is fetched | * placed in hashBlock. If blockIndex is provided, the transaction is fetched | ||||
* from the corresponding block. | * from the corresponding block. | ||||
*/ | */ | ||||
bool GetTransaction(const TxId &txid, CTransactionRef &txOut, | bool GetTransaction(const TxId &txid, CTransactionRef &txOut, | ||||
▲ Show 20 Lines • Show All 4,775 Lines • ▼ Show 20 Lines | try { | ||||
if (amountdelta != Amount::zero()) { | if (amountdelta != Amount::zero()) { | ||||
pool.PrioritiseTransaction(tx->GetId(), prioritydummy, | pool.PrioritiseTransaction(tx->GetId(), prioritydummy, | ||||
amountdelta); | amountdelta); | ||||
} | } | ||||
CValidationState state; | CValidationState state; | ||||
if (nTime + nExpiryTimeout > nNow) { | if (nTime + nExpiryTimeout > nNow) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
AcceptToMemoryPoolWithTime( | AcceptToMemoryPoolWithTime( | ||||
config, pool, state, tx, true /* fLimitFree */, | config, pool, state, tx, nullptr /* pfMissingInputs */, | ||||
nullptr /* pfMissingInputs */, nTime, | nTime, false /* fOverrideMempoolLimit */, | ||||
false /* fOverrideMempoolLimit */, | |||||
Amount::zero() /* nAbsurdFee */, false /* test_accept */); | Amount::zero() /* nAbsurdFee */, false /* test_accept */); | ||||
if (state.IsValid()) { | if (state.IsValid()) { | ||||
++count; | ++count; | ||||
} else { | } else { | ||||
// mempool may contain the transaction already, e.g. from | // mempool may contain the transaction already, e.g. from | ||||
// wallet(s) having loaded it while we were processing | // wallet(s) having loaded it while we were processing | ||||
// mempool transactions; consider these as valid, instead of | // mempool transactions; consider these as valid, instead of | ||||
// failed, but mark them as 'already there' | // failed, but mark them as 'already there' | ||||
▲ Show 20 Lines • Show All 130 Lines • Show Last 20 Lines |