122 lines
4.9 KiB
Diff
122 lines
4.9 KiB
Diff
# UNDF: UNDF-2026-000001230
|
|
# UNDF: UNDF-PENDING
|
|
--- a/zebra-rpc/src/methods/types/get_block_template/zip317.rs
|
|
+++ b/zebra-rpc/src/methods/types/get_block_template/zip317.rs
|
|
@@ -91,9 +91,11 @@ pub fn select_mempool_transactions(
|
|
// Setup the transaction lists.
|
|
let (mut conventional_fee_txs, mut low_fee_txs): (Vec<_>, Vec<_>) = independent_mempool_txs
|
|
.into_values()
|
|
.partition(VerifiedUnminedTx::pays_conventional_fee);
|
|
|
|
let mut selected_txs = Vec::new();
|
|
+ // HashSet of selected tx IDs for O(1) dependency satisfaction checks.
|
|
+ let mut selected_tx_ids: HashSet<transaction::Hash> = HashSet::new();
|
|
|
|
// Set up limit tracking
|
|
let mut remaining_block_bytes: usize = MAX_BLOCK_BYTES.try_into().expect("fits in memory");
|
|
@@ -108,7 +110,7 @@ pub fn select_mempool_transactions(
|
|
while let Some(tx_weights) = conventional_fee_tx_weights {
|
|
conventional_fee_tx_weights = checked_add_transaction_weighted_random(
|
|
&mut conventional_fee_txs,
|
|
&mut dependent_mempool_txs,
|
|
tx_weights,
|
|
&mut selected_txs,
|
|
+ &mut selected_tx_ids,
|
|
&mempool_tx_deps,
|
|
&mut remaining_block_bytes,
|
|
&mut remaining_block_sigops,
|
|
@@ -122,7 +124,7 @@ pub fn select_mempool_transactions(
|
|
while let Some(tx_weights) = low_fee_tx_weights {
|
|
low_fee_tx_weights = checked_add_transaction_weighted_random(
|
|
&mut low_fee_txs,
|
|
&mut dependent_mempool_txs,
|
|
tx_weights,
|
|
&mut selected_txs,
|
|
+ &mut selected_tx_ids,
|
|
&mempool_tx_deps,
|
|
&mut remaining_block_bytes,
|
|
&mut remaining_block_sigops,
|
|
@@ -210,20 +212,16 @@ fn dependencies_depth(
|
|
/// Checks if every item in `candidate_tx_deps` is present in `selected_txs`.
|
|
///
|
|
-/// Requires items in `selected_txs` to be unique to work correctly.
|
|
-fn has_direct_dependencies(
|
|
+/// Uses a pre-built `selected_tx_ids` HashSet for O(D) membership checks
|
|
+/// instead of scanning the entire Vec<SelectedMempoolTx> in O(S) per call.
|
|
+fn has_direct_dependencies(
|
|
candidate_tx_deps: Option<&HashSet<transaction::Hash>>,
|
|
- selected_txs: &Vec<SelectedMempoolTx>,
|
|
+ selected_tx_ids: &HashSet<transaction::Hash>,
|
|
) -> bool {
|
|
let Some(deps) = candidate_tx_deps else {
|
|
return true;
|
|
};
|
|
|
|
- if selected_txs.len() < deps.len() {
|
|
- return false;
|
|
- }
|
|
-
|
|
- let mut num_available_deps = 0;
|
|
- for tx in selected_txs {
|
|
- #[cfg(test)]
|
|
- let (_, tx) = tx;
|
|
- if deps.contains(&tx.transaction.id.mined_id()) {
|
|
- num_available_deps += 1;
|
|
- } else {
|
|
- continue;
|
|
- }
|
|
-
|
|
- if num_available_deps == deps.len() {
|
|
- return true;
|
|
- }
|
|
- }
|
|
-
|
|
- false
|
|
+ // O(D) where D = number of direct dependencies (typically 1-3).
|
|
+ // Previously O(S) where S = number of already-selected transactions.
|
|
+ deps.iter().all(|dep_id| selected_tx_ids.contains(dep_id))
|
|
}
|
|
|
|
/// Chooses a random transaction from `txs` using the weighted index `tx_weights`,
|
|
@@ -275,6 +273,7 @@ fn checked_add_transaction_weighted_random(
|
|
candidate_txs: &mut Vec<VerifiedUnminedTx>,
|
|
dependent_txs: &mut HashMap<transaction::Hash, VerifiedUnminedTx>,
|
|
tx_weights: WeightedIndex<f32>,
|
|
selected_txs: &mut Vec<SelectedMempoolTx>,
|
|
+ selected_tx_ids: &mut HashSet<transaction::Hash>,
|
|
mempool_tx_deps: &TransactionDependencies,
|
|
remaining_block_bytes: &mut usize,
|
|
remaining_block_sigops: &mut u32,
|
|
@@ -298,11 +297,14 @@ fn checked_add_transaction_weighted_random(
|
|
"all candidate transactions should be independent"
|
|
);
|
|
|
|
+ selected_tx_ids.insert(*selected_tx_id);
|
|
+
|
|
#[cfg(not(test))]
|
|
selected_txs.push(candidate_tx);
|
|
|
|
#[cfg(test)]
|
|
selected_txs.push((0, candidate_tx));
|
|
|
|
// Try adding any dependent transactions if all of their dependencies have been selected.
|
|
|
|
let mut current_level_dependents = mempool_tx_deps.direct_dependents(selected_tx_id);
|
|
@@ -314,7 +316,7 @@ fn checked_add_transaction_weighted_random(
|
|
// the selected txs, which come from the mempool. If the tx also spends in-chain outputs, it won't
|
|
// be added. This behavior is not specified by consensus rules and can be changed at any time,
|
|
// meaning that such txs could be added.
|
|
- if has_direct_dependencies(tx_dependencies.get(dependent_tx_id), selected_txs) {
|
|
+ if has_direct_dependencies(tx_dependencies.get(dependent_tx_id), selected_tx_ids) {
|
|
let Some(candidate_tx) = dependent_txs.remove(dependent_tx_id) else {
|
|
continue;
|
|
};
|
|
@@ -337,6 +339,8 @@ fn checked_add_transaction_weighted_random(
|
|
continue;
|
|
}
|
|
|
|
+ selected_tx_ids.insert(*dependent_tx_id);
|
|
+
|
|
#[cfg(not(test))]
|
|
selected_txs.push(candidate_tx);
|
|
|