| 1039 | } |
| 1040 | |
| 1041 | bool MemPoolAccept::PackageRBFChecks(const std::vector<CTransactionRef>& txns, |
| 1042 | std::vector<Workspace>& workspaces, |
| 1043 | const int64_t total_vsize, |
| 1044 | PackageValidationState& package_state) |
| 1045 | { |
| 1046 | AssertLockHeld(cs_main); |
| 1047 | AssertLockHeld(m_pool.cs); |
| 1048 | |
| 1049 | assert(std::all_of(txns.cbegin(), txns.cend(), [this](const auto& tx) |
| 1050 | { return !m_pool.exists(tx->GetHash());})); |
| 1051 | |
| 1052 | assert(txns.size() == workspaces.size()); |
| 1053 | |
| 1054 | // We're in package RBF context; replacement proposal must be size 2 |
| 1055 | if (workspaces.size() != 2 || !Assume(IsChildWithParents(txns))) { |
| 1056 | return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package RBF failed: package must be 1-parent-1-child"); |
| 1057 | } |
| 1058 | |
| 1059 | // If the package has in-mempool parents, we won't consider a package RBF |
| 1060 | // since it would result in a cluster larger than 2. |
| 1061 | // N.B. To relax this constraint we will need to revisit how CCoinsViewMemPool::PackageAddTransaction |
| 1062 | // is being used inside AcceptMultipleTransactions to track available inputs while processing a package. |
| 1063 | // Specifically we would need to check that the ancestors of the new |
| 1064 | // transactions don't intersect with the set of transactions to be removed |
| 1065 | // due to RBF, which is not checked at all in the package acceptance |
| 1066 | // context. |
| 1067 | for (const auto& ws : workspaces) { |
| 1068 | if (!ws.m_parents.empty()) { |
| 1069 | return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package RBF failed: new transaction cannot have mempool ancestors"); |
| 1070 | } |
| 1071 | } |
| 1072 | |
| 1073 | // Aggregate all conflicts into one set. |
| 1074 | CTxMemPool::setEntries direct_conflict_iters; |
| 1075 | for (Workspace& ws : workspaces) { |
| 1076 | // Aggregate all conflicts into one set. |
| 1077 | direct_conflict_iters.merge(ws.m_iters_conflicting); |
| 1078 | } |
| 1079 | |
| 1080 | const auto& parent_ws = workspaces[0]; |
| 1081 | const auto& child_ws = workspaces[1]; |
| 1082 | |
| 1083 | // Don't consider replacements that would cause us to remove a large number of mempool entries. |
| 1084 | // This limit is not increased in a package RBF. Use the aggregate number of transactions. |
| 1085 | CTxMemPool::setEntries all_conflicts; |
| 1086 | if (const auto err_string{GetEntriesForConflicts(*child_ws.m_ptx, m_pool, direct_conflict_iters, |
| 1087 | all_conflicts)}) { |
| 1088 | return package_state.Invalid(PackageValidationResult::PCKG_POLICY, |
| 1089 | "package RBF failed: too many potential replacements", *err_string); |
| 1090 | } |
| 1091 | |
| 1092 | for (CTxMemPool::txiter it : all_conflicts) { |
| 1093 | m_subpackage.m_changeset->StageRemoval(it); |
| 1094 | m_subpackage.m_conflicting_fees += it->GetModifiedFee(); |
| 1095 | m_subpackage.m_conflicting_size += it->GetTxSize(); |
| 1096 | } |
| 1097 | |
| 1098 | // Use the child as the transaction for attributing errors to. |
nothing calls this directly
no test coverage detected