aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorglozow <gloriajzhao@gmail.com>2022-01-25 11:39:03 +0000
committerglozow <gloriajzhao@gmail.com>2022-04-05 18:51:37 -0400
commit1b93748c937e870e7574a8e120a85bee6f9013ff (patch)
treed9b93020e1d810a3126c4ae7f31f904f3e58f701 /src
parent17a8ffd8020375d60428695858558f2be264aa36 (diff)
downloadbitcoin-1b93748c937e870e7574a8e120a85bee6f9013ff.tar.xz
[validation] try individual validation before package validation
This avoids "parents pay for children" and "siblings pay for siblings" behavior, since package feerate is calculated with totals and is topology-unaware. It also ensures that package validation never causes us to reject a transaction that we would have otherwise accepted in single-tx validation.
Diffstat (limited to 'src')
-rw-r--r--src/validation.cpp31
1 files changed, 29 insertions, 2 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index 42c2189668..446eac5aa1 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -508,6 +508,19 @@ public:
};
}
+ /** Parameters for a single transaction within a package. */
+ static ATMPArgs SingleInPackageAccept(const ATMPArgs& package_args) {
+ return ATMPArgs{/* m_chainparams */ package_args.m_chainparams,
+ /* m_accept_time */ package_args.m_accept_time,
+ /* m_bypass_limits */ false,
+ /* m_coins_to_uncache */ package_args.m_coins_to_uncache,
+ /* m_test_accept */ package_args.m_test_accept,
+ /* m_allow_bip125_replacement */ true,
+ /* m_package_submission */ false,
+ /* m_package_feerates */ false, // only 1 transaction
+ };
+ }
+
private:
// Private ctor to avoid exposing details to clients and allowing the possibility of
// mixing up the order of the arguments. Use static functions above instead.
@@ -1328,6 +1341,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
// transactions that are already in the mempool, and only call AcceptMultipleTransactions() with
// the new transactions. This ensures we don't double-count transaction counts and sizes when
// checking ancestor/descendant limits, or double-count transaction fees for fee-related policy.
+ ATMPArgs single_args = ATMPArgs::SingleInPackageAccept(args);
std::vector<CTransactionRef> txns_new;
for (const auto& tx : package) {
const auto& wtxid = tx->GetWitnessHash();
@@ -1354,18 +1368,31 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
results.emplace(wtxid, MempoolAcceptResult::MempoolTxDifferentWitness(iter.value()->GetTx().GetWitnessHash()));
} else {
// Transaction does not already exist in the mempool.
- txns_new.push_back(tx);
+ // Try submitting the transaction on its own.
+ const auto single_res = AcceptSingleTransaction(tx, single_args);
+ if (single_res.m_result_type == MempoolAcceptResult::ResultType::VALID) {
+ // The transaction succeeded on its own and is now in the mempool. Don't include it
+ // in package validation, because its fees should only be "used" once.
+ assert(m_pool.exists(GenTxid::Wtxid(wtxid)));
+ results.emplace(wtxid, single_res);
+ } else {
+ txns_new.push_back(tx);
+ }
}
}
// Nothing to do if the entire package has already been submitted.
- if (txns_new.empty()) return PackageMempoolAcceptResult(package_state, std::move(results));
+ if (txns_new.empty()) {
+ // No package feerate when no package validation was done.
+ return PackageMempoolAcceptResult(package_state, std::move(results));
+ }
// Validate the (deduplicated) transactions as a package.
auto submission_result = AcceptMultipleTransactions(txns_new, args);
// Include already-in-mempool transaction results in the final result.
for (const auto& [wtxid, mempoolaccept_res] : results) {
submission_result.m_tx_results.emplace(wtxid, mempoolaccept_res);
}
+ if (submission_result.m_state.IsValid()) assert(submission_result.m_package_feerate.has_value());
return submission_result;
}