Skip to content

Commit 3f033f0

Browse files
committed
MOVEONLY: check for disjoint conflicts and ancestors to policy/rbf
This checks that a transaction isn't trying to replace something it supposedly depends on.
1 parent 7b60c02 commit 3f033f0

File tree

3 files changed

+32
-10
lines changed

3 files changed

+32
-10
lines changed

src/policy/rbf.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,20 @@ std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx,
112112
}
113113
return std::nullopt;
114114
}
115+
116+
std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& setAncestors,
117+
const std::set<uint256>& setConflicts,
118+
const uint256& txid)
119+
{
120+
for (CTxMemPool::txiter ancestorIt : setAncestors)
121+
{
122+
const uint256 &hashAncestor = ancestorIt->GetTx().GetHash();
123+
if (setConflicts.count(hashAncestor))
124+
{
125+
return strprintf("%s spends conflicting transaction %s",
126+
txid.ToString(),
127+
hashAncestor.ToString());
128+
}
129+
}
130+
return std::nullopt;
131+
}

src/policy/rbf.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,17 @@ std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx, CTxMem
5656
std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx, const CTxMemPool& m_pool,
5757
const CTxMemPool::setEntries& setIterConflicting)
5858
EXCLUSIVE_LOCKS_REQUIRED(m_pool.cs);
59+
60+
/** Check the intersection between two sets of transactions (a set of mempool entries and a set of
61+
* txids) to make sure they are disjoint.
62+
* @param[in] setAncestors Set of mempool entries corresponding to ancestors of the
63+
* replacement transactions.
64+
* @param[in] setConflicts Set of txids corresponding to the mempool conflicts
65+
* (candidates to be replaced).
66+
* @param[in] txid Transaction ID, included in the error message if violation occurs.
67+
* @returns error message if the sets intersect, std::nullopt if they are disjoint.
68+
*/
69+
std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& setAncestors,
70+
const std::set<uint256>& setConflicts,
71+
const uint256& txid);
5972
#endif // BITCOIN_POLICY_RBF_H

src/validation.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -770,16 +770,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
770770
// that we have the set of all ancestors we can detect this
771771
// pathological case by making sure setConflicts and setAncestors don't
772772
// intersect.
773-
for (CTxMemPool::txiter ancestorIt : setAncestors)
774-
{
775-
const uint256 &hashAncestor = ancestorIt->GetTx().GetHash();
776-
if (setConflicts.count(hashAncestor))
777-
{
778-
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-spends-conflicting-tx",
779-
strprintf("%s spends conflicting transaction %s",
780-
hash.ToString(),
781-
hashAncestor.ToString()));
782-
}
773+
if (const auto err_string{EntriesAndTxidsDisjoint(setAncestors, setConflicts, hash)}) {
774+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-spends-conflicting-tx", *err_string);
783775
}
784776

785777

0 commit comments

Comments
 (0)