Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions minotari-scanning/src/scanning/http/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,14 @@ where
"start_height cannot be greater than end_height".to_string(),
));
}
let tip = self.get_tip_info().await?;
if tip.best_block_height <= config.start_height {
debug!(
"Tip height {} is less than requested start height {}, returning empty results",
tip.best_block_height, config.start_height
);
return Ok((Vec::new(), false));
}

match &self.current_in_progress.get_config() {
Some(existing_scan) if *existing_scan == config => {
Expand Down
2 changes: 0 additions & 2 deletions minotari/src/scan/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ impl<E: EventSender + Clone + Send + 'static> ScanCoordinator<E> {
) -> Result<AccountSyncTarget, ScanError> {
let key_manager = account.get_key_manager(password)?;
let view_key = key_manager.get_private_view_key();

let reorg_result = reorg::handle_reorgs(scanner, conn, account.id, self.webhook_config.clone())
.await
.map_err(ScanError::Fatal)?;
Expand Down Expand Up @@ -391,7 +390,6 @@ impl<E: EventSender + Clone + Send + 'static> ScanCoordinator<E> {
}

let mut conn = db_handler.get_connection().await?;

for target in targets {
let res = reorg::handle_reorgs(scanner, &mut conn, target.account.id, self.webhook_config.clone())
.await
Expand Down
2 changes: 0 additions & 2 deletions minotari/src/scan/reorg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ pub async fn handle_reorgs(
reorg_information: None,
});
}

let mut reorg_start_height = 0;
let mut is_reorg_detected = false;

Expand All @@ -67,7 +66,6 @@ pub async fn handle_reorgs(
is_reorg_detected = true;
}
}

if is_reorg_detected {
warn!(
target: "audit",
Expand Down
3 changes: 0 additions & 3 deletions minotari/src/scan/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,6 @@ async fn wait_for_next_poll_cycle<E: EventSender>(
}

let mut conn = db_handler.get_connection().await?;

let reorg_result = reorg::handle_reorgs(&mut scanner_context.scanner, &mut conn, scanner_context.account_id)
.await
.map_err(ScanError::Fatal)?;
Expand Down Expand Up @@ -423,7 +422,6 @@ async fn prepare_account_scan(
let mut scanner = HttpBlockchainScanner::new(base_url.to_string(), vec![key_manager.clone()], processing_threads)
.await
.map_err(|e| ScanError::Intermittent(e.to_string()))?;

let reorg_result = reorg::handle_reorgs(&mut scanner, conn, account.id)
.await
.map_err(ScanError::Fatal)?;
Expand Down Expand Up @@ -615,7 +613,6 @@ async fn run_scan_loop<E: EventSender + Clone + Send + 'static>(
}));
}
}

if more_blocks && blocks_since_reorg_check >= scanner_context.reorg_check_interval {
let mut conn = db_handler.get_connection().await?;
let reorg_result =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::scan::block_event_accumulator::BlockEventAccumulator;
use crate::scan::{DetectedOutput, MemoInfo, SpentInput};
use log::debug;
use rusqlite::Connection;
use std::cmp::Reverse;
use std::collections::HashMap;
use tari_common_types::transaction::TxId;
use tari_common_types::types::FixedHash;
Expand Down Expand Up @@ -112,6 +113,7 @@ impl DisplayedTransactionProcessor {
// we need to create a new display tx for this input
new_debit.push((balance_change.clone(), output.clone()));
}
new_debit.sort_by_key(|a| a.1.output.value());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The new_debit vector is sorted in ascending order by output value. For a branch-and-bound algorithm like iter_search_for_matching_inputs, sorting inputs in descending order of value can often lead to faster convergence by pruning branches earlier. Since std::cmp::Reverse is imported but not used, consider sorting in reverse order to potentially improve performance. If iter_search_for_matching_inputs is not on a critical path and is used infrequently, this optimization could be deferred as per repository guidelines on performance trade-offs.

Suggested change
new_debit.sort_by_key(|a| a.1.output.value());
new_debit.sort_by_key(|a| Reverse(a.1.output.value()));
References
  1. Performance optimizations for functions not on a critical path and used infrequently can be deferred, noting the trade-off.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gemini-code-assist
because we want search for explicit matches, if we sort the branch ascending order, when we get to the actual search algorhtim, we can do this:

let new_total = amount_already_selected + input_value;
            if new_total > amount_sent {
                return false;
            }

there by pruning the branch.
If we do decending order, we cannot do this and we have to finish searching that entire order

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You make a very good point. My suggestion was based on a general heuristic for branch-and-bound algorithms, where sorting in descending order can often lead to faster convergence by finding a solution quicker or pruning branches that quickly exceed the target. However, for your specific implementation, where you are looking for an exact match and have the pruning condition if new_total > amount_sent { return false; }, sorting the inputs in ascending order is indeed more effective. This allows you to prune branches as soon as the sum exceeds amount_sent, knowing that any subsequent (larger) inputs would also exceed the target. Thank you for clarifying the specific logic of iter_search_for_matching_inputs.


//Now we have a list of inputs and outputs that don't have matching transactions
let mut new_transactions = Vec::new();
Expand Down Expand Up @@ -165,7 +167,7 @@ impl DisplayedTransactionProcessor {
// So this is change from our wallet.
let total_send =
amount + output.output.value() + output.output.payment_id().get_fee().unwrap_or_default();
let mut selected_inputs = Vec::new();
let mut selected_inputs = Vec::with_capacity(new_debit.len());
if Self::iter_search_for_matching_inputs(
total_send,
MicroMinotari::from(0),
Expand Down Expand Up @@ -255,34 +257,32 @@ impl DisplayedTransactionProcessor {
fn iter_search_for_matching_inputs(
amount_sent: MicroMinotari,
amount_already_selected: MicroMinotari,
spent_inputs: &Vec<(BalanceChange, SpentInput)>,
spent_inputs: &[(BalanceChange, SpentInput)],
selected_inputs: &mut Vec<usize>,
start_index: usize,
) -> bool {
for i in start_index..spent_inputs.len() {
if selected_inputs.contains(&i) {
continue;
}
let input = &spent_inputs.get(i).expect("index is in bounds");
if amount_already_selected + input.1.output.value() > amount_sent {
continue;
let input_value = spent_inputs.get(i).expect("bounds are checked").1.output.value();
let new_total = amount_already_selected + input_value;
if new_total > amount_sent {
return false;
}
let new_total = amount_already_selected + input.1.output.value();

if new_total == amount_sent {
selected_inputs.push(i);
// we have our match, stop searching
selected_inputs.push(i);
return true;
}
// search this branch further
let mut new_selected = selected_inputs.clone();
new_selected.push(i);
if Self::iter_search_for_matching_inputs(amount_sent, new_total, spent_inputs, &mut new_selected, i + 1) {
*selected_inputs = new_selected;
if i + 1 == spent_inputs.len() {
return false;
}
// search this branch further; backtrack if no match found
selected_inputs.push(i);
if Self::iter_search_for_matching_inputs(amount_sent, new_total, spent_inputs, selected_inputs, i + 1) {
return true;
}
//on to next output
selected_inputs.pop();
}
// no match found in this search branch
false
}

Expand Down
Loading