@@ -585,22 +585,27 @@ class MemPoolAccept
585
585
// of checking a given transaction.
586
586
struct Workspace {
587
587
explicit Workspace (const CTransactionRef& ptx) : m_ptx(ptx), m_hash(ptx->GetHash ()) {}
588
- /* * Txids of mempool transactions that this transaction directly conflicts with. */
588
+ /* * Txids of mempool transactions that this transaction directly conflicts with or may
589
+ * replace via sibling eviction. */
589
590
std::set<Txid> m_conflicts;
590
- /* * Iterators to mempool entries that this transaction directly conflicts with. */
591
+ /* * Iterators to mempool entries that this transaction directly conflicts with or may
592
+ * replace via sibling eviction. */
591
593
CTxMemPool::setEntries m_iters_conflicting;
592
594
/* * Iterators to all mempool entries that would be replaced by this transaction, including
593
- * those it directly conflicts with and their descendants. */
595
+ * m_conflicts and their descendants. */
594
596
CTxMemPool::setEntries m_all_conflicting;
595
597
/* * All mempool ancestors of this transaction. */
596
598
CTxMemPool::setEntries m_ancestors;
597
599
/* * Mempool entry constructed for this transaction. Constructed in PreChecks() but not
598
600
* inserted into the mempool until Finalize(). */
599
601
std::unique_ptr<CTxMemPoolEntry> m_entry;
600
602
/* * Pointers to the transactions that have been removed from the mempool and replaced by
601
- * this transaction, used to return to the MemPoolAccept caller. Only populated if
603
+ * this transaction (everything in m_all_conflicting) , used to return to the MemPoolAccept caller. Only populated if
602
604
* validation is successful and the original transactions are removed. */
603
605
std::list<CTransactionRef> m_replaced_transactions;
606
+ /* * Whether RBF-related data structures (m_conflicts, m_iters_conflicting, m_all_conflicting,
607
+ * m_replaced_transactions) include a sibling in addition to txns with conflicting inputs. */
608
+ bool m_sibling_eviction{false };
604
609
605
610
/* * Virtual size of the transaction as used by the mempool, calculated using serialized size
606
611
* of the transaction and sigops. */
@@ -690,7 +695,8 @@ class MemPoolAccept
690
695
691
696
Chainstate& m_active_chainstate;
692
697
693
- /* * Whether the transaction(s) would replace any mempool transactions. If so, RBF rules apply. */
698
+ /* * Whether the transaction(s) would replace any mempool transactions and/or evict any siblings.
699
+ * If so, RBF rules apply. */
694
700
bool m_rbf{false };
695
701
};
696
702
@@ -954,8 +960,27 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
954
960
}
955
961
956
962
ws.m_ancestors = *ancestors;
963
+ // Even though just checking direct mempool parents for inheritance would be sufficient, we
964
+ // check using the full ancestor set here because it's more convenient to use what we have
965
+ // already calculated.
957
966
if (const auto err{SingleV3Checks (ws.m_ptx , ws.m_ancestors , ws.m_conflicts , ws.m_vsize )}) {
958
- return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " v3-rule-violation" , err->first );
967
+ // Disabled within package validation.
968
+ if (err->second != nullptr && args.m_allow_replacement ) {
969
+ // Potential sibling eviction. Add the sibling to our list of mempool conflicts to be
970
+ // included in RBF checks.
971
+ ws.m_conflicts .insert (err->second ->GetHash ());
972
+ // Adding the sibling to m_iters_conflicting here means that it doesn't count towards
973
+ // RBF Carve Out above. This is correct, since removing to-be-replaced transactions from
974
+ // the descendant count is done separately in SingleV3Checks for v3 transactions.
975
+ ws.m_iters_conflicting .insert (m_pool.GetIter (err->second ->GetHash ()).value ());
976
+ ws.m_sibling_eviction = true ;
977
+ // The sibling will be treated as part of the to-be-replaced set in ReplacementChecks.
978
+ // Note that we are not checking whether it opts in to replaceability via BIP125 or v3
979
+ // (which is normally done in PreChecks). However, the only way a v3 transaction can
980
+ // have a non-v3 and non-BIP125 descendant is due to a reorg.
981
+ } else {
982
+ return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " v3-rule-violation" , err->first );
983
+ }
959
984
}
960
985
961
986
// A transaction that spends outputs that would be replaced by it is invalid. Now
@@ -995,18 +1020,21 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
995
1020
// Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not
996
1021
// TX_RECONSIDERABLE, because it cannot be bypassed using package validation.
997
1022
// This must be changed if package RBF is enabled.
998
- return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " insufficient fee" , *err_string);
1023
+ return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY,
1024
+ strprintf (" insufficient fee%s" , ws.m_sibling_eviction ? " (including sibling eviction)" : " " ), *err_string);
999
1025
}
1000
1026
1001
1027
// Calculate all conflicting entries and enforce Rule #5.
1002
1028
if (const auto err_string{GetEntriesForConflicts (tx, m_pool, ws.m_iters_conflicting , ws.m_all_conflicting )}) {
1003
1029
return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY,
1004
- " too many potential replacements" , *err_string);
1030
+ strprintf ( " too many potential replacements%s " , ws. m_sibling_eviction ? " (including sibling eviction) " : " " ) , *err_string);
1005
1031
}
1006
1032
// Enforce Rule #2.
1007
1033
if (const auto err_string{HasNoNewUnconfirmed (tx, m_pool, ws.m_iters_conflicting )}) {
1034
+ // Sibling eviction is only done for v3 transactions, which cannot have multiple ancestors.
1035
+ Assume (!ws.m_sibling_eviction );
1008
1036
return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY,
1009
- " replacement-adds-unconfirmed" , *err_string);
1037
+ strprintf ( " replacement-adds-unconfirmed%s " , ws. m_sibling_eviction ? " (including sibling eviction) " : " " ) , *err_string);
1010
1038
}
1011
1039
// Check if it's economically rational to mine this transaction rather than the ones it
1012
1040
// replaces and pays for its own relay fees. Enforce Rules #3 and #4.
@@ -1019,7 +1047,8 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
1019
1047
// Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not
1020
1048
// TX_RECONSIDERABLE, because it cannot be bypassed using package validation.
1021
1049
// This must be changed if package RBF is enabled.
1022
- return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " insufficient fee" , *err_string);
1050
+ return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY,
1051
+ strprintf (" insufficient fee%s" , ws.m_sibling_eviction ? " (including sibling eviction)" : " " ), *err_string);
1023
1052
}
1024
1053
return true ;
1025
1054
}
0 commit comments