Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 521 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 bypass_limits, 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 156 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
strprintf("%d", nSigOpsCount)); | strprintf("%d", nSigOpsCount)); | ||||
} | } | ||||
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 (!bypass_limits && 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) && | if (gArgs.GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && | ||||
nModifiedFees < minRelayTxFee.GetFee(nSize) && | nModifiedFees < minRelayTxFee.GetFee(nSize) && | ||||
!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 (bypass_limits && nModifiedFees < minRelayTxFee.GetFee(nSize)) { | ||||
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: | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
// Tx was accepted, but not added | // Tx was accepted, but not added | ||||
return true; | return true; | ||||
} | } | ||||
// Store transaction in memory. | // Store transaction in memory. | ||||
pool.addUnchecked(txid, entry, setAncestors); | pool.addUnchecked(txid, entry, setAncestors); | ||||
// Trim mempool and check if tx was trimmed. | // Trim mempool and check if tx was trimmed. | ||||
if (!fOverrideMempoolLimit) { | if (!bypass_limits) { | ||||
pool.LimitSize( | pool.LimitSize( | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, | ||||
gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * | gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * | ||||
60); | 60); | ||||
if (!pool.exists(txid)) { | if (!pool.exists(txid)) { | ||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | ||||
"mempool full"); | "mempool full"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
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 bypass_limits, const Amount nAbsurdFee, | |||||
bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(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, bypass_limits, | ||||
fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache, test_accept); | 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 bypass_limits, | ||||
bool fOverrideMempoolLimit, const Amount nAbsurdFee, | const Amount nAbsurdFee, bool test_accept) { | ||||
bool test_accept) { | return AcceptToMemoryPoolWithTime(config, pool, state, tx, pfMissingInputs, | ||||
return AcceptToMemoryPoolWithTime( | GetTime(), bypass_limits, nAbsurdFee, | ||||
config, pool, state, tx, fLimitFree, pfMissingInputs, GetTime(), | 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 Consensus::Params ¶ms, const TxId &txid, | bool GetTransaction(const Consensus::Params ¶ms, const TxId &txid, | ||||
▲ Show 20 Lines • Show All 4,730 Lines • ▼ Show 20 Lines | try { | ||||
if (amountdelta != Amount::zero()) { | if (amountdelta != Amount::zero()) { | ||||
g_mempool.PrioritiseTransaction(tx->GetId(), prioritydummy, | g_mempool.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, g_mempool, state, tx, true /* fLimitFree */, | config, g_mempool, state, tx, nullptr /* pfMissingInputs */, | ||||
nullptr /* pfMissingInputs */, nTime, | nTime, false /* bypass_limits */, | ||||
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 128 Lines • Show Last 20 Lines |