diff --git a/wallet/src/checker.rs b/wallet/src/checker.rs index 38a5abe1f..4657b6676 100644 --- a/wallet/src/checker.rs +++ b/wallet/src/checker.rs @@ -50,7 +50,7 @@ fn mark_spent_output(out: &mut OutputData) { } } -/// Builds a single api query to retrieve the latest output data from the node. +/// Builds multiple api queries to retrieve the latest output data from the node. /// So we can refresh the local wallet outputs. pub fn refresh_outputs(config: &WalletConfig, keychain: &Keychain) -> Result<(), Error> { debug!(LOGGER, "Refreshing wallet outputs"); @@ -66,14 +66,16 @@ pub fn refresh_outputs(config: &WalletConfig, keychain: &Keychain) -> Result<(), .filter(|out| out.root_key_id == keychain.root_key_id()) .filter(|out| out.status != OutputStatus::Spent) { - let commit = keychain.commit_with_key_index(out.value, out.n_child).unwrap(); + let commit = keychain + .commit_with_key_index(out.value, out.n_child) + .unwrap(); commits.push(commit); wallet_outputs.insert(commit, out.key_id.clone()); } }); // build the necessary query params - - // ?id=xxx&id=yyy&id=zzz + // ?id=xxx&id=yyy&id=zzz let query_params: Vec = commits .iter() .map(|commit| { @@ -81,38 +83,56 @@ pub fn refresh_outputs(config: &WalletConfig, keychain: &Keychain) -> Result<(), format!("id={}", id) }) .collect(); - let query_string = query_params.join("&"); - - let url = format!( - "{}/v1/chain/utxos/byids?{}", - config.check_node_api_http_addr, - query_string, - ); // build a map of api outputs by commit so we can look them up efficiently let mut api_outputs: HashMap = HashMap::new(); - match api::client::get::>(url.as_str()) { - Ok(outputs) => for out in outputs { - api_outputs.insert(out.commit, out); - }, - Err(e) => { - // if we got anything other than 200 back from server, don't attempt to refresh the wallet - // data after - return Err(Error::Node(e)); + + // size of the batch size for the utxo query + let batch_query_size = 500; + + let mut index_id = 0; + while index_id < query_params.len() { + let batch_query: Vec; + if index_id + batch_query_size > query_params.len() { + batch_query = query_params[index_id..query_params.len()].to_vec(); + index_id = query_params.len(); + } else { + batch_query = query_params[index_id..index_id + batch_query_size].to_vec(); + index_id = index_id + batch_query_size; } - }; + + let query_string = batch_query.join("&"); + + let url = format!( + "{}/v1/chain/utxos/byids?{}", + config.check_node_api_http_addr, query_string, + ); + + match api::client::get::>(url.as_str()) { + Ok(outputs) => for out in outputs { + api_outputs.insert(out.commit, out); + }, + Err(e) => { + // if we got anything other than 200 back from server, don't attempt to refresh + // the wallet data after + return Err(Error::Node(e)); + } + }; + } // now for each commit, find the output in the wallet and - // the corresponding api output (if it exists) - // and refresh it in-place in the wallet. - // Note: minimizing the time we spend holding the wallet lock. - WalletData::with_wallet(&config.data_file_dir, |wallet_data| for commit in commits { - let id = wallet_outputs.get(&commit).unwrap(); - if let Entry::Occupied(mut output) = wallet_data.outputs.entry(id.to_hex()) { - match api_outputs.get(&commit) { - Some(api_output) => refresh_output(&mut output.get_mut(), api_output), - None => mark_spent_output(&mut output.get_mut()), - }; + // the corresponding api output (if it exists) + // and refresh it in-place in the wallet. + // Note: minimizing the time we spend holding the wallet lock. + WalletData::with_wallet(&config.data_file_dir, |wallet_data| { + for commit in commits { + let id = wallet_outputs.get(&commit).unwrap(); + if let Entry::Occupied(mut output) = wallet_data.outputs.entry(id.to_hex()) { + match api_outputs.get(&commit) { + Some(api_output) => refresh_output(&mut output.get_mut(), api_output), + None => mark_spent_output(&mut output.get_mut()), + }; + } } }) }