Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-756 #426

Merged
merged 11 commits into from
Mar 24, 2024
65 changes: 36 additions & 29 deletions node/src/accountant/db_access_objects/pending_payable_dao.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use crate::accountant::{checked_conversion, comma_joined_stringifiable};
use crate::blockchain::blockchain_bridge::PendingPayableFingerprint;
use crate::database::rusqlite_wrappers::ConnectionWrapper;
use crate::sub_lib::wallet::Wallet;
use itertools::Itertools;
use masq_lib::utils::ExpectValue;
use rusqlite::Row;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt::Debug;
use std::str::FromStr;
use std::time::SystemTime;
use web3::types::H256;
Expand All @@ -26,9 +26,15 @@ pub enum PendingPayableDaoError {
ErrorMarkFailed(String),
}

#[derive(Debug)]
pub struct TransactionHashes {
pub rowid_results: Vec<(u64, H256)>,
pub no_rowid_results: Vec<H256>,
}

pub trait PendingPayableDao {
// Note that the order of the returned results is not guaranteed
fn fingerprints_rowids(&self, hashes: &[H256]) -> Vec<(Option<u64>, H256)>;
fn fingerprints_rowids(&self, hashes: &[H256]) -> TransactionHashes;
fn return_all_errorless_fingerprints(&self) -> Vec<PendingPayableFingerprint>;
fn insert_new_fingerprints(
&self,
Expand All @@ -41,35 +47,43 @@ pub trait PendingPayableDao {
}

impl PendingPayableDao for PendingPayableDaoReal<'_> {
fn fingerprints_rowids(&self, hashes: &[H256]) -> Vec<(Option<u64>, H256)> {
fn hash_and_rowid_in_single_row(row: &Row) -> rusqlite::Result<(H256, u64)> {
fn fingerprints_rowids(&self, hashes: &[H256]) -> TransactionHashes {
//Vec<(Option<u64>, H256)> {
fn hash_and_rowid_in_single_row(row: &Row) -> rusqlite::Result<(u64, H256)> {
let hash_str: String = row.get(0).expectv("hash");
let hash = H256::from_str(&hash_str[2..]).expect("hash inserted right turned wrong");
let sqlite_signed_rowid: i64 = row.get(1).expectv("rowid");
let rowid = u64::try_from(sqlite_signed_rowid).expect("SQlite goes from 1 to i64:MAX");
Ok((hash, rowid))
Ok((rowid, hash))
}

let sql = format!(
"select transaction_hash, rowid from pending_payable where transaction_hash in ({})",
comma_joined_stringifiable(hashes, |hash| format!("'{:?}'", hash))
);

let all_found_records = self
.conn
.prepare(&sql)
.expect("Internal error")
.query_map([], hash_and_rowid_in_single_row)
.expect("map query failed")
.vigilant_flatten()
.collect::<HashMap<H256, u64>>();
let hashes_of_missing_rowids = hashes
.collect::<Vec<(u64, H256)>>();
let hashes_of_found_records = all_found_records
.iter()
.filter(|hash| !all_found_records.keys().contains(hash));
all_found_records
.map(|(_, hash)| *hash)
.collect::<HashSet<H256>>();
let hashes_of_missing_rowids = hashes
.iter()
.map(|(hash, rowid)| (Some(*rowid), *hash))
.chain(hashes_of_missing_rowids.map(|hash| (None, *hash)))
.collect()
.filter(|hash| !hashes_of_found_records.contains(hash))
.cloned()
.collect();

TransactionHashes {
rowid_results: all_found_records,
no_rowid_results: hashes_of_missing_rowids,
}
}

fn return_all_errorless_fingerprints(&self) -> Vec<PendingPayableFingerprint> {
Expand Down Expand Up @@ -403,21 +417,21 @@ mod tests {

let result = subject.fingerprints_rowids(&[hash_1, hash_2]);

let first_expected_pair = (Some(1), hash_1);
let first_expected_pair = &(1, hash_1);
assert!(
result.contains(&first_expected_pair),
result.rowid_results.contains(first_expected_pair),
"Returned rowid pairs should have contained {:?} but all it did is {:?}",
first_expected_pair,
result
result.rowid_results
);
let second_expected_pair = (Some(2), hash_2);
let second_expected_pair = &(2, hash_2);
assert!(
result.contains(&second_expected_pair),
result.rowid_results.contains(second_expected_pair),
"Returned rowid pairs should have contained {:?} but all it did is {:?}",
second_expected_pair,
result
result.rowid_results
);
assert_eq!(result.len(), 2);
assert_eq!(result.rowid_results.len(), 2);
}

#[test]
Expand Down Expand Up @@ -447,15 +461,8 @@ mod tests {

let result = subject.fingerprints_rowids(&[hash_1, hash_2, hash_3, hash_4]);

assert_eq!(
result,
vec![
(Some(2), hash_3),
(None, hash_1),
(None, hash_2),
(None, hash_4)
]
)
assert_eq!(result.rowid_results, vec![(2, hash_3),]);
assert_eq!(result.no_rowid_results, vec![hash_1, hash_2, hash_4]);
}

#[test]
Expand Down
36 changes: 24 additions & 12 deletions node/src/accountant/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,7 @@ mod tests {
PayableAccount, PayableDaoError, PayableDaoFactory,
};
use crate::accountant::db_access_objects::pending_payable_dao::{
PendingPayable, PendingPayableDaoError,
PendingPayable, PendingPayableDaoError, TransactionHashes,
};
use crate::accountant::db_access_objects::receivable_dao::ReceivableAccount;
use crate::accountant::db_access_objects::utils::{from_time_t, to_time_t, CustomQuery};
Expand Down Expand Up @@ -1349,8 +1349,11 @@ mod tests {
#[test]
fn sent_payable_with_response_skeleton_sends_scan_response_to_ui_gateway() {
let config = bc_from_earning_wallet(make_wallet("earning_wallet"));
let pending_payable_dao = PendingPayableDaoMock::default()
.fingerprints_rowids_result(vec![(Some(1), make_tx_hash(123))]);
let pending_payable_dao =
PendingPayableDaoMock::default().fingerprints_rowids_result(TransactionHashes {
rowid_results: vec![(1, make_tx_hash(123))],
no_rowid_results: vec![],
});
let payable_dao = PayableDaoMock::default().mark_pending_payables_rowids_result(Ok(()));
let subject = AccountantBuilder::default()
.pending_payable_daos(vec![ForPayableScanner(pending_payable_dao)])
Expand Down Expand Up @@ -1751,7 +1754,10 @@ mod tests {
let expected_rowid = 45623;
let pending_payable_dao = PendingPayableDaoMock::default()
.fingerprints_rowids_params(&fingerprints_rowids_params_arc)
.fingerprints_rowids_result(vec![(Some(expected_rowid), expected_hash)]);
.fingerprints_rowids_result(TransactionHashes {
rowid_results: vec![(expected_rowid, expected_hash)],
no_rowid_results: vec![],
});
let payable_dao = PayableDaoMock::new()
.mark_pending_payables_rowids_params(&mark_pending_payables_rowids_params_arc)
.mark_pending_payables_rowids_result(Ok(()));
Expand Down Expand Up @@ -3307,10 +3313,13 @@ mod tests {
..fingerprint_2_first_round.clone()
};
let pending_payable_dao_for_payable_scanner = PendingPayableDaoMock::default()
.fingerprints_rowids_result(vec![
(Some(rowid_for_account_1), pending_tx_hash_1),
(Some(rowid_for_account_2), pending_tx_hash_2),
]);
.fingerprints_rowids_result(TransactionHashes {
rowid_results: vec![
(rowid_for_account_1, pending_tx_hash_1),
(rowid_for_account_2, pending_tx_hash_2),
],
no_rowid_results: vec![],
});
let mut pending_payable_dao_for_pending_payable_scanner = PendingPayableDaoMock::new()
.return_all_errorless_fingerprints_params(&return_all_errorless_fingerprints_params_arc)
.return_all_errorless_fingerprints_result(vec![])
Expand All @@ -3327,10 +3336,13 @@ mod tests {
fingerprint_2_third_round,
])
.return_all_errorless_fingerprints_result(vec![fingerprint_2_fourth_round.clone()])
.fingerprints_rowids_result(vec![
(Some(rowid_for_account_1), pending_tx_hash_1),
(Some(rowid_for_account_2), pending_tx_hash_2),
])
.fingerprints_rowids_result(TransactionHashes {
rowid_results: vec![
(rowid_for_account_1, pending_tx_hash_1),
(rowid_for_account_2, pending_tx_hash_2),
],
no_rowid_results: vec![],
})
.increment_scan_attempts_params(&update_fingerprint_params_arc)
.increment_scan_attempts_result(Ok(()))
.increment_scan_attempts_result(Ok(()))
Expand Down
Loading
Loading