mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-19 13:27:35 +02:00
Merge f34fe0806a into merged_master (Bitcoin PR bitcoin/bitcoin#31122)
This commit is contained in:
commit
d4461d4c55
27 changed files with 708 additions and 398 deletions
|
|
@ -337,7 +337,7 @@ void Chainstate::MaybeUpdateMempoolForReorg(
|
|||
}
|
||||
}
|
||||
|
||||
// AcceptToMemoryPool/addUnchecked all assume that new mempool entries have
|
||||
// AcceptToMemoryPool/addNewTransaction all assume that new mempool entries have
|
||||
// no in-mempool children, which is generally not true when adding
|
||||
// previously-confirmed transactions back to the mempool.
|
||||
// UpdateTransactionsFromBlock finds descendants of any transactions in
|
||||
|
|
@ -653,10 +653,9 @@ private:
|
|||
CTxMemPool::setEntries m_iters_conflicting;
|
||||
/** All mempool ancestors of this transaction. */
|
||||
CTxMemPool::setEntries m_ancestors;
|
||||
/** Mempool entry constructed for this transaction. Constructed in PreChecks() but not
|
||||
* inserted into the mempool until Finalize(). */
|
||||
std::unique_ptr<CTxMemPoolEntry> m_entry;
|
||||
/** Whether RBF-related data structures (m_conflicts, m_iters_conflicting, m_all_conflicting,
|
||||
/* Handle to the tx in the changeset */
|
||||
CTxMemPool::ChangeSet::TxHandle m_tx_handle;
|
||||
/** Whether RBF-related data structures (m_conflicts, m_iters_conflicting,
|
||||
* m_replaced_transactions) include a sibling in addition to txns with conflicting inputs. */
|
||||
bool m_sibling_eviction{false};
|
||||
|
||||
|
|
@ -709,9 +708,7 @@ private:
|
|||
bool ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
|
||||
|
||||
// Try to add the transaction to the mempool, removing any conflicts first.
|
||||
// Returns true if the transaction is in the mempool after any size
|
||||
// limiting is performed, false otherwise.
|
||||
bool Finalize(const ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
|
||||
void FinalizeSubpackage(const ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
|
||||
|
||||
// Submit all transactions to the mempool and call ConsensusScriptChecks to add to the script
|
||||
// cache - should only be called after successful validation of all transactions in the package.
|
||||
|
|
@ -891,10 +888,10 @@ private:
|
|||
/** Whether the transaction(s) would replace any mempool transactions and/or evict any siblings.
|
||||
* If so, RBF rules apply. */
|
||||
bool m_rbf{false};
|
||||
/** All directly conflicting mempool transactions and their descendants. */
|
||||
CTxMemPool::setEntries m_all_conflicts;
|
||||
/** Mempool transactions that were replaced. */
|
||||
std::list<CTransactionRef> m_replaced_transactions;
|
||||
/* Changeset representing adding transactions and removing their conflicts. */
|
||||
std::unique_ptr<CTxMemPool::ChangeSet> m_changeset;
|
||||
|
||||
/** Total modified fees of mempool transactions being replaced. */
|
||||
CAmount m_conflicting_fees{0};
|
||||
|
|
@ -930,7 +927,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
|
||||
// Alias what we need out of ws
|
||||
TxValidationState& state = ws.m_state;
|
||||
std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry;
|
||||
std::set<std::pair<uint256, COutPoint>>& setPeginsSpent = ws.m_set_pegins_spent;
|
||||
|
||||
if (!CheckTransaction(tx, state)) {
|
||||
|
|
@ -1109,10 +1105,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
// We only consider policyAsset
|
||||
ws.m_base_fees = fee_map[policyAsset];
|
||||
|
||||
// ws.m_modified_fees includes any fee deltas from PrioritiseTransaction
|
||||
ws.m_modified_fees = ws.m_base_fees;
|
||||
m_pool.ApplyDelta(hash, ws.m_modified_fees);
|
||||
|
||||
// Keep track of transactions that spend a coinbase, which we re-scan
|
||||
// during reorgs to ensure COINBASE_MATURITY is still met.
|
||||
bool fSpendsCoinbase = false;
|
||||
|
|
@ -1131,9 +1123,15 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
// Set entry_sequence to 0 when bypass_limits is used; this allows txs from a block
|
||||
// reorg to be marked earlier than any child txs that were already in the mempool.
|
||||
const uint64_t entry_sequence = bypass_limits ? 0 : m_pool.GetSequence();
|
||||
entry.reset(new CTxMemPoolEntry(ptx, ws.m_base_fees, nAcceptTime, m_active_chainstate.m_chain.Height(), entry_sequence,
|
||||
fSpendsCoinbase, nSigOpsCost, lock_points.value(), setPeginsSpent));
|
||||
ws.m_vsize = entry->GetTxSize();
|
||||
if (!m_subpackage.m_changeset) {
|
||||
m_subpackage.m_changeset = m_pool.GetChangeSet();
|
||||
}
|
||||
ws.m_tx_handle = m_subpackage.m_changeset->StageAddition(ptx, ws.m_base_fees, nAcceptTime, m_active_chainstate.m_chain.Height(), entry_sequence, fSpendsCoinbase, nSigOpsCost, lock_points.value(), setPeginsSpent);
|
||||
|
||||
// ws.m_modified_fees includes any fee deltas from PrioritiseTransaction
|
||||
ws.m_modified_fees = ws.m_tx_handle->GetModifiedFee();
|
||||
|
||||
ws.m_vsize = ws.m_tx_handle->GetTxSize();
|
||||
|
||||
// Enforces 0-fee for dust transactions, no incentive to be mined alone
|
||||
if (m_pool.m_opts.require_standard) {
|
||||
|
|
@ -1210,7 +1208,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
maybe_rbf_limits.descendant_size_vbytes += conflict->GetSizeWithDescendants();
|
||||
}
|
||||
|
||||
if (auto ancestors{m_pool.CalculateMemPoolAncestors(*entry, maybe_rbf_limits)}) {
|
||||
if (auto ancestors{m_subpackage.m_changeset->CalculateMemPoolAncestors(ws.m_tx_handle, maybe_rbf_limits)}) {
|
||||
ws.m_ancestors = std::move(*ancestors);
|
||||
} else {
|
||||
// If CalculateMemPoolAncestors fails second time, we want the original error string.
|
||||
|
|
@ -1242,7 +1240,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx->version == TRUC_VERSION) {
|
||||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
|
||||
}
|
||||
if (auto ancestors_retry{m_pool.CalculateMemPoolAncestors(*entry, cpfp_carve_out_limits)}) {
|
||||
if (auto ancestors_retry{m_subpackage.m_changeset->CalculateMemPoolAncestors(ws.m_tx_handle, cpfp_carve_out_limits)}) {
|
||||
ws.m_ancestors = std::move(*ancestors_retry);
|
||||
} else {
|
||||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
|
||||
|
|
@ -1316,13 +1314,15 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
|
|||
strprintf("insufficient fee%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
|
||||
}
|
||||
|
||||
CTxMemPool::setEntries all_conflicts;
|
||||
|
||||
// Calculate all conflicting entries and enforce Rule #5.
|
||||
if (const auto err_string{GetEntriesForConflicts(tx, m_pool, ws.m_iters_conflicting, m_subpackage.m_all_conflicts)}) {
|
||||
if (const auto err_string{GetEntriesForConflicts(tx, m_pool, ws.m_iters_conflicting, all_conflicts)}) {
|
||||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
|
||||
strprintf("too many potential replacements%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
|
||||
}
|
||||
// Enforce Rule #2.
|
||||
if (const auto err_string{HasNoNewUnconfirmed(tx, m_pool, m_subpackage.m_all_conflicts)}) {
|
||||
if (const auto err_string{HasNoNewUnconfirmed(tx, m_pool, all_conflicts)}) {
|
||||
// Sibling eviction is only done for TRUC transactions, which cannot have multiple ancestors.
|
||||
Assume(!ws.m_sibling_eviction);
|
||||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
|
||||
|
|
@ -1331,7 +1331,7 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
|
|||
|
||||
// Check if it's economically rational to mine this transaction rather than the ones it
|
||||
// replaces and pays for its own relay fees. Enforce Rules #3 and #4.
|
||||
for (CTxMemPool::txiter it : m_subpackage.m_all_conflicts) {
|
||||
for (CTxMemPool::txiter it : all_conflicts) {
|
||||
m_subpackage.m_conflicting_fees += it->GetModifiedFee();
|
||||
m_subpackage.m_conflicting_size += it->GetTxSize();
|
||||
}
|
||||
|
|
@ -1341,6 +1341,11 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
|
|||
return state.Invalid(TxValidationResult::TX_RECONSIDERABLE,
|
||||
strprintf("insufficient fee%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
|
||||
}
|
||||
|
||||
// Add all the to-be-removed transactions to the changeset.
|
||||
for (auto it : all_conflicts) {
|
||||
m_subpackage.m_changeset->StageRemoval(it);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1394,13 +1399,16 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
|
|||
|
||||
// Don't consider replacements that would cause us to remove a large number of mempool entries.
|
||||
// This limit is not increased in a package RBF. Use the aggregate number of transactions.
|
||||
CTxMemPool::setEntries all_conflicts;
|
||||
if (const auto err_string{GetEntriesForConflicts(*child_ws.m_ptx, m_pool, direct_conflict_iters,
|
||||
m_subpackage.m_all_conflicts)}) {
|
||||
all_conflicts)}) {
|
||||
return package_state.Invalid(PackageValidationResult::PCKG_POLICY,
|
||||
"package RBF failed: too many potential replacements", *err_string);
|
||||
}
|
||||
|
||||
for (CTxMemPool::txiter it : m_subpackage.m_all_conflicts) {
|
||||
|
||||
for (CTxMemPool::txiter it : all_conflicts) {
|
||||
m_subpackage.m_changeset->StageRemoval(it);
|
||||
m_subpackage.m_conflicting_fees += it->GetModifiedFee();
|
||||
m_subpackage.m_conflicting_size += it->GetTxSize();
|
||||
}
|
||||
|
|
@ -1427,14 +1435,15 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
|
|||
|
||||
// Check if it's economically rational to mine this package rather than the ones it replaces.
|
||||
// This takes the place of ReplacementChecks()'s PaysMoreThanConflicts() in the package RBF setting.
|
||||
if (const auto err_tup{ImprovesFeerateDiagram(m_pool, direct_conflict_iters, m_subpackage.m_all_conflicts, m_subpackage.m_total_modified_fees, m_subpackage.m_total_vsize)}) {
|
||||
if (const auto err_tup{ImprovesFeerateDiagram(*m_subpackage.m_changeset)}) {
|
||||
return package_state.Invalid(PackageValidationResult::PCKG_POLICY,
|
||||
"package RBF failed: " + err_tup.value().second, "");
|
||||
}
|
||||
|
||||
LogDebug(BCLog::TXPACKAGES, "package RBF checks passed: parent %s (wtxid=%s), child %s (wtxid=%s)\n",
|
||||
LogDebug(BCLog::TXPACKAGES, "package RBF checks passed: parent %s (wtxid=%s), child %s (wtxid=%s), package hash (%s)\n",
|
||||
txns.front()->GetHash().ToString(), txns.front()->GetWitnessHash().ToString(),
|
||||
txns.back()->GetHash().ToString(), txns.back()->GetWitnessHash().ToString());
|
||||
txns.back()->GetHash().ToString(), txns.back()->GetWitnessHash().ToString(),
|
||||
GetPackageHash(txns).ToString());
|
||||
|
||||
|
||||
return true;
|
||||
|
|
@ -1509,58 +1518,55 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
|
||||
void MemPoolAccept::FinalizeSubpackage(const ATMPArgs& args)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
AssertLockHeld(m_pool.cs);
|
||||
const CTransaction& tx = *ws.m_ptx;
|
||||
const uint256& hash = ws.m_hash;
|
||||
TxValidationState& state = ws.m_state;
|
||||
const bool bypass_limits = args.m_bypass_limits;
|
||||
std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry;
|
||||
|
||||
if (!m_subpackage.m_all_conflicts.empty()) Assume(args.m_allow_replacement);
|
||||
if (!m_subpackage.m_changeset->GetRemovals().empty()) Assume(args.m_allow_replacement);
|
||||
// Remove conflicting transactions from the mempool
|
||||
for (CTxMemPool::txiter it : m_subpackage.m_all_conflicts)
|
||||
for (CTxMemPool::txiter it : m_subpackage.m_changeset->GetRemovals())
|
||||
{
|
||||
LogDebug(BCLog::MEMPOOL, "replacing mempool tx %s (wtxid=%s, fees=%s, vsize=%s). New tx %s (wtxid=%s, fees=%s, vsize=%s)\n",
|
||||
it->GetTx().GetHash().ToString(),
|
||||
it->GetTx().GetWitnessHash().ToString(),
|
||||
it->GetFee(),
|
||||
it->GetTxSize(),
|
||||
hash.ToString(),
|
||||
tx.GetWitnessHash().ToString(),
|
||||
entry->GetFee(),
|
||||
entry->GetTxSize());
|
||||
std::string log_string = strprintf("replacing mempool tx %s (wtxid=%s, fees=%s, vsize=%s). ",
|
||||
it->GetTx().GetHash().ToString(),
|
||||
it->GetTx().GetWitnessHash().ToString(),
|
||||
it->GetFee(),
|
||||
it->GetTxSize());
|
||||
FeeFrac feerate{m_subpackage.m_total_modified_fees, int32_t(m_subpackage.m_total_vsize)};
|
||||
uint256 tx_or_package_hash{};
|
||||
const bool replaced_with_tx{m_subpackage.m_changeset->GetTxCount() == 1};
|
||||
if (replaced_with_tx) {
|
||||
const CTransaction& tx = m_subpackage.m_changeset->GetAddedTxn(0);
|
||||
tx_or_package_hash = tx.GetHash();
|
||||
log_string += strprintf("New tx %s (wtxid=%s, fees=%s, vsize=%s)",
|
||||
tx.GetHash().ToString(),
|
||||
tx.GetWitnessHash().ToString(),
|
||||
feerate.fee,
|
||||
feerate.size);
|
||||
} else {
|
||||
tx_or_package_hash = GetPackageHash(m_subpackage.m_changeset->GetAddedTxns());
|
||||
log_string += strprintf("New package %s with %lu txs, fees=%s, vsize=%s",
|
||||
tx_or_package_hash.ToString(),
|
||||
m_subpackage.m_changeset->GetTxCount(),
|
||||
feerate.fee,
|
||||
feerate.size);
|
||||
|
||||
}
|
||||
LogDebug(BCLog::MEMPOOL, "%s\n", log_string);
|
||||
TRACEPOINT(mempool, replaced,
|
||||
it->GetTx().GetHash().data(),
|
||||
it->GetTxSize(),
|
||||
it->GetFee(),
|
||||
std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(it->GetTime()).count(),
|
||||
hash.data(),
|
||||
entry->GetTxSize(),
|
||||
entry->GetFee()
|
||||
tx_or_package_hash.data(),
|
||||
feerate.size,
|
||||
feerate.fee,
|
||||
replaced_with_tx
|
||||
);
|
||||
m_subpackage.m_replaced_transactions.push_back(it->GetSharedTx());
|
||||
}
|
||||
m_pool.RemoveStaged(m_subpackage.m_all_conflicts, false, MemPoolRemovalReason::REPLACED);
|
||||
// Don't attempt to process the same conflicts repeatedly during subpackage evaluation:
|
||||
// they no longer exist on subsequent calls to Finalize() post-RemoveStaged
|
||||
m_subpackage.m_all_conflicts.clear();
|
||||
// Store transaction in memory
|
||||
m_pool.addUnchecked(*entry, ws.m_ancestors);
|
||||
|
||||
// trim mempool and check if tx was trimmed
|
||||
// If we are validating a package, don't trim here because we could evict a previous transaction
|
||||
// in the package. LimitMempoolSize() should be called at the very end to make sure the mempool
|
||||
// is still within limits and package submission happens atomically.
|
||||
if (!args.m_package_submission && !bypass_limits) {
|
||||
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip());
|
||||
if (!m_pool.exists(GenTxid::Txid(hash)))
|
||||
// The tx no longer meets our (new) mempool minimum feerate but could be reconsidered in a package.
|
||||
return state.Invalid(TxValidationResult::TX_RECONSIDERABLE, "mempool full");
|
||||
}
|
||||
return true;
|
||||
m_subpackage.m_changeset->Apply();
|
||||
m_subpackage.m_changeset.reset();
|
||||
}
|
||||
|
||||
bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>& workspaces,
|
||||
|
|
@ -1575,6 +1581,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
|
|||
return !m_pool.exists(GenTxid::Txid(ws.m_ptx->GetHash())); }));
|
||||
|
||||
bool all_submitted = true;
|
||||
FinalizeSubpackage(args);
|
||||
// ConsensusScriptChecks adds to the script cache and is therefore consensus-critical;
|
||||
// CheckInputsFromMempoolAndCache asserts that transactions only spend coins available from the
|
||||
// mempool or UTXO set. Submit each transaction to the mempool immediately after calling
|
||||
|
|
@ -1588,36 +1595,19 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
|
|||
package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR,
|
||||
strprintf("BUG! PolicyScriptChecks succeeded but ConsensusScriptChecks failed: %s",
|
||||
ws.m_ptx->GetHash().ToString()));
|
||||
// Remove the transaction from the mempool.
|
||||
if (!m_subpackage.m_changeset) m_subpackage.m_changeset = m_pool.GetChangeSet();
|
||||
m_subpackage.m_changeset->StageRemoval(m_pool.GetIter(ws.m_ptx->GetHash()).value());
|
||||
}
|
||||
|
||||
// Re-calculate mempool ancestors to call addUnchecked(). They may have changed since the
|
||||
// last calculation done in PreChecks, since package ancestors have already been submitted.
|
||||
{
|
||||
auto ancestors{m_pool.CalculateMemPoolAncestors(*ws.m_entry, m_pool.m_opts.limits)};
|
||||
if(!ancestors) {
|
||||
results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
|
||||
// Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail.
|
||||
Assume(false);
|
||||
all_submitted = false;
|
||||
package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR,
|
||||
strprintf("BUG! Mempool ancestors or descendants were underestimated: %s",
|
||||
ws.m_ptx->GetHash().ToString()));
|
||||
}
|
||||
ws.m_ancestors = std::move(ancestors).value_or(ws.m_ancestors);
|
||||
}
|
||||
// If we call LimitMempoolSize() for each individual Finalize(), the mempool will not take
|
||||
// the transaction's descendant feerate into account because it hasn't seen them yet. Also,
|
||||
// we risk evicting a transaction that a subsequent package transaction depends on. Instead,
|
||||
// allow the mempool to temporarily bypass limits, the maximum package size) while
|
||||
// submitting transactions individually and then trim at the very end.
|
||||
if (!Finalize(args, ws)) {
|
||||
results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
|
||||
// Since LimitMempoolSize() won't be called, this should never fail.
|
||||
Assume(false);
|
||||
all_submitted = false;
|
||||
package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR,
|
||||
strprintf("BUG! Adding to mempool failed: %s", ws.m_ptx->GetHash().ToString()));
|
||||
}
|
||||
}
|
||||
if (!all_submitted) {
|
||||
Assume(m_subpackage.m_changeset);
|
||||
// This code should be unreachable; it's here as belt-and-suspenders
|
||||
// to try to ensure we have no consensus-invalid transactions in the
|
||||
// mempool.
|
||||
m_subpackage.m_changeset->Apply();
|
||||
m_subpackage.m_changeset.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Wtxid> all_package_wtxids;
|
||||
|
|
@ -1634,6 +1624,8 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
|
|||
|
||||
// Add successful results. The returned results may change later if LimitMempoolSize() evicts them.
|
||||
for (Workspace& ws : workspaces) {
|
||||
auto iter = m_pool.GetIter(ws.m_ptx->GetHash());
|
||||
Assume(iter.has_value());
|
||||
const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate :
|
||||
CFeeRate{ws.m_modified_fees, static_cast<uint32_t>(ws.m_vsize)};
|
||||
const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids :
|
||||
|
|
@ -1644,7 +1636,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
|
|||
if (!m_pool.m_opts.signals) continue;
|
||||
const CTransaction& tx = *ws.m_ptx;
|
||||
const auto tx_info = NewMempoolTransactionInfo(ws.m_ptx, ws.m_base_fees,
|
||||
ws.m_vsize, ws.m_entry->GetHeight(),
|
||||
ws.m_vsize, (*iter)->GetHeight(),
|
||||
args.m_bypass_limits, args.m_package_submission,
|
||||
IsCurrentForFeeEstimation(m_active_chainstate),
|
||||
m_pool.HasNoInputsOf(tx));
|
||||
|
|
@ -1669,6 +1661,9 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
|
|||
return MempoolAcceptResult::Failure(ws.m_state);
|
||||
}
|
||||
|
||||
m_subpackage.m_total_vsize = ws.m_vsize;
|
||||
m_subpackage.m_total_modified_fees = ws.m_modified_fees;
|
||||
|
||||
// Individual modified feerate exceeded caller-defined max; abort
|
||||
if (args.m_client_maxfeerate && CFeeRate(ws.m_modified_fees, ws.m_vsize) > args.m_client_maxfeerate.value()) {
|
||||
ws.m_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "max feerate exceeded", "");
|
||||
|
|
@ -1706,17 +1701,24 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
|
|||
ws.m_base_fees, effective_feerate, single_wtxid);
|
||||
}
|
||||
|
||||
if (!Finalize(args, ws)) {
|
||||
// The only possible failure reason is fee-related (mempool full).
|
||||
// Failed for fee reasons. Provide the effective feerate and which txns were included.
|
||||
Assume(ws.m_state.GetResult() == TxValidationResult::TX_RECONSIDERABLE);
|
||||
return MempoolAcceptResult::FeeFailure(ws.m_state, CFeeRate(ws.m_modified_fees, ws.m_vsize), {ws.m_ptx->GetWitnessHash()});
|
||||
FinalizeSubpackage(args);
|
||||
|
||||
// Limit the mempool, if appropriate.
|
||||
if (!args.m_package_submission && !args.m_bypass_limits) {
|
||||
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip());
|
||||
if (!m_pool.exists(GenTxid::Txid(ws.m_hash))) {
|
||||
// The tx no longer meets our (new) mempool minimum feerate but could be reconsidered in a package.
|
||||
ws.m_state.Invalid(TxValidationResult::TX_RECONSIDERABLE, "mempool full");
|
||||
return MempoolAcceptResult::FeeFailure(ws.m_state, CFeeRate(ws.m_modified_fees, ws.m_vsize), {ws.m_ptx->GetWitnessHash()});
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pool.m_opts.signals) {
|
||||
const CTransaction& tx = *ws.m_ptx;
|
||||
auto iter = m_pool.GetIter(tx.GetHash());
|
||||
Assume(iter.has_value());
|
||||
const auto tx_info = NewMempoolTransactionInfo(ws.m_ptx, ws.m_base_fees,
|
||||
ws.m_vsize, ws.m_entry->GetHeight(),
|
||||
ws.m_vsize, (*iter)->GetHeight(),
|
||||
args.m_bypass_limits, args.m_package_submission,
|
||||
IsCurrentForFeeEstimation(m_active_chainstate),
|
||||
m_pool.HasNoInputsOf(tx));
|
||||
|
|
@ -2052,6 +2054,11 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
|
|||
AcceptSubPackage(txns_package_eval, args);
|
||||
PackageValidationState& package_state_final = multi_submission_result.m_state;
|
||||
|
||||
// This is invoked by AcceptSubPackage() already, so this is just here for
|
||||
// clarity (since it's not permitted to invoke LimitMempoolSize() while a
|
||||
// changeset is outstanding).
|
||||
ClearSubPackageState();
|
||||
|
||||
// Make sure we haven't exceeded max mempool size.
|
||||
// Package transactions that were submitted to mempool or already in mempool may be evicted.
|
||||
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue