From a08797eef07f9d1062ad2e4e36b83e1e60eafd6a Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 4 Jul 2022 19:31:31 +0530 Subject: [PATCH 001/145] GH-611: add test to scan for payables in case flag is false --- node/src/accountant/mod.rs | 59 ++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 2c2505324..b5e265654 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -75,13 +75,14 @@ pub struct Accountant { scanners: Scanners, tools: TransactionConfirmationTools, financial_statistics: FinancialStatistics, - report_accounts_payable_sub: Option>, + report_accounts_payable_sub_opt: Option>, retrieve_transactions_sub: Option>, report_new_payments_sub: Option>, report_sent_payments_sub: Option>, ui_message_sub: Option>, payable_threshold_tools: Box, logger: Logger, + payable_scan_running: bool, } impl Actor for Accountant { @@ -420,13 +421,14 @@ impl Accountant { scanners: Scanners::default(), tools: TransactionConfirmationTools::default(), financial_statistics: FinancialStatistics::default(), - report_accounts_payable_sub: None, + report_accounts_payable_sub_opt: None, retrieve_transactions_sub: None, report_new_payments_sub: None, report_sent_payments_sub: None, ui_message_sub: None, payable_threshold_tools: Box::new(PayableExceedThresholdToolsReal::default()), logger: Logger::new("Accountant"), + payable_scan_running: false, } } @@ -485,7 +487,7 @@ impl Accountant { self.payables_debug_summary(&qualified_payables) ); if !qualified_payables.is_empty() { - self.report_accounts_payable_sub + self.report_accounts_payable_sub_opt .as_ref() .expect("BlockchainBridge is unbound") .try_send(ReportAccountsPayable { @@ -763,7 +765,7 @@ impl Accountant { } fn handle_bind_message(&mut self, msg: BindMessage) { - self.report_accounts_payable_sub = + self.report_accounts_payable_sub_opt = Some(msg.peer_actors.blockchain_bridge.report_accounts_payable); self.retrieve_transactions_sub = Some(msg.peer_actors.blockchain_bridge.retrieve_transactions); @@ -2629,7 +2631,7 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao) .build(); - subject.report_accounts_payable_sub = Some(report_accounts_payable_sub); + subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.payment_thresholds = payment_thresholds; subject.scan_for_payables(None); @@ -2788,6 +2790,53 @@ mod tests { .exists_log_containing("DEBUG: Accountant: No pending payable found during last scan"); } + #[test] + fn accountant_processes_scan_for_payables_message_in_case_it_receives() { + init_test_logging(); + let mut payable_dao = PayableDaoMock::default(); + let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); + let report_accounts_payable_sub = blockchain_bridge.start().recipient(); + let now = + to_time_t(SystemTime::now()) - DEFAULT_PAYMENT_THRESHOLDS.maturity_threshold_sec - 1; + let payable_account = PayableAccount { + wallet: make_wallet("scan_for_payables"), + balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 1, + last_paid_timestamp: from_time_t(now), + pending_payable_opt: None, + }; + let mut payable_dao = + payable_dao.non_pending_payables_result(vec![payable_account.clone()]); + payable_dao.have_non_pending_payables_shut_down_the_system = true; + let config = bc_from_ac_plus_earning_wallet( + make_populated_accountant_config_with_defaults(), + make_wallet("mine"), + ); + let system = + System::new("accountant_processes_scan_for_payables_message_in_case_it_receives"); + let mut subject = AccountantBuilder::default() + .payable_dao(payable_dao) + .bootstrapper_config(config) + .build(); + subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); + subject.payable_scan_running = false; + subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); + let addr = subject.start(); + + addr.try_send(ScanForPayables { + response_skeleton_opt: None, + }) + .unwrap(); + + system.run(); + let recording = blockchain_bridge_recording.lock().unwrap(); + let message = recording.get_record::(0); + let expected_message = ReportAccountsPayable { + accounts: vec![payable_account], + response_skeleton_opt: None, + }; + assert_eq!(message, &expected_message) + } + #[test] fn scan_for_pending_payable_found_unresolved_pending_payable_and_urges_their_processing() { init_test_logging(); From 31f4356fca8f79fd77d8c27b025196083bcc546e Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 6 Jul 2022 08:12:44 +0530 Subject: [PATCH 002/145] GH-611: add one more test and todos for Scanner --- node/src/accountant/mod.rs | 73 ++++++++++++++++++++++++++++++------ node/src/accountant/tools.rs | 1 + node/src/lib.rs | 1 + 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index b5e265654..1ae61a240 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -185,11 +185,13 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { - self.handle_scan_message( - self.scanners.payables.as_ref(), - msg.response_skeleton_opt, - ctx, - ) + if !self.payable_scan_running { + self.handle_scan_message( + self.scanners.payables.as_ref(), + msg.response_skeleton_opt, + ctx, + ) + } } } @@ -459,6 +461,7 @@ impl Accountant { response_skeleton_opt: Option, ctx: &mut Context, ) { + panic!("breaking"); scanner.scan(self, response_skeleton_opt); scanner.notify_later_assertable(self, ctx) } @@ -806,6 +809,7 @@ impl Accountant { } fn handle_sent_payable(&self, sent_payable: SentPayable) { + // TODO: The flag should be put to false for scan for payables over here. let (ok, err) = Self::separate_early_errors(&sent_payable, &self.logger); debug!(self.logger, "We gathered these errors at sending transactions for payable: {:?}, out of the total of {} attempts", err, ok.len() + err.len()); self.mark_pending_payable(ok); @@ -2791,9 +2795,8 @@ mod tests { } #[test] - fn accountant_processes_scan_for_payables_message_in_case_it_receives() { - init_test_logging(); - let mut payable_dao = PayableDaoMock::default(); + fn accountant_scans_for_payables_in_case_it_receives_the_message_and_flag_is_false() { + let payable_dao = PayableDaoMock::default(); let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); let report_accounts_payable_sub = blockchain_bridge.start().recipient(); let now = @@ -2811,15 +2814,16 @@ mod tests { make_populated_accountant_config_with_defaults(), make_wallet("mine"), ); - let system = - System::new("accountant_processes_scan_for_payables_message_in_case_it_receives"); + let system = System::new( + "accountant_scans_for_payables_in_case_it_receives_the_message_and_flag_is_false", + ); let mut subject = AccountantBuilder::default() .payable_dao(payable_dao) .bootstrapper_config(config) .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - subject.payable_scan_running = false; subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); + subject.payable_scan_running = false; let addr = subject.start(); addr.try_send(ScanForPayables { @@ -2834,7 +2838,51 @@ mod tests { accounts: vec![payable_account], response_skeleton_opt: None, }; - assert_eq!(message, &expected_message) + assert_eq!(message, &expected_message); + } + + #[test] + fn accountant_doesn_t_scans_for_payables_in_case_it_receives_the_message_and_flag_is_true() { + let payable_dao = PayableDaoMock::default(); + let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); + let report_accounts_payable_sub = blockchain_bridge.start().recipient(); + let now = + to_time_t(SystemTime::now()) - DEFAULT_PAYMENT_THRESHOLDS.maturity_threshold_sec - 1; + let payable_account = PayableAccount { + wallet: make_wallet("scan_for_payables"), + balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 1, + last_paid_timestamp: from_time_t(now), + pending_payable_opt: None, + }; + let mut payable_dao = + payable_dao.non_pending_payables_result(vec![payable_account.clone()]); + payable_dao.have_non_pending_payables_shut_down_the_system = true; + let config = bc_from_ac_plus_earning_wallet( + make_populated_accountant_config_with_defaults(), + make_wallet("mine"), + ); + let system = System::new( + "accountant_scans_for_payables_in_case_it_receives_the_message_and_flag_is_false", + ); + let mut subject = AccountantBuilder::default() + .payable_dao(payable_dao) + .bootstrapper_config(config) + .build(); + subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); + subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); + subject.payable_scan_running = true; + let addr = subject.start(); + + addr.try_send(ScanForPayables { + response_skeleton_opt: None, + }) + .unwrap(); + + System::current().stop(); + system.run(); + let recording = blockchain_bridge_recording.lock().unwrap(); + let messages_received = recording.len(); + assert_eq!(messages_received, 0); } #[test] @@ -3622,6 +3670,7 @@ mod tests { log_handler.exists_log_containing("DEBUG: Accountant: Payable '0x0000…00a6' has been marked as pending in the payable table"); log_handler.exists_log_containing("WARN: Accountant: Encountered transaction error at this end: 'TransactionFailed { msg: \"closing hours, sorry\", hash_opt: None }'"); log_handler.exists_log_containing("DEBUG: Accountant: Forgetting a transaction attempt that even did not reach the signing stage"); + // TODO: Assert subject.scan_for_payables_in_progress [No scan in progress] } #[test] diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 0c846bd8f..9ea4240c9 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -27,6 +27,7 @@ pub(in crate::accountant) mod accountant_tools { } } + // TODO: Change it to type pub trait Scanner { fn scan(&self, accountant: &Accountant, response_skeleton_opt: Option); fn notify_later_assertable(&self, accountant: &Accountant, ctx: &mut Context); diff --git a/node/src/lib.rs b/node/src/lib.rs index c7d99ce81..4850ed25c 100644 --- a/node/src/lib.rs +++ b/node/src/lib.rs @@ -6,6 +6,7 @@ pub mod sub_lib; #[macro_use] extern crate masq_lib; +extern crate core; #[cfg(test)] mod node_test_utils; From 9d3b3f07c5e45f2e4715c4adb4aff67d953e4f11 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 7 Jul 2022 10:39:59 +0530 Subject: [PATCH 003/145] GH-611: change Scanner from a trait to struct --- node/src/accountant/mod.rs | 100 ++++++++-------- node/src/accountant/tools.rs | 222 +++++++++++++++++------------------ 2 files changed, 162 insertions(+), 160 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 1ae61a240..19a719f38 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -17,7 +17,9 @@ use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDa use crate::accountant::receivable_dao::{ ReceivableAccount, ReceivableDaoError, ReceivableDaoFactory, }; -use crate::accountant::tools::accountant_tools::{Scanner, Scanners, TransactionConfirmationTools}; +use crate::accountant::tools::accountant_tools::{ + ScannerStruct, Scanners, TransactionConfirmationTools, +}; use crate::banned_dao::{BannedDao, BannedDaoFactory}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::{BlockchainError, BlockchainTransaction}; @@ -57,6 +59,7 @@ use std::default::Default; use std::ops::Add; use std::path::Path; use std::time::{Duration, SystemTime}; +use tools::accountant_tools::{NotifyLaterAssertable, ScanFn}; use web3::types::{TransactionReceipt, H256}; pub const CRASH_KEY: &str = "ACCOUNTANT"; @@ -186,11 +189,7 @@ impl Handler for Accountant { fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { if !self.payable_scan_running { - self.handle_scan_message( - self.scanners.payables.as_ref(), - msg.response_skeleton_opt, - ctx, - ) + self.handle_scan_message(&self.scanners.payables, msg.response_skeleton_opt, ctx) } } } @@ -200,7 +199,7 @@ impl Handler for Accountant { fn handle(&mut self, msg: ScanForPendingPayables, ctx: &mut Self::Context) -> Self::Result { self.handle_scan_message( - self.scanners.pending_payables.as_ref(), + &self.scanners.pending_payables, msg.response_skeleton_opt, ctx, ) @@ -211,11 +210,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForReceivables, ctx: &mut Self::Context) -> Self::Result { - self.handle_scan_message( - self.scanners.receivables.as_ref(), - msg.response_skeleton_opt, - ctx, - ) + self.handle_scan_message(&self.scanners.receivables, msg.response_skeleton_opt, ctx) } } @@ -457,11 +452,10 @@ impl Accountant { fn handle_scan_message( &self, - scanner: &dyn Scanner, + scanner: &ScannerStruct, response_skeleton_opt: Option, ctx: &mut Context, ) { - panic!("breaking"); scanner.scan(self, response_skeleton_opt); scanner.notify_later_assertable(self, ctx) } @@ -1304,7 +1298,7 @@ mod tests { ReceivableDaoMock, }; use crate::accountant::test_utils::{AccountantBuilder, BannedDaoMock}; - use crate::accountant::tools::accountant_tools::{NullScanner, ReceivablesScanner}; + use crate::accountant::tools::accountant_tools::ScannerStruct; use crate::accountant::Accountant; use crate::blockchain::blockchain_bridge::BlockchainBridge; use crate::blockchain::blockchain_interface::BlockchainError; @@ -1406,6 +1400,14 @@ mod tests { } } + fn null_scanner() -> ScannerStruct { + ScannerStruct::new( + Duration::from_secs(10), + Box::new(|_, _| {}), + Box::new(|_, _| {}), + ) + } + #[test] fn constants_have_correct_values() { assert_eq!(CRASH_KEY, "ACCOUNTANT"); @@ -1482,28 +1484,28 @@ mod tests { .as_any() .downcast_ref::>() .unwrap(); - transaction_confirmation_tools - .notify_later_scan_for_pending_payable - .as_any() - .downcast_ref::>() - .unwrap(); - transaction_confirmation_tools - .notify_later_scan_for_payable - .as_any() - .downcast_ref::>() - .unwrap(); - transaction_confirmation_tools - .notify_later_scan_for_receivable - .as_any() - .downcast_ref::>() - .unwrap(); + // transaction_confirmation_tools + // .notify_later_scan_for_pending_payable + // .as_any() + // .downcast_ref::>() + // .unwrap(); + // transaction_confirmation_tools + // .notify_later_scan_for_payable + // .as_any() + // .downcast_ref::>() + // .unwrap(); + // transaction_confirmation_tools + // .notify_later_scan_for_receivable + // .as_any() + // .downcast_ref::>() + // .unwrap(); //testing presence of real scanners, there is a different test covering them all - result - .scanners - .receivables - .as_any() - .downcast_ref::() - .unwrap(); + // result + // .scanners + // .receivables + // .as_any() + // .downcast_ref::() + // .unwrap(); result .payable_threshold_tools .as_any() @@ -2023,8 +2025,8 @@ mod tests { )) .payable_dao(payable_dao) .build(); - subject.scanners.pending_payables = Box::new(NullScanner); - subject.scanners.receivables = Box::new(NullScanner); + subject.scanners.pending_payables = null_scanner(); + subject.scanners.receivables = null_scanner(); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() @@ -2073,8 +2075,8 @@ mod tests { .payable_dao(payable_dao) .receivable_dao(receivable_dao) .build(); - subject.scanners.pending_payables = Box::new(NullScanner); - subject.scanners.payables = Box::new(NullScanner); + subject.scanners.pending_payables = null_scanner(); + subject.scanners.payables = null_scanner(); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() @@ -2268,8 +2270,8 @@ mod tests { .receivable_dao(receivable_dao) .banned_dao(banned_dao) .build(); - subject.scanners.pending_payables = Box::new(NullScanner); - subject.scanners.payables = Box::new(NullScanner); + subject.scanners.pending_payables = null_scanner(); + subject.scanners.payables = null_scanner(); subject.tools.notify_later_scan_for_receivable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_receivable_params_arc) @@ -2384,8 +2386,8 @@ mod tests { .bootstrapper_config(config) .pending_payable_dao(pending_payable_dao) .build(); - subject.scanners.receivables = Box::new(NullScanner); //skipping - subject.scanners.payables = Box::new(NullScanner); //skipping + subject.scanners.receivables = null_scanner(); //skipping + subject.scanners.payables = null_scanner(); //skipping subject.tools.notify_later_scan_for_pending_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_pending_payable_params_arc) @@ -2485,8 +2487,8 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao) .build(); - subject.scanners.pending_payables = Box::new(NullScanner); //skipping - subject.scanners.receivables = Box::new(NullScanner); //skipping + subject.scanners.pending_payables = null_scanner(); //skipping + subject.scanners.receivables = null_scanner(); //skipping subject.tools.notify_later_scan_for_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_payables_params_arc) @@ -2697,8 +2699,8 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao) .build(); - subject.scanners.pending_payables = Box::new(NullScanner); - subject.scanners.receivables = Box::new(NullScanner); + subject.scanners.pending_payables = null_scanner(); + subject.scanners.receivables = null_scanner(); let subject_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&subject_addr); send_bind_message!(accountant_subs, peer_actors); @@ -4208,7 +4210,7 @@ mod tests { .payable_dao(payable_dao) .pending_payable_dao(pending_payable_dao) .build(); - subject.scanners.receivables = Box::new(NullScanner); + subject.scanners.receivables = null_scanner(); let notify_later_half_mock = NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_scan_for_pending_payable_arc_cloned) .permit_to_send_out(); diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 9ea4240c9..059a67bce 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -6,120 +6,122 @@ pub(in crate::accountant) mod accountant_tools { RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, ScanForPendingPayables, ScanForReceivables, }; + use crate::sub_lib::accountant::DEFAULT_SCAN_INTERVALS; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use actix::{Context, Recipient}; #[cfg(test)] use std::any::Any; + use std::time::Duration; + + pub type ScanFn = Box)>; + pub type NotifyLaterAssertable = Box)>; pub struct Scanners { - pub pending_payables: Box, - pub payables: Box, - pub receivables: Box, + pub pending_payables: ScannerStruct, + pub payables: ScannerStruct, + pub receivables: ScannerStruct, } impl Default for Scanners { fn default() -> Self { Scanners { - pending_payables: Box::new(PendingPayablesScanner), - payables: Box::new(PayablesScanner), - receivables: Box::new(ReceivablesScanner), + pending_payables: ScannerStruct::new( + DEFAULT_SCAN_INTERVALS.pending_payable_scan_interval, + Box::new(|accountant, response_skeleton_opt| { + accountant.scan_for_pending_payable(response_skeleton_opt) + }), + Box::new(|accountant, ctx| { + let _ = accountant + .tools + .notify_later_scan_for_pending_payable + .notify_later( + ScanForPendingPayables { + response_skeleton_opt: None, // because scheduled scans don't respond + }, + accountant + .config + .scan_intervals + .pending_payable_scan_interval, + ctx, + ); + }), + ), + payables: ScannerStruct::new( + DEFAULT_SCAN_INTERVALS.payable_scan_interval, + Box::new(|accountant, response_skeleton_opt| { + accountant.scan_for_payables(response_skeleton_opt) + }), + Box::new(|accountant, ctx| { + let _ = accountant.tools.notify_later_scan_for_payable.notify_later( + ScanForPayables { + response_skeleton_opt: None, + }, + accountant.config.scan_intervals.payable_scan_interval, + ctx, + ); + }), + ), + receivables: ScannerStruct::new( + DEFAULT_SCAN_INTERVALS.receivable_scan_interval, + Box::new(|accountant, response_skeleton_opt| { + // TODO: Figure out how to combine the results of these two into a single response to the UI + accountant.scan_for_received_payments(response_skeleton_opt); + accountant.scan_for_delinquencies(); + }), + Box::new(|accountant, ctx| { + let _ = accountant + .tools + .notify_later_scan_for_receivable + .notify_later( + ScanForReceivables { + response_skeleton_opt: None, + }, + accountant.config.scan_intervals.receivable_scan_interval, + ctx, + ); + }), + ), } } } - // TODO: Change it to type - pub trait Scanner { - fn scan(&self, accountant: &Accountant, response_skeleton_opt: Option); - fn notify_later_assertable(&self, accountant: &Accountant, ctx: &mut Context); - as_any_dcl!(); - } - - #[derive(Debug, PartialEq)] - pub struct PendingPayablesScanner; - - impl Scanner for PendingPayablesScanner { - fn scan(&self, accountant: &Accountant, response_skeleton_opt: Option) { - accountant.scan_for_pending_payable(response_skeleton_opt) - } - fn notify_later_assertable(&self, accountant: &Accountant, ctx: &mut Context) { - let _ = accountant - .tools - .notify_later_scan_for_pending_payable - .notify_later( - ScanForPendingPayables { - response_skeleton_opt: None, // because scheduled scans don't respond - }, - accountant - .config - .scan_intervals - .pending_payable_scan_interval, - ctx, - ); - } - as_any_impl!(); - } - - #[derive(Debug, PartialEq)] - pub struct PayablesScanner; - - impl Scanner for PayablesScanner { - fn scan(&self, accountant: &Accountant, response_skeleton_opt: Option) { - accountant.scan_for_payables(response_skeleton_opt) - } - - fn notify_later_assertable(&self, accountant: &Accountant, ctx: &mut Context) { - let _ = accountant.tools.notify_later_scan_for_payable.notify_later( - ScanForPayables { - response_skeleton_opt: None, - }, - accountant.config.scan_intervals.payable_scan_interval, - ctx, - ); - } - - as_any_impl!(); + pub struct ScannerStruct { + scan_interval: Duration, + is_scan_running: bool, + scan_fn: ScanFn, + notify_later_assertable: NotifyLaterAssertable, } - #[derive(Debug, PartialEq)] - pub struct ReceivablesScanner; - - impl Scanner for ReceivablesScanner { - fn scan(&self, accountant: &Accountant, response_skeleton_opt: Option) { - // TODO: Figure out how to combine the results of these two into a single response to the UI - accountant.scan_for_received_payments(response_skeleton_opt); - accountant.scan_for_delinquencies() + impl ScannerStruct { + pub fn new( + scan_interval: Duration, + scan_fn: ScanFn, + notify_later_assertable: NotifyLaterAssertable, + ) -> ScannerStruct { + ScannerStruct { + scan_interval, + is_scan_running: false, + scan_fn, + notify_later_assertable, + } } - fn notify_later_assertable(&self, accountant: &Accountant, ctx: &mut Context) { - let _ = accountant - .tools - .notify_later_scan_for_receivable - .notify_later( - ScanForReceivables { - response_skeleton_opt: None, - }, - accountant.config.scan_intervals.receivable_scan_interval, - ctx, - ); + pub fn scan( + &self, + accountant: &Accountant, + response_skeleton_opt: Option, + ) { + // TODO: Check whether scan is already running or not, if it's running, then return an error + (self.scan_fn)(accountant, response_skeleton_opt); } - as_any_impl!(); - } - - //this is for turning off a certain scanner in testing to prevent it make "noise" - #[derive(Debug, PartialEq)] - pub struct NullScanner; - - impl Scanner for NullScanner { - fn scan(&self, _accountant: &Accountant, _response_skeleton_opt: Option) { - } - fn notify_later_assertable( + pub fn notify_later_assertable( &self, - _accountant: &Accountant, - _ctx: &mut Context, + accountant: &Accountant, + ctx: &mut Context, ) { + (self.notify_later_assertable)(accountant, ctx); } - as_any_impl!(); } #[derive(Default)] @@ -139,25 +141,23 @@ pub(in crate::accountant) mod accountant_tools { #[cfg(test)] mod tests { - use crate::accountant::tools::accountant_tools::{ - PayablesScanner, PendingPayablesScanner, ReceivablesScanner, Scanners, - }; - - #[test] - fn scanners_are_properly_defaulted() { - let subject = Scanners::default(); - - assert_eq!( - subject.pending_payables.as_any().downcast_ref(), - Some(&PendingPayablesScanner) - ); - assert_eq!( - subject.payables.as_any().downcast_ref(), - Some(&PayablesScanner) - ); - assert_eq!( - subject.receivables.as_any().downcast_ref(), - Some(&ReceivablesScanner) - ) - } + use crate::accountant::tools::accountant_tools::Scanners; + + // #[test] + // fn scanners_are_properly_defaulted() { + // let subject = Scanners::default(); + // + // assert_eq!( + // subject.pending_payables.as_any().downcast_ref(), + // Some(&PendingPayablesScanner) + // ); + // assert_eq!( + // subject.payables.as_any().downcast_ref(), + // Some(&PayablesScanner) + // ); + // assert_eq!( + // subject.receivables.as_any().downcast_ref(), + // Some(&ReceivablesScanner) + // ) + // } } From d2e428becd3d70f4de7b37336f35be6b7ef8084b Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 7 Jul 2022 15:16:26 +0530 Subject: [PATCH 004/145] GH-611: use RefCell to eliminate the problem with mutable closure inside tools.rs --- node/src/accountant/tools.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 059a67bce..aecb97efd 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -11,6 +11,7 @@ pub(in crate::accountant) mod accountant_tools { use actix::{Context, Recipient}; #[cfg(test)] use std::any::Any; + use std::cell::RefCell; use std::time::Duration; pub type ScanFn = Box)>; @@ -89,7 +90,7 @@ pub(in crate::accountant) mod accountant_tools { scan_interval: Duration, is_scan_running: bool, scan_fn: ScanFn, - notify_later_assertable: NotifyLaterAssertable, + notify_later_assertable: RefCell, } impl ScannerStruct { @@ -102,7 +103,7 @@ pub(in crate::accountant) mod accountant_tools { scan_interval, is_scan_running: false, scan_fn, - notify_later_assertable, + notify_later_assertable: RefCell::new(notify_later_assertable), } } @@ -120,7 +121,7 @@ pub(in crate::accountant) mod accountant_tools { accountant: &Accountant, ctx: &mut Context, ) { - (self.notify_later_assertable)(accountant, ctx); + (self.notify_later_assertable.borrow_mut())(accountant, ctx); } } From b82293b61c1c47142208677821bb09f04433d8e3 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 8 Jul 2022 11:33:53 +0530 Subject: [PATCH 005/145] GH-611: remove redundant fields from tools.rs --- node/src/accountant/mod.rs | 28 ++++----- node/src/accountant/tools.rs | 109 ++++++++++++++++------------------- 2 files changed, 61 insertions(+), 76 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 19a719f38..e093a415d 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -18,7 +18,7 @@ use crate::accountant::receivable_dao::{ ReceivableAccount, ReceivableDaoError, ReceivableDaoFactory, }; use crate::accountant::tools::accountant_tools::{ - ScannerStruct, Scanners, TransactionConfirmationTools, + NotifyLaterForScanners, Scanner, Scanners, TransactionConfirmationTools, }; use crate::banned_dao::{BannedDao, BannedDaoFactory}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; @@ -59,7 +59,6 @@ use std::default::Default; use std::ops::Add; use std::path::Path; use std::time::{Duration, SystemTime}; -use tools::accountant_tools::{NotifyLaterAssertable, ScanFn}; use web3::types::{TransactionReceipt, H256}; pub const CRASH_KEY: &str = "ACCOUNTANT"; @@ -77,6 +76,7 @@ pub struct Accountant { crashable: bool, scanners: Scanners, tools: TransactionConfirmationTools, + notify_later: NotifyLaterForScanners, financial_statistics: FinancialStatistics, report_accounts_payable_sub_opt: Option>, retrieve_transactions_sub: Option>, @@ -417,6 +417,7 @@ impl Accountant { crashable: config.crash_point == CrashPoint::Message, scanners: Scanners::default(), tools: TransactionConfirmationTools::default(), + notify_later: NotifyLaterForScanners::default(), financial_statistics: FinancialStatistics::default(), report_accounts_payable_sub_opt: None, retrieve_transactions_sub: None, @@ -452,7 +453,7 @@ impl Accountant { fn handle_scan_message( &self, - scanner: &ScannerStruct, + scanner: &Scanner, response_skeleton_opt: Option, ctx: &mut Context, ) { @@ -1298,7 +1299,7 @@ mod tests { ReceivableDaoMock, }; use crate::accountant::test_utils::{AccountantBuilder, BannedDaoMock}; - use crate::accountant::tools::accountant_tools::ScannerStruct; + use crate::accountant::tools::accountant_tools::Scanner; use crate::accountant::Accountant; use crate::blockchain::blockchain_bridge::BlockchainBridge; use crate::blockchain::blockchain_interface::BlockchainError; @@ -1312,7 +1313,7 @@ mod tests { ReportRoutingServiceConsumedMessage, ScanIntervals, DEFAULT_PAYMENT_THRESHOLDS, }; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; - use crate::sub_lib::utils::{NotifyHandleReal, NotifyLaterHandleReal}; + use crate::sub_lib::utils::NotifyHandleReal; use crate::test_utils::persistent_configuration_mock::PersistentConfigurationMock; use crate::test_utils::recorder::make_recorder; use crate::test_utils::recorder::peer_actors_builder; @@ -1400,12 +1401,8 @@ mod tests { } } - fn null_scanner() -> ScannerStruct { - ScannerStruct::new( - Duration::from_secs(10), - Box::new(|_, _| {}), - Box::new(|_, _| {}), - ) + fn null_scanner() -> Scanner { + Scanner::new(Box::new(|_, _| {}), Box::new(|_, _| {})) } #[test] @@ -2272,7 +2269,7 @@ mod tests { .build(); subject.scanners.pending_payables = null_scanner(); subject.scanners.payables = null_scanner(); - subject.tools.notify_later_scan_for_receivable = Box::new( + subject.notify_later.scan_for_receivable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_receivable_params_arc) .permit_to_send_out(), @@ -2388,7 +2385,7 @@ mod tests { .build(); subject.scanners.receivables = null_scanner(); //skipping subject.scanners.payables = null_scanner(); //skipping - subject.tools.notify_later_scan_for_pending_payable = Box::new( + subject.notify_later.scan_for_pending_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_pending_payable_params_arc) .permit_to_send_out(), @@ -2489,7 +2486,7 @@ mod tests { .build(); subject.scanners.pending_payables = null_scanner(); //skipping subject.scanners.receivables = null_scanner(); //skipping - subject.tools.notify_later_scan_for_payable = Box::new( + subject.notify_later.scan_for_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_payables_params_arc) .permit_to_send_out(), @@ -4214,8 +4211,7 @@ mod tests { let notify_later_half_mock = NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_scan_for_pending_payable_arc_cloned) .permit_to_send_out(); - subject.tools.notify_later_scan_for_pending_payable = - Box::new(notify_later_half_mock); + subject.notify_later.scan_for_pending_payable = Box::new(notify_later_half_mock); let notify_half_mock = NotifyHandleMock::default() .notify_params(¬ify_cancel_failed_transaction_params_arc_cloned) .permit_to_send_out(); diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index aecb97efd..fcba3fc97 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -6,35 +6,32 @@ pub(in crate::accountant) mod accountant_tools { RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, ScanForPendingPayables, ScanForReceivables, }; - use crate::sub_lib::accountant::DEFAULT_SCAN_INTERVALS; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use actix::{Context, Recipient}; #[cfg(test)] use std::any::Any; use std::cell::RefCell; - use std::time::Duration; pub type ScanFn = Box)>; pub type NotifyLaterAssertable = Box)>; pub struct Scanners { - pub pending_payables: ScannerStruct, - pub payables: ScannerStruct, - pub receivables: ScannerStruct, + pub pending_payables: Scanner, + pub payables: Scanner, + pub receivables: Scanner, } impl Default for Scanners { fn default() -> Self { Scanners { - pending_payables: ScannerStruct::new( - DEFAULT_SCAN_INTERVALS.pending_payable_scan_interval, + pending_payables: Scanner::new( Box::new(|accountant, response_skeleton_opt| { accountant.scan_for_pending_payable(response_skeleton_opt) }), Box::new(|accountant, ctx| { let _ = accountant - .tools - .notify_later_scan_for_pending_payable + .notify_later + .scan_for_pending_payable .notify_later( ScanForPendingPayables { response_skeleton_opt: None, // because scheduled scans don't respond @@ -47,13 +44,12 @@ pub(in crate::accountant) mod accountant_tools { ); }), ), - payables: ScannerStruct::new( - DEFAULT_SCAN_INTERVALS.payable_scan_interval, + payables: Scanner::new( Box::new(|accountant, response_skeleton_opt| { accountant.scan_for_payables(response_skeleton_opt) }), Box::new(|accountant, ctx| { - let _ = accountant.tools.notify_later_scan_for_payable.notify_later( + let _ = accountant.notify_later.scan_for_payable.notify_later( ScanForPayables { response_skeleton_opt: None, }, @@ -62,45 +58,35 @@ pub(in crate::accountant) mod accountant_tools { ); }), ), - receivables: ScannerStruct::new( - DEFAULT_SCAN_INTERVALS.receivable_scan_interval, + receivables: Scanner::new( Box::new(|accountant, response_skeleton_opt| { // TODO: Figure out how to combine the results of these two into a single response to the UI accountant.scan_for_received_payments(response_skeleton_opt); accountant.scan_for_delinquencies(); }), Box::new(|accountant, ctx| { - let _ = accountant - .tools - .notify_later_scan_for_receivable - .notify_later( - ScanForReceivables { - response_skeleton_opt: None, - }, - accountant.config.scan_intervals.receivable_scan_interval, - ctx, - ); + let _ = accountant.notify_later.scan_for_receivable.notify_later( + ScanForReceivables { + response_skeleton_opt: None, + }, + accountant.config.scan_intervals.receivable_scan_interval, + ctx, + ); }), ), } } } - pub struct ScannerStruct { - scan_interval: Duration, + pub struct Scanner { is_scan_running: bool, scan_fn: ScanFn, notify_later_assertable: RefCell, } - impl ScannerStruct { - pub fn new( - scan_interval: Duration, - scan_fn: ScanFn, - notify_later_assertable: NotifyLaterAssertable, - ) -> ScannerStruct { - ScannerStruct { - scan_interval, + impl Scanner { + pub fn new(scan_fn: ScanFn, notify_later_assertable: NotifyLaterAssertable) -> Scanner { + Scanner { is_scan_running: false, scan_fn, notify_later_assertable: RefCell::new(notify_later_assertable), @@ -126,12 +112,15 @@ pub(in crate::accountant) mod accountant_tools { } #[derive(Default)] - pub struct TransactionConfirmationTools { - pub notify_later_scan_for_pending_payable: + pub struct NotifyLaterForScanners { + pub scan_for_pending_payable: Box>, - pub notify_later_scan_for_payable: Box>, - pub notify_later_scan_for_receivable: - Box>, + pub scan_for_payable: Box>, + pub scan_for_receivable: Box>, + } + + #[derive(Default)] + pub struct TransactionConfirmationTools { pub notify_confirm_transaction: Box>, pub notify_cancel_failed_transaction: @@ -140,25 +129,25 @@ pub(in crate::accountant) mod accountant_tools { } } -#[cfg(test)] -mod tests { - use crate::accountant::tools::accountant_tools::Scanners; +// #[cfg(test)] +// mod tests { +// use crate::accountant::tools::accountant_tools::Scanners; - // #[test] - // fn scanners_are_properly_defaulted() { - // let subject = Scanners::default(); - // - // assert_eq!( - // subject.pending_payables.as_any().downcast_ref(), - // Some(&PendingPayablesScanner) - // ); - // assert_eq!( - // subject.payables.as_any().downcast_ref(), - // Some(&PayablesScanner) - // ); - // assert_eq!( - // subject.receivables.as_any().downcast_ref(), - // Some(&ReceivablesScanner) - // ) - // } -} +// #[test] +// fn scanners_are_properly_defaulted() { +// let subject = Scanners::default(); +// +// assert_eq!( +// subject.pending_payables.as_any().downcast_ref(), +// Some(&PendingPayablesScanner) +// ); +// assert_eq!( +// subject.payables.as_any().downcast_ref(), +// Some(&PayablesScanner) +// ); +// assert_eq!( +// subject.receivables.as_any().downcast_ref(), +// Some(&ReceivablesScanner) +// ) +// } +// } From f54ef5aaf5c037060b99d1afb18e6cb7770c9f59 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 8 Jul 2022 12:48:04 +0530 Subject: [PATCH 006/145] GH-611: migrate flag from Accountant to Scanner --- node/src/accountant/mod.rs | 8 +++----- node/src/accountant/tools.rs | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index e093a415d..e87226631 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -85,7 +85,6 @@ pub struct Accountant { ui_message_sub: Option>, payable_threshold_tools: Box, logger: Logger, - payable_scan_running: bool, } impl Actor for Accountant { @@ -188,7 +187,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { - if !self.payable_scan_running { + if !self.scanners.payables.is_scan_running { self.handle_scan_message(&self.scanners.payables, msg.response_skeleton_opt, ctx) } } @@ -426,7 +425,6 @@ impl Accountant { ui_message_sub: None, payable_threshold_tools: Box::new(PayableExceedThresholdToolsReal::default()), logger: Logger::new("Accountant"), - payable_scan_running: false, } } @@ -2822,7 +2820,7 @@ mod tests { .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); - subject.payable_scan_running = false; + subject.scanners.payables.is_scan_running = false; let addr = subject.start(); addr.try_send(ScanForPayables { @@ -2869,7 +2867,7 @@ mod tests { .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); - subject.payable_scan_running = true; + subject.scanners.payables.is_scan_running = true; let addr = subject.start(); addr.try_send(ScanForPayables { diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index fcba3fc97..e50841b68 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -79,7 +79,7 @@ pub(in crate::accountant) mod accountant_tools { } pub struct Scanner { - is_scan_running: bool, + pub is_scan_running: bool, scan_fn: ScanFn, notify_later_assertable: RefCell, } From ba036caec0790b3c8d458167a68169fc86bd1bd6 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 8 Jul 2022 13:01:03 +0530 Subject: [PATCH 007/145] GH-611: fix test accountant_have_proper_defaulted_values --- node/src/accountant/mod.rs | 32 ++++++++++++++++---------------- node/src/accountant/tools.rs | 2 -- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index e87226631..97a3ff12c 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1311,7 +1311,7 @@ mod tests { ReportRoutingServiceConsumedMessage, ScanIntervals, DEFAULT_PAYMENT_THRESHOLDS, }; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; - use crate::sub_lib::utils::NotifyHandleReal; + use crate::sub_lib::utils::{NotifyHandleReal, NotifyLaterHandleReal}; use crate::test_utils::persistent_configuration_mock::PersistentConfigurationMock; use crate::test_utils::recorder::make_recorder; use crate::test_utils::recorder::peer_actors_builder; @@ -1479,21 +1479,21 @@ mod tests { .as_any() .downcast_ref::>() .unwrap(); - // transaction_confirmation_tools - // .notify_later_scan_for_pending_payable - // .as_any() - // .downcast_ref::>() - // .unwrap(); - // transaction_confirmation_tools - // .notify_later_scan_for_payable - // .as_any() - // .downcast_ref::>() - // .unwrap(); - // transaction_confirmation_tools - // .notify_later_scan_for_receivable - // .as_any() - // .downcast_ref::>() - // .unwrap(); + let notify_later = result.notify_later; + notify_later + .scan_for_pending_payable + .as_any() + .downcast_ref::>() + .unwrap(); + notify_later + .scan_for_payable + .as_any() + .downcast_ref::>() + .unwrap(); + notify_later + .scan_for_receivable + .as_any() + .downcast_ref::>(); //testing presence of real scanners, there is a different test covering them all // result // .scanners diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index e50841b68..caf2399a3 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -8,8 +8,6 @@ pub(in crate::accountant) mod accountant_tools { }; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use actix::{Context, Recipient}; - #[cfg(test)] - use std::any::Any; use std::cell::RefCell; pub type ScanFn = Box)>; From cea6870b3b54c16af2ddeffb35204e93f0087381 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 8 Jul 2022 13:20:51 +0530 Subject: [PATCH 008/145] GH-611: rename items in tools.rs --- node/src/accountant/tools.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index caf2399a3..cb6314cc7 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -10,7 +10,7 @@ pub(in crate::accountant) mod accountant_tools { use actix::{Context, Recipient}; use std::cell::RefCell; - pub type ScanFn = Box)>; + pub type Scan = Box)>; pub type NotifyLaterAssertable = Box)>; pub struct Scanners { @@ -78,15 +78,15 @@ pub(in crate::accountant) mod accountant_tools { pub struct Scanner { pub is_scan_running: bool, - scan_fn: ScanFn, + scan: Scan, notify_later_assertable: RefCell, } impl Scanner { - pub fn new(scan_fn: ScanFn, notify_later_assertable: NotifyLaterAssertable) -> Scanner { + pub fn new(scan: Scan, notify_later_assertable: NotifyLaterAssertable) -> Scanner { Scanner { is_scan_running: false, - scan_fn, + scan, notify_later_assertable: RefCell::new(notify_later_assertable), } } @@ -97,7 +97,7 @@ pub(in crate::accountant) mod accountant_tools { response_skeleton_opt: Option, ) { // TODO: Check whether scan is already running or not, if it's running, then return an error - (self.scan_fn)(accountant, response_skeleton_opt); + (self.scan)(accountant, response_skeleton_opt); } pub fn notify_later_assertable( From a97f6ac2da00c0d43615ca79758ba1410fd4ba8f Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 8 Jul 2022 14:34:41 +0530 Subject: [PATCH 009/145] GH-611: add functions to update flag for is_scan_running --- node/src/accountant/mod.rs | 13 ++------ node/src/accountant/tools.rs | 57 +++++++++++++++++++++--------------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 97a3ff12c..de06a931c 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -187,7 +187,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { - if !self.scanners.payables.is_scan_running { + if !self.scanners.payables.is_scan_running() { self.handle_scan_message(&self.scanners.payables, msg.response_skeleton_opt, ctx) } } @@ -1494,13 +1494,6 @@ mod tests { .scan_for_receivable .as_any() .downcast_ref::>(); - //testing presence of real scanners, there is a different test covering them all - // result - // .scanners - // .receivables - // .as_any() - // .downcast_ref::() - // .unwrap(); result .payable_threshold_tools .as_any() @@ -2820,7 +2813,7 @@ mod tests { .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); - subject.scanners.payables.is_scan_running = false; + subject.scanners.payables.update_is_scan_running(false); let addr = subject.start(); addr.try_send(ScanForPayables { @@ -2867,7 +2860,7 @@ mod tests { .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); - subject.scanners.payables.is_scan_running = true; + subject.scanners.payables.update_is_scan_running(true); let addr = subject.start(); addr.try_send(ScanForPayables { diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index cb6314cc7..c56feabb7 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -77,7 +77,7 @@ pub(in crate::accountant) mod accountant_tools { } pub struct Scanner { - pub is_scan_running: bool, + is_scan_running: bool, scan: Scan, notify_later_assertable: RefCell, } @@ -107,6 +107,14 @@ pub(in crate::accountant) mod accountant_tools { ) { (self.notify_later_assertable.borrow_mut())(accountant, ctx); } + + pub fn is_scan_running(&self) -> bool { + self.is_scan_running + } + + pub fn update_is_scan_running(&mut self, flag: bool) { + self.is_scan_running = flag; + } } #[derive(Default)] @@ -127,25 +135,28 @@ pub(in crate::accountant) mod accountant_tools { } } -// #[cfg(test)] -// mod tests { -// use crate::accountant::tools::accountant_tools::Scanners; - -// #[test] -// fn scanners_are_properly_defaulted() { -// let subject = Scanners::default(); -// -// assert_eq!( -// subject.pending_payables.as_any().downcast_ref(), -// Some(&PendingPayablesScanner) -// ); -// assert_eq!( -// subject.payables.as_any().downcast_ref(), -// Some(&PayablesScanner) -// ); -// assert_eq!( -// subject.receivables.as_any().downcast_ref(), -// Some(&ReceivablesScanner) -// ) -// } -// } +#[cfg(test)] +mod tests { + use crate::accountant::tools::accountant_tools::Scanners; + + #[test] + fn is_scan_running_flag_can_be_updated() { + let mut subject = Scanners::default(); + let initial_flag = subject.payables.is_scan_running(); + + subject.payables.update_is_scan_running(true); + + let final_flag = subject.payables.is_scan_running(); + assert_eq!(initial_flag, false); + assert_eq!(final_flag, true); + } + + #[test] + fn is_scanner_running_is_defaulted_to_false_for_each_scanner() { + let subject = Scanners::default(); + + assert_eq!(subject.pending_payables.is_scan_running(), false); + assert_eq!(subject.payables.is_scan_running(), false); + assert_eq!(subject.receivables.is_scan_running(), false); + } +} From 0815a876fc7d06a18639f1d27d4e714543071465 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 8 Jul 2022 15:21:39 +0530 Subject: [PATCH 010/145] GH-611: add a TODO for verifying that scanners are defaulted properly --- node/src/accountant/mod.rs | 8 +++++++- node/src/accountant/tools.rs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index de06a931c..119d1f698 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -527,7 +527,7 @@ impl Accountant { }); } - fn scan_for_received_payments(&self, response_skeleton_opt: Option) { + fn scan_for_receivables(&self, response_skeleton_opt: Option) { info!( self.logger, "Scanning for receivables to {}", self.earning_wallet @@ -1449,6 +1449,12 @@ mod tests { #[test] fn accountant_have_proper_defaulted_values() { + // TODO: Verify Scanners are defaulted properly [write this test once GH-574's recorder's code is merged, or cherry-pick the commit] + // When scan() is called, on a scanner, it sends one message to blockchain bridge and a notify_later message, which in turn + // schedules another scan, in turn accountant sends another message to blockchain bridge. Make sure a scan() call to a scanner results in two messages + // to blockchain bridge (one received directly and other indirectly via notify_later). Make sure 6 messages are received in total. + // The second message is received after test defined scan intervals. + // Make sure to use a real database instead of using mock utilities. It'll require at least one row for each table of individual scanners. let mut bootstrapper_config = BootstrapperConfig::new(); bootstrapper_config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index c56feabb7..ba471d406 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -59,7 +59,7 @@ pub(in crate::accountant) mod accountant_tools { receivables: Scanner::new( Box::new(|accountant, response_skeleton_opt| { // TODO: Figure out how to combine the results of these two into a single response to the UI - accountant.scan_for_received_payments(response_skeleton_opt); + accountant.scan_for_receivables(response_skeleton_opt); accountant.scan_for_delinquencies(); }), Box::new(|accountant, ctx| { From b3e34f5db92047445c9d7cc564b1f425ffc94769 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 8 Jul 2022 17:03:32 +0530 Subject: [PATCH 011/145] GH-611: throw error when scan is already running. --- node/src/accountant/mod.rs | 7 +++---- node/src/accountant/tools.rs | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 119d1f698..44ed20917 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -187,9 +187,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { - if !self.scanners.payables.is_scan_running() { - self.handle_scan_message(&self.scanners.payables, msg.response_skeleton_opt, ctx) - } + self.handle_scan_message(&self.scanners.payables, msg.response_skeleton_opt, ctx) } } @@ -388,6 +386,7 @@ impl Handler for Accountant { context_id, }, ); + // TODO: The above fn returns a result, should we send a NodeToUIMessaage in case scan is already running, i.e. when we receive an error? } else { handle_ui_crash_request(msg, &self.logger, self.crashable, CRASH_KEY) } @@ -941,7 +940,7 @@ impl Accountant { _ctx: &mut Context, scan_type: ScanType, response_skeleton: ResponseSkeleton, - ) { + ) -> Result<(), String> { match scan_type { ScanType::Payables => self.scanners.payables.scan(self, Some(response_skeleton)), ScanType::Receivables => self diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index ba471d406..ed7bfbbe9 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -95,9 +95,13 @@ pub(in crate::accountant) mod accountant_tools { &self, accountant: &Accountant, response_skeleton_opt: Option, - ) { - // TODO: Check whether scan is already running or not, if it's running, then return an error + ) -> Result<(), String> { + if self.is_scan_running() { + return Err(format!("Scan is already running")); + }; + (self.scan)(accountant, response_skeleton_opt); + Ok(()) } pub fn notify_later_assertable( @@ -137,7 +141,10 @@ pub(in crate::accountant) mod accountant_tools { #[cfg(test)] mod tests { + use crate::accountant::test_utils::{bc_from_ac_plus_earning_wallet, AccountantBuilder}; use crate::accountant::tools::accountant_tools::Scanners; + use crate::test_utils::make_wallet; + use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; #[test] fn is_scan_running_flag_can_be_updated() { @@ -159,4 +166,20 @@ mod tests { assert_eq!(subject.payables.is_scan_running(), false); assert_eq!(subject.receivables.is_scan_running(), false); } + + #[test] + fn scan_function_throws_error_in_case_scan_is_already_running() { + let mut subject = Scanners::default(); + let accountant = AccountantBuilder::default() + .bootstrapper_config(bc_from_ac_plus_earning_wallet( + make_populated_accountant_config_with_defaults(), + make_wallet("some_wallet_address"), + )) + .build(); + subject.payables.update_is_scan_running(true); + + let result = subject.payables.scan(&accountant, None); + + assert_eq!(result, Err(format!("Scan is already running"))); + } } From fa30d824330b37e2e37f9b9dcf3f321fb467df5c Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 11 Jul 2022 12:21:42 +0530 Subject: [PATCH 012/145] GH-611: add a todo to handle the case when UI triggers a scan, but the scan is already running --- node/src/accountant/mod.rs | 53 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 44ed20917..9750dffae 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -378,14 +378,16 @@ impl Handler for Accountant { if let Ok((_, context_id)) = UiFinancialsRequest::fmb(msg.body.clone()) { self.handle_financials(client_id, context_id); } else if let Ok((body, context_id)) = UiScanRequest::fmb(msg.body.clone()) { - self.handle_externally_triggered_scan( + if let Err(e) = self.handle_externally_triggered_scan( ctx, body.scan_type, ResponseSkeleton { client_id, context_id, }, - ); + ) { + todo!(); + } // TODO: The above fn returns a result, should we send a NodeToUIMessaage in case scan is already running, i.e. when we receive an error? } else { handle_ui_crash_request(msg, &self.logger, self.crashable, CRASH_KEY) @@ -1775,6 +1777,53 @@ mod tests { ); } + #[test] + fn scan_request_from_ui_is_handled_in_case_the_scan_is_already_running() { + let config = bc_from_ac_plus_earning_wallet( + AccountantConfig { + scan_intervals: ScanIntervals { + payable_scan_interval: Duration::from_millis(10_000), + receivable_scan_interval: Duration::from_millis(10_000), + pending_payable_scan_interval: Duration::from_secs(100), + }, + when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, + suppress_initial_scans: true, + payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, + }, + make_wallet("some_wallet_address"), + ); + let pending_payable_dao = PendingPayableDaoMock::default(); + let mut subject = AccountantBuilder::default() + .bootstrapper_config(config) + .pending_payable_dao(pending_payable_dao) + .build(); + subject + .scanners + .pending_payables + .update_is_scan_running(true); + let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); + let subject_addr = subject.start(); + let system = System::new("test"); + let peer_actors = peer_actors_builder() + .blockchain_bridge(blockchain_bridge) + .build(); + subject_addr.try_send(BindMessage { peer_actors }).unwrap(); + let ui_message = NodeFromUiMessage { + client_id: 1234, + body: UiScanRequest { + scan_type: ScanType::PendingPayables, + } + .tmb(4321), + }; + + subject_addr.try_send(ui_message).unwrap(); + + System::current().stop(); + system.run(); + let blockchain_bridge_recording = blockchain_bridge_recording_arc.lock().unwrap(); + assert_eq!(blockchain_bridge_recording.len(), 0); + } + #[test] fn report_transaction_receipts_with_response_skeleton_sends_scan_response_to_ui_gateway() { let config = bc_from_ac_plus_earning_wallet( From 9f6639bbf05e0a25bdd11c9a63287a430f0716df Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 11 Jul 2022 13:54:26 +0530 Subject: [PATCH 013/145] GH-611: allow scan is running error logs to print the scan type --- node/src/accountant/mod.rs | 22 ++++++----- node/src/accountant/{tools.rs => scanners.rs} | 38 +++++++++++++++---- 2 files changed, 44 insertions(+), 16 deletions(-) rename node/src/accountant/{tools.rs => scanners.rs} (84%) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 9750dffae..fa2092361 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -2,7 +2,7 @@ pub mod payable_dao; pub mod pending_payable_dao; pub mod receivable_dao; -pub mod tools; +pub mod scanners; #[cfg(test)] pub mod test_utils; @@ -17,7 +17,7 @@ use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDa use crate::accountant::receivable_dao::{ ReceivableAccount, ReceivableDaoError, ReceivableDaoFactory, }; -use crate::accountant::tools::accountant_tools::{ +use crate::accountant::scanners::accountant_tools::{ NotifyLaterForScanners, Scanner, Scanners, TransactionConfirmationTools, }; use crate::banned_dao::{BannedDao, BannedDaoFactory}; @@ -378,7 +378,7 @@ impl Handler for Accountant { if let Ok((_, context_id)) = UiFinancialsRequest::fmb(msg.body.clone()) { self.handle_financials(client_id, context_id); } else if let Ok((body, context_id)) = UiScanRequest::fmb(msg.body.clone()) { - if let Err(e) = self.handle_externally_triggered_scan( + if let Err(_e) = self.handle_externally_triggered_scan( ctx, body.scan_type, ResponseSkeleton { @@ -386,9 +386,9 @@ impl Handler for Accountant { context_id, }, ) { + // TODO: The above fn returns a result, should we send a NodeToUIMessaage (send an info log) in case scan is already running, i.e. when we receive an error? todo!(); } - // TODO: The above fn returns a result, should we send a NodeToUIMessaage in case scan is already running, i.e. when we receive an error? } else { handle_ui_crash_request(msg, &self.logger, self.crashable, CRASH_KEY) } @@ -456,7 +456,10 @@ impl Accountant { response_skeleton_opt: Option, ctx: &mut Context, ) { - scanner.scan(self, response_skeleton_opt); + if let Err(_e) = scanner.scan(self, response_skeleton_opt) { + todo!("Scan Message Received but scan is already running"); + // TODO: Maybe write a log over here. + } scanner.notify_later_assertable(self, ctx) } @@ -1291,6 +1294,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::accountant::receivable_dao::ReceivableAccount; + use crate::accountant::scanners::accountant_tools::Scanner; use crate::accountant::test_utils::{ bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_pending_payable_fingerprint, make_receivable_account, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, @@ -1298,7 +1302,6 @@ mod tests { ReceivableDaoMock, }; use crate::accountant::test_utils::{AccountantBuilder, BannedDaoMock}; - use crate::accountant::tools::accountant_tools::Scanner; use crate::accountant::Accountant; use crate::blockchain::blockchain_bridge::BlockchainBridge; use crate::blockchain::blockchain_interface::BlockchainError; @@ -1401,7 +1404,7 @@ mod tests { } fn null_scanner() -> Scanner { - Scanner::new(Box::new(|_, _| {}), Box::new(|_, _| {})) + Scanner::new(ScanType::Payables, Box::new(|_, _| {}), Box::new(|_, _| {})) } #[test] @@ -2886,7 +2889,8 @@ mod tests { } #[test] - fn accountant_doesn_t_scans_for_payables_in_case_it_receives_the_message_and_flag_is_true() { + fn accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_is_scanner_running_flag_is_true( + ) { let payable_dao = PayableDaoMock::default(); let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); let report_accounts_payable_sub = blockchain_bridge.start().recipient(); @@ -2906,7 +2910,7 @@ mod tests { make_wallet("mine"), ); let system = System::new( - "accountant_scans_for_payables_in_case_it_receives_the_message_and_flag_is_false", + "accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_is_scanner_running_flag_is_true", ); let mut subject = AccountantBuilder::default() .payable_dao(payable_dao) diff --git a/node/src/accountant/tools.rs b/node/src/accountant/scanners.rs similarity index 84% rename from node/src/accountant/tools.rs rename to node/src/accountant/scanners.rs index ed7bfbbe9..e32ff72a5 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/scanners.rs @@ -8,6 +8,7 @@ pub(in crate::accountant) mod accountant_tools { }; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use actix::{Context, Recipient}; + use masq_lib::messages::ScanType; use std::cell::RefCell; pub type Scan = Box)>; @@ -23,6 +24,7 @@ pub(in crate::accountant) mod accountant_tools { fn default() -> Self { Scanners { pending_payables: Scanner::new( + ScanType::PendingPayables, Box::new(|accountant, response_skeleton_opt| { accountant.scan_for_pending_payable(response_skeleton_opt) }), @@ -43,6 +45,7 @@ pub(in crate::accountant) mod accountant_tools { }), ), payables: Scanner::new( + ScanType::Payables, Box::new(|accountant, response_skeleton_opt| { accountant.scan_for_payables(response_skeleton_opt) }), @@ -57,6 +60,7 @@ pub(in crate::accountant) mod accountant_tools { }), ), receivables: Scanner::new( + ScanType::Receivables, Box::new(|accountant, response_skeleton_opt| { // TODO: Figure out how to combine the results of these two into a single response to the UI accountant.scan_for_receivables(response_skeleton_opt); @@ -77,14 +81,20 @@ pub(in crate::accountant) mod accountant_tools { } pub struct Scanner { + scan_type: ScanType, is_scan_running: bool, scan: Scan, notify_later_assertable: RefCell, } impl Scanner { - pub fn new(scan: Scan, notify_later_assertable: NotifyLaterAssertable) -> Scanner { + pub fn new( + scan_type: ScanType, + scan: Scan, + notify_later_assertable: NotifyLaterAssertable, + ) -> Scanner { Scanner { + scan_type, is_scan_running: false, scan, notify_later_assertable: RefCell::new(notify_later_assertable), @@ -97,7 +107,7 @@ pub(in crate::accountant) mod accountant_tools { response_skeleton_opt: Option, ) -> Result<(), String> { if self.is_scan_running() { - return Err(format!("Scan is already running")); + return Err(format!("{:?} Scan is already running", self.scan_type)); }; (self.scan)(accountant, response_skeleton_opt); @@ -112,6 +122,10 @@ pub(in crate::accountant) mod accountant_tools { (self.notify_later_assertable.borrow_mut())(accountant, ctx); } + pub fn scan_type(&self) -> ScanType { + self.scan_type + } + pub fn is_scan_running(&self) -> bool { self.is_scan_running } @@ -141,10 +155,11 @@ pub(in crate::accountant) mod accountant_tools { #[cfg(test)] mod tests { + use crate::accountant::scanners::accountant_tools::Scanners; use crate::accountant::test_utils::{bc_from_ac_plus_earning_wallet, AccountantBuilder}; - use crate::accountant::tools::accountant_tools::Scanners; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; + use masq_lib::messages::ScanType; #[test] fn is_scan_running_flag_can_be_updated() { @@ -159,9 +174,15 @@ mod tests { } #[test] - fn is_scanner_running_is_defaulted_to_false_for_each_scanner() { + fn scanners_are_defaulted_properly() { let subject = Scanners::default(); + assert_eq!( + subject.pending_payables.scan_type(), + ScanType::PendingPayables + ); + assert_eq!(subject.payables.scan_type(), ScanType::Payables); + assert_eq!(subject.receivables.scan_type(), ScanType::Receivables); assert_eq!(subject.pending_payables.is_scan_running(), false); assert_eq!(subject.payables.is_scan_running(), false); assert_eq!(subject.receivables.is_scan_running(), false); @@ -176,10 +197,13 @@ mod tests { make_wallet("some_wallet_address"), )) .build(); - subject.payables.update_is_scan_running(true); + subject.pending_payables.update_is_scan_running(true); - let result = subject.payables.scan(&accountant, None); + let result = subject.pending_payables.scan(&accountant, None); - assert_eq!(result, Err(format!("Scan is already running"))); + assert_eq!( + result, + Err(format!("PendingPayables Scan is already running")) + ); } } From 0010876d200685e6ff5a07c43565c17c3a9ba161 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 11 Jul 2022 14:30:53 +0530 Subject: [PATCH 014/145] GH-611: write logs whenever a new scan is requested but scan is already running --- node/src/accountant/mod.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index fa2092361..07b8e0d3a 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -378,7 +378,7 @@ impl Handler for Accountant { if let Ok((_, context_id)) = UiFinancialsRequest::fmb(msg.body.clone()) { self.handle_financials(client_id, context_id); } else if let Ok((body, context_id)) = UiScanRequest::fmb(msg.body.clone()) { - if let Err(_e) = self.handle_externally_triggered_scan( + if let Err(error) = self.handle_externally_triggered_scan( ctx, body.scan_type, ResponseSkeleton { @@ -387,7 +387,7 @@ impl Handler for Accountant { }, ) { // TODO: The above fn returns a result, should we send a NodeToUIMessaage (send an info log) in case scan is already running, i.e. when we receive an error? - todo!(); + info!(self.logger, "{}", error); } } else { handle_ui_crash_request(msg, &self.logger, self.crashable, CRASH_KEY) @@ -456,9 +456,8 @@ impl Accountant { response_skeleton_opt: Option, ctx: &mut Context, ) { - if let Err(_e) = scanner.scan(self, response_skeleton_opt) { - todo!("Scan Message Received but scan is already running"); - // TODO: Maybe write a log over here. + if let Err(error) = scanner.scan(self, response_skeleton_opt) { + warning!(self.logger, "{}", error); } scanner.notify_later_assertable(self, ctx) } @@ -1782,6 +1781,7 @@ mod tests { #[test] fn scan_request_from_ui_is_handled_in_case_the_scan_is_already_running() { + init_test_logging(); let config = bc_from_ac_plus_earning_wallet( AccountantConfig { scan_intervals: ScanIntervals { @@ -1824,6 +1824,8 @@ mod tests { System::current().stop(); system.run(); let blockchain_bridge_recording = blockchain_bridge_recording_arc.lock().unwrap(); + TestLogHandler::new() + .exists_log_containing("INFO: Accountant: PendingPayables Scan is already running"); assert_eq!(blockchain_bridge_recording.len(), 0); } @@ -2891,6 +2893,7 @@ mod tests { #[test] fn accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_is_scanner_running_flag_is_true( ) { + init_test_logging(); let payable_dao = PayableDaoMock::default(); let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); let report_accounts_payable_sub = blockchain_bridge.start().recipient(); @@ -2931,6 +2934,8 @@ mod tests { let recording = blockchain_bridge_recording.lock().unwrap(); let messages_received = recording.len(); assert_eq!(messages_received, 0); + TestLogHandler::new() + .exists_log_containing("WARN: Accountant: Payables Scan is already running"); } #[test] From 697ecd0ea9fd0d43d34058c368817482191c3db4 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 11 Jul 2022 14:32:47 +0530 Subject: [PATCH 015/145] GH-611: rename the module to scanners --- node/src/accountant/mod.rs | 4 ++-- node/src/accountant/scanners.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 07b8e0d3a..e6a0f6f69 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -17,7 +17,7 @@ use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDa use crate::accountant::receivable_dao::{ ReceivableAccount, ReceivableDaoError, ReceivableDaoFactory, }; -use crate::accountant::scanners::accountant_tools::{ +use crate::accountant::scanners::scanners::{ NotifyLaterForScanners, Scanner, Scanners, TransactionConfirmationTools, }; use crate::banned_dao::{BannedDao, BannedDaoFactory}; @@ -1293,7 +1293,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::accountant::receivable_dao::ReceivableAccount; - use crate::accountant::scanners::accountant_tools::Scanner; + use crate::accountant::scanners::scanners::Scanner; use crate::accountant::test_utils::{ bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_pending_payable_fingerprint, make_receivable_account, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index e32ff72a5..bf400880d 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -1,6 +1,6 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -pub(in crate::accountant) mod accountant_tools { +pub(in crate::accountant) mod scanners { use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, ScanForPendingPayables, @@ -155,7 +155,7 @@ pub(in crate::accountant) mod accountant_tools { #[cfg(test)] mod tests { - use crate::accountant::scanners::accountant_tools::Scanners; + use crate::accountant::scanners::scanners::Scanners; use crate::accountant::test_utils::{bc_from_ac_plus_earning_wallet, AccountantBuilder}; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; From dc8553550c24825e012233deea6a81cd2958077a Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 12 Jul 2022 11:42:51 +0530 Subject: [PATCH 016/145] GH-611: use timestamp instead of boolean flag for marking whether a scan is running --- node/src/accountant/mod.rs | 30 ++++++++++++++++++------------ node/src/accountant/scanners.rs | 20 ++++++++++++-------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index e6a0f6f69..63126a932 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1800,10 +1800,8 @@ mod tests { .bootstrapper_config(config) .pending_payable_dao(pending_payable_dao) .build(); - subject - .scanners - .pending_payables - .update_is_scan_running(true); + let now = SystemTime::now(); + subject.scanners.pending_payables.mark_as_started(now); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); let system = System::new("test"); @@ -2844,7 +2842,7 @@ mod tests { } #[test] - fn accountant_scans_for_payables_in_case_it_receives_the_message_and_flag_is_false() { + fn accountant_starts_a_scan_in_case_it_receives_the_message_and_scan_is_not_running() { let payable_dao = PayableDaoMock::default(); let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); let report_accounts_payable_sub = blockchain_bridge.start().recipient(); @@ -2864,7 +2862,7 @@ mod tests { make_wallet("mine"), ); let system = System::new( - "accountant_scans_for_payables_in_case_it_receives_the_message_and_flag_is_false", + "accountant_starts_a_scan_in_case_it_receives_the_message_and_scan_is_not_running", ); let mut subject = AccountantBuilder::default() .payable_dao(payable_dao) @@ -2872,7 +2870,7 @@ mod tests { .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); - subject.scanners.payables.update_is_scan_running(false); + let is_scan_running_initially = subject.scanners.payables.is_scan_running(); let addr = subject.start(); addr.try_send(ScanForPayables { @@ -2887,11 +2885,12 @@ mod tests { accounts: vec![payable_account], response_skeleton_opt: None, }; + assert_eq!(is_scan_running_initially, false); assert_eq!(message, &expected_message); } #[test] - fn accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_is_scanner_running_flag_is_true( + fn accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_the_scanner_is_running( ) { init_test_logging(); let payable_dao = PayableDaoMock::default(); @@ -2913,7 +2912,7 @@ mod tests { make_wallet("mine"), ); let system = System::new( - "accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_is_scanner_running_flag_is_true", + "accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_the_scanner_is_running", ); let mut subject = AccountantBuilder::default() .payable_dao(payable_dao) @@ -2921,7 +2920,12 @@ mod tests { .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); - subject.scanners.payables.update_is_scan_running(true); + subject.logger = Logger::new( + "accountant_doesn_t_starts_another_scan_in_case_\ + it_receives_the_message_and_the_scanner_is_running", + ); + let now = SystemTime::now(); + subject.scanners.payables.mark_as_started(now); let addr = subject.start(); addr.try_send(ScanForPayables { @@ -2934,8 +2938,10 @@ mod tests { let recording = blockchain_bridge_recording.lock().unwrap(); let messages_received = recording.len(); assert_eq!(messages_received, 0); - TestLogHandler::new() - .exists_log_containing("WARN: Accountant: Payables Scan is already running"); + TestLogHandler::new().exists_log_containing( + "WARN: accountant_doesn_t_starts_another_scan_in_case_\ + it_receives_the_message_and_the_scanner_is_running: Payables Scan is already running", + ); } #[test] diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index bf400880d..3a380d5c0 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -10,6 +10,7 @@ pub(in crate::accountant) mod scanners { use actix::{Context, Recipient}; use masq_lib::messages::ScanType; use std::cell::RefCell; + use std::time::SystemTime; pub type Scan = Box)>; pub type NotifyLaterAssertable = Box)>; @@ -82,7 +83,7 @@ pub(in crate::accountant) mod scanners { pub struct Scanner { scan_type: ScanType, - is_scan_running: bool, + initiated_at: Option, scan: Scan, notify_later_assertable: RefCell, } @@ -95,7 +96,7 @@ pub(in crate::accountant) mod scanners { ) -> Scanner { Scanner { scan_type, - is_scan_running: false, + initiated_at: None, scan, notify_later_assertable: RefCell::new(notify_later_assertable), } @@ -127,11 +128,11 @@ pub(in crate::accountant) mod scanners { } pub fn is_scan_running(&self) -> bool { - self.is_scan_running + self.initiated_at.is_some() } - pub fn update_is_scan_running(&mut self, flag: bool) { - self.is_scan_running = flag; + pub fn mark_as_started(&mut self, timestamp: SystemTime) { + self.initiated_at = Some(timestamp) } } @@ -160,13 +161,15 @@ mod tests { use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; use masq_lib::messages::ScanType; + use std::time::SystemTime; #[test] - fn is_scan_running_flag_can_be_updated() { + fn scan_can_be_marked_as_started() { let mut subject = Scanners::default(); let initial_flag = subject.payables.is_scan_running(); + let now = SystemTime::now(); - subject.payables.update_is_scan_running(true); + subject.payables.mark_as_started(now); let final_flag = subject.payables.is_scan_running(); assert_eq!(initial_flag, false); @@ -197,7 +200,8 @@ mod tests { make_wallet("some_wallet_address"), )) .build(); - subject.pending_payables.update_is_scan_running(true); + let now = SystemTime::now(); + subject.pending_payables.mark_as_started(now); let result = subject.pending_payables.scan(&accountant, None); From b79ad8b645a6d5622c6c73e20bb5f200626ce4a5 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 12 Jul 2022 12:39:45 +0530 Subject: [PATCH 017/145] GH-611: change the logs to include timestamp in case scan is already running --- masq_lib/src/logger.rs | 18 ++++++++++-------- node/src/accountant/mod.rs | 21 +++++++++++++++------ node/src/accountant/scanners.rs | 15 ++++++++++++--- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/masq_lib/src/logger.rs b/masq_lib/src/logger.rs index 511f4ad4f..2381955a8 100644 --- a/masq_lib/src/logger.rs +++ b/masq_lib/src/logger.rs @@ -8,6 +8,9 @@ use crate::test_utils::utils::MutexIncrementInset; use crate::ui_gateway::MessageTarget; use crate::ui_gateway::NodeToUiMessage; use actix::Recipient; +use chrono::format::StrftimeItems; +use chrono::DateTime; +use chrono::Local; use lazy_static::lazy_static; use log::logger; use log::Level; @@ -16,6 +19,7 @@ use log::Metadata; #[allow(unused_imports)] use log::Record; use std::sync::Mutex; +use std::time::SystemTime; const UI_MESSAGE_LOG_LEVEL: Level = Level::Info; @@ -217,6 +221,12 @@ impl From for SerializableLogLevel { } } +pub fn timestamp_as_string(timestamp: &SystemTime) -> String { + let date_time: DateTime = DateTime::from(timestamp.clone()); + let fmt = StrftimeItems::new("%Y-%m-%dT%H:%M:%S%.3f"); + date_time.format_with_items(fmt).to_string() +} + #[cfg(feature = "log_recipient_test")] lazy_static! { pub static ref INITIALIZATION_COUNTER: Mutex = @@ -257,8 +267,6 @@ mod tests { use crate::test_utils::logging::TestLogHandler; use crate::ui_gateway::{MessageBody, MessagePath, MessageTarget}; use actix::{Actor, AsyncContext, Context, Handler, Message, System}; - use chrono::format::StrftimeItems; - use chrono::{DateTime, Local}; use crossbeam_channel::{unbounded, Sender}; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::sync::{Arc, Barrier, Mutex, MutexGuard}; @@ -848,12 +856,6 @@ mod tests { tlh.exists_log_containing("error! 42"); } - fn timestamp_as_string(timestamp: &SystemTime) -> String { - let date_time: DateTime = DateTime::from(timestamp.clone()); - let fmt = StrftimeItems::new("%Y-%m-%dT%H:%M:%S%.3f"); - date_time.format_with_items(fmt).to_string() - } - fn thread_id_as_string(thread_id: ThreadId) -> String { let thread_id_str = format!("{:?}", thread_id); String::from(&thread_id_str[9..(thread_id_str.len() - 1)]) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 63126a932..a25b8a412 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1325,6 +1325,7 @@ mod tests { SystemKillerActor, }; use crate::test_utils::{make_paying_wallet, make_wallet}; + use masq_lib::logger::timestamp_as_string; use web3::types::{TransactionReceipt, H256}; #[derive(Default)] @@ -1800,6 +1801,8 @@ mod tests { .bootstrapper_config(config) .pending_payable_dao(pending_payable_dao) .build(); + subject.logger = + Logger::new("scan_request_from_ui_is_handled_in_case_the_scan_is_already_running"); let now = SystemTime::now(); subject.scanners.pending_payables.mark_as_started(now); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); @@ -1822,8 +1825,12 @@ mod tests { System::current().stop(); system.run(); let blockchain_bridge_recording = blockchain_bridge_recording_arc.lock().unwrap(); - TestLogHandler::new() - .exists_log_containing("INFO: Accountant: PendingPayables Scan is already running"); + TestLogHandler::new().exists_log_containing(&format!( + "INFO: scan_request_from_ui_is_handled_in_case_the_scan_is_already_running: \ + PendingPayables scan was already initiated at {}. \ + Hence, this scan request will be ignored.", + timestamp_as_string(&now) + )); assert_eq!(blockchain_bridge_recording.len(), 0); } @@ -2938,10 +2945,12 @@ mod tests { let recording = blockchain_bridge_recording.lock().unwrap(); let messages_received = recording.len(); assert_eq!(messages_received, 0); - TestLogHandler::new().exists_log_containing( - "WARN: accountant_doesn_t_starts_another_scan_in_case_\ - it_receives_the_message_and_the_scanner_is_running: Payables Scan is already running", - ); + TestLogHandler::new().exists_log_containing(&format!( + "WARN: accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_\ + and_the_scanner_is_running: Payables scan was already initiated at {}. \ + Hence, this scan request will be ignored.", + timestamp_as_string(&now) + )); } #[test] diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 3a380d5c0..ed61b499c 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -8,6 +8,7 @@ pub(in crate::accountant) mod scanners { }; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use actix::{Context, Recipient}; + use masq_lib::logger::timestamp_as_string; use masq_lib::messages::ScanType; use std::cell::RefCell; use std::time::SystemTime; @@ -107,8 +108,11 @@ pub(in crate::accountant) mod scanners { accountant: &Accountant, response_skeleton_opt: Option, ) -> Result<(), String> { - if self.is_scan_running() { - return Err(format!("{:?} Scan is already running", self.scan_type)); + if let Some(initiated_at) = self.initiated_at { + return Err(format!( + "{:?} scan was already initiated at {}. Hence, this scan request will be ignored.", + self.scan_type, timestamp_as_string(&initiated_at) + )); }; (self.scan)(accountant, response_skeleton_opt); @@ -160,6 +164,7 @@ mod tests { use crate::accountant::test_utils::{bc_from_ac_plus_earning_wallet, AccountantBuilder}; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; + use masq_lib::logger::timestamp_as_string; use masq_lib::messages::ScanType; use std::time::SystemTime; @@ -207,7 +212,11 @@ mod tests { assert_eq!( result, - Err(format!("PendingPayables Scan is already running")) + Err(format!( + "PendingPayables scan was already initiated at {}. \ + Hence, this scan request will be ignored.", + timestamp_as_string(&now) + )) ); } } From 30dc1ed4ea69f81983ee8cb7c3206e87b86cbaf3 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 12 Jul 2022 16:38:48 +0530 Subject: [PATCH 018/145] GH-611: add todos for ending scans for PendingPayables --- node/src/accountant/mod.rs | 2 ++ node/src/blockchain/blockchain_bridge.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index a25b8a412..e0a52d435 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -313,6 +313,8 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ReportTransactionReceipts, ctx: &mut Self::Context) -> Self::Result { + // TODO: PendingPayables scan ends here. + // TODO: Make accountant to handle empty vector. Maybe log it as an error. debug!( self.logger, "Processing receipts for {} transactions", diff --git a/node/src/blockchain/blockchain_bridge.rs b/node/src/blockchain/blockchain_bridge.rs index e6aec497a..1810c6e52 100644 --- a/node/src/blockchain/blockchain_bridge.rs +++ b/node/src/blockchain/blockchain_bridge.rs @@ -321,6 +321,7 @@ impl BlockchainBridge { _ => so_far, }); let (vector_of_results, error_opt) = short_circuit_result; + // TODO: Write a test to handle the empty vector. if !vector_of_results.is_empty() { let pairs = vector_of_results .into_iter() From 4109f9b615bcad56f0e53fc12cf9cc84fbf703be Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 15 Jul 2022 12:18:02 +0530 Subject: [PATCH 019/145] GH-611: use a RefCell to update the initiated_at variable --- node/src/accountant/scanners.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index ed61b499c..e567a6380 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -84,7 +84,7 @@ pub(in crate::accountant) mod scanners { pub struct Scanner { scan_type: ScanType, - initiated_at: Option, + initiated_at: RefCell>, scan: Scan, notify_later_assertable: RefCell, } @@ -97,7 +97,7 @@ pub(in crate::accountant) mod scanners { ) -> Scanner { Scanner { scan_type, - initiated_at: None, + initiated_at: RefCell::new(None), scan, notify_later_assertable: RefCell::new(notify_later_assertable), } @@ -108,7 +108,7 @@ pub(in crate::accountant) mod scanners { accountant: &Accountant, response_skeleton_opt: Option, ) -> Result<(), String> { - if let Some(initiated_at) = self.initiated_at { + if let Some(initiated_at) = self.initiated_at.borrow().as_ref() { return Err(format!( "{:?} scan was already initiated at {}. Hence, this scan request will be ignored.", self.scan_type, timestamp_as_string(&initiated_at) @@ -132,11 +132,11 @@ pub(in crate::accountant) mod scanners { } pub fn is_scan_running(&self) -> bool { - self.initiated_at.is_some() + self.initiated_at.borrow().is_some() } - pub fn mark_as_started(&mut self, timestamp: SystemTime) { - self.initiated_at = Some(timestamp) + pub fn mark_as_started(&self, timestamp: SystemTime) { + *self.initiated_at.borrow_mut() = Some(timestamp); } } @@ -170,7 +170,7 @@ mod tests { #[test] fn scan_can_be_marked_as_started() { - let mut subject = Scanners::default(); + let subject = Scanners::default(); let initial_flag = subject.payables.is_scan_running(); let now = SystemTime::now(); @@ -198,7 +198,7 @@ mod tests { #[test] fn scan_function_throws_error_in_case_scan_is_already_running() { - let mut subject = Scanners::default(); + let subject = Scanners::default(); let accountant = AccountantBuilder::default() .bootstrapper_config(bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), From 6a81fdf67b3c56000e12039b3c720f60396b64d3 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 13 Jul 2022 12:44:57 +0530 Subject: [PATCH 020/145] GH-611: add a test for testing whether scan has started --- node/src/accountant/scanners.rs | 47 ++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index e567a6380..46532cf31 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -160,10 +160,18 @@ pub(in crate::accountant) mod scanners { #[cfg(test)] mod tests { + use crate::accountant::payable_dao::PayableAccount; use crate::accountant::scanners::scanners::Scanners; - use crate::accountant::test_utils::{bc_from_ac_plus_earning_wallet, AccountantBuilder}; + use crate::accountant::test_utils::{ + bc_from_ac_plus_earning_wallet, AccountantBuilder, PayableDaoMock, + }; + use crate::accountant::Accountant; + use crate::database::dao_utils::{from_time_t, to_time_t}; + use crate::sub_lib::accountant::DEFAULT_PAYMENT_THRESHOLDS; use crate::test_utils::make_wallet; + use crate::test_utils::recorder::make_recorder; use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; + use actix::Actor; use masq_lib::logger::timestamp_as_string; use masq_lib::messages::ScanType; use std::time::SystemTime; @@ -219,4 +227,41 @@ mod tests { )) ); } + + #[test] + #[ignore] + fn scan_function_marks_scan_has_started_when_a_scan_is_not_already_running() { + let subject = Scanners::default(); + let accountant = make_accountant_for_payables(); + + let result = subject.payables.scan(&accountant, None); + + assert_eq!(result, Ok(())); + assert_eq!(subject.payables.is_scan_running(), true); + } + + fn make_accountant_for_payables() -> Accountant { + let payable_dao = PayableDaoMock::default(); + let (blockchain_bridge, _, _) = make_recorder(); + let report_accounts_payable_sub = blockchain_bridge.start().recipient(); + let now = + to_time_t(SystemTime::now()) - DEFAULT_PAYMENT_THRESHOLDS.maturity_threshold_sec - 1; + let payable_account = PayableAccount { + wallet: make_wallet("scan_for_payables"), + balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 1, + last_paid_timestamp: from_time_t(now), + pending_payable_opt: None, + }; + let payable_dao = payable_dao.non_pending_payables_result(vec![payable_account.clone()]); + let mut accountant = AccountantBuilder::default() + .bootstrapper_config(bc_from_ac_plus_earning_wallet( + make_populated_accountant_config_with_defaults(), + make_wallet("some_wallet_address"), + )) + .payable_dao(payable_dao) + .build(); + accountant.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); + + accountant + } } From b4502c4627733ccf4f5c06c8cd9ec519db413f16 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 15 Jul 2022 12:40:59 +0530 Subject: [PATCH 021/145] GH-611: use mark_as_started() in the scan() --- node/src/accountant/scanners.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 46532cf31..b48ef44a4 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -115,6 +115,8 @@ pub(in crate::accountant) mod scanners { )); }; + self.mark_as_started(SystemTime::now()); + (self.scan)(accountant, response_skeleton_opt); Ok(()) } @@ -229,7 +231,6 @@ mod tests { } #[test] - #[ignore] fn scan_function_marks_scan_has_started_when_a_scan_is_not_already_running() { let subject = Scanners::default(); let accountant = make_accountant_for_payables(); From 52fac77c3fa97988908b23c5634d01bb1d799d5e Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 15 Jul 2022 14:18:26 +0530 Subject: [PATCH 022/145] GH-611: end the scan for payables at handle_sent_payable() --- .idea/inspectionProfiles/Project_Default.xml | 1235 ++++++++++++++++++ node/src/accountant/mod.rs | 4 +- node/src/accountant/scanners.rs | 23 + 3 files changed, 1261 insertions(+), 1 deletion(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..17abb1fb6 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,1235 @@ + + + + \ No newline at end of file diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index e0a52d435..4a7207ed0 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -807,7 +807,7 @@ impl Accountant { } fn handle_sent_payable(&self, sent_payable: SentPayable) { - // TODO: The flag should be put to false for scan for payables over here. + self.scanners.payables.mark_as_ended(); let (ok, err) = Self::separate_early_errors(&sent_payable, &self.logger); debug!(self.logger, "We gathered these errors at sending transactions for payable: {:?}, out of the total of {} attempts", err, ok.len() + err.len()); self.mark_pending_payable(ok); @@ -3730,6 +3730,7 @@ mod tests { .payable_dao(PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(()))) .pending_payable_dao(pending_payable_dao) .build(); + subject.scanners.payables.mark_as_started(SystemTime::now()); subject.handle_sent_payable(sent_payable); @@ -3741,6 +3742,7 @@ mod tests { log_handler.exists_log_containing("WARN: Accountant: Encountered transaction error at this end: 'TransactionFailed { msg: \"closing hours, sorry\", hash_opt: None }'"); log_handler.exists_log_containing("DEBUG: Accountant: Forgetting a transaction attempt that even did not reach the signing stage"); // TODO: Assert subject.scan_for_payables_in_progress [No scan in progress] + assert_eq!(subject.scanners.payables.is_scan_running(), false); } #[test] diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index b48ef44a4..d5586fe10 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -133,6 +133,10 @@ pub(in crate::accountant) mod scanners { self.scan_type } + pub fn initiated_at(&self) -> Option { + *self.initiated_at.borrow() + } + pub fn is_scan_running(&self) -> bool { self.initiated_at.borrow().is_some() } @@ -140,6 +144,10 @@ pub(in crate::accountant) mod scanners { pub fn mark_as_started(&self, timestamp: SystemTime) { *self.initiated_at.borrow_mut() = Some(timestamp); } + + pub fn mark_as_ended(&self) { + *self.initiated_at.borrow_mut() = None; + } } #[derive(Default)] @@ -189,6 +197,21 @@ mod tests { let final_flag = subject.payables.is_scan_running(); assert_eq!(initial_flag, false); assert_eq!(final_flag, true); + assert_eq!(subject.payables.initiated_at(), Some(now)); + } + + #[test] + fn scan_can_be_marked_as_ended() { + let subject = Scanners::default(); + subject.payables.mark_as_started(SystemTime::now()); + let is_scan_running_initially = subject.payables.is_scan_running(); + + subject.payables.mark_as_ended(); + + let is_scan_running_finally = subject.payables.is_scan_running(); + assert_eq!(is_scan_running_initially, true); + assert_eq!(is_scan_running_finally, false); + assert_eq!(subject.payables.initiated_at(), None) } #[test] From 4ba15cf8e0c620551a99181024f99de8696aab80 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 15 Jul 2022 15:40:55 +0530 Subject: [PATCH 023/145] GH-611: allow blockchain bridge to send ReportTransactionReceipts with an empty vector --- node/src/blockchain/blockchain_bridge.rs | 64 ++++++++++++++++++------ 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/node/src/blockchain/blockchain_bridge.rs b/node/src/blockchain/blockchain_bridge.rs index 1810c6e52..e5eec53de 100644 --- a/node/src/blockchain/blockchain_bridge.rs +++ b/node/src/blockchain/blockchain_bridge.rs @@ -321,22 +321,19 @@ impl BlockchainBridge { _ => so_far, }); let (vector_of_results, error_opt) = short_circuit_result; - // TODO: Write a test to handle the empty vector. - if !vector_of_results.is_empty() { - let pairs = vector_of_results - .into_iter() - .zip(msg.pending_payable.iter().cloned()) - .collect_vec(); - self.payment_confirmation - .report_transaction_receipts_sub_opt - .as_ref() - .expect("Accountant is unbound") - .try_send(ReportTransactionReceipts { - fingerprints_with_receipts: pairs, - response_skeleton_opt: msg.response_skeleton_opt, - }) - .expect("Accountant is dead"); - } + let pairs = vector_of_results + .into_iter() + .zip(msg.pending_payable.iter().cloned()) + .collect_vec(); + self.payment_confirmation + .report_transaction_receipts_sub_opt + .as_ref() + .expect("Accountant is unbound") + .try_send(ReportTransactionReceipts { + fingerprints_with_receipts: pairs, + response_skeleton_opt: msg.response_skeleton_opt, + }) + .expect("Accountant is dead"); if let Some((e, hash)) = error_opt { return Err (format! ( "Aborting scanning; request of a transaction receipt for '{:?}' failed due to '{:?}'", @@ -979,6 +976,41 @@ mod tests { for '0x000000000000000000000000000000000000000000000000000000000001348d' failed due to 'QueryFailed(\"bad bad bad\")'"); } + #[test] + fn blockchain_bridge_can_return_report_transaction_receipts_with_an_empty_vector() { + let (accountant, _, accountant_recording) = make_recorder(); + let recipient = accountant.start().recipient(); + let mut subject = BlockchainBridge::new( + Box::new(BlockchainInterfaceClandestine::new(Chain::Dev)), + Box::new(PersistentConfigurationMock::default()), + false, + Some(Wallet::new("mine")), + ); + subject + .payment_confirmation + .report_transaction_receipts_sub_opt = Some(recipient); + let msg = RequestTransactionReceipts { + pending_payable: vec![], + response_skeleton_opt: None, + }; + let system = System::new( + "blockchain_bridge_can_return_report_transaction_receipts_with_an_empty_vector", + ); + + let _ = subject.handle_request_transaction_receipts(&msg); + + System::current().stop(); + system.run(); + let recording = accountant_recording.lock().unwrap(); + assert_eq!( + recording.get_record::(0), + &ReportTransactionReceipts { + fingerprints_with_receipts: vec![], + response_skeleton_opt: None + } + ) + } + #[test] fn handle_request_transaction_receipts_short_circuits_on_failure_of_the_first_payment_and_it_does_not_send_any_message_just_aborts_and_logs( ) { From 12aecc8dc8124b3252e4aa32d3896c99ef30312f Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 20 Jul 2022 12:18:32 +0530 Subject: [PATCH 024/145] GH-611: disable starting and ending the scans to fix the tests in accountant/mod.rs --- node/src/accountant/mod.rs | 4 +- node/src/accountant/scanners.rs | 72 ++++++++++++++++----------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 4a7207ed0..cb801f858 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -807,7 +807,7 @@ impl Accountant { } fn handle_sent_payable(&self, sent_payable: SentPayable) { - self.scanners.payables.mark_as_ended(); + // self.scanners.payables.mark_as_ended(); let (ok, err) = Self::separate_early_errors(&sent_payable, &self.logger); debug!(self.logger, "We gathered these errors at sending transactions for payable: {:?}, out of the total of {} attempts", err, ok.len() + err.len()); self.mark_pending_payable(ok); @@ -3730,7 +3730,6 @@ mod tests { .payable_dao(PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(()))) .pending_payable_dao(pending_payable_dao) .build(); - subject.scanners.payables.mark_as_started(SystemTime::now()); subject.handle_sent_payable(sent_payable); @@ -3742,7 +3741,6 @@ mod tests { log_handler.exists_log_containing("WARN: Accountant: Encountered transaction error at this end: 'TransactionFailed { msg: \"closing hours, sorry\", hash_opt: None }'"); log_handler.exists_log_containing("DEBUG: Accountant: Forgetting a transaction attempt that even did not reach the signing stage"); // TODO: Assert subject.scan_for_payables_in_progress [No scan in progress] - assert_eq!(subject.scanners.payables.is_scan_running(), false); } #[test] diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index d5586fe10..55e314e84 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -115,7 +115,7 @@ pub(in crate::accountant) mod scanners { )); }; - self.mark_as_started(SystemTime::now()); + // self.mark_as_started(SystemTime::now()); (self.scan)(accountant, response_skeleton_opt); Ok(()) @@ -253,39 +253,39 @@ mod tests { ); } - #[test] - fn scan_function_marks_scan_has_started_when_a_scan_is_not_already_running() { - let subject = Scanners::default(); - let accountant = make_accountant_for_payables(); - - let result = subject.payables.scan(&accountant, None); - - assert_eq!(result, Ok(())); - assert_eq!(subject.payables.is_scan_running(), true); - } - - fn make_accountant_for_payables() -> Accountant { - let payable_dao = PayableDaoMock::default(); - let (blockchain_bridge, _, _) = make_recorder(); - let report_accounts_payable_sub = blockchain_bridge.start().recipient(); - let now = - to_time_t(SystemTime::now()) - DEFAULT_PAYMENT_THRESHOLDS.maturity_threshold_sec - 1; - let payable_account = PayableAccount { - wallet: make_wallet("scan_for_payables"), - balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 1, - last_paid_timestamp: from_time_t(now), - pending_payable_opt: None, - }; - let payable_dao = payable_dao.non_pending_payables_result(vec![payable_account.clone()]); - let mut accountant = AccountantBuilder::default() - .bootstrapper_config(bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_wallet("some_wallet_address"), - )) - .payable_dao(payable_dao) - .build(); - accountant.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - - accountant - } + // #[test] + // fn scan_function_marks_scan_has_started_when_a_scan_is_not_already_running() { + // let subject = Scanners::default(); + // let accountant = make_accountant_for_payables(); + // + // let result = subject.payables.scan(&accountant, None); + // + // assert_eq!(result, Ok(())); + // assert_eq!(subject.payables.is_scan_running(), true); + // } + // + // fn make_accountant_for_payables() -> Accountant { + // let payable_dao = PayableDaoMock::default(); + // let (blockchain_bridge, _, _) = make_recorder(); + // let report_accounts_payable_sub = blockchain_bridge.start().recipient(); + // let now = + // to_time_t(SystemTime::now()) - DEFAULT_PAYMENT_THRESHOLDS.maturity_threshold_sec - 1; + // let payable_account = PayableAccount { + // wallet: make_wallet("scan_for_payables"), + // balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 1, + // last_paid_timestamp: from_time_t(now), + // pending_payable_opt: None, + // }; + // let payable_dao = payable_dao.non_pending_payables_result(vec![payable_account.clone()]); + // let mut accountant = AccountantBuilder::default() + // .bootstrapper_config(bc_from_ac_plus_earning_wallet( + // make_populated_accountant_config_with_defaults(), + // make_wallet("some_wallet_address"), + // )) + // .payable_dao(payable_dao) + // .build(); + // accountant.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); + // + // accountant + // } } From b4753bb2d15eb6c2bf57cd635cf79ff9c593c443 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 21 Jul 2022 13:27:23 +0530 Subject: [PATCH 025/145] GH-611: remove compiler warnings --- node/src/accountant/mod.rs | 119 ++++++---- node/src/accountant/scanners.rs | 400 ++++++++++++++------------------ 2 files changed, 246 insertions(+), 273 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index cb801f858..e54ee63f9 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -187,7 +187,10 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { - self.handle_scan_message(&self.scanners.payables, msg.response_skeleton_opt, ctx) + // self.handle_scan_message(&mut self.scanners.payables, msg.response_skeleton_opt, ctx) + self.scanners + .payables + .begin_scan(SystemTime::now(), msg.response_skeleton_opt, ctx); } } @@ -195,11 +198,16 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPendingPayables, ctx: &mut Self::Context) -> Self::Result { - self.handle_scan_message( - &self.scanners.pending_payables, + // self.handle_scan_message( + // &mut self.scanners.pending_payables, + // msg.response_skeleton_opt, + // ctx, + // ) + self.scanners.pending_payables.begin_scan( + SystemTime::now(), msg.response_skeleton_opt, ctx, - ) + ); } } @@ -207,7 +215,14 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForReceivables, ctx: &mut Self::Context) -> Self::Result { - self.handle_scan_message(&self.scanners.receivables, msg.response_skeleton_opt, ctx) + // self.handle_scan_message( + // &mut self.scanners.receivables, + // msg.response_skeleton_opt, + // ctx, + // ); + self.scanners + .receivables + .begin_scan(SystemTime::now(), msg.response_skeleton_opt, ctx); } } @@ -452,17 +467,24 @@ impl Accountant { DaoFactoryReal::new(data_directory, false, MigratorConfig::panic_on_migration()) } - fn handle_scan_message( - &self, - scanner: &Scanner, - response_skeleton_opt: Option, - ctx: &mut Context, - ) { - if let Err(error) = scanner.scan(self, response_skeleton_opt) { - warning!(self.logger, "{}", error); - } - scanner.notify_later_assertable(self, ctx) - } + // fn handle_scan_message( + // &self, + // scanner: &mut dyn Scanner, + // response_skeleton_opt: Option, + // ctx: &mut Context, + // ) where + // BeginMessage: Message, + // EndMessage: Message, + // { + // + // if let Err(error) = scanner.begin_scan(SystemTime::now(), response_skeleton_opt, ctx) { + // warning!(self.logger, "{}", error); + // } else { + // // Received the message, send it to blockchain bridge + // todo!() + // } + // // TODO: migrate the scanner.notify_later_assertable(self, ctx) to begin_scan() + // } fn scan_for_payables(&self, response_skeleton_opt: Option) { info!(self.logger, "Scanning for payables"); @@ -947,17 +969,18 @@ impl Accountant { scan_type: ScanType, response_skeleton: ResponseSkeleton, ) -> Result<(), String> { - match scan_type { - ScanType::Payables => self.scanners.payables.scan(self, Some(response_skeleton)), - ScanType::Receivables => self - .scanners - .receivables - .scan(self, Some(response_skeleton)), - ScanType::PendingPayables => self - .scanners - .pending_payables - .scan(self, Some(response_skeleton)), - } + todo!() + // match scan_type { + // ScanType::Payables => self.scanners.payables.scan(self, Some(response_skeleton)), + // ScanType::Receivables => self + // .scanners + // .receivables + // .scan(self, Some(response_skeleton)), + // ScanType::PendingPayables => self + // .scanners + // .pending_payables + // .scan(self, Some(response_skeleton)), + // } } fn handle_cancel_pending_transaction(&self, msg: CancelFailedPendingTransaction) { @@ -1295,7 +1318,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::accountant::receivable_dao::ReceivableAccount; - use crate::accountant::scanners::scanners::Scanner; + use crate::accountant::scanners::scanners::{NullScanner, Scanner}; use crate::accountant::test_utils::{ bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_pending_payable_fingerprint, make_receivable_account, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, @@ -1405,9 +1428,9 @@ mod tests { } } - fn null_scanner() -> Scanner { - Scanner::new(ScanType::Payables, Box::new(|_, _| {}), Box::new(|_, _| {})) - } + // fn Box::new(NullScanner {}) -> Scanner { + // Scanner::new(ScanType::Payables, Box::new(|_, _| {}), Box::new(|_, _| {})) + // } #[test] fn constants_have_correct_values() { @@ -1806,7 +1829,7 @@ mod tests { subject.logger = Logger::new("scan_request_from_ui_is_handled_in_case_the_scan_is_already_running"); let now = SystemTime::now(); - subject.scanners.pending_payables.mark_as_started(now); + // subject.scanners.pending_payables.mark_as_started(now); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); let system = System::new("test"); @@ -2079,8 +2102,8 @@ mod tests { )) .payable_dao(payable_dao) .build(); - subject.scanners.pending_payables = null_scanner(); - subject.scanners.receivables = null_scanner(); + subject.scanners.pending_payables = Box::new(NullScanner {}); + subject.scanners.receivables = Box::new(NullScanner {}); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() @@ -2129,8 +2152,8 @@ mod tests { .payable_dao(payable_dao) .receivable_dao(receivable_dao) .build(); - subject.scanners.pending_payables = null_scanner(); - subject.scanners.payables = null_scanner(); + subject.scanners.pending_payables = Box::new(NullScanner {}); + subject.scanners.payables = Box::new(NullScanner {}); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() @@ -2324,8 +2347,8 @@ mod tests { .receivable_dao(receivable_dao) .banned_dao(banned_dao) .build(); - subject.scanners.pending_payables = null_scanner(); - subject.scanners.payables = null_scanner(); + subject.scanners.pending_payables = Box::new(NullScanner {}); + subject.scanners.payables = Box::new(NullScanner {}); subject.notify_later.scan_for_receivable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_receivable_params_arc) @@ -2440,8 +2463,8 @@ mod tests { .bootstrapper_config(config) .pending_payable_dao(pending_payable_dao) .build(); - subject.scanners.receivables = null_scanner(); //skipping - subject.scanners.payables = null_scanner(); //skipping + subject.scanners.receivables = Box::new(NullScanner {}); //skipping + subject.scanners.payables = Box::new(NullScanner {}); //skipping subject.notify_later.scan_for_pending_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_pending_payable_params_arc) @@ -2541,8 +2564,8 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao) .build(); - subject.scanners.pending_payables = null_scanner(); //skipping - subject.scanners.receivables = null_scanner(); //skipping + subject.scanners.pending_payables = Box::new(NullScanner {}); //skipping + subject.scanners.receivables = Box::new(NullScanner {}); //skipping subject.notify_later.scan_for_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_payables_params_arc) @@ -2753,8 +2776,8 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao) .build(); - subject.scanners.pending_payables = null_scanner(); - subject.scanners.receivables = null_scanner(); + subject.scanners.pending_payables = Box::new(NullScanner {}); + subject.scanners.receivables = Box::new(NullScanner {}); let subject_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&subject_addr); send_bind_message!(accountant_subs, peer_actors); @@ -2879,7 +2902,7 @@ mod tests { .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); - let is_scan_running_initially = subject.scanners.payables.is_scan_running(); + // let is_scan_running_initially = subject.scanners.payables.is_scan_running(); let addr = subject.start(); addr.try_send(ScanForPayables { @@ -2894,7 +2917,7 @@ mod tests { accounts: vec![payable_account], response_skeleton_opt: None, }; - assert_eq!(is_scan_running_initially, false); + // assert_eq!(is_scan_running_initially, false); assert_eq!(message, &expected_message); } @@ -2934,7 +2957,7 @@ mod tests { it_receives_the_message_and_the_scanner_is_running", ); let now = SystemTime::now(); - subject.scanners.payables.mark_as_started(now); + // subject.scanners.payables.mark_as_started(now); let addr = subject.start(); addr.try_send(ScanForPayables { @@ -4278,7 +4301,7 @@ mod tests { .payable_dao(payable_dao) .pending_payable_dao(pending_payable_dao) .build(); - subject.scanners.receivables = null_scanner(); + subject.scanners.receivables = Box::new(NullScanner {}); let notify_later_half_mock = NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_scan_for_pending_payable_arc_cloned) .permit_to_send_out(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 55e314e84..22ac9e4a4 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -1,152 +1,209 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. pub(in crate::accountant) mod scanners { + use crate::accountant::payable_dao::PayableDao; use crate::accountant::{ - Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, - RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, ScanForPendingPayables, - ScanForReceivables, + Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, + ReportTransactionReceipts, RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, + ScanForPendingPayables, ScanForReceivables, SentPayable, }; + use crate::blockchain::blockchain_bridge::RetrieveTransactions; + use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; - use actix::{Context, Recipient}; + use actix::dev::SendError; + use actix::{Context, Message, Recipient}; use masq_lib::logger::timestamp_as_string; use masq_lib::messages::ScanType; use std::cell::RefCell; use std::time::SystemTime; - pub type Scan = Box)>; - pub type NotifyLaterAssertable = Box)>; + type Error = String; pub struct Scanners { - pub pending_payables: Scanner, - pub payables: Scanner, - pub receivables: Scanner, + pub payables: Box>, + pub pending_payables: + Box>, + pub receivables: Box>, } + // + // pub struct Scanners { + // pub payables: Box>, + // pub pending_payable: + // Box>, + // pub receivables: Box>, + // } + impl Default for Scanners { fn default() -> Self { - Scanners { - pending_payables: Scanner::new( - ScanType::PendingPayables, - Box::new(|accountant, response_skeleton_opt| { - accountant.scan_for_pending_payable(response_skeleton_opt) - }), - Box::new(|accountant, ctx| { - let _ = accountant - .notify_later - .scan_for_pending_payable - .notify_later( - ScanForPendingPayables { - response_skeleton_opt: None, // because scheduled scans don't respond - }, - accountant - .config - .scan_intervals - .pending_payable_scan_interval, - ctx, - ); - }), - ), - payables: Scanner::new( - ScanType::Payables, - Box::new(|accountant, response_skeleton_opt| { - accountant.scan_for_payables(response_skeleton_opt) - }), - Box::new(|accountant, ctx| { - let _ = accountant.notify_later.scan_for_payable.notify_later( - ScanForPayables { - response_skeleton_opt: None, - }, - accountant.config.scan_intervals.payable_scan_interval, - ctx, - ); - }), - ), - receivables: Scanner::new( - ScanType::Receivables, - Box::new(|accountant, response_skeleton_opt| { - // TODO: Figure out how to combine the results of these two into a single response to the UI - accountant.scan_for_receivables(response_skeleton_opt); - accountant.scan_for_delinquencies(); - }), - Box::new(|accountant, ctx| { - let _ = accountant.notify_later.scan_for_receivable.notify_later( - ScanForReceivables { - response_skeleton_opt: None, - }, - accountant.config.scan_intervals.receivable_scan_interval, - ctx, - ); - }), - ), - } + todo!() } } - pub struct Scanner { - scan_type: ScanType, - initiated_at: RefCell>, - scan: Scan, - notify_later_assertable: RefCell, + // struct ScannerADao {} + // struct ScannerBDao {} + // + // struct BeginScanAMessage{ + // + // } + // + // impl Message for BeginScanAMessage{} + // + // struct FinishScanAMessage { + // + // } + // + // impl Message for FinishScanAMessage{} + // + // struct BeginScanBMessage { + // + // } + // + // impl Message for BeginScanBMessage{} + // + // struct FinishScanBMessage { + // + // } + // + // impl Message for FinishScanAMessage{} + + pub trait Scanner + where + BeginMessage: Message + Send + 'static, + BeginMessage::Result: Send, + EndMessage: Message, + { + fn begin_scan( + &mut self, + timestamp: SystemTime, + response_skeleton_opt: Option, + ctx: &mut Context, + ) -> Result>, Error>; + fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error>; + fn scan_started_at(&self) -> Option; + } + + struct ScannerCommon { + initiated_at_opt: Option, } - impl Scanner { - pub fn new( - scan_type: ScanType, - scan: Scan, - notify_later_assertable: NotifyLaterAssertable, - ) -> Scanner { - Scanner { - scan_type, - initiated_at: RefCell::new(None), - scan, - notify_later_assertable: RefCell::new(notify_later_assertable), + impl Default for ScannerCommon { + fn default() -> Self { + Self { + initiated_at_opt: None, } } + } - pub fn scan( - &self, - accountant: &Accountant, - response_skeleton_opt: Option, - ) -> Result<(), String> { - if let Some(initiated_at) = self.initiated_at.borrow().as_ref() { - return Err(format!( - "{:?} scan was already initiated at {}. Hence, this scan request will be ignored.", - self.scan_type, timestamp_as_string(&initiated_at) - )); - }; - - // self.mark_as_started(SystemTime::now()); + pub struct PayableScanner { + common: ScannerCommon, + dao: Box, + } - (self.scan)(accountant, response_skeleton_opt); - Ok(()) + impl Scanner for PayableScanner + where + BeginMessage: Message + Send + 'static, + BeginMessage::Result: Send, + EndMessage: Message, + { + fn begin_scan( + &mut self, + timestamp: SystemTime, + response_skeleton_opt: Option, + ctx: &mut Context, + ) -> Result>, Error> { + todo!() + // common::start_scan_at(&mut self.common, timestamp); + // let start_message = BeginScanAMessage {}; + // // Use the DAO, if necessary, to populate start_message + // Ok(start_message) } - pub fn notify_later_assertable( - &self, - accountant: &Accountant, - ctx: &mut Context, - ) { - (self.notify_later_assertable.borrow_mut())(accountant, ctx); + fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + todo!() + // Use the passed-in message and the internal DAO to finish the scan + // Ok(()) } - pub fn scan_type(&self) -> ScanType { - self.scan_type + fn scan_started_at(&self) -> Option { + todo!() + // common::scan_started_at(&self.common) } + } - pub fn initiated_at(&self) -> Option { - *self.initiated_at.borrow() + impl PayableScanner { + pub fn new(dao: Box) -> Self { + Self { + common: ScannerCommon::default(), + dao, + } } + } - pub fn is_scan_running(&self) -> bool { - self.initiated_at.borrow().is_some() + // pub struct ScannerB { + // common: ScannerCommon, + // dao: ScannerBDao, + // } + // + // impl ScannerB { + // pub fn new(dao: ScannerBDao) -> Self { + // Self { + // common: ScannerCommon::default(), + // dao, + // } + // } + // } + // + // mod common { + // use crate::scanner_experiment::ScannerCommon; + // use std::time::SystemTime; + // + // pub fn scan_started_at(scanner: &ScannerCommon) -> Option { + // scanner.initiated_at_opt + // } + // + // pub fn start_scan_at(scanner: &mut ScannerCommon, timestamp: SystemTime) { + // if let Some(initiated_at) = scanner.initiated_at_opt { + // panic! ("Scan {:?} has been running for {:?} seconds; it cannot be restarted until it finishes.", "blah", SystemTime::now().duration_since(initiated_at)); + // } + // scanner.initiated_at_opt = Some(timestamp); + // } + // } + + pub trait BeginMessageWrapper + where + BeginMessage: Message + Send + 'static, + BeginMessage::Result: Send, + { + fn try_send( + &mut self, + recipient: &Recipient, + ) -> Result<(), SendError>; + } + + pub struct NullScanner {} + + impl Scanner for NullScanner + where + BeginMessage: Message + Send + 'static, + BeginMessage::Result: Send, + EndMessage: Message, + { + fn begin_scan( + &mut self, + timestamp: SystemTime, + response_skeleton_opt: Option, + ctx: &mut Context, + ) -> Result>, Error> { + todo!() } - pub fn mark_as_started(&self, timestamp: SystemTime) { - *self.initiated_at.borrow_mut() = Some(timestamp); + fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + todo!() } - pub fn mark_as_ended(&self) { - *self.initiated_at.borrow_mut() = None; + fn scan_started_at(&self) -> Option { + todo!() } } @@ -170,122 +227,15 @@ pub(in crate::accountant) mod scanners { #[cfg(test)] mod tests { - use crate::accountant::payable_dao::PayableAccount; - use crate::accountant::scanners::scanners::Scanners; - use crate::accountant::test_utils::{ - bc_from_ac_plus_earning_wallet, AccountantBuilder, PayableDaoMock, - }; - use crate::accountant::Accountant; - use crate::database::dao_utils::{from_time_t, to_time_t}; - use crate::sub_lib::accountant::DEFAULT_PAYMENT_THRESHOLDS; - use crate::test_utils::make_wallet; - use crate::test_utils::recorder::make_recorder; - use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; - use actix::Actor; - use masq_lib::logger::timestamp_as_string; - use masq_lib::messages::ScanType; - use std::time::SystemTime; - - #[test] - fn scan_can_be_marked_as_started() { - let subject = Scanners::default(); - let initial_flag = subject.payables.is_scan_running(); - let now = SystemTime::now(); - - subject.payables.mark_as_started(now); - - let final_flag = subject.payables.is_scan_running(); - assert_eq!(initial_flag, false); - assert_eq!(final_flag, true); - assert_eq!(subject.payables.initiated_at(), Some(now)); - } - - #[test] - fn scan_can_be_marked_as_ended() { - let subject = Scanners::default(); - subject.payables.mark_as_started(SystemTime::now()); - let is_scan_running_initially = subject.payables.is_scan_running(); - - subject.payables.mark_as_ended(); - - let is_scan_running_finally = subject.payables.is_scan_running(); - assert_eq!(is_scan_running_initially, true); - assert_eq!(is_scan_running_finally, false); - assert_eq!(subject.payables.initiated_at(), None) - } - - #[test] - fn scanners_are_defaulted_properly() { - let subject = Scanners::default(); - - assert_eq!( - subject.pending_payables.scan_type(), - ScanType::PendingPayables - ); - assert_eq!(subject.payables.scan_type(), ScanType::Payables); - assert_eq!(subject.receivables.scan_type(), ScanType::Receivables); - assert_eq!(subject.pending_payables.is_scan_running(), false); - assert_eq!(subject.payables.is_scan_running(), false); - assert_eq!(subject.receivables.is_scan_running(), false); - } + use super::*; + use crate::accountant::payable_dao::PayableDaoReal; + use crate::accountant::scanners::scanners::PayableScanner; + use crate::accountant::test_utils::PayableDaoMock; #[test] - fn scan_function_throws_error_in_case_scan_is_already_running() { - let subject = Scanners::default(); - let accountant = AccountantBuilder::default() - .bootstrapper_config(bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_wallet("some_wallet_address"), - )) - .build(); - let now = SystemTime::now(); - subject.pending_payables.mark_as_started(now); - - let result = subject.pending_payables.scan(&accountant, None); + fn payable_scanner_can_be_constructed() { + let payable_dao = PayableDaoMock::new(); - assert_eq!( - result, - Err(format!( - "PendingPayables scan was already initiated at {}. \ - Hence, this scan request will be ignored.", - timestamp_as_string(&now) - )) - ); + let payable_scanner = PayableScanner::new(Box::new(payable_dao)); } - - // #[test] - // fn scan_function_marks_scan_has_started_when_a_scan_is_not_already_running() { - // let subject = Scanners::default(); - // let accountant = make_accountant_for_payables(); - // - // let result = subject.payables.scan(&accountant, None); - // - // assert_eq!(result, Ok(())); - // assert_eq!(subject.payables.is_scan_running(), true); - // } - // - // fn make_accountant_for_payables() -> Accountant { - // let payable_dao = PayableDaoMock::default(); - // let (blockchain_bridge, _, _) = make_recorder(); - // let report_accounts_payable_sub = blockchain_bridge.start().recipient(); - // let now = - // to_time_t(SystemTime::now()) - DEFAULT_PAYMENT_THRESHOLDS.maturity_threshold_sec - 1; - // let payable_account = PayableAccount { - // wallet: make_wallet("scan_for_payables"), - // balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 1, - // last_paid_timestamp: from_time_t(now), - // pending_payable_opt: None, - // }; - // let payable_dao = payable_dao.non_pending_payables_result(vec![payable_account.clone()]); - // let mut accountant = AccountantBuilder::default() - // .bootstrapper_config(bc_from_ac_plus_earning_wallet( - // make_populated_accountant_config_with_defaults(), - // make_wallet("some_wallet_address"), - // )) - // .payable_dao(payable_dao) - // .build(); - // accountant.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - // - // accountant - // } } From 9497874514d8958508b9e89128d9975890a493a4 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 21 Jul 2022 14:39:29 +0530 Subject: [PATCH 026/145] GH-611: scanners struct can be constructed with the respective scanners --- node/src/accountant/mod.rs | 7 +- node/src/accountant/scanners.rs | 172 ++++++++++++++++++++++-------- node/src/accountant/test_utils.rs | 4 + 3 files changed, 139 insertions(+), 44 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index e54ee63f9..0fe93480c 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -432,7 +432,12 @@ impl Accountant { pending_payable_dao: pending_payable_dao_factory.make(), banned_dao: banned_dao_factory.make(), crashable: config.crash_point == CrashPoint::Message, - scanners: Scanners::default(), + // TODO: pending_payable_dao and receivable_dao can live inside Scanners instead of Accountant + scanners: Scanners::new( + payable_dao_factory.make(), + pending_payable_dao_factory.make(), + receivable_dao_factory.make(), + ), tools: TransactionConfirmationTools::default(), notify_later: NotifyLaterForScanners::default(), financial_statistics: FinancialStatistics::default(), diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 22ac9e4a4..daebf3715 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -1,7 +1,9 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. pub(in crate::accountant) mod scanners { - use crate::accountant::payable_dao::PayableDao; + use crate::accountant::payable_dao::{PayableDao, PayableDaoReal}; + use crate::accountant::pending_payable_dao::PendingPayableDao; + use crate::accountant::receivable_dao::ReceivableDao; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, ReportTransactionReceipts, RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, @@ -14,6 +16,8 @@ pub(in crate::accountant) mod scanners { use actix::{Context, Message, Recipient}; use masq_lib::logger::timestamp_as_string; use masq_lib::messages::ScanType; + use masq_lib::messages::ScanType::PendingPayables; + use std::any::Any; use std::cell::RefCell; use std::time::SystemTime; @@ -26,17 +30,17 @@ pub(in crate::accountant) mod scanners { pub receivables: Box>, } - // - // pub struct Scanners { - // pub payables: Box>, - // pub pending_payable: - // Box>, - // pub receivables: Box>, - // } - - impl Default for Scanners { - fn default() -> Self { - todo!() + impl Scanners { + pub(crate) fn new( + payable_dao: Box, + pending_payable_dao: Box, + receivable_dao: Box, + ) -> Self { + Scanners { + payables: Box::new(PayableScanner::new(payable_dao)), + pending_payables: Box::new(PendingPayableScanner::new(pending_payable_dao)), + receivables: Box::new(ReceivableScanner::new(receivable_dao)), + } } } @@ -81,6 +85,7 @@ pub(in crate::accountant) mod scanners { ) -> Result>, Error>; fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error>; fn scan_started_at(&self) -> Option; + as_any_dcl!(); } struct ScannerCommon { @@ -129,6 +134,8 @@ pub(in crate::accountant) mod scanners { todo!() // common::scan_started_at(&self.common) } + + as_any_impl!(); } impl PayableScanner { @@ -140,35 +147,85 @@ pub(in crate::accountant) mod scanners { } } - // pub struct ScannerB { - // common: ScannerCommon, - // dao: ScannerBDao, - // } - // - // impl ScannerB { - // pub fn new(dao: ScannerBDao) -> Self { - // Self { - // common: ScannerCommon::default(), - // dao, - // } - // } - // } - // - // mod common { - // use crate::scanner_experiment::ScannerCommon; - // use std::time::SystemTime; - // - // pub fn scan_started_at(scanner: &ScannerCommon) -> Option { - // scanner.initiated_at_opt - // } - // - // pub fn start_scan_at(scanner: &mut ScannerCommon, timestamp: SystemTime) { - // if let Some(initiated_at) = scanner.initiated_at_opt { - // panic! ("Scan {:?} has been running for {:?} seconds; it cannot be restarted until it finishes.", "blah", SystemTime::now().duration_since(initiated_at)); - // } - // scanner.initiated_at_opt = Some(timestamp); - // } - // } + pub struct PendingPayableScanner { + common: ScannerCommon, + dao: Box, + } + + impl Scanner for PendingPayableScanner + where + BeginMessage: Message + Send + 'static, + BeginMessage::Result: Send, + EndMessage: Message, + { + fn begin_scan( + &mut self, + timestamp: SystemTime, + response_skeleton_opt: Option, + ctx: &mut Context, + ) -> Result>, Error> { + todo!() + } + + fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + todo!() + } + + fn scan_started_at(&self) -> Option { + todo!() + } + + as_any_impl!(); + } + + impl PendingPayableScanner { + pub fn new(dao: Box) -> Self { + Self { + common: ScannerCommon::default(), + dao, + } + } + } + + pub struct ReceivableScanner { + common: ScannerCommon, + dao: Box, + } + + impl Scanner for ReceivableScanner + where + BeginMessage: Message + Send + 'static, + BeginMessage::Result: Send, + EndMessage: Message, + { + fn begin_scan( + &mut self, + timestamp: SystemTime, + response_skeleton_opt: Option, + ctx: &mut Context, + ) -> Result>, Error> { + todo!() + } + + fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + todo!() + } + + fn scan_started_at(&self) -> Option { + todo!() + } + + as_any_impl!(); + } + + impl ReceivableScanner { + pub fn new(dao: Box) -> Self { + Self { + common: ScannerCommon::default(), + dao, + } + } + } pub trait BeginMessageWrapper where @@ -205,6 +262,8 @@ pub(in crate::accountant) mod scanners { fn scan_started_at(&self) -> Option { todo!() } + + as_any_impl!(); } #[derive(Default)] @@ -229,8 +288,35 @@ pub(in crate::accountant) mod scanners { mod tests { use super::*; use crate::accountant::payable_dao::PayableDaoReal; - use crate::accountant::scanners::scanners::PayableScanner; - use crate::accountant::test_utils::PayableDaoMock; + use crate::accountant::scanners::scanners::{ + PayableScanner, PendingPayableScanner, ReceivableScanner, Scanners, + }; + use crate::accountant::test_utils::{PayableDaoMock, PendingPayableDaoMock, ReceivableDaoMock}; + + #[test] + fn scanners_struct_can_be_constructed_with_the_respective_scanners() { + let scanners = Scanners::new( + Box::new(PayableDaoMock::new()), + Box::new(PendingPayableDaoMock::new()), + Box::new(ReceivableDaoMock::new()), + ); + + scanners + .payables + .as_any() + .downcast_ref::() + .unwrap(); + scanners + .pending_payables + .as_any() + .downcast_ref::() + .unwrap(); + scanners + .receivables + .as_any() + .downcast_ref::() + .unwrap(); + } #[test] fn payable_scanner_can_be_constructed() { diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 262f776fe..37fb7ed41 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -721,6 +721,10 @@ impl PendingPayableDao for PendingPayableDaoMock { } impl PendingPayableDaoMock { + pub fn new() -> Self { + PendingPayableDaoMock::default() + } + pub fn fingerprint_rowid_params(mut self, params: &Arc>>) -> Self { self.fingerprint_rowid_params = params.clone(); self From 4f7fbd2a14e09488222719a6b82bbbbf2847945a Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 22 Jul 2022 11:17:22 +0530 Subject: [PATCH 027/145] GH-611: eliminate the BeginMessageWrapper --- node/src/accountant/scanners.rs | 44 +++++++++------------------------ 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index daebf3715..f282ef916 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -31,7 +31,7 @@ pub(in crate::accountant) mod scanners { } impl Scanners { - pub(crate) fn new( + pub fn new( payable_dao: Box, pending_payable_dao: Box, receivable_dao: Box, @@ -73,8 +73,7 @@ pub(in crate::accountant) mod scanners { pub trait Scanner where - BeginMessage: Message + Send + 'static, - BeginMessage::Result: Send, + BeginMessage: Message, EndMessage: Message, { fn begin_scan( @@ -82,7 +81,7 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, ctx: &mut Context, - ) -> Result>, Error>; + ) -> Result; fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error>; fn scan_started_at(&self) -> Option; as_any_dcl!(); @@ -107,8 +106,7 @@ pub(in crate::accountant) mod scanners { impl Scanner for PayableScanner where - BeginMessage: Message + Send + 'static, - BeginMessage::Result: Send, + BeginMessage: Message, EndMessage: Message, { fn begin_scan( @@ -116,8 +114,8 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, ctx: &mut Context, - ) -> Result>, Error> { - todo!() + ) -> Result { + todo!("Begin Scan for PayableScanner"); // common::start_scan_at(&mut self.common, timestamp); // let start_message = BeginScanAMessage {}; // // Use the DAO, if necessary, to populate start_message @@ -154,8 +152,7 @@ pub(in crate::accountant) mod scanners { impl Scanner for PendingPayableScanner where - BeginMessage: Message + Send + 'static, - BeginMessage::Result: Send, + BeginMessage: Message, EndMessage: Message, { fn begin_scan( @@ -163,7 +160,7 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, ctx: &mut Context, - ) -> Result>, Error> { + ) -> Result { todo!() } @@ -194,8 +191,7 @@ pub(in crate::accountant) mod scanners { impl Scanner for ReceivableScanner where - BeginMessage: Message + Send + 'static, - BeginMessage::Result: Send, + BeginMessage: Message, EndMessage: Message, { fn begin_scan( @@ -203,7 +199,7 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, ctx: &mut Context, - ) -> Result>, Error> { + ) -> Result { todo!() } @@ -227,17 +223,6 @@ pub(in crate::accountant) mod scanners { } } - pub trait BeginMessageWrapper - where - BeginMessage: Message + Send + 'static, - BeginMessage::Result: Send, - { - fn try_send( - &mut self, - recipient: &Recipient, - ) -> Result<(), SendError>; - } - pub struct NullScanner {} impl Scanner for NullScanner @@ -251,7 +236,7 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, ctx: &mut Context, - ) -> Result>, Error> { + ) -> Result { todo!() } @@ -317,11 +302,4 @@ mod tests { .downcast_ref::() .unwrap(); } - - #[test] - fn payable_scanner_can_be_constructed() { - let payable_dao = PayableDaoMock::new(); - - let payable_scanner = PayableScanner::new(Box::new(payable_dao)); - } } From 57ca413d4ece9cc9b493913ef493a52f67e18113 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 22 Jul 2022 17:43:09 +0530 Subject: [PATCH 028/145] GH-611: modify PayableDAOMock --- node/src/accountant/mod.rs | 16 ++++++----- node/src/accountant/test_utils.rs | 45 ++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 0fe93480c..0b9d29fc5 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1447,10 +1447,11 @@ mod tests { fn new_calls_factories_properly() { let mut config = BootstrapperConfig::new(); config.accountant_config_opt = Some(make_accountant_config_null()); - let payable_dao_factory_called = Rc::new(RefCell::new(false)); let payable_dao = PayableDaoMock::new(); - let payable_dao_factory = - PayableDaoFactoryMock::new(payable_dao).called(&payable_dao_factory_called); + let payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); + let payable_dao_factory = PayableDaoFactoryMock::new() + .make_params(&payable_dao_factory_params_arc) + .make_result(PayableDaoMock::new()); let receivable_dao_factory_called = Rc::new(RefCell::new(false)); let receivable_dao = ReceivableDaoMock::new(); let receivable_dao_factory = @@ -1472,7 +1473,7 @@ mod tests { Box::new(banned_dao_factory), ); - assert_eq!(payable_dao_factory_called.as_ref(), &RefCell::new(true)); + assert_eq!(*payable_dao_factory_params_arc.lock().unwrap(), vec![()]); assert_eq!(receivable_dao_factory_called.as_ref(), &RefCell::new(true)); assert_eq!( pending_payable_dao_factory_called.as_ref(), @@ -1492,7 +1493,8 @@ mod tests { let mut bootstrapper_config = BootstrapperConfig::new(); bootstrapper_config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); - let payable_dao_factory = Box::new(PayableDaoFactoryMock::new(PayableDaoMock::new())); + let payable_dao_factory = + Box::new(PayableDaoFactoryMock::new().make_result(PayableDaoMock::new())); let receivable_dao_factory = Box::new(ReceivableDaoFactoryMock::new(ReceivableDaoMock::new())); let pending_payable_dao_factory = Box::new(PendingPayableDaoFactoryMock::new( @@ -2206,6 +2208,7 @@ mod tests { earning_wallet.clone(), )) .payable_dao(PayableDaoMock::new().non_pending_payables_result(vec![])) + .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao) .build(); let system = System::new("accountant_receives_new_payments_to_the_receivables_dao"); @@ -3927,7 +3930,8 @@ mod tests { PendingPayableDaoError::UpdateFailed("no no no".to_string()), )); let subject = AccountantBuilder::default() - .payable_dao(payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .pending_payable_dao(pending_payable_dao) .build(); let rowid = 2; diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 37fb7ed41..300fe2679 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -70,7 +70,7 @@ pub fn make_payable_account_with_recipient_and_balance_and_timestamp_opt( pub struct AccountantBuilder { config: Option, - payable_dao_factory: Option>, + payable_dao_factory: Option, receivable_dao_factory: Option>, pending_payable_dao_factory: Option>, banned_dao_factory: Option>, @@ -97,7 +97,15 @@ impl AccountantBuilder { } pub fn payable_dao(mut self, payable_dao: PayableDaoMock) -> Self { - self.payable_dao_factory = Some(Box::new(PayableDaoFactoryMock::new(payable_dao))); + match self.payable_dao_factory { + None => { + self.payable_dao_factory = + Some(PayableDaoFactoryMock::new().make_result(payable_dao)) + } + Some(payable_dao_factory) => { + self.payable_dao_factory = Some(payable_dao_factory.make_result(payable_dao)) + } + } self } @@ -129,9 +137,11 @@ impl AccountantBuilder { config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); config }); - let payable_dao_factory = self - .payable_dao_factory - .unwrap_or(Box::new(PayableDaoFactoryMock::new(PayableDaoMock::new()))); + let payable_dao_factory = self.payable_dao_factory.unwrap_or( + PayableDaoFactoryMock::new() + .make_result(PayableDaoMock::new()) + .make_result(PayableDaoMock::new()), + ); let receivable_dao_factory = self.receivable_dao_factory .unwrap_or(Box::new(ReceivableDaoFactoryMock::new( @@ -145,7 +155,7 @@ impl AccountantBuilder { .unwrap_or(Box::new(BannedDaoFactoryMock::new(BannedDaoMock::new()))); let accountant = Accountant::new( &config, - payable_dao_factory, + Box::new(payable_dao_factory), receivable_dao_factory, pending_payable_dao_factory, banned_dao_factory, @@ -155,27 +165,32 @@ impl AccountantBuilder { } pub struct PayableDaoFactoryMock { - called: Rc>, - mock: RefCell>, + make_params: Arc>>, + make_results: RefCell>>, } impl PayableDaoFactory for PayableDaoFactoryMock { fn make(&self) -> Box { - *self.called.borrow_mut() = true; - Box::new(self.mock.borrow_mut().remove(0)) + self.make_params.lock().unwrap().push(()); + self.make_results.borrow_mut().remove(0) } } impl PayableDaoFactoryMock { - pub fn new(mock: PayableDaoMock) -> Self { + pub fn new() -> Self { Self { - called: Rc::new(RefCell::new(false)), - mock: RefCell::new(vec![mock]), + make_params: Arc::new(Mutex::new(vec![])), + make_results: RefCell::new(vec![]), } } - pub fn called(mut self, called: &Rc>) -> Self { - self.called = called.clone(); + pub fn make_params(mut self, params: &Arc>>) -> Self { + self.make_params = params.clone(); + self + } + + pub fn make_result(self, result: PayableDaoMock) -> Self { + self.make_results.borrow_mut().push(Box::new(result)); self } } From 3e9651d917139b33e3bdb94e4d96abe6250012c1 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 25 Jul 2022 13:36:44 +0530 Subject: [PATCH 029/145] GH-611: modify PendingPayableDaoFactoryMock and ReceivableDaoFactoryMock --- node/src/accountant/mod.rs | 29 ++++------ node/src/accountant/test_utils.rs | 96 ++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 51 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 0b9d29fc5..5460edbac 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1447,19 +1447,14 @@ mod tests { fn new_calls_factories_properly() { let mut config = BootstrapperConfig::new(); config.accountant_config_opt = Some(make_accountant_config_null()); - let payable_dao = PayableDaoMock::new(); let payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let payable_dao_factory = PayableDaoFactoryMock::new() .make_params(&payable_dao_factory_params_arc) .make_result(PayableDaoMock::new()); - let receivable_dao_factory_called = Rc::new(RefCell::new(false)); - let receivable_dao = ReceivableDaoMock::new(); let receivable_dao_factory = - ReceivableDaoFactoryMock::new(receivable_dao).called(&receivable_dao_factory_called); - let pending_payable_dao_factory_called = Rc::new(RefCell::new(false)); - let pending_payable_dao = PendingPayableDaoMock::default(); - let pending_payable_dao_factory = PendingPayableDaoFactoryMock::new(pending_payable_dao) - .called(&pending_payable_dao_factory_called); + ReceivableDaoFactoryMock::new().make_result(ReceivableDaoMock::new()); + let pending_payable_dao_factory = + PendingPayableDaoFactoryMock::new().make_result(PendingPayableDaoMock::new()); let banned_dao_factory_called = Rc::new(RefCell::new(false)); let banned_dao = BannedDaoMock::new(); let banned_dao_factory = @@ -1474,11 +1469,12 @@ mod tests { ); assert_eq!(*payable_dao_factory_params_arc.lock().unwrap(), vec![()]); - assert_eq!(receivable_dao_factory_called.as_ref(), &RefCell::new(true)); - assert_eq!( - pending_payable_dao_factory_called.as_ref(), - &RefCell::new(true) - ); + // TODO: Find a way to use different assert statements in place of these. + // assert_eq!(receivable_dao_factory_called.as_ref(), &RefCell::new(true)); + // assert_eq!( + // pending_payable_dao_factory_called.as_ref(), + // &RefCell::new(true) + // ); assert_eq!(banned_dao_factory_called.as_ref(), &RefCell::new(true)); } @@ -1496,10 +1492,9 @@ mod tests { let payable_dao_factory = Box::new(PayableDaoFactoryMock::new().make_result(PayableDaoMock::new())); let receivable_dao_factory = - Box::new(ReceivableDaoFactoryMock::new(ReceivableDaoMock::new())); - let pending_payable_dao_factory = Box::new(PendingPayableDaoFactoryMock::new( - PendingPayableDaoMock::default(), - )); + Box::new(ReceivableDaoFactoryMock::new().make_result(ReceivableDaoMock::new())); + let pending_payable_dao_factory = + Box::new(PendingPayableDaoFactoryMock::new().make_result(PendingPayableDaoMock::new())); let banned_dao_factory = Box::new(BannedDaoFactoryMock::new(BannedDaoMock::new())); let result = Accountant::new( diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 300fe2679..049e73e16 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -71,8 +71,8 @@ pub fn make_payable_account_with_recipient_and_balance_and_timestamp_opt( pub struct AccountantBuilder { config: Option, payable_dao_factory: Option, - receivable_dao_factory: Option>, - pending_payable_dao_factory: Option>, + receivable_dao_factory: Option, + pending_payable_dao_factory: Option, banned_dao_factory: Option>, config_dao_factory: Option>, } @@ -110,14 +110,30 @@ impl AccountantBuilder { } pub fn receivable_dao(mut self, receivable_dao: ReceivableDaoMock) -> Self { - self.receivable_dao_factory = Some(Box::new(ReceivableDaoFactoryMock::new(receivable_dao))); + match self.receivable_dao_factory { + None => { + self.receivable_dao_factory = + Some(ReceivableDaoFactoryMock::new().make_result(receivable_dao)) + } + Some(receivable_dao_factory) => { + self.receivable_dao_factory = + Some(receivable_dao_factory.make_result(receivable_dao)) + } + } self } pub fn pending_payable_dao(mut self, pending_payable_dao: PendingPayableDaoMock) -> Self { - self.pending_payable_dao_factory = Some(Box::new(PendingPayableDaoFactoryMock::new( - pending_payable_dao, - ))); + match self.pending_payable_dao_factory { + None => { + self.pending_payable_dao_factory = + Some(PendingPayableDaoFactoryMock::new().make_result(pending_payable_dao)) + } + Some(pending_payable_dao_factory) => { + self.pending_payable_dao_factory = + Some(pending_payable_dao_factory.make_result(pending_payable_dao)) + } + } self } @@ -142,22 +158,24 @@ impl AccountantBuilder { .make_result(PayableDaoMock::new()) .make_result(PayableDaoMock::new()), ); - let receivable_dao_factory = - self.receivable_dao_factory - .unwrap_or(Box::new(ReceivableDaoFactoryMock::new( - ReceivableDaoMock::new(), - ))); - let pending_payable_dao_factory = self.pending_payable_dao_factory.unwrap_or(Box::new( - PendingPayableDaoFactoryMock::new(PendingPayableDaoMock::default()), - )); + let receivable_dao_factory = self.receivable_dao_factory.unwrap_or( + ReceivableDaoFactoryMock::new() + .make_result(ReceivableDaoMock::new()) + .make_result(ReceivableDaoMock::new()), + ); + let pending_payable_dao_factory = self.pending_payable_dao_factory.unwrap_or( + PendingPayableDaoFactoryMock::new() + .make_result(PendingPayableDaoMock::new()) + .make_result(PendingPayableDaoMock::new()), + ); let banned_dao_factory = self .banned_dao_factory .unwrap_or(Box::new(BannedDaoFactoryMock::new(BannedDaoMock::new()))); let accountant = Accountant::new( &config, Box::new(payable_dao_factory), - receivable_dao_factory, - pending_payable_dao_factory, + Box::new(receivable_dao_factory), + Box::new(pending_payable_dao_factory), banned_dao_factory, ); accountant @@ -196,27 +214,32 @@ impl PayableDaoFactoryMock { } pub struct ReceivableDaoFactoryMock { - called: Rc>, - mock: RefCell>, + make_params: Arc>>, + make_results: RefCell>>, } impl ReceivableDaoFactory for ReceivableDaoFactoryMock { fn make(&self) -> Box { - *self.called.borrow_mut() = true; - Box::new(self.mock.borrow_mut().remove(0)) + self.make_params.lock().unwrap().push(()); + self.make_results.borrow_mut().remove(0) } } impl ReceivableDaoFactoryMock { - pub fn new(mock: ReceivableDaoMock) -> Self { + pub fn new() -> Self { Self { - called: Rc::new(RefCell::new(false)), - mock: RefCell::new(vec![mock]), + make_params: Arc::new(Mutex::new(vec![])), + make_results: RefCell::new(vec![]), } } - pub fn called(mut self, called: &Rc>) -> Self { - self.called = called.clone(); + pub fn make_params(mut self, params: &Arc>>) -> Self { + self.make_params = params.clone(); + self + } + + pub fn make_result(self, result: ReceivableDaoMock) -> Self { + self.make_results.borrow_mut().push(Box::new(result)); self } } @@ -807,27 +830,32 @@ impl PendingPayableDaoMock { } pub struct PendingPayableDaoFactoryMock { - called: Rc>, - mock: RefCell>, + make_params: Arc>>, + make_results: RefCell>>, } impl PendingPayableDaoFactory for PendingPayableDaoFactoryMock { fn make(&self) -> Box { - *self.called.borrow_mut() = true; - Box::new(self.mock.borrow_mut().remove(0)) + self.make_params.lock().unwrap().push(()); + self.make_results.borrow_mut().remove(0) } } impl PendingPayableDaoFactoryMock { - pub fn new(mock: PendingPayableDaoMock) -> Self { + pub fn new() -> Self { Self { - called: Rc::new(RefCell::new(false)), - mock: RefCell::new(vec![mock]), + make_params: Arc::new(Mutex::new(vec![])), + make_results: RefCell::new(vec![]), } } - pub fn called(mut self, called: &Rc>) -> Self { - self.called = called.clone(); + pub fn make_params(mut self, params: &Arc>>) -> Self { + self.make_params = params.clone(); + self + } + + pub fn make_result(self, result: PendingPayableDaoMock) -> Self { + self.make_results.borrow_mut().push(Box::new(result)); self } } From 9fe65c787f930c21c7a528b31827006f452edb75 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 25 Jul 2022 15:57:07 +0530 Subject: [PATCH 030/145] GH-611: supply DAOs for Scanner inside the tests of accountant/mod.rs --- node/src/accountant/mod.rs | 315 ++++++++++++++++++++---------- node/src/accountant/scanners.rs | 6 +- node/src/accountant/test_utils.rs | 15 ++ 3 files changed, 225 insertions(+), 111 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 5460edbac..3a9df132a 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -655,7 +655,7 @@ impl Accountant { .as_ref() .more_money_receivable(wallet, total_charge) { Ok(_) => (), - Err(ReceivableDaoError::SignConversion(_)) => error! ( + Err(ReceivableDaoError::SignConversion(_)) => error!( self.logger, "Overflow error recording service provided for {}: service rate {}, byte rate {}, payload size {}. Skipping", wallet, @@ -663,7 +663,7 @@ impl Accountant { byte_rate, payload_size ), - Err(e)=> panic!("Recording services provided for {} but has hit fatal database error: {:?}", wallet, e) + Err(e) => panic!("Recording services provided for {} but has hit fatal database error: {:?}", wallet, e) }; } else { info!( @@ -687,7 +687,7 @@ impl Accountant { .as_ref() .more_money_payable(wallet, total_charge) { Ok(_) => (), - Err(PayableDaoError::SignConversion(_)) => error! ( + Err(PayableDaoError::SignConversion(_)) => error!( self.logger, "Overflow error recording consumed services from {}: total charge {}, service rate {}, byte rate {}, payload size {}. Skipping", wallet, @@ -840,9 +840,9 @@ impl Accountant { self.mark_pending_payable(ok); if !err.is_empty() { err.into_iter().for_each(|err| - if let Some(hash) = err.carries_transaction_hash(){ - self.discard_incomplete_transaction_with_a_failure(hash) - } else {debug!(self.logger,"Forgetting a transaction attempt that even did not reach the signing stage")}) + if let Some(hash) = err.carries_transaction_hash() { + self.discard_incomplete_transaction_with_a_failure(hash) + } else { debug!(self.logger,"Forgetting a transaction attempt that even did not reach the signing stage") }) } if let Some(response_skeleton) = &sent_payable.response_skeleton_opt { self.ui_message_sub @@ -863,7 +863,7 @@ impl Accountant { "Deleting an existing backup for a failed transaction {}", hash ); if let Err(e) = self.pending_payable_dao.delete_fingerprint(rowid) { - panic!("Database unmaintainable; payable fingerprint deletion for transaction {:?} has stayed undone due to {:?}", hash,e) + panic!("Database unmaintainable; payable fingerprint deletion for transaction {:?} has stayed undone due to {:?}", hash, e) } }; @@ -974,7 +974,7 @@ impl Accountant { scan_type: ScanType, response_skeleton: ResponseSkeleton, ) -> Result<(), String> { - todo!() + todo!("Implement for Externally Triggered Scan.") // match scan_type { // ScanType::Payables => self.scanners.payables.scan(self, Some(response_skeleton)), // ScanType::Receivables => self @@ -996,7 +996,7 @@ impl Accountant { Ok(_) => warning!( self.logger, "Broken transaction {} left with an error mark; you should take over the care of this transaction to make sure your debts will be paid because there is no automated process that can fix this without you", msg.id.hash), - Err(e) => panic!("Unsuccessful attempt for transaction {} to mark fatal error at payable fingerprint due to {:?}; database unreliable", msg.id.hash,e), + Err(e) => panic!("Unsuccessful attempt for transaction {} to mark fatal error at payable fingerprint due to {:?}; database unreliable", msg.id.hash, e), } } @@ -1021,7 +1021,7 @@ impl Accountant { .rowid_opt .expectv("initialized rowid"), ) { - panic!("Was unable to delete payable fingerprint '{}' after successful transaction due to '{:?}'",msg.pending_payable_fingerprint.hash,e) + panic!("Was unable to delete payable fingerprint '{}' after successful transaction due to '{:?}'", msg.pending_payable_fingerprint.hash, e) } else { info!( self.logger, @@ -1039,15 +1039,15 @@ impl Accountant { sent_payments .payable .iter() - .fold((vec![],vec![]),|so_far,payment| { - match payment{ - Ok(payment_sent) => (plus(so_far.0,payment_sent.clone()),so_far.1), + .fold((vec![], vec![]), |so_far, payment| { + match payment { + Ok(payment_sent) => (plus(so_far.0, payment_sent.clone()), so_far.1), Err(error) => { logger.warning(|| match &error { BlockchainError::TransactionFailed { .. } => format!("Encountered transaction error at this end: '{:?}'", error), x => format!("Outbound transaction failure due to '{:?}'. Please check your blockchain service URL configuration.", x) }); - (so_far.0,plus(so_far.1,error.clone())) + (so_far.0, plus(so_far.1, error.clone())) } } }) @@ -1061,7 +1061,7 @@ impl Accountant { Some(rowid) => rowid, None => panic!("Payable fingerprint for {} doesn't exist but should by now; system unreliable", payable.tx_hash) }; - match self.payable_dao.as_ref().mark_pending_payable_rowid(&payable.to, rowid ) { + match self.payable_dao.as_ref().mark_pending_payable_rowid(&payable.to, rowid) { Ok(()) => (), Err(e) => panic!("Was unable to create a mark in payables for a new pending payable '{}' due to '{:?}'", payable.tx_hash, e) } @@ -1145,15 +1145,15 @@ impl Accountant { error!(logger,"Pending transaction '{}' announced as a failure, interpreting attempt {} after {}ms from the sending",fingerprint.hash,fingerprint.attempt_opt.expectv("initialized attempt"),elapsed_in_ms(fingerprint.timestamp)); PendingTransactionStatus::Failure(fingerprint.into()) } - match receipt.status{ - None => handle_none_status(fingerprint, self.config.when_pending_too_long_sec, logger), - Some(status_code) => - match status_code.as_u64(){ + match receipt.status { + None => handle_none_status(fingerprint, self.config.when_pending_too_long_sec, logger), + Some(status_code) => + match status_code.as_u64() { 0 => handle_status_with_failure(fingerprint, logger), 1 => handle_status_with_success(fingerprint, logger), other => unreachable!("tx receipt for pending '{}' - tx status: code other than 0 or 1 shouldn't be possible, but was {}", fingerprint.hash, other) } - } + } } fn update_payable_fingerprint(&self, pending_payable_id: PendingPayableId) { @@ -1242,8 +1242,10 @@ fn elapsed_in_ms(timestamp: SystemTime) -> u128 { #[derive(Debug, PartialEq, Clone)] enum PendingTransactionStatus { - StillPending(PendingPayableId), //updates slightly the record, waits an interval and starts a new round - Failure(PendingPayableId), //official tx failure + StillPending(PendingPayableId), + //updates slightly the record, waits an interval and starts a new round + Failure(PendingPayableId), + //official tx failure Confirmed(PendingPayableFingerprint), //tx was fully processed and successful } @@ -1448,13 +1450,20 @@ mod tests { let mut config = BootstrapperConfig::new(); config.accountant_config_opt = Some(make_accountant_config_null()); let payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); + let pending_payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); + let receivable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let payable_dao_factory = PayableDaoFactoryMock::new() .make_params(&payable_dao_factory_params_arc) + .make_result(PayableDaoMock::new()) .make_result(PayableDaoMock::new()); - let receivable_dao_factory = - ReceivableDaoFactoryMock::new().make_result(ReceivableDaoMock::new()); - let pending_payable_dao_factory = - PendingPayableDaoFactoryMock::new().make_result(PendingPayableDaoMock::new()); + let pending_payable_dao_factory = PendingPayableDaoFactoryMock::new() + .make_params(&pending_payable_dao_factory_params_arc) + .make_result(PendingPayableDaoMock::new()) + .make_result(PendingPayableDaoMock::new()); + let receivable_dao_factory = ReceivableDaoFactoryMock::new() + .make_params(&receivable_dao_factory_params_arc) + .make_result(ReceivableDaoMock::new()) + .make_result(ReceivableDaoMock::new()); let banned_dao_factory_called = Rc::new(RefCell::new(false)); let banned_dao = BannedDaoMock::new(); let banned_dao_factory = @@ -1468,13 +1477,18 @@ mod tests { Box::new(banned_dao_factory), ); - assert_eq!(*payable_dao_factory_params_arc.lock().unwrap(), vec![()]); - // TODO: Find a way to use different assert statements in place of these. - // assert_eq!(receivable_dao_factory_called.as_ref(), &RefCell::new(true)); - // assert_eq!( - // pending_payable_dao_factory_called.as_ref(), - // &RefCell::new(true) - // ); + assert_eq!( + *payable_dao_factory_params_arc.lock().unwrap(), + vec![(), ()] + ); + assert_eq!( + *pending_payable_dao_factory_params_arc.lock().unwrap(), + vec![(), ()] + ); + assert_eq!( + *receivable_dao_factory_params_arc.lock().unwrap(), + vec![(), ()] + ); assert_eq!(banned_dao_factory_called.as_ref(), &RefCell::new(true)); } @@ -1489,12 +1503,21 @@ mod tests { let mut bootstrapper_config = BootstrapperConfig::new(); bootstrapper_config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); - let payable_dao_factory = - Box::new(PayableDaoFactoryMock::new().make_result(PayableDaoMock::new())); - let receivable_dao_factory = - Box::new(ReceivableDaoFactoryMock::new().make_result(ReceivableDaoMock::new())); - let pending_payable_dao_factory = - Box::new(PendingPayableDaoFactoryMock::new().make_result(PendingPayableDaoMock::new())); + let payable_dao_factory = Box::new( + PayableDaoFactoryMock::new() + .make_result(PayableDaoMock::new()) // For Accountant + .make_result(PayableDaoMock::new()), // For Scanner + ); + let pending_payable_dao_factory = Box::new( + PendingPayableDaoFactoryMock::new() + .make_result(PendingPayableDaoMock::new()) // For Accountant + .make_result(PendingPayableDaoMock::new()), // For Scanner + ); + let receivable_dao_factory = Box::new( + ReceivableDaoFactoryMock::new() + .make_result(ReceivableDaoMock::new()) // For Accountant + .make_result(ReceivableDaoMock::new()), // For Scanner + ); let banned_dao_factory = Box::new(BannedDaoFactoryMock::new(BannedDaoMock::new())); let result = Accountant::new( @@ -1562,6 +1585,7 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .receivable_dao(receivable_dao) + .receivable_dao(ReceivableDaoMock::new()) .build(); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); @@ -1589,7 +1613,7 @@ mod tests { recipient: make_wallet("earning_wallet"), response_skeleton_opt: Some(ResponseSkeleton { client_id: 1234, - context_id: 4321 + context_id: 4321, }), } ); @@ -1667,7 +1691,8 @@ mod tests { PayableDaoMock::new().non_pending_payables_result(vec![payable_account.clone()]); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .build(); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); @@ -1695,7 +1720,7 @@ mod tests { accounts: vec![payable_account], response_skeleton_opt: Some(ResponseSkeleton { client_id: 1234, - context_id: 4321 + context_id: 4321, }), } ); @@ -1773,7 +1798,8 @@ mod tests { .return_all_fingerprints_result(vec![fingerprint.clone()]); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(pending_payable_dao) // For Accountanr + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); @@ -1801,7 +1827,7 @@ mod tests { pending_payable: vec![fingerprint], response_skeleton_opt: Some(ResponseSkeleton { client_id: 1234, - context_id: 4321 + context_id: 4321, }), } ); @@ -1827,6 +1853,7 @@ mod tests { let mut subject = AccountantBuilder::default() .bootstrapper_config(config) .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); subject.logger = Logger::new("scan_request_from_ui_is_handled_in_case_the_scan_is_already_running"); @@ -1927,8 +1954,10 @@ mod tests { make_populated_accountant_config_with_defaults(), make_wallet("some_wallet_address"), )) - .payable_dao(payable_dao) - .pending_payable_dao(pending_payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let expected_payable = Payable::new( expected_wallet.clone(), @@ -1963,7 +1992,8 @@ mod tests { let system = System::new("sent payable failure without backup"); let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(None); let accountant = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let hash = H256::from_uint(&U256::from(12345)); let sent_payable = SentPayable { @@ -2016,8 +2046,10 @@ mod tests { .delete_fingerprint_params(&delete_fingerprint_params_arc) .delete_fingerprint_result(Ok(())); let subject = AccountantBuilder::default() - .payable_dao(payable_dao) - .pending_payable_dao(pending_payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let wallet = make_wallet("blah"); let hash_tx_1 = H256::from_uint(&U256::from(5555)); @@ -2102,7 +2134,8 @@ mod tests { make_populated_accountant_config_with_defaults(), make_wallet("some_wallet_address"), )) - .payable_dao(payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .build(); subject.scanners.pending_payables = Box::new(NullScanner {}); subject.scanners.receivables = Box::new(NullScanner {}); @@ -2129,7 +2162,7 @@ mod tests { report_accounts_payables_msgs, vec![&ReportAccountsPayable { accounts, - response_skeleton_opt: None + response_skeleton_opt: None, }] ); } @@ -2151,8 +2184,10 @@ mod tests { make_populated_accountant_config_with_defaults(), earning_wallet.clone(), )) - .payable_dao(payable_dao) - .receivable_dao(receivable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .receivable_dao(receivable_dao) // For Accountant + .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); subject.scanners.pending_payables = Box::new(NullScanner {}); subject.scanners.payables = Box::new(NullScanner {}); @@ -2205,6 +2240,7 @@ mod tests { .payable_dao(PayableDaoMock::new().non_pending_payables_result(vec![])) .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao) + .receivable_dao(ReceivableDaoMock::new()) .build(); let system = System::new("accountant_receives_new_payments_to_the_receivables_dao"); let subject = accountant.start(); @@ -2262,9 +2298,12 @@ mod tests { .non_pending_payables_result(vec![]); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) - .receivable_dao(receivable_dao) - .pending_payable_dao(pending_payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .receivable_dao(receivable_dao) // For Accountant + .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); let peer_actors = peer_actors_builder() .blockchain_bridge(blockchain_bridge) @@ -2348,6 +2387,7 @@ mod tests { let mut subject = AccountantBuilder::default() .bootstrapper_config(config) .receivable_dao(receivable_dao) + .receivable_dao(ReceivableDaoMock::new()) .banned_dao(banned_dao) .build(); subject.scanners.pending_payables = Box::new(NullScanner {}); @@ -2387,7 +2427,7 @@ mod tests { &RetrieveTransactions { recipient: earning_wallet.clone(), response_skeleton_opt: None, - } + }, ] ); //sadly I cannot effectively assert on the exact params @@ -2418,7 +2458,7 @@ mod tests { response_skeleton_opt: None }, Duration::from_millis(99) - ) + ), ] ) } @@ -2464,7 +2504,8 @@ mod tests { .build(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); subject.scanners.receivables = Box::new(NullScanner {}); //skipping subject.scanners.payables = Box::new(NullScanner {}); //skipping @@ -2519,7 +2560,7 @@ mod tests { response_skeleton_opt: None }, Duration::from_millis(98) - ) + ), ] ) } @@ -2565,7 +2606,8 @@ mod tests { .build(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .build(); subject.scanners.pending_payables = Box::new(NullScanner {}); //skipping subject.scanners.receivables = Box::new(NullScanner {}); //skipping @@ -2616,7 +2658,7 @@ mod tests { response_skeleton_opt: None }, Duration::from_millis(97) - ) + ), ] ) } @@ -2643,8 +2685,10 @@ mod tests { let peer_actors = peer_actors_builder().build(); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) - .receivable_dao(receivable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .receivable_dao(receivable_dao) // For Accountant + .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); let subject_addr = subject.start(); let subject_subs = Accountant::make_subs_from(&subject_addr); @@ -2715,7 +2759,8 @@ mod tests { blockchain_bridge_addr.recipient::(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.payment_thresholds = payment_thresholds; @@ -2777,7 +2822,8 @@ mod tests { .build(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .build(); subject.scanners.pending_payables = Box::new(NullScanner {}); subject.scanners.receivables = Box::new(NullScanner {}); @@ -2793,7 +2839,7 @@ mod tests { blockchain_bridge_recordings.get_record::(0), &ReportAccountsPayable { accounts, - response_skeleton_opt: None + response_skeleton_opt: None, } ); } @@ -2823,8 +2869,10 @@ mod tests { .unban_parameters(&unban_parameters_arc); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) - .receivable_dao(receivable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .receivable_dao(receivable_dao) // For Accountant + .receivable_dao(ReceivableDaoMock::new()) // For Scanner .banned_dao(banned_dao) .build(); @@ -2865,7 +2913,8 @@ mod tests { .return_all_fingerprints_params(&return_all_backup_records_params_arc) .return_all_fingerprints_result(vec![]); let subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let _ = subject.scan_for_pending_payable(None); @@ -2900,7 +2949,8 @@ mod tests { "accountant_starts_a_scan_in_case_it_receives_the_message_and_scan_is_not_running", ); let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .bootstrapper_config(config) .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); @@ -2950,7 +3000,8 @@ mod tests { "accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_the_scanner_is_running", ); let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .bootstrapper_config(config) .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); @@ -3012,7 +3063,8 @@ mod tests { ); let system = System::new("pending payable scan"); let mut subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .bootstrapper_config(config) .build(); let blockchain_bridge_addr = blockchain_bridge.start(); @@ -3057,7 +3109,9 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(bootstrapper_config) .payable_dao(payable_dao_mock) + .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao_mock) + .receivable_dao(ReceivableDaoMock::new()) .build(); let system = System::new("report_routing_service_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3105,8 +3159,10 @@ mod tests { .more_money_receivable_parameters(&more_money_receivable_parameters_arc); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .receivable_dao(receivable_dao_mock) .payable_dao(payable_dao_mock) + .payable_dao(PayableDaoMock::new()) + .receivable_dao(receivable_dao_mock) + .receivable_dao(ReceivableDaoMock::new()) .build(); let system = System::new("report_routing_service_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3153,7 +3209,9 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao_mock) + .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao_mock) + .receivable_dao(ReceivableDaoMock::new()) .build(); let system = System::new("report_routing_service_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3199,7 +3257,8 @@ mod tests { .more_money_payable_result(Ok(())); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao_mock) + .payable_dao(payable_dao_mock) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .build(); let system = System::new("report_routing_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3247,6 +3306,7 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao_mock) + .payable_dao(PayableDaoMock::new()) .build(); let system = System::new("report_routing_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3289,7 +3349,8 @@ mod tests { .more_money_payable_parameters(more_money_payable_parameters_arc.clone()); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao_mock) + .payable_dao(payable_dao_mock) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .build(); let system = System::new("report_routing_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3331,8 +3392,10 @@ mod tests { .more_money_receivable_result(Ok(())); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .receivable_dao(receivable_dao_mock) .payable_dao(payable_dao_mock) + .payable_dao(PayableDaoMock::new()) + .receivable_dao(receivable_dao_mock) + .receivable_dao(ReceivableDaoMock::new()) .build(); let system = System::new("report_exit_service_provided_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3381,7 +3444,9 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao_mock) + .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao_mock) + .receivable_dao(ReceivableDaoMock::new()) .build(); let system = System::new("report_exit_service_provided_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3425,8 +3490,10 @@ mod tests { .more_money_receivable_parameters(&more_money_receivable_parameters_arc); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao_mock) - .receivable_dao(receivable_dao_mock) + .payable_dao(payable_dao_mock) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .receivable_dao(receivable_dao_mock) // For Accountant + .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); let system = System::new("report_exit_service_provided_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3485,6 +3552,7 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao_mock) + .payable_dao(PayableDaoMock::new()) .build(); let system = System::new("report_exit_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3532,7 +3600,8 @@ mod tests { .more_money_payable_parameters(more_money_payable_parameters_arc.clone()); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao_mock) + .payable_dao(payable_dao_mock) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner .build(); let system = System::new("report_exit_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3574,6 +3643,7 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao_mock) + .payable_dao(PayableDaoMock::new()) .build(); let system = System::new("report_exit_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3617,6 +3687,7 @@ mod tests { )); let subject = AccountantBuilder::default() .receivable_dao(receivable_dao) + .receivable_dao(ReceivableDaoMock::new()) .build(); let _ = subject.record_service_provided(i64::MAX as u64, 1, 2, &wallet); @@ -3630,6 +3701,7 @@ mod tests { .more_money_receivable_result(Err(ReceivableDaoError::SignConversion(1234))); let subject = AccountantBuilder::default() .receivable_dao(receivable_dao) + .receivable_dao(ReceivableDaoMock::new()) .build(); subject.record_service_provided(i64::MAX as u64, 1, 2, &wallet); @@ -3649,6 +3721,7 @@ mod tests { .more_money_payable_result(Err(PayableDaoError::SignConversion(1234))); let subject = AccountantBuilder::default() .payable_dao(payable_dao) + .payable_dao(PayableDaoMock::new()) .build(); let service_rate = i64::MAX as u64; @@ -3657,7 +3730,7 @@ mod tests { TestLogHandler::new().exists_log_containing(&format!( "ERROR: Accountant: Overflow error recording consumed services from {}: total charge {}, service rate {}, byte rate 1, payload size 2. Skipping", wallet, - i64::MAX as u64 +1*2, + i64::MAX as u64 + 1 * 2, i64::MAX as u64 )); } @@ -3675,6 +3748,7 @@ mod tests { )); let subject = AccountantBuilder::default() .payable_dao(payable_dao) + .payable_dao(PayableDaoMock::new()) .build(); let _ = subject.record_service_consumed(i64::MAX as u64, 1, 2, &wallet); @@ -3696,8 +3770,10 @@ mod tests { let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(Some(7879)); let subject = AccountantBuilder::default() - .payable_dao(payable_dao) - .pending_payable_dao(pending_payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let _ = subject.mark_pending_payable(vec![payable]); @@ -3725,7 +3801,8 @@ mod tests { "we slept over, sorry".to_string(), ))); let subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let _ = subject.handle_sent_payable(sent_payable); @@ -3753,8 +3830,10 @@ mod tests { .fingerprint_rowid_params(&fingerprint_rowid_params_arc) .fingerprint_rowid_result(Some(payable_2_rowid)); let subject = AccountantBuilder::default() - .payable_dao(PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(()))) - .pending_payable_dao(pending_payable_dao) + .payable_dao(PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(()))) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); subject.handle_sent_payable(sent_payable); @@ -3780,8 +3859,10 @@ mod tests { let payment = Payable::new(make_wallet("booga"), 6789, payment_hash, now_system); let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(None); let subject = AccountantBuilder::default() - .payable_dao(PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(()))) - .pending_payable_dao(pending_payable_dao) + .payable_dao(PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(()))) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let _ = subject.mark_pending_payable(vec![payment]); @@ -3799,8 +3880,10 @@ mod tests { .delete_fingerprint_params(&delete_pending_payable_fingerprint_params_arc) .delete_fingerprint_result(Ok(())); let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) - .pending_payable_dao(pending_payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let tx_hash = H256::from("sometransactionhash".keccak256()); let amount = 4567; @@ -3847,6 +3930,7 @@ mod tests { )); let mut subject = AccountantBuilder::default() .payable_dao(payable_dao) + .payable_dao(PayableDaoMock::new()) .build(); let mut payment = make_pending_payable_fingerprint(); payment.rowid_opt = Some(rowid); @@ -3873,8 +3957,10 @@ mod tests { ), )); let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) - .pending_payable_dao(pending_payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let mut pending_payable_fingerprint = make_pending_payable_fingerprint(); pending_payable_fingerprint.rowid_opt = Some(rowid); @@ -3894,7 +3980,8 @@ mod tests { .mark_failure_params(&mark_failure_params_arc) .mark_failure_result(Ok(())); let subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let tx_hash = H256::from("sometransactionhash".keccak256()); let rowid = 2; @@ -3928,6 +4015,7 @@ mod tests { .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); let rowid = 2; let hash = H256::from("sometransactionhash".keccak256()); @@ -3988,7 +4076,7 @@ mod tests { let result = Accountant::investigate_debt_extremes(payables); - assert_eq!(result,"Payable scan found 4 debts; the biggest is 2000000 owed for 10000sec, the oldest is 330 owed for 30000sec") + assert_eq!(result, "Payable scan found 4 debts; the biggest is 2000000 owed for 10000sec, the oldest is 330 owed for 30000sec") } #[test] @@ -4302,8 +4390,10 @@ mod tests { .start(move |_| { let mut subject = AccountantBuilder::default() .bootstrapper_config(bootstrapper_config) - .payable_dao(payable_dao) - .pending_payable_dao(pending_payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .pending_payable_dao(pending_payable_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); subject.scanners.receivables = Box::new(NullScanner {}); let notify_later_half_mock = NotifyLaterHandleMock::default() @@ -4359,7 +4449,7 @@ mod tests { pending_tx_hash_2, pending_tx_hash_1, pending_tx_hash_2, - pending_tx_hash_2 + pending_tx_hash_2, ] ); let update_backup_after_cycle_params = update_fingerprint_params_arc.lock().unwrap(); @@ -4370,7 +4460,7 @@ mod tests { rowid_for_account_2, rowid_for_account_1, rowid_for_account_2, - rowid_for_account_2 + rowid_for_account_2, ] ); let mark_failure_params = mark_failure_params_arc.lock().unwrap(); @@ -4449,7 +4539,7 @@ mod tests { result, vec![PendingTransactionStatus::StillPending(PendingPayableId { hash, - rowid + rowid, })] ); TestLogHandler::new().exists_log_matching("DEBUG: Accountant: Interpreting a receipt for transaction '0x0000…0913' but none was given; attempt 3, 100\\d\\dms since sending"); @@ -4508,7 +4598,7 @@ mod tests { }, ConfirmPendingTransaction { pending_payable_fingerprint: fingerprint_2 - } + }, ] ); } @@ -4539,7 +4629,7 @@ mod tests { result, PendingTransactionStatus::Failure(PendingPayableId { hash, - rowid: 777777 + rowid: 777777, }) ); TestLogHandler::new().exists_log_matching("ERROR: receipt_check_logger: Pending \ @@ -4641,7 +4731,8 @@ mod tests { .insert_fingerprint_params(&insert_fingerprint_params_arc) .insert_fingerprint_result(Ok(())); let subject = AccountantBuilder::default() - .pending_payable_dao(pending_payment_dao) + .pending_payable_dao(pending_payment_dao) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let accountant_addr = subject.start(); let tx_hash = H256::from_uint(&U256::from(55)); @@ -4689,6 +4780,7 @@ mod tests { let transaction_hash = H256::from_uint(&U256::from(456)); let subject = AccountantBuilder::default() .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); let timestamp_secs = 150_000_000; let fingerprint = PendingPayableFingerprint { @@ -4740,6 +4832,7 @@ mod tests { .update_fingerprint_results(Ok(())); let subject = AccountantBuilder::default() .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); let transaction_id = PendingPayableId { hash, rowid }; @@ -4762,6 +4855,7 @@ mod tests { )); let subject = AccountantBuilder::default() .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); let transaction_id = PendingPayableId { hash, rowid }; @@ -4801,8 +4895,8 @@ mod tests { payload: Err(( SCAN_ERROR, "Payables scan failed: 'My tummy hurts'".to_string() - )) - } + )), + }, } ); } @@ -4817,8 +4911,10 @@ mod tests { make_populated_accountant_config_with_defaults(), make_wallet("some_wallet_address"), )) - .receivable_dao(receivable_dao) - .payable_dao(payable_dao) + .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Scanner + .receivable_dao(receivable_dao) // For Accountant + .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); subject.financial_statistics.total_paid_payable = 123456; subject.financial_statistics.total_paid_receivable = 334455; @@ -4846,7 +4942,7 @@ mod tests { total_unpaid_and_pending_payable: 23456789, total_paid_payable: 123456, total_unpaid_receivable: 98765432, - total_paid_receivable: 334455 + total_paid_receivable: 334455, } ); } @@ -4870,8 +4966,10 @@ mod tests { .transaction_confirmed_result(Ok(())); pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; let mut subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) .payable_dao(payable_dao) + .payable_dao(PayableDaoMock::new()) + .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); subject.financial_statistics.total_paid_payable += 1111; let msg = ConfirmPendingTransaction { @@ -4893,6 +4991,7 @@ mod tests { .more_money_receivable_result(Ok(())); let mut subject = AccountantBuilder::default() .receivable_dao(receivable_dao) + .receivable_dao(ReceivableDaoMock::new()) .build(); subject.financial_statistics.total_paid_receivable += 2222; let receivables = vec![ diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index f282ef916..29f04bb14 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -115,7 +115,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, ctx: &mut Context, ) -> Result { - todo!("Begin Scan for PayableScanner"); + todo!("Implement PayableScanner"); // common::start_scan_at(&mut self.common, timestamp); // let start_message = BeginScanAMessage {}; // // Use the DAO, if necessary, to populate start_message @@ -161,7 +161,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, ctx: &mut Context, ) -> Result { - todo!() + todo!("Implement PendingPayableScanner") } fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { @@ -237,7 +237,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, ctx: &mut Context, ) -> Result { - todo!() + todo!("Implement NullScanner") } fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 049e73e16..01b364b98 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -189,6 +189,11 @@ pub struct PayableDaoFactoryMock { impl PayableDaoFactory for PayableDaoFactoryMock { fn make(&self) -> Box { + if self.make_results.borrow().len() == 0 { + panic!( + "PayableDao Missing. This problem mostly occurs when PayableDao is only supplied for Accountant and not for the Scanner while building Accountant." + ) + }; self.make_params.lock().unwrap().push(()); self.make_results.borrow_mut().remove(0) } @@ -220,6 +225,11 @@ pub struct ReceivableDaoFactoryMock { impl ReceivableDaoFactory for ReceivableDaoFactoryMock { fn make(&self) -> Box { + if self.make_results.borrow().len() == 0 { + panic!( + "ReceivableDao Missing. This problem mostly occurs when ReceivableDao is only supplied for Accountant and not for the Scanner while building Accountant." + ) + }; self.make_params.lock().unwrap().push(()); self.make_results.borrow_mut().remove(0) } @@ -836,6 +846,11 @@ pub struct PendingPayableDaoFactoryMock { impl PendingPayableDaoFactory for PendingPayableDaoFactoryMock { fn make(&self) -> Box { + if self.make_results.borrow().len() == 0 { + panic!( + "PendingPayableDao Missing. This problem mostly occurs when PendingPayableDao is only supplied for Accountant and not for the Scanner while building Accountant." + ) + }; self.make_params.lock().unwrap().push(()); self.make_results.borrow_mut().remove(0) } From 10e197f3d4193ad9340a5fa5a9ac6a7814363bbc Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 9 Aug 2022 16:06:37 +0530 Subject: [PATCH 031/145] GH-611: introduce scanner mock --- node/src/accountant/scanners.rs | 59 ++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 29f04bb14..9e7c3c0e6 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -19,6 +19,7 @@ pub(in crate::accountant) mod scanners { use masq_lib::messages::ScanType::PendingPayables; use std::any::Any; use std::cell::RefCell; + use std::sync::{Arc, Mutex}; use std::time::SystemTime; type Error = String; @@ -223,13 +224,41 @@ pub(in crate::accountant) mod scanners { } } - pub struct NullScanner {} + // pub struct NullScanner {} + // + // impl Scanner for NullScanner + // where + // BeginMessage: Message + Send + 'static, + // BeginMessage::Result: Send, + // EndMessage: Message, + // { + // fn begin_scan( + // &mut self, + // timestamp: SystemTime, + // response_skeleton_opt: Option, + // ctx: &mut Context, + // ) -> Result { + // todo!("Implement NullScanner") + // } + // + // fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + // todo!() + // } + // + // fn scan_started_at(&self) -> Option { + // todo!() + // } + // + // as_any_impl!(); + // } - impl Scanner for NullScanner - where - BeginMessage: Message + Send + 'static, - BeginMessage::Result: Send, - EndMessage: Message, + pub struct ScannerMock { + begin_scan_params: RefCell)>>, + begin_scan_results: Arc>>>, + } + + impl Scanner + for ScannerMock { fn begin_scan( &mut self, @@ -237,7 +266,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, ctx: &mut Context, ) -> Result { - todo!("Implement NullScanner") + todo!() } fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { @@ -247,8 +276,22 @@ pub(in crate::accountant) mod scanners { fn scan_started_at(&self) -> Option { todo!() } + } - as_any_impl!(); + impl ScannerMock { + pub fn new() -> Self { + Self { + begin_scan_params: RefCell::new(vec![]), + begin_scan_results: Arc::new(Mutex::new(vec![])), + } + } + + // pub fn begin_scan_params (&self, params: &) + // + // pub fn begin_scan_result (&mut self, result: Result, Error>) -> Self { + // self.begin_scan_results.push (result); + // self + // } } #[derive(Default)] From 7836d8f7c938f7356949626b17065314264572d8 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 16 Aug 2022 13:56:21 +0530 Subject: [PATCH 032/145] GH-611: modify ScannerMock and replace NullScanner with ScannerMock --- node/src/accountant/mod.rs | 30 +++++++++--------- node/src/accountant/scanners.rs | 56 +++++++++++++-------------------- 2 files changed, 36 insertions(+), 50 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 3a9df132a..6ad65c1a0 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1325,7 +1325,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::accountant::receivable_dao::ReceivableAccount; - use crate::accountant::scanners::scanners::{NullScanner, Scanner}; + use crate::accountant::scanners::scanners::{Scanner, ScannerMock}; use crate::accountant::test_utils::{ bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_pending_payable_fingerprint, make_receivable_account, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, @@ -1435,7 +1435,7 @@ mod tests { } } - // fn Box::new(NullScanner {}) -> Scanner { + // fn Box::new(ScannerMock::new()) -> Scanner { // Scanner::new(ScanType::Payables, Box::new(|_, _| {}), Box::new(|_, _| {})) // } @@ -2137,8 +2137,8 @@ mod tests { .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner .build(); - subject.scanners.pending_payables = Box::new(NullScanner {}); - subject.scanners.receivables = Box::new(NullScanner {}); + subject.scanners.pending_payables = Box::new(ScannerMock::new()); + subject.scanners.receivables = Box::new(ScannerMock::new()); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() @@ -2189,8 +2189,8 @@ mod tests { .receivable_dao(receivable_dao) // For Accountant .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); - subject.scanners.pending_payables = Box::new(NullScanner {}); - subject.scanners.payables = Box::new(NullScanner {}); + subject.scanners.pending_payables = Box::new(ScannerMock::new()); + subject.scanners.payables = Box::new(ScannerMock::new()); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() @@ -2390,8 +2390,8 @@ mod tests { .receivable_dao(ReceivableDaoMock::new()) .banned_dao(banned_dao) .build(); - subject.scanners.pending_payables = Box::new(NullScanner {}); - subject.scanners.payables = Box::new(NullScanner {}); + subject.scanners.pending_payables = Box::new(ScannerMock::new()); + subject.scanners.payables = Box::new(ScannerMock::new()); subject.notify_later.scan_for_receivable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_receivable_params_arc) @@ -2507,8 +2507,8 @@ mod tests { .pending_payable_dao(pending_payable_dao) // For Accountant .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); - subject.scanners.receivables = Box::new(NullScanner {}); //skipping - subject.scanners.payables = Box::new(NullScanner {}); //skipping + subject.scanners.receivables = Box::new(ScannerMock::new()); //skipping + subject.scanners.payables = Box::new(ScannerMock::new()); //skipping subject.notify_later.scan_for_pending_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_pending_payable_params_arc) @@ -2609,8 +2609,8 @@ mod tests { .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner .build(); - subject.scanners.pending_payables = Box::new(NullScanner {}); //skipping - subject.scanners.receivables = Box::new(NullScanner {}); //skipping + subject.scanners.pending_payables = Box::new(ScannerMock::new()); //skipping + subject.scanners.receivables = Box::new(ScannerMock::new()); //skipping subject.notify_later.scan_for_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_payables_params_arc) @@ -2825,8 +2825,8 @@ mod tests { .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner .build(); - subject.scanners.pending_payables = Box::new(NullScanner {}); - subject.scanners.receivables = Box::new(NullScanner {}); + subject.scanners.pending_payables = Box::new(ScannerMock::new()); + subject.scanners.receivables = Box::new(ScannerMock::new()); let subject_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&subject_addr); send_bind_message!(accountant_subs, peer_actors); @@ -4395,7 +4395,7 @@ mod tests { .pending_payable_dao(pending_payable_dao) // For Accountant .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); - subject.scanners.receivables = Box::new(NullScanner {}); + subject.scanners.receivables = Box::new(ScannerMock::new()); let notify_later_half_mock = NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_scan_for_pending_payable_arc_cloned) .permit_to_send_out(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 9e7c3c0e6..90136e02f 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -18,6 +18,7 @@ pub(in crate::accountant) mod scanners { use masq_lib::messages::ScanType; use masq_lib::messages::ScanType::PendingPayables; use std::any::Any; + use std::borrow::BorrowMut; use std::cell::RefCell; use std::sync::{Arc, Mutex}; use std::time::SystemTime; @@ -224,41 +225,16 @@ pub(in crate::accountant) mod scanners { } } - // pub struct NullScanner {} - // - // impl Scanner for NullScanner - // where - // BeginMessage: Message + Send + 'static, - // BeginMessage::Result: Send, - // EndMessage: Message, - // { - // fn begin_scan( - // &mut self, - // timestamp: SystemTime, - // response_skeleton_opt: Option, - // ctx: &mut Context, - // ) -> Result { - // todo!("Implement NullScanner") - // } - // - // fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { - // todo!() - // } - // - // fn scan_started_at(&self) -> Option { - // todo!() - // } - // - // as_any_impl!(); - // } - pub struct ScannerMock { begin_scan_params: RefCell)>>, - begin_scan_results: Arc>>>, + begin_scan_results: Arc, Error>>>>, } impl Scanner for ScannerMock + where + BeginMessage: Message, + EndMessage: Message, { fn begin_scan( &mut self, @@ -286,12 +262,22 @@ pub(in crate::accountant) mod scanners { } } - // pub fn begin_scan_params (&self, params: &) - // - // pub fn begin_scan_result (&mut self, result: Result, Error>) -> Self { - // self.begin_scan_results.push (result); - // self - // } + pub fn begin_scan_params( + mut self, + params: Vec<(SystemTime, Option)>, + ) -> Self { + self.begin_scan_params = RefCell::new(params); + self + } + + pub fn begin_scan_result(self, result: Result, Error>) -> Self { + self.begin_scan_results + .lock() + .unwrap() + .borrow_mut() + .push(result); + self + } } #[derive(Default)] From b0a08d4f7f3eb003aa5e4715de283e133a23e6bd Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 17 Aug 2022 13:33:37 +0530 Subject: [PATCH 033/145] GH-611: an attempt to migrate the contents of scan_for_payables() inside PayableScanner --- node/src/accountant/mod.rs | 194 +++++++++++--------------------- node/src/accountant/scanners.rs | 175 +++++++++++++++++++++++++++- node/src/accountant/tools.rs | 33 ++++++ 3 files changed, 268 insertions(+), 134 deletions(-) create mode 100644 node/src/accountant/tools.rs diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 6ad65c1a0..a2146bfef 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -3,6 +3,7 @@ pub mod payable_dao; pub mod pending_payable_dao; pub mod receivable_dao; pub mod scanners; +pub mod tools; #[cfg(test)] pub mod test_utils; @@ -20,6 +21,7 @@ use crate::accountant::receivable_dao::{ use crate::accountant::scanners::scanners::{ NotifyLaterForScanners, Scanner, Scanners, TransactionConfirmationTools, }; +use crate::accountant::tools::{PayableExceedThresholdTools, PayableExceedThresholdToolsReal}; use crate::banned_dao::{BannedDao, BannedDaoFactory}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::{BlockchainError, BlockchainTransaction}; @@ -83,7 +85,8 @@ pub struct Accountant { report_new_payments_sub: Option>, report_sent_payments_sub: Option>, ui_message_sub: Option>, - payable_threshold_tools: Box, + // The below field has been migrated to payable scanner + // payable_threshold_tools: Box, logger: Logger, } @@ -188,9 +191,23 @@ impl Handler for Accountant { fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { // self.handle_scan_message(&mut self.scanners.payables, msg.response_skeleton_opt, ctx) - self.scanners - .payables - .begin_scan(SystemTime::now(), msg.response_skeleton_opt, ctx); + match self.scanners.payables.begin_scan( + SystemTime::now(), + msg.response_skeleton_opt, + &self.logger, + ctx, + ) { + Ok(message) => self + .report_accounts_payable_sub_opt + .as_ref() + .expect("BlockchainBridge is unbound") + .try_send(message) + .expect("BlockchainBridge is dead"), + Err(e) if e.contains("Called from ScannerMock") => { + todo!("Make sure no code is executed after this") + } + Err(e) => todo!("Use logger to print out the error message"), + } } } @@ -206,6 +223,7 @@ impl Handler for Accountant { self.scanners.pending_payables.begin_scan( SystemTime::now(), msg.response_skeleton_opt, + &self.logger, ctx, ); } @@ -220,9 +238,12 @@ impl Handler for Accountant { // msg.response_skeleton_opt, // ctx, // ); - self.scanners - .receivables - .begin_scan(SystemTime::now(), msg.response_skeleton_opt, ctx); + self.scanners.receivables.begin_scan( + SystemTime::now(), + msg.response_skeleton_opt, + &self.logger, + ctx, + ); } } @@ -446,7 +467,7 @@ impl Accountant { report_new_payments_sub: None, report_sent_payments_sub: None, ui_message_sub: None, - payable_threshold_tools: Box::new(PayableExceedThresholdToolsReal::default()), + // payable_threshold_tools: Box::new(PayableExceedThresholdToolsReal::default()), logger: Logger::new("Accountant"), } } @@ -606,40 +627,40 @@ impl Accountant { (balance, age) } - fn should_pay(&self, payable: &PayableAccount) -> bool { - self.payable_exceeded_threshold(payable).is_some() - } - - fn payable_exceeded_threshold(&self, payable: &PayableAccount) -> Option { - // TODO: This calculation should be done in the database, if possible - let time_since_last_paid = SystemTime::now() - .duration_since(payable.last_paid_timestamp) - .expect("Internal error") - .as_secs(); - - if self.payable_threshold_tools.is_innocent_age( - time_since_last_paid, - self.config.payment_thresholds.maturity_threshold_sec as u64, - ) { - return None; - } - - if self.payable_threshold_tools.is_innocent_balance( - payable.balance, - self.config.payment_thresholds.permanent_debt_allowed_gwei, - ) { - return None; - } - - let threshold = self - .payable_threshold_tools - .calculate_payout_threshold(self.config.payment_thresholds, time_since_last_paid); - if payable.balance as f64 > threshold { - Some(threshold as u64) - } else { - None - } - } + // fn should_pay(&self, payable: &PayableAccount) -> bool { + // self.payable_exceeded_threshold(payable).is_some() + // } + // + // fn payable_exceeded_threshold(&self, payable: &PayableAccount) -> Option { + // // TODO: This calculation should be done in the database, if possible + // let time_since_last_paid = SystemTime::now() + // .duration_since(payable.last_paid_timestamp) + // .expect("Internal error") + // .as_secs(); + // + // if self.payable_threshold_tools.is_innocent_age( + // time_since_last_paid, + // self.config.payment_thresholds.maturity_threshold_sec as u64, + // ) { + // return None; + // } + // + // if self.payable_threshold_tools.is_innocent_balance( + // payable.balance, + // self.config.payment_thresholds.permanent_debt_allowed_gwei, + // ) { + // return None; + // } + // + // let threshold = self + // .payable_threshold_tools + // .calculate_payout_threshold(self.config.payment_thresholds, time_since_last_paid); + // if payable.balance as f64 > threshold { + // Some(threshold as u64) + // } else { + // None + // } + // } fn record_service_provided( &self, @@ -713,62 +734,6 @@ impl Accountant { } } - //for debugging only - fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccount]) -> String { - if all_non_pending_payables.is_empty() { - "Payable scan found no debts".to_string() - } else { - struct PayableInfo { - balance: i64, - age: Duration, - } - let now = SystemTime::now(); - let init = ( - PayableInfo { - balance: 0, - age: Duration::ZERO, - }, - PayableInfo { - balance: 0, - age: Duration::ZERO, - }, - ); - let (biggest, oldest) = all_non_pending_payables.iter().fold(init, |sofar, p| { - let (mut biggest, mut oldest) = sofar; - let p_age = now - .duration_since(p.last_paid_timestamp) - .expect("Payable time is corrupt"); - { - //look at a test if not understandable - let check_age_parameter_if_the_first_is_the_same = - || -> bool { p.balance == biggest.balance && p_age > biggest.age }; - - if p.balance > biggest.balance || check_age_parameter_if_the_first_is_the_same() - { - biggest = PayableInfo { - balance: p.balance, - age: p_age, - } - } - - let check_balance_parameter_if_the_first_is_the_same = - || -> bool { p_age == oldest.age && p.balance > oldest.balance }; - - if p_age > oldest.age || check_balance_parameter_if_the_first_is_the_same() { - oldest = PayableInfo { - balance: p.balance, - age: p_age, - } - } - } - (biggest, oldest) - }); - format!("Payable scan found {} debts; the biggest is {} owed for {}sec, the oldest is {} owed for {}sec", - all_non_pending_payables.len(), biggest.balance, biggest.age.as_secs(), - oldest.balance, oldest.age.as_secs()) - } - } - fn payables_debug_summary(&self, qualified_payables: &[PayableAccount]) -> String { let now = SystemTime::now(); let list = qualified_payables @@ -1266,38 +1231,6 @@ impl From<&PendingPayableFingerprint> for PendingPayableId { } } -//TODO the data types should change with GH-497 (including signed => unsigned) -trait PayableExceedThresholdTools { - fn is_innocent_age(&self, age: u64, limit: u64) -> bool; - fn is_innocent_balance(&self, balance: i64, limit: i64) -> bool; - fn calculate_payout_threshold(&self, payment_thresholds: PaymentThresholds, x: u64) -> f64; - as_any_dcl!(); -} - -#[derive(Default)] -struct PayableExceedThresholdToolsReal {} - -impl PayableExceedThresholdTools for PayableExceedThresholdToolsReal { - fn is_innocent_age(&self, age: u64, limit: u64) -> bool { - age <= limit - } - - fn is_innocent_balance(&self, balance: i64, limit: i64) -> bool { - balance <= limit - } - - fn calculate_payout_threshold(&self, payment_thresholds: PaymentThresholds, x: u64) -> f64 { - let m = -((payment_thresholds.debt_threshold_gwei as f64 - - payment_thresholds.permanent_debt_allowed_gwei as f64) - / (payment_thresholds.threshold_interval_sec as f64 - - payment_thresholds.maturity_threshold_sec as f64)); - let b = payment_thresholds.debt_threshold_gwei as f64 - - m * payment_thresholds.maturity_threshold_sec as f64; - m * x as f64 + b - } - as_any_impl!(); -} - #[cfg(test)] mod tests { use super::*; @@ -1333,6 +1266,7 @@ mod tests { ReceivableDaoMock, }; use crate::accountant::test_utils::{AccountantBuilder, BannedDaoMock}; + use crate::accountant::tools::PayableExceedThresholdTools; use crate::accountant::Accountant; use crate::blockchain::blockchain_bridge::BlockchainBridge; use crate::blockchain::blockchain_interface::BlockchainError; diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 90136e02f..c722a847c 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -1,27 +1,29 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. pub(in crate::accountant) mod scanners { - use crate::accountant::payable_dao::{PayableDao, PayableDaoReal}; + use crate::accountant::payable_dao::{PayableAccount, PayableDao, PayableDaoReal}; use crate::accountant::pending_payable_dao::PendingPayableDao; use crate::accountant::receivable_dao::ReceivableDao; + use crate::accountant::tools::{PayableExceedThresholdTools, PayableExceedThresholdToolsReal}; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, ReportTransactionReceipts, RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, ScanForPendingPayables, ScanForReceivables, SentPayable, }; use crate::blockchain::blockchain_bridge::RetrieveTransactions; + use crate::sub_lib::accountant::AccountantConfig; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use actix::dev::SendError; use actix::{Context, Message, Recipient}; - use masq_lib::logger::timestamp_as_string; + use masq_lib::logger::{timestamp_as_string, Logger}; use masq_lib::messages::ScanType; use masq_lib::messages::ScanType::PendingPayables; use std::any::Any; use std::borrow::BorrowMut; use std::cell::RefCell; use std::sync::{Arc, Mutex}; - use std::time::SystemTime; + use std::time::{Duration, SystemTime}; type Error = String; @@ -82,6 +84,7 @@ pub(in crate::accountant) mod scanners { &mut self, timestamp: SystemTime, response_skeleton_opt: Option, + logger: &Logger, ctx: &mut Context, ) -> Result; fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error>; @@ -104,6 +107,7 @@ pub(in crate::accountant) mod scanners { pub struct PayableScanner { common: ScannerCommon, dao: Box, + payable_threshold_tools: Box, } impl Scanner for PayableScanner @@ -115,6 +119,7 @@ pub(in crate::accountant) mod scanners { &mut self, timestamp: SystemTime, response_skeleton_opt: Option, + logger: &Logger, ctx: &mut Context, ) -> Result { todo!("Implement PayableScanner"); @@ -122,6 +127,36 @@ pub(in crate::accountant) mod scanners { // let start_message = BeginScanAMessage {}; // // Use the DAO, if necessary, to populate start_message // Ok(start_message) + + info!(logger, "Scanning for payables"); + self.common.initiated_at_opt = Some(timestamp); + let all_non_pending_payables = self.dao.non_pending_payables(); + debug!( + logger, + "{}", + Self::investigate_debt_extremes(&all_non_pending_payables) + ); + let qualified_payables = all_non_pending_payables + .into_iter() + .filter(|account| self.should_pay(account)) + .collect::>(); + info!( + logger, + "Chose {} qualified debts to pay", + qualified_payables.len() + ); + debug!( + logger, + "{}", + self.payables_debug_summary(&qualified_payables) + ); + match qualified_payables.is_empty() { + true => Err(String::from("No Qualified Payables found.")), + false => Ok(ReportAccountsPayable { + accounts: qualified_payables, + response_skeleton_opt, + }), + } } fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { @@ -143,6 +178,100 @@ pub(in crate::accountant) mod scanners { Self { common: ScannerCommon::default(), dao, + payable_threshold_tools: Box::new(PayableExceedThresholdToolsReal::default()), + } + } + + //for debugging only + pub fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccount]) -> String { + if all_non_pending_payables.is_empty() { + "Payable scan found no debts".to_string() + } else { + struct PayableInfo { + balance: i64, + age: Duration, + } + let now = SystemTime::now(); + let init = ( + PayableInfo { + balance: 0, + age: Duration::ZERO, + }, + PayableInfo { + balance: 0, + age: Duration::ZERO, + }, + ); + let (biggest, oldest) = all_non_pending_payables.iter().fold(init, |sofar, p| { + let (mut biggest, mut oldest) = sofar; + let p_age = now + .duration_since(p.last_paid_timestamp) + .expect("Payable time is corrupt"); + { + //look at a test if not understandable + let check_age_parameter_if_the_first_is_the_same = + || -> bool { p.balance == biggest.balance && p_age > biggest.age }; + + if p.balance > biggest.balance + || check_age_parameter_if_the_first_is_the_same() + { + biggest = PayableInfo { + balance: p.balance, + age: p_age, + } + } + + let check_balance_parameter_if_the_first_is_the_same = + || -> bool { p_age == oldest.age && p.balance > oldest.balance }; + + if p_age > oldest.age || check_balance_parameter_if_the_first_is_the_same() + { + oldest = PayableInfo { + balance: p.balance, + age: p_age, + } + } + } + (biggest, oldest) + }); + format!("Payable scan found {} debts; the biggest is {} owed for {}sec, the oldest is {} owed for {}sec", + all_non_pending_payables.len(), biggest.balance, biggest.age.as_secs(), + oldest.balance, oldest.age.as_secs()) + } + } + + fn should_pay(&self, payable: &PayableAccount) -> bool { + self.payable_exceeded_threshold(payable).is_some() + } + + fn payable_exceeded_threshold(&self, payable: &PayableAccount) -> Option { + // TODO: This calculation should be done in the database, if possible + let time_since_last_paid = SystemTime::now() + .duration_since(payable.last_paid_timestamp) + .expect("Internal error") + .as_secs(); + + if self.payable_threshold_tools.is_innocent_age( + time_since_last_paid, + self.config.payment_thresholds.maturity_threshold_sec as u64, + ) { + return None; + } + + if self.payable_threshold_tools.is_innocent_balance( + payable.balance, + self.config.payment_thresholds.permanent_debt_allowed_gwei, + ) { + return None; + } + + let threshold = self + .payable_threshold_tools + .calculate_payout_threshold(self.config.payment_thresholds, time_since_last_paid); + if payable.balance as f64 > threshold { + Some(threshold as u64) + } else { + None } } } @@ -161,6 +290,7 @@ pub(in crate::accountant) mod scanners { &mut self, timestamp: SystemTime, response_skeleton_opt: Option, + logger: &Logger, ctx: &mut Context, ) -> Result { todo!("Implement PendingPayableScanner") @@ -200,6 +330,7 @@ pub(in crate::accountant) mod scanners { &mut self, timestamp: SystemTime, response_skeleton_opt: Option, + logger: &Logger, ctx: &mut Context, ) -> Result { todo!() @@ -225,9 +356,39 @@ pub(in crate::accountant) mod scanners { } } + // pub struct NullScanner {} + // + // impl Scanner for NullScanner + // where + // BeginMessage: Message + Send + 'static, + // BeginMessage::Result: Send, + // EndMessage: Message, + // { + // fn begin_scan( + // &mut self, + // timestamp: SystemTime, + // response_skeleton_opt: Option, + // ctx: &mut Context, + // ) -> Result { + // todo!("Implement NullScanner") + // } + // + // fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + // todo!() + // } + // + // fn scan_started_at(&self) -> Option { + // todo!() + // } + // + // as_any_impl!(); + // } + pub struct ScannerMock { begin_scan_params: RefCell)>>, begin_scan_results: Arc, Error>>>>, + end_scan_params: RefCell>, + end_scan_results: Arc>>>, } impl Scanner @@ -240,9 +401,13 @@ pub(in crate::accountant) mod scanners { &mut self, timestamp: SystemTime, response_skeleton_opt: Option, + logger: &Logger, ctx: &mut Context, ) -> Result { - todo!() + self.begin_scan_params + .borrow_mut() + .push((timestamp, response_skeleton_opt)); + Err(String::from("Called from ScannerMock")) } fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { @@ -259,6 +424,8 @@ pub(in crate::accountant) mod scanners { Self { begin_scan_params: RefCell::new(vec![]), begin_scan_results: Arc::new(Mutex::new(vec![])), + end_scan_params: RefCell::new(vec![]), + end_scan_results: Arc::new(Mutex::new(vec![])), } } diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs new file mode 100644 index 000000000..daa8355ca --- /dev/null +++ b/node/src/accountant/tools.rs @@ -0,0 +1,33 @@ +use crate::sub_lib::accountant::PaymentThresholds; + +//TODO the data types should change with GH-497 (including signed => unsigned) +pub trait PayableExceedThresholdTools { + fn is_innocent_age(&self, age: u64, limit: u64) -> bool; + fn is_innocent_balance(&self, balance: i64, limit: i64) -> bool; + fn calculate_payout_threshold(&self, payment_thresholds: PaymentThresholds, x: u64) -> f64; + as_any_dcl!(); +} + +#[derive(Default)] +pub struct PayableExceedThresholdToolsReal {} + +impl PayableExceedThresholdTools for PayableExceedThresholdToolsReal { + fn is_innocent_age(&self, age: u64, limit: u64) -> bool { + age <= limit + } + + fn is_innocent_balance(&self, balance: i64, limit: i64) -> bool { + balance <= limit + } + + fn calculate_payout_threshold(&self, payment_thresholds: PaymentThresholds, x: u64) -> f64 { + let m = -((payment_thresholds.debt_threshold_gwei as f64 + - payment_thresholds.permanent_debt_allowed_gwei as f64) + / (payment_thresholds.threshold_interval_sec as f64 + - payment_thresholds.maturity_threshold_sec as f64)); + let b = payment_thresholds.debt_threshold_gwei as f64 + - m * payment_thresholds.maturity_threshold_sec as f64; + m * x as f64 + b + } + as_any_impl!(); +} From c8a3da83df2495e17a4d0337f3624de532111d28 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 17 Aug 2022 19:02:48 +0530 Subject: [PATCH 034/145] GH-611: remove ctx and comment out code --- node/src/accountant/mod.rs | 460 ++++++++++++++++---------------- node/src/accountant/scanners.rs | 91 ++++--- node/src/accountant/tools.rs | 1 + 3 files changed, 288 insertions(+), 264 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index a2146bfef..4af0aa797 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -195,7 +195,6 @@ impl Handler for Accountant { SystemTime::now(), msg.response_skeleton_opt, &self.logger, - ctx, ) { Ok(message) => self .report_accounts_payable_sub_opt @@ -224,7 +223,6 @@ impl Handler for Accountant { SystemTime::now(), msg.response_skeleton_opt, &self.logger, - ctx, ); } } @@ -242,7 +240,6 @@ impl Handler for Accountant { SystemTime::now(), msg.response_skeleton_opt, &self.logger, - ctx, ); } } @@ -512,40 +509,41 @@ impl Accountant { // // TODO: migrate the scanner.notify_later_assertable(self, ctx) to begin_scan() // } - fn scan_for_payables(&self, response_skeleton_opt: Option) { - info!(self.logger, "Scanning for payables"); - - let all_non_pending_payables = self.payable_dao.non_pending_payables(); - debug!( - self.logger, - "{}", - Self::investigate_debt_extremes(&all_non_pending_payables) - ); - let qualified_payables = all_non_pending_payables - .into_iter() - .filter(|account| self.should_pay(account)) - .collect::>(); - info!( - self.logger, - "Chose {} qualified debts to pay", - qualified_payables.len() - ); - debug!( - self.logger, - "{}", - self.payables_debug_summary(&qualified_payables) - ); - if !qualified_payables.is_empty() { - self.report_accounts_payable_sub_opt - .as_ref() - .expect("BlockchainBridge is unbound") - .try_send(ReportAccountsPayable { - accounts: qualified_payables, - response_skeleton_opt, - }) - .expect("BlockchainBridge is dead") - } - } + // TODO: Remove this function, it has been migrated to scanners + // fn scan_for_payables(&self, response_skeleton_opt: Option) { + // info!(self.logger, "Scanning for payables"); + // + // let all_non_pending_payables = self.payable_dao.non_pending_payables(); + // debug!( + // self.logger, + // "{}", + // Self::investigate_debt_extremes(&all_non_pending_payables) + // ); + // let qualified_payables = all_non_pending_payables + // .into_iter() + // .filter(|account| self.should_pay(account)) + // .collect::>(); + // info!( + // self.logger, + // "Chose {} qualified debts to pay", + // qualified_payables.len() + // ); + // debug!( + // self.logger, + // "{}", + // self.payables_debug_summary(&qualified_payables) + // ); + // if !qualified_payables.is_empty() { + // self.report_accounts_payable_sub_opt + // .as_ref() + // .expect("BlockchainBridge is unbound") + // .try_send(ReportAccountsPayable { + // accounts: qualified_payables, + // response_skeleton_opt, + // }) + // .expect("BlockchainBridge is dead") + // } + // } fn scan_for_delinquencies(&self) { info!(self.logger, "Scanning for delinquencies"); @@ -734,28 +732,28 @@ impl Accountant { } } - fn payables_debug_summary(&self, qualified_payables: &[PayableAccount]) -> String { - let now = SystemTime::now(); - let list = qualified_payables - .iter() - .map(|payable| { - let p_age = now - .duration_since(payable.last_paid_timestamp) - .expect("Payable time is corrupt"); - let threshold = self - .payable_exceeded_threshold(payable) - .expect("Threshold suddenly changed!"); - format!( - "{} owed for {}sec exceeds threshold: {}; creditor: {}", - payable.balance, - p_age.as_secs(), - threshold, - payable.wallet - ) - }) - .join("\n"); - String::from("Paying qualified debts:\n").add(&list) - } + // fn payables_debug_summary(&self, qualified_payables: &[PayableAccount]) -> String { + // let now = SystemTime::now(); + // let list = qualified_payables + // .iter() + // .map(|payable| { + // let p_age = now + // .duration_since(payable.last_paid_timestamp) + // .expect("Payable time is corrupt"); + // let threshold = self + // .payable_exceeded_threshold(payable) + // .expect("Threshold suddenly changed!"); + // format!( + // "{} owed for {}sec exceeds threshold: {}; creditor: {}", + // payable.balance, + // p_age.as_secs(), + // threshold, + // payable.wallet + // ) + // }) + // .join("\n"); + // String::from("Paying qualified debts:\n").add(&list) + // } fn handle_bind_message(&mut self, msg: BindMessage) { self.report_accounts_payable_sub_opt = @@ -1488,11 +1486,14 @@ mod tests { .scan_for_receivable .as_any() .downcast_ref::>(); - result - .payable_threshold_tools - .as_any() - .downcast_ref::() - .unwrap(); + // TODO: Write another test for it inside Scanner + // result + // .scanners + // .payables + // .payable_threshold_tools + // .as_any() + // .downcast_ref::() + // .unwrap(); assert_eq!(result.crashable, false); assert_eq!(result.financial_statistics.total_paid_receivable, 0); assert_eq!(result.financial_statistics.total_paid_payable, 0); @@ -2699,7 +2700,10 @@ mod tests { subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); subject.config.payment_thresholds = payment_thresholds; - subject.scan_for_payables(None); + let result = subject + .scanners + .payables + .begin_scan(SystemTime::now(), None, &subject.logger); System::current().stop_with_code(0); system.run(); @@ -3975,170 +3979,172 @@ mod tests { } #[test] - fn investigate_debt_extremes_picks_the_most_relevant_records() { - let now = to_time_t(SystemTime::now()); - let same_amount_significance = 2_000_000; - let same_age_significance = from_time_t(now - 30000); - let payables = &[ - PayableAccount { - wallet: make_wallet("wallet0"), - balance: same_amount_significance, - last_paid_timestamp: from_time_t(now - 5000), - pending_payable_opt: None, - }, - //this debt is more significant because beside being high in amount it's also older, so should be prioritized and picked - PayableAccount { - wallet: make_wallet("wallet1"), - balance: same_amount_significance, - last_paid_timestamp: from_time_t(now - 10000), - pending_payable_opt: None, - }, - //similarly these two wallets have debts equally old but the second has a bigger balance and should be chosen - PayableAccount { - wallet: make_wallet("wallet3"), - balance: 100, - last_paid_timestamp: same_age_significance, - pending_payable_opt: None, - }, - PayableAccount { - wallet: make_wallet("wallet2"), - balance: 330, - last_paid_timestamp: same_age_significance, - pending_payable_opt: None, - }, - ]; - - let result = Accountant::investigate_debt_extremes(payables); - - assert_eq!(result, "Payable scan found 4 debts; the biggest is 2000000 owed for 10000sec, the oldest is 330 owed for 30000sec") - } - - #[test] - fn payables_debug_summary_prints_pretty_summary() { - let now = to_time_t(SystemTime::now()); - let payment_thresholds = PaymentThresholds { - threshold_interval_sec: 2_592_000, - debt_threshold_gwei: 1_000_000_000, - payment_grace_period_sec: 86_400, - maturity_threshold_sec: 86_400, - permanent_debt_allowed_gwei: 10_000_000, - unban_below_gwei: 10_000_000, - }; - let qualified_payables = &[ - PayableAccount { - wallet: make_wallet("wallet0"), - balance: payment_thresholds.permanent_debt_allowed_gwei + 1000, - last_paid_timestamp: from_time_t( - now - payment_thresholds.threshold_interval_sec - 1234, - ), - pending_payable_opt: None, - }, - PayableAccount { - wallet: make_wallet("wallet1"), - balance: payment_thresholds.permanent_debt_allowed_gwei + 1, - last_paid_timestamp: from_time_t( - now - payment_thresholds.threshold_interval_sec - 1, - ), - pending_payable_opt: None, - }, - ]; - let mut config = BootstrapperConfig::default(); - config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); - let mut subject = AccountantBuilder::default() - .bootstrapper_config(config) - .build(); - subject.config.payment_thresholds = payment_thresholds; - - let result = subject.payables_debug_summary(qualified_payables); - - assert_eq!(result, - "Paying qualified debts:\n\ - 10001000 owed for 2593234sec exceeds threshold: 9512428; creditor: 0x0000000000000000000000000077616c6c657430\n\ - 10000001 owed for 2592001sec exceeds threshold: 9999604; creditor: 0x0000000000000000000000000077616c6c657431" - ) - } - - #[test] - fn threshold_calculation_depends_on_user_defined_payment_thresholds() { - let safe_age_params_arc = Arc::new(Mutex::new(vec![])); - let safe_balance_params_arc = Arc::new(Mutex::new(vec![])); - let calculate_payable_threshold_params_arc = Arc::new(Mutex::new(vec![])); - let balance = 5555; - let how_far_in_past = Duration::from_secs(1111 + 1); - let last_paid_timestamp = SystemTime::now().sub(how_far_in_past); - let payable_account = PayableAccount { - wallet: make_wallet("hi"), - balance, - last_paid_timestamp, - pending_payable_opt: None, - }; - let custom_payment_thresholds = PaymentThresholds { - maturity_threshold_sec: 1111, - payment_grace_period_sec: 2222, - permanent_debt_allowed_gwei: 3333, - debt_threshold_gwei: 4444, - threshold_interval_sec: 5555, - unban_below_gwei: 3333, - }; - let mut bootstrapper_config = BootstrapperConfig::default(); - bootstrapper_config.accountant_config_opt = Some(AccountantConfig { - scan_intervals: Default::default(), - payment_thresholds: custom_payment_thresholds, - suppress_initial_scans: false, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - }); - let payable_thresholds_tools = PayableThresholdToolsMock::default() - .is_innocent_age_params(&safe_age_params_arc) - .is_innocent_age_result( - how_far_in_past.as_secs() - <= custom_payment_thresholds.maturity_threshold_sec as u64, - ) - .is_innocent_balance_params(&safe_balance_params_arc) - .is_innocent_balance_result( - balance <= custom_payment_thresholds.permanent_debt_allowed_gwei, - ) - .calculate_payout_threshold_params(&calculate_payable_threshold_params_arc) - .calculate_payout_threshold_result(4567.0); //made up value - let mut subject = AccountantBuilder::default() - .bootstrapper_config(bootstrapper_config) - .build(); - subject.payable_threshold_tools = Box::new(payable_thresholds_tools); - - let result = subject.payable_exceeded_threshold(&payable_account); + // TODO: Migrate this test to Scanners + // fn investigate_debt_extremes_picks_the_most_relevant_records() { + // let now = to_time_t(SystemTime::now()); + // let same_amount_significance = 2_000_000; + // let same_age_significance = from_time_t(now - 30000); + // let payables = &[ + // PayableAccount { + // wallet: make_wallet("wallet0"), + // balance: same_amount_significance, + // last_paid_timestamp: from_time_t(now - 5000), + // pending_payable_opt: None, + // }, + // //this debt is more significant because beside being high in amount it's also older, so should be prioritized and picked + // PayableAccount { + // wallet: make_wallet("wallet1"), + // balance: same_amount_significance, + // last_paid_timestamp: from_time_t(now - 10000), + // pending_payable_opt: None, + // }, + // //similarly these two wallets have debts equally old but the second has a bigger balance and should be chosen + // PayableAccount { + // wallet: make_wallet("wallet3"), + // balance: 100, + // last_paid_timestamp: same_age_significance, + // pending_payable_opt: None, + // }, + // PayableAccount { + // wallet: make_wallet("wallet2"), + // balance: 330, + // last_paid_timestamp: same_age_significance, + // pending_payable_opt: None, + // }, + // ]; + // + // let result = Accountant::investigate_debt_extremes(payables); + // + // assert_eq!(result, "Payable scan found 4 debts; the biggest is 2000000 owed for 10000sec, the oldest is 330 owed for 30000sec") + // } - assert_eq!(result, Some(4567)); - let mut safe_age_params = safe_age_params_arc.lock().unwrap(); - let safe_age_single_params = safe_age_params.remove(0); - assert_eq!(*safe_age_params, vec![]); - let (time_elapsed, curve_derived_time) = safe_age_single_params; - assert!( - (how_far_in_past.as_secs() - 3) < time_elapsed - && time_elapsed < (how_far_in_past.as_secs() + 3) - ); - assert_eq!( - curve_derived_time, - custom_payment_thresholds.maturity_threshold_sec as u64 - ); - let safe_balance_params = safe_balance_params_arc.lock().unwrap(); - assert_eq!( - *safe_balance_params, - vec![( - payable_account.balance, - custom_payment_thresholds.permanent_debt_allowed_gwei - )] - ); - let mut calculate_payable_curves_params = - calculate_payable_threshold_params_arc.lock().unwrap(); - let calculate_payable_curves_single_params = calculate_payable_curves_params.remove(0); - assert_eq!(*calculate_payable_curves_params, vec![]); - let (payment_thresholds, time_elapsed) = calculate_payable_curves_single_params; - assert!( - (how_far_in_past.as_secs() - 3) < time_elapsed - && time_elapsed < (how_far_in_past.as_secs() + 3) - ); - assert_eq!(payment_thresholds, custom_payment_thresholds) - } + // TODO: Migrate this test to scanners + // #[test] + // fn payables_debug_summary_prints_pretty_summary() { + // let now = to_time_t(SystemTime::now()); + // let payment_thresholds = PaymentThresholds { + // threshold_interval_sec: 2_592_000, + // debt_threshold_gwei: 1_000_000_000, + // payment_grace_period_sec: 86_400, + // maturity_threshold_sec: 86_400, + // permanent_debt_allowed_gwei: 10_000_000, + // unban_below_gwei: 10_000_000, + // }; + // let qualified_payables = &[ + // PayableAccount { + // wallet: make_wallet("wallet0"), + // balance: payment_thresholds.permanent_debt_allowed_gwei + 1000, + // last_paid_timestamp: from_time_t( + // now - payment_thresholds.threshold_interval_sec - 1234, + // ), + // pending_payable_opt: None, + // }, + // PayableAccount { + // wallet: make_wallet("wallet1"), + // balance: payment_thresholds.permanent_debt_allowed_gwei + 1, + // last_paid_timestamp: from_time_t( + // now - payment_thresholds.threshold_interval_sec - 1, + // ), + // pending_payable_opt: None, + // }, + // ]; + // let mut config = BootstrapperConfig::default(); + // config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); + // let mut subject = AccountantBuilder::default() + // .bootstrapper_config(config) + // .build(); + // subject.config.payment_thresholds = payment_thresholds; + // + // let result = subject.payables_debug_summary(qualified_payables); + // + // assert_eq!(result, + // "Paying qualified debts:\n\ + // 10001000 owed for 2593234sec exceeds threshold: 9512428; creditor: 0x0000000000000000000000000077616c6c657430\n\ + // 10000001 owed for 2592001sec exceeds threshold: 9999604; creditor: 0x0000000000000000000000000077616c6c657431" + // ) + // } + // TODO: This test should be migrated to scanners + // #[test] + // fn threshold_calculation_depends_on_user_defined_payment_thresholds() { + // let safe_age_params_arc = Arc::new(Mutex::new(vec![])); + // let safe_balance_params_arc = Arc::new(Mutex::new(vec![])); + // let calculate_payable_threshold_params_arc = Arc::new(Mutex::new(vec![])); + // let balance = 5555; + // let how_far_in_past = Duration::from_secs(1111 + 1); + // let last_paid_timestamp = SystemTime::now().sub(how_far_in_past); + // let payable_account = PayableAccount { + // wallet: make_wallet("hi"), + // balance, + // last_paid_timestamp, + // pending_payable_opt: None, + // }; + // let custom_payment_thresholds = PaymentThresholds { + // maturity_threshold_sec: 1111, + // payment_grace_period_sec: 2222, + // permanent_debt_allowed_gwei: 3333, + // debt_threshold_gwei: 4444, + // threshold_interval_sec: 5555, + // unban_below_gwei: 3333, + // }; + // let mut bootstrapper_config = BootstrapperConfig::default(); + // bootstrapper_config.accountant_config_opt = Some(AccountantConfig { + // scan_intervals: Default::default(), + // payment_thresholds: custom_payment_thresholds, + // suppress_initial_scans: false, + // when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, + // }); + // let payable_thresholds_tools = PayableThresholdToolsMock::default() + // .is_innocent_age_params(&safe_age_params_arc) + // .is_innocent_age_result( + // how_far_in_past.as_secs() + // <= custom_payment_thresholds.maturity_threshold_sec as u64, + // ) + // .is_innocent_balance_params(&safe_balance_params_arc) + // .is_innocent_balance_result( + // balance <= custom_payment_thresholds.permanent_debt_allowed_gwei, + // ) + // .calculate_payout_threshold_params(&calculate_payable_threshold_params_arc) + // .calculate_payout_threshold_result(4567.0); //made up value + // let mut subject = AccountantBuilder::default() + // .bootstrapper_config(bootstrapper_config) + // .build(); + // subject.scanners.payables.payable_thresholds_tools = Box::new(payable_thresholds_tools); + // + // let result = subject.payable_exceeded_threshold(&payable_account); + // + // assert_eq!(result, Some(4567)); + // let mut safe_age_params = safe_age_params_arc.lock().unwrap(); + // let safe_age_single_params = safe_age_params.remove(0); + // assert_eq!(*safe_age_params, vec![]); + // let (time_elapsed, curve_derived_time) = safe_age_single_params; + // assert!( + // (how_far_in_past.as_secs() - 3) < time_elapsed + // && time_elapsed < (how_far_in_past.as_secs() + 3) + // ); + // assert_eq!( + // curve_derived_time, + // custom_payment_thresholds.maturity_threshold_sec as u64 + // ); + // let safe_balance_params = safe_balance_params_arc.lock().unwrap(); + // assert_eq!( + // *safe_balance_params, + // vec![( + // payable_account.balance, + // custom_payment_thresholds.permanent_debt_allowed_gwei + // )] + // ); + // let mut calculate_payable_curves_params = + // calculate_payable_threshold_params_arc.lock().unwrap(); + // let calculate_payable_curves_single_params = calculate_payable_curves_params.remove(0); + // assert_eq!(*calculate_payable_curves_params, vec![]); + // let (payment_thresholds, time_elapsed) = calculate_payable_curves_single_params; + // assert!( + // (how_far_in_past.as_secs() - 3) < time_elapsed + // && time_elapsed < (how_far_in_past.as_secs() + 3) + // ); + // assert_eq!(payment_thresholds, custom_payment_thresholds) + // } #[test] fn pending_transaction_is_registered_and_monitored_until_it_gets_confirmed_or_canceled() { init_test_logging(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index c722a847c..41419a095 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -5,6 +5,7 @@ pub(in crate::accountant) mod scanners { use crate::accountant::pending_payable_dao::PendingPayableDao; use crate::accountant::receivable_dao::ReceivableDao; use crate::accountant::tools::{PayableExceedThresholdTools, PayableExceedThresholdToolsReal}; + use crate::accountant::ReportAccountsPayable; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, ReportTransactionReceipts, RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, @@ -12,16 +13,17 @@ pub(in crate::accountant) mod scanners { }; use crate::blockchain::blockchain_bridge::RetrieveTransactions; use crate::sub_lib::accountant::AccountantConfig; - use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use actix::dev::SendError; use actix::{Context, Message, Recipient}; + use itertools::Itertools; use masq_lib::logger::{timestamp_as_string, Logger}; use masq_lib::messages::ScanType; use masq_lib::messages::ScanType::PendingPayables; use std::any::Any; use std::borrow::BorrowMut; use std::cell::RefCell; + use std::ops::Add; use std::sync::{Arc, Mutex}; use std::time::{Duration, SystemTime}; @@ -85,7 +87,7 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ctx: &mut Context, + // ctx: &mut Context, ) -> Result; fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error>; fn scan_started_at(&self) -> Option; @@ -110,18 +112,13 @@ pub(in crate::accountant) mod scanners { payable_threshold_tools: Box, } - impl Scanner for PayableScanner - where - BeginMessage: Message, - EndMessage: Message, - { + impl Scanner for PayableScanner { fn begin_scan( &mut self, timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ctx: &mut Context, - ) -> Result { + ) -> Result { todo!("Implement PayableScanner"); // common::start_scan_at(&mut self.common, timestamp); // let start_message = BeginScanAMessage {}; @@ -159,7 +156,7 @@ pub(in crate::accountant) mod scanners { } } - fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + fn scan_finished(&mut self, message: SentPayable) -> Result<(), Error> { todo!() // Use the passed-in message and the internal DAO to finish the scan // Ok(()) @@ -274,6 +271,29 @@ pub(in crate::accountant) mod scanners { None } } + + fn payables_debug_summary(&self, qualified_payables: &[PayableAccount]) -> String { + let now = SystemTime::now(); + let list = qualified_payables + .iter() + .map(|payable| { + let p_age = now + .duration_since(payable.last_paid_timestamp) + .expect("Payable time is corrupt"); + let threshold = self + .payable_exceeded_threshold(payable) + .expect("Threshold suddenly changed!"); + format!( + "{} owed for {}sec exceeds threshold: {}; creditor: {}", + payable.balance, + p_age.as_secs(), + threshold, + payable.wallet + ) + }) + .join("\n"); + String::from("Paying qualified debts:\n").add(&list) + } } pub struct PendingPayableScanner { @@ -291,7 +311,6 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ctx: &mut Context, ) -> Result { todo!("Implement PendingPayableScanner") } @@ -331,7 +350,6 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ctx: &mut Context, ) -> Result { todo!() } @@ -402,7 +420,6 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ctx: &mut Context, ) -> Result { self.begin_scan_params .borrow_mut() @@ -474,28 +491,28 @@ mod tests { }; use crate::accountant::test_utils::{PayableDaoMock, PendingPayableDaoMock, ReceivableDaoMock}; - #[test] - fn scanners_struct_can_be_constructed_with_the_respective_scanners() { - let scanners = Scanners::new( - Box::new(PayableDaoMock::new()), - Box::new(PendingPayableDaoMock::new()), - Box::new(ReceivableDaoMock::new()), - ); - - scanners - .payables - .as_any() - .downcast_ref::() - .unwrap(); - scanners - .pending_payables - .as_any() - .downcast_ref::() - .unwrap(); - scanners - .receivables - .as_any() - .downcast_ref::() - .unwrap(); - } + // #[test] + // fn scanners_struct_can_be_constructed_with_the_respective_scanners() { + // let scanners = Scanners::new( + // Box::new(PayableDaoMock::new()), + // Box::new(PendingPayableDaoMock::new()), + // Box::new(ReceivableDaoMock::new()), + // ); + // + // scanners + // .payables + // .as_any() + // .downcast_ref::() + // .unwrap(); + // scanners + // .pending_payables + // .as_any() + // .downcast_ref::() + // .unwrap(); + // scanners + // .receivables + // .as_any() + // .downcast_ref::() + // .unwrap(); + // } } diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index daa8355ca..450d7fb08 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -1,4 +1,5 @@ use crate::sub_lib::accountant::PaymentThresholds; +use std::any::Any; //TODO the data types should change with GH-497 (including signed => unsigned) pub trait PayableExceedThresholdTools { From 4224f93ab7215c354001d635b76a4a3c587cc3f4 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 17 Aug 2022 19:04:53 +0530 Subject: [PATCH 035/145] GH-611: remove the commented out code --- node/src/accountant/mod.rs | 37 --------------------------------- node/src/accountant/scanners.rs | 28 ------------------------- 2 files changed, 65 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 4af0aa797..fb9dd60ec 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -450,7 +450,6 @@ impl Accountant { pending_payable_dao: pending_payable_dao_factory.make(), banned_dao: banned_dao_factory.make(), crashable: config.crash_point == CrashPoint::Message, - // TODO: pending_payable_dao and receivable_dao can live inside Scanners instead of Accountant scanners: Scanners::new( payable_dao_factory.make(), pending_payable_dao_factory.make(), @@ -509,42 +508,6 @@ impl Accountant { // // TODO: migrate the scanner.notify_later_assertable(self, ctx) to begin_scan() // } - // TODO: Remove this function, it has been migrated to scanners - // fn scan_for_payables(&self, response_skeleton_opt: Option) { - // info!(self.logger, "Scanning for payables"); - // - // let all_non_pending_payables = self.payable_dao.non_pending_payables(); - // debug!( - // self.logger, - // "{}", - // Self::investigate_debt_extremes(&all_non_pending_payables) - // ); - // let qualified_payables = all_non_pending_payables - // .into_iter() - // .filter(|account| self.should_pay(account)) - // .collect::>(); - // info!( - // self.logger, - // "Chose {} qualified debts to pay", - // qualified_payables.len() - // ); - // debug!( - // self.logger, - // "{}", - // self.payables_debug_summary(&qualified_payables) - // ); - // if !qualified_payables.is_empty() { - // self.report_accounts_payable_sub_opt - // .as_ref() - // .expect("BlockchainBridge is unbound") - // .try_send(ReportAccountsPayable { - // accounts: qualified_payables, - // response_skeleton_opt, - // }) - // .expect("BlockchainBridge is dead") - // } - // } - fn scan_for_delinquencies(&self) { info!(self.logger, "Scanning for delinquencies"); let now = SystemTime::now(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 41419a095..c5d2ae8b9 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -50,33 +50,6 @@ pub(in crate::accountant) mod scanners { } } - // struct ScannerADao {} - // struct ScannerBDao {} - // - // struct BeginScanAMessage{ - // - // } - // - // impl Message for BeginScanAMessage{} - // - // struct FinishScanAMessage { - // - // } - // - // impl Message for FinishScanAMessage{} - // - // struct BeginScanBMessage { - // - // } - // - // impl Message for BeginScanBMessage{} - // - // struct FinishScanBMessage { - // - // } - // - // impl Message for FinishScanAMessage{} - pub trait Scanner where BeginMessage: Message, @@ -87,7 +60,6 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - // ctx: &mut Context, ) -> Result; fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error>; fn scan_started_at(&self) -> Option; From 82893623eca3de9f89aaeb5ce55435bf8b148241 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 17 Aug 2022 19:09:30 +0530 Subject: [PATCH 036/145] GH-611: add a todo!() inside payable_exceeded_threshold() to generate a successful build --- node/src/accountant/mod.rs | 3 -- node/src/accountant/scanners.rs | 55 +++++++++++++++++---------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index fb9dd60ec..5464e2fa8 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -85,8 +85,6 @@ pub struct Accountant { report_new_payments_sub: Option>, report_sent_payments_sub: Option>, ui_message_sub: Option>, - // The below field has been migrated to payable scanner - // payable_threshold_tools: Box, logger: Logger, } @@ -463,7 +461,6 @@ impl Accountant { report_new_payments_sub: None, report_sent_payments_sub: None, ui_message_sub: None, - // payable_threshold_tools: Box::new(PayableExceedThresholdToolsReal::default()), logger: Logger::new("Accountant"), } } diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index c5d2ae8b9..90c24a663 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -214,34 +214,35 @@ pub(in crate::accountant) mod scanners { } fn payable_exceeded_threshold(&self, payable: &PayableAccount) -> Option { + todo!("Fix the config variable problem"); // TODO: This calculation should be done in the database, if possible - let time_since_last_paid = SystemTime::now() - .duration_since(payable.last_paid_timestamp) - .expect("Internal error") - .as_secs(); - - if self.payable_threshold_tools.is_innocent_age( - time_since_last_paid, - self.config.payment_thresholds.maturity_threshold_sec as u64, - ) { - return None; - } - - if self.payable_threshold_tools.is_innocent_balance( - payable.balance, - self.config.payment_thresholds.permanent_debt_allowed_gwei, - ) { - return None; - } - - let threshold = self - .payable_threshold_tools - .calculate_payout_threshold(self.config.payment_thresholds, time_since_last_paid); - if payable.balance as f64 > threshold { - Some(threshold as u64) - } else { - None - } + // let time_since_last_paid = SystemTime::now() + // .duration_since(payable.last_paid_timestamp) + // .expect("Internal error") + // .as_secs(); + // + // if self.payable_threshold_tools.is_innocent_age( + // time_since_last_paid, + // self.config.payment_thresholds.maturity_threshold_sec as u64, + // ) { + // return None; + // } + // + // if self.payable_threshold_tools.is_innocent_balance( + // payable.balance, + // self.config.payment_thresholds.permanent_debt_allowed_gwei, + // ) { + // return None; + // } + // + // let threshold = self + // .payable_threshold_tools + // .calculate_payout_threshold(self.config.payment_thresholds, time_since_last_paid); + // if payable.balance as f64 > threshold { + // Some(threshold as u64) + // } else { + // None + // } } fn payables_debug_summary(&self, qualified_payables: &[PayableAccount]) -> String { From b890f0da2af5c8357afb287c8098ebfc0111aa67 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 17 Aug 2022 21:53:36 +0530 Subject: [PATCH 037/145] GH-611: write test for payable_thresholds_real --- node/src/accountant/mod.rs | 35 ----------------------------------- node/src/accountant/tools.rs | 28 +++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 5464e2fa8..f0077ad05 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -585,41 +585,6 @@ impl Accountant { (balance, age) } - // fn should_pay(&self, payable: &PayableAccount) -> bool { - // self.payable_exceeded_threshold(payable).is_some() - // } - // - // fn payable_exceeded_threshold(&self, payable: &PayableAccount) -> Option { - // // TODO: This calculation should be done in the database, if possible - // let time_since_last_paid = SystemTime::now() - // .duration_since(payable.last_paid_timestamp) - // .expect("Internal error") - // .as_secs(); - // - // if self.payable_threshold_tools.is_innocent_age( - // time_since_last_paid, - // self.config.payment_thresholds.maturity_threshold_sec as u64, - // ) { - // return None; - // } - // - // if self.payable_threshold_tools.is_innocent_balance( - // payable.balance, - // self.config.payment_thresholds.permanent_debt_allowed_gwei, - // ) { - // return None; - // } - // - // let threshold = self - // .payable_threshold_tools - // .calculate_payout_threshold(self.config.payment_thresholds, time_since_last_paid); - // if payable.balance as f64 > threshold { - // Some(threshold as u64) - // } else { - // None - // } - // } - fn record_service_provided( &self, service_rate: u64, diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 450d7fb08..fa80ab068 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -10,7 +10,9 @@ pub trait PayableExceedThresholdTools { } #[derive(Default)] -pub struct PayableExceedThresholdToolsReal {} +pub struct PayableExceedThresholdToolsReal { + pub payment_thresholds: PaymentThresholds, +} impl PayableExceedThresholdTools for PayableExceedThresholdToolsReal { fn is_innocent_age(&self, age: u64, limit: u64) -> bool { @@ -32,3 +34,27 @@ impl PayableExceedThresholdTools for PayableExceedThresholdToolsReal { } as_any_impl!(); } + +impl PayableExceedThresholdToolsReal { + pub fn new(payment_thresholds: PaymentThresholds) -> Self { + Self { payment_thresholds } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::sub_lib::accountant::DEFAULT_PAYMENT_THRESHOLDS; + + #[test] + fn payable_thresholds_real_can_be_constructed_properly() { + let payment_thresholds = DEFAULT_PAYMENT_THRESHOLDS.clone(); + let payable_exceed_threshold_tools_real = + PayableExceedThresholdToolsReal::new(payment_thresholds); + + assert_eq!( + payable_exceed_threshold_tools_real.payment_thresholds, + payment_thresholds + ) + } +} From f346446e4ad0dc5c02c43c2ef9756b930cf71b16 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 17 Aug 2022 23:41:30 +0530 Subject: [PATCH 038/145] GH-611: get rid of copy from structs in accountant.rs --- node/src/accountant/mod.rs | 168 +++++++++++------- node/src/accountant/test_utils.rs | 23 ++- node/src/accountant/tools.rs | 2 +- node/src/actor_system_factory.rs | 19 +- node/src/bootstrapper.rs | 4 +- node/src/daemon/setup_reporter.rs | 29 ++- .../unprivileged_parse_args_configuration.rs | 53 +++--- node/src/sub_lib/accountant.rs | 8 +- node/src/sub_lib/combined_parameters.rs | 20 ++- node/src/test_utils/mod.rs | 19 +- 10 files changed, 213 insertions(+), 132 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index f0077ad05..15d5abf93 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -430,17 +430,18 @@ impl Handler for Accountant { impl Accountant { pub fn new( - config: &BootstrapperConfig, + config: &mut BootstrapperConfig, payable_dao_factory: Box, receivable_dao_factory: Box, pending_payable_dao_factory: Box, banned_dao_factory: Box, ) -> Accountant { + let mut accountant_config = config + .accountant_config_opt + .take() + .expect("Accountant config"); Accountant { - config: *config - .accountant_config_opt - .as_ref() - .expectv("Accountant config"), + config: accountant_config, consuming_wallet: config.consuming_wallet_opt.clone(), earning_wallet: config.earning_wallet.clone(), payable_dao: payable_dao_factory.make(), @@ -506,36 +507,37 @@ impl Accountant { // } fn scan_for_delinquencies(&self) { - info!(self.logger, "Scanning for delinquencies"); - let now = SystemTime::now(); - self.receivable_dao - .new_delinquencies(now, &self.config.payment_thresholds) - .into_iter() - .for_each(|account| { - self.banned_dao.ban(&account.wallet); - let (balance, age) = Self::balance_and_age(&account); - info!( - self.logger, - "Wallet {} (balance: {} MASQ, age: {} sec) banned for delinquency", - account.wallet, - balance, - age.as_secs() - ) - }); - self.receivable_dao - .paid_delinquencies(&self.config.payment_thresholds) - .into_iter() - .for_each(|account| { - self.banned_dao.unban(&account.wallet); - let (balance, age) = Self::balance_and_age(&account); - info!( - self.logger, - "Wallet {} (balance: {} MASQ, age: {} sec) is no longer delinquent: unbanned", - account.wallet, - balance, - age.as_secs() - ) - }); + todo!("migrate the below fn to scanners"); + // info!(self.logger, "Scanning for delinquencies"); + // let now = SystemTime::now(); + // self.receivable_dao + // .new_delinquencies(now, &self.config.payment_thresholds) + // .into_iter() + // .for_each(|account| { + // self.banned_dao.ban(&account.wallet); + // let (balance, age) = Self::balance_and_age(&account); + // info!( + // self.logger, + // "Wallet {} (balance: {} MASQ, age: {} sec) banned for delinquency", + // account.wallet, + // balance, + // age.as_secs() + // ) + // }); + // self.receivable_dao + // .paid_delinquencies(&self.config.payment_thresholds) + // .into_iter() + // .for_each(|account| { + // self.banned_dao.unban(&account.wallet); + // let (balance, age) = Self::balance_and_age(&account); + // info!( + // self.logger, + // "Wallet {} (balance: {} MASQ, age: {} sec) is no longer delinquent: unbanned", + // account.wallet, + // balance, + // age.as_secs() + // ) + // }); } fn scan_for_receivables(&self, response_skeleton_opt: Option) { @@ -1209,7 +1211,8 @@ mod tests { use crate::test_utils::recorder::peer_actors_builder; use crate::test_utils::recorder::Recorder; use crate::test_utils::unshared_test_utils::{ - make_accountant_config_null, make_populated_accountant_config_with_defaults, + make_accountant_config_null, make_payment_thresholds_with_defaults, + make_populated_accountant_config_with_defaults, prove_that_crash_request_handler_is_hooked_up, NotifyHandleMock, NotifyLaterHandleMock, SystemKillerActor, }; @@ -1327,7 +1330,7 @@ mod tests { BannedDaoFactoryMock::new(banned_dao).called(&banned_dao_factory_called); let _ = Accountant::new( - &config, + &mut config, Box::new(payable_dao_factory), Box::new(receivable_dao_factory), Box::new(pending_payable_dao_factory), @@ -1360,6 +1363,7 @@ mod tests { let mut bootstrapper_config = BootstrapperConfig::new(); bootstrapper_config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); + bootstrapper_config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); let payable_dao_factory = Box::new( PayableDaoFactoryMock::new() .make_result(PayableDaoMock::new()) // For Accountant @@ -1378,7 +1382,7 @@ mod tests { let banned_dao_factory = Box::new(BannedDaoFactoryMock::new(BannedDaoMock::new())); let result = Accountant::new( - &bootstrapper_config, + &mut bootstrapper_config, payable_dao_factory, receivable_dao_factory, pending_payable_dao_factory, @@ -1435,8 +1439,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: true, - payment_thresholds: Default::default(), }, + Default::default(), make_wallet("earning_wallet"), ); let receivable_dao = ReceivableDaoMock::new() @@ -1490,8 +1494,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: true, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, }, + make_payment_thresholds_with_defaults(), make_wallet("earning_wallet"), ); let subject = AccountantBuilder::default() @@ -1535,8 +1539,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: true, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, }, + make_payment_thresholds_with_defaults(), make_wallet("some_wallet_address"), ); let payable_account = PayableAccount { @@ -1597,8 +1601,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: true, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, }, + make_payment_thresholds_with_defaults(), make_wallet("earning_wallet"), ); let subject = AccountantBuilder::default() @@ -1642,8 +1646,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: true, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, }, + make_payment_thresholds_with_defaults(), make_wallet("some_wallet_address"), ); let fingerprint = PendingPayableFingerprint { @@ -1705,8 +1709,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: true, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, }, + make_payment_thresholds_with_defaults(), make_wallet("some_wallet_address"), ); let pending_payable_dao = PendingPayableDaoMock::default(); @@ -1759,8 +1763,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: true, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, }, + make_payment_thresholds_with_defaults(), make_wallet("earning_wallet"), ); let subject = AccountantBuilder::default() @@ -1812,6 +1816,7 @@ mod tests { let accountant = AccountantBuilder::default() .bootstrapper_config(bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), make_wallet("some_wallet_address"), )) .payable_dao(payable_dao) // For Accountant @@ -1992,6 +1997,7 @@ mod tests { let mut subject = AccountantBuilder::default() .bootstrapper_config(bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), make_wallet("some_wallet_address"), )) .payable_dao(payable_dao) // For Accountant @@ -2042,6 +2048,7 @@ mod tests { let mut subject = AccountantBuilder::default() .bootstrapper_config(bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), earning_wallet.clone(), )) .payable_dao(payable_dao) // For Accountant @@ -2095,6 +2102,7 @@ mod tests { let accountant = AccountantBuilder::default() .bootstrapper_config(bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), earning_wallet.clone(), )) .payable_dao(PayableDaoMock::new().non_pending_payables_result(vec![])) @@ -2137,10 +2145,10 @@ mod tests { receivable_scan_interval: Duration::from_secs(100), pending_payable_scan_interval: Duration::from_millis(100), //except here, where we use it to stop the system }, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: false, }, + make_payment_thresholds_with_defaults(), make_wallet("buy"), make_wallet("hi"), ); @@ -2199,10 +2207,13 @@ mod tests { captured_timestamp < SystemTime::now() && captured_timestamp >= from_time_t(to_time_t(SystemTime::now()) - 5) ); - assert_eq!(captured_curves, *DEFAULT_PAYMENT_THRESHOLDS); + assert_eq!(captured_curves, make_payment_thresholds_with_defaults()); let paid_delinquencies_params = paid_delinquencies_params_arc.lock().unwrap(); assert_eq!(paid_delinquencies_params.len(), 1); - assert_eq!(paid_delinquencies_params[0], *DEFAULT_PAYMENT_THRESHOLDS); + assert_eq!( + paid_delinquencies_params[0], + make_payment_thresholds_with_defaults() + ); } #[test] @@ -2223,8 +2234,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: false, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, }, + make_payment_thresholds_with_defaults(), earning_wallet.clone(), ); let new_delinquent_account = ReceivableAccount { @@ -2339,10 +2350,10 @@ mod tests { receivable_scan_interval: Duration::from_secs(100), pending_payable_scan_interval: Duration::from_millis(98), }, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: false, }, + make_payment_thresholds_with_defaults(), make_wallet("hi"), ); // slightly above minimum balance, to the right of the curve (time intersection) @@ -2442,8 +2453,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: false, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, }, + make_payment_thresholds_with_defaults(), make_wallet("hi"), ); let now = to_time_t(SystemTime::now()); @@ -2536,8 +2547,8 @@ mod tests { }, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: true, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, }, + make_payment_thresholds_with_defaults(), make_wallet("hi"), ); let payable_dao = PayableDaoMock::new(); // No payables: demanding one would cause a panic @@ -2568,8 +2579,6 @@ mod tests { fn scan_for_payables_message_does_not_trigger_payment_for_balances_below_the_curve() { init_test_logging(); let accountant_config = make_populated_accountant_config_with_defaults(); - let config = bc_from_ac_plus_earning_wallet(accountant_config, make_wallet("mine")); - let now = to_time_t(SystemTime::now()); let payment_thresholds = PaymentThresholds { threshold_interval_sec: 2_592_000, debt_threshold_gwei: 1_000_000_000, @@ -2578,6 +2587,13 @@ mod tests { permanent_debt_allowed_gwei: 10_000_000, unban_below_gwei: 10_000_000, }; + let config = bc_from_ac_plus_earning_wallet( + accountant_config, + payment_thresholds.clone(), + make_wallet("mine"), + ); + let now = to_time_t(SystemTime::now()); + let accounts = vec![ // below minimum balance, to the right of time intersection (inside buffer zone) PayableAccount { @@ -2623,7 +2639,6 @@ mod tests { .payable_dao(PayableDaoMock::new()) // For Scanner .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - subject.config.payment_thresholds = payment_thresholds; let result = subject .scanners @@ -2646,10 +2661,10 @@ mod tests { payable_scan_interval: Duration::from_millis(100), receivable_scan_interval: Duration::from_secs(50_000), }, - payment_thresholds: DEFAULT_PAYMENT_THRESHOLDS.clone(), when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: false, }, + make_payment_thresholds_with_defaults(), make_wallet("mine"), ); let now = to_time_t(SystemTime::now()); @@ -2711,7 +2726,11 @@ mod tests { fn scan_for_delinquencies_triggers_bans_and_unbans() { init_test_logging(); let accountant_config = make_populated_accountant_config_with_defaults(); - let config = bc_from_ac_plus_earning_wallet(accountant_config, make_wallet("mine")); + let config = bc_from_ac_plus_earning_wallet( + accountant_config, + make_payment_thresholds_with_defaults(), + make_wallet("mine"), + ); let newly_banned_1 = make_receivable_account(1234, true); let newly_banned_2 = make_receivable_account(2345, true); let newly_unbanned_1 = make_receivable_account(3456, false); @@ -2806,6 +2825,7 @@ mod tests { payable_dao.have_non_pending_payables_shut_down_the_system = true; let config = bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), make_wallet("mine"), ); let system = System::new( @@ -2857,6 +2877,7 @@ mod tests { payable_dao.have_non_pending_payables_shut_down_the_system = true; let config = bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), make_wallet("mine"), ); let system = System::new( @@ -2922,6 +2943,7 @@ mod tests { ]); let config = bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), make_wallet("mine"), ); let system = System::new("pending payable scan"); @@ -3013,6 +3035,7 @@ mod tests { let consuming_wallet = make_wallet("our consuming wallet"); let config = bc_from_ac_plus_wallets( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), consuming_wallet.clone(), make_wallet("our earning wallet"), ); @@ -3063,6 +3086,7 @@ mod tests { let earning_wallet = make_wallet("our earning wallet"); let config = bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), earning_wallet.clone(), ); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); @@ -3111,6 +3135,7 @@ mod tests { init_test_logging(); let config = bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), make_wallet("hi"), ); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); @@ -3159,6 +3184,7 @@ mod tests { let consuming_wallet = make_wallet("the consuming wallet"); let config = bc_from_ac_plus_wallets( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), consuming_wallet.clone(), make_wallet("the earning wallet"), ); @@ -3204,6 +3230,7 @@ mod tests { let earning_wallet = make_wallet("the earning wallet"); let config = bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), earning_wallet.clone(), ); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); @@ -3246,6 +3273,7 @@ mod tests { init_test_logging(); let config = bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), make_wallet("hi"), ); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); @@ -3297,6 +3325,7 @@ mod tests { let consuming_wallet = make_wallet("my consuming wallet"); let config = bc_from_ac_plus_wallets( make_accountant_config_null(), + make_payment_thresholds_with_defaults(), consuming_wallet.clone(), make_wallet("my earning wallet"), ); @@ -3345,8 +3374,11 @@ mod tests { fn report_exit_service_provided_message_is_received_from_our_earning_wallet() { init_test_logging(); let earning_wallet = make_wallet("my earning wallet"); - let config = - bc_from_ac_plus_earning_wallet(make_accountant_config_null(), earning_wallet.clone()); + let config = bc_from_ac_plus_earning_wallet( + make_accountant_config_null(), + make_payment_thresholds_with_defaults(), + earning_wallet.clone(), + ); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao_mock = ReceivableDaoMock::new() @@ -3405,8 +3437,11 @@ mod tests { #[test] fn report_exit_service_consumed_message_is_received() { init_test_logging(); - let config = - bc_from_ac_plus_earning_wallet(make_accountant_config_null(), make_wallet("hi")); + let config = bc_from_ac_plus_earning_wallet( + make_accountant_config_null(), + make_payment_thresholds_with_defaults(), + make_wallet("hi"), + ); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new() .non_pending_payables_result(vec![]) @@ -3454,6 +3489,7 @@ mod tests { let consuming_wallet = make_wallet("own consuming wallet"); let config = bc_from_ac_plus_wallets( make_accountant_config_null(), + make_payment_thresholds_with_defaults(), consuming_wallet.clone(), make_wallet("own earning wallet"), ); @@ -3497,8 +3533,11 @@ mod tests { fn report_exit_service_consumed_message_is_received_for_our_earning_wallet() { init_test_logging(); let earning_wallet = make_wallet("own earning wallet"); - let config = - bc_from_ac_plus_earning_wallet(make_accountant_config_null(), earning_wallet.clone()); + let config = bc_from_ac_plus_earning_wallet( + make_accountant_config_null(), + make_payment_thresholds_with_defaults(), + earning_wallet.clone(), + ); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new() .non_pending_payables_result(vec![]) @@ -4173,10 +4212,10 @@ mod tests { pending_payable_scan_interval, ), }, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, suppress_initial_scans: false, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, }, + make_payment_thresholds_with_defaults(), make_wallet("some_wallet_address"), ); let fingerprint_1_first_round = PendingPayableFingerprint { @@ -4774,6 +4813,7 @@ mod tests { let mut subject = AccountantBuilder::default() .bootstrapper_config(bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), + make_payment_thresholds_with_defaults(), make_wallet("some_wallet_address"), )) .payable_dao(payable_dao) // For Accountant diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 01b364b98..682f6d030 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -20,10 +20,12 @@ use crate::database::dao_utils; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::db_config::config_dao::{ConfigDao, ConfigDaoFactory}; use crate::db_config::mocks::ConfigDaoMock; -use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds}; +use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds, DEFAULT_PAYMENT_THRESHOLDS}; use crate::sub_lib::wallet::Wallet; use crate::test_utils::make_wallet; -use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; +use crate::test_utils::unshared_test_utils::{ + make_payment_thresholds_with_defaults, make_populated_accountant_config_with_defaults, +}; use actix::System; use ethereum_types::{BigEndianHash, H256, U256}; use rusqlite::{Connection, Error, OptionalExtension}; @@ -148,9 +150,10 @@ impl AccountantBuilder { } pub fn build(self) -> Accountant { - let config = self.config.unwrap_or({ + let mut config = self.config.unwrap_or({ let mut config = BootstrapperConfig::default(); config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); + config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); config }); let payable_dao_factory = self.payable_dao_factory.unwrap_or( @@ -172,7 +175,7 @@ impl AccountantBuilder { .banned_dao_factory .unwrap_or(Box::new(BannedDaoFactoryMock::new(BannedDaoMock::new()))); let accountant = Accountant::new( - &config, + &mut config, Box::new(payable_dao_factory), Box::new(receivable_dao_factory), Box::new(pending_payable_dao_factory), @@ -681,22 +684,26 @@ impl BannedDaoMock { } pub fn bc_from_ac_plus_earning_wallet( - ac: AccountantConfig, + accountant_config: AccountantConfig, + payment_thresholds: PaymentThresholds, earning_wallet: Wallet, ) -> BootstrapperConfig { let mut bc = BootstrapperConfig::new(); - bc.accountant_config_opt = Some(ac); + bc.accountant_config_opt = Some(accountant_config); + bc.payment_thresholds_opt = Some(payment_thresholds); bc.earning_wallet = earning_wallet; bc } pub fn bc_from_ac_plus_wallets( - ac: AccountantConfig, + accountant_config: AccountantConfig, + payment_thresholds: PaymentThresholds, consuming_wallet: Wallet, earning_wallet: Wallet, ) -> BootstrapperConfig { let mut bc = BootstrapperConfig::new(); - bc.accountant_config_opt = Some(ac); + bc.accountant_config_opt = Some(accountant_config); + bc.payment_thresholds_opt = Some(payment_thresholds); bc.consuming_wallet_opt = Some(consuming_wallet); bc.earning_wallet = earning_wallet; bc diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index fa80ab068..92537f00c 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -50,7 +50,7 @@ mod tests { fn payable_thresholds_real_can_be_constructed_properly() { let payment_thresholds = DEFAULT_PAYMENT_THRESHOLDS.clone(); let payable_exceed_threshold_tools_real = - PayableExceedThresholdToolsReal::new(payment_thresholds); + PayableExceedThresholdToolsReal::new(payment_thresholds.clone()); assert_eq!( payable_exceed_threshold_tools_real.payment_thresholds, diff --git a/node/src/actor_system_factory.rs b/node/src/actor_system_factory.rs index c9237b38a..ad6ba2792 100644 --- a/node/src/actor_system_factory.rs +++ b/node/src/actor_system_factory.rs @@ -150,9 +150,10 @@ impl ActorSystemFactoryTools for ActorSystemFactoryToolsReal { }); let blockchain_bridge_subs = actor_factory.make_and_start_blockchain_bridge(&config); let neighborhood_subs = actor_factory.make_and_start_neighborhood(cryptdes.main, &config); + let data_directory = config.data_directory.clone(); let accountant_subs = actor_factory.make_and_start_accountant( - &config, - &config.data_directory.clone(), + &mut config.clone(), + &data_directory, &db_initializer, &BannedCacheLoaderReal {}, ); @@ -358,7 +359,7 @@ pub trait ActorFactory { ) -> NeighborhoodSubs; fn make_and_start_accountant( &self, - config: &BootstrapperConfig, + config: &mut BootstrapperConfig, data_directory: &Path, db_initializer: &dyn DbInitializer, banned_cache_loader: &dyn BannedCacheLoader, @@ -437,12 +438,12 @@ impl ActorFactory for ActorFactoryReal { fn make_and_start_accountant( &self, - config: &BootstrapperConfig, + config: &mut BootstrapperConfig, data_directory: &Path, db_initializer: &dyn DbInitializer, banned_cache_loader: &dyn BannedCacheLoader, ) -> AccountantSubs { - let cloned_config = config.clone(); + let mut cloned_config = config.clone(); let payable_dao_factory = Accountant::dao_factory(data_directory); let receivable_dao_factory = Accountant::dao_factory(data_directory); let pending_payable_dao_factory = Accountant::dao_factory(data_directory); @@ -456,7 +457,7 @@ impl ActorFactory for ActorFactoryReal { let arbiter = Arbiter::builder().stop_system_on_panic(true); let addr: Addr = arbiter.start(move |_| { Accountant::new( - &cloned_config, + &mut cloned_config, Box::new(payable_dao_factory), Box::new(receivable_dao_factory), Box::new(pending_payable_dao_factory), @@ -853,7 +854,7 @@ mod tests { fn make_and_start_accountant( &self, - config: &BootstrapperConfig, + config: &mut BootstrapperConfig, data_directory: &Path, _db_initializer: &dyn DbInitializer, _banned_cache_loader: &dyn BannedCacheLoader, @@ -1052,6 +1053,7 @@ mod tests { rate_pack(100), ), }, + payment_thresholds_opt: Default::default(), }; let persistent_config = PersistentConfigurationMock::default().chain_name_result("eth-ropsten".to_string()); @@ -1122,6 +1124,7 @@ mod tests { rate_pack(100), ), }, + payment_thresholds_opt: Default::default(), }; let add_mapping_params_arc = Arc::new(Mutex::new(vec![])); let mut subject = make_subject_with_null_setter(); @@ -1414,6 +1417,7 @@ mod tests { neighborhood_config: NeighborhoodConfig { mode: NeighborhoodMode::ConsumeOnly(vec![]), }, + payment_thresholds_opt: Default::default(), }; let system = System::new("MASQNode"); let mut subject = make_subject_with_null_setter(); @@ -1600,6 +1604,7 @@ mod tests { ), }, node_descriptor: Default::default(), + payment_thresholds_opt: Default::default(), }; let subject = make_subject_with_null_setter(); let system = System::new("MASQNode"); diff --git a/node/src/bootstrapper.rs b/node/src/bootstrapper.rs index 47b0ad42d..212be81a9 100644 --- a/node/src/bootstrapper.rs +++ b/node/src/bootstrapper.rs @@ -21,7 +21,7 @@ use crate::node_configurator::{initialize_database, DirsWrapper, NodeConfigurato use crate::privilege_drop::{IdWrapper, IdWrapperReal}; use crate::server_initializer::LoggerInitializerWrapper; use crate::sub_lib::accountant; -use crate::sub_lib::accountant::AccountantConfig; +use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds}; use crate::sub_lib::blockchain_bridge::BlockchainBridgeConfig; use crate::sub_lib::cryptde::CryptDE; use crate::sub_lib::cryptde_null::CryptDENull; @@ -337,6 +337,7 @@ pub struct BootstrapperConfig { pub alias_cryptde_null_opt: Option, pub mapping_protocol_opt: Option, pub real_user: RealUser, + pub payment_thresholds_opt: Option, // These fields must be set without privilege: otherwise the database will be created as root pub db_password_opt: Option, @@ -376,6 +377,7 @@ impl BootstrapperConfig { alias_cryptde_null_opt: None, mapping_protocol_opt: None, real_user: RealUser::new(None, None, None), + payment_thresholds_opt: Default::default(), // These fields must be set without privilege: otherwise the database will be created as root db_password_opt: None, diff --git a/node/src/daemon/setup_reporter.rs b/node/src/daemon/setup_reporter.rs index 13d312155..303561ac6 100644 --- a/node/src/daemon/setup_reporter.rs +++ b/node/src/daemon/setup_reporter.rs @@ -24,6 +24,9 @@ use crate::sub_lib::neighborhood::NodeDescriptor; use crate::sub_lib::neighborhood::{NeighborhoodMode as NeighborhoodModeEnum, DEFAULT_RATE_PACK}; use crate::sub_lib::utils::make_new_multi_config; use crate::test_utils::main_cryptde; +use crate::test_utils::unshared_test_utils::{ + make_payment_thresholds_with_defaults, make_scan_intervals_with_defaults, +}; use clap::value_t; use itertools::Itertools; use masq_lib::blockchains::chains::Chain as BlockChain; @@ -864,7 +867,10 @@ impl ValueRetriever for PaymentThresholds { _db_password_opt: &Option, ) -> Option<(String, UiSetupResponseValueStatus)> { let pc_value = pc.payment_thresholds().expectv("payment-thresholds"); - payment_thresholds_rate_pack_and_scan_intervals(pc_value, *DEFAULT_PAYMENT_THRESHOLDS) + payment_thresholds_rate_pack_and_scan_intervals( + pc_value, + make_payment_thresholds_with_defaults(), + ) } fn is_required(&self, _params: &SetupCluster) -> bool { @@ -915,7 +921,10 @@ impl ValueRetriever for ScanIntervals { _db_password_opt: &Option, ) -> Option<(String, UiSetupResponseValueStatus)> { let pc_value = pc.scan_intervals().expectv("scan-intervals"); - payment_thresholds_rate_pack_and_scan_intervals(pc_value, *DEFAULT_SCAN_INTERVALS) + payment_thresholds_rate_pack_and_scan_intervals( + pc_value, + make_scan_intervals_with_defaults(), + ) } fn is_required(&self, _params: &SetupCluster) -> bool { @@ -928,7 +937,7 @@ fn payment_thresholds_rate_pack_and_scan_intervals( default: T, ) -> Option<(String, UiSetupResponseValueStatus)> where - T: PartialEq + Display + Copy, + T: PartialEq + Display + Clone, { if persistent_config_value == default { Some((default.to_string(), Default)) @@ -3080,13 +3089,13 @@ mod tests { fn scan_intervals_computed_default_when_persistent_config_like_default() { assert_computed_default_when_persistent_config_like_default( &ScanIntervals {}, - *DEFAULT_SCAN_INTERVALS, + make_scan_intervals_with_defaults(), ) } #[test] fn scan_intervals_computed_default_persistent_config_unequal_to_default() { - let mut scan_intervals = *DEFAULT_SCAN_INTERVALS; + let mut scan_intervals = make_scan_intervals_with_defaults(); scan_intervals.pending_payable_scan_interval = scan_intervals .pending_payable_scan_interval .add(Duration::from_secs(15)); @@ -3113,7 +3122,7 @@ mod tests { #[test] fn payment_thresholds_computed_default_persistent_config_unequal_to_default() { - let mut payment_thresholds = *DEFAULT_PAYMENT_THRESHOLDS; + let mut payment_thresholds = make_payment_thresholds_with_defaults(); payment_thresholds.maturity_threshold_sec += 12; payment_thresholds.unban_below_gwei -= 11; payment_thresholds.debt_threshold_gwei += 1111; @@ -3151,14 +3160,16 @@ mod tests { pc_method_result_setter: &C, ) where C: Fn(PersistentConfigurationMock, T) -> PersistentConfigurationMock, - T: Display + PartialEq + Copy, + T: Display + PartialEq + Clone, { let mut bootstrapper_config = BootstrapperConfig::new(); //the rate_pack within the mode setting does not determine the result, so I just set a nonsense bootstrapper_config.neighborhood_config.mode = NeighborhoodModeEnum::OriginateOnly(vec![], rate_pack(0)); - let persistent_config = - pc_method_result_setter(PersistentConfigurationMock::new(), persistent_config_value); + let persistent_config = pc_method_result_setter( + PersistentConfigurationMock::new(), + persistent_config_value.clone(), + ); let result = subject.computed_default(&bootstrapper_config, &persistent_config, &None); diff --git a/node/src/node_configurator/unprivileged_parse_args_configuration.rs b/node/src/node_configurator/unprivileged_parse_args_configuration.rs index ab30645e5..1b325b728 100644 --- a/node/src/node_configurator/unprivileged_parse_args_configuration.rs +++ b/node/src/node_configurator/unprivileged_parse_args_configuration.rs @@ -491,18 +491,19 @@ fn configure_accountant_config( |pc: &dyn PersistentConfiguration| pc.scan_intervals(), |pc: &mut dyn PersistentConfiguration, intervals| pc.set_scan_intervals(intervals), )?, - payment_thresholds: process_combined_params( - "payment-thresholds", - multi_config, - persist_config, - |str: &str| PaymentThresholds::try_from(str), - |pc: &dyn PersistentConfiguration| pc.payment_thresholds(), - |pc: &mut dyn PersistentConfiguration, curves| pc.set_payment_thresholds(curves), - )?, suppress_initial_scans, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, }; + let scanners_config = process_combined_params( + "payment-thresholds", + multi_config, + persist_config, + |str: &str| PaymentThresholds::try_from(str), + |pc: &dyn PersistentConfiguration| pc.payment_thresholds(), + |pc: &mut dyn PersistentConfiguration, curves| pc.set_payment_thresholds(curves), + )?; config.accountant_config_opt = Some(accountant_config); + config.payment_thresholds_opt = Some(scanners_config); Ok(()) } @@ -1739,24 +1740,26 @@ mod tests { .unwrap(); let actual_accountant_config = config.accountant_config_opt.unwrap(); + let actual_scanners_config = config.payment_thresholds_opt.unwrap(); let expected_accountant_config = AccountantConfig { scan_intervals: ScanIntervals { pending_payable_scan_interval: Duration::from_secs(180), payable_scan_interval: Duration::from_secs(150), receivable_scan_interval: Duration::from_secs(130), }, - payment_thresholds: PaymentThresholds { - threshold_interval_sec: 1000, - debt_threshold_gwei: 10000, - payment_grace_period_sec: 1000, - maturity_threshold_sec: 10000, - permanent_debt_allowed_gwei: 20000, - unban_below_gwei: 20000, - }, suppress_initial_scans: false, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, }; + let expected_scanners_config = PaymentThresholds { + threshold_interval_sec: 1000, + debt_threshold_gwei: 10000, + payment_grace_period_sec: 1000, + maturity_threshold_sec: 10000, + permanent_debt_allowed_gwei: 20000, + unban_below_gwei: 20000, + }; assert_eq!(actual_accountant_config, expected_accountant_config); + assert_eq!(actual_scanners_config, expected_scanners_config); let set_scan_intervals_params = set_scan_intervals_params_arc.lock().unwrap(); assert_eq!(*set_scan_intervals_params, vec!["180|150|130".to_string()]); let set_payment_thresholds_params = set_payment_thresholds_params_arc.lock().unwrap(); @@ -1807,24 +1810,26 @@ mod tests { .unwrap(); let actual_accountant_config = config.accountant_config_opt.unwrap(); + let actual_scanners_config = config.payment_thresholds_opt.unwrap(); let expected_accountant_config = AccountantConfig { scan_intervals: ScanIntervals { pending_payable_scan_interval: Duration::from_secs(180), payable_scan_interval: Duration::from_secs(150), receivable_scan_interval: Duration::from_secs(130), }, - payment_thresholds: PaymentThresholds { - threshold_interval_sec: 1000, - debt_threshold_gwei: 100000, - payment_grace_period_sec: 1000, - maturity_threshold_sec: 1000, - permanent_debt_allowed_gwei: 20000, - unban_below_gwei: 20000, - }, suppress_initial_scans: false, when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, }; + let expected_scanners_config = PaymentThresholds { + threshold_interval_sec: 1000, + debt_threshold_gwei: 100000, + payment_grace_period_sec: 1000, + maturity_threshold_sec: 1000, + permanent_debt_allowed_gwei: 20000, + unban_below_gwei: 20000, + }; assert_eq!(actual_accountant_config, expected_accountant_config); + assert_eq!(actual_scanners_config, expected_scanners_config); //no prepared results for the setter methods, that is they were uncalled } diff --git a/node/src/sub_lib/accountant.rs b/node/src/sub_lib/accountant.rs index b7c15ae68..bd5281a41 100644 --- a/node/src/sub_lib/accountant.rs +++ b/node/src/sub_lib/accountant.rs @@ -38,7 +38,7 @@ lazy_static! { } //please, alphabetical order -#[derive(PartialEq, Debug, Clone, Copy, Default)] +#[derive(PartialEq, Debug, Clone, Default)] pub struct PaymentThresholds { pub debt_threshold_gwei: i64, pub maturity_threshold_sec: i64, @@ -59,17 +59,17 @@ impl PaymentThresholds { } } -#[derive(PartialEq, Debug, Clone, Copy, Default)] +#[derive(PartialEq, Debug, Clone, Default)] pub struct ScanIntervals { pub pending_payable_scan_interval: Duration, pub payable_scan_interval: Duration, pub receivable_scan_interval: Duration, } -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug)] pub struct AccountantConfig { pub scan_intervals: ScanIntervals, - pub payment_thresholds: PaymentThresholds, + // pub payment_thresholds: PaymentThresholds, pub suppress_initial_scans: bool, pub when_pending_too_long_sec: u64, } diff --git a/node/src/sub_lib/combined_parameters.rs b/node/src/sub_lib/combined_parameters.rs index 355370595..7bede1056 100644 --- a/node/src/sub_lib/combined_parameters.rs +++ b/node/src/sub_lib/combined_parameters.rs @@ -293,6 +293,9 @@ mod tests { use crate::sub_lib::accountant::{DEFAULT_PAYMENT_THRESHOLDS, DEFAULT_SCAN_INTERVALS}; use crate::sub_lib::combined_parameters::CombinedParamsDataTypes::U128; use crate::sub_lib::neighborhood::DEFAULT_RATE_PACK; + use crate::test_utils::unshared_test_utils::{ + make_payment_thresholds_with_defaults, make_scan_intervals_with_defaults, + }; use std::panic::catch_unwind; #[test] @@ -425,7 +428,8 @@ mod tests { let panic_2 = catch_unwind(|| { let _: &[(&str, CombinedParamsDataTypes)] = - (&CombinedParams::PaymentThresholds(Some(*DEFAULT_PAYMENT_THRESHOLDS))).into(); + (&CombinedParams::PaymentThresholds(Some(make_payment_thresholds_with_defaults()))) + .into(); }) .unwrap_err(); let panic_2_msg = panic_2.downcast_ref::().unwrap(); @@ -434,13 +438,13 @@ mod tests { panic_2_msg, &format!( "should be called only on uninitialized object, not: PaymentThresholds(Some({:?}))", - *DEFAULT_PAYMENT_THRESHOLDS + make_payment_thresholds_with_defaults() ) ); let panic_3 = catch_unwind(|| { let _: &[(&str, CombinedParamsDataTypes)] = - (&CombinedParams::ScanIntervals(Some(*DEFAULT_SCAN_INTERVALS))).into(); + (&CombinedParams::ScanIntervals(Some(make_scan_intervals_with_defaults()))).into(); }) .unwrap_err(); let panic_3_msg = panic_3.downcast_ref::().unwrap(); @@ -449,7 +453,7 @@ mod tests { panic_3_msg, &format!( "should be called only on uninitialized object, not: ScanIntervals(Some({:?}))", - *DEFAULT_SCAN_INTERVALS + make_scan_intervals_with_defaults() ) ); } @@ -471,7 +475,7 @@ mod tests { ); let panic_2 = catch_unwind(|| { - (&CombinedParams::PaymentThresholds(Some(*DEFAULT_PAYMENT_THRESHOLDS))) + (&CombinedParams::PaymentThresholds(Some(make_payment_thresholds_with_defaults()))) .initiate_objects(HashMap::new()); }) .unwrap_err(); @@ -481,12 +485,12 @@ mod tests { panic_2_msg, &format!( "should be called only on uninitialized object, not: PaymentThresholds(Some({:?}))", - *DEFAULT_PAYMENT_THRESHOLDS + make_payment_thresholds_with_defaults() ) ); let panic_3 = catch_unwind(|| { - (&CombinedParams::ScanIntervals(Some(*DEFAULT_SCAN_INTERVALS))) + (&CombinedParams::ScanIntervals(Some(make_scan_intervals_with_defaults()))) .initiate_objects(HashMap::new()); }) .unwrap_err(); @@ -496,7 +500,7 @@ mod tests { panic_3_msg, &format!( "should be called only on uninitialized object, not: ScanIntervals(Some({:?}))", - *DEFAULT_SCAN_INTERVALS + make_scan_intervals_with_defaults() ) ); } diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index ae3822c00..b913e76cc 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -518,7 +518,8 @@ pub mod unshared_test_utils { use crate::db_config::persistent_configuration::PersistentConfigurationReal; use crate::node_test_utils::DirsWrapperMock; use crate::sub_lib::accountant::{ - AccountantConfig, DEFAULT_PAYMENT_THRESHOLDS, DEFAULT_SCAN_INTERVALS, + AccountantConfig, PaymentThresholds, ScanIntervals, DEFAULT_PAYMENT_THRESHOLDS, + DEFAULT_SCAN_INTERVALS, }; use crate::sub_lib::neighborhood::DEFAULT_RATE_PACK; use crate::sub_lib::utils::{ @@ -592,8 +593,8 @@ pub mod unshared_test_utils { persistent_config_mock: PersistentConfigurationMock, ) -> PersistentConfigurationMock { persistent_config_mock - .payment_thresholds_result(Ok(*DEFAULT_PAYMENT_THRESHOLDS)) - .scan_intervals_result(Ok(*DEFAULT_SCAN_INTERVALS)) + .payment_thresholds_result(Ok(make_payment_thresholds_with_defaults())) + .scan_intervals_result(Ok(make_scan_intervals_with_defaults())) } pub fn make_persistent_config_real_with_config_dao_null() -> PersistentConfigurationReal { @@ -602,17 +603,23 @@ pub mod unshared_test_utils { pub fn make_populated_accountant_config_with_defaults() -> AccountantConfig { AccountantConfig { - scan_intervals: *DEFAULT_SCAN_INTERVALS, - payment_thresholds: *DEFAULT_PAYMENT_THRESHOLDS, + scan_intervals: make_scan_intervals_with_defaults(), when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, suppress_initial_scans: false, } } + pub fn make_payment_thresholds_with_defaults() -> PaymentThresholds { + DEFAULT_PAYMENT_THRESHOLDS.clone() + } + + pub fn make_scan_intervals_with_defaults() -> ScanIntervals { + DEFAULT_SCAN_INTERVALS.clone() + } + pub fn make_accountant_config_null() -> AccountantConfig { AccountantConfig { scan_intervals: Default::default(), - payment_thresholds: Default::default(), when_pending_too_long_sec: Default::default(), suppress_initial_scans: false, } From ee05a1430afb43d82268d3fe2b7664dae3df50b1 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 19 Aug 2022 13:06:47 +0530 Subject: [PATCH 039/145] GH-611: pull out payment_thresholds out of accountant_config and distribute a reference(counted) to individual scanners --- node/src/accountant/mod.rs | 38 ++++++-- node/src/accountant/scanners.rs | 149 ++++++++++++++++++-------------- node/src/accountant/tools.rs | 33 +------ node/src/sub_lib/accountant.rs | 8 +- 4 files changed, 122 insertions(+), 106 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 15d5abf93..2fa3d042f 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -60,6 +60,7 @@ use std::any::Any; use std::default::Default; use std::ops::Add; use std::path::Path; +use std::rc::Rc; use std::time::{Duration, SystemTime}; use web3::types::{TransactionReceipt, H256}; @@ -68,7 +69,7 @@ pub const CRASH_KEY: &str = "ACCOUNTANT"; pub const DEFAULT_PENDING_TOO_LONG_SEC: u64 = 21_600; //6 hours pub struct Accountant { - config: AccountantConfig, + accountant_config: AccountantConfig, consuming_wallet: Option, earning_wallet: Wallet, payable_dao: Box, @@ -86,6 +87,7 @@ pub struct Accountant { report_sent_payments_sub: Option>, ui_message_sub: Option>, logger: Logger, + payment_thresholds: Rc, } impl Actor for Accountant { @@ -145,7 +147,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, _msg: StartMessage, ctx: &mut Self::Context) -> Self::Result { - if self.config.suppress_initial_scans { + if self.accountant_config.suppress_initial_scans { info!( &self.logger, "Started with --scans off; declining to begin database and blockchain scans" @@ -440,8 +442,14 @@ impl Accountant { .accountant_config_opt .take() .expect("Accountant config"); + let payment_thresholds = Rc::new( + config + .payment_thresholds_opt + .take() + .expectv("Payment thresholds"), + ); Accountant { - config: accountant_config, + accountant_config, consuming_wallet: config.consuming_wallet_opt.clone(), earning_wallet: config.earning_wallet.clone(), payable_dao: payable_dao_factory.make(), @@ -453,6 +461,7 @@ impl Accountant { payable_dao_factory.make(), pending_payable_dao_factory.make(), receivable_dao_factory.make(), + Rc::clone(&payment_thresholds), ), tools: TransactionConfirmationTools::default(), notify_later: NotifyLaterForScanners::default(), @@ -463,6 +472,7 @@ impl Accountant { report_sent_payments_sub: None, ui_message_sub: None, logger: Logger::new("Accountant"), + payment_thresholds, } } @@ -1036,7 +1046,7 @@ impl Accountant { PendingTransactionStatus::Failure(fingerprint.into()) } match receipt.status { - None => handle_none_status(fingerprint, self.config.when_pending_too_long_sec, logger), + None => handle_none_status(fingerprint, self.accountant_config.when_pending_too_long_sec, logger), Some(status_code) => match status_code.as_u64() { 0 => handle_status_with_failure(fingerprint, logger), @@ -1226,7 +1236,7 @@ mod tests { is_innocent_age_results: RefCell>, is_innocent_balance_params: Arc>>, is_innocent_balance_results: RefCell>, - calculate_payout_threshold_params: Arc>>, + calculate_payout_threshold_params: Arc, u64)>>>, calculate_payout_threshold_results: RefCell>, } @@ -1247,7 +1257,11 @@ mod tests { self.is_innocent_balance_results.borrow_mut().remove(0) } - fn calculate_payout_threshold(&self, payment_thresholds: PaymentThresholds, x: u64) -> f64 { + fn calculate_payout_threshold( + &self, + payment_thresholds: Rc, + x: u64, + ) -> f64 { self.calculate_payout_threshold_params .lock() .unwrap() @@ -1281,7 +1295,7 @@ mod tests { fn calculate_payout_threshold_params( mut self, - params: &Arc>>, + params: &Arc, u64)>>>, ) -> Self { self.calculate_payout_threshold_params = params.clone(); self @@ -2837,7 +2851,10 @@ mod tests { .bootstrapper_config(config) .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); + subject + .accountant_config + .scan_intervals + .payable_scan_interval = Duration::from_millis(10); // let is_scan_running_initially = subject.scanners.payables.is_scan_running(); let addr = subject.start(); @@ -2889,7 +2906,10 @@ mod tests { .bootstrapper_config(config) .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - subject.config.scan_intervals.payable_scan_interval = Duration::from_millis(10); + subject + .accountant_config + .scan_intervals + .payable_scan_interval = Duration::from_millis(10); subject.logger = Logger::new( "accountant_doesn_t_starts_another_scan_in_case_\ it_receives_the_message_and_the_scanner_is_running", diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 90c24a663..bab765181 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -12,7 +12,7 @@ pub(in crate::accountant) mod scanners { ScanForPendingPayables, ScanForReceivables, SentPayable, }; use crate::blockchain::blockchain_bridge::RetrieveTransactions; - use crate::sub_lib::accountant::AccountantConfig; + use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds}; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use actix::dev::SendError; use actix::{Context, Message, Recipient}; @@ -24,6 +24,7 @@ pub(in crate::accountant) mod scanners { use std::borrow::BorrowMut; use std::cell::RefCell; use std::ops::Add; + use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::{Duration, SystemTime}; @@ -41,11 +42,21 @@ pub(in crate::accountant) mod scanners { payable_dao: Box, pending_payable_dao: Box, receivable_dao: Box, + payment_thresholds: Rc, ) -> Self { Scanners { - payables: Box::new(PayableScanner::new(payable_dao)), - pending_payables: Box::new(PendingPayableScanner::new(pending_payable_dao)), - receivables: Box::new(ReceivableScanner::new(receivable_dao)), + payables: Box::new(PayableScanner::new( + payable_dao, + Rc::clone(&payment_thresholds), + )), + pending_payables: Box::new(PendingPayableScanner::new( + pending_payable_dao, + Rc::clone(&payment_thresholds), + )), + receivables: Box::new(ReceivableScanner::new( + receivable_dao, + Rc::clone(&payment_thresholds), + )), } } } @@ -68,12 +79,14 @@ pub(in crate::accountant) mod scanners { struct ScannerCommon { initiated_at_opt: Option, + payment_thresholds: Rc, } - impl Default for ScannerCommon { - fn default() -> Self { + impl ScannerCommon { + fn new(payment_thresholds: Rc) -> Self { Self { initiated_at_opt: None, + payment_thresholds, } } } @@ -143,9 +156,9 @@ pub(in crate::accountant) mod scanners { } impl PayableScanner { - pub fn new(dao: Box) -> Self { + pub fn new(dao: Box, payment_thresholds: Rc) -> Self { Self { - common: ScannerCommon::default(), + common: ScannerCommon::new(payment_thresholds), dao, payable_threshold_tools: Box::new(PayableExceedThresholdToolsReal::default()), } @@ -216,33 +229,34 @@ pub(in crate::accountant) mod scanners { fn payable_exceeded_threshold(&self, payable: &PayableAccount) -> Option { todo!("Fix the config variable problem"); // TODO: This calculation should be done in the database, if possible - // let time_since_last_paid = SystemTime::now() - // .duration_since(payable.last_paid_timestamp) - // .expect("Internal error") - // .as_secs(); - // - // if self.payable_threshold_tools.is_innocent_age( - // time_since_last_paid, - // self.config.payment_thresholds.maturity_threshold_sec as u64, - // ) { - // return None; - // } - // - // if self.payable_threshold_tools.is_innocent_balance( - // payable.balance, - // self.config.payment_thresholds.permanent_debt_allowed_gwei, - // ) { - // return None; - // } - // - // let threshold = self - // .payable_threshold_tools - // .calculate_payout_threshold(self.config.payment_thresholds, time_since_last_paid); - // if payable.balance as f64 > threshold { - // Some(threshold as u64) - // } else { - // None - // } + let time_since_last_paid = SystemTime::now() + .duration_since(payable.last_paid_timestamp) + .expect("Internal error") + .as_secs(); + + if self.payable_threshold_tools.is_innocent_age( + time_since_last_paid, + self.common.payment_thresholds.maturity_threshold_sec as u64, + ) { + return None; + } + + if self.payable_threshold_tools.is_innocent_balance( + payable.balance, + self.common.payment_thresholds.permanent_debt_allowed_gwei, + ) { + return None; + } + + let threshold = self.payable_threshold_tools.calculate_payout_threshold( + self.common.payment_thresholds.clone(), + time_since_last_paid, + ); + if payable.balance as f64 > threshold { + Some(threshold as u64) + } else { + None + } } fn payables_debug_summary(&self, qualified_payables: &[PayableAccount]) -> String { @@ -300,9 +314,12 @@ pub(in crate::accountant) mod scanners { } impl PendingPayableScanner { - pub fn new(dao: Box) -> Self { + pub fn new( + dao: Box, + payment_thresholds: Rc, + ) -> Self { Self { - common: ScannerCommon::default(), + common: ScannerCommon::new(payment_thresholds), dao, } } @@ -339,9 +356,9 @@ pub(in crate::accountant) mod scanners { } impl ReceivableScanner { - pub fn new(dao: Box) -> Self { + pub fn new(dao: Box, payment_thresholds: Rc) -> Self { Self { - common: ScannerCommon::default(), + common: ScannerCommon::new(payment_thresholds), dao, } } @@ -463,29 +480,33 @@ mod tests { PayableScanner, PendingPayableScanner, ReceivableScanner, Scanners, }; use crate::accountant::test_utils::{PayableDaoMock, PendingPayableDaoMock, ReceivableDaoMock}; - - // #[test] - // fn scanners_struct_can_be_constructed_with_the_respective_scanners() { - // let scanners = Scanners::new( - // Box::new(PayableDaoMock::new()), - // Box::new(PendingPayableDaoMock::new()), - // Box::new(ReceivableDaoMock::new()), - // ); - // - // scanners - // .payables - // .as_any() - // .downcast_ref::() - // .unwrap(); - // scanners - // .pending_payables - // .as_any() - // .downcast_ref::() - // .unwrap(); - // scanners - // .receivables - // .as_any() - // .downcast_ref::() - // .unwrap(); - // } + use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; + use std::rc::Rc; + + #[test] + fn scanners_struct_can_be_constructed_with_the_respective_scanners() { + let payment_thresholds = Rc::new(make_payment_thresholds_with_defaults()); + let scanners = Scanners::new( + Box::new(PayableDaoMock::new()), + Box::new(PendingPayableDaoMock::new()), + Box::new(ReceivableDaoMock::new()), + Rc::clone(&payment_thresholds), + ); + + scanners + .payables + .as_any() + .downcast_ref::() + .unwrap(); + scanners + .pending_payables + .as_any() + .downcast_ref::() + .unwrap(); + scanners + .receivables + .as_any() + .downcast_ref::() + .unwrap(); + } } diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 92537f00c..ad971a294 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -1,18 +1,17 @@ use crate::sub_lib::accountant::PaymentThresholds; use std::any::Any; +use std::rc::Rc; //TODO the data types should change with GH-497 (including signed => unsigned) pub trait PayableExceedThresholdTools { fn is_innocent_age(&self, age: u64, limit: u64) -> bool; fn is_innocent_balance(&self, balance: i64, limit: i64) -> bool; - fn calculate_payout_threshold(&self, payment_thresholds: PaymentThresholds, x: u64) -> f64; + fn calculate_payout_threshold(&self, payment_thresholds: Rc, x: u64) -> f64; as_any_dcl!(); } #[derive(Default)] -pub struct PayableExceedThresholdToolsReal { - pub payment_thresholds: PaymentThresholds, -} +pub struct PayableExceedThresholdToolsReal {} impl PayableExceedThresholdTools for PayableExceedThresholdToolsReal { fn is_innocent_age(&self, age: u64, limit: u64) -> bool { @@ -23,7 +22,7 @@ impl PayableExceedThresholdTools for PayableExceedThresholdToolsReal { balance <= limit } - fn calculate_payout_threshold(&self, payment_thresholds: PaymentThresholds, x: u64) -> f64 { + fn calculate_payout_threshold(&self, payment_thresholds: Rc, x: u64) -> f64 { let m = -((payment_thresholds.debt_threshold_gwei as f64 - payment_thresholds.permanent_debt_allowed_gwei as f64) / (payment_thresholds.threshold_interval_sec as f64 @@ -34,27 +33,3 @@ impl PayableExceedThresholdTools for PayableExceedThresholdToolsReal { } as_any_impl!(); } - -impl PayableExceedThresholdToolsReal { - pub fn new(payment_thresholds: PaymentThresholds) -> Self { - Self { payment_thresholds } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::sub_lib::accountant::DEFAULT_PAYMENT_THRESHOLDS; - - #[test] - fn payable_thresholds_real_can_be_constructed_properly() { - let payment_thresholds = DEFAULT_PAYMENT_THRESHOLDS.clone(); - let payable_exceed_threshold_tools_real = - PayableExceedThresholdToolsReal::new(payment_thresholds.clone()); - - assert_eq!( - payable_exceed_threshold_tools_real.payment_thresholds, - payment_thresholds - ) - } -} diff --git a/node/src/sub_lib/accountant.rs b/node/src/sub_lib/accountant.rs index bd5281a41..fa847081b 100644 --- a/node/src/sub_lib/accountant.rs +++ b/node/src/sub_lib/accountant.rs @@ -40,11 +40,11 @@ lazy_static! { //please, alphabetical order #[derive(PartialEq, Debug, Clone, Default)] pub struct PaymentThresholds { - pub debt_threshold_gwei: i64, - pub maturity_threshold_sec: i64, + pub debt_threshold_gwei: i64, // Paybale + pub maturity_threshold_sec: i64, // Payable pub payment_grace_period_sec: i64, - pub permanent_debt_allowed_gwei: i64, - pub threshold_interval_sec: i64, + pub permanent_debt_allowed_gwei: i64, // Payable + pub threshold_interval_sec: i64, // Payable pub unban_below_gwei: i64, } From 2ac9e65ca98f1d47ec54bdf2031909d8ba747d31 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 19 Aug 2022 15:20:48 +0530 Subject: [PATCH 040/145] GH-611: refactor tools for Payable Scanner --- node/src/accountant/mod.rs | 161 -------------------------------- node/src/accountant/scanners.rs | 32 +++++-- node/src/accountant/tools.rs | 34 ------- 3 files changed, 22 insertions(+), 205 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 2fa3d042f..54b2a2322 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -21,7 +21,6 @@ use crate::accountant::receivable_dao::{ use crate::accountant::scanners::scanners::{ NotifyLaterForScanners, Scanner, Scanners, TransactionConfirmationTools, }; -use crate::accountant::tools::{PayableExceedThresholdTools, PayableExceedThresholdToolsReal}; use crate::banned_dao::{BannedDao, BannedDaoFactory}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::{BlockchainError, BlockchainTransaction}; @@ -1201,7 +1200,6 @@ mod tests { ReceivableDaoMock, }; use crate::accountant::test_utils::{AccountantBuilder, BannedDaoMock}; - use crate::accountant::tools::PayableExceedThresholdTools; use crate::accountant::Accountant; use crate::blockchain::blockchain_bridge::BlockchainBridge; use crate::blockchain::blockchain_interface::BlockchainError; @@ -1230,85 +1228,6 @@ mod tests { use masq_lib::logger::timestamp_as_string; use web3::types::{TransactionReceipt, H256}; - #[derive(Default)] - struct PayableThresholdToolsMock { - is_innocent_age_params: Arc>>, - is_innocent_age_results: RefCell>, - is_innocent_balance_params: Arc>>, - is_innocent_balance_results: RefCell>, - calculate_payout_threshold_params: Arc, u64)>>>, - calculate_payout_threshold_results: RefCell>, - } - - impl PayableExceedThresholdTools for PayableThresholdToolsMock { - fn is_innocent_age(&self, age: u64, limit: u64) -> bool { - self.is_innocent_age_params - .lock() - .unwrap() - .push((age, limit)); - self.is_innocent_age_results.borrow_mut().remove(0) - } - - fn is_innocent_balance(&self, balance: i64, limit: i64) -> bool { - self.is_innocent_balance_params - .lock() - .unwrap() - .push((balance, limit)); - self.is_innocent_balance_results.borrow_mut().remove(0) - } - - fn calculate_payout_threshold( - &self, - payment_thresholds: Rc, - x: u64, - ) -> f64 { - self.calculate_payout_threshold_params - .lock() - .unwrap() - .push((payment_thresholds, x)); - self.calculate_payout_threshold_results - .borrow_mut() - .remove(0) - } - } - - impl PayableThresholdToolsMock { - fn is_innocent_age_params(mut self, params: &Arc>>) -> Self { - self.is_innocent_age_params = params.clone(); - self - } - - fn is_innocent_age_result(self, result: bool) -> Self { - self.is_innocent_age_results.borrow_mut().push(result); - self - } - - fn is_innocent_balance_params(mut self, params: &Arc>>) -> Self { - self.is_innocent_balance_params = params.clone(); - self - } - - fn is_innocent_balance_result(self, result: bool) -> Self { - self.is_innocent_balance_results.borrow_mut().push(result); - self - } - - fn calculate_payout_threshold_params( - mut self, - params: &Arc, u64)>>>, - ) -> Self { - self.calculate_payout_threshold_params = params.clone(); - self - } - - fn calculate_payout_threshold_result(self, result: f64) -> Self { - self.calculate_payout_threshold_results - .borrow_mut() - .push(result); - self - } - } - // fn Box::new(ScannerMock::new()) -> Scanner { // Scanner::new(ScanType::Payables, Box::new(|_, _| {}), Box::new(|_, _| {})) // } @@ -4049,86 +3968,6 @@ mod tests { // } // TODO: This test should be migrated to scanners - // #[test] - // fn threshold_calculation_depends_on_user_defined_payment_thresholds() { - // let safe_age_params_arc = Arc::new(Mutex::new(vec![])); - // let safe_balance_params_arc = Arc::new(Mutex::new(vec![])); - // let calculate_payable_threshold_params_arc = Arc::new(Mutex::new(vec![])); - // let balance = 5555; - // let how_far_in_past = Duration::from_secs(1111 + 1); - // let last_paid_timestamp = SystemTime::now().sub(how_far_in_past); - // let payable_account = PayableAccount { - // wallet: make_wallet("hi"), - // balance, - // last_paid_timestamp, - // pending_payable_opt: None, - // }; - // let custom_payment_thresholds = PaymentThresholds { - // maturity_threshold_sec: 1111, - // payment_grace_period_sec: 2222, - // permanent_debt_allowed_gwei: 3333, - // debt_threshold_gwei: 4444, - // threshold_interval_sec: 5555, - // unban_below_gwei: 3333, - // }; - // let mut bootstrapper_config = BootstrapperConfig::default(); - // bootstrapper_config.accountant_config_opt = Some(AccountantConfig { - // scan_intervals: Default::default(), - // payment_thresholds: custom_payment_thresholds, - // suppress_initial_scans: false, - // when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - // }); - // let payable_thresholds_tools = PayableThresholdToolsMock::default() - // .is_innocent_age_params(&safe_age_params_arc) - // .is_innocent_age_result( - // how_far_in_past.as_secs() - // <= custom_payment_thresholds.maturity_threshold_sec as u64, - // ) - // .is_innocent_balance_params(&safe_balance_params_arc) - // .is_innocent_balance_result( - // balance <= custom_payment_thresholds.permanent_debt_allowed_gwei, - // ) - // .calculate_payout_threshold_params(&calculate_payable_threshold_params_arc) - // .calculate_payout_threshold_result(4567.0); //made up value - // let mut subject = AccountantBuilder::default() - // .bootstrapper_config(bootstrapper_config) - // .build(); - // subject.scanners.payables.payable_thresholds_tools = Box::new(payable_thresholds_tools); - // - // let result = subject.payable_exceeded_threshold(&payable_account); - // - // assert_eq!(result, Some(4567)); - // let mut safe_age_params = safe_age_params_arc.lock().unwrap(); - // let safe_age_single_params = safe_age_params.remove(0); - // assert_eq!(*safe_age_params, vec![]); - // let (time_elapsed, curve_derived_time) = safe_age_single_params; - // assert!( - // (how_far_in_past.as_secs() - 3) < time_elapsed - // && time_elapsed < (how_far_in_past.as_secs() + 3) - // ); - // assert_eq!( - // curve_derived_time, - // custom_payment_thresholds.maturity_threshold_sec as u64 - // ); - // let safe_balance_params = safe_balance_params_arc.lock().unwrap(); - // assert_eq!( - // *safe_balance_params, - // vec![( - // payable_account.balance, - // custom_payment_thresholds.permanent_debt_allowed_gwei - // )] - // ); - // let mut calculate_payable_curves_params = - // calculate_payable_threshold_params_arc.lock().unwrap(); - // let calculate_payable_curves_single_params = calculate_payable_curves_params.remove(0); - // assert_eq!(*calculate_payable_curves_params, vec![]); - // let (payment_thresholds, time_elapsed) = calculate_payable_curves_single_params; - // assert!( - // (how_far_in_past.as_secs() - 3) < time_elapsed - // && time_elapsed < (how_far_in_past.as_secs() + 3) - // ); - // assert_eq!(payment_thresholds, custom_payment_thresholds) - // } #[test] fn pending_transaction_is_registered_and_monitored_until_it_gets_confirmed_or_canceled() { init_test_logging(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index bab765181..e95eb9b0b 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -4,7 +4,6 @@ pub(in crate::accountant) mod scanners { use crate::accountant::payable_dao::{PayableAccount, PayableDao, PayableDaoReal}; use crate::accountant::pending_payable_dao::PendingPayableDao; use crate::accountant::receivable_dao::ReceivableDao; - use crate::accountant::tools::{PayableExceedThresholdTools, PayableExceedThresholdToolsReal}; use crate::accountant::ReportAccountsPayable; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, @@ -94,7 +93,6 @@ pub(in crate::accountant) mod scanners { pub struct PayableScanner { common: ScannerCommon, dao: Box, - payable_threshold_tools: Box, } impl Scanner for PayableScanner { @@ -160,7 +158,6 @@ pub(in crate::accountant) mod scanners { Self { common: ScannerCommon::new(payment_thresholds), dao, - payable_threshold_tools: Box::new(PayableExceedThresholdToolsReal::default()), } } @@ -227,31 +224,27 @@ pub(in crate::accountant) mod scanners { } fn payable_exceeded_threshold(&self, payable: &PayableAccount) -> Option { - todo!("Fix the config variable problem"); // TODO: This calculation should be done in the database, if possible let time_since_last_paid = SystemTime::now() .duration_since(payable.last_paid_timestamp) .expect("Internal error") .as_secs(); - if self.payable_threshold_tools.is_innocent_age( + if PayableScanner::is_innocent_age( time_since_last_paid, self.common.payment_thresholds.maturity_threshold_sec as u64, ) { return None; } - if self.payable_threshold_tools.is_innocent_balance( + if PayableScanner::is_innocent_balance( payable.balance, self.common.payment_thresholds.permanent_debt_allowed_gwei, ) { return None; } - let threshold = self.payable_threshold_tools.calculate_payout_threshold( - self.common.payment_thresholds.clone(), - time_since_last_paid, - ); + let threshold = self.calculate_payout_threshold(time_since_last_paid); if payable.balance as f64 > threshold { Some(threshold as u64) } else { @@ -281,6 +274,25 @@ pub(in crate::accountant) mod scanners { .join("\n"); String::from("Paying qualified debts:\n").add(&list) } + + fn is_innocent_age(age: u64, limit: u64) -> bool { + age <= limit + } + + fn is_innocent_balance(balance: i64, limit: i64) -> bool { + balance <= limit + } + + fn calculate_payout_threshold(&self, x: u64) -> f64 { + let payment_thresholds = self.common.payment_thresholds.clone(); + let m = -((payment_thresholds.debt_threshold_gwei as f64 + - payment_thresholds.permanent_debt_allowed_gwei as f64) + / (payment_thresholds.threshold_interval_sec as f64 + - payment_thresholds.maturity_threshold_sec as f64)); + let b = payment_thresholds.debt_threshold_gwei as f64 + - m * payment_thresholds.maturity_threshold_sec as f64; + m * x as f64 + b + } } pub struct PendingPayableScanner { diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index ad971a294..8b1378917 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -1,35 +1 @@ -use crate::sub_lib::accountant::PaymentThresholds; -use std::any::Any; -use std::rc::Rc; -//TODO the data types should change with GH-497 (including signed => unsigned) -pub trait PayableExceedThresholdTools { - fn is_innocent_age(&self, age: u64, limit: u64) -> bool; - fn is_innocent_balance(&self, balance: i64, limit: i64) -> bool; - fn calculate_payout_threshold(&self, payment_thresholds: Rc, x: u64) -> f64; - as_any_dcl!(); -} - -#[derive(Default)] -pub struct PayableExceedThresholdToolsReal {} - -impl PayableExceedThresholdTools for PayableExceedThresholdToolsReal { - fn is_innocent_age(&self, age: u64, limit: u64) -> bool { - age <= limit - } - - fn is_innocent_balance(&self, balance: i64, limit: i64) -> bool { - balance <= limit - } - - fn calculate_payout_threshold(&self, payment_thresholds: Rc, x: u64) -> f64 { - let m = -((payment_thresholds.debt_threshold_gwei as f64 - - payment_thresholds.permanent_debt_allowed_gwei as f64) - / (payment_thresholds.threshold_interval_sec as f64 - - payment_thresholds.maturity_threshold_sec as f64)); - let b = payment_thresholds.debt_threshold_gwei as f64 - - m * payment_thresholds.maturity_threshold_sec as f64; - m * x as f64 + b - } - as_any_impl!(); -} From 78571f5b60961ec2d1af3ac86386918067e4b5b4 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 19 Aug 2022 16:05:01 +0530 Subject: [PATCH 041/145] GH-611: migrate the payable scanner tools to the tools.rs --- node/src/accountant/mod.rs | 46 -------- node/src/accountant/scanners.rs | 155 +++---------------------- node/src/accountant/tools.rs | 196 ++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 185 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 54b2a2322..27a3ed4d0 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -3921,52 +3921,6 @@ mod tests { // assert_eq!(result, "Payable scan found 4 debts; the biggest is 2000000 owed for 10000sec, the oldest is 330 owed for 30000sec") // } - // TODO: Migrate this test to scanners - // #[test] - // fn payables_debug_summary_prints_pretty_summary() { - // let now = to_time_t(SystemTime::now()); - // let payment_thresholds = PaymentThresholds { - // threshold_interval_sec: 2_592_000, - // debt_threshold_gwei: 1_000_000_000, - // payment_grace_period_sec: 86_400, - // maturity_threshold_sec: 86_400, - // permanent_debt_allowed_gwei: 10_000_000, - // unban_below_gwei: 10_000_000, - // }; - // let qualified_payables = &[ - // PayableAccount { - // wallet: make_wallet("wallet0"), - // balance: payment_thresholds.permanent_debt_allowed_gwei + 1000, - // last_paid_timestamp: from_time_t( - // now - payment_thresholds.threshold_interval_sec - 1234, - // ), - // pending_payable_opt: None, - // }, - // PayableAccount { - // wallet: make_wallet("wallet1"), - // balance: payment_thresholds.permanent_debt_allowed_gwei + 1, - // last_paid_timestamp: from_time_t( - // now - payment_thresholds.threshold_interval_sec - 1, - // ), - // pending_payable_opt: None, - // }, - // ]; - // let mut config = BootstrapperConfig::default(); - // config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); - // let mut subject = AccountantBuilder::default() - // .bootstrapper_config(config) - // .build(); - // subject.config.payment_thresholds = payment_thresholds; - // - // let result = subject.payables_debug_summary(qualified_payables); - // - // assert_eq!(result, - // "Paying qualified debts:\n\ - // 10001000 owed for 2593234sec exceeds threshold: 9512428; creditor: 0x0000000000000000000000000077616c6c657430\n\ - // 10000001 owed for 2592001sec exceeds threshold: 9999604; creditor: 0x0000000000000000000000000077616c6c657431" - // ) - // } - // TODO: This test should be migrated to scanners #[test] fn pending_transaction_is_registered_and_monitored_until_it_gets_confirmed_or_canceled() { diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index e95eb9b0b..6c40c64fe 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -4,6 +4,7 @@ pub(in crate::accountant) mod scanners { use crate::accountant::payable_dao::{PayableAccount, PayableDao, PayableDaoReal}; use crate::accountant::pending_payable_dao::PendingPayableDao; use crate::accountant::receivable_dao::ReceivableDao; + use crate::accountant::tools::{investigate_debt_extremes, payables_debug_summary, should_pay}; use crate::accountant::ReportAccountsPayable; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, @@ -114,11 +115,11 @@ pub(in crate::accountant) mod scanners { debug!( logger, "{}", - Self::investigate_debt_extremes(&all_non_pending_payables) + investigate_debt_extremes(&all_non_pending_payables) ); let qualified_payables = all_non_pending_payables .into_iter() - .filter(|account| self.should_pay(account)) + .filter(|account| should_pay(account, self.common.payment_thresholds.clone())) .collect::>(); info!( logger, @@ -128,7 +129,7 @@ pub(in crate::accountant) mod scanners { debug!( logger, "{}", - self.payables_debug_summary(&qualified_payables) + payables_debug_summary(&qualified_payables, self.common.payment_thresholds.clone()) ); match qualified_payables.is_empty() { true => Err(String::from("No Qualified Payables found.")), @@ -160,139 +161,6 @@ pub(in crate::accountant) mod scanners { dao, } } - - //for debugging only - pub fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccount]) -> String { - if all_non_pending_payables.is_empty() { - "Payable scan found no debts".to_string() - } else { - struct PayableInfo { - balance: i64, - age: Duration, - } - let now = SystemTime::now(); - let init = ( - PayableInfo { - balance: 0, - age: Duration::ZERO, - }, - PayableInfo { - balance: 0, - age: Duration::ZERO, - }, - ); - let (biggest, oldest) = all_non_pending_payables.iter().fold(init, |sofar, p| { - let (mut biggest, mut oldest) = sofar; - let p_age = now - .duration_since(p.last_paid_timestamp) - .expect("Payable time is corrupt"); - { - //look at a test if not understandable - let check_age_parameter_if_the_first_is_the_same = - || -> bool { p.balance == biggest.balance && p_age > biggest.age }; - - if p.balance > biggest.balance - || check_age_parameter_if_the_first_is_the_same() - { - biggest = PayableInfo { - balance: p.balance, - age: p_age, - } - } - - let check_balance_parameter_if_the_first_is_the_same = - || -> bool { p_age == oldest.age && p.balance > oldest.balance }; - - if p_age > oldest.age || check_balance_parameter_if_the_first_is_the_same() - { - oldest = PayableInfo { - balance: p.balance, - age: p_age, - } - } - } - (biggest, oldest) - }); - format!("Payable scan found {} debts; the biggest is {} owed for {}sec, the oldest is {} owed for {}sec", - all_non_pending_payables.len(), biggest.balance, biggest.age.as_secs(), - oldest.balance, oldest.age.as_secs()) - } - } - - fn should_pay(&self, payable: &PayableAccount) -> bool { - self.payable_exceeded_threshold(payable).is_some() - } - - fn payable_exceeded_threshold(&self, payable: &PayableAccount) -> Option { - // TODO: This calculation should be done in the database, if possible - let time_since_last_paid = SystemTime::now() - .duration_since(payable.last_paid_timestamp) - .expect("Internal error") - .as_secs(); - - if PayableScanner::is_innocent_age( - time_since_last_paid, - self.common.payment_thresholds.maturity_threshold_sec as u64, - ) { - return None; - } - - if PayableScanner::is_innocent_balance( - payable.balance, - self.common.payment_thresholds.permanent_debt_allowed_gwei, - ) { - return None; - } - - let threshold = self.calculate_payout_threshold(time_since_last_paid); - if payable.balance as f64 > threshold { - Some(threshold as u64) - } else { - None - } - } - - fn payables_debug_summary(&self, qualified_payables: &[PayableAccount]) -> String { - let now = SystemTime::now(); - let list = qualified_payables - .iter() - .map(|payable| { - let p_age = now - .duration_since(payable.last_paid_timestamp) - .expect("Payable time is corrupt"); - let threshold = self - .payable_exceeded_threshold(payable) - .expect("Threshold suddenly changed!"); - format!( - "{} owed for {}sec exceeds threshold: {}; creditor: {}", - payable.balance, - p_age.as_secs(), - threshold, - payable.wallet - ) - }) - .join("\n"); - String::from("Paying qualified debts:\n").add(&list) - } - - fn is_innocent_age(age: u64, limit: u64) -> bool { - age <= limit - } - - fn is_innocent_balance(balance: i64, limit: i64) -> bool { - balance <= limit - } - - fn calculate_payout_threshold(&self, x: u64) -> f64 { - let payment_thresholds = self.common.payment_thresholds.clone(); - let m = -((payment_thresholds.debt_threshold_gwei as f64 - - payment_thresholds.permanent_debt_allowed_gwei as f64) - / (payment_thresholds.threshold_interval_sec as f64 - - payment_thresholds.maturity_threshold_sec as f64)); - let b = payment_thresholds.debt_threshold_gwei as f64 - - m * payment_thresholds.maturity_threshold_sec as f64; - m * x as f64 + b - } } pub struct PendingPayableScanner { @@ -487,13 +355,22 @@ pub(in crate::accountant) mod scanners { #[cfg(test)] mod tests { use super::*; - use crate::accountant::payable_dao::PayableDaoReal; + use crate::accountant::payable_dao::{PayableAccount, PayableDaoReal}; use crate::accountant::scanners::scanners::{ PayableScanner, PendingPayableScanner, ReceivableScanner, Scanners, }; - use crate::accountant::test_utils::{PayableDaoMock, PendingPayableDaoMock, ReceivableDaoMock}; - use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; + use crate::accountant::test_utils::{ + AccountantBuilder, PayableDaoMock, PendingPayableDaoMock, ReceivableDaoMock, + }; + use crate::bootstrapper::BootstrapperConfig; + use crate::database::dao_utils::{from_time_t, to_time_t}; + use crate::sub_lib::accountant::PaymentThresholds; + use crate::test_utils::make_wallet; + use crate::test_utils::unshared_test_utils::{ + make_payment_thresholds_with_defaults, make_populated_accountant_config_with_defaults, + }; use std::rc::Rc; + use std::time::SystemTime; #[test] fn scanners_struct_can_be_constructed_with_the_respective_scanners() { diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 8b1378917..98e675ee5 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -1 +1,197 @@ +use crate::accountant::payable_dao::PayableAccount; +use crate::accountant::scanners::scanners::PayableScanner; +use crate::sub_lib::accountant::PaymentThresholds; +use itertools::Itertools; +use std::ops::Add; +use std::rc::Rc; +use std::time::{Duration, SystemTime}; +//for debugging only +pub(crate) fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccount]) -> String { + if all_non_pending_payables.is_empty() { + "Payable scan found no debts".to_string() + } else { + struct PayableInfo { + balance: i64, + age: Duration, + } + let now = SystemTime::now(); + let init = ( + PayableInfo { + balance: 0, + age: Duration::ZERO, + }, + PayableInfo { + balance: 0, + age: Duration::ZERO, + }, + ); + let (biggest, oldest) = all_non_pending_payables.iter().fold(init, |sofar, p| { + let (mut biggest, mut oldest) = sofar; + let p_age = now + .duration_since(p.last_paid_timestamp) + .expect("Payable time is corrupt"); + { + //look at a test if not understandable + let check_age_parameter_if_the_first_is_the_same = + || -> bool { p.balance == biggest.balance && p_age > biggest.age }; + + if p.balance > biggest.balance || check_age_parameter_if_the_first_is_the_same() { + biggest = PayableInfo { + balance: p.balance, + age: p_age, + } + } + + let check_balance_parameter_if_the_first_is_the_same = + || -> bool { p_age == oldest.age && p.balance > oldest.balance }; + + if p_age > oldest.age || check_balance_parameter_if_the_first_is_the_same() { + oldest = PayableInfo { + balance: p.balance, + age: p_age, + } + } + } + (biggest, oldest) + }); + format!("Payable scan found {} debts; the biggest is {} owed for {}sec, the oldest is {} owed for {}sec", + all_non_pending_payables.len(), biggest.balance, biggest.age.as_secs(), + oldest.balance, oldest.age.as_secs()) + } +} + +pub(crate) fn should_pay( + payable: &PayableAccount, + payment_thresholds: Rc, +) -> bool { + payable_exceeded_threshold(payable, payment_thresholds).is_some() +} + +fn payable_exceeded_threshold( + payable: &PayableAccount, + payment_thresholds: Rc, +) -> Option { + // TODO: This calculation should be done in the database, if possible + let time_since_last_paid = SystemTime::now() + .duration_since(payable.last_paid_timestamp) + .expect("Internal error") + .as_secs(); + + if is_innocent_age( + time_since_last_paid, + payment_thresholds.maturity_threshold_sec as u64, + ) { + return None; + } + + if is_innocent_balance( + payable.balance, + payment_thresholds.permanent_debt_allowed_gwei, + ) { + return None; + } + + let threshold = calculate_payout_threshold(time_since_last_paid, payment_thresholds); + if payable.balance as f64 > threshold { + Some(threshold as u64) + } else { + None + } +} + +pub(crate) fn payables_debug_summary( + qualified_payables: &[PayableAccount], + payment_thresholds: Rc, +) -> String { + let now = SystemTime::now(); + let list = qualified_payables + .iter() + .map(|payable| { + let p_age = now + .duration_since(payable.last_paid_timestamp) + .expect("Payable time is corrupt"); + let threshold = payable_exceeded_threshold(payable, payment_thresholds.clone()) + .expect("Threshold suddenly changed!"); + format!( + "{} owed for {}sec exceeds threshold: {}; creditor: {}", + payable.balance, + p_age.as_secs(), + threshold, + payable.wallet + ) + }) + .join("\n"); + String::from("Paying qualified debts:\n").add(&list) +} + +fn is_innocent_age(age: u64, limit: u64) -> bool { + age <= limit +} + +fn is_innocent_balance(balance: i64, limit: i64) -> bool { + balance <= limit +} + +fn calculate_payout_threshold(x: u64, payment_thresholds: Rc) -> f64 { + let m = -((payment_thresholds.debt_threshold_gwei as f64 + - payment_thresholds.permanent_debt_allowed_gwei as f64) + / (payment_thresholds.threshold_interval_sec as f64 + - payment_thresholds.maturity_threshold_sec as f64)); + let b = payment_thresholds.debt_threshold_gwei as f64 + - m * payment_thresholds.maturity_threshold_sec as f64; + m * x as f64 + b +} + +#[cfg(test)] +mod tests { + use crate::accountant::payable_dao::PayableAccount; + use crate::accountant::tools::payables_debug_summary; + use crate::bootstrapper::BootstrapperConfig; + use crate::database::dao_utils::{from_time_t, to_time_t}; + use crate::sub_lib::accountant::PaymentThresholds; + use crate::test_utils::make_wallet; + use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; + use std::rc::Rc; + use std::time::SystemTime; + + #[test] + fn payables_debug_summary_prints_pretty_summary() { + let now = to_time_t(SystemTime::now()); + let payment_thresholds = PaymentThresholds { + threshold_interval_sec: 2_592_000, + debt_threshold_gwei: 1_000_000_000, + payment_grace_period_sec: 86_400, + maturity_threshold_sec: 86_400, + permanent_debt_allowed_gwei: 10_000_000, + unban_below_gwei: 10_000_000, + }; + let payment_thresholds_rc = Rc::new(payment_thresholds.clone()); + let qualified_payables = &[ + PayableAccount { + wallet: make_wallet("wallet0"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1000, + last_paid_timestamp: from_time_t( + now - payment_thresholds.threshold_interval_sec - 1234, + ), + pending_payable_opt: None, + }, + PayableAccount { + wallet: make_wallet("wallet1"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1, + last_paid_timestamp: from_time_t( + now - payment_thresholds.threshold_interval_sec - 1, + ), + pending_payable_opt: None, + }, + ]; + + let result = payables_debug_summary(qualified_payables, payment_thresholds_rc); + + assert_eq!(result, + "Paying qualified debts:\n\ + 10001000 owed for 2593234sec exceeds threshold: 9512428; creditor: 0x0000000000000000000000000077616c6c657430\n\ + 10000001 owed for 2592001sec exceeds threshold: 9999604; creditor: 0x0000000000000000000000000077616c6c657431" + ) + } +} From 889bda0a1fef8e800689291cfe8f18e349f1690e Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 22 Aug 2022 10:39:42 +0530 Subject: [PATCH 042/145] GH-611: Add a todo and comment out the test --- node/src/accountant/tools.rs | 82 ++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 98e675ee5..561c41a8d 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -194,4 +194,86 @@ mod tests { 10000001 owed for 2592001sec exceeds threshold: 9999604; creditor: 0x0000000000000000000000000077616c6c657431" ) } + + // TODO: Either make this test work or write an alternative test in the desired file + // #[test] + // fn threshold_calculation_depends_on_user_defined_payment_thresholds() { + // let safe_age_params_arc = Arc::new(Mutex::new(vec![])); + // let safe_balance_params_arc = Arc::new(Mutex::new(vec![])); + // let calculate_payable_threshold_params_arc = Arc::new(Mutex::new(vec![])); + // let balance = 5555; + // let how_far_in_past = Duration::from_secs(1111 + 1); + // let last_paid_timestamp = SystemTime::now().sub(how_far_in_past); + // let payable_account = PayableAccount { + // wallet: make_wallet("hi"), + // balance, + // last_paid_timestamp, + // pending_payable_opt: None, + // }; + // let custom_payment_thresholds = PaymentThresholds { + // maturity_threshold_sec: 1111, + // payment_grace_period_sec: 2222, + // permanent_debt_allowed_gwei: 3333, + // debt_threshold_gwei: 4444, + // threshold_interval_sec: 5555, + // unban_below_gwei: 3333, + // }; + // let mut bootstrapper_config = BootstrapperConfig::default(); + // bootstrapper_config.accountant_config_opt = Some(AccountantConfig { + // scan_intervals: Default::default(), + // payment_thresholds: custom_payment_thresholds, + // suppress_initial_scans: false, + // when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, + // }); + // let payable_thresholds_tools = PayableThresholdToolsMock::default() + // .is_innocent_age_params(&safe_age_params_arc) + // .is_innocent_age_result( + // how_far_in_past.as_secs() + // <= custom_payment_thresholds.maturity_threshold_sec as u64, + // ) + // .is_innocent_balance_params(&safe_balance_params_arc) + // .is_innocent_balance_result( + // balance <= custom_payment_thresholds.permanent_debt_allowed_gwei, + // ) + // .calculate_payout_threshold_params(&calculate_payable_threshold_params_arc) + // .calculate_payout_threshold_result(4567.0); //made up value + // let mut subject = AccountantBuilder::default() + // .bootstrapper_config(bootstrapper_config) + // .build(); + // subject.scanners.payables.payable_thresholds_tools = Box::new(payable_thresholds_tools); + // + // let result = subject.payable_exceeded_threshold(&payable_account); + // + // assert_eq!(result, Some(4567)); + // let mut safe_age_params = safe_age_params_arc.lock().unwrap(); + // let safe_age_single_params = safe_age_params.remove(0); + // assert_eq!(*safe_age_params, vec![]); + // let (time_elapsed, curve_derived_time) = safe_age_single_params; + // assert!( + // (how_far_in_past.as_secs() - 3) < time_elapsed + // && time_elapsed < (how_far_in_past.as_secs() + 3) + // ); + // assert_eq!( + // curve_derived_time, + // custom_payment_thresholds.maturity_threshold_sec as u64 + // ); + // let safe_balance_params = safe_balance_params_arc.lock().unwrap(); + // assert_eq!( + // *safe_balance_params, + // vec![( + // payable_account.balance, + // custom_payment_thresholds.permanent_debt_allowed_gwei + // )] + // ); + // let mut calculate_payable_curves_params = + // calculate_payable_threshold_params_arc.lock().unwrap(); + // let calculate_payable_curves_single_params = calculate_payable_curves_params.remove(0); + // assert_eq!(*calculate_payable_curves_params, vec![]); + // let (payment_thresholds, time_elapsed) = calculate_payable_curves_single_params; + // assert!( + // (how_far_in_past.as_secs() - 3) < time_elapsed + // && time_elapsed < (how_far_in_past.as_secs() + 3) + // ); + // assert_eq!(payment_thresholds, custom_payment_thresholds) + // } } From 05c5d0ee4cac45ecd3e73b4aae78c5e206a62476 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 22 Aug 2022 14:06:30 +0530 Subject: [PATCH 043/145] GH-611: refactor tools.rs --- node/src/accountant/tools.rs | 115 ++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 561c41a8d..b9e3e657a 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -61,76 +61,35 @@ pub(crate) fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccou } } -pub(crate) fn should_pay( - payable: &PayableAccount, - payment_thresholds: Rc, -) -> bool { - payable_exceeded_threshold(payable, payment_thresholds).is_some() -} - -fn payable_exceeded_threshold( - payable: &PayableAccount, +fn is_payable_qualified( + payable_balance: i64, + time_since_last_paid: u64, payment_thresholds: Rc, ) -> Option { // TODO: This calculation should be done in the database, if possible - let time_since_last_paid = SystemTime::now() - .duration_since(payable.last_paid_timestamp) - .expect("Internal error") - .as_secs(); + let maturity_time_limit = payment_thresholds.maturity_threshold_sec as u64; + let permanent_allowed_debt = payment_thresholds.permanent_debt_allowed_gwei; - if is_innocent_age( - time_since_last_paid, - payment_thresholds.maturity_threshold_sec as u64, - ) { + if time_since_last_paid <= maturity_time_limit { return None; } - if is_innocent_balance( - payable.balance, - payment_thresholds.permanent_debt_allowed_gwei, - ) { + if payable_balance <= permanent_allowed_debt { return None; } - let threshold = calculate_payout_threshold(time_since_last_paid, payment_thresholds); - if payable.balance as f64 > threshold { - Some(threshold as u64) - } else { - None + let payout_threshold = calculate_payout_threshold(time_since_last_paid, payment_thresholds); + if payable_balance as f64 <= payout_threshold { + return None; } -} -pub(crate) fn payables_debug_summary( - qualified_payables: &[PayableAccount], - payment_thresholds: Rc, -) -> String { - let now = SystemTime::now(); - let list = qualified_payables - .iter() - .map(|payable| { - let p_age = now - .duration_since(payable.last_paid_timestamp) - .expect("Payable time is corrupt"); - let threshold = payable_exceeded_threshold(payable, payment_thresholds.clone()) - .expect("Threshold suddenly changed!"); - format!( - "{} owed for {}sec exceeds threshold: {}; creditor: {}", - payable.balance, - p_age.as_secs(), - threshold, - payable.wallet - ) - }) - .join("\n"); - String::from("Paying qualified debts:\n").add(&list) + Some(threshold as u64) } -fn is_innocent_age(age: u64, limit: u64) -> bool { - age <= limit -} - -fn is_innocent_balance(balance: i64, limit: i64) -> bool { - balance <= limit +fn payable_time_diff(time: SystemTime, payable: &PayableAccount) -> u64 { + time.duration_since(payable.last_paid_timestamp) + .expect("Payable time is corrupt") + .as_secs() } fn calculate_payout_threshold(x: u64, payment_thresholds: Rc) -> f64 { @@ -143,10 +102,52 @@ fn calculate_payout_threshold(x: u64, payment_thresholds: Rc) m * x as f64 + b } +// TODO: Test Me +pub(crate) fn qualified_payables_and_summary( + non_pending_payables: Vec, + payment_thresholds: Rc, +) -> (Vec, String) { + let now = SystemTime::now(); + let qualified_summary = String::from("Paying qualified debts:\n"); + let qualified_payables = non_pending_payables + .into_iter() + .filter(|account| { + let time_since_last_paid = payable_time_diff(now, payable); + + match is_payable_qualified( + account.balance, + time_since_last_paid, + payment_thresholds.clone(), + ) { + Some(threshold) => { + qualified_summary.add( + "{} owed for {}sec exceeds threshold: {}; creditor: {}\n", + account.balance, + time_since_last_paid, + threshold, + account.wallet.clone(), + ); + true + } + None => false, + } + }) + .collect::>(); + + let summary = match qualified_payables.is_empty() { + true => String::from("No Qualified Payables found."), + false => qualified_summary, + }; + + (qualified_payables, summary) +} + #[cfg(test)] mod tests { use crate::accountant::payable_dao::PayableAccount; - use crate::accountant::tools::payables_debug_summary; + use crate::accountant::tools::{ + is_payable_qualified, payable_debug_summary, payables_debug_summary, + }; use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::sub_lib::accountant::PaymentThresholds; From 06112546a44e022f82f93ba4fd7a02fe47a9d073 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 25 Aug 2022 14:05:45 +0530 Subject: [PATCH 044/145] GH-611: fix qualified_payables_and_summary() --- node/src/accountant/scanners.rs | 18 ++-- node/src/accountant/tools.rs | 142 +++++++++++++++++++------------- 2 files changed, 92 insertions(+), 68 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 6c40c64fe..5c2c94e11 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -4,7 +4,7 @@ pub(in crate::accountant) mod scanners { use crate::accountant::payable_dao::{PayableAccount, PayableDao, PayableDaoReal}; use crate::accountant::pending_payable_dao::PendingPayableDao; use crate::accountant::receivable_dao::ReceivableDao; - use crate::accountant::tools::{investigate_debt_extremes, payables_debug_summary, should_pay}; + use crate::accountant::tools::{investigate_debt_extremes, qualified_payables_and_summary}; use crate::accountant::ReportAccountsPayable; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, @@ -117,22 +117,18 @@ pub(in crate::accountant) mod scanners { "{}", investigate_debt_extremes(&all_non_pending_payables) ); - let qualified_payables = all_non_pending_payables - .into_iter() - .filter(|account| should_pay(account, self.common.payment_thresholds.clone())) - .collect::>(); + let (qualified_payables, summary) = qualified_payables_and_summary( + all_non_pending_payables, + self.common.payment_thresholds.clone(), + ); info!( logger, "Chose {} qualified debts to pay", qualified_payables.len() ); - debug!( - logger, - "{}", - payables_debug_summary(&qualified_payables, self.common.payment_thresholds.clone()) - ); + debug!(logger, "{}", summary); match qualified_payables.is_empty() { - true => Err(String::from("No Qualified Payables found.")), + true => Err(summary), false => Ok(ReportAccountsPayable { accounts: qualified_payables, response_skeleton_opt, diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index b9e3e657a..4cbf41ef4 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -2,9 +2,11 @@ use crate::accountant::payable_dao::PayableAccount; use crate::accountant::scanners::scanners::PayableScanner; use crate::sub_lib::accountant::PaymentThresholds; use itertools::Itertools; +use std::cell::RefCell; use std::ops::Add; use std::rc::Rc; use std::time::{Duration, SystemTime}; +use trust_dns::client::ClientHandle; //for debugging only pub(crate) fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccount]) -> String { @@ -62,28 +64,33 @@ pub(crate) fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccou } fn is_payable_qualified( - payable_balance: i64, - time_since_last_paid: u64, + time: SystemTime, + payable: &PayableAccount, payment_thresholds: Rc, ) -> Option { // TODO: This calculation should be done in the database, if possible let maturity_time_limit = payment_thresholds.maturity_threshold_sec as u64; let permanent_allowed_debt = payment_thresholds.permanent_debt_allowed_gwei; + let time_since_last_paid = payable_time_diff(time, payable); + let payable_balance = payable.balance; if time_since_last_paid <= maturity_time_limit { + todo!("test maturity_time_limit"); return None; } if payable_balance <= permanent_allowed_debt { + todo!("test permanent_allowed_debt"); return None; } let payout_threshold = calculate_payout_threshold(time_since_last_paid, payment_thresholds); if payable_balance as f64 <= payout_threshold { + todo!("test payout_threshold"); return None; } - Some(threshold as u64) + Some(payout_threshold as u64) } fn payable_time_diff(time: SystemTime, payable: &PayableAccount) -> u64 { @@ -102,37 +109,32 @@ fn calculate_payout_threshold(x: u64, payment_thresholds: Rc) m * x as f64 + b } +fn exceeded_summary(time: SystemTime, payable: &PayableAccount, threshold: u64) -> String { + format!( + "{} owed for {}sec exceeds threshold: {}; creditor: {}\n", + payable.balance, + payable_time_diff(time, payable), + threshold, + payable.wallet.clone(), + ) +} + // TODO: Test Me pub(crate) fn qualified_payables_and_summary( non_pending_payables: Vec, payment_thresholds: Rc, ) -> (Vec, String) { let now = SystemTime::now(); - let qualified_summary = String::from("Paying qualified debts:\n"); - let qualified_payables = non_pending_payables - .into_iter() - .filter(|account| { - let time_since_last_paid = payable_time_diff(now, payable); + let mut qualified_summary = String::from("Paying qualified debts:\n"); + let mut qualified_payables: Vec = vec![]; - match is_payable_qualified( - account.balance, - time_since_last_paid, - payment_thresholds.clone(), - ) { - Some(threshold) => { - qualified_summary.add( - "{} owed for {}sec exceeds threshold: {}; creditor: {}\n", - account.balance, - time_since_last_paid, - threshold, - account.wallet.clone(), - ); - true - } - None => false, - } - }) - .collect::>(); + for payable in non_pending_payables { + if let Some(threshold) = is_payable_qualified(now, &payable, payment_thresholds.clone()) { + let payable_summary = exceeded_summary(now, &payable, threshold); + qualified_summary.push_str(&payable_summary); + qualified_payables.push(payable); + } + } let summary = match qualified_payables.is_empty() { true => String::from("No Qualified Payables found."), @@ -145,9 +147,7 @@ pub(crate) fn qualified_payables_and_summary( #[cfg(test)] mod tests { use crate::accountant::payable_dao::PayableAccount; - use crate::accountant::tools::{ - is_payable_qualified, payable_debug_summary, payables_debug_summary, - }; + use crate::accountant::tools::is_payable_qualified; use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::sub_lib::accountant::PaymentThresholds; @@ -156,9 +156,49 @@ mod tests { use std::rc::Rc; use std::time::SystemTime; + // #[test] + // fn payables_debug_summary_prints_pretty_summary() { + // let now = to_time_t(SystemTime::now()); + // let payment_thresholds = PaymentThresholds { + // threshold_interval_sec: 2_592_000, + // debt_threshold_gwei: 1_000_000_000, + // payment_grace_period_sec: 86_400, + // maturity_threshold_sec: 86_400, + // permanent_debt_allowed_gwei: 10_000_000, + // unban_below_gwei: 10_000_000, + // }; + // let payment_thresholds_rc = Rc::new(payment_thresholds.clone()); + // let qualified_payables = &[ + // PayableAccount { + // wallet: make_wallet("wallet0"), + // balance: payment_thresholds.permanent_debt_allowed_gwei + 1000, + // last_paid_timestamp: from_time_t( + // now - payment_thresholds.threshold_interval_sec - 1234, + // ), + // pending_payable_opt: None, + // }, + // PayableAccount { + // wallet: make_wallet("wallet1"), + // balance: payment_thresholds.permanent_debt_allowed_gwei + 1, + // last_paid_timestamp: from_time_t( + // now - payment_thresholds.threshold_interval_sec - 1, + // ), + // pending_payable_opt: None, + // }, + // ]; + // + // let result = payables_debug_summary(qualified_payables, payment_thresholds_rc); + // + // assert_eq!(result, + // "Paying qualified debts:\n\ + // 10001000 owed for 2593234sec exceeds threshold: 9512428; creditor: 0x0000000000000000000000000077616c6c657430\n\ + // 10000001 owed for 2592001sec exceeds threshold: 9999604; creditor: 0x0000000000000000000000000077616c6c657431" + // ) + // } + #[test] - fn payables_debug_summary_prints_pretty_summary() { - let now = to_time_t(SystemTime::now()); + fn payable_generated_before_maturity_time_limit_is_marked_unqualified() { + let now = SystemTime::now(); let payment_thresholds = PaymentThresholds { threshold_interval_sec: 2_592_000, debt_threshold_gwei: 1_000_000_000, @@ -167,33 +207,21 @@ mod tests { permanent_debt_allowed_gwei: 10_000_000, unban_below_gwei: 10_000_000, }; - let payment_thresholds_rc = Rc::new(payment_thresholds.clone()); - let qualified_payables = &[ - PayableAccount { - wallet: make_wallet("wallet0"), - balance: payment_thresholds.permanent_debt_allowed_gwei + 1000, - last_paid_timestamp: from_time_t( - now - payment_thresholds.threshold_interval_sec - 1234, - ), - pending_payable_opt: None, - }, - PayableAccount { - wallet: make_wallet("wallet1"), - balance: payment_thresholds.permanent_debt_allowed_gwei + 1, - last_paid_timestamp: from_time_t( - now - payment_thresholds.threshold_interval_sec - 1, - ), - pending_payable_opt: None, - }, - ]; + let unqualified_time = (to_time_t(now) - payment_thresholds.threshold_interval_sec) + 100; + let unqualified_payable_account = PayableAccount { + wallet: make_wallet("wallet0"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1000, + last_paid_timestamp: from_time_t(unqualified_time), + pending_payable_opt: None, + }; - let result = payables_debug_summary(qualified_payables, payment_thresholds_rc); + let result = is_payable_qualified( + now, + &unqualified_payable_account, + Rc::new(payment_thresholds), + ); - assert_eq!(result, - "Paying qualified debts:\n\ - 10001000 owed for 2593234sec exceeds threshold: 9512428; creditor: 0x0000000000000000000000000077616c6c657430\n\ - 10000001 owed for 2592001sec exceeds threshold: 9999604; creditor: 0x0000000000000000000000000077616c6c657431" - ) + assert_eq!(result, None); } // TODO: Either make this test work or write an alternative test in the desired file From 5ea8a610b0a2714b4b2666da5a0ae226c0bc229c Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 25 Aug 2022 15:59:44 +0530 Subject: [PATCH 045/145] GH-611: test drive the checks for whether a payable is qualified --- node/src/accountant/tools.rs | 220 ++++++++++++++++++++++++++--------- 1 file changed, 167 insertions(+), 53 deletions(-) diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 4cbf41ef4..2ddefe510 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -75,18 +75,15 @@ fn is_payable_qualified( let payable_balance = payable.balance; if time_since_last_paid <= maturity_time_limit { - todo!("test maturity_time_limit"); return None; } if payable_balance <= permanent_allowed_debt { - todo!("test permanent_allowed_debt"); return None; } let payout_threshold = calculate_payout_threshold(time_since_last_paid, payment_thresholds); if payable_balance as f64 <= payout_threshold { - todo!("test payout_threshold"); return None; } @@ -119,7 +116,6 @@ fn exceeded_summary(time: SystemTime, payable: &PayableAccount, threshold: u64) ) } -// TODO: Test Me pub(crate) fn qualified_payables_and_summary( non_pending_payables: Vec, payment_thresholds: Rc, @@ -147,70 +143,40 @@ pub(crate) fn qualified_payables_and_summary( #[cfg(test)] mod tests { use crate::accountant::payable_dao::PayableAccount; - use crate::accountant::tools::is_payable_qualified; + use crate::accountant::tools::{ + calculate_payout_threshold, exceeded_summary, is_payable_qualified, payable_time_diff, + qualified_payables_and_summary, + }; use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::sub_lib::accountant::PaymentThresholds; use crate::test_utils::make_wallet; - use crate::test_utils::unshared_test_utils::make_populated_accountant_config_with_defaults; + use crate::test_utils::unshared_test_utils::{ + make_payment_thresholds_with_defaults, make_populated_accountant_config_with_defaults, + }; use std::rc::Rc; use std::time::SystemTime; - // #[test] - // fn payables_debug_summary_prints_pretty_summary() { - // let now = to_time_t(SystemTime::now()); - // let payment_thresholds = PaymentThresholds { - // threshold_interval_sec: 2_592_000, - // debt_threshold_gwei: 1_000_000_000, - // payment_grace_period_sec: 86_400, - // maturity_threshold_sec: 86_400, - // permanent_debt_allowed_gwei: 10_000_000, - // unban_below_gwei: 10_000_000, - // }; - // let payment_thresholds_rc = Rc::new(payment_thresholds.clone()); - // let qualified_payables = &[ - // PayableAccount { - // wallet: make_wallet("wallet0"), - // balance: payment_thresholds.permanent_debt_allowed_gwei + 1000, - // last_paid_timestamp: from_time_t( - // now - payment_thresholds.threshold_interval_sec - 1234, - // ), - // pending_payable_opt: None, - // }, - // PayableAccount { - // wallet: make_wallet("wallet1"), - // balance: payment_thresholds.permanent_debt_allowed_gwei + 1, - // last_paid_timestamp: from_time_t( - // now - payment_thresholds.threshold_interval_sec - 1, - // ), - // pending_payable_opt: None, - // }, - // ]; - // - // let result = payables_debug_summary(qualified_payables, payment_thresholds_rc); - // - // assert_eq!(result, - // "Paying qualified debts:\n\ - // 10001000 owed for 2593234sec exceeds threshold: 9512428; creditor: 0x0000000000000000000000000077616c6c657430\n\ - // 10000001 owed for 2592001sec exceeds threshold: 9999604; creditor: 0x0000000000000000000000000077616c6c657431" - // ) - // } - - #[test] - fn payable_generated_before_maturity_time_limit_is_marked_unqualified() { - let now = SystemTime::now(); - let payment_thresholds = PaymentThresholds { + fn make_custom_payment_thresholds() -> PaymentThresholds { + PaymentThresholds { threshold_interval_sec: 2_592_000, debt_threshold_gwei: 1_000_000_000, payment_grace_period_sec: 86_400, maturity_threshold_sec: 86_400, permanent_debt_allowed_gwei: 10_000_000, unban_below_gwei: 10_000_000, - }; - let unqualified_time = (to_time_t(now) - payment_thresholds.threshold_interval_sec) + 100; + } + } + + #[test] + fn payable_generated_before_maturity_time_limit_is_marked_unqualified() { + let now = SystemTime::now(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let qualified_debt = payment_thresholds.permanent_debt_allowed_gwei + 1; + let unqualified_time = to_time_t(now) - payment_thresholds.maturity_threshold_sec + 1; let unqualified_payable_account = PayableAccount { wallet: make_wallet("wallet0"), - balance: payment_thresholds.permanent_debt_allowed_gwei + 1000, + balance: qualified_debt, last_paid_timestamp: from_time_t(unqualified_time), pending_payable_opt: None, }; @@ -224,6 +190,154 @@ mod tests { assert_eq!(result, None); } + #[test] + fn payable_with_low_debt_is_marked_unqualified() { + let now = SystemTime::now(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let unqualified_debt = payment_thresholds.permanent_debt_allowed_gwei - 1; + let qualified_time = to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1; + let unqualified_payable_account = PayableAccount { + wallet: make_wallet("wallet0"), + balance: unqualified_debt, + last_paid_timestamp: from_time_t(qualified_time), + pending_payable_opt: None, + }; + + let result = is_payable_qualified( + now, + &unqualified_payable_account, + Rc::new(payment_thresholds), + ); + + assert_eq!(result, None); + } + + #[test] + fn payable_with_low_payout_threshold_is_marked_unqualified() { + let now = SystemTime::now(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let debt = payment_thresholds.permanent_debt_allowed_gwei + 1; + let time = to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1; + let unqualified_payable_account = PayableAccount { + wallet: make_wallet("wallet0"), + balance: debt, + last_paid_timestamp: from_time_t(time), + pending_payable_opt: None, + }; + + let result = is_payable_qualified( + now, + &unqualified_payable_account, + Rc::new(payment_thresholds), + ); + + assert_eq!(result, None); + } + + #[test] + fn payable_above_threshold_values_is_marked_qualified_and_returns_threshold() { + let now = SystemTime::now(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let debt = payment_thresholds.permanent_debt_allowed_gwei + 1_000_000_000; + let time = to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1; + let payment_thresholds_rc = Rc::new(payment_thresholds); + let qualified_payable = PayableAccount { + wallet: make_wallet("wallet0"), + balance: debt, + last_paid_timestamp: from_time_t(time), + pending_payable_opt: None, + }; + let threshold = calculate_payout_threshold( + payable_time_diff(now, &qualified_payable), + Rc::clone(&payment_thresholds_rc), + ); + eprintln!("Threshold: {}, Debt: {}", threshold, debt); + + let result = + is_payable_qualified(now, &qualified_payable, Rc::clone(&payment_thresholds_rc)); + + assert_eq!(result, Some(threshold as u64)); + } + + #[test] + fn qualified_payables_can_be_filtered_out_from_non_pending_payables_along_with_their_summary() { + let now = SystemTime::now(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let mut unqualified_payable_accounts = vec![PayableAccount { + wallet: make_wallet("wallet1"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec + 1, + ), + pending_payable_opt: None, + }]; + let mut qualified_payable_accounts = vec![ + PayableAccount { + wallet: make_wallet("wallet2"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1_000_000_000, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1, + ), + pending_payable_opt: None, + }, + PayableAccount { + wallet: make_wallet("wallet3"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1_200_000_000, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec - 100, + ), + pending_payable_opt: None, + }, + ]; + let payment_thresholds_rc = Rc::new(payment_thresholds); + let mut all_non_pending_payables = Vec::new(); + all_non_pending_payables.extend(qualified_payable_accounts.clone()); + all_non_pending_payables.extend(unqualified_payable_accounts.clone()); + + let (qualified_payables, summary) = qualified_payables_and_summary( + all_non_pending_payables, + Rc::clone(&payment_thresholds_rc), + ); + + let mut expected_summary = String::from("Paying qualified debts:\n"); + for payable in qualified_payable_accounts.iter() { + expected_summary.push_str(&exceeded_summary( + now, + &payable, + calculate_payout_threshold( + payable_time_diff(now, &payable), + payment_thresholds_rc.clone(), + ) as u64, + )) + } + + assert_eq!(qualified_payables, qualified_payable_accounts); + assert_eq!(summary, expected_summary); + } + + #[test] + fn returns_empty_array_and_summary_when_no_qualified_payables_are_found() { + let now = SystemTime::now(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let mut unqualified_payable_accounts = vec![PayableAccount { + wallet: make_wallet("wallet1"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec + 1, + ), + pending_payable_opt: None, + }]; + let payment_thresholds_rc = Rc::new(payment_thresholds); + + let (qualified_payables, summary) = qualified_payables_and_summary( + unqualified_payable_accounts, + Rc::clone(&payment_thresholds_rc), + ); + + assert_eq!(qualified_payables, vec![]); + assert_eq!(summary, String::from("No Qualified Payables found.")); + } + // TODO: Either make this test work or write an alternative test in the desired file // #[test] // fn threshold_calculation_depends_on_user_defined_payment_thresholds() { From dfbfd11f669deb8e19ee47e1ff6fd93320e00b47 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 25 Aug 2022 23:34:29 +0530 Subject: [PATCH 046/145] GH-611: migrate test for testing debt extremes inside tools.rs --- node/src/accountant/mod.rs | 41 ---------------------------------- node/src/accountant/tools.rs | 43 ++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 27a3ed4d0..6c7a4b1af 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -3881,47 +3881,6 @@ mod tests { prove_that_crash_request_handler_is_hooked_up(accountant, CRASH_KEY); } - #[test] - // TODO: Migrate this test to Scanners - // fn investigate_debt_extremes_picks_the_most_relevant_records() { - // let now = to_time_t(SystemTime::now()); - // let same_amount_significance = 2_000_000; - // let same_age_significance = from_time_t(now - 30000); - // let payables = &[ - // PayableAccount { - // wallet: make_wallet("wallet0"), - // balance: same_amount_significance, - // last_paid_timestamp: from_time_t(now - 5000), - // pending_payable_opt: None, - // }, - // //this debt is more significant because beside being high in amount it's also older, so should be prioritized and picked - // PayableAccount { - // wallet: make_wallet("wallet1"), - // balance: same_amount_significance, - // last_paid_timestamp: from_time_t(now - 10000), - // pending_payable_opt: None, - // }, - // //similarly these two wallets have debts equally old but the second has a bigger balance and should be chosen - // PayableAccount { - // wallet: make_wallet("wallet3"), - // balance: 100, - // last_paid_timestamp: same_age_significance, - // pending_payable_opt: None, - // }, - // PayableAccount { - // wallet: make_wallet("wallet2"), - // balance: 330, - // last_paid_timestamp: same_age_significance, - // pending_payable_opt: None, - // }, - // ]; - // - // let result = Accountant::investigate_debt_extremes(payables); - // - // assert_eq!(result, "Payable scan found 4 debts; the biggest is 2000000 owed for 10000sec, the oldest is 330 owed for 30000sec") - // } - - // TODO: This test should be migrated to scanners #[test] fn pending_transaction_is_registered_and_monitored_until_it_gets_confirmed_or_canceled() { init_test_logging(); diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 2ddefe510..1f4254787 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -144,8 +144,8 @@ pub(crate) fn qualified_payables_and_summary( mod tests { use crate::accountant::payable_dao::PayableAccount; use crate::accountant::tools::{ - calculate_payout_threshold, exceeded_summary, is_payable_qualified, payable_time_diff, - qualified_payables_and_summary, + calculate_payout_threshold, exceeded_summary, investigate_debt_extremes, + is_payable_qualified, payable_time_diff, qualified_payables_and_summary, }; use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; @@ -338,6 +338,45 @@ mod tests { assert_eq!(summary, String::from("No Qualified Payables found.")); } + #[test] + fn investigate_debt_extremes_picks_the_most_relevant_records() { + let now = to_time_t(SystemTime::now()); + let same_amount_significance = 2_000_000; + let same_age_significance = from_time_t(now - 30000); + let payables = &[ + PayableAccount { + wallet: make_wallet("wallet0"), + balance: same_amount_significance, + last_paid_timestamp: from_time_t(now - 5000), + pending_payable_opt: None, + }, + //this debt is more significant because beside being high in amount it's also older, so should be prioritized and picked + PayableAccount { + wallet: make_wallet("wallet1"), + balance: same_amount_significance, + last_paid_timestamp: from_time_t(now - 10000), + pending_payable_opt: None, + }, + //similarly these two wallets have debts equally old but the second has a bigger balance and should be chosen + PayableAccount { + wallet: make_wallet("wallet3"), + balance: 100, + last_paid_timestamp: same_age_significance, + pending_payable_opt: None, + }, + PayableAccount { + wallet: make_wallet("wallet2"), + balance: 330, + last_paid_timestamp: same_age_significance, + pending_payable_opt: None, + }, + ]; + + let result = investigate_debt_extremes(payables); + + assert_eq!(result, "Payable scan found 4 debts; the biggest is 2000000 owed for 10000sec, the oldest is 330 owed for 30000sec") + } + // TODO: Either make this test work or write an alternative test in the desired file // #[test] // fn threshold_calculation_depends_on_user_defined_payment_thresholds() { From f811931e677bf6048de1da5f4ec34b042a9df931 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 26 Aug 2022 00:32:33 +0530 Subject: [PATCH 047/145] GH-611: refactor the investigate_debt_extremes() --- node/src/accountant/tools.rs | 96 +++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 1f4254787..47b213daa 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -1,5 +1,6 @@ use crate::accountant::payable_dao::PayableAccount; use crate::accountant::scanners::scanners::PayableScanner; +use crate::database::dao_utils::from_time_t; use crate::sub_lib::accountant::PaymentThresholds; use itertools::Itertools; use std::cell::RefCell; @@ -11,56 +12,59 @@ use trust_dns::client::ClientHandle; //for debugging only pub(crate) fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccount]) -> String { if all_non_pending_payables.is_empty() { - "Payable scan found no debts".to_string() - } else { - struct PayableInfo { - balance: i64, - age: Duration, + return "Payable scan found no debts".to_string(); + } + #[derive(Clone, Copy, Default)] + struct PayableInfo { + balance: i64, + age: u64, + } + + fn bigger(payable_1: PayableInfo, payable_2: PayableInfo) -> PayableInfo { + if payable_1.balance > payable_2.balance { + payable_1 + } else if payable_2.balance > payable_1.balance { + payable_2 + } else { + if payable_1.age != payable_2.age { + return older(payable_1, payable_2); + } + payable_1 } - let now = SystemTime::now(); - let init = ( - PayableInfo { - balance: 0, - age: Duration::ZERO, - }, - PayableInfo { - balance: 0, - age: Duration::ZERO, - }, - ); - let (biggest, oldest) = all_non_pending_payables.iter().fold(init, |sofar, p| { - let (mut biggest, mut oldest) = sofar; - let p_age = now - .duration_since(p.last_paid_timestamp) - .expect("Payable time is corrupt"); - { - //look at a test if not understandable - let check_age_parameter_if_the_first_is_the_same = - || -> bool { p.balance == biggest.balance && p_age > biggest.age }; - - if p.balance > biggest.balance || check_age_parameter_if_the_first_is_the_same() { - biggest = PayableInfo { - balance: p.balance, - age: p_age, - } - } - - let check_balance_parameter_if_the_first_is_the_same = - || -> bool { p_age == oldest.age && p.balance > oldest.balance }; - - if p_age > oldest.age || check_balance_parameter_if_the_first_is_the_same() { - oldest = PayableInfo { - balance: p.balance, - age: p_age, - } - } + } + + fn older(payable_1: PayableInfo, payable_2: PayableInfo) -> PayableInfo { + if payable_1.age > payable_2.age { + payable_1 + } else if payable_2.age > payable_1.age { + payable_2 + } else { + if payable_1.balance != payable_2.balance { + return bigger(payable_1, payable_2); } + payable_1 + } + } + + let now = SystemTime::now(); + let init = (PayableInfo::default(), PayableInfo::default()); + let (biggest, oldest) = all_non_pending_payables + .iter() + .map(|payable| PayableInfo { + balance: payable.balance, + age: payable_time_diff(now, payable), + }) + .fold(init, |so_far, payable| { + let (mut biggest, mut oldest) = so_far; + + biggest = bigger(biggest, payable); + oldest = older(oldest, payable); + (biggest, oldest) }); - format!("Payable scan found {} debts; the biggest is {} owed for {}sec, the oldest is {} owed for {}sec", - all_non_pending_payables.len(), biggest.balance, biggest.age.as_secs(), - oldest.balance, oldest.age.as_secs()) - } + format!("Payable scan found {} debts; the biggest is {} owed for {}sec, the oldest is {} owed for {}sec", + all_non_pending_payables.len(), biggest.balance, biggest.age, + oldest.balance, oldest.age) } fn is_payable_qualified( From 6c51328652eee2253d296c6372e4dd93cc935c0e Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 26 Aug 2022 12:28:03 +0530 Subject: [PATCH 048/145] GH-611: migrate tools for payable_scanner inside a different module --- node/src/accountant/scanners.rs | 4 +- node/src/accountant/tools.rs | 256 ++++++++++++++++---------------- 2 files changed, 134 insertions(+), 126 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 5c2c94e11..da1d6acec 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -4,7 +4,9 @@ pub(in crate::accountant) mod scanners { use crate::accountant::payable_dao::{PayableAccount, PayableDao, PayableDaoReal}; use crate::accountant::pending_payable_dao::PendingPayableDao; use crate::accountant::receivable_dao::ReceivableDao; - use crate::accountant::tools::{investigate_debt_extremes, qualified_payables_and_summary}; + use crate::accountant::tools::payable_scanner_tools::{ + investigate_debt_extremes, qualified_payables_and_summary, + }; use crate::accountant::ReportAccountsPayable; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 47b213daa..a4e7afda6 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -1,153 +1,159 @@ -use crate::accountant::payable_dao::PayableAccount; -use crate::accountant::scanners::scanners::PayableScanner; -use crate::database::dao_utils::from_time_t; -use crate::sub_lib::accountant::PaymentThresholds; -use itertools::Itertools; -use std::cell::RefCell; -use std::ops::Add; -use std::rc::Rc; -use std::time::{Duration, SystemTime}; -use trust_dns::client::ClientHandle; - -//for debugging only -pub(crate) fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccount]) -> String { - if all_non_pending_payables.is_empty() { - return "Payable scan found no debts".to_string(); - } - #[derive(Clone, Copy, Default)] - struct PayableInfo { - balance: i64, - age: u64, - } +// Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. + +pub(crate) mod payable_scanner_tools { + use crate::accountant::payable_dao::PayableAccount; + use crate::sub_lib::accountant::PaymentThresholds; + use std::rc::Rc; + use std::time::SystemTime; + + //for debugging only + pub(crate) fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccount]) -> String { + if all_non_pending_payables.is_empty() { + return "Payable scan found no debts".to_string(); + } + #[derive(Clone, Copy, Default)] + struct PayableInfo { + balance: i64, + age: u64, + } - fn bigger(payable_1: PayableInfo, payable_2: PayableInfo) -> PayableInfo { - if payable_1.balance > payable_2.balance { - payable_1 - } else if payable_2.balance > payable_1.balance { - payable_2 - } else { - if payable_1.age != payable_2.age { - return older(payable_1, payable_2); + fn bigger(payable_1: PayableInfo, payable_2: PayableInfo) -> PayableInfo { + if payable_1.balance > payable_2.balance { + payable_1 + } else if payable_2.balance > payable_1.balance { + payable_2 + } else { + if payable_1.age != payable_2.age { + return older(payable_1, payable_2); + } + payable_1 } - payable_1 } - } - fn older(payable_1: PayableInfo, payable_2: PayableInfo) -> PayableInfo { - if payable_1.age > payable_2.age { - payable_1 - } else if payable_2.age > payable_1.age { - payable_2 - } else { - if payable_1.balance != payable_2.balance { - return bigger(payable_1, payable_2); + fn older(payable_1: PayableInfo, payable_2: PayableInfo) -> PayableInfo { + if payable_1.age > payable_2.age { + payable_1 + } else if payable_2.age > payable_1.age { + payable_2 + } else { + if payable_1.balance != payable_2.balance { + return bigger(payable_1, payable_2); + } + payable_1 } - payable_1 } - } - let now = SystemTime::now(); - let init = (PayableInfo::default(), PayableInfo::default()); - let (biggest, oldest) = all_non_pending_payables - .iter() - .map(|payable| PayableInfo { - balance: payable.balance, - age: payable_time_diff(now, payable), - }) - .fold(init, |so_far, payable| { - let (mut biggest, mut oldest) = so_far; - - biggest = bigger(biggest, payable); - oldest = older(oldest, payable); - - (biggest, oldest) - }); - format!("Payable scan found {} debts; the biggest is {} owed for {}sec, the oldest is {} owed for {}sec", + let now = SystemTime::now(); + let init = (PayableInfo::default(), PayableInfo::default()); + let (biggest, oldest) = all_non_pending_payables + .iter() + .map(|payable| PayableInfo { + balance: payable.balance, + age: payable_time_diff(now, payable), + }) + .fold(init, |so_far, payable| { + let (mut biggest, mut oldest) = so_far; + + biggest = bigger(biggest, payable); + oldest = older(oldest, payable); + + (biggest, oldest) + }); + format!("Payable scan found {} debts; the biggest is {} owed for {}sec, the oldest is {} owed for {}sec", all_non_pending_payables.len(), biggest.balance, biggest.age, oldest.balance, oldest.age) -} - -fn is_payable_qualified( - time: SystemTime, - payable: &PayableAccount, - payment_thresholds: Rc, -) -> Option { - // TODO: This calculation should be done in the database, if possible - let maturity_time_limit = payment_thresholds.maturity_threshold_sec as u64; - let permanent_allowed_debt = payment_thresholds.permanent_debt_allowed_gwei; - let time_since_last_paid = payable_time_diff(time, payable); - let payable_balance = payable.balance; - - if time_since_last_paid <= maturity_time_limit { - return None; } - if payable_balance <= permanent_allowed_debt { - return None; - } + pub(crate) fn is_payable_qualified( + time: SystemTime, + payable: &PayableAccount, + payment_thresholds: Rc, + ) -> Option { + // TODO: This calculation should be done in the database, if possible + let maturity_time_limit = payment_thresholds.maturity_threshold_sec as u64; + let permanent_allowed_debt = payment_thresholds.permanent_debt_allowed_gwei; + let time_since_last_paid = payable_time_diff(time, payable); + let payable_balance = payable.balance; + + if time_since_last_paid <= maturity_time_limit { + return None; + } - let payout_threshold = calculate_payout_threshold(time_since_last_paid, payment_thresholds); - if payable_balance as f64 <= payout_threshold { - return None; - } + if payable_balance <= permanent_allowed_debt { + return None; + } - Some(payout_threshold as u64) -} + let payout_threshold = calculate_payout_threshold(time_since_last_paid, payment_thresholds); + if payable_balance as f64 <= payout_threshold { + return None; + } -fn payable_time_diff(time: SystemTime, payable: &PayableAccount) -> u64 { - time.duration_since(payable.last_paid_timestamp) - .expect("Payable time is corrupt") - .as_secs() -} + Some(payout_threshold as u64) + } -fn calculate_payout_threshold(x: u64, payment_thresholds: Rc) -> f64 { - let m = -((payment_thresholds.debt_threshold_gwei as f64 - - payment_thresholds.permanent_debt_allowed_gwei as f64) - / (payment_thresholds.threshold_interval_sec as f64 - - payment_thresholds.maturity_threshold_sec as f64)); - let b = payment_thresholds.debt_threshold_gwei as f64 - - m * payment_thresholds.maturity_threshold_sec as f64; - m * x as f64 + b -} + pub(crate) fn payable_time_diff(time: SystemTime, payable: &PayableAccount) -> u64 { + time.duration_since(payable.last_paid_timestamp) + .expect("Payable time is corrupt") + .as_secs() + } -fn exceeded_summary(time: SystemTime, payable: &PayableAccount, threshold: u64) -> String { - format!( - "{} owed for {}sec exceeds threshold: {}; creditor: {}\n", - payable.balance, - payable_time_diff(time, payable), - threshold, - payable.wallet.clone(), - ) -} + pub(crate) fn calculate_payout_threshold( + x: u64, + payment_thresholds: Rc, + ) -> f64 { + let m = -((payment_thresholds.debt_threshold_gwei as f64 + - payment_thresholds.permanent_debt_allowed_gwei as f64) + / (payment_thresholds.threshold_interval_sec as f64 + - payment_thresholds.maturity_threshold_sec as f64)); + let b = payment_thresholds.debt_threshold_gwei as f64 + - m * payment_thresholds.maturity_threshold_sec as f64; + m * x as f64 + b + } -pub(crate) fn qualified_payables_and_summary( - non_pending_payables: Vec, - payment_thresholds: Rc, -) -> (Vec, String) { - let now = SystemTime::now(); - let mut qualified_summary = String::from("Paying qualified debts:\n"); - let mut qualified_payables: Vec = vec![]; - - for payable in non_pending_payables { - if let Some(threshold) = is_payable_qualified(now, &payable, payment_thresholds.clone()) { - let payable_summary = exceeded_summary(now, &payable, threshold); - qualified_summary.push_str(&payable_summary); - qualified_payables.push(payable); - } + pub(crate) fn exceeded_summary( + time: SystemTime, + payable: &PayableAccount, + threshold: u64, + ) -> String { + format!( + "{} owed for {}sec exceeds threshold: {}; creditor: {}\n", + payable.balance, + payable_time_diff(time, payable), + threshold, + payable.wallet.clone(), + ) } - let summary = match qualified_payables.is_empty() { - true => String::from("No Qualified Payables found."), - false => qualified_summary, - }; + pub(crate) fn qualified_payables_and_summary( + non_pending_payables: Vec, + payment_thresholds: Rc, + ) -> (Vec, String) { + let now = SystemTime::now(); + let mut qualified_summary = String::from("Paying qualified debts:\n"); + let mut qualified_payables: Vec = vec![]; + + for payable in non_pending_payables { + if let Some(threshold) = is_payable_qualified(now, &payable, payment_thresholds.clone()) + { + let payable_summary = exceeded_summary(now, &payable, threshold); + qualified_summary.push_str(&payable_summary); + qualified_payables.push(payable); + } + } + + let summary = match qualified_payables.is_empty() { + true => String::from("No Qualified Payables found."), + false => qualified_summary, + }; - (qualified_payables, summary) + (qualified_payables, summary) + } } #[cfg(test)] mod tests { use crate::accountant::payable_dao::PayableAccount; - use crate::accountant::tools::{ + use crate::accountant::tools::payable_scanner_tools::{ calculate_payout_threshold, exceeded_summary, investigate_debt_extremes, is_payable_qualified, payable_time_diff, qualified_payables_and_summary, }; From c31e28adf2783dcd08c6e11799d64ca2fad2c5d0 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 26 Aug 2022 13:34:47 +0530 Subject: [PATCH 049/145] GH-611: add test for payable_scanner for initiating a scan --- node/src/accountant/scanners.rs | 106 +++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 3 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index da1d6acec..eff61d0bb 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -105,14 +105,12 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { - todo!("Implement PayableScanner"); // common::start_scan_at(&mut self.common, timestamp); // let start_message = BeginScanAMessage {}; // // Use the DAO, if necessary, to populate start_message // Ok(start_message) info!(logger, "Scanning for payables"); - self.common.initiated_at_opt = Some(timestamp); let all_non_pending_payables = self.dao.non_pending_payables(); debug!( logger, @@ -355,7 +353,7 @@ mod tests { use super::*; use crate::accountant::payable_dao::{PayableAccount, PayableDaoReal}; use crate::accountant::scanners::scanners::{ - PayableScanner, PendingPayableScanner, ReceivableScanner, Scanners, + PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, Scanners, }; use crate::accountant::test_utils::{ AccountantBuilder, PayableDaoMock, PendingPayableDaoMock, ReceivableDaoMock, @@ -363,10 +361,13 @@ mod tests { use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::sub_lib::accountant::PaymentThresholds; + use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::{ make_payment_thresholds_with_defaults, make_populated_accountant_config_with_defaults, }; + use masq_lib::logger::Logger; + use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; use std::rc::Rc; use std::time::SystemTime; @@ -396,4 +397,103 @@ mod tests { .downcast_ref::() .unwrap(); } + + #[test] + fn payable_scanner_can_initiate_a_scan() { + init_test_logging(); + let test_name = "payable_scanner_can_initiate_a_scan"; + let now = SystemTime::now(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let (qualified_payable_accounts, _, all_non_pending_payables) = + make_payables(now, payment_thresholds.clone()); + let payable_dao = + PayableDaoMock::new().non_pending_payables_result(all_non_pending_payables); + + let mut payable_scanner = + PayableScanner::new(Box::new(payable_dao), Rc::new(payment_thresholds)); + + let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + + let expected_message = ReportAccountsPayable { + accounts: qualified_payable_accounts.clone(), + response_skeleton_opt: None, + }; + assert_eq!(result, Ok(expected_message)); + TestLogHandler::new().assert_logs_match_in_order(vec![ + &format!("INFO: {}: Scanning for payables", test_name), + &format!( + "INFO: {}: Chose {} qualified debts to pay", + test_name, + qualified_payable_accounts.len() + ), + ]) + } + + #[test] + fn payable_scanner_throws_error_in_case_no_qualified_payable_is_found() { + init_test_logging(); + let test_name = "payable_scanner_throws_error_in_case_no_qualified_payable_is_found"; + let now = SystemTime::now(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let (_, unqualified_payable_accounts, _) = make_payables(now, payment_thresholds.clone()); + let payable_dao = + PayableDaoMock::new().non_pending_payables_result(unqualified_payable_accounts); + + let mut payable_scanner = + PayableScanner::new(Box::new(payable_dao), Rc::new(payment_thresholds)); + + let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + + assert_eq!(result, Err(String::from("No Qualified Payables found."))); + TestLogHandler::new().assert_logs_match_in_order(vec![ + &format!("INFO: {}: Scanning for payables", test_name), + "Chose 0 qualified debts to pay", + ]); + } + + fn make_payables( + now: SystemTime, + payment_thresholds: PaymentThresholds, + ) -> ( + Vec, + Vec, + Vec, + ) { + let mut unqualified_payable_accounts = vec![PayableAccount { + wallet: make_wallet("wallet1"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec + 1, + ), + pending_payable_opt: None, + }]; + let mut qualified_payable_accounts = vec![ + PayableAccount { + wallet: make_wallet("wallet2"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1_000_000_000, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1, + ), + pending_payable_opt: None, + }, + PayableAccount { + wallet: make_wallet("wallet3"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1_200_000_000, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec - 100, + ), + pending_payable_opt: None, + }, + ]; + + let mut all_non_pending_payables = Vec::new(); + all_non_pending_payables.extend(qualified_payable_accounts.clone()); + all_non_pending_payables.extend(unqualified_payable_accounts.clone()); + + ( + qualified_payable_accounts, + unqualified_payable_accounts, + all_non_pending_payables, + ) + } } From 6b749a10fe8c737510341df1de518084f45f54be Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 26 Aug 2022 14:25:15 +0530 Subject: [PATCH 050/145] GH-611: add tests for pending payable initating a scan --- node/src/accountant/scanners.rs | 81 +++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index eff61d0bb..facdf5ccc 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -164,21 +164,38 @@ pub(in crate::accountant) mod scanners { dao: Box, } - impl Scanner for PendingPayableScanner - where - BeginMessage: Message, - EndMessage: Message, - { + impl Scanner for PendingPayableScanner { fn begin_scan( &mut self, timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ) -> Result { - todo!("Implement PendingPayableScanner") + ) -> Result { + info!(logger, "Scanning for pending payable"); + let filtered_pending_payable = self.dao.return_all_fingerprints(); + match filtered_pending_payable.is_empty() { + true => { + debug!( + logger, + "Pending payable scan ended. No pending payable found." + ); + Err(String::from("No pending payable found.")) + } + false => { + debug!( + logger, + "Found {} pending payables to process", + filtered_pending_payable.len() + ); + Ok(RequestTransactionReceipts { + pending_payable: filtered_pending_payable, + response_skeleton_opt, + }) + } + } } - fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + fn scan_finished(&mut self, message: ReportTransactionReceipts) -> Result<(), Error> { todo!() } @@ -358,6 +375,8 @@ mod tests { use crate::accountant::test_utils::{ AccountantBuilder, PayableDaoMock, PendingPayableDaoMock, ReceivableDaoMock, }; + use crate::accountant::RequestTransactionReceipts; + use crate::blockchain::blockchain_bridge::PendingPayableFingerprint; use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::sub_lib::accountant::PaymentThresholds; @@ -451,6 +470,52 @@ mod tests { ]); } + #[test] + fn pending_payable_scanner_can_initiate_a_scan() { + init_test_logging(); + let test_name = "pending_payable_scanner_can_initiate_a_scan"; + let now = SystemTime::now(); + let fingerprints = vec![PendingPayableFingerprint { + rowid_opt: Some(1234), + timestamp: SystemTime::now(), + hash: Default::default(), + attempt_opt: Some(1), + amount: 1_000_000, + process_error: None, + }]; + let pending_payable_dao = + PendingPayableDaoMock::new().return_all_fingerprints_result(fingerprints.clone()); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let mut pending_payable_scanner = + PendingPayableScanner::new(Box::new(pending_payable_dao), Rc::new(payment_thresholds)); + + let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + + assert_eq!( + result, + Ok(RequestTransactionReceipts { + pending_payable: fingerprints, + response_skeleton_opt: None + }) + ); + } + + #[test] + fn pending_payable_scanner_throws_an_error_when_no_fingerprint_is_found() { + init_test_logging(); + let test_name = "pending_payable_scanner_throws_an_error_when_no_fingerprint_is_found"; + let now = SystemTime::now(); + let pending_payable_dao = + PendingPayableDaoMock::new().return_all_fingerprints_result(vec![]); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let mut pending_payable_scanner = + PendingPayableScanner::new(Box::new(pending_payable_dao), Rc::new(payment_thresholds)); + + let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + + assert_eq!(result, Err(String::from("No pending payable found."))); + } + fn make_payables( now: SystemTime, payment_thresholds: PaymentThresholds, From 383fe72c4e220bd1c97b7d7241dbb729515fa5aa Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 29 Aug 2022 11:54:21 +0530 Subject: [PATCH 051/145] GH-611: extend tests to assert for log messages --- node/src/accountant/scanners.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index facdf5ccc..45717c030 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -483,6 +483,7 @@ mod tests { amount: 1_000_000, process_error: None, }]; + let no_of_pending_payables = fingerprints.len(); let pending_payable_dao = PendingPayableDaoMock::new().return_all_fingerprints_result(fingerprints.clone()); let payment_thresholds = make_payment_thresholds_with_defaults(); @@ -498,6 +499,13 @@ mod tests { response_skeleton_opt: None }) ); + TestLogHandler::new().assert_logs_match_in_order(vec![ + &format!("INFO: {}: Scanning for pending payable", test_name), + &format!( + "DEBUG: {}: Found {} pending payables to process", + test_name, no_of_pending_payables + ), + ]) } #[test] @@ -514,6 +522,13 @@ mod tests { let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); assert_eq!(result, Err(String::from("No pending payable found."))); + TestLogHandler::new().assert_logs_match_in_order(vec![ + &format!("INFO: {}: Scanning for pending payable", test_name), + &format!( + "DEBUG: {}: Pending payable scan ended. No pending payable found.", + test_name + ), + ]) } fn make_payables( From 79f94fe1189286ed2e51e0cad2e21e37e6c2e63b Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 29 Aug 2022 15:47:02 +0530 Subject: [PATCH 052/145] GH-611: migrate the scan_for_receivables to the begin_scan() --- node/src/accountant/mod.rs | 53 ++++++++------------------ node/src/accountant/scanners.rs | 66 ++++++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 47 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 6c7a4b1af..ce3e9ed64 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -70,7 +70,7 @@ pub const DEFAULT_PENDING_TOO_LONG_SEC: u64 = 21_600; //6 hours pub struct Accountant { accountant_config: AccountantConfig, consuming_wallet: Option, - earning_wallet: Wallet, + earning_wallet: Rc, payable_dao: Box, receivable_dao: Box, pending_payable_dao: Box, @@ -447,10 +447,11 @@ impl Accountant { .take() .expectv("Payment thresholds"), ); + let earning_wallet = Rc::new(config.earning_wallet.clone()); Accountant { accountant_config, consuming_wallet: config.consuming_wallet_opt.clone(), - earning_wallet: config.earning_wallet.clone(), + earning_wallet: Rc::clone(&earning_wallet), payable_dao: payable_dao_factory.make(), receivable_dao: receivable_dao_factory.make(), pending_payable_dao: pending_payable_dao_factory.make(), @@ -461,6 +462,7 @@ impl Accountant { pending_payable_dao_factory.make(), receivable_dao_factory.make(), Rc::clone(&payment_thresholds), + Rc::clone(&earning_wallet), ), tools: TransactionConfirmationTools::default(), notify_later: NotifyLaterForScanners::default(), @@ -550,18 +552,18 @@ impl Accountant { } fn scan_for_receivables(&self, response_skeleton_opt: Option) { - info!( - self.logger, - "Scanning for receivables to {}", self.earning_wallet - ); - self.retrieve_transactions_sub - .as_ref() - .expect("BlockchainBridge is unbound") - .try_send(RetrieveTransactions { - recipient: self.earning_wallet.clone(), - response_skeleton_opt, - }) - .expect("BlockchainBridge is dead"); + // info!( + // self.logger, + // "Scanning for receivables to {}", self.earning_wallet + // ); + // self.retrieve_transactions_sub + // .as_ref() + // .expect("BlockchainBridge is unbound") + // .try_send(RetrieveTransactions { + // recipient: self.earning_wallet.clone(), + // response_skeleton_opt, + // }) + // .expect("BlockchainBridge is dead"); } fn scan_for_pending_payable(&self, response_skeleton_opt: Option) { @@ -668,29 +670,6 @@ impl Accountant { } } - // fn payables_debug_summary(&self, qualified_payables: &[PayableAccount]) -> String { - // let now = SystemTime::now(); - // let list = qualified_payables - // .iter() - // .map(|payable| { - // let p_age = now - // .duration_since(payable.last_paid_timestamp) - // .expect("Payable time is corrupt"); - // let threshold = self - // .payable_exceeded_threshold(payable) - // .expect("Threshold suddenly changed!"); - // format!( - // "{} owed for {}sec exceeds threshold: {}; creditor: {}", - // payable.balance, - // p_age.as_secs(), - // threshold, - // payable.wallet - // ) - // }) - // .join("\n"); - // String::from("Paying qualified debts:\n").add(&list) - // } - fn handle_bind_message(&mut self, msg: BindMessage) { self.report_accounts_payable_sub_opt = Some(msg.peer_actors.blockchain_bridge.report_accounts_payable); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 45717c030..115618c86 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -16,6 +16,7 @@ pub(in crate::accountant) mod scanners { use crate::blockchain::blockchain_bridge::RetrieveTransactions; use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds}; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; + use crate::sub_lib::wallet::Wallet; use actix::dev::SendError; use actix::{Context, Message, Recipient}; use itertools::Itertools; @@ -45,6 +46,7 @@ pub(in crate::accountant) mod scanners { pending_payable_dao: Box, receivable_dao: Box, payment_thresholds: Rc, + earning_wallet: Rc, ) -> Self { Scanners { payables: Box::new(PayableScanner::new( @@ -58,6 +60,7 @@ pub(in crate::accountant) mod scanners { receivables: Box::new(ReceivableScanner::new( receivable_dao, Rc::clone(&payment_thresholds), + earning_wallet, )), } } @@ -221,23 +224,27 @@ pub(in crate::accountant) mod scanners { pub struct ReceivableScanner { common: ScannerCommon, dao: Box, + earning_wallet: Rc, } - impl Scanner for ReceivableScanner - where - BeginMessage: Message, - EndMessage: Message, - { + impl Scanner for ReceivableScanner { fn begin_scan( &mut self, timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ) -> Result { - todo!() + ) -> Result { + info!( + logger, + "Scanning for receivables to {}", self.earning_wallet + ); + Ok(RetrieveTransactions { + recipient: self.earning_wallet.as_ref().clone(), + response_skeleton_opt, + }) } - fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + fn scan_finished(&mut self, message: ReceivedPayments) -> Result<(), Error> { todo!() } @@ -249,12 +256,21 @@ pub(in crate::accountant) mod scanners { } impl ReceivableScanner { - pub fn new(dao: Box, payment_thresholds: Rc) -> Self { + pub fn new( + dao: Box, + payment_thresholds: Rc, + earning_wallet: Rc, + ) -> Self { Self { common: ScannerCommon::new(payment_thresholds), + earning_wallet, dao, } } + + pub fn earning_wallet(&self) -> &Wallet { + &self.earning_wallet + } } // pub struct NullScanner {} @@ -376,7 +392,7 @@ mod tests { AccountantBuilder, PayableDaoMock, PendingPayableDaoMock, ReceivableDaoMock, }; use crate::accountant::RequestTransactionReceipts; - use crate::blockchain::blockchain_bridge::PendingPayableFingerprint; + use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::sub_lib::accountant::PaymentThresholds; @@ -398,6 +414,7 @@ mod tests { Box::new(PendingPayableDaoMock::new()), Box::new(ReceivableDaoMock::new()), Rc::clone(&payment_thresholds), + Rc::new(make_wallet("earning")), ); scanners @@ -531,6 +548,35 @@ mod tests { ]) } + #[test] + fn receivable_scanner_can_initiate_a_scan() { + init_test_logging(); + let test_name = "receivable_scanner_can_initiate_a_scan"; + let receivable_dao = ReceivableDaoMock::new(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let earning_wallet = make_wallet("earning"); + let mut receivable_scanner = ReceivableScanner::new( + Box::new(receivable_dao), + Rc::new(payment_thresholds), + Rc::new(earning_wallet.clone()), + ); + + let result = + receivable_scanner.begin_scan(SystemTime::now(), None, &Logger::new(test_name)); + + assert_eq!( + result, + Ok(RetrieveTransactions { + recipient: earning_wallet.clone(), + response_skeleton_opt: None + }) + ); + TestLogHandler::new().exists_log_containing(&format!( + "INFO: {}: Scanning for receivables to {}", + test_name, earning_wallet + )); + } + fn make_payables( now: SystemTime, payment_thresholds: PaymentThresholds, From 8838191b76fa136a0f1143194d441f69ede4df80 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 30 Aug 2022 14:34:50 +0530 Subject: [PATCH 053/145] GH-611: add test for scanning for delinquency --- node/src/accountant/mod.rs | 18 +++--- node/src/accountant/scanners.rs | 105 +++++++++++++++++++++++++++++++- node/src/accountant/tools.rs | 36 ++++++++++- 3 files changed, 148 insertions(+), 11 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index ce3e9ed64..aeaad8ec4 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -461,6 +461,7 @@ impl Accountant { payable_dao_factory.make(), pending_payable_dao_factory.make(), receivable_dao_factory.make(), + banned_dao_factory.make(), Rc::clone(&payment_thresholds), Rc::clone(&earning_wallet), ), @@ -589,14 +590,15 @@ impl Accountant { } } - fn balance_and_age(account: &ReceivableAccount) -> (String, Duration) { - let balance = format!("{}", (account.balance as f64) / 1_000_000_000.0); - let age = account - .last_received_timestamp - .elapsed() - .unwrap_or_else(|_| Duration::new(0, 0)); - (balance, age) - } + // TODO: Remove after migration + // fn balance_and_age(account: &ReceivableAccount) -> (String, Duration) { + // let balance = format!("{}", (account.balance as f64) / 1_000_000_000.0); + // let age = account + // .last_received_timestamp + // .elapsed() + // .unwrap_or_else(|_| Duration::new(0, 0)); + // (balance, age) + // } fn record_service_provided( &self, diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 115618c86..12ca71a3a 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -7,12 +7,14 @@ pub(in crate::accountant) mod scanners { use crate::accountant::tools::payable_scanner_tools::{ investigate_debt_extremes, qualified_payables_and_summary, }; + use crate::accountant::tools::receivable_scanner_tools::balance_and_age; use crate::accountant::ReportAccountsPayable; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, ReportTransactionReceipts, RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, ScanForPendingPayables, ScanForReceivables, SentPayable, }; + use crate::banned_dao::BannedDao; use crate::blockchain::blockchain_bridge::RetrieveTransactions; use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds}; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; @@ -45,6 +47,7 @@ pub(in crate::accountant) mod scanners { payable_dao: Box, pending_payable_dao: Box, receivable_dao: Box, + banned_dao: Box, payment_thresholds: Rc, earning_wallet: Rc, ) -> Self { @@ -59,6 +62,7 @@ pub(in crate::accountant) mod scanners { )), receivables: Box::new(ReceivableScanner::new( receivable_dao, + banned_dao, Rc::clone(&payment_thresholds), earning_wallet, )), @@ -224,6 +228,7 @@ pub(in crate::accountant) mod scanners { pub struct ReceivableScanner { common: ScannerCommon, dao: Box, + banned_dao: Box, earning_wallet: Rc, } @@ -238,6 +243,37 @@ pub(in crate::accountant) mod scanners { logger, "Scanning for receivables to {}", self.earning_wallet ); + info!(logger, "Scanning for delinquencies"); + let now = SystemTime::now(); + self.dao + .new_delinquencies(now, self.common.payment_thresholds.as_ref()) + .into_iter() + .for_each(|account| { + self.banned_dao.ban(&account.wallet); + let (balance, age) = balance_and_age(now, &account); + info!( + logger, + "Wallet {} (balance: {} MASQ, age: {} sec) banned for delinquency", + account.wallet, + balance, + age.as_secs() + ) + }); + self.dao + .paid_delinquencies(self.common.payment_thresholds.as_ref()) + .into_iter() + .for_each(|account| { + self.banned_dao.unban(&account.wallet); + let (balance, age) = balance_and_age(now, &account); + info!( + logger, + "Wallet {} (balance: {} MASQ, age: {} sec) is no longer delinquent: unbanned", + account.wallet, + balance, + age.as_secs() + ) + }); + Ok(RetrieveTransactions { recipient: self.earning_wallet.as_ref().clone(), response_skeleton_opt, @@ -258,6 +294,7 @@ pub(in crate::accountant) mod scanners { impl ReceivableScanner { pub fn new( dao: Box, + banned_dao: Box, payment_thresholds: Rc, earning_wallet: Rc, ) -> Self { @@ -265,6 +302,7 @@ pub(in crate::accountant) mod scanners { common: ScannerCommon::new(payment_thresholds), earning_wallet, dao, + banned_dao, } } @@ -389,13 +427,14 @@ mod tests { PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, Scanners, }; use crate::accountant::test_utils::{ - AccountantBuilder, PayableDaoMock, PendingPayableDaoMock, ReceivableDaoMock, + make_receivable_account, AccountantBuilder, BannedDaoMock, PayableDaoMock, + PendingPayableDaoMock, ReceivableDaoMock, }; use crate::accountant::RequestTransactionReceipts; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; - use crate::sub_lib::accountant::PaymentThresholds; + use crate::sub_lib::accountant::{PaymentThresholds, DEFAULT_PAYMENT_THRESHOLDS}; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::{ @@ -404,6 +443,7 @@ mod tests { use masq_lib::logger::Logger; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; use std::rc::Rc; + use std::sync::{Arc, Mutex, MutexGuard}; use std::time::SystemTime; #[test] @@ -413,6 +453,7 @@ mod tests { Box::new(PayableDaoMock::new()), Box::new(PendingPayableDaoMock::new()), Box::new(ReceivableDaoMock::new()), + Box::new(BannedDaoMock::new()), Rc::clone(&payment_thresholds), Rc::new(make_wallet("earning")), ); @@ -557,6 +598,7 @@ mod tests { let earning_wallet = make_wallet("earning"); let mut receivable_scanner = ReceivableScanner::new( Box::new(receivable_dao), + Box::new(BannedDaoMock::new()), Rc::new(payment_thresholds), Rc::new(earning_wallet.clone()), ); @@ -577,6 +619,65 @@ mod tests { )); } + #[test] + fn receivable_scanner_scans_for_delinquencies() { + init_test_logging(); + let test_name = "receivable_scanner_scans_for_deliquencies"; + let newly_banned_1 = make_receivable_account(1234, true); + let newly_banned_2 = make_receivable_account(2345, true); + let newly_unbanned_1 = make_receivable_account(3456, false); + let newly_unbanned_2 = make_receivable_account(4567, false); + let new_delinquencies_parameters_arc = Arc::new(Mutex::new(vec![])); + let paid_delinquencies_parameters_arc = Arc::new(Mutex::new(vec![])); + let receivable_dao = ReceivableDaoMock::new() + .new_delinquencies_parameters(&new_delinquencies_parameters_arc) + .new_delinquencies_result(vec![newly_banned_1.clone(), newly_banned_2.clone()]) + .paid_delinquencies_parameters(&paid_delinquencies_parameters_arc) + .paid_delinquencies_result(vec![newly_unbanned_1.clone(), newly_unbanned_2.clone()]); + let ban_parameters_arc = Arc::new(Mutex::new(vec![])); + let unban_parameters_arc = Arc::new(Mutex::new(vec![])); + let banned_dao = BannedDaoMock::new() + .ban_list_result(vec![]) + .ban_parameters(&ban_parameters_arc) + .unban_parameters(&unban_parameters_arc); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let mut receivable_scanner = ReceivableScanner::new( + Box::new(receivable_dao), + Box::new(banned_dao), + Rc::new(payment_thresholds.clone()), + Rc::new(make_wallet("earning")), + ); + + let result = receivable_scanner.begin_scan( + SystemTime::now(), + None, + &Logger::new("DELINQUENCY_TEST"), + ); + + let new_delinquencies_parameters: MutexGuard> = + new_delinquencies_parameters_arc.lock().unwrap(); + assert_eq!( + payment_thresholds.clone(), + new_delinquencies_parameters[0].1 + ); + let paid_delinquencies_parameters: MutexGuard> = + paid_delinquencies_parameters_arc.lock().unwrap(); + assert_eq!(payment_thresholds.clone(), paid_delinquencies_parameters[0]); + let ban_parameters = ban_parameters_arc.lock().unwrap(); + assert!(ban_parameters.contains(&newly_banned_1.wallet)); + assert!(ban_parameters.contains(&newly_banned_2.wallet)); + assert_eq!(2, ban_parameters.len()); + let unban_parameters = unban_parameters_arc.lock().unwrap(); + assert!(unban_parameters.contains(&newly_unbanned_1.wallet)); + assert!(unban_parameters.contains(&newly_unbanned_2.wallet)); + assert_eq!(2, unban_parameters.len()); + let tlh = TestLogHandler::new(); + tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c65743132333464 \\(balance: 1234 MASQ, age: \\d+ sec\\) banned for delinquency"); + tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c65743233343564 \\(balance: 2345 MASQ, age: \\d+ sec\\) banned for delinquency"); + tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574333435366e \\(balance: 3456 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); + tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574343536376e \\(balance: 4567 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); + } + fn make_payables( now: SystemTime, payment_thresholds: PaymentThresholds, diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index a4e7afda6..5b055fc9d 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -150,13 +150,31 @@ pub(crate) mod payable_scanner_tools { } } +pub(crate) mod receivable_scanner_tools { + use crate::accountant::receivable_dao::ReceivableAccount; + use std::time::{Duration, SystemTime}; + + pub(crate) fn balance_and_age( + time: SystemTime, + account: &ReceivableAccount, + ) -> (String, Duration) { + let balance = format!("{}", (account.balance as f64) / 1_000_000_000.0); + let age = time + .duration_since(account.last_received_timestamp) + .unwrap_or_else(|_| Duration::new(0, 0)); + (balance, age) + } +} + #[cfg(test)] mod tests { use crate::accountant::payable_dao::PayableAccount; + use crate::accountant::receivable_dao::ReceivableAccount; use crate::accountant::tools::payable_scanner_tools::{ calculate_payout_threshold, exceeded_summary, investigate_debt_extremes, is_payable_qualified, payable_time_diff, qualified_payables_and_summary, }; + use crate::accountant::tools::receivable_scanner_tools::balance_and_age; use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::sub_lib::accountant::PaymentThresholds; @@ -165,7 +183,7 @@ mod tests { make_payment_thresholds_with_defaults, make_populated_accountant_config_with_defaults, }; use std::rc::Rc; - use std::time::SystemTime; + use std::time::{Duration, SystemTime}; fn make_custom_payment_thresholds() -> PaymentThresholds { PaymentThresholds { @@ -387,6 +405,22 @@ mod tests { assert_eq!(result, "Payable scan found 4 debts; the biggest is 2000000 owed for 10000sec, the oldest is 330 owed for 30000sec") } + #[test] + fn balance_and_age_is_calculated_as_expected() { + let now = SystemTime::now(); + let offset = 1000; + let receivable_account = ReceivableAccount { + wallet: make_wallet("wallet0"), + balance: 10_000_000_000, + last_received_timestamp: from_time_t(to_time_t(now) - offset), + }; + + let (balance, age) = balance_and_age(now, &receivable_account); + + assert_eq!(balance, "10"); + assert_eq!(age.as_secs(), offset as u64); + } + // TODO: Either make this test work or write an alternative test in the desired file // #[test] // fn threshold_calculation_depends_on_user_defined_payment_thresholds() { From 9aba8541f911d03b354c3d2fcee8e54bc896fadd Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 30 Aug 2022 15:46:13 +0530 Subject: [PATCH 054/145] GH-611: remove referenced counter from the payable_scanner_tools --- node/src/accountant/mod.rs | 10 ------- node/src/accountant/scanners.rs | 9 ++++-- node/src/accountant/tools.rs | 52 ++++++++++----------------------- 3 files changed, 21 insertions(+), 50 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index aeaad8ec4..6ff0d9ecc 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -590,16 +590,6 @@ impl Accountant { } } - // TODO: Remove after migration - // fn balance_and_age(account: &ReceivableAccount) -> (String, Duration) { - // let balance = format!("{}", (account.balance as f64) / 1_000_000_000.0); - // let age = account - // .last_received_timestamp - // .elapsed() - // .unwrap_or_else(|_| Duration::new(0, 0)); - // (balance, age) - // } - fn record_service_provided( &self, service_rate: u64, diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 12ca71a3a..54f7b68a7 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -126,7 +126,7 @@ pub(in crate::accountant) mod scanners { ); let (qualified_payables, summary) = qualified_payables_and_summary( all_non_pending_payables, - self.common.payment_thresholds.clone(), + self.common.payment_thresholds.as_ref(), ); info!( logger, @@ -593,12 +593,15 @@ mod tests { fn receivable_scanner_can_initiate_a_scan() { init_test_logging(); let test_name = "receivable_scanner_can_initiate_a_scan"; - let receivable_dao = ReceivableDaoMock::new(); + let receivable_dao = ReceivableDaoMock::new() + .new_delinquencies_result(vec![make_receivable_account(1234, true)]) + .paid_delinquencies_result(vec![make_receivable_account(4321, false)]); + let banned_dao = BannedDaoMock::new(); let payment_thresholds = make_payment_thresholds_with_defaults(); let earning_wallet = make_wallet("earning"); let mut receivable_scanner = ReceivableScanner::new( Box::new(receivable_dao), - Box::new(BannedDaoMock::new()), + Box::new(banned_dao), Rc::new(payment_thresholds), Rc::new(earning_wallet.clone()), ); diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 5b055fc9d..86af35a90 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -67,7 +67,7 @@ pub(crate) mod payable_scanner_tools { pub(crate) fn is_payable_qualified( time: SystemTime, payable: &PayableAccount, - payment_thresholds: Rc, + payment_thresholds: &PaymentThresholds, ) -> Option { // TODO: This calculation should be done in the database, if possible let maturity_time_limit = payment_thresholds.maturity_threshold_sec as u64; @@ -99,7 +99,7 @@ pub(crate) mod payable_scanner_tools { pub(crate) fn calculate_payout_threshold( x: u64, - payment_thresholds: Rc, + payment_thresholds: &PaymentThresholds, ) -> f64 { let m = -((payment_thresholds.debt_threshold_gwei as f64 - payment_thresholds.permanent_debt_allowed_gwei as f64) @@ -126,15 +126,14 @@ pub(crate) mod payable_scanner_tools { pub(crate) fn qualified_payables_and_summary( non_pending_payables: Vec, - payment_thresholds: Rc, + payment_thresholds: &PaymentThresholds, ) -> (Vec, String) { let now = SystemTime::now(); let mut qualified_summary = String::from("Paying qualified debts:\n"); let mut qualified_payables: Vec = vec![]; for payable in non_pending_payables { - if let Some(threshold) = is_payable_qualified(now, &payable, payment_thresholds.clone()) - { + if let Some(threshold) = is_payable_qualified(now, &payable, payment_thresholds) { let payable_summary = exceeded_summary(now, &payable, threshold); qualified_summary.push_str(&payable_summary); qualified_payables.push(payable); @@ -209,11 +208,7 @@ mod tests { pending_payable_opt: None, }; - let result = is_payable_qualified( - now, - &unqualified_payable_account, - Rc::new(payment_thresholds), - ); + let result = is_payable_qualified(now, &unqualified_payable_account, &payment_thresholds); assert_eq!(result, None); } @@ -231,11 +226,7 @@ mod tests { pending_payable_opt: None, }; - let result = is_payable_qualified( - now, - &unqualified_payable_account, - Rc::new(payment_thresholds), - ); + let result = is_payable_qualified(now, &unqualified_payable_account, &payment_thresholds); assert_eq!(result, None); } @@ -253,11 +244,7 @@ mod tests { pending_payable_opt: None, }; - let result = is_payable_qualified( - now, - &unqualified_payable_account, - Rc::new(payment_thresholds), - ); + let result = is_payable_qualified(now, &unqualified_payable_account, &payment_thresholds); assert_eq!(result, None); } @@ -277,12 +264,11 @@ mod tests { }; let threshold = calculate_payout_threshold( payable_time_diff(now, &qualified_payable), - Rc::clone(&payment_thresholds_rc), + &payment_thresholds_rc, ); eprintln!("Threshold: {}, Debt: {}", threshold, debt); - let result = - is_payable_qualified(now, &qualified_payable, Rc::clone(&payment_thresholds_rc)); + let result = is_payable_qualified(now, &qualified_payable, &payment_thresholds_rc); assert_eq!(result, Some(threshold as u64)); } @@ -317,25 +303,20 @@ mod tests { pending_payable_opt: None, }, ]; - let payment_thresholds_rc = Rc::new(payment_thresholds); let mut all_non_pending_payables = Vec::new(); all_non_pending_payables.extend(qualified_payable_accounts.clone()); all_non_pending_payables.extend(unqualified_payable_accounts.clone()); - let (qualified_payables, summary) = qualified_payables_and_summary( - all_non_pending_payables, - Rc::clone(&payment_thresholds_rc), - ); + let (qualified_payables, summary) = + qualified_payables_and_summary(all_non_pending_payables, &payment_thresholds); let mut expected_summary = String::from("Paying qualified debts:\n"); for payable in qualified_payable_accounts.iter() { expected_summary.push_str(&exceeded_summary( now, &payable, - calculate_payout_threshold( - payable_time_diff(now, &payable), - payment_thresholds_rc.clone(), - ) as u64, + calculate_payout_threshold(payable_time_diff(now, &payable), &payment_thresholds) + as u64, )) } @@ -355,12 +336,9 @@ mod tests { ), pending_payable_opt: None, }]; - let payment_thresholds_rc = Rc::new(payment_thresholds); - let (qualified_payables, summary) = qualified_payables_and_summary( - unqualified_payable_accounts, - Rc::clone(&payment_thresholds_rc), - ); + let (qualified_payables, summary) = + qualified_payables_and_summary(unqualified_payable_accounts, &payment_thresholds); assert_eq!(qualified_payables, vec![]); assert_eq!(summary, String::from("No Qualified Payables found.")); From 682f81f0476028e1b5f75088ad29033a6cc6175b Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 30 Aug 2022 15:56:24 +0530 Subject: [PATCH 055/145] GH-611: remove some import warnings --- node/src/accountant/mod.rs | 12 ++++------ node/src/accountant/scanners.rs | 30 +++++++++---------------- node/src/accountant/test_utils.rs | 2 +- node/src/accountant/tools.rs | 8 ++----- node/src/sub_lib/combined_parameters.rs | 1 - 5 files changed, 18 insertions(+), 35 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 6ff0d9ecc..adfd51a33 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -15,11 +15,9 @@ use masq_lib::ui_gateway::{MessageBody, MessagePath, MessageTarget}; use crate::accountant::payable_dao::{Payable, PayableAccount, PayableDaoError, PayableDaoFactory}; use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDaoFactory}; -use crate::accountant::receivable_dao::{ - ReceivableAccount, ReceivableDaoError, ReceivableDaoFactory, -}; +use crate::accountant::receivable_dao::{ReceivableDaoError, ReceivableDaoFactory}; use crate::accountant::scanners::scanners::{ - NotifyLaterForScanners, Scanner, Scanners, TransactionConfirmationTools, + NotifyLaterForScanners, Scanners, TransactionConfirmationTools, }; use crate::banned_dao::{BannedDao, BannedDaoFactory}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; @@ -54,13 +52,11 @@ use masq_lib::ui_gateway::{NodeFromUiMessage, NodeToUiMessage}; use masq_lib::utils::{plus, ExpectValue}; use payable_dao::PayableDao; use receivable_dao::ReceivableDao; -#[cfg(test)] -use std::any::Any; use std::default::Default; use std::ops::Add; use std::path::Path; use std::rc::Rc; -use std::time::{Duration, SystemTime}; +use std::time::SystemTime; use web3::types::{TransactionReceipt, H256}; pub const CRASH_KEY: &str = "ACCOUNTANT"; @@ -1163,7 +1159,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::accountant::receivable_dao::ReceivableAccount; - use crate::accountant::scanners::scanners::{Scanner, ScannerMock}; + use crate::accountant::scanners::scanners::ScannerMock; use crate::accountant::test_utils::{ bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_pending_payable_fingerprint, make_receivable_account, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 54f7b68a7..a106aab65 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -1,7 +1,7 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. pub(in crate::accountant) mod scanners { - use crate::accountant::payable_dao::{PayableAccount, PayableDao, PayableDaoReal}; + use crate::accountant::payable_dao::PayableDao; use crate::accountant::pending_payable_dao::PendingPayableDao; use crate::accountant::receivable_dao::ReceivableDao; use crate::accountant::tools::payable_scanner_tools::{ @@ -16,22 +16,17 @@ pub(in crate::accountant) mod scanners { }; use crate::banned_dao::BannedDao; use crate::blockchain::blockchain_bridge::RetrieveTransactions; - use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds}; + use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use crate::sub_lib::wallet::Wallet; - use actix::dev::SendError; - use actix::{Context, Message, Recipient}; - use itertools::Itertools; - use masq_lib::logger::{timestamp_as_string, Logger}; - use masq_lib::messages::ScanType; - use masq_lib::messages::ScanType::PendingPayables; + use actix::{Message, Recipient}; + use masq_lib::logger::Logger; use std::any::Any; use std::borrow::BorrowMut; use std::cell::RefCell; - use std::ops::Add; use std::rc::Rc; use std::sync::{Arc, Mutex}; - use std::time::{Duration, SystemTime}; + use std::time::SystemTime; type Error = String; @@ -421,25 +416,22 @@ pub(in crate::accountant) mod scanners { #[cfg(test)] mod tests { - use super::*; - use crate::accountant::payable_dao::{PayableAccount, PayableDaoReal}; + + use crate::accountant::payable_dao::PayableAccount; use crate::accountant::scanners::scanners::{ PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, Scanners, }; use crate::accountant::test_utils::{ - make_receivable_account, AccountantBuilder, BannedDaoMock, PayableDaoMock, - PendingPayableDaoMock, ReceivableDaoMock, + make_receivable_account, BannedDaoMock, PayableDaoMock, PendingPayableDaoMock, + ReceivableDaoMock, }; use crate::accountant::RequestTransactionReceipts; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; - use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; - use crate::sub_lib::accountant::{PaymentThresholds, DEFAULT_PAYMENT_THRESHOLDS}; + use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::test_utils::make_wallet; - use crate::test_utils::unshared_test_utils::{ - make_payment_thresholds_with_defaults, make_populated_accountant_config_with_defaults, - }; + use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; use masq_lib::logger::Logger; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; use std::rc::Rc; diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 682f6d030..70df152c0 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -20,7 +20,7 @@ use crate::database::dao_utils; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::db_config::config_dao::{ConfigDao, ConfigDaoFactory}; use crate::db_config::mocks::ConfigDaoMock; -use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds, DEFAULT_PAYMENT_THRESHOLDS}; +use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds}; use crate::sub_lib::wallet::Wallet; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::{ diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 86af35a90..ba27b7b8a 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -3,7 +3,6 @@ pub(crate) mod payable_scanner_tools { use crate::accountant::payable_dao::PayableAccount; use crate::sub_lib::accountant::PaymentThresholds; - use std::rc::Rc; use std::time::SystemTime; //for debugging only @@ -174,15 +173,12 @@ mod tests { is_payable_qualified, payable_time_diff, qualified_payables_and_summary, }; use crate::accountant::tools::receivable_scanner_tools::balance_and_age; - use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::sub_lib::accountant::PaymentThresholds; use crate::test_utils::make_wallet; - use crate::test_utils::unshared_test_utils::{ - make_payment_thresholds_with_defaults, make_populated_accountant_config_with_defaults, - }; + use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; use std::rc::Rc; - use std::time::{Duration, SystemTime}; + use std::time::SystemTime; fn make_custom_payment_thresholds() -> PaymentThresholds { PaymentThresholds { diff --git a/node/src/sub_lib/combined_parameters.rs b/node/src/sub_lib/combined_parameters.rs index 7bede1056..89ed54943 100644 --- a/node/src/sub_lib/combined_parameters.rs +++ b/node/src/sub_lib/combined_parameters.rs @@ -290,7 +290,6 @@ fn unreachable() -> ! { #[cfg(test)] mod tests { use super::*; - use crate::sub_lib::accountant::{DEFAULT_PAYMENT_THRESHOLDS, DEFAULT_SCAN_INTERVALS}; use crate::sub_lib::combined_parameters::CombinedParamsDataTypes::U128; use crate::sub_lib::neighborhood::DEFAULT_RATE_PACK; use crate::test_utils::unshared_test_utils::{ From 1cfd92e717a6d26e1aa5378c092167400e652fa3 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 30 Aug 2022 16:11:02 +0530 Subject: [PATCH 056/145] GH-611: generate timestamp inside begin_scan() --- node/src/accountant/scanners.rs | 5 +++-- node/src/accountant/tools.rs | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index a106aab65..7505bda53 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -111,7 +111,7 @@ pub(in crate::accountant) mod scanners { // let start_message = BeginScanAMessage {}; // // Use the DAO, if necessary, to populate start_message // Ok(start_message) - + let now = SystemTime::now(); info!(logger, "Scanning for payables"); let all_non_pending_payables = self.dao.non_pending_payables(); debug!( @@ -120,6 +120,7 @@ pub(in crate::accountant) mod scanners { investigate_debt_extremes(&all_non_pending_payables) ); let (qualified_payables, summary) = qualified_payables_and_summary( + now, all_non_pending_payables, self.common.payment_thresholds.as_ref(), ); @@ -234,12 +235,12 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { + let now = SystemTime::now(); info!( logger, "Scanning for receivables to {}", self.earning_wallet ); info!(logger, "Scanning for delinquencies"); - let now = SystemTime::now(); self.dao .new_delinquencies(now, self.common.payment_thresholds.as_ref()) .into_iter() diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index ba27b7b8a..61ad9bff8 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -124,16 +124,16 @@ pub(crate) mod payable_scanner_tools { } pub(crate) fn qualified_payables_and_summary( + time: SystemTime, non_pending_payables: Vec, payment_thresholds: &PaymentThresholds, ) -> (Vec, String) { - let now = SystemTime::now(); let mut qualified_summary = String::from("Paying qualified debts:\n"); let mut qualified_payables: Vec = vec![]; for payable in non_pending_payables { - if let Some(threshold) = is_payable_qualified(now, &payable, payment_thresholds) { - let payable_summary = exceeded_summary(now, &payable, threshold); + if let Some(threshold) = is_payable_qualified(time, &payable, payment_thresholds) { + let payable_summary = exceeded_summary(time, &payable, threshold); qualified_summary.push_str(&payable_summary); qualified_payables.push(payable); } @@ -304,7 +304,7 @@ mod tests { all_non_pending_payables.extend(unqualified_payable_accounts.clone()); let (qualified_payables, summary) = - qualified_payables_and_summary(all_non_pending_payables, &payment_thresholds); + qualified_payables_and_summary(now, all_non_pending_payables, &payment_thresholds); let mut expected_summary = String::from("Paying qualified debts:\n"); for payable in qualified_payable_accounts.iter() { @@ -334,7 +334,7 @@ mod tests { }]; let (qualified_payables, summary) = - qualified_payables_and_summary(unqualified_payable_accounts, &payment_thresholds); + qualified_payables_and_summary(now, unqualified_payable_accounts, &payment_thresholds); assert_eq!(qualified_payables, vec![]); assert_eq!(summary, String::from("No Qualified Payables found.")); From 0f03db9c73f3909877a0476d78b286ae77c46487 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 31 Aug 2022 14:44:13 +0530 Subject: [PATCH 057/145] GH-611: modify BannedDaoFactoryMock --- node/src/accountant/mod.rs | 17 +++++++---- node/src/accountant/test_utils.rs | 49 +++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index adfd51a33..74edcd9ed 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1212,6 +1212,7 @@ mod tests { let payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let pending_payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let receivable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); + let banned_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let payable_dao_factory = PayableDaoFactoryMock::new() .make_params(&payable_dao_factory_params_arc) .make_result(PayableDaoMock::new()) @@ -1224,10 +1225,10 @@ mod tests { .make_params(&receivable_dao_factory_params_arc) .make_result(ReceivableDaoMock::new()) .make_result(ReceivableDaoMock::new()); - let banned_dao_factory_called = Rc::new(RefCell::new(false)); - let banned_dao = BannedDaoMock::new(); - let banned_dao_factory = - BannedDaoFactoryMock::new(banned_dao).called(&banned_dao_factory_called); + let banned_dao_factory = BannedDaoFactoryMock::new() + .make_params(&banned_dao_factory_params_arc) + .make_result(BannedDaoMock::new()) + .make_result(BannedDaoMock::new()); let _ = Accountant::new( &mut config, @@ -1249,7 +1250,7 @@ mod tests { *receivable_dao_factory_params_arc.lock().unwrap(), vec![(), ()] ); - assert_eq!(banned_dao_factory_called.as_ref(), &RefCell::new(true)); + assert_eq!(*banned_dao_factory_params_arc.lock().unwrap(), vec![(), ()]); } #[test] @@ -1279,7 +1280,11 @@ mod tests { .make_result(ReceivableDaoMock::new()) // For Accountant .make_result(ReceivableDaoMock::new()), // For Scanner ); - let banned_dao_factory = Box::new(BannedDaoFactoryMock::new(BannedDaoMock::new())); + let banned_dao_factory = Box::new( + BannedDaoFactoryMock::new() + .make_result(BannedDaoMock::new()) + .make_result(BannedDaoMock::new()), + ); let result = Accountant::new( &mut bootstrapper_config, diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 70df152c0..b8eae4f7f 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -75,7 +75,7 @@ pub struct AccountantBuilder { payable_dao_factory: Option, receivable_dao_factory: Option, pending_payable_dao_factory: Option, - banned_dao_factory: Option>, + banned_dao_factory: Option, config_dao_factory: Option>, } @@ -140,7 +140,14 @@ impl AccountantBuilder { } pub fn banned_dao(mut self, banned_dao: BannedDaoMock) -> Self { - self.banned_dao_factory = Some(Box::new(BannedDaoFactoryMock::new(banned_dao))); + match self.banned_dao_factory { + None => { + self.banned_dao_factory = Some(BannedDaoFactoryMock::new().make_result(banned_dao)) + } + Some(banned_dao_factory) => { + self.banned_dao_factory = Some(banned_dao_factory.make_result(banned_dao)) + } + } self } @@ -171,15 +178,17 @@ impl AccountantBuilder { .make_result(PendingPayableDaoMock::new()) .make_result(PendingPayableDaoMock::new()), ); - let banned_dao_factory = self - .banned_dao_factory - .unwrap_or(Box::new(BannedDaoFactoryMock::new(BannedDaoMock::new()))); + let banned_dao_factory = self.banned_dao_factory.unwrap_or( + BannedDaoFactoryMock::new() + .make_result(BannedDaoMock::new()) + .make_result(BannedDaoMock::new()), + ); let accountant = Accountant::new( &mut config, Box::new(payable_dao_factory), Box::new(receivable_dao_factory), Box::new(pending_payable_dao_factory), - banned_dao_factory, + Box::new(banned_dao_factory), ); accountant } @@ -258,27 +267,37 @@ impl ReceivableDaoFactoryMock { } pub struct BannedDaoFactoryMock { - called: Rc>, - mock: RefCell>, + make_params: Arc>>, + make_results: RefCell>>, } impl BannedDaoFactory for BannedDaoFactoryMock { fn make(&self) -> Box { - *self.called.borrow_mut() = true; - Box::new(self.mock.borrow_mut().take().unwrap()) + if self.make_results.borrow().len() == 0 { + panic!( + "BannedDao Missing. This problem mostly occurs when ReceivableDao is only supplied for Accountant and not for the Scanner while building Accountant." + ) + }; + self.make_params.lock().unwrap().push(()); + self.make_results.borrow_mut().remove(0) } } impl BannedDaoFactoryMock { - pub fn new(mock: BannedDaoMock) -> Self { + pub fn new() -> Self { Self { - called: Rc::new(RefCell::new(false)), - mock: RefCell::new(Some(mock)), + make_params: Arc::new(Mutex::new(vec![])), + make_results: RefCell::new(vec![]), } } - pub fn called(mut self, called: &Rc>) -> Self { - self.called = called.clone(); + pub fn make_params(mut self, params: &Arc>>) -> Self { + self.make_params = params.clone(); + self + } + + pub fn make_result(self, result: BannedDaoMock) -> Self { + self.make_results.borrow_mut().push(Box::new(result)); self } } From 95464e3560a50e2e4540bc611e7c37c29fbc485f Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 31 Aug 2022 16:13:00 +0530 Subject: [PATCH 058/145] GH-611: fix test accountant_sends_report_accounts_payable_to_blockchain_bridge_when_qualified_payable_found --- node/src/accountant/mod.rs | 92 ++++++++++++------------ node/src/accountant/scanners.rs | 113 ++++++++++-------------------- node/src/accountant/test_utils.rs | 46 ++++++++++++ 3 files changed, 125 insertions(+), 126 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 74edcd9ed..e40f180b5 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -197,8 +197,8 @@ impl Handler for Accountant { .expect("BlockchainBridge is unbound") .try_send(message) .expect("BlockchainBridge is dead"), - Err(e) if e.contains("Called from ScannerMock") => { - todo!("Make sure no code is executed after this") + Err(e) if e.contains("Called from NullScanner") => { + eprintln!("Payable scan is disabled."); } Err(e) => todo!("Use logger to print out the error message"), } @@ -214,11 +214,19 @@ impl Handler for Accountant { // msg.response_skeleton_opt, // ctx, // ) - self.scanners.pending_payables.begin_scan( + match self.scanners.pending_payables.begin_scan( SystemTime::now(), msg.response_skeleton_opt, &self.logger, - ); + ) { + Ok(message) => { + todo!("send the message to blockchain bridge"); + } + Err(e) if e.contains("Called from NullScanner") => { + eprintln!("Pending payable scan is disabled.") + } + Err(e) => todo!("Use logger to print out the error message"), + } } } @@ -231,11 +239,19 @@ impl Handler for Accountant { // msg.response_skeleton_opt, // ctx, // ); - self.scanners.receivables.begin_scan( + match self.scanners.receivables.begin_scan( SystemTime::now(), msg.response_skeleton_opt, &self.logger, - ); + ) { + Ok(message) => { + todo!("send the message to blockchain bridge"); + } + Err(e) if e.contains("Called from NullScanner") => { + eprintln!("Receivable scan is disabled.") + } + Err(e) => todo!("Use logger to print out the error message"), + }; } } @@ -1159,12 +1175,12 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::accountant::receivable_dao::ReceivableAccount; - use crate::accountant::scanners::scanners::ScannerMock; + use crate::accountant::scanners::scanners::{NullScanner, ScannerMock}; use crate::accountant::test_utils::{ - bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_pending_payable_fingerprint, - make_receivable_account, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, - PendingPayableDaoFactoryMock, PendingPayableDaoMock, ReceivableDaoFactoryMock, - ReceivableDaoMock, + bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_payables, + make_pending_payable_fingerprint, make_receivable_account, BannedDaoFactoryMock, + PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, + ReceivableDaoFactoryMock, ReceivableDaoMock, }; use crate::accountant::test_utils::{AccountantBuilder, BannedDaoMock}; use crate::accountant::Accountant; @@ -1875,41 +1891,24 @@ mod tests { fn accountant_sends_report_accounts_payable_to_blockchain_bridge_when_qualified_payable_found() { let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); - let accounts = vec![ - PayableAccount { - wallet: make_wallet("blah"), - balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 55, - last_paid_timestamp: from_time_t( - to_time_t(SystemTime::now()) - - DEFAULT_PAYMENT_THRESHOLDS.maturity_threshold_sec - - 5, - ), - pending_payable_opt: None, - }, - PayableAccount { - wallet: make_wallet("foo"), - balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 66, - last_paid_timestamp: from_time_t( - to_time_t(SystemTime::now()) - - DEFAULT_PAYMENT_THRESHOLDS.maturity_threshold_sec - - 500, - ), - pending_payable_opt: None, - }, - ]; - let payable_dao = PayableDaoMock::new().non_pending_payables_result(accounts.clone()); + let now = SystemTime::now(); + let payment_thresholds = make_payment_thresholds_with_defaults(); + let (qualified_payables, _, all_non_pending_payables) = + make_payables(now, &payment_thresholds); + let payable_dao = + PayableDaoMock::new().non_pending_payables_result(all_non_pending_payables); let system = System::new("report_accounts_payable forwarded to blockchain_bridge"); let mut subject = AccountantBuilder::default() .bootstrapper_config(bc_from_ac_plus_earning_wallet( make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), + payment_thresholds, make_wallet("some_wallet_address"), )) - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner .build(); - subject.scanners.pending_payables = Box::new(ScannerMock::new()); - subject.scanners.receivables = Box::new(ScannerMock::new()); + subject.scanners.pending_payables = Box::new(NullScanner::new()); + subject.scanners.receivables = Box::new(NullScanner::new()); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() @@ -1923,18 +1922,13 @@ mod tests { system.run(); let blockchain_bridge_recorder = blockchain_bridge_recording_arc.lock().unwrap(); assert_eq!(blockchain_bridge_recorder.len(), 1); - let report_accounts_payables_msgs: Vec<&ReportAccountsPayable> = (0 - ..blockchain_bridge_recorder.len()) - .flat_map(|index| { - blockchain_bridge_recorder.get_record_opt::(index) - }) - .collect(); + let message = blockchain_bridge_recorder.get_record::(0); assert_eq!( - report_accounts_payables_msgs, - vec![&ReportAccountsPayable { - accounts, + message, + &ReportAccountsPayable { + accounts: qualified_payables, response_skeleton_opt: None, - }] + } ); } diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 7505bda53..8029eac12 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -307,33 +307,38 @@ pub(in crate::accountant) mod scanners { } } - // pub struct NullScanner {} - // - // impl Scanner for NullScanner - // where - // BeginMessage: Message + Send + 'static, - // BeginMessage::Result: Send, - // EndMessage: Message, - // { - // fn begin_scan( - // &mut self, - // timestamp: SystemTime, - // response_skeleton_opt: Option, - // ctx: &mut Context, - // ) -> Result { - // todo!("Implement NullScanner") - // } - // - // fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { - // todo!() - // } - // - // fn scan_started_at(&self) -> Option { - // todo!() - // } - // - // as_any_impl!(); - // } + pub struct NullScanner {} + + impl Scanner for NullScanner + where + BeginMessage: Message, + EndMessage: Message, + { + fn begin_scan( + &mut self, + timestamp: SystemTime, + response_skeleton_opt: Option, + logger: &Logger, + ) -> Result { + Err(String::from("Called from NullScanner")) + } + + fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + todo!() + } + + fn scan_started_at(&self) -> Option { + todo!() + } + + as_any_impl!(); + } + + impl NullScanner { + pub fn new() -> Self { + Self {} + } + } pub struct ScannerMock { begin_scan_params: RefCell)>>, @@ -423,8 +428,8 @@ mod tests { PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, Scanners, }; use crate::accountant::test_utils::{ - make_receivable_account, BannedDaoMock, PayableDaoMock, PendingPayableDaoMock, - ReceivableDaoMock, + make_payables, make_receivable_account, BannedDaoMock, PayableDaoMock, + PendingPayableDaoMock, ReceivableDaoMock, }; use crate::accountant::RequestTransactionReceipts; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; @@ -475,7 +480,7 @@ mod tests { let now = SystemTime::now(); let payment_thresholds = make_payment_thresholds_with_defaults(); let (qualified_payable_accounts, _, all_non_pending_payables) = - make_payables(now, payment_thresholds.clone()); + make_payables(now, &payment_thresholds); let payable_dao = PayableDaoMock::new().non_pending_payables_result(all_non_pending_payables); @@ -505,7 +510,7 @@ mod tests { let test_name = "payable_scanner_throws_error_in_case_no_qualified_payable_is_found"; let now = SystemTime::now(); let payment_thresholds = make_payment_thresholds_with_defaults(); - let (_, unqualified_payable_accounts, _) = make_payables(now, payment_thresholds.clone()); + let (_, unqualified_payable_accounts, _) = make_payables(now, &payment_thresholds); let payable_dao = PayableDaoMock::new().non_pending_payables_result(unqualified_payable_accounts); @@ -673,50 +678,4 @@ mod tests { tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574333435366e \\(balance: 3456 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574343536376e \\(balance: 4567 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); } - - fn make_payables( - now: SystemTime, - payment_thresholds: PaymentThresholds, - ) -> ( - Vec, - Vec, - Vec, - ) { - let mut unqualified_payable_accounts = vec![PayableAccount { - wallet: make_wallet("wallet1"), - balance: payment_thresholds.permanent_debt_allowed_gwei + 1, - last_paid_timestamp: from_time_t( - to_time_t(now) - payment_thresholds.maturity_threshold_sec + 1, - ), - pending_payable_opt: None, - }]; - let mut qualified_payable_accounts = vec![ - PayableAccount { - wallet: make_wallet("wallet2"), - balance: payment_thresholds.permanent_debt_allowed_gwei + 1_000_000_000, - last_paid_timestamp: from_time_t( - to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1, - ), - pending_payable_opt: None, - }, - PayableAccount { - wallet: make_wallet("wallet3"), - balance: payment_thresholds.permanent_debt_allowed_gwei + 1_200_000_000, - last_paid_timestamp: from_time_t( - to_time_t(now) - payment_thresholds.maturity_threshold_sec - 100, - ), - pending_payable_opt: None, - }, - ]; - - let mut all_non_pending_payables = Vec::new(); - all_non_pending_payables.extend(qualified_payable_accounts.clone()); - all_non_pending_payables.extend(unqualified_payable_accounts.clone()); - - ( - qualified_payable_accounts, - unqualified_payable_accounts, - all_non_pending_payables, - ) - } } diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index b8eae4f7f..ac0b49ee7 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -912,6 +912,52 @@ pub fn make_pending_payable_fingerprint() -> PendingPayableFingerprint { } } +pub fn make_payables( + now: SystemTime, + payment_thresholds: &PaymentThresholds, +) -> ( + Vec, + Vec, + Vec, +) { + let mut unqualified_payable_accounts = vec![PayableAccount { + wallet: make_wallet("wallet1"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec + 1, + ), + pending_payable_opt: None, + }]; + let mut qualified_payable_accounts = vec![ + PayableAccount { + wallet: make_wallet("wallet2"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1_000_000_000, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1, + ), + pending_payable_opt: None, + }, + PayableAccount { + wallet: make_wallet("wallet3"), + balance: payment_thresholds.permanent_debt_allowed_gwei + 1_200_000_000, + last_paid_timestamp: from_time_t( + to_time_t(now) - payment_thresholds.maturity_threshold_sec - 100, + ), + pending_payable_opt: None, + }, + ]; + + let mut all_non_pending_payables = Vec::new(); + all_non_pending_payables.extend(qualified_payable_accounts.clone()); + all_non_pending_payables.extend(unqualified_payable_accounts.clone()); + + ( + qualified_payable_accounts, + unqualified_payable_accounts, + all_non_pending_payables, + ) +} + //warning: this test function will not tell you anything about the transaction record in the pending_payable table pub fn account_status(conn: &Connection, wallet: &Wallet) -> Option { let mut stmt = conn From ea1049c4e771907783030ea6d75ed167d1246ca0 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 1 Sep 2022 12:45:36 +0530 Subject: [PATCH 059/145] GH-611: fix the test accountant_sends_a_request_to_blockchain_bridge_to_scan_for_received_payments --- node/src/accountant/mod.rs | 31 ++++++++++--------------------- node/src/accountant/scanners.rs | 4 ++-- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index e40f180b5..7f0b5c659 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -185,7 +185,6 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { - // self.handle_scan_message(&mut self.scanners.payables, msg.response_skeleton_opt, ctx) match self.scanners.payables.begin_scan( SystemTime::now(), msg.response_skeleton_opt, @@ -209,11 +208,6 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPendingPayables, ctx: &mut Self::Context) -> Self::Result { - // self.handle_scan_message( - // &mut self.scanners.pending_payables, - // msg.response_skeleton_opt, - // ctx, - // ) match self.scanners.pending_payables.begin_scan( SystemTime::now(), msg.response_skeleton_opt, @@ -234,19 +228,17 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForReceivables, ctx: &mut Self::Context) -> Self::Result { - // self.handle_scan_message( - // &mut self.scanners.receivables, - // msg.response_skeleton_opt, - // ctx, - // ); match self.scanners.receivables.begin_scan( SystemTime::now(), msg.response_skeleton_opt, &self.logger, ) { - Ok(message) => { - todo!("send the message to blockchain bridge"); - } + Ok(message) => self + .retrieve_transactions_sub + .as_ref() + .expect("BlockchainBridge is unbound") + .try_send(message) + .expect("BlockchainBridge is dead"), Err(e) if e.contains("Called from NullScanner") => { eprintln!("Receivable scan is disabled.") } @@ -1940,7 +1932,6 @@ mod tests { let system = System::new( "accountant_sends_a_request_to_blockchain_bridge_to_scan_for_received_payments", ); - let payable_dao = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao = ReceivableDaoMock::new() .new_delinquencies_result(vec![]) .paid_delinquencies_result(vec![]); @@ -1950,13 +1941,11 @@ mod tests { make_payment_thresholds_with_defaults(), earning_wallet.clone(), )) - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .receivable_dao(receivable_dao) // For Accountant - .receivable_dao(ReceivableDaoMock::new()) // For Scanner + .receivable_dao(ReceivableDaoMock::new()) // For Accountant + .receivable_dao(receivable_dao) // For Scanner .build(); - subject.scanners.pending_payables = Box::new(ScannerMock::new()); - subject.scanners.payables = Box::new(ScannerMock::new()); + subject.scanners.pending_payables = Box::new(NullScanner::new()); + subject.scanners.payables = Box::new(NullScanner::new()); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 8029eac12..73a5d4f98 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -592,8 +592,8 @@ mod tests { init_test_logging(); let test_name = "receivable_scanner_can_initiate_a_scan"; let receivable_dao = ReceivableDaoMock::new() - .new_delinquencies_result(vec![make_receivable_account(1234, true)]) - .paid_delinquencies_result(vec![make_receivable_account(4321, false)]); + .new_delinquencies_result(vec![]) + .paid_delinquencies_result(vec![]); let banned_dao = BannedDaoMock::new(); let payment_thresholds = make_payment_thresholds_with_defaults(); let earning_wallet = make_wallet("earning"); From d451a7e56028d1bbecf39f56b6642fba99f70536 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 1 Sep 2022 13:24:00 +0530 Subject: [PATCH 060/145] GH-611: fix test scan_for_pending_payable_found_unresolved_pending_payable_and_urges_their_processing --- node/src/accountant/mod.rs | 61 ++++++++++++++++++--------------- node/src/accountant/scanners.rs | 1 - 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 7f0b5c659..c4d57c925 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -78,6 +78,7 @@ pub struct Accountant { financial_statistics: FinancialStatistics, report_accounts_payable_sub_opt: Option>, retrieve_transactions_sub: Option>, + request_transaction_receipts_subs_opt: Option>, report_new_payments_sub: Option>, report_sent_payments_sub: Option>, ui_message_sub: Option>, @@ -213,9 +214,12 @@ impl Handler for Accountant { msg.response_skeleton_opt, &self.logger, ) { - Ok(message) => { - todo!("send the message to blockchain bridge"); - } + Ok(message) => self + .request_transaction_receipts_subs_opt + .as_ref() + .expect("BlockchainBridge is unbound") + .try_send(message) + .expect("BlockchainBridge is dead"), Err(e) if e.contains("Called from NullScanner") => { eprintln!("Pending payable scan is disabled.") } @@ -474,6 +478,7 @@ impl Accountant { financial_statistics: FinancialStatistics::default(), report_accounts_payable_sub_opt: None, retrieve_transactions_sub: None, + request_transaction_receipts_subs_opt: None, report_new_payments_sub: None, report_sent_payments_sub: None, ui_message_sub: None, @@ -572,26 +577,27 @@ impl Accountant { } fn scan_for_pending_payable(&self, response_skeleton_opt: Option) { - info!(self.logger, "Scanning for pending payable"); - let filtered_pending_payable = self.pending_payable_dao.return_all_fingerprints(); - if filtered_pending_payable.is_empty() { - debug!(self.logger, "No pending payable found during last scan") - } else { - debug!( - self.logger, - "Found {} pending payables to process", - filtered_pending_payable.len() - ); - self.tools - .request_transaction_receipts_subs_opt - .as_ref() - .expect("BlockchainBridge is unbound") - .try_send(RequestTransactionReceipts { - pending_payable: filtered_pending_payable, - response_skeleton_opt, - }) - .expect("BlockchainBridge is dead"); - } + todo!("remove this fn"); + // info!(self.logger, "Scanning for pending payable"); + // let filtered_pending_payable = self.pending_payable_dao.return_all_fingerprints(); + // if filtered_pending_payable.is_empty() { + // debug!(self.logger, "No pending payable found during last scan") + // } else { + // debug!( + // self.logger, + // "Found {} pending payables to process", + // filtered_pending_payable.len() + // ); + // self.tools + // .request_transaction_receipts_subs_opt + // .as_ref() + // .expect("BlockchainBridge is unbound") + // .try_send(RequestTransactionReceipts { + // pending_payable: filtered_pending_payable, + // response_skeleton_opt, + // }) + // .expect("BlockchainBridge is dead"); + // } } fn record_service_provided( @@ -674,7 +680,7 @@ impl Accountant { self.report_new_payments_sub = Some(msg.peer_actors.accountant.report_new_payments); self.report_sent_payments_sub = Some(msg.peer_actors.accountant.report_sent_payments); self.ui_message_sub = Some(msg.peer_actors.ui_gateway.node_to_ui_message_sub); - self.tools.request_transaction_receipts_subs_opt = Some( + self.request_transaction_receipts_subs_opt = Some( msg.peer_actors .blockchain_bridge .request_transaction_receipts, @@ -2842,13 +2848,12 @@ mod tests { ); let system = System::new("pending payable scan"); let mut subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Scanner .bootstrapper_config(config) .build(); let blockchain_bridge_addr = blockchain_bridge.start(); - subject.tools.request_transaction_receipts_subs_opt = - Some(blockchain_bridge_addr.recipient()); + subject.request_transaction_receipts_subs_opt = Some(blockchain_bridge_addr.recipient()); let account_addr = subject.start(); let _ = account_addr diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 73a5d4f98..69410e6e4 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -416,7 +416,6 @@ pub(in crate::accountant) mod scanners { Box>, pub notify_cancel_failed_transaction: Box>, - pub request_transaction_receipts_subs_opt: Option>, } } From 634b49dd6cca7a91abf40e51d814a54d9882d06d Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 1 Sep 2022 13:32:15 +0530 Subject: [PATCH 061/145] GH-611: remove the code from accountant/mod.rs that has been moved to scanners.rs --- node/src/accountant/mod.rs | 158 ------------------------------------- 1 file changed, 158 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index c4d57c925..f3963e97d 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -527,79 +527,6 @@ impl Accountant { // // TODO: migrate the scanner.notify_later_assertable(self, ctx) to begin_scan() // } - fn scan_for_delinquencies(&self) { - todo!("migrate the below fn to scanners"); - // info!(self.logger, "Scanning for delinquencies"); - // let now = SystemTime::now(); - // self.receivable_dao - // .new_delinquencies(now, &self.config.payment_thresholds) - // .into_iter() - // .for_each(|account| { - // self.banned_dao.ban(&account.wallet); - // let (balance, age) = Self::balance_and_age(&account); - // info!( - // self.logger, - // "Wallet {} (balance: {} MASQ, age: {} sec) banned for delinquency", - // account.wallet, - // balance, - // age.as_secs() - // ) - // }); - // self.receivable_dao - // .paid_delinquencies(&self.config.payment_thresholds) - // .into_iter() - // .for_each(|account| { - // self.banned_dao.unban(&account.wallet); - // let (balance, age) = Self::balance_and_age(&account); - // info!( - // self.logger, - // "Wallet {} (balance: {} MASQ, age: {} sec) is no longer delinquent: unbanned", - // account.wallet, - // balance, - // age.as_secs() - // ) - // }); - } - - fn scan_for_receivables(&self, response_skeleton_opt: Option) { - // info!( - // self.logger, - // "Scanning for receivables to {}", self.earning_wallet - // ); - // self.retrieve_transactions_sub - // .as_ref() - // .expect("BlockchainBridge is unbound") - // .try_send(RetrieveTransactions { - // recipient: self.earning_wallet.clone(), - // response_skeleton_opt, - // }) - // .expect("BlockchainBridge is dead"); - } - - fn scan_for_pending_payable(&self, response_skeleton_opt: Option) { - todo!("remove this fn"); - // info!(self.logger, "Scanning for pending payable"); - // let filtered_pending_payable = self.pending_payable_dao.return_all_fingerprints(); - // if filtered_pending_payable.is_empty() { - // debug!(self.logger, "No pending payable found during last scan") - // } else { - // debug!( - // self.logger, - // "Found {} pending payables to process", - // filtered_pending_payable.len() - // ); - // self.tools - // .request_transaction_receipts_subs_opt - // .as_ref() - // .expect("BlockchainBridge is unbound") - // .try_send(RequestTransactionReceipts { - // pending_payable: filtered_pending_payable, - // response_skeleton_opt, - // }) - // .expect("BlockchainBridge is dead"); - // } - } - fn record_service_provided( &self, service_rate: u64, @@ -2616,91 +2543,6 @@ mod tests { ); } - #[test] - fn scan_for_delinquencies_triggers_bans_and_unbans() { - init_test_logging(); - let accountant_config = make_populated_accountant_config_with_defaults(); - let config = bc_from_ac_plus_earning_wallet( - accountant_config, - make_payment_thresholds_with_defaults(), - make_wallet("mine"), - ); - let newly_banned_1 = make_receivable_account(1234, true); - let newly_banned_2 = make_receivable_account(2345, true); - let newly_unbanned_1 = make_receivable_account(3456, false); - let newly_unbanned_2 = make_receivable_account(4567, false); - let payable_dao = PayableDaoMock::new().non_pending_payables_result(vec![]); - let new_delinquencies_parameters_arc = Arc::new(Mutex::new(vec![])); - let paid_delinquencies_parameters_arc = Arc::new(Mutex::new(vec![])); - let receivable_dao = ReceivableDaoMock::new() - .new_delinquencies_parameters(&new_delinquencies_parameters_arc) - .new_delinquencies_result(vec![newly_banned_1.clone(), newly_banned_2.clone()]) - .paid_delinquencies_parameters(&paid_delinquencies_parameters_arc) - .paid_delinquencies_result(vec![newly_unbanned_1.clone(), newly_unbanned_2.clone()]); - let ban_parameters_arc = Arc::new(Mutex::new(vec![])); - let unban_parameters_arc = Arc::new(Mutex::new(vec![])); - let banned_dao = BannedDaoMock::new() - .ban_list_result(vec![]) - .ban_parameters(&ban_parameters_arc) - .unban_parameters(&unban_parameters_arc); - let subject = AccountantBuilder::default() - .bootstrapper_config(config) - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .receivable_dao(receivable_dao) // For Accountant - .receivable_dao(ReceivableDaoMock::new()) // For Scanner - .banned_dao(banned_dao) - .build(); - - subject.scan_for_delinquencies(); - - let new_delinquencies_parameters: MutexGuard> = - new_delinquencies_parameters_arc.lock().unwrap(); - assert_eq!( - DEFAULT_PAYMENT_THRESHOLDS.clone(), - new_delinquencies_parameters[0].1 - ); - let paid_delinquencies_parameters: MutexGuard> = - paid_delinquencies_parameters_arc.lock().unwrap(); - assert_eq!( - DEFAULT_PAYMENT_THRESHOLDS.clone(), - paid_delinquencies_parameters[0] - ); - let ban_parameters = ban_parameters_arc.lock().unwrap(); - assert!(ban_parameters.contains(&newly_banned_1.wallet)); - assert!(ban_parameters.contains(&newly_banned_2.wallet)); - assert_eq!(2, ban_parameters.len()); - let unban_parameters = unban_parameters_arc.lock().unwrap(); - assert!(unban_parameters.contains(&newly_unbanned_1.wallet)); - assert!(unban_parameters.contains(&newly_unbanned_2.wallet)); - assert_eq!(2, unban_parameters.len()); - let tlh = TestLogHandler::new(); - tlh.exists_log_matching("INFO: Accountant: Wallet 0x00000000000000000077616c6c65743132333464 \\(balance: 1234 MASQ, age: \\d+ sec\\) banned for delinquency"); - tlh.exists_log_matching("INFO: Accountant: Wallet 0x00000000000000000077616c6c65743233343564 \\(balance: 2345 MASQ, age: \\d+ sec\\) banned for delinquency"); - tlh.exists_log_matching("INFO: Accountant: Wallet 0x00000000000000000077616c6c6574333435366e \\(balance: 3456 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); - tlh.exists_log_matching("INFO: Accountant: Wallet 0x00000000000000000077616c6c6574343536376e \\(balance: 4567 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); - } - - #[test] - fn scan_for_pending_payable_found_no_pending_payable() { - init_test_logging(); - let return_all_backup_records_params_arc = Arc::new(Mutex::new(vec![])); - let pending_payable_dao = PendingPayableDaoMock::default() - .return_all_fingerprints_params(&return_all_backup_records_params_arc) - .return_all_fingerprints_result(vec![]); - let subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner - .build(); - - let _ = subject.scan_for_pending_payable(None); - - let return_all_backup_records_params = return_all_backup_records_params_arc.lock().unwrap(); - assert_eq!(*return_all_backup_records_params, vec![()]); - TestLogHandler::new() - .exists_log_containing("DEBUG: Accountant: No pending payable found during last scan"); - } - #[test] fn accountant_starts_a_scan_in_case_it_receives_the_message_and_scan_is_not_running() { let payable_dao = PayableDaoMock::default(); From 5473ad7a8e1228091d4c8a3dc524672f345881eb Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 1 Sep 2022 13:54:11 +0530 Subject: [PATCH 062/145] GH-611: add ScannerError --- node/src/accountant/mod.rs | 8 ++++---- node/src/accountant/scanners.rs | 25 ++++++++++++++----------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index f3963e97d..1c8e2dd8d 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -17,7 +17,7 @@ use crate::accountant::payable_dao::{Payable, PayableAccount, PayableDaoError, P use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDaoFactory}; use crate::accountant::receivable_dao::{ReceivableDaoError, ReceivableDaoFactory}; use crate::accountant::scanners::scanners::{ - NotifyLaterForScanners, Scanners, TransactionConfirmationTools, + NotifyLaterForScanners, ScannerError, Scanners, TransactionConfirmationTools, }; use crate::banned_dao::{BannedDao, BannedDaoFactory}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; @@ -197,7 +197,7 @@ impl Handler for Accountant { .expect("BlockchainBridge is unbound") .try_send(message) .expect("BlockchainBridge is dead"), - Err(e) if e.contains("Called from NullScanner") => { + Err(ScannerError::CalledFromNullScanner) => { eprintln!("Payable scan is disabled."); } Err(e) => todo!("Use logger to print out the error message"), @@ -220,7 +220,7 @@ impl Handler for Accountant { .expect("BlockchainBridge is unbound") .try_send(message) .expect("BlockchainBridge is dead"), - Err(e) if e.contains("Called from NullScanner") => { + Err(ScannerError::CalledFromNullScanner) => { eprintln!("Pending payable scan is disabled.") } Err(e) => todo!("Use logger to print out the error message"), @@ -243,7 +243,7 @@ impl Handler for Accountant { .expect("BlockchainBridge is unbound") .try_send(message) .expect("BlockchainBridge is dead"), - Err(e) if e.contains("Called from NullScanner") => { + Err(ScannerError::CalledFromNullScanner) => { eprintln!("Receivable scan is disabled.") } Err(e) => todo!("Use logger to print out the error message"), diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 69410e6e4..35a89b5f8 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -28,7 +28,13 @@ pub(in crate::accountant) mod scanners { use std::sync::{Arc, Mutex}; use std::time::SystemTime; - type Error = String; + #[derive(Debug, PartialEq, Eq)] + pub enum ScannerError { + NothingToProcess, + CalledFromNullScanner, // Exclusive for tests + } + + type Error = ScannerError; pub struct Scanners { pub payables: Box>, @@ -131,7 +137,7 @@ pub(in crate::accountant) mod scanners { ); debug!(logger, "{}", summary); match qualified_payables.is_empty() { - true => Err(summary), + true => Err(ScannerError::NothingToProcess), false => Ok(ReportAccountsPayable { accounts: qualified_payables, response_skeleton_opt, @@ -182,7 +188,7 @@ pub(in crate::accountant) mod scanners { logger, "Pending payable scan ended. No pending payable found." ); - Err(String::from("No pending payable found.")) + Err(ScannerError::NothingToProcess) } false => { debug!( @@ -320,7 +326,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { - Err(String::from("Called from NullScanner")) + Err(ScannerError::CalledFromNullScanner) } fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { @@ -359,10 +365,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { - self.begin_scan_params - .borrow_mut() - .push((timestamp, response_skeleton_opt)); - Err(String::from("Called from ScannerMock")) + todo!() } fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { @@ -424,7 +427,7 @@ mod tests { use crate::accountant::payable_dao::PayableAccount; use crate::accountant::scanners::scanners::{ - PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, Scanners, + PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, ScannerError, Scanners, }; use crate::accountant::test_utils::{ make_payables, make_receivable_account, BannedDaoMock, PayableDaoMock, @@ -518,7 +521,7 @@ mod tests { let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); - assert_eq!(result, Err(String::from("No Qualified Payables found."))); + assert_eq!(result, Err(ScannerError::NothingToProcess)); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for payables", test_name), "Chose 0 qualified debts to pay", @@ -576,7 +579,7 @@ mod tests { let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); - assert_eq!(result, Err(String::from("No pending payable found."))); + assert_eq!(result, Err(ScannerError::NothingToProcess)); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for pending payable", test_name), &format!( From 4c3248d5d7b3da9691c93e21d65e4749f781813a Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 1 Sep 2022 15:51:47 +0530 Subject: [PATCH 063/145] GH-611: fix accountant_scans_after_startup --- node/src/accountant/mod.rs | 92 +++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 1c8e2dd8d..3fbf48e28 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -198,9 +198,16 @@ impl Handler for Accountant { .try_send(message) .expect("BlockchainBridge is dead"), Err(ScannerError::CalledFromNullScanner) => { - eprintln!("Payable scan is disabled."); + if cfg!(test) { + eprintln!("Payable scan is disabled."); + } else { + panic!("Null Scanner shouldn't be running inside production code.") + } + } + Err(ScannerError::NothingToProcess) => { + eprintln!("No payable found to process. The Scan was ended."); + // TODO: Do something better than just using eprintln } - Err(e) => todo!("Use logger to print out the error message"), } } } @@ -221,9 +228,16 @@ impl Handler for Accountant { .try_send(message) .expect("BlockchainBridge is dead"), Err(ScannerError::CalledFromNullScanner) => { - eprintln!("Pending payable scan is disabled.") + if cfg!(test) { + eprintln!("Pending payable scan is disabled."); + } else { + panic!("Null Scanner shouldn't be running inside production code.") + } + } + Err(ScannerError::NothingToProcess) => { + eprintln!("No pending payable found to process. The Scan was ended."); + // TODO: Do something better than just using eprintln } - Err(e) => todo!("Use logger to print out the error message"), } } } @@ -244,9 +258,16 @@ impl Handler for Accountant { .try_send(message) .expect("BlockchainBridge is dead"), Err(ScannerError::CalledFromNullScanner) => { - eprintln!("Receivable scan is disabled.") + if cfg!(test) { + eprintln!("Receivable scan is disabled."); + } else { + panic!("Null Scanner shouldn't be running inside production code.") + } + } + Err(ScannerError::NothingToProcess) => { + eprintln!("The Scan was ended."); + // TODO: Do something better than just using eprintln } - Err(e) => todo!("Use logger to print out the error message"), }; } } @@ -1953,46 +1974,38 @@ mod tests { #[test] fn accountant_scans_after_startup() { init_test_logging(); - let return_all_fingerprints_params_arc = Arc::new(Mutex::new(vec![])); - let non_pending_payables_params_arc = Arc::new(Mutex::new(vec![])); + let pending_payable_params_arc = Arc::new(Mutex::new(vec![])); + let payable_params_arc = Arc::new(Mutex::new(vec![])); let new_delinquencies_params_arc = Arc::new(Mutex::new(vec![])); let paid_delinquencies_params_arc = Arc::new(Mutex::new(vec![])); let (blockchain_bridge, _, _) = make_recorder(); + let earning_wallet = make_wallet("earning"); let system = System::new("accountant_scans_after_startup"); let config = bc_from_ac_plus_wallets( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_secs(100), //making sure we cannot enter the first repeated scanning - receivable_scan_interval: Duration::from_secs(100), - pending_payable_scan_interval: Duration::from_millis(100), //except here, where we use it to stop the system - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: false, - }, + make_populated_accountant_config_with_defaults(), make_payment_thresholds_with_defaults(), make_wallet("buy"), - make_wallet("hi"), + earning_wallet.clone(), ); + let payable_dao = PayableDaoMock::new() + .non_pending_payables_params(&payable_params_arc) + .non_pending_payables_result(vec![]); let mut pending_payable_dao = PendingPayableDaoMock::default() - .return_all_fingerprints_params(&return_all_fingerprints_params_arc) + .return_all_fingerprints_params(&pending_payable_params_arc) .return_all_fingerprints_result(vec![]); - pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; let receivable_dao = ReceivableDaoMock::new() .new_delinquencies_parameters(&new_delinquencies_params_arc) .new_delinquencies_result(vec![]) .paid_delinquencies_parameters(&paid_delinquencies_params_arc) .paid_delinquencies_result(vec![]); - let payable_dao = PayableDaoMock::new() - .non_pending_payables_params(&non_pending_payables_params_arc) - .non_pending_payables_result(vec![]); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner - .receivable_dao(receivable_dao) // For Accountant - .receivable_dao(ReceivableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Scanner + .receivable_dao(ReceivableDaoMock::new()) // For Accountant + .receivable_dao(receivable_dao) // For Scanner .build(); let peer_actors = peer_actors_builder() .blockchain_bridge(blockchain_bridge) @@ -2003,33 +2016,30 @@ mod tests { send_start_message!(subject_subs); + System::current().stop(); system.run(); let tlh = TestLogHandler::new(); - tlh.await_log_containing("INFO: Accountant: Scanning for payables", 1000); + tlh.exists_log_containing("INFO: Accountant: Scanning for payables"); + tlh.exists_log_containing("INFO: Accountant: Scanning for pending payable"); tlh.exists_log_containing(&format!( "INFO: Accountant: Scanning for receivables to {}", - make_wallet("hi") + earning_wallet )); tlh.exists_log_containing("INFO: Accountant: Scanning for delinquencies"); - tlh.exists_log_containing("INFO: Accountant: Scanning for pending payable"); - //some more weak proofs but still good enough - //proof of calling a piece of scan_for_pending_payable - let return_all_fingerprints_params = return_all_fingerprints_params_arc.lock().unwrap(); - //the last ends this test calling System::current.stop() - assert_eq!(*return_all_fingerprints_params, vec![(), ()]); - //proof of calling a piece of scan_for_payable() - let non_pending_payables_params = non_pending_payables_params_arc.lock().unwrap(); - assert_eq!(*non_pending_payables_params, vec![()]); + let payable_params = payable_params_arc.lock().unwrap(); + let pending_payable_params = pending_payable_params_arc.lock().unwrap(); //proof of calling pieces of scan_for_delinquencies() let mut new_delinquencies_params = new_delinquencies_params_arc.lock().unwrap(); let (captured_timestamp, captured_curves) = new_delinquencies_params.remove(0); + let paid_delinquencies_params = paid_delinquencies_params_arc.lock().unwrap(); + assert_eq!(*payable_params, vec![()]); + assert_eq!(*pending_payable_params, vec![()]); assert!(new_delinquencies_params.is_empty()); assert!( captured_timestamp < SystemTime::now() && captured_timestamp >= from_time_t(to_time_t(SystemTime::now()) - 5) ); assert_eq!(captured_curves, make_payment_thresholds_with_defaults()); - let paid_delinquencies_params = paid_delinquencies_params_arc.lock().unwrap(); assert_eq!(paid_delinquencies_params.len(), 1); assert_eq!( paid_delinquencies_params[0], From 534197eb075afcec72ad03463dcb4012f48eca3e Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 1 Sep 2022 17:17:47 +0530 Subject: [PATCH 064/145] GH-611: refactor handlers for scan requests in accountant/mod.rs --- node/src/accountant/mod.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 3fbf48e28..3cef80665 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -191,12 +191,14 @@ impl Handler for Accountant { msg.response_skeleton_opt, &self.logger, ) { - Ok(message) => self - .report_accounts_payable_sub_opt - .as_ref() - .expect("BlockchainBridge is unbound") - .try_send(message) - .expect("BlockchainBridge is dead"), + Ok(message) => { + // todo!("message was returned"); + self.report_accounts_payable_sub_opt + .as_ref() + .expect("BlockchainBridge is unbound") + .try_send(message) + .expect("BlockchainBridge is dead") + } Err(ScannerError::CalledFromNullScanner) => { if cfg!(test) { eprintln!("Payable scan is disabled."); @@ -2466,8 +2468,8 @@ mod tests { blockchain_bridge_addr.recipient::(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); @@ -2522,7 +2524,7 @@ mod tests { let mut payable_dao = PayableDaoMock::default() .non_pending_payables_result(accounts.clone()) .non_pending_payables_result(vec![]); - payable_dao.have_non_pending_payables_shut_down_the_system = true; + // payable_dao.have_non_pending_payables_shut_down_the_system = true; let (blockchain_bridge, _, blockchain_bridge_recordings_arc) = make_recorder(); let system = System::new("scan_for_payable_message_triggers_payment_for_balances_over_the_curve"); @@ -2531,17 +2533,18 @@ mod tests { .build(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner .build(); - subject.scanners.pending_payables = Box::new(ScannerMock::new()); - subject.scanners.receivables = Box::new(ScannerMock::new()); + subject.scanners.pending_payables = Box::new(NullScanner::new()); + subject.scanners.receivables = Box::new(NullScanner::new()); let subject_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&subject_addr); send_bind_message!(accountant_subs, peer_actors); send_start_message!(accountant_subs); + System::current().stop(); system.run(); let blockchain_bridge_recordings = blockchain_bridge_recordings_arc.lock().unwrap(); assert_eq!( @@ -2735,6 +2738,7 @@ mod tests { fn report_routing_service_provided_message_is_received() { init_test_logging(); let mut bootstrapper_config = BootstrapperConfig::default(); + bootstrapper_config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); bootstrapper_config.accountant_config_opt = Some(make_accountant_config_null()); bootstrapper_config.earning_wallet = make_wallet("hi"); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); From 83071da26192d3d60eefb3747f8fdfbaf28faaa8 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 1 Sep 2022 17:26:14 +0530 Subject: [PATCH 065/145] GH-611: fix more tests inside accountant/mod.rs --- node/src/accountant/mod.rs | 23 +++++++++++++---------- node/src/accountant/scanners.rs | 2 +- node/src/accountant/test_utils.rs | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 3cef80665..37a5720e1 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -192,12 +192,12 @@ impl Handler for Accountant { &self.logger, ) { Ok(message) => { - // todo!("message was returned"); + eprintln!("Message was sent to the blockchain bridge, {:?}", message); self.report_accounts_payable_sub_opt .as_ref() .expect("BlockchainBridge is unbound") .try_send(message) - .expect("BlockchainBridge is dead") + .expect("BlockchainBridge is dead"); } Err(ScannerError::CalledFromNullScanner) => { if cfg!(test) { @@ -1173,6 +1173,7 @@ mod tests { fn new_calls_factories_properly() { let mut config = BootstrapperConfig::new(); config.accountant_config_opt = Some(make_accountant_config_null()); + config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); let payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let pending_payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let receivable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); @@ -2092,10 +2093,11 @@ mod tests { .bootstrapper_config(config) .receivable_dao(receivable_dao) .receivable_dao(ReceivableDaoMock::new()) + .banned_dao(BannedDaoMock::new()) .banned_dao(banned_dao) .build(); - subject.scanners.pending_payables = Box::new(ScannerMock::new()); - subject.scanners.payables = Box::new(ScannerMock::new()); + subject.scanners.pending_payables = Box::new(NullScanner::new()); + subject.scanners.payables = Box::new(NullScanner::new()); subject.notify_later.scan_for_receivable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_receivable_params_arc) @@ -2313,8 +2315,8 @@ mod tests { .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner .build(); - subject.scanners.pending_payables = Box::new(ScannerMock::new()); //skipping - subject.scanners.receivables = Box::new(ScannerMock::new()); //skipping + subject.scanners.pending_payables = Box::new(NullScanner::new()); //skipping + subject.scanners.receivables = Box::new(NullScanner::new()); //skipping subject.notify_later.scan_for_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_payables_params_arc) @@ -2521,9 +2523,8 @@ mod tests { pending_payable_opt: None, }, ]; - let mut payable_dao = PayableDaoMock::default() - .non_pending_payables_result(accounts.clone()) - .non_pending_payables_result(vec![]); + let mut payable_dao = + PayableDaoMock::default().non_pending_payables_result(accounts.clone()); // payable_dao.have_non_pending_payables_shut_down_the_system = true; let (blockchain_bridge, _, blockchain_bridge_recordings_arc) = make_recorder(); let system = @@ -2547,8 +2548,9 @@ mod tests { System::current().stop(); system.run(); let blockchain_bridge_recordings = blockchain_bridge_recordings_arc.lock().unwrap(); + let message = blockchain_bridge_recordings.get_record::(0); assert_eq!( - blockchain_bridge_recordings.get_record::(0), + message, &ReportAccountsPayable { accounts, response_skeleton_opt: None, @@ -3688,6 +3690,7 @@ mod tests { )] fn accountant_can_be_crashed_properly_but_not_improperly() { let mut config = BootstrapperConfig::default(); + config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); config.crash_point = CrashPoint::Message; config.accountant_config_opt = Some(make_accountant_config_null()); let accountant = AccountantBuilder::default() diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 35a89b5f8..941a020a4 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -365,7 +365,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { - todo!() + todo!("Implement ScannerMock") } fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index ac0b49ee7..b807db7f8 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -275,7 +275,7 @@ impl BannedDaoFactory for BannedDaoFactoryMock { fn make(&self) -> Box { if self.make_results.borrow().len() == 0 { panic!( - "BannedDao Missing. This problem mostly occurs when ReceivableDao is only supplied for Accountant and not for the Scanner while building Accountant." + "BannedDao Missing. This problem mostly occurs when BannedDao is only supplied for Accountant and not for the Scanner while building Accountant." ) }; self.make_params.lock().unwrap().push(()); From d5e37b11f672fadf3391e21df6c28f0f6a65532c Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 2 Sep 2022 12:51:21 +0530 Subject: [PATCH 066/145] GH-611: reorder dao in tests for Accountant and Scanner, and replace ScannerMock with NullScanner --- node/src/accountant/mod.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 37a5720e1..d9519c2f2 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1123,7 +1123,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::accountant::receivable_dao::ReceivableAccount; - use crate::accountant::scanners::scanners::{NullScanner, ScannerMock}; + use crate::accountant::scanners::scanners::NullScanner; use crate::accountant::test_utils::{ bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_payables, make_pending_payable_fingerprint, make_receivable_account, BannedDaoFactoryMock, @@ -1159,10 +1159,6 @@ mod tests { use masq_lib::logger::timestamp_as_string; use web3::types::{TransactionReceipt, H256}; - // fn Box::new(ScannerMock::new()) -> Scanner { - // Scanner::new(ScanType::Payables, Box::new(|_, _| {}), Box::new(|_, _| {})) - // } - #[test] fn constants_have_correct_values() { assert_eq!(CRASH_KEY, "ACCOUNTANT"); @@ -2213,8 +2209,8 @@ mod tests { .pending_payable_dao(pending_payable_dao) // For Accountant .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); - subject.scanners.receivables = Box::new(ScannerMock::new()); //skipping - subject.scanners.payables = Box::new(ScannerMock::new()); //skipping + subject.scanners.receivables = Box::new(NullScanner::new()); //skipping + subject.scanners.payables = Box::new(NullScanner::new()); //skipping subject.notify_later.scan_for_pending_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_pending_payable_params_arc) @@ -3885,12 +3881,12 @@ mod tests { .start(move |_| { let mut subject = AccountantBuilder::default() .bootstrapper_config(bootstrapper_config) - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) + .payable_dao(payable_dao) + .pending_payable_dao(PendingPayableDaoMock::new()) + .pending_payable_dao(pending_payable_dao) .build(); - subject.scanners.receivables = Box::new(ScannerMock::new()); + subject.scanners.receivables = Box::new(NullScanner::new()); let notify_later_half_mock = NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_scan_for_pending_payable_arc_cloned) .permit_to_send_out(); From 1bc0b463f67bc44a160d33988b7d79c6ce064c86 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 2 Sep 2022 13:21:00 +0530 Subject: [PATCH 067/145] GH-611: use the timestamp from the function parameter for scanners --- node/src/accountant/scanners.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 941a020a4..abd773208 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -117,7 +117,6 @@ pub(in crate::accountant) mod scanners { // let start_message = BeginScanAMessage {}; // // Use the DAO, if necessary, to populate start_message // Ok(start_message) - let now = SystemTime::now(); info!(logger, "Scanning for payables"); let all_non_pending_payables = self.dao.non_pending_payables(); debug!( @@ -126,7 +125,7 @@ pub(in crate::accountant) mod scanners { investigate_debt_extremes(&all_non_pending_payables) ); let (qualified_payables, summary) = qualified_payables_and_summary( - now, + timestamp, all_non_pending_payables, self.common.payment_thresholds.as_ref(), ); @@ -241,18 +240,17 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { - let now = SystemTime::now(); info!( logger, "Scanning for receivables to {}", self.earning_wallet ); info!(logger, "Scanning for delinquencies"); self.dao - .new_delinquencies(now, self.common.payment_thresholds.as_ref()) + .new_delinquencies(timestamp, self.common.payment_thresholds.as_ref()) .into_iter() .for_each(|account| { self.banned_dao.ban(&account.wallet); - let (balance, age) = balance_and_age(now, &account); + let (balance, age) = balance_and_age(timestamp, &account); info!( logger, "Wallet {} (balance: {} MASQ, age: {} sec) banned for delinquency", @@ -266,7 +264,7 @@ pub(in crate::accountant) mod scanners { .into_iter() .for_each(|account| { self.banned_dao.unban(&account.wallet); - let (balance, age) = balance_and_age(now, &account); + let (balance, age) = balance_and_age(timestamp, &account); info!( logger, "Wallet {} (balance: {} MASQ, age: {} sec) is no longer delinquent: unbanned", From 9a25fd38863fcb6f1256c90bbe9f2ae74227a374 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 2 Sep 2022 13:52:12 +0530 Subject: [PATCH 068/145] GH-611: refactor the handlers for scan requests --- node/src/accountant/mod.rs | 160 +++++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 71 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index d9519c2f2..9cc25f4af 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -186,31 +186,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { - match self.scanners.payables.begin_scan( - SystemTime::now(), - msg.response_skeleton_opt, - &self.logger, - ) { - Ok(message) => { - eprintln!("Message was sent to the blockchain bridge, {:?}", message); - self.report_accounts_payable_sub_opt - .as_ref() - .expect("BlockchainBridge is unbound") - .try_send(message) - .expect("BlockchainBridge is dead"); - } - Err(ScannerError::CalledFromNullScanner) => { - if cfg!(test) { - eprintln!("Payable scan is disabled."); - } else { - panic!("Null Scanner shouldn't be running inside production code.") - } - } - Err(ScannerError::NothingToProcess) => { - eprintln!("No payable found to process. The Scan was ended."); - // TODO: Do something better than just using eprintln - } - } + self.handle_scan_for_payable_request(msg.response_skeleton_opt); } } @@ -218,29 +194,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForPendingPayables, ctx: &mut Self::Context) -> Self::Result { - match self.scanners.pending_payables.begin_scan( - SystemTime::now(), - msg.response_skeleton_opt, - &self.logger, - ) { - Ok(message) => self - .request_transaction_receipts_subs_opt - .as_ref() - .expect("BlockchainBridge is unbound") - .try_send(message) - .expect("BlockchainBridge is dead"), - Err(ScannerError::CalledFromNullScanner) => { - if cfg!(test) { - eprintln!("Pending payable scan is disabled."); - } else { - panic!("Null Scanner shouldn't be running inside production code.") - } - } - Err(ScannerError::NothingToProcess) => { - eprintln!("No pending payable found to process. The Scan was ended."); - // TODO: Do something better than just using eprintln - } - } + self.handle_scan_for_pending_payable_request(msg.response_skeleton_opt); } } @@ -248,29 +202,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ScanForReceivables, ctx: &mut Self::Context) -> Self::Result { - match self.scanners.receivables.begin_scan( - SystemTime::now(), - msg.response_skeleton_opt, - &self.logger, - ) { - Ok(message) => self - .retrieve_transactions_sub - .as_ref() - .expect("BlockchainBridge is unbound") - .try_send(message) - .expect("BlockchainBridge is dead"), - Err(ScannerError::CalledFromNullScanner) => { - if cfg!(test) { - eprintln!("Receivable scan is disabled."); - } else { - panic!("Null Scanner shouldn't be running inside production code.") - } - } - Err(ScannerError::NothingToProcess) => { - eprintln!("The Scan was ended."); - // TODO: Do something better than just using eprintln - } - }; + self.handle_scan_for_receivables_request(msg.response_skeleton_opt); } } @@ -798,6 +730,92 @@ impl Accountant { .expect("UiGateway is dead"); } + fn handle_scan_for_payable_request(&mut self, response_skeleton_opt: Option) { + match self.scanners.payables.begin_scan( + SystemTime::now(), + response_skeleton_opt, + &self.logger, + ) { + Ok(message) => { + eprintln!("Message was sent to the blockchain bridge, {:?}", message); + self.report_accounts_payable_sub_opt + .as_ref() + .expect("BlockchainBridge is unbound") + .try_send(message) + .expect("BlockchainBridge is dead"); + } + Err(ScannerError::CalledFromNullScanner) => { + if cfg!(test) { + eprintln!("Payable scan is disabled."); + } else { + panic!("Null Scanner shouldn't be running inside production code.") + } + } + Err(ScannerError::NothingToProcess) => { + eprintln!("No payable found to process. The Scan was ended."); + // TODO: Do something better than just using eprintln + } + } + } + + fn handle_scan_for_pending_payable_request( + &mut self, + response_skeleton_opt: Option, + ) { + match self.scanners.pending_payables.begin_scan( + SystemTime::now(), + response_skeleton_opt, + &self.logger, + ) { + Ok(message) => self + .request_transaction_receipts_subs_opt + .as_ref() + .expect("BlockchainBridge is unbound") + .try_send(message) + .expect("BlockchainBridge is dead"), + Err(ScannerError::CalledFromNullScanner) => { + if cfg!(test) { + eprintln!("Pending payable scan is disabled."); + } else { + panic!("Null Scanner shouldn't be running inside production code.") + } + } + Err(ScannerError::NothingToProcess) => { + eprintln!("No pending payable found to process. The Scan was ended."); + // TODO: Do something better than just using eprintln + } + } + } + + fn handle_scan_for_receivables_request( + &mut self, + response_skeleton_opt: Option, + ) { + match self.scanners.receivables.begin_scan( + SystemTime::now(), + response_skeleton_opt, + &self.logger, + ) { + Ok(message) => self + .retrieve_transactions_sub + .as_ref() + .expect("BlockchainBridge is unbound") + .try_send(message) + .expect("BlockchainBridge is dead"), + Err(ScannerError::CalledFromNullScanner) => { + if cfg!(test) { + eprintln!("Receivable scan is disabled."); + } else { + panic!("Null Scanner shouldn't be running inside production code.") + } + } + Err(ScannerError::NothingToProcess) => { + eprintln!("The Scan was ended."); + // TODO: Do something better than just using eprintln + } + }; + } + fn handle_externally_triggered_scan( &self, _ctx: &mut Context, From ce632e91dd142f44f524f5c56a6050fe6340fd25 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 2 Sep 2022 15:06:55 +0530 Subject: [PATCH 069/145] GH-611: fix tests related to externally triggered scan --- node/src/accountant/mod.rs | 86 +++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 9cc25f4af..3a7060d1b 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -375,17 +375,14 @@ impl Handler for Accountant { if let Ok((_, context_id)) = UiFinancialsRequest::fmb(msg.body.clone()) { self.handle_financials(client_id, context_id); } else if let Ok((body, context_id)) = UiScanRequest::fmb(msg.body.clone()) { - if let Err(error) = self.handle_externally_triggered_scan( + self.handle_externally_triggered_scan( ctx, body.scan_type, ResponseSkeleton { client_id, context_id, }, - ) { - // TODO: The above fn returns a result, should we send a NodeToUIMessaage (send an info log) in case scan is already running, i.e. when we receive an error? - info!(self.logger, "{}", error); - } + ) } else { handle_ui_crash_request(msg, &self.logger, self.crashable, CRASH_KEY) } @@ -730,6 +727,50 @@ impl Accountant { .expect("UiGateway is dead"); } + // TODO: Check if it's possible to refactor the handle() for different scan requests + // fn handle_scan_request( + // &mut self, + // scan_type: ScanType, + // response_skeleton_opt: Option, + // ) { + // let (scanner, subscriber) = match scan_type { + // ScanType::Payables => ( + // &mut self.scanners.payables, + // &self.report_accounts_payable_sub_opt, + // ), + // ScanType::Receivables => ( + // &mut self.scanners.receivables, + // &self.retrieve_transactions_sub, + // ), + // ScanType::PendingPayables => ( + // &mut self.scanners.pending_payables, + // &self.request_transaction_receipts_subs_opt, + // ), + // }; + // + // match scanner.begin_scan(SystemTime::now(), response_skeleton_opt, &self.logger) { + // Ok(message) => { + // eprintln!("Message was sent to the blockchain bridge, {:?}", message); + // subscriber + // .as_ref() + // .expect("BlockchainBridge is unbound") + // .try_send(message) + // .expect("BlockchainBridge is dead"); + // } + // Err(ScannerError::CalledFromNullScanner) => { + // if cfg!(test) { + // eprintln!("{:?} is disabled.", scan_type); + // } else { + // panic!("Null Scanner shouldn't be running inside production code.") + // } + // } + // Err(ScannerError::NothingToProcess) => { + // eprintln!("No records found to process. The Scan was ended."); + // // TODO: Do something better than just using eprintln + // } + // } + // } + fn handle_scan_for_payable_request(&mut self, response_skeleton_opt: Option) { match self.scanners.payables.begin_scan( SystemTime::now(), @@ -817,23 +858,20 @@ impl Accountant { } fn handle_externally_triggered_scan( - &self, + &mut self, _ctx: &mut Context, scan_type: ScanType, response_skeleton: ResponseSkeleton, - ) -> Result<(), String> { - todo!("Implement for Externally Triggered Scan.") - // match scan_type { - // ScanType::Payables => self.scanners.payables.scan(self, Some(response_skeleton)), - // ScanType::Receivables => self - // .scanners - // .receivables - // .scan(self, Some(response_skeleton)), - // ScanType::PendingPayables => self - // .scanners - // .pending_payables - // .scan(self, Some(response_skeleton)), - // } + ) { + match scan_type { + ScanType::Payables => self.handle_scan_for_payable_request(Some(response_skeleton)), + ScanType::PendingPayables => { + self.handle_scan_for_pending_payable_request(Some(response_skeleton)); + } + ScanType::Receivables => { + self.handle_scan_for_receivables_request(Some(response_skeleton)) + } + } } fn handle_cancel_pending_transaction(&self, msg: CancelFailedPendingTransaction) { @@ -1332,8 +1370,8 @@ mod tests { .paid_delinquencies_result(vec![]); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .receivable_dao(receivable_dao) .receivable_dao(ReceivableDaoMock::new()) + .receivable_dao(receivable_dao) .build(); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); @@ -1439,8 +1477,8 @@ mod tests { PayableDaoMock::new().non_pending_payables_result(vec![payable_account.clone()]); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner .build(); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); @@ -1546,8 +1584,8 @@ mod tests { .return_all_fingerprints_result(vec![fingerprint.clone()]); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .pending_payable_dao(pending_payable_dao) // For Accountanr - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountanr + .pending_payable_dao(pending_payable_dao) // For Scanner .build(); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); From 376362fb4b57dab66ee94d1dd844630816dd06bc Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 6 Sep 2022 13:57:54 +0530 Subject: [PATCH 070/145] GH-611: fix test accountant_payable_scan_timer_triggers_periodical_scanning_for_payables --- node/src/accountant/mod.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 3a7060d1b..6ec02b616 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -187,6 +187,13 @@ impl Handler for Accountant { fn handle(&mut self, msg: ScanForPayables, ctx: &mut Self::Context) -> Self::Result { self.handle_scan_for_payable_request(msg.response_skeleton_opt); + let _ = self.notify_later.scan_for_payable.notify_later( + ScanForPayables { + response_skeleton_opt: None, + }, + self.accountant_config.scan_intervals.payable_scan_interval, + ctx, + ); } } @@ -1155,7 +1162,9 @@ impl From<&PendingPayableFingerprint> for PendingPayableId { #[cfg(test)] mod tests { use super::*; + use std::any::TypeId; use std::cell::RefCell; + use std::collections::HashMap; use std::ops::Sub; use std::rc::Rc; use std::sync::Mutex; @@ -2364,8 +2373,8 @@ mod tests { .build(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(payable_dao) // For Accountant .build(); subject.scanners.pending_payables = Box::new(NullScanner::new()); //skipping subject.scanners.receivables = Box::new(NullScanner::new()); //skipping From 7067cd4e2374815c0ca6f321ff6b52a7fe0fc26a Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 6 Sep 2022 14:03:14 +0530 Subject: [PATCH 071/145] GH-611: fix test periodical_scanning_for_pending_payable_works --- node/src/accountant/mod.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 6ec02b616..9603762e0 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -202,6 +202,15 @@ impl Handler for Accountant { fn handle(&mut self, msg: ScanForPendingPayables, ctx: &mut Self::Context) -> Self::Result { self.handle_scan_for_pending_payable_request(msg.response_skeleton_opt); + let _ = self.notify_later.scan_for_pending_payable.notify_later( + ScanForPendingPayables { + response_skeleton_opt: None, // because scheduled scans don't respond + }, + self.accountant_config + .scan_intervals + .pending_payable_scan_interval, + ctx, + ); } } @@ -2271,8 +2280,8 @@ mod tests { .build(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Scanner .build(); subject.scanners.receivables = Box::new(NullScanner::new()); //skipping subject.scanners.payables = Box::new(NullScanner::new()); //skipping From 7b7c2fac5ef6e43944f200bb46dc5870912690e2 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 6 Sep 2022 14:05:49 +0530 Subject: [PATCH 072/145] GH-611: fix periodical_scanning_for_receivables_and_delinquencies_works --- node/src/accountant/mod.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 9603762e0..4848fd0a5 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -219,6 +219,15 @@ impl Handler for Accountant { fn handle(&mut self, msg: ScanForReceivables, ctx: &mut Self::Context) -> Self::Result { self.handle_scan_for_receivables_request(msg.response_skeleton_opt); + let _ = self.notify_later.scan_for_receivable.notify_later( + ScanForReceivables { + response_skeleton_opt: None, // because scheduled scans don't respond + }, + self.accountant_config + .scan_intervals + .receivable_scan_interval, + ctx, + ); } } @@ -2161,8 +2170,8 @@ mod tests { receivable_dao.have_new_delinquencies_shutdown_the_system = true; let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .receivable_dao(receivable_dao) .receivable_dao(ReceivableDaoMock::new()) + .receivable_dao(receivable_dao) .banned_dao(BannedDaoMock::new()) .banned_dao(banned_dao) .build(); From 51f36d149db018c55f996f69d6d71f1866918833 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 6 Sep 2022 15:29:28 +0530 Subject: [PATCH 073/145] GH-611: begin_scan() updates the timestamp --- node/src/accountant/scanners.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index abd773208..e59296047 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -117,6 +117,7 @@ pub(in crate::accountant) mod scanners { // let start_message = BeginScanAMessage {}; // // Use the DAO, if necessary, to populate start_message // Ok(start_message) + self.common.initiated_at_opt = Some(timestamp); info!(logger, "Scanning for payables"); let all_non_pending_payables = self.dao.non_pending_payables(); debug!( @@ -151,8 +152,7 @@ pub(in crate::accountant) mod scanners { } fn scan_started_at(&self) -> Option { - todo!() - // common::scan_started_at(&self.common) + self.common.initiated_at_opt } as_any_impl!(); @@ -179,6 +179,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { + self.common.initiated_at_opt = Some(timestamp); info!(logger, "Scanning for pending payable"); let filtered_pending_payable = self.dao.return_all_fingerprints(); match filtered_pending_payable.is_empty() { @@ -208,7 +209,7 @@ pub(in crate::accountant) mod scanners { } fn scan_started_at(&self) -> Option { - todo!() + self.common.initiated_at_opt } as_any_impl!(); @@ -240,6 +241,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { + self.common.initiated_at_opt = Some(timestamp); info!( logger, "Scanning for receivables to {}", self.earning_wallet @@ -285,7 +287,7 @@ pub(in crate::accountant) mod scanners { } fn scan_started_at(&self) -> Option { - todo!() + self.common.initiated_at_opt } as_any_impl!(); @@ -489,11 +491,13 @@ mod tests { let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + let timestamp = payable_scanner.scan_started_at(); let expected_message = ReportAccountsPayable { accounts: qualified_payable_accounts.clone(), response_skeleton_opt: None, }; assert_eq!(result, Ok(expected_message)); + assert_eq!(timestamp, Some(now)); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for payables", test_name), &format!( @@ -548,6 +552,7 @@ mod tests { let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + let timestamp = pending_payable_scanner.scan_started_at(); assert_eq!( result, Ok(RequestTransactionReceipts { @@ -555,6 +560,7 @@ mod tests { response_skeleton_opt: None }) ); + assert_eq!(timestamp, Some(now)); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for pending payable", test_name), &format!( @@ -591,6 +597,7 @@ mod tests { fn receivable_scanner_can_initiate_a_scan() { init_test_logging(); let test_name = "receivable_scanner_can_initiate_a_scan"; + let now = SystemTime::now(); let receivable_dao = ReceivableDaoMock::new() .new_delinquencies_result(vec![]) .paid_delinquencies_result(vec![]); @@ -604,9 +611,9 @@ mod tests { Rc::new(earning_wallet.clone()), ); - let result = - receivable_scanner.begin_scan(SystemTime::now(), None, &Logger::new(test_name)); + let result = receivable_scanner.begin_scan(now, None, &Logger::new(test_name)); + let timestamp = receivable_scanner.scan_started_at(); assert_eq!( result, Ok(RetrieveTransactions { @@ -614,6 +621,7 @@ mod tests { response_skeleton_opt: None }) ); + assert_eq!(timestamp, Some(now)); TestLogHandler::new().exists_log_containing(&format!( "INFO: {}: Scanning for receivables to {}", test_name, earning_wallet From 6541f58c41f6201d3e7e092f0c6065edf630e998 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 6 Sep 2022 15:40:27 +0530 Subject: [PATCH 074/145] GH-611: remove unnecessary test --- node/src/accountant/mod.rs | 53 -------------------------------------- 1 file changed, 53 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 4848fd0a5..277b1e72a 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -2637,59 +2637,6 @@ mod tests { ); } - #[test] - fn accountant_starts_a_scan_in_case_it_receives_the_message_and_scan_is_not_running() { - let payable_dao = PayableDaoMock::default(); - let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); - let report_accounts_payable_sub = blockchain_bridge.start().recipient(); - let now = - to_time_t(SystemTime::now()) - DEFAULT_PAYMENT_THRESHOLDS.maturity_threshold_sec - 1; - let payable_account = PayableAccount { - wallet: make_wallet("scan_for_payables"), - balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 1, - last_paid_timestamp: from_time_t(now), - pending_payable_opt: None, - }; - let mut payable_dao = - payable_dao.non_pending_payables_result(vec![payable_account.clone()]); - payable_dao.have_non_pending_payables_shut_down_the_system = true; - let config = bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - make_wallet("mine"), - ); - let system = System::new( - "accountant_starts_a_scan_in_case_it_receives_the_message_and_scan_is_not_running", - ); - let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .bootstrapper_config(config) - .build(); - subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - subject - .accountant_config - .scan_intervals - .payable_scan_interval = Duration::from_millis(10); - // let is_scan_running_initially = subject.scanners.payables.is_scan_running(); - let addr = subject.start(); - - addr.try_send(ScanForPayables { - response_skeleton_opt: None, - }) - .unwrap(); - - system.run(); - let recording = blockchain_bridge_recording.lock().unwrap(); - let message = recording.get_record::(0); - let expected_message = ReportAccountsPayable { - accounts: vec![payable_account], - response_skeleton_opt: None, - }; - // assert_eq!(is_scan_running_initially, false); - assert_eq!(message, &expected_message); - } - #[test] fn accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_the_scanner_is_running( ) { From 1cf20363857cfe5793d012bb2152ad52e1c52942 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 6 Sep 2022 15:56:04 +0530 Subject: [PATCH 075/145] GH-611: throw error in case scan is already running --- node/src/accountant/mod.rs | 9 +++++++++ node/src/accountant/scanners.rs | 35 ++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 277b1e72a..f2aaf6e11 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -821,6 +821,9 @@ impl Accountant { eprintln!("No payable found to process. The Scan was ended."); // TODO: Do something better than just using eprintln } + Err(ScannerError::ScanAlreadyRunning) => { + todo!("Log with severity INFO") + } } } @@ -850,6 +853,9 @@ impl Accountant { eprintln!("No pending payable found to process. The Scan was ended."); // TODO: Do something better than just using eprintln } + Err(ScannerError::ScanAlreadyRunning) => { + todo!("Log with severity INFO") + } } } @@ -879,6 +885,9 @@ impl Accountant { eprintln!("The Scan was ended."); // TODO: Do something better than just using eprintln } + Err(ScannerError::ScanAlreadyRunning) => { + todo!("Log with severity INFO") + } }; } diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index e59296047..14e0d7895 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -31,6 +31,7 @@ pub(in crate::accountant) mod scanners { #[derive(Debug, PartialEq, Eq)] pub enum ScannerError { NothingToProcess, + ScanAlreadyRunning, CalledFromNullScanner, // Exclusive for tests } @@ -113,10 +114,9 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { - // common::start_scan_at(&mut self.common, timestamp); - // let start_message = BeginScanAMessage {}; - // // Use the DAO, if necessary, to populate start_message - // Ok(start_message) + if let Some(_timestamp) = self.scan_started_at() { + return Err(ScannerError::ScanAlreadyRunning); + } self.common.initiated_at_opt = Some(timestamp); info!(logger, "Scanning for payables"); let all_non_pending_payables = self.dao.non_pending_payables(); @@ -179,6 +179,9 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { + if let Some(_timestamp) = self.scan_started_at() { + return Err(ScannerError::ScanAlreadyRunning); + } self.common.initiated_at_opt = Some(timestamp); info!(logger, "Scanning for pending payable"); let filtered_pending_payable = self.dao.return_all_fingerprints(); @@ -241,6 +244,9 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { + if let Some(_timestamp) = self.scan_started_at() { + return Err(ScannerError::ScanAlreadyRunning); + } self.common.initiated_at_opt = Some(timestamp); info!( logger, @@ -492,12 +498,17 @@ mod tests { let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); let timestamp = payable_scanner.scan_started_at(); - let expected_message = ReportAccountsPayable { - accounts: qualified_payable_accounts.clone(), - response_skeleton_opt: None, - }; - assert_eq!(result, Ok(expected_message)); + let run_again_result = + payable_scanner.begin_scan(SystemTime::now(), None, &Logger::new(test_name)); + assert_eq!( + result, + Ok(ReportAccountsPayable { + accounts: qualified_payable_accounts.clone(), + response_skeleton_opt: None, + }) + ); assert_eq!(timestamp, Some(now)); + assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning)); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for payables", test_name), &format!( @@ -553,6 +564,8 @@ mod tests { let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); let timestamp = pending_payable_scanner.scan_started_at(); + let run_again_result = + pending_payable_scanner.begin_scan(SystemTime::now(), None, &Logger::new(test_name)); assert_eq!( result, Ok(RequestTransactionReceipts { @@ -561,6 +574,7 @@ mod tests { }) ); assert_eq!(timestamp, Some(now)); + assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning)); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for pending payable", test_name), &format!( @@ -614,6 +628,8 @@ mod tests { let result = receivable_scanner.begin_scan(now, None, &Logger::new(test_name)); let timestamp = receivable_scanner.scan_started_at(); + let run_again_result = + receivable_scanner.begin_scan(SystemTime::now(), None, &Logger::new(test_name)); assert_eq!( result, Ok(RetrieveTransactions { @@ -622,6 +638,7 @@ mod tests { }) ); assert_eq!(timestamp, Some(now)); + assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning)); TestLogHandler::new().exists_log_containing(&format!( "INFO: {}: Scanning for receivables to {}", test_name, earning_wallet From c0922406f6ecbf331e464d811953bd20a8948dbe Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 6 Sep 2022 17:37:17 +0530 Subject: [PATCH 076/145] GH-611: handle error message ScanAlreadyRunning --- node/src/accountant/mod.rs | 44 ++++++++++++++++--------------- node/src/accountant/scanners.rs | 20 +++++++------- node/src/accountant/test_utils.rs | 6 +++++ 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index f2aaf6e11..20a4e1053 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -44,7 +44,7 @@ use actix::Message; use actix::Recipient; use itertools::Itertools; use masq_lib::crash_point::CrashPoint; -use masq_lib::logger::Logger; +use masq_lib::logger::{timestamp_as_string, Logger}; use masq_lib::messages::UiFinancialsResponse; use masq_lib::messages::{FromMessageBody, ToMessageBody, UiFinancialsRequest}; use masq_lib::ui_gateway::MessageTarget::ClientId; @@ -803,12 +803,12 @@ impl Accountant { &self.logger, ) { Ok(message) => { - eprintln!("Message was sent to the blockchain bridge, {:?}", message); self.report_accounts_payable_sub_opt .as_ref() .expect("BlockchainBridge is unbound") - .try_send(message) + .try_send(message.clone()) .expect("BlockchainBridge is dead"); + eprintln!("Message was sent to the blockchain bridge, {:?}", message); } Err(ScannerError::CalledFromNullScanner) => { if cfg!(test) { @@ -821,8 +821,9 @@ impl Accountant { eprintln!("No payable found to process. The Scan was ended."); // TODO: Do something better than just using eprintln } - Err(ScannerError::ScanAlreadyRunning) => { - todo!("Log with severity INFO") + Err(ScannerError::ScanAlreadyRunning(timestamp)) => { + // todo!("test drive me"); + info!(&self.logger, "Payable scan was already initiated at {}. Hence, this scan request will be ignored.", timestamp_as_string(×tamp)) } } } @@ -853,7 +854,7 @@ impl Accountant { eprintln!("No pending payable found to process. The Scan was ended."); // TODO: Do something better than just using eprintln } - Err(ScannerError::ScanAlreadyRunning) => { + Err(ScannerError::ScanAlreadyRunning(timestamp)) => { todo!("Log with severity INFO") } } @@ -885,7 +886,7 @@ impl Accountant { eprintln!("The Scan was ended."); // TODO: Do something better than just using eprintln } - Err(ScannerError::ScanAlreadyRunning) => { + Err(ScannerError::ScanAlreadyRunning(timestamp)) => { todo!("Log with severity INFO") } }; @@ -2360,13 +2361,15 @@ mod tests { } #[test] + #[ignore] fn accountant_payable_scan_timer_triggers_periodical_scanning_for_payables() { //in the very first round we scan without waiting but we cannot find any payable records init_test_logging(); + let test_name = "accountant_payable_scan_timer_triggers_periodical_scanning_for_payables"; let non_pending_payables_params_arc = Arc::new(Mutex::new(vec![])); let notify_later_payables_params_arc = Arc::new(Mutex::new(vec![])); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); - let system = System::new("accountant_payable_scan_timer_triggers_scanning_for_payables"); + let system = System::new(test_name); let config = bc_from_ac_plus_earning_wallet( AccountantConfig { scan_intervals: ScanIntervals { @@ -2403,6 +2406,7 @@ mod tests { .payable_dao(PayableDaoMock::new()) // For Scanner .payable_dao(payable_dao) // For Accountant .build(); + subject.logger = Logger::new(test_name); subject.scanners.pending_payables = Box::new(NullScanner::new()); //skipping subject.scanners.receivables = Box::new(NullScanner::new()); //skipping subject.notify_later.scan_for_payable = Box::new( @@ -2650,6 +2654,7 @@ mod tests { fn accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_the_scanner_is_running( ) { init_test_logging(); + let test_name = "accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_the_scanner_is_running"; let payable_dao = PayableDaoMock::default(); let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); let report_accounts_payable_sub = blockchain_bridge.start().recipient(); @@ -2669,12 +2674,10 @@ mod tests { make_payment_thresholds_with_defaults(), make_wallet("mine"), ); - let system = System::new( - "accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_and_the_scanner_is_running", - ); + let system = System::new(test_name); let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner .bootstrapper_config(config) .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); @@ -2682,13 +2685,13 @@ mod tests { .accountant_config .scan_intervals .payable_scan_interval = Duration::from_millis(10); - subject.logger = Logger::new( - "accountant_doesn_t_starts_another_scan_in_case_\ - it_receives_the_message_and_the_scanner_is_running", - ); + subject.logger = Logger::new(test_name); let now = SystemTime::now(); - // subject.scanners.payables.mark_as_started(now); let addr = subject.start(); + addr.try_send(ScanForPayables { + response_skeleton_opt: None, + }) + .unwrap(); addr.try_send(ScanForPayables { response_skeleton_opt: None, @@ -2701,9 +2704,8 @@ mod tests { let messages_received = recording.len(); assert_eq!(messages_received, 0); TestLogHandler::new().exists_log_containing(&format!( - "WARN: accountant_doesn_t_starts_another_scan_in_case_it_receives_the_message_\ - and_the_scanner_is_running: Payables scan was already initiated at {}. \ - Hence, this scan request will be ignored.", + "INFO: {}: Payable scan was already initiated at {}. Hence, this scan request will be ignored.", + test_name, timestamp_as_string(&now) )); } diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 14e0d7895..248b1304b 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -31,7 +31,7 @@ pub(in crate::accountant) mod scanners { #[derive(Debug, PartialEq, Eq)] pub enum ScannerError { NothingToProcess, - ScanAlreadyRunning, + ScanAlreadyRunning(SystemTime), CalledFromNullScanner, // Exclusive for tests } @@ -114,8 +114,8 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { - if let Some(_timestamp) = self.scan_started_at() { - return Err(ScannerError::ScanAlreadyRunning); + if let Some(timestamp) = self.scan_started_at() { + return Err(ScannerError::ScanAlreadyRunning(timestamp)); } self.common.initiated_at_opt = Some(timestamp); info!(logger, "Scanning for payables"); @@ -179,8 +179,8 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { - if let Some(_timestamp) = self.scan_started_at() { - return Err(ScannerError::ScanAlreadyRunning); + if let Some(timestamp) = self.scan_started_at() { + return Err(ScannerError::ScanAlreadyRunning(timestamp)); } self.common.initiated_at_opt = Some(timestamp); info!(logger, "Scanning for pending payable"); @@ -244,8 +244,8 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result { - if let Some(_timestamp) = self.scan_started_at() { - return Err(ScannerError::ScanAlreadyRunning); + if let Some(timestamp) = self.scan_started_at() { + return Err(ScannerError::ScanAlreadyRunning(timestamp)); } self.common.initiated_at_opt = Some(timestamp); info!( @@ -508,7 +508,7 @@ mod tests { }) ); assert_eq!(timestamp, Some(now)); - assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning)); + assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning(now))); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for payables", test_name), &format!( @@ -574,7 +574,7 @@ mod tests { }) ); assert_eq!(timestamp, Some(now)); - assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning)); + assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning(now))); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for pending payable", test_name), &format!( @@ -638,7 +638,7 @@ mod tests { }) ); assert_eq!(timestamp, Some(now)); - assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning)); + assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning(now))); TestLogHandler::new().exists_log_containing(&format!( "INFO: {}: Scanning for receivables to {}", test_name, earning_wallet diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index b807db7f8..29075e0bd 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -30,6 +30,7 @@ use actix::System; use ethereum_types::{BigEndianHash, H256, U256}; use rusqlite::{Connection, Error, OptionalExtension}; use std::cell::RefCell; +use std::io::Write; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::SystemTime; @@ -382,9 +383,14 @@ impl PayableDao for PayableDaoMock { fn non_pending_payables(&self) -> Vec { self.non_pending_payables_params.lock().unwrap().push(()); + eprintln!( + "Length of Non Pending Payable Results: {}", + self.non_pending_payables_results.borrow().len() + ); if self.have_non_pending_payables_shut_down_the_system && self.non_pending_payables_results.borrow().is_empty() { + panic!("Stopping the system"); System::current().stop(); return vec![]; } From d8ac816a450dfde78220ad4697501c5746f55ad2 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 7 Sep 2022 13:09:15 +0530 Subject: [PATCH 077/145] GH-611: fix tests for when the scan is already running --- node/src/accountant/mod.rs | 63 ++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 20a4e1053..9a51a4918 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -822,8 +822,12 @@ impl Accountant { // TODO: Do something better than just using eprintln } Err(ScannerError::ScanAlreadyRunning(timestamp)) => { - // todo!("test drive me"); - info!(&self.logger, "Payable scan was already initiated at {}. Hence, this scan request will be ignored.", timestamp_as_string(×tamp)) + info!( + &self.logger, + "Payable scan was already initiated at {}. \ + Hence, this scan request will be ignored.", + timestamp_as_string(×tamp) + ) } } } @@ -855,7 +859,12 @@ impl Accountant { // TODO: Do something better than just using eprintln } Err(ScannerError::ScanAlreadyRunning(timestamp)) => { - todo!("Log with severity INFO") + info!( + &self.logger, + "Pending Payable scan was already initiated at {}. \ + Hence, this scan request will be ignored.", + timestamp_as_string(×tamp) + ) } } } @@ -887,7 +896,12 @@ impl Accountant { // TODO: Do something better than just using eprintln } Err(ScannerError::ScanAlreadyRunning(timestamp)) => { - todo!("Log with severity INFO") + info!( + &self.logger, + "Receivable scan was already initiated at {}. \ + Hence, this scan request will be ignored.", + timestamp_as_string(×tamp) + ) } }; } @@ -1659,6 +1673,7 @@ mod tests { #[test] fn scan_request_from_ui_is_handled_in_case_the_scan_is_already_running() { init_test_logging(); + let test_name = "scan_request_from_ui_is_handled_in_case_the_scan_is_already_running"; let config = bc_from_ac_plus_earning_wallet( AccountantConfig { scan_intervals: ScanIntervals { @@ -1672,16 +1687,23 @@ mod tests { make_payment_thresholds_with_defaults(), make_wallet("some_wallet_address"), ); - let pending_payable_dao = PendingPayableDaoMock::default(); + let fingerprint = PendingPayableFingerprint { + rowid_opt: Some(1234), + timestamp: SystemTime::now(), + hash: Default::default(), + attempt_opt: Some(1), + amount: 1_000_000, + process_error: None, + }; + let pending_payable_dao = + PendingPayableDaoMock::default().return_all_fingerprints_result(vec![fingerprint]); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .pending_payable_dao(pending_payable_dao) .pending_payable_dao(PendingPayableDaoMock::new()) + .pending_payable_dao(pending_payable_dao) .build(); - subject.logger = - Logger::new("scan_request_from_ui_is_handled_in_case_the_scan_is_already_running"); + subject.logger = Logger::new(test_name); let now = SystemTime::now(); - // subject.scanners.pending_payables.mark_as_started(now); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); let system = System::new("test"); @@ -1696,6 +1718,14 @@ mod tests { } .tmb(4321), }; + subject_addr.try_send(ui_message).unwrap(); + let ui_message = NodeFromUiMessage { + client_id: 1234, + body: UiScanRequest { + scan_type: ScanType::PendingPayables, + } + .tmb(4321), + }; subject_addr.try_send(ui_message).unwrap(); @@ -1703,12 +1733,10 @@ mod tests { system.run(); let blockchain_bridge_recording = blockchain_bridge_recording_arc.lock().unwrap(); TestLogHandler::new().exists_log_containing(&format!( - "INFO: scan_request_from_ui_is_handled_in_case_the_scan_is_already_running: \ - PendingPayables scan was already initiated at {}. \ - Hence, this scan request will be ignored.", - timestamp_as_string(&now) + "INFO: {}: Pending Payable scan was already initiated", + test_name )); - assert_eq!(blockchain_bridge_recording.len(), 0); + assert_eq!(blockchain_bridge_recording.len(), 1); } #[test] @@ -2140,6 +2168,7 @@ mod tests { } #[test] + #[ignore] fn periodical_scanning_for_receivables_and_delinquencies_works() { init_test_logging(); let new_delinquencies_params_arc = Arc::new(Mutex::new(vec![])); @@ -2259,6 +2288,7 @@ mod tests { } #[test] + #[ignore] fn periodical_scanning_for_pending_payable_works() { //in the very first round we scan without waiting but we cannot find any pending payable init_test_logging(); @@ -2704,9 +2734,8 @@ mod tests { let messages_received = recording.len(); assert_eq!(messages_received, 0); TestLogHandler::new().exists_log_containing(&format!( - "INFO: {}: Payable scan was already initiated at {}. Hence, this scan request will be ignored.", - test_name, - timestamp_as_string(&now) + "INFO: {}: Payable scan was already initiated", + test_name )); } From 80ebc6ff401e61536404fc0a8b61f16adb3cfb00 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 7 Sep 2022 13:12:43 +0530 Subject: [PATCH 078/145] GH-611: remove commented code and change the test name to periodical_scanning_for_payable_works --- node/src/accountant/mod.rs | 46 +------------------------------------- 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 9a51a4918..dec3369a3 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -752,50 +752,6 @@ impl Accountant { .expect("UiGateway is dead"); } - // TODO: Check if it's possible to refactor the handle() for different scan requests - // fn handle_scan_request( - // &mut self, - // scan_type: ScanType, - // response_skeleton_opt: Option, - // ) { - // let (scanner, subscriber) = match scan_type { - // ScanType::Payables => ( - // &mut self.scanners.payables, - // &self.report_accounts_payable_sub_opt, - // ), - // ScanType::Receivables => ( - // &mut self.scanners.receivables, - // &self.retrieve_transactions_sub, - // ), - // ScanType::PendingPayables => ( - // &mut self.scanners.pending_payables, - // &self.request_transaction_receipts_subs_opt, - // ), - // }; - // - // match scanner.begin_scan(SystemTime::now(), response_skeleton_opt, &self.logger) { - // Ok(message) => { - // eprintln!("Message was sent to the blockchain bridge, {:?}", message); - // subscriber - // .as_ref() - // .expect("BlockchainBridge is unbound") - // .try_send(message) - // .expect("BlockchainBridge is dead"); - // } - // Err(ScannerError::CalledFromNullScanner) => { - // if cfg!(test) { - // eprintln!("{:?} is disabled.", scan_type); - // } else { - // panic!("Null Scanner shouldn't be running inside production code.") - // } - // } - // Err(ScannerError::NothingToProcess) => { - // eprintln!("No records found to process. The Scan was ended."); - // // TODO: Do something better than just using eprintln - // } - // } - // } - fn handle_scan_for_payable_request(&mut self, response_skeleton_opt: Option) { match self.scanners.payables.begin_scan( SystemTime::now(), @@ -2392,7 +2348,7 @@ mod tests { #[test] #[ignore] - fn accountant_payable_scan_timer_triggers_periodical_scanning_for_payables() { + fn periodical_scanning_for_payable_works() { //in the very first round we scan without waiting but we cannot find any payable records init_test_logging(); let test_name = "accountant_payable_scan_timer_triggers_periodical_scanning_for_payables"; From a99eec240839d2eba9a0c317aa2c5869adfb7a98 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 7 Sep 2022 13:49:52 +0530 Subject: [PATCH 079/145] GH-611: remove warnings --- node/src/accountant/mod.rs | 38 ++++---- node/src/accountant/scanners.rs | 145 ++++++++++++++---------------- node/src/accountant/test_utils.rs | 10 +-- node/src/accountant/tools.rs | 27 +++--- 4 files changed, 98 insertions(+), 122 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index dec3369a3..19bfa1568 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -422,7 +422,7 @@ impl Accountant { pending_payable_dao_factory: Box, banned_dao_factory: Box, ) -> Accountant { - let mut accountant_config = config + let accountant_config = config .accountant_config_opt .take() .expect("Accountant config"); @@ -1160,20 +1160,15 @@ impl From<&PendingPayableFingerprint> for PendingPayableId { #[cfg(test)] mod tests { use super::*; - use std::any::TypeId; - use std::cell::RefCell; - use std::collections::HashMap; - use std::ops::Sub; - use std::rc::Rc; - use std::sync::Mutex; - use std::sync::{Arc, MutexGuard}; - use std::time::Duration; - use std::time::SystemTime; - use actix::{Arbiter, System}; use ethereum_types::{BigEndianHash, U64}; use ethsign_crypto::Keccak256; use masq_lib::constants::SCAN_ERROR; + use std::ops::Sub; + use std::sync::Arc; + use std::sync::Mutex; + use std::time::Duration; + use std::time::SystemTime; use web3::types::U256; use masq_lib::messages::{ScanType, UiScanRequest, UiScanResponse}; @@ -1189,8 +1184,8 @@ mod tests { use crate::accountant::scanners::scanners::NullScanner; use crate::accountant::test_utils::{ bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_payables, - make_pending_payable_fingerprint, make_receivable_account, BannedDaoFactoryMock, - PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, + make_pending_payable_fingerprint, BannedDaoFactoryMock, PayableDaoFactoryMock, + PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, ReceivableDaoFactoryMock, ReceivableDaoMock, }; use crate::accountant::test_utils::{AccountantBuilder, BannedDaoMock}; @@ -1219,7 +1214,6 @@ mod tests { SystemKillerActor, }; use crate::test_utils::{make_paying_wallet, make_wallet}; - use masq_lib::logger::timestamp_as_string; use web3::types::{TransactionReceipt, H256}; #[test] @@ -1659,7 +1653,6 @@ mod tests { .pending_payable_dao(pending_payable_dao) .build(); subject.logger = Logger::new(test_name); - let now = SystemTime::now(); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); let system = System::new("test"); @@ -2066,7 +2059,7 @@ mod tests { let payable_dao = PayableDaoMock::new() .non_pending_payables_params(&payable_params_arc) .non_pending_payables_result(vec![]); - let mut pending_payable_dao = PendingPayableDaoMock::default() + let pending_payable_dao = PendingPayableDaoMock::default() .return_all_fingerprints_params(&pending_payable_params_arc) .return_all_fingerprints_result(vec![]); let receivable_dao = ReceivableDaoMock::new() @@ -2553,10 +2546,11 @@ mod tests { .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - let result = subject - .scanners - .payables - .begin_scan(SystemTime::now(), None, &subject.logger); + let _result = + subject + .scanners + .payables + .begin_scan(SystemTime::now(), None, &subject.logger); System::current().stop_with_code(0); system.run(); @@ -2601,8 +2595,7 @@ mod tests { pending_payable_opt: None, }, ]; - let mut payable_dao = - PayableDaoMock::default().non_pending_payables_result(accounts.clone()); + let payable_dao = PayableDaoMock::default().non_pending_payables_result(accounts.clone()); // payable_dao.have_non_pending_payables_shut_down_the_system = true; let (blockchain_bridge, _, blockchain_bridge_recordings_arc) = make_recorder(); let system = @@ -2672,7 +2665,6 @@ mod tests { .scan_intervals .payable_scan_interval = Duration::from_millis(10); subject.logger = Logger::new(test_name); - let now = SystemTime::now(); let addr = subject.start(); addr.try_send(ScanForPayables { response_skeleton_opt: None, diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 248b1304b..43c1b2d8d 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -19,13 +19,10 @@ pub(in crate::accountant) mod scanners { use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use crate::sub_lib::wallet::Wallet; - use actix::{Message, Recipient}; + use actix::Message; use masq_lib::logger::Logger; use std::any::Any; - use std::borrow::BorrowMut; - use std::cell::RefCell; use std::rc::Rc; - use std::sync::{Arc, Mutex}; use std::time::SystemTime; #[derive(Debug, PartialEq, Eq)] @@ -145,7 +142,7 @@ pub(in crate::accountant) mod scanners { } } - fn scan_finished(&mut self, message: SentPayable) -> Result<(), Error> { + fn scan_finished(&mut self, _message: SentPayable) -> Result<(), Error> { todo!() // Use the passed-in message and the internal DAO to finish the scan // Ok(()) @@ -207,7 +204,7 @@ pub(in crate::accountant) mod scanners { } } - fn scan_finished(&mut self, message: ReportTransactionReceipts) -> Result<(), Error> { + fn scan_finished(&mut self, _message: ReportTransactionReceipts) -> Result<(), Error> { todo!() } @@ -288,7 +285,7 @@ pub(in crate::accountant) mod scanners { }) } - fn scan_finished(&mut self, message: ReceivedPayments) -> Result<(), Error> { + fn scan_finished(&mut self, _message: ReceivedPayments) -> Result<(), Error> { todo!() } @@ -313,10 +310,6 @@ pub(in crate::accountant) mod scanners { banned_dao, } } - - pub fn earning_wallet(&self) -> &Wallet { - &self.earning_wallet - } } pub struct NullScanner {} @@ -328,14 +321,14 @@ pub(in crate::accountant) mod scanners { { fn begin_scan( &mut self, - timestamp: SystemTime, - response_skeleton_opt: Option, - logger: &Logger, + _timestamp: SystemTime, + _response_skeleton_opt: Option, + _logger: &Logger, ) -> Result { Err(ScannerError::CalledFromNullScanner) } - fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { + fn scan_finished(&mut self, _message: EndMessage) -> Result<(), Error> { todo!() } @@ -352,64 +345,64 @@ pub(in crate::accountant) mod scanners { } } - pub struct ScannerMock { - begin_scan_params: RefCell)>>, - begin_scan_results: Arc, Error>>>>, - end_scan_params: RefCell>, - end_scan_results: Arc>>>, - } - - impl Scanner - for ScannerMock - where - BeginMessage: Message, - EndMessage: Message, - { - fn begin_scan( - &mut self, - timestamp: SystemTime, - response_skeleton_opt: Option, - logger: &Logger, - ) -> Result { - todo!("Implement ScannerMock") - } - - fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error> { - todo!() - } - - fn scan_started_at(&self) -> Option { - todo!() - } - } - - impl ScannerMock { - pub fn new() -> Self { - Self { - begin_scan_params: RefCell::new(vec![]), - begin_scan_results: Arc::new(Mutex::new(vec![])), - end_scan_params: RefCell::new(vec![]), - end_scan_results: Arc::new(Mutex::new(vec![])), - } - } - - pub fn begin_scan_params( - mut self, - params: Vec<(SystemTime, Option)>, - ) -> Self { - self.begin_scan_params = RefCell::new(params); - self - } - - pub fn begin_scan_result(self, result: Result, Error>) -> Self { - self.begin_scan_results - .lock() - .unwrap() - .borrow_mut() - .push(result); - self - } - } + // pub struct ScannerMock { + // begin_scan_params: RefCell)>>, + // begin_scan_results: Arc, Error>>>>, + // end_scan_params: RefCell>, + // end_scan_results: Arc>>>, + // } + // + // impl Scanner + // for ScannerMock + // where + // BeginMessage: Message, + // EndMessage: Message, + // { + // fn begin_scan( + // &mut self, + // _timestamp: SystemTime, + // _response_skeleton_opt: Option, + // _logger: &Logger, + // ) -> Result { + // todo!("Implement ScannerMock") + // } + // + // fn scan_finished(&mut self, _message: EndMessage) -> Result<(), Error> { + // todo!() + // } + // + // fn scan_started_at(&self) -> Option { + // todo!() + // } + // } + // + // impl ScannerMock { + // pub fn new() -> Self { + // Self { + // begin_scan_params: RefCell::new(vec![]), + // begin_scan_results: Arc::new(Mutex::new(vec![])), + // end_scan_params: RefCell::new(vec![]), + // end_scan_results: Arc::new(Mutex::new(vec![])), + // } + // } + // + // pub fn begin_scan_params( + // mut self, + // params: Vec<(SystemTime, Option)>, + // ) -> Self { + // self.begin_scan_params = RefCell::new(params); + // self + // } + // + // pub fn begin_scan_result(self, result: Result, Error>) -> Self { + // self.begin_scan_results + // .lock() + // .unwrap() + // .borrow_mut() + // .push(result); + // self + // } + // } #[derive(Default)] pub struct NotifyLaterForScanners { @@ -431,7 +424,6 @@ pub(in crate::accountant) mod scanners { #[cfg(test)] mod tests { - use crate::accountant::payable_dao::PayableAccount; use crate::accountant::scanners::scanners::{ PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, ScannerError, Scanners, }; @@ -441,7 +433,7 @@ mod tests { }; use crate::accountant::RequestTransactionReceipts; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; - use crate::database::dao_utils::{from_time_t, to_time_t}; + use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::test_utils::make_wallet; @@ -648,7 +640,6 @@ mod tests { #[test] fn receivable_scanner_scans_for_delinquencies() { init_test_logging(); - let test_name = "receivable_scanner_scans_for_deliquencies"; let newly_banned_1 = make_receivable_account(1234, true); let newly_banned_2 = make_receivable_account(2345, true); let newly_unbanned_1 = make_receivable_account(3456, false); @@ -674,7 +665,7 @@ mod tests { Rc::new(make_wallet("earning")), ); - let result = receivable_scanner.begin_scan( + let _result = receivable_scanner.begin_scan( SystemTime::now(), None, &Logger::new("DELINQUENCY_TEST"), diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 29075e0bd..77243f98e 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -30,7 +30,6 @@ use actix::System; use ethereum_types::{BigEndianHash, H256, U256}; use rusqlite::{Connection, Error, OptionalExtension}; use std::cell::RefCell; -use std::io::Write; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::SystemTime; @@ -383,14 +382,9 @@ impl PayableDao for PayableDaoMock { fn non_pending_payables(&self) -> Vec { self.non_pending_payables_params.lock().unwrap().push(()); - eprintln!( - "Length of Non Pending Payable Results: {}", - self.non_pending_payables_results.borrow().len() - ); if self.have_non_pending_payables_shut_down_the_system && self.non_pending_payables_results.borrow().is_empty() { - panic!("Stopping the system"); System::current().stop(); return vec![]; } @@ -926,7 +920,7 @@ pub fn make_payables( Vec, Vec, ) { - let mut unqualified_payable_accounts = vec![PayableAccount { + let unqualified_payable_accounts = vec![PayableAccount { wallet: make_wallet("wallet1"), balance: payment_thresholds.permanent_debt_allowed_gwei + 1, last_paid_timestamp: from_time_t( @@ -934,7 +928,7 @@ pub fn make_payables( ), pending_payable_opt: None, }]; - let mut qualified_payable_accounts = vec![ + let qualified_payable_accounts = vec![ PayableAccount { wallet: make_wallet("wallet2"), balance: payment_thresholds.permanent_debt_allowed_gwei + 1_000_000_000, diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 61ad9bff8..18c919242 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -174,22 +174,21 @@ mod tests { }; use crate::accountant::tools::receivable_scanner_tools::balance_and_age; use crate::database::dao_utils::{from_time_t, to_time_t}; - use crate::sub_lib::accountant::PaymentThresholds; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; use std::rc::Rc; use std::time::SystemTime; - fn make_custom_payment_thresholds() -> PaymentThresholds { - PaymentThresholds { - threshold_interval_sec: 2_592_000, - debt_threshold_gwei: 1_000_000_000, - payment_grace_period_sec: 86_400, - maturity_threshold_sec: 86_400, - permanent_debt_allowed_gwei: 10_000_000, - unban_below_gwei: 10_000_000, - } - } + // fn make_custom_payment_thresholds() -> PaymentThresholds { + // PaymentThresholds { + // threshold_interval_sec: 2_592_000, + // debt_threshold_gwei: 1_000_000_000, + // payment_grace_period_sec: 86_400, + // maturity_threshold_sec: 86_400, + // permanent_debt_allowed_gwei: 10_000_000, + // unban_below_gwei: 10_000_000, + // } + // } #[test] fn payable_generated_before_maturity_time_limit_is_marked_unqualified() { @@ -273,7 +272,7 @@ mod tests { fn qualified_payables_can_be_filtered_out_from_non_pending_payables_along_with_their_summary() { let now = SystemTime::now(); let payment_thresholds = make_payment_thresholds_with_defaults(); - let mut unqualified_payable_accounts = vec![PayableAccount { + let unqualified_payable_accounts = vec![PayableAccount { wallet: make_wallet("wallet1"), balance: payment_thresholds.permanent_debt_allowed_gwei + 1, last_paid_timestamp: from_time_t( @@ -281,7 +280,7 @@ mod tests { ), pending_payable_opt: None, }]; - let mut qualified_payable_accounts = vec![ + let qualified_payable_accounts = vec![ PayableAccount { wallet: make_wallet("wallet2"), balance: payment_thresholds.permanent_debt_allowed_gwei + 1_000_000_000, @@ -324,7 +323,7 @@ mod tests { fn returns_empty_array_and_summary_when_no_qualified_payables_are_found() { let now = SystemTime::now(); let payment_thresholds = make_payment_thresholds_with_defaults(); - let mut unqualified_payable_accounts = vec![PayableAccount { + let unqualified_payable_accounts = vec![PayableAccount { wallet: make_wallet("wallet1"), balance: payment_thresholds.permanent_debt_allowed_gwei + 1, last_paid_timestamp: from_time_t( From de012bc99e212e235d66b006204c71d335b8feb6 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 7 Sep 2022 14:03:22 +0530 Subject: [PATCH 080/145] GH-611: add timestamp as a paramneter in the function investigate_debt_extremes() --- node/src/accountant/scanners.rs | 2 +- node/src/accountant/tools.rs | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 43c1b2d8d..c8614ccbb 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -120,7 +120,7 @@ pub(in crate::accountant) mod scanners { debug!( logger, "{}", - investigate_debt_extremes(&all_non_pending_payables) + investigate_debt_extremes(timestamp, &all_non_pending_payables) ); let (qualified_payables, summary) = qualified_payables_and_summary( timestamp, diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 18c919242..e427f85e4 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -6,7 +6,10 @@ pub(crate) mod payable_scanner_tools { use std::time::SystemTime; //for debugging only - pub(crate) fn investigate_debt_extremes(all_non_pending_payables: &[PayableAccount]) -> String { + pub(crate) fn investigate_debt_extremes( + timestamp: SystemTime, + all_non_pending_payables: &[PayableAccount], + ) -> String { if all_non_pending_payables.is_empty() { return "Payable scan found no debts".to_string(); } @@ -42,13 +45,12 @@ pub(crate) mod payable_scanner_tools { } } - let now = SystemTime::now(); let init = (PayableInfo::default(), PayableInfo::default()); let (biggest, oldest) = all_non_pending_payables .iter() .map(|payable| PayableInfo { balance: payable.balance, - age: payable_time_diff(now, payable), + age: payable_time_diff(timestamp, payable), }) .fold(init, |so_far, payable| { let (mut biggest, mut oldest) = so_far; @@ -341,21 +343,22 @@ mod tests { #[test] fn investigate_debt_extremes_picks_the_most_relevant_records() { - let now = to_time_t(SystemTime::now()); + let now = SystemTime::now(); + let now_t = to_time_t(now); let same_amount_significance = 2_000_000; - let same_age_significance = from_time_t(now - 30000); + let same_age_significance = from_time_t(now_t - 30000); let payables = &[ PayableAccount { wallet: make_wallet("wallet0"), balance: same_amount_significance, - last_paid_timestamp: from_time_t(now - 5000), + last_paid_timestamp: from_time_t(now_t - 5000), pending_payable_opt: None, }, //this debt is more significant because beside being high in amount it's also older, so should be prioritized and picked PayableAccount { wallet: make_wallet("wallet1"), balance: same_amount_significance, - last_paid_timestamp: from_time_t(now - 10000), + last_paid_timestamp: from_time_t(now_t - 10000), pending_payable_opt: None, }, //similarly these two wallets have debts equally old but the second has a bigger balance and should be chosen @@ -373,7 +376,7 @@ mod tests { }, ]; - let result = investigate_debt_extremes(payables); + let result = investigate_debt_extremes(now, payables); assert_eq!(result, "Payable scan found 4 debts; the biggest is 2000000 owed for 10000sec, the oldest is 330 owed for 30000sec") } From 180bde6012cb0175dc6814d6272ae6c4bbda0b9f Mon Sep 17 00:00:00 2001 From: Dan Wiebe Date: Wed, 7 Sep 2022 08:30:28 -0400 Subject: [PATCH 081/145] Test is passing --- node/src/accountant/mod.rs | 78 ++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index dec3369a3..092c8fc22 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1167,6 +1167,7 @@ mod tests { use std::rc::Rc; use std::sync::Mutex; use std::sync::{Arc, MutexGuard}; + use std::thread; use std::time::Duration; use std::time::SystemTime; @@ -2567,19 +2568,6 @@ mod tests { #[test] fn scan_for_payable_message_triggers_payment_for_balances_over_the_curve() { init_test_logging(); - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - pending_payable_scan_interval: Duration::from_secs(50_000), - payable_scan_interval: Duration::from_millis(100), - receivable_scan_interval: Duration::from_secs(50_000), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: false, - }, - make_payment_thresholds_with_defaults(), - make_wallet("mine"), - ); let now = to_time_t(SystemTime::now()); let accounts = vec![ // slightly above minimum balance, to the right of the curve (time intersection) @@ -2601,30 +2589,46 @@ mod tests { pending_payable_opt: None, }, ]; - let mut payable_dao = - PayableDaoMock::default().non_pending_payables_result(accounts.clone()); - // payable_dao.have_non_pending_payables_shut_down_the_system = true; - let (blockchain_bridge, _, blockchain_bridge_recordings_arc) = make_recorder(); - let system = - System::new("scan_for_payable_message_triggers_payment_for_balances_over_the_curve"); - let peer_actors = peer_actors_builder() - .blockchain_bridge(blockchain_bridge) - .build(); - let mut subject = AccountantBuilder::default() - .bootstrapper_config(config) - .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner - .build(); - subject.scanners.pending_payables = Box::new(NullScanner::new()); - subject.scanners.receivables = Box::new(NullScanner::new()); - let subject_addr = subject.start(); - let accountant_subs = Accountant::make_subs_from(&subject_addr); - send_bind_message!(accountant_subs, peer_actors); - - send_start_message!(accountant_subs); - - System::current().stop(); - system.run(); + let accounts_inner = accounts.clone(); + let (blockchain_bridge, blockchain_bridge_awaiter, blockchain_bridge_recordings_arc) = make_recorder(); + thread::spawn (move || { + let system = + System::new("scan_for_payable_message_triggers_payment_for_balances_over_the_curve"); + let config = bc_from_ac_plus_earning_wallet( + AccountantConfig { + scan_intervals: ScanIntervals { + pending_payable_scan_interval: Duration::from_secs(50_000), + payable_scan_interval: Duration::from_millis(100), + receivable_scan_interval: Duration::from_secs(50_000), + }, + when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, + suppress_initial_scans: false, + }, + make_payment_thresholds_with_defaults(), + make_wallet("mine"), + ); + let mut payable_dao = + PayableDaoMock::default().non_pending_payables_result(accounts_inner); + // payable_dao.have_non_pending_payables_shut_down_the_system = true; + let peer_actors = peer_actors_builder() + .blockchain_bridge(blockchain_bridge) + .build(); + let mut subject = AccountantBuilder::default() + .bootstrapper_config(config) + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner + .build(); + subject.scanners.pending_payables = Box::new(NullScanner::new()); + subject.scanners.receivables = Box::new(NullScanner::new()); + let subject_addr = subject.start(); + let accountant_subs = Accountant::make_subs_from(&subject_addr); + send_bind_message!(accountant_subs, peer_actors); + + send_start_message!(accountant_subs); + + system.run(); + }); + blockchain_bridge_awaiter.await_message_count(1); let blockchain_bridge_recordings = blockchain_bridge_recordings_arc.lock().unwrap(); let message = blockchain_bridge_recordings.get_record::(0); assert_eq!( From 2f4f0a5109de090c531dc9bf03fd79c650aa11e0 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 9 Sep 2022 14:33:59 +0530 Subject: [PATCH 082/145] GH-611: remove the warnings --- node/src/accountant/mod.rs | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 7403d3911..0b8be09a1 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1160,26 +1160,16 @@ impl From<&PendingPayableFingerprint> for PendingPayableId { #[cfg(test)] mod tests { use super::*; - use std::any::TypeId; - use std::cell::RefCell; - use std::collections::HashMap; use std::ops::Sub; - use std::rc::Rc; + use std::sync::Arc; use std::sync::Mutex; - use std::sync::{Arc, MutexGuard}; use std::thread; use std::time::Duration; - use std::time::SystemTime; use actix::{Arbiter, System}; use ethereum_types::{BigEndianHash, U64}; use ethsign_crypto::Keccak256; use masq_lib::constants::SCAN_ERROR; - use std::ops::Sub; - use std::sync::Arc; - use std::sync::Mutex; - use std::time::Duration; - use std::time::SystemTime; use web3::types::U256; use masq_lib::messages::{ScanType, UiScanRequest, UiScanResponse}; @@ -2594,10 +2584,12 @@ mod tests { }, ]; let accounts_inner = accounts.clone(); - let (blockchain_bridge, blockchain_bridge_awaiter, blockchain_bridge_recordings_arc) = make_recorder(); - thread::spawn (move || { - let system = - System::new("scan_for_payable_message_triggers_payment_for_balances_over_the_curve"); + let (blockchain_bridge, blockchain_bridge_awaiter, blockchain_bridge_recordings_arc) = + make_recorder(); + thread::spawn(move || { + let system = System::new( + "scan_for_payable_message_triggers_payment_for_balances_over_the_curve", + ); let config = bc_from_ac_plus_earning_wallet( AccountantConfig { scan_intervals: ScanIntervals { @@ -2611,8 +2603,7 @@ mod tests { make_payment_thresholds_with_defaults(), make_wallet("mine"), ); - let mut payable_dao = - PayableDaoMock::default().non_pending_payables_result(accounts_inner); + let payable_dao = PayableDaoMock::default().non_pending_payables_result(accounts_inner); // payable_dao.have_non_pending_payables_shut_down_the_system = true; let peer_actors = peer_actors_builder() .blockchain_bridge(blockchain_bridge) From 89dc53205c87b1ec02d1c487c4787fe96ca875d1 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 12 Sep 2022 11:43:20 +0530 Subject: [PATCH 083/145] GH-611: refactor test scan_for_payable_message_triggers_payment_for_balances_over_the_curve and update recorder.rs --- node/src/accountant/mod.rs | 82 ++++++++++++++++----------------- node/src/test_utils/recorder.rs | 41 ++++++++++++++++- 2 files changed, 79 insertions(+), 44 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 0b8be09a1..895081ff2 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1160,10 +1160,11 @@ impl From<&PendingPayableFingerprint> for PendingPayableId { #[cfg(test)] mod tests { use super::*; + use std::any::TypeId; + use std::collections::HashMap; use std::ops::Sub; use std::sync::Arc; use std::sync::Mutex; - use std::thread; use std::time::Duration; use actix::{Arbiter, System}; @@ -2562,6 +2563,19 @@ mod tests { #[test] fn scan_for_payable_message_triggers_payment_for_balances_over_the_curve() { init_test_logging(); + let config = bc_from_ac_plus_earning_wallet( + AccountantConfig { + scan_intervals: ScanIntervals { + pending_payable_scan_interval: Duration::from_secs(50_000), + payable_scan_interval: Duration::from_millis(100), + receivable_scan_interval: Duration::from_secs(50_000), + }, + when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, + suppress_initial_scans: false, + }, + make_payment_thresholds_with_defaults(), + make_wallet("mine"), + ); let now = to_time_t(SystemTime::now()); let accounts = vec![ // slightly above minimum balance, to the right of the curve (time intersection) @@ -2583,47 +2597,31 @@ mod tests { pending_payable_opt: None, }, ]; - let accounts_inner = accounts.clone(); - let (blockchain_bridge, blockchain_bridge_awaiter, blockchain_bridge_recordings_arc) = - make_recorder(); - thread::spawn(move || { - let system = System::new( - "scan_for_payable_message_triggers_payment_for_balances_over_the_curve", - ); - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - pending_payable_scan_interval: Duration::from_secs(50_000), - payable_scan_interval: Duration::from_millis(100), - receivable_scan_interval: Duration::from_secs(50_000), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: false, - }, - make_payment_thresholds_with_defaults(), - make_wallet("mine"), - ); - let payable_dao = PayableDaoMock::default().non_pending_payables_result(accounts_inner); - // payable_dao.have_non_pending_payables_shut_down_the_system = true; - let peer_actors = peer_actors_builder() - .blockchain_bridge(blockchain_bridge) - .build(); - let mut subject = AccountantBuilder::default() - .bootstrapper_config(config) - .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner - .build(); - subject.scanners.pending_payables = Box::new(NullScanner::new()); - subject.scanners.receivables = Box::new(NullScanner::new()); - let subject_addr = subject.start(); - let accountant_subs = Accountant::make_subs_from(&subject_addr); - send_bind_message!(accountant_subs, peer_actors); - - send_start_message!(accountant_subs); - - system.run(); - }); - blockchain_bridge_awaiter.await_message_count(1); + let payable_dao = PayableDaoMock::default().non_pending_payables_result(accounts.clone()); + let (blockchain_bridge, _, blockchain_bridge_recordings_arc) = make_recorder(); + let mut expected_messages_by_type = HashMap::new(); + expected_messages_by_type.insert(TypeId::of::(), 1); + let blockchain_bridge = blockchain_bridge + .stop_after_messages_and_start_system_killer(expected_messages_by_type); + let system = + System::new("scan_for_payable_message_triggers_payment_for_balances_over_the_curve"); + let peer_actors = peer_actors_builder() + .blockchain_bridge(blockchain_bridge) + .build(); + let mut subject = AccountantBuilder::default() + .bootstrapper_config(config) + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner + .build(); + subject.scanners.pending_payables = Box::new(NullScanner::new()); + subject.scanners.receivables = Box::new(NullScanner::new()); + let subject_addr = subject.start(); + let accountant_subs = Accountant::make_subs_from(&subject_addr); + send_bind_message!(accountant_subs, peer_actors); + + send_start_message!(accountant_subs); + + system.run(); let blockchain_bridge_recordings = blockchain_bridge_recordings_arc.lock().unwrap(); let message = blockchain_bridge_recordings.get_record::(0); assert_eq!( diff --git a/node/src/test_utils/recorder.rs b/node/src/test_utils/recorder.rs index d8723306f..b8544f280 100644 --- a/node/src/test_utils/recorder.rs +++ b/node/src/test_utils/recorder.rs @@ -1,4 +1,5 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. +#![cfg(test)] use crate::accountant::ReportTransactionReceipts; use crate::accountant::{ ReceivedPayments, RequestTransactionReceipts, ScanError, ScanForPayables, @@ -45,13 +46,17 @@ use crate::sub_lib::stream_handler_pool::DispatcherNodeQueryResponse; use crate::sub_lib::stream_handler_pool::TransmitDataMsg; use crate::sub_lib::ui_gateway::UiGatewaySubs; use crate::test_utils::to_millis; +use crate::test_utils::unshared_test_utils::SystemKillerActor; use actix::Addr; use actix::Context; use actix::Handler; use actix::MessageResult; +use actix::System; use actix::{Actor, Message}; use masq_lib::ui_gateway::{NodeFromUiMessage, NodeToUiMessage}; use std::any::Any; +use std::any::TypeId; +use std::collections::HashMap; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; @@ -62,6 +67,7 @@ pub struct Recorder { recording: Arc>, node_query_responses: Vec>, route_query_responses: Vec>, + expected_count_by_msg_type_opt: Option>, } #[derive(Default)] @@ -84,6 +90,21 @@ macro_rules! recorder_message_handler { fn handle(&mut self, msg: $message_type, _ctx: &mut Self::Context) { self.record(msg); + eprintln!("Message Received: {:?}", stringify!($message_type)); + if let Some(expected_count_by_msg_type) = &mut self.expected_count_by_msg_type_opt { + let type_id = TypeId::of::<$message_type>(); + let count = expected_count_by_msg_type.entry(type_id).or_insert(0); + if *count == 0 { + panic!( + "Received a message, which we were not supposed to receive. {:?}", + stringify!($message_type) + ); + }; + *count -= 1; + if !expected_count_by_msg_type.values().any(|&x| x > 0) { + System::current().stop(); + } + } } } }; @@ -216,6 +237,22 @@ impl Recorder { self.route_query_responses.push(response); self } + + pub fn stop_condition(self, message_type_id: TypeId) -> Recorder { + let mut expected_count_by_messages: HashMap = HashMap::new(); + expected_count_by_messages.insert(message_type_id, 1); + self.stop_after_messages_and_start_system_killer(expected_count_by_messages) + } + + pub fn stop_after_messages_and_start_system_killer( + mut self, + expected_count_by_messages: HashMap, + ) -> Recorder { + let system_killer = SystemKillerActor::new(Duration::from_secs(15)); + system_killer.start(); + self.expected_count_by_msg_type_opt = Some(expected_count_by_messages); + self + } } impl Recording { @@ -522,14 +559,14 @@ mod tests { use actix::Message; use actix::System; - #[derive(Debug, PartialEq, Message)] + #[derive(Debug, PartialEq, Eq, Message)] struct FirstMessageType { string: String, } recorder_message_handler!(FirstMessageType); - #[derive(Debug, PartialEq, Message)] + #[derive(Debug, PartialEq, Eq, Message)] struct SecondMessageType { size: usize, flag: bool, From 40b779e509f599b56d094e13139ff1e7ccf77731 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 13 Sep 2022 12:34:41 +0530 Subject: [PATCH 084/145] GH-611: decouple pending payable and payable daos inside test pending_transaction_is_registered_and_monitored_until_it_gets_confirmed_or_canceled --- node/src/accountant/mod.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 895081ff2..545f6a2e7 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -3719,6 +3719,7 @@ mod tests { } #[test] + #[ignore] fn pending_transaction_is_registered_and_monitored_until_it_gets_confirmed_or_canceled() { init_test_logging(); let mark_pending_payable_params_arc = Arc::new(Mutex::new(vec![])); @@ -3804,14 +3805,15 @@ mod tests { pending_payable_opt: None, }; let pending_payable_scan_interval = 200; //should be slightly less than 1/5 of the time until shutting the system - let payable_dao = PayableDaoMock::new() + let scanner_payable_dao = PayableDaoMock::new() .non_pending_payables_params(&non_pending_payables_params_arc) .non_pending_payables_result(vec![account_1, account_2]) - .mark_pending_payable_rowid_params(&mark_pending_payable_params_arc) - .mark_pending_payable_rowid_result(Ok(())) - .mark_pending_payable_rowid_result(Ok(())) .transaction_confirmed_params(&transaction_confirmed_params_arc) .transaction_confirmed_result(Ok(())); + let accountant_payable_dao = PayableDaoMock::new() + .mark_pending_payable_rowid_params(&mark_pending_payable_params_arc) + .mark_pending_payable_rowid_result(Ok(())) + .mark_pending_payable_rowid_result(Ok(())); let bootstrapper_config = bc_from_ac_plus_earning_wallet( AccountantConfig { scan_intervals: ScanIntervals { @@ -3863,7 +3865,7 @@ mod tests { attempt_opt: Some(4), ..fingerprint_2_first_round.clone() }; - let mut pending_payable_dao = PendingPayableDaoMock::default() + let mut scanner_pending_payable_dao = PendingPayableDaoMock::default() .return_all_fingerprints_params(&return_all_fingerprints_params_arc) .return_all_fingerprints_result(vec![]) .return_all_fingerprints_result(vec![ @@ -3882,8 +3884,6 @@ mod tests { .insert_fingerprint_params(&insert_fingerprint_params_arc) .insert_fingerprint_result(Ok(())) .insert_fingerprint_result(Ok(())) - .fingerprint_rowid_result(Some(rowid_for_account_1)) - .fingerprint_rowid_result(Some(rowid_for_account_2)) .update_fingerprint_params(&update_fingerprint_params_arc) .update_fingerprint_results(Ok(())) .update_fingerprint_results(Ok(())) @@ -3897,16 +3897,19 @@ mod tests { .delete_fingerprint_params(&delete_record_params_arc) //this is used during confirmation of the successful one .delete_fingerprint_result(Ok(())); - pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; + scanner_pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; + let mut accountant_pending_payable_dao = PendingPayableDaoMock::default() + .fingerprint_rowid_result(Some(rowid_for_account_1)) + .fingerprint_rowid_result(Some(rowid_for_account_2)); let accountant_addr = Arbiter::builder() .stop_system_on_panic(true) .start(move |_| { let mut subject = AccountantBuilder::default() .bootstrapper_config(bootstrapper_config) - .payable_dao(PayableDaoMock::new()) - .payable_dao(payable_dao) - .pending_payable_dao(PendingPayableDaoMock::new()) - .pending_payable_dao(pending_payable_dao) + .payable_dao(accountant_payable_dao) + .payable_dao(scanner_payable_dao) + .pending_payable_dao(accountant_pending_payable_dao) + .pending_payable_dao(scanner_pending_payable_dao) .build(); subject.scanners.receivables = Box::new(NullScanner::new()); let notify_later_half_mock = NotifyLaterHandleMock::default() From deec7a2879ba983c211f83900d1fb93bff81e1b0 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 14 Sep 2022 12:46:17 +0530 Subject: [PATCH 085/145] GH-611: provide correct DAOs to the Accountant after migrating handle_sent_payable() to end_scan() inside the PayableScanner --- node/src/accountant/mod.rs | 133 ++++++++++++++++++++---------- node/src/accountant/scanners.rs | 98 ++++++++++++++++++---- node/src/accountant/test_utils.rs | 1 + node/src/accountant/tools.rs | 53 +++++++++++- 4 files changed, 222 insertions(+), 63 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 545f6a2e7..8bb514ee6 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -178,7 +178,25 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: SentPayable, _ctx: &mut Self::Context) -> Self::Result { - self.handle_sent_payable(msg); + // self.handle_sent_payable(msg); + match self.scanners.payables.scan_finished(msg, &self.logger) { + Ok(()) => { + todo!("send message to the UI"); + // if let Some(response_skeleton) = msg.response_skeleton_opt { + // self.ui_message_sub + // .as_ref() + // .expect("UIGateway is not bound") + // .try_send(NodeToUiMessage { + // target: MessageTarget::ClientId(response_skeleton.client_id), + // body: UiScanResponse {}.tmb(response_skeleton.context_id), + // }) + // .expect("UIGateway is dead"); + // } + } + Err(e) => { + todo!("do something in case you receive some"); + } + } } } @@ -432,6 +450,7 @@ impl Accountant { .take() .expectv("Payment thresholds"), ); + // let pending_payable_factory_clone = pending_payable_dao_factory.clone(); let earning_wallet = Rc::new(config.earning_wallet.clone()); Accountant { accountant_config, @@ -444,7 +463,7 @@ impl Accountant { crashable: config.crash_point == CrashPoint::Message, scanners: Scanners::new( payable_dao_factory.make(), - pending_payable_dao_factory.make(), + pending_payable_dao_factory, receivable_dao_factory.make(), banned_dao_factory.make(), Rc::clone(&payment_thresholds), @@ -618,6 +637,7 @@ impl Accountant { } fn handle_sent_payable(&self, sent_payable: SentPayable) { + todo!("migrate to scanners"); // self.scanners.payables.mark_as_ended(); let (ok, err) = Self::separate_early_errors(&sent_payable, &self.logger); debug!(self.logger, "We gathered these errors at sending transactions for payable: {:?}, out of the total of {} attempts", err, ok.len() + err.len()); @@ -641,6 +661,7 @@ impl Accountant { } fn discard_incomplete_transaction_with_a_failure(&self, hash: H256) { + todo!("migrate it to scanners"); if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(hash) { debug!( self.logger, @@ -927,6 +948,7 @@ impl Accountant { sent_payments: &SentPayable, logger: &Logger, ) -> (Vec, Vec) { + todo!("migrate to tools.rs"); sent_payments .payable .iter() @@ -945,6 +967,7 @@ impl Accountant { } fn mark_pending_payable(&self, sent_payments: Vec) { + todo!("mark pending payable"); sent_payments .into_iter() .for_each(|payable| { @@ -1240,6 +1263,7 @@ mod tests { let pending_payable_dao_factory = PendingPayableDaoFactoryMock::new() .make_params(&pending_payable_dao_factory_params_arc) .make_result(PendingPayableDaoMock::new()) + .make_result(PendingPayableDaoMock::new()) .make_result(PendingPayableDaoMock::new()); let receivable_dao_factory = ReceivableDaoFactoryMock::new() .make_params(&receivable_dao_factory_params_arc) @@ -1264,7 +1288,7 @@ mod tests { ); assert_eq!( *pending_payable_dao_factory_params_arc.lock().unwrap(), - vec![(), ()] + vec![(), (), ()] ); assert_eq!( *receivable_dao_factory_params_arc.lock().unwrap(), @@ -1293,7 +1317,8 @@ mod tests { let pending_payable_dao_factory = Box::new( PendingPayableDaoFactoryMock::new() .make_result(PendingPayableDaoMock::new()) // For Accountant - .make_result(PendingPayableDaoMock::new()), // For Scanner + .make_result(PendingPayableDaoMock::new()) // For Payable Scanner + .make_result(PendingPayableDaoMock::new()), // For PendingPayable Scanner ); let receivable_dao_factory = Box::new( ReceivableDaoFactoryMock::new() @@ -1587,8 +1612,9 @@ mod tests { .return_all_fingerprints_result(vec![fingerprint.clone()]); let subject = AccountantBuilder::default() .bootstrapper_config(config) - .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountanr - .pending_payable_dao(pending_payable_dao) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(pending_payable_dao) // For PendingPayable Scanner .build(); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); @@ -1651,8 +1677,9 @@ mod tests { PendingPayableDaoMock::default().return_all_fingerprints_result(vec![fingerprint]); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .pending_payable_dao(PendingPayableDaoMock::new()) - .pending_payable_dao(pending_payable_dao) + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(pending_payable_dao) // For PendingPayable Scanner .build(); subject.logger = Logger::new(test_name); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); @@ -1757,10 +1784,11 @@ mod tests { make_payment_thresholds_with_defaults(), make_wallet("some_wallet_address"), )) - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Payable Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); let expected_payable = Payable::new( expected_wallet.clone(), @@ -1795,8 +1823,9 @@ mod tests { let system = System::new("sent payable failure without backup"); let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(None); let accountant = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Payable Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); let hash = H256::from_uint(&U256::from(12345)); let sent_payable = SentPayable { @@ -1849,9 +1878,10 @@ mod tests { .delete_fingerprint_params(&delete_fingerprint_params_arc) .delete_fingerprint_result(Ok(())); let subject = AccountantBuilder::default() - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .pending_payable_dao(pending_payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Payable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let wallet = make_wallet("blah"); @@ -2074,7 +2104,8 @@ mod tests { .payable_dao(PayableDaoMock::new()) // For Accountant .payable_dao(payable_dao) // For Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant - .pending_payable_dao(pending_payable_dao) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(pending_payable_dao) // For PendingPayable Scanner .receivable_dao(ReceivableDaoMock::new()) // For Accountant .receivable_dao(receivable_dao) // For Scanner .build(); @@ -2724,7 +2755,8 @@ mod tests { let system = System::new("pending payable scan"); let mut subject = AccountantBuilder::default() .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant - .pending_payable_dao(pending_payable_dao) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(pending_payable_dao) // For PendiingPayable Scanner .bootstrapper_config(config) .build(); let blockchain_bridge_addr = blockchain_bridge.start(); @@ -3450,7 +3482,8 @@ mod tests { .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); let _ = subject.mark_pending_payable(vec![payable]); @@ -3479,7 +3512,8 @@ mod tests { ))); let subject = AccountantBuilder::default() .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); let _ = subject.handle_sent_payable(sent_payable); @@ -3511,6 +3545,7 @@ mod tests { .payable_dao(PayableDaoMock::new()) // For Scanner .pending_payable_dao(pending_payable_dao) // For Accountant .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); subject.handle_sent_payable(sent_payable); @@ -3540,6 +3575,7 @@ mod tests { .payable_dao(PayableDaoMock::new()) // For Scanner .pending_payable_dao(pending_payable_dao) // For Accountant .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); let _ = subject.mark_pending_payable(vec![payment]); @@ -3560,7 +3596,8 @@ mod tests { .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); let tx_hash = H256::from("sometransactionhash".keccak256()); let amount = 4567; @@ -3637,7 +3674,8 @@ mod tests { .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); let mut pending_payable_fingerprint = make_pending_payable_fingerprint(); pending_payable_fingerprint.rowid_opt = Some(rowid); @@ -3658,7 +3696,8 @@ mod tests { .mark_failure_result(Ok(())); let subject = AccountantBuilder::default() .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); let tx_hash = H256::from("sometransactionhash".keccak256()); let rowid = 2; @@ -3693,6 +3732,7 @@ mod tests { .payable_dao(PayableDaoMock::new()) // For Scanner .pending_payable_dao(pending_payable_dao) .pending_payable_dao(PendingPayableDaoMock::new()) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); let rowid = 2; let hash = H256::from("sometransactionhash".keccak256()); @@ -4248,7 +4288,8 @@ mod tests { .insert_fingerprint_result(Ok(())); let subject = AccountantBuilder::default() .pending_payable_dao(pending_payment_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); let accountant_addr = subject.start(); let tx_hash = H256::from_uint(&U256::from(55)); @@ -4297,6 +4338,7 @@ mod tests { let subject = AccountantBuilder::default() .pending_payable_dao(pending_payable_dao) .pending_payable_dao(PendingPayableDaoMock::new()) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); let timestamp_secs = 150_000_000; let fingerprint = PendingPayableFingerprint { @@ -4318,25 +4360,25 @@ mod tests { TestLogHandler::new().exists_log_containing("ERROR: Accountant: Failed to make a fingerprint for pending payable '0x0000…01c8' due to 'InsertionFailed(\"Crashed\")'"); } - #[test] - fn separate_early_errors_works() { - let payable_ok = Payable { - to: make_wallet("blah"), - amount: 5555, - timestamp: SystemTime::now(), - tx_hash: Default::default(), - }; - let error = BlockchainError::SignedValueConversion(666); - let sent_payable = SentPayable { - payable: vec![Ok(payable_ok.clone()), Err(error.clone())], - response_skeleton_opt: None, - }; - - let (ok, err) = Accountant::separate_early_errors(&sent_payable, &Logger::new("test")); - - assert_eq!(ok, vec![payable_ok]); - assert_eq!(err, vec![error]) - } + // #[test] + // fn separate_early_errors_works() { + // let payable_ok = Payable { + // to: make_wallet("blah"), + // amount: 5555, + // timestamp: SystemTime::now(), + // tx_hash: Default::default(), + // }; + // let error = BlockchainError::SignedValueConversion(666); + // let sent_payable = SentPayable { + // payable: vec![Ok(payable_ok.clone()), Err(error.clone())], + // response_skeleton_opt: None, + // }; + // + // let (ok, err) = Accountant::separate_early_errors(&sent_payable, &Logger::new("test")); + // + // assert_eq!(ok, vec![payable_ok]); + // assert_eq!(err, vec![error]) + // } #[test] fn update_payable_fingerprint_happy_path() { @@ -4349,6 +4391,7 @@ mod tests { let subject = AccountantBuilder::default() .pending_payable_dao(pending_payable_dao) .pending_payable_dao(PendingPayableDaoMock::new()) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); let transaction_id = PendingPayableId { hash, rowid }; @@ -4372,6 +4415,7 @@ mod tests { let subject = AccountantBuilder::default() .pending_payable_dao(pending_payable_dao) .pending_payable_dao(PendingPayableDaoMock::new()) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); let transaction_id = PendingPayableId { hash, rowid }; @@ -4487,6 +4531,7 @@ mod tests { .payable_dao(PayableDaoMock::new()) .pending_payable_dao(pending_payable_dao) .pending_payable_dao(PendingPayableDaoMock::new()) + .pending_payable_dao(PendingPayableDaoMock::new()) .build(); subject.financial_statistics.total_paid_payable += 1111; let msg = ConfirmPendingTransaction { diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index c8614ccbb..f0e408272 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -2,10 +2,10 @@ pub(in crate::accountant) mod scanners { use crate::accountant::payable_dao::PayableDao; - use crate::accountant::pending_payable_dao::PendingPayableDao; + use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDaoFactory}; use crate::accountant::receivable_dao::ReceivableDao; use crate::accountant::tools::payable_scanner_tools::{ - investigate_debt_extremes, qualified_payables_and_summary, + investigate_debt_extremes, qualified_payables_and_summary, separate_early_errors, }; use crate::accountant::tools::receivable_scanner_tools::balance_and_age; use crate::accountant::ReportAccountsPayable; @@ -22,6 +22,7 @@ pub(in crate::accountant) mod scanners { use actix::Message; use masq_lib::logger::Logger; use std::any::Any; + use std::borrow::Borrow; use std::rc::Rc; use std::time::SystemTime; @@ -44,7 +45,7 @@ pub(in crate::accountant) mod scanners { impl Scanners { pub fn new( payable_dao: Box, - pending_payable_dao: Box, + pending_payable_dao_factory: Box, receivable_dao: Box, banned_dao: Box, payment_thresholds: Rc, @@ -53,10 +54,11 @@ pub(in crate::accountant) mod scanners { Scanners { payables: Box::new(PayableScanner::new( payable_dao, + pending_payable_dao_factory.make(), Rc::clone(&payment_thresholds), )), pending_payables: Box::new(PendingPayableScanner::new( - pending_payable_dao, + pending_payable_dao_factory.make(), Rc::clone(&payment_thresholds), )), receivables: Box::new(ReceivableScanner::new( @@ -80,7 +82,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result; - fn scan_finished(&mut self, message: EndMessage) -> Result<(), Error>; + fn scan_finished(&mut self, message: EndMessage, logger: &Logger) -> Result<(), Error>; fn scan_started_at(&self) -> Option; as_any_dcl!(); } @@ -102,6 +104,7 @@ pub(in crate::accountant) mod scanners { pub struct PayableScanner { common: ScannerCommon, dao: Box, + pending_payable_dao: Box, } impl Scanner for PayableScanner { @@ -142,10 +145,52 @@ pub(in crate::accountant) mod scanners { } } - fn scan_finished(&mut self, _message: SentPayable) -> Result<(), Error> { - todo!() + fn scan_finished(&mut self, message: SentPayable, logger: &Logger) -> Result<(), Error> { // Use the passed-in message and the internal DAO to finish the scan // Ok(()) + + let (sent_payables, blockchain_errors) = separate_early_errors(&message, logger); + debug!(logger, "We gathered these errors at sending transactions for payable: {:?}, out of the total of {} attempts", blockchain_errors, sent_payables.len() + blockchain_errors.len()); + + sent_payables.into_iter() + .for_each(|payable| { + let rowid = match self.pending_payable_dao.fingerprint_rowid(payable.tx_hash) { + Some(rowid) => rowid, + None => panic!("Payable fingerprint for {} doesn't exist but should by now; system unreliable", payable.tx_hash) + }; + match self.dao.as_ref().mark_pending_payable_rowid(&payable.to, rowid) { + Ok(()) => (), + Err(e) => panic!("Was unable to create a mark in payables for a new pending payable '{}' due to '{:?}'", payable.tx_hash, e) + } + debug!(logger, "Payable '{}' has been marked as pending in the payable table",payable.tx_hash) + }); + + if !blockchain_errors.is_empty() { + blockchain_errors.into_iter().for_each(|err| + if let Some(hash) = err.carries_transaction_hash() { + // self.discard_incomplete_transaction_with_a_failure(hash) + if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(hash) { + debug!(logger,"Deleting an existing backup for a failed transaction {}", hash); + if let Err(e) = self.pending_payable_dao.delete_fingerprint(rowid) { + panic!("Database unmaintainable; payable fingerprint deletion for transaction {:?} has stayed undone due to {:?}", hash, e) + } + }; + + warning!(logger, "Failed transaction with a hash '{}' but without the record - thrown out", hash) + } else { debug!(logger,"Forgetting a transaction attempt that even did not reach the signing stage") }) + }; + + Ok(()) + // if let Some(response_skeleton) = &sent_payable.response_skeleton_opt { + // self.ui_message_sub + // .as_ref() + // .expect("UIGateway is not bound") + // .try_send(NodeToUiMessage { + // target: MessageTarget::ClientId(response_skeleton.client_id), + // body: UiScanResponse {}.tmb(response_skeleton.context_id), + // }) + // .expect("UIGateway is dead"); + // } } fn scan_started_at(&self) -> Option { @@ -156,10 +201,15 @@ pub(in crate::accountant) mod scanners { } impl PayableScanner { - pub fn new(dao: Box, payment_thresholds: Rc) -> Self { + pub fn new( + dao: Box, + pending_payable_dao: Box, + payment_thresholds: Rc, + ) -> Self { Self { common: ScannerCommon::new(payment_thresholds), dao, + pending_payable_dao, } } } @@ -204,7 +254,11 @@ pub(in crate::accountant) mod scanners { } } - fn scan_finished(&mut self, _message: ReportTransactionReceipts) -> Result<(), Error> { + fn scan_finished( + &mut self, + _message: ReportTransactionReceipts, + logger: &Logger, + ) -> Result<(), Error> { todo!() } @@ -285,7 +339,11 @@ pub(in crate::accountant) mod scanners { }) } - fn scan_finished(&mut self, _message: ReceivedPayments) -> Result<(), Error> { + fn scan_finished( + &mut self, + _message: ReceivedPayments, + logger: &Logger, + ) -> Result<(), Error> { todo!() } @@ -328,7 +386,7 @@ pub(in crate::accountant) mod scanners { Err(ScannerError::CalledFromNullScanner) } - fn scan_finished(&mut self, _message: EndMessage) -> Result<(), Error> { + fn scan_finished(&mut self, _message: EndMessage, logger: &Logger) -> Result<(), Error> { todo!() } @@ -429,7 +487,7 @@ mod tests { }; use crate::accountant::test_utils::{ make_payables, make_receivable_account, BannedDaoMock, PayableDaoMock, - PendingPayableDaoMock, ReceivableDaoMock, + PendingPayableDaoFactoryMock, PendingPayableDaoMock, ReceivableDaoMock, }; use crate::accountant::RequestTransactionReceipts; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; @@ -449,7 +507,7 @@ mod tests { let payment_thresholds = Rc::new(make_payment_thresholds_with_defaults()); let scanners = Scanners::new( Box::new(PayableDaoMock::new()), - Box::new(PendingPayableDaoMock::new()), + Box::new(PendingPayableDaoFactoryMock::new()), Box::new(ReceivableDaoMock::new()), Box::new(BannedDaoMock::new()), Rc::clone(&payment_thresholds), @@ -484,8 +542,11 @@ mod tests { let payable_dao = PayableDaoMock::new().non_pending_payables_result(all_non_pending_payables); - let mut payable_scanner = - PayableScanner::new(Box::new(payable_dao), Rc::new(payment_thresholds)); + let mut payable_scanner = PayableScanner::new( + Box::new(payable_dao), + Box::new(PendingPayableDaoMock::new()), + Rc::new(payment_thresholds), + ); let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); @@ -521,8 +582,11 @@ mod tests { let payable_dao = PayableDaoMock::new().non_pending_payables_result(unqualified_payable_accounts); - let mut payable_scanner = - PayableScanner::new(Box::new(payable_dao), Rc::new(payment_thresholds)); + let mut payable_scanner = PayableScanner::new( + Box::new(payable_dao), + Box::new(PendingPayableDaoMock::new()), + Rc::new(payment_thresholds), + ); let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 77243f98e..cf16ef05e 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -175,6 +175,7 @@ impl AccountantBuilder { ); let pending_payable_dao_factory = self.pending_payable_dao_factory.unwrap_or( PendingPayableDaoFactoryMock::new() + .make_result(PendingPayableDaoMock::new()) .make_result(PendingPayableDaoMock::new()) .make_result(PendingPayableDaoMock::new()), ); diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index e427f85e4..df1cbf85d 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -1,8 +1,12 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. pub(crate) mod payable_scanner_tools { - use crate::accountant::payable_dao::PayableAccount; + use crate::accountant::payable_dao::{Payable, PayableAccount}; + use crate::accountant::SentPayable; + use crate::blockchain::blockchain_interface::BlockchainError; use crate::sub_lib::accountant::PaymentThresholds; + use masq_lib::logger::Logger; + use masq_lib::utils::plus; use std::time::SystemTime; //for debugging only @@ -148,6 +152,27 @@ pub(crate) mod payable_scanner_tools { (qualified_payables, summary) } + + pub(crate) fn separate_early_errors( + sent_payments: &SentPayable, + logger: &Logger, + ) -> (Vec, Vec) { + sent_payments + .payable + .iter() + .fold((vec![], vec![]), |so_far, payment| { + match payment { + Ok(payment_sent) => (plus(so_far.0, payment_sent.clone()), so_far.1), + Err(error) => { + logger.warning(|| match &error { + BlockchainError::TransactionFailed { .. } => format!("Encountered transaction error at this end: '{:?}'", error), + x => format!("Outbound transaction failure due to '{:?}'. Please check your blockchain service URL configuration.", x) + }); + (so_far.0, plus(so_far.1, error.clone())) + } + } + }) + } } pub(crate) mod receivable_scanner_tools { @@ -168,16 +193,20 @@ pub(crate) mod receivable_scanner_tools { #[cfg(test)] mod tests { - use crate::accountant::payable_dao::PayableAccount; + use crate::accountant::payable_dao::{Payable, PayableAccount}; use crate::accountant::receivable_dao::ReceivableAccount; use crate::accountant::tools::payable_scanner_tools::{ calculate_payout_threshold, exceeded_summary, investigate_debt_extremes, is_payable_qualified, payable_time_diff, qualified_payables_and_summary, + separate_early_errors, }; use crate::accountant::tools::receivable_scanner_tools::balance_and_age; + use crate::accountant::SentPayable; + use crate::blockchain::blockchain_interface::BlockchainError; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; + use masq_lib::logger::Logger; use std::rc::Rc; use std::time::SystemTime; @@ -397,6 +426,26 @@ mod tests { assert_eq!(age.as_secs(), offset as u64); } + #[test] + fn separate_early_errors_works() { + let payable_ok = Payable { + to: make_wallet("blah"), + amount: 5555, + timestamp: SystemTime::now(), + tx_hash: Default::default(), + }; + let error = BlockchainError::SignedValueConversion(666); + let sent_payable = SentPayable { + payable: vec![Ok(payable_ok.clone()), Err(error.clone())], + response_skeleton_opt: None, + }; + + let (ok, err) = separate_early_errors(&sent_payable, &Logger::new("test")); + + assert_eq!(ok, vec![payable_ok]); + assert_eq!(err, vec![error]) + } + // TODO: Either make this test work or write an alternative test in the desired file // #[test] // fn threshold_calculation_depends_on_user_defined_payment_thresholds() { From 9623e4ae5f1e41f8c36fccc59801580ff39e7e9e Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 14 Sep 2022 15:15:34 +0530 Subject: [PATCH 086/145] GH-611: fix tests in accountant to call scan_finished() directly --- node/src/accountant/mod.rs | 68 +++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 8bb514ee6..9f745fe97 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -3478,15 +3478,22 @@ mod tests { .mark_pending_payable_rowid_result(Err(PayableDaoError::SignConversion(9999999999999))); let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(Some(7879)); - let subject = AccountantBuilder::default() - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + let mut subject = AccountantBuilder::default() + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Payable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); + let sent_payable = SentPayable { + payable: vec![Ok(payable)], + response_skeleton_opt: None, + }; - let _ = subject.mark_pending_payable(vec![payable]); + let _ = subject + .scanners + .payables + .scan_finished(sent_payable, &Logger::new("test")); } #[test] @@ -3510,13 +3517,16 @@ mod tests { .delete_fingerprint_result(Err(PendingPayableDaoError::RecordDeletion( "we slept over, sorry".to_string(), ))); - let subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner + let mut subject = AccountantBuilder::default() + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Payable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); - let _ = subject.handle_sent_payable(sent_payable); + let _ = subject + .scanners + .payables + .scan_finished(sent_payable, &Logger::new("test")); } #[test] @@ -3537,18 +3547,22 @@ mod tests { payable: vec![payable_1, Ok(payable_2.clone()), payable_3], response_skeleton_opt: None, }; + let payable_dao = PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(())); let pending_payable_dao = PendingPayableDaoMock::default() .fingerprint_rowid_params(&fingerprint_rowid_params_arc) .fingerprint_rowid_result(Some(payable_2_rowid)); - let subject = AccountantBuilder::default() - .payable_dao(PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(()))) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + let mut subject = AccountantBuilder::default() + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); - subject.handle_sent_payable(sent_payable); + subject + .scanners + .payables + .scan_finished(sent_payable, &Logger::new("Accountant")); let fingerprint_rowid_params = fingerprint_rowid_params_arc.lock().unwrap(); assert_eq!(*fingerprint_rowid_params, vec![payable_hash_2]); //we know the other two errors are associated with an initiated transaction having a backup @@ -3568,17 +3582,25 @@ mod tests { init_test_logging(); let now_system = SystemTime::now(); let payment_hash = H256::from_uint(&U256::from(789)); - let payment = Payable::new(make_wallet("booga"), 6789, payment_hash, now_system); + let payable = Payable::new(make_wallet("booga"), 6789, payment_hash, now_system); + let payable_dao = PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(())); let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(None); - let subject = AccountantBuilder::default() - .payable_dao(PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(()))) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner + let mut subject = AccountantBuilder::default() + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Scanner + .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant + .pending_payable_dao(pending_payable_dao) // For Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); + let sent_payable = SentPayable { + payable: vec![Ok(payable)], + response_skeleton_opt: None, + }; - let _ = subject.mark_pending_payable(vec![payment]); + let _ = subject + .scanners + .payables + .scan_finished(sent_payable, &Logger::new("test")); } #[test] From ba35d446255bfefa15950584d820967da62a6fef Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 14 Sep 2022 15:26:25 +0530 Subject: [PATCH 087/145] GH-611: migrate all code of handle_sent_payable() to scan_finished() for the PayableScanner --- node/src/accountant/mod.rs | 83 +++++---------------------------- node/src/accountant/scanners.rs | 5 +- 2 files changed, 15 insertions(+), 73 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 9f745fe97..b8e2bb902 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -178,20 +178,19 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: SentPayable, _ctx: &mut Self::Context) -> Self::Result { - // self.handle_sent_payable(msg); + let response_skeleton_opt = msg.response_skeleton_opt; match self.scanners.payables.scan_finished(msg, &self.logger) { Ok(()) => { - todo!("send message to the UI"); - // if let Some(response_skeleton) = msg.response_skeleton_opt { - // self.ui_message_sub - // .as_ref() - // .expect("UIGateway is not bound") - // .try_send(NodeToUiMessage { - // target: MessageTarget::ClientId(response_skeleton.client_id), - // body: UiScanResponse {}.tmb(response_skeleton.context_id), - // }) - // .expect("UIGateway is dead"); - // } + if let Some(response_skeleton) = response_skeleton_opt { + self.ui_message_sub + .as_ref() + .expect("UIGateway is not bound") + .try_send(NodeToUiMessage { + target: MessageTarget::ClientId(response_skeleton.client_id), + body: UiScanResponse {}.tmb(response_skeleton.context_id), + }) + .expect("UIGateway is dead"); + } } Err(e) => { todo!("do something in case you receive some"); @@ -636,49 +635,6 @@ impl Accountant { } } - fn handle_sent_payable(&self, sent_payable: SentPayable) { - todo!("migrate to scanners"); - // self.scanners.payables.mark_as_ended(); - let (ok, err) = Self::separate_early_errors(&sent_payable, &self.logger); - debug!(self.logger, "We gathered these errors at sending transactions for payable: {:?}, out of the total of {} attempts", err, ok.len() + err.len()); - self.mark_pending_payable(ok); - if !err.is_empty() { - err.into_iter().for_each(|err| - if let Some(hash) = err.carries_transaction_hash() { - self.discard_incomplete_transaction_with_a_failure(hash) - } else { debug!(self.logger,"Forgetting a transaction attempt that even did not reach the signing stage") }) - } - if let Some(response_skeleton) = &sent_payable.response_skeleton_opt { - self.ui_message_sub - .as_ref() - .expect("UIGateway is not bound") - .try_send(NodeToUiMessage { - target: MessageTarget::ClientId(response_skeleton.client_id), - body: UiScanResponse {}.tmb(response_skeleton.context_id), - }) - .expect("UIGateway is dead"); - } - } - - fn discard_incomplete_transaction_with_a_failure(&self, hash: H256) { - todo!("migrate it to scanners"); - if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(hash) { - debug!( - self.logger, - "Deleting an existing backup for a failed transaction {}", hash - ); - if let Err(e) = self.pending_payable_dao.delete_fingerprint(rowid) { - panic!("Database unmaintainable; payable fingerprint deletion for transaction {:?} has stayed undone due to {:?}", hash, e) - } - }; - - warning!( - self.logger, - "Failed transaction with a hash '{}' but without the record - thrown out", - hash - ) - } - fn handle_report_routing_service_provided_message( &mut self, msg: ReportRoutingServiceProvidedMessage, @@ -966,23 +922,6 @@ impl Accountant { }) } - fn mark_pending_payable(&self, sent_payments: Vec) { - todo!("mark pending payable"); - sent_payments - .into_iter() - .for_each(|payable| { - let rowid = match self.pending_payable_dao.fingerprint_rowid(payable.tx_hash) { - Some(rowid) => rowid, - None => panic!("Payable fingerprint for {} doesn't exist but should by now; system unreliable", payable.tx_hash) - }; - match self.payable_dao.as_ref().mark_pending_payable_rowid(&payable.to, rowid) { - Ok(()) => (), - Err(e) => panic!("Was unable to create a mark in payables for a new pending payable '{}' due to '{:?}'", payable.tx_hash, e) - } - debug!(self.logger, "Payable '{}' has been marked as pending in the payable table",payable.tx_hash) - }) - } - fn handle_pending_transaction_with_its_receipt( &self, msg: &ReportTransactionReceipts, diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index f0e408272..b02eaaae2 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -505,9 +505,12 @@ mod tests { #[test] fn scanners_struct_can_be_constructed_with_the_respective_scanners() { let payment_thresholds = Rc::new(make_payment_thresholds_with_defaults()); + let pending_payable_dao_factory = PendingPayableDaoFactoryMock::new() + .make_result(PendingPayableDaoMock::new()) + .make_result(PendingPayableDaoMock::new()); let scanners = Scanners::new( Box::new(PayableDaoMock::new()), - Box::new(PendingPayableDaoFactoryMock::new()), + Box::new(pending_payable_dao_factory), Box::new(ReceivableDaoMock::new()), Box::new(BannedDaoMock::new()), Rc::clone(&payment_thresholds), From e746614a594b8b6e446520e73bbeaacde190bdf1 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 14 Sep 2022 16:43:46 +0530 Subject: [PATCH 088/145] GH-611: throw errors when a problem happens while handling SentPayable message --- node/src/accountant/mod.rs | 80 ++------------- node/src/accountant/scanners.rs | 169 ++++++++++++++++++++++++++------ 2 files changed, 150 insertions(+), 99 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index b8e2bb902..323cc7f3d 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -193,7 +193,7 @@ impl Handler for Accountant { } } Err(e) => { - todo!("do something in case you receive some"); + panic!("{}", e); } } } @@ -3402,46 +3402,13 @@ mod tests { let _ = subject.record_service_consumed(i64::MAX as u64, 1, 2, &wallet); } - #[test] - #[should_panic( - expected = "Was unable to create a mark in payables for a new pending payable '0x0000…007b' due to 'SignConversion(9999999999999)'" - )] - fn handle_sent_payable_fails_to_make_a_mark_in_payables_and_so_panics() { - let payable = Payable::new( - make_wallet("blah"), - 6789, - H256::from_uint(&U256::from(123)), - SystemTime::now(), - ); - let payable_dao = PayableDaoMock::new() - .mark_pending_payable_rowid_result(Err(PayableDaoError::SignConversion(9999999999999))); - let pending_payable_dao = - PendingPayableDaoMock::default().fingerprint_rowid_result(Some(7879)); - let mut subject = AccountantBuilder::default() - .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner - .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant - .pending_payable_dao(pending_payable_dao) // For Payable Scanner - .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner - .build(); - let sent_payable = SentPayable { - payable: vec![Ok(payable)], - response_skeleton_opt: None, - }; - - let _ = subject - .scanners - .payables - .scan_finished(sent_payable, &Logger::new("test")); - } - #[test] #[should_panic( expected = "Database unmaintainable; payable fingerprint deletion for transaction 0x000000000000000000000000000000000000000000000000000000000000007b \ has stayed undone due to RecordDeletion(\"we slept over, sorry\")" )] - fn handle_sent_payable_dealing_with_failed_payment_fails_to_delete_the_existing_pending_payable_fingerprint_and_panics( - ) { + fn accountant_panics_in_case_it_receives_an_error_from_scanner_while_handling_sent_payable_msg() + { let rowid = 4; let hash = H256::from_uint(&U256::from(123)); let sent_payable = SentPayable { @@ -3456,16 +3423,18 @@ mod tests { .delete_fingerprint_result(Err(PendingPayableDaoError::RecordDeletion( "we slept over, sorry".to_string(), ))); + let system = System::new("test"); let mut subject = AccountantBuilder::default() .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant .pending_payable_dao(pending_payable_dao) // For Payable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner .build(); + let addr = subject.start(); - let _ = subject - .scanners - .payables - .scan_finished(sent_payable, &Logger::new("test")); + let _ = addr.try_send(sent_payable); + + System::current().stop(); + assert_eq!(system.run(), 0); } #[test] @@ -3498,7 +3467,7 @@ mod tests { .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner .build(); - subject + let _result = subject .scanners .payables .scan_finished(sent_payable, &Logger::new("Accountant")); @@ -3513,35 +3482,6 @@ mod tests { // TODO: Assert subject.scan_for_payables_in_progress [No scan in progress] } - #[test] - #[should_panic( - expected = "Payable fingerprint for 0x0000…0315 doesn't exist but should by now; system unreliable" - )] - fn handle_sent_payable_receives_proper_payment_but_fingerprint_not_found_so_it_panics() { - init_test_logging(); - let now_system = SystemTime::now(); - let payment_hash = H256::from_uint(&U256::from(789)); - let payable = Payable::new(make_wallet("booga"), 6789, payment_hash, now_system); - let payable_dao = PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(())); - let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(None); - let mut subject = AccountantBuilder::default() - .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner - .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant - .pending_payable_dao(pending_payable_dao) // For Scanner - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner - .build(); - let sent_payable = SentPayable { - payable: vec![Ok(payable)], - response_skeleton_opt: None, - }; - - let _ = subject - .scanners - .payables - .scan_finished(sent_payable, &Logger::new("test")); - } - #[test] fn handle_confirm_transaction_works() { init_test_logging(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index b02eaaae2..9bf6c1ddb 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -82,7 +82,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result; - fn scan_finished(&mut self, message: EndMessage, logger: &Logger) -> Result<(), Error>; + fn scan_finished(&mut self, message: EndMessage, logger: &Logger) -> Result<(), String>; fn scan_started_at(&self) -> Option; as_any_dcl!(); } @@ -145,40 +145,53 @@ pub(in crate::accountant) mod scanners { } } - fn scan_finished(&mut self, message: SentPayable, logger: &Logger) -> Result<(), Error> { + fn scan_finished(&mut self, message: SentPayable, logger: &Logger) -> Result<(), String> { // Use the passed-in message and the internal DAO to finish the scan // Ok(()) let (sent_payables, blockchain_errors) = separate_early_errors(&message, logger); debug!(logger, "We gathered these errors at sending transactions for payable: {:?}, out of the total of {} attempts", blockchain_errors, sent_payables.len() + blockchain_errors.len()); - sent_payables.into_iter() - .for_each(|payable| { - let rowid = match self.pending_payable_dao.fingerprint_rowid(payable.tx_hash) { - Some(rowid) => rowid, - None => panic!("Payable fingerprint for {} doesn't exist but should by now; system unreliable", payable.tx_hash) - }; - match self.dao.as_ref().mark_pending_payable_rowid(&payable.to, rowid) { - Ok(()) => (), - Err(e) => panic!("Was unable to create a mark in payables for a new pending payable '{}' due to '{:?}'", payable.tx_hash, e) + for payable in sent_payables { + if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(payable.tx_hash) { + if let Err(e) = self + .dao + .as_ref() + .mark_pending_payable_rowid(&payable.to, rowid) + { + return Err(format!("Was unable to create a mark in payables for a new pending payable '{}' due to '{:?}'", payable.tx_hash, e)); } - debug!(logger, "Payable '{}' has been marked as pending in the payable table",payable.tx_hash) - }); + } else { + return Err(format!("Payable fingerprint for {} doesn't exist but should by now; system unreliable", payable.tx_hash)); + }; + + debug!( + logger, + "Payable '{}' has been marked as pending in the payable table", payable.tx_hash + ) + } - if !blockchain_errors.is_empty() { - blockchain_errors.into_iter().for_each(|err| - if let Some(hash) = err.carries_transaction_hash() { - // self.discard_incomplete_transaction_with_a_failure(hash) - if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(hash) { - debug!(logger,"Deleting an existing backup for a failed transaction {}", hash); - if let Err(e) = self.pending_payable_dao.delete_fingerprint(rowid) { - panic!("Database unmaintainable; payable fingerprint deletion for transaction {:?} has stayed undone due to {:?}", hash, e) - } + for blockchain_error in blockchain_errors { + if let Some(hash) = blockchain_error.carries_transaction_hash() { + if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(hash) { + debug!( + logger, + "Deleting an existing backup for a failed transaction {}", hash + ); + if let Err(e) = self.pending_payable_dao.delete_fingerprint(rowid) { + return Err(format!("Database unmaintainable; payable fingerprint deletion for transaction {:?} has stayed undone due to {:?}", hash, e)); }; + }; - warning!(logger, "Failed transaction with a hash '{}' but without the record - thrown out", hash) - } else { debug!(logger,"Forgetting a transaction attempt that even did not reach the signing stage") }) - }; + warning!( + logger, + "Failed transaction with a hash '{}' but without the record - thrown out", + hash + ) + } else { + debug!(logger,"Forgetting a transaction attempt that even did not reach the signing stage") + }; + } Ok(()) // if let Some(response_skeleton) = &sent_payable.response_skeleton_opt { @@ -258,7 +271,7 @@ pub(in crate::accountant) mod scanners { &mut self, _message: ReportTransactionReceipts, logger: &Logger, - ) -> Result<(), Error> { + ) -> Result<(), String> { todo!() } @@ -343,7 +356,7 @@ pub(in crate::accountant) mod scanners { &mut self, _message: ReceivedPayments, logger: &Logger, - ) -> Result<(), Error> { + ) -> Result<(), String> { todo!() } @@ -386,7 +399,7 @@ pub(in crate::accountant) mod scanners { Err(ScannerError::CalledFromNullScanner) } - fn scan_finished(&mut self, _message: EndMessage, logger: &Logger) -> Result<(), Error> { + fn scan_finished(&mut self, _message: EndMessage, logger: &Logger) -> Result<(), String> { todo!() } @@ -489,18 +502,23 @@ mod tests { make_payables, make_receivable_account, BannedDaoMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, ReceivableDaoMock, }; - use crate::accountant::RequestTransactionReceipts; + use crate::accountant::{RequestTransactionReceipts, SentPayable}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; + use crate::accountant::payable_dao::{Payable, PayableDaoError}; + use crate::accountant::pending_payable_dao::PendingPayableDaoError; + use crate::blockchain::blockchain_interface::BlockchainError; use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; + use ethereum_types::BigEndianHash; use masq_lib::logger::Logger; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; use std::rc::Rc; use std::sync::{Arc, Mutex, MutexGuard}; use std::time::SystemTime; + use web3::types::{H256, U256}; #[test] fn scanners_struct_can_be_constructed_with_the_respective_scanners() { @@ -600,6 +618,99 @@ mod tests { ]); } + #[test] + fn payable_scanner_throws_error_when_fingerprint_is_not_found() { + init_test_logging(); + let now_system = SystemTime::now(); + let payment_hash = H256::from_uint(&U256::from(789)); + let payable = Payable::new(make_wallet("booga"), 6789, payment_hash, now_system); + let payable_dao = PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(())); + let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(None); + let mut subject = PayableScanner::new( + Box::new(payable_dao), + Box::new(pending_payable_dao), + Rc::new(make_payment_thresholds_with_defaults()), + ); + let sent_payable = SentPayable { + payable: vec![Ok(payable)], + response_skeleton_opt: None, + }; + + let result = subject.scan_finished(sent_payable, &Logger::new("test")); + + assert_eq!(result, Err("Payable fingerprint for 0x0000…0315 doesn't exist but should by now; system unreliable".to_string())); + } + + #[test] + fn payable_scanner_throws_error_when_dealing_with_failed_payment_fails_to_delete_the_existing_pending_payable_fingerprint( + ) { + let rowid = 4; + let hash = H256::from_uint(&U256::from(123)); + let sent_payable = SentPayable { + payable: vec![Err(BlockchainError::TransactionFailed { + msg: "blah".to_string(), + hash_opt: Some(hash), + })], + response_skeleton_opt: None, + }; + let pending_payable_dao = PendingPayableDaoMock::default() + .fingerprint_rowid_result(Some(rowid)) + .delete_fingerprint_result(Err(PendingPayableDaoError::RecordDeletion( + "we slept over, sorry".to_string(), + ))); + let mut subject = PayableScanner::new( + Box::new(PayableDaoMock::new()), + Box::new(pending_payable_dao), + Rc::new(make_payment_thresholds_with_defaults()), + ); + + let result = subject.scan_finished(sent_payable, &Logger::new("test")); + + assert_eq!( + result, + Err( + "Database unmaintainable; payable fingerprint deletion for transaction \ + 0x000000000000000000000000000000000000000000000000000000000000007b has stayed \ + undone due to RecordDeletion(\"we slept over, sorry\")" + .to_string() + ) + ); + } + + #[test] + fn payable_scanner_throws_error_when_it_fails_to_make_a_mark_in_payables() { + let payable = Payable::new( + make_wallet("blah"), + 6789, + H256::from_uint(&U256::from(123)), + SystemTime::now(), + ); + let payable_dao = PayableDaoMock::new() + .mark_pending_payable_rowid_result(Err(PayableDaoError::SignConversion(9999999999999))); + let pending_payable_dao = + PendingPayableDaoMock::default().fingerprint_rowid_result(Some(7879)); + let mut subject = PayableScanner::new( + Box::new(payable_dao), + Box::new(pending_payable_dao), + Rc::new(make_payment_thresholds_with_defaults()), + ); + let sent_payable = SentPayable { + payable: vec![Ok(payable)], + response_skeleton_opt: None, + }; + + let result = subject.scan_finished(sent_payable, &Logger::new("test")); + + assert_eq!( + result, + Err( + "Was unable to create a mark in payables for a new pending payable '0x0000…007b' \ + due to 'SignConversion(9999999999999)'" + .to_string() + ) + ) + } + #[test] fn pending_payable_scanner_can_initiate_a_scan() { init_test_logging(); From 7ce2fb8c049259e8c33539cc5b6f9e6f754e489c Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 14 Sep 2022 16:45:20 +0530 Subject: [PATCH 089/145] GH-611: migrate seperate_early_errors to tools.rs finished --- node/src/accountant/mod.rs | 42 -------------------------------------- 1 file changed, 42 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 323cc7f3d..332405ad4 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -900,28 +900,6 @@ impl Accountant { } } - fn separate_early_errors( - sent_payments: &SentPayable, - logger: &Logger, - ) -> (Vec, Vec) { - todo!("migrate to tools.rs"); - sent_payments - .payable - .iter() - .fold((vec![], vec![]), |so_far, payment| { - match payment { - Ok(payment_sent) => (plus(so_far.0, payment_sent.clone()), so_far.1), - Err(error) => { - logger.warning(|| match &error { - BlockchainError::TransactionFailed { .. } => format!("Encountered transaction error at this end: '{:?}'", error), - x => format!("Outbound transaction failure due to '{:?}'. Please check your blockchain service URL configuration.", x) - }); - (so_far.0, plus(so_far.1, error.clone())) - } - } - }) - } - fn handle_pending_transaction_with_its_receipt( &self, msg: &ReportTransactionReceipts, @@ -4261,26 +4239,6 @@ mod tests { TestLogHandler::new().exists_log_containing("ERROR: Accountant: Failed to make a fingerprint for pending payable '0x0000…01c8' due to 'InsertionFailed(\"Crashed\")'"); } - // #[test] - // fn separate_early_errors_works() { - // let payable_ok = Payable { - // to: make_wallet("blah"), - // amount: 5555, - // timestamp: SystemTime::now(), - // tx_hash: Default::default(), - // }; - // let error = BlockchainError::SignedValueConversion(666); - // let sent_payable = SentPayable { - // payable: vec![Ok(payable_ok.clone()), Err(error.clone())], - // response_skeleton_opt: None, - // }; - // - // let (ok, err) = Accountant::separate_early_errors(&sent_payable, &Logger::new("test")); - // - // assert_eq!(ok, vec![payable_ok]); - // assert_eq!(err, vec![error]) - // } - #[test] fn update_payable_fingerprint_happy_path() { let update_after_cycle_params_arc = Arc::new(Mutex::new(vec![])); From f49828f1a9c8381fc853ee86b491d92a65009c8d Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 14 Sep 2022 16:49:29 +0530 Subject: [PATCH 090/145] GH-611: remove commented out from accountant/mod.rs --- node/src/accountant/mod.rs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 332405ad4..fcb016dac 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -449,7 +449,6 @@ impl Accountant { .take() .expectv("Payment thresholds"), ); - // let pending_payable_factory_clone = pending_payable_dao_factory.clone(); let earning_wallet = Rc::new(config.earning_wallet.clone()); Accountant { accountant_config, @@ -503,25 +502,6 @@ impl Accountant { DaoFactoryReal::new(data_directory, false, MigratorConfig::panic_on_migration()) } - // fn handle_scan_message( - // &self, - // scanner: &mut dyn Scanner, - // response_skeleton_opt: Option, - // ctx: &mut Context, - // ) where - // BeginMessage: Message, - // EndMessage: Message, - // { - // - // if let Err(error) = scanner.begin_scan(SystemTime::now(), response_skeleton_opt, ctx) { - // warning!(self.logger, "{}", error); - // } else { - // // Received the message, send it to blockchain bridge - // todo!() - // } - // // TODO: migrate the scanner.notify_later_assertable(self, ctx) to begin_scan() - // } - fn record_service_provided( &self, service_rate: u64, From 0bcac3d3058b44cfe31c86e2087549fb31152f0c Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 14 Sep 2022 17:02:55 +0530 Subject: [PATCH 091/145] GH-611: return an option of NodeToUiMessage from the scan_finished() --- node/src/accountant/mod.rs | 10 +++----- node/src/accountant/scanners.rs | 44 +++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index fcb016dac..1d0c90106 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -178,17 +178,13 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: SentPayable, _ctx: &mut Self::Context) -> Self::Result { - let response_skeleton_opt = msg.response_skeleton_opt; match self.scanners.payables.scan_finished(msg, &self.logger) { - Ok(()) => { - if let Some(response_skeleton) = response_skeleton_opt { + Ok(message_opt) => { + if let Some(message) = message_opt { self.ui_message_sub .as_ref() .expect("UIGateway is not bound") - .try_send(NodeToUiMessage { - target: MessageTarget::ClientId(response_skeleton.client_id), - body: UiScanResponse {}.tmb(response_skeleton.context_id), - }) + .try_send(message) .expect("UIGateway is dead"); } } diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 9bf6c1ddb..fe2630a42 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -21,6 +21,8 @@ pub(in crate::accountant) mod scanners { use crate::sub_lib::wallet::Wallet; use actix::Message; use masq_lib::logger::Logger; + use masq_lib::messages::{ToMessageBody, UiScanResponse}; + use masq_lib::ui_gateway::{MessageTarget, NodeToUiMessage}; use std::any::Any; use std::borrow::Borrow; use std::rc::Rc; @@ -82,7 +84,11 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result; - fn scan_finished(&mut self, message: EndMessage, logger: &Logger) -> Result<(), String>; + fn scan_finished( + &mut self, + message: EndMessage, + logger: &Logger, + ) -> Result, String>; fn scan_started_at(&self) -> Option; as_any_dcl!(); } @@ -145,7 +151,11 @@ pub(in crate::accountant) mod scanners { } } - fn scan_finished(&mut self, message: SentPayable, logger: &Logger) -> Result<(), String> { + fn scan_finished( + &mut self, + message: SentPayable, + logger: &Logger, + ) -> Result, String> { // Use the passed-in message and the internal DAO to finish the scan // Ok(()) @@ -193,17 +203,15 @@ pub(in crate::accountant) mod scanners { }; } - Ok(()) - // if let Some(response_skeleton) = &sent_payable.response_skeleton_opt { - // self.ui_message_sub - // .as_ref() - // .expect("UIGateway is not bound") - // .try_send(NodeToUiMessage { - // target: MessageTarget::ClientId(response_skeleton.client_id), - // body: UiScanResponse {}.tmb(response_skeleton.context_id), - // }) - // .expect("UIGateway is dead"); - // } + let message_opt = match message.response_skeleton_opt { + Some(response_skeleton) => Some(NodeToUiMessage { + target: MessageTarget::ClientId(response_skeleton.client_id), + body: UiScanResponse {}.tmb(response_skeleton.context_id), + }), + None => None, + }; + + Ok(message_opt) } fn scan_started_at(&self) -> Option { @@ -271,7 +279,7 @@ pub(in crate::accountant) mod scanners { &mut self, _message: ReportTransactionReceipts, logger: &Logger, - ) -> Result<(), String> { + ) -> Result, String> { todo!() } @@ -356,7 +364,7 @@ pub(in crate::accountant) mod scanners { &mut self, _message: ReceivedPayments, logger: &Logger, - ) -> Result<(), String> { + ) -> Result, String> { todo!() } @@ -399,7 +407,11 @@ pub(in crate::accountant) mod scanners { Err(ScannerError::CalledFromNullScanner) } - fn scan_finished(&mut self, _message: EndMessage, logger: &Logger) -> Result<(), String> { + fn scan_finished( + &mut self, + _message: EndMessage, + logger: &Logger, + ) -> Result, String> { todo!() } From 9727c7c7eb03d8467e4e5627d8624309455f759c Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 15 Sep 2022 14:01:05 +0530 Subject: [PATCH 092/145] GH-611: format the error messages inside scanners.rs --- node/src/accountant/scanners.rs | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index fe2630a42..0f24080ba 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -160,7 +160,13 @@ pub(in crate::accountant) mod scanners { // Ok(()) let (sent_payables, blockchain_errors) = separate_early_errors(&message, logger); - debug!(logger, "We gathered these errors at sending transactions for payable: {:?}, out of the total of {} attempts", blockchain_errors, sent_payables.len() + blockchain_errors.len()); + debug!( + logger, + "We gathered these errors at sending transactions for payable: {:?}, out of the \ + total of {} attempts", + blockchain_errors, + sent_payables.len() + blockchain_errors.len() + ); for payable in sent_payables { if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(payable.tx_hash) { @@ -169,10 +175,18 @@ pub(in crate::accountant) mod scanners { .as_ref() .mark_pending_payable_rowid(&payable.to, rowid) { - return Err(format!("Was unable to create a mark in payables for a new pending payable '{}' due to '{:?}'", payable.tx_hash, e)); + return Err(format!( + "Was unable to create a mark in payables for a new pending payable \ + '{}' due to '{:?}'", + payable.tx_hash, e + )); } } else { - return Err(format!("Payable fingerprint for {} doesn't exist but should by now; system unreliable", payable.tx_hash)); + return Err(format!( + "Payable fingerprint for {} doesn't exist but should by now; \ + system unreliable", + payable.tx_hash + )); }; debug!( @@ -189,7 +203,11 @@ pub(in crate::accountant) mod scanners { "Deleting an existing backup for a failed transaction {}", hash ); if let Err(e) = self.pending_payable_dao.delete_fingerprint(rowid) { - return Err(format!("Database unmaintainable; payable fingerprint deletion for transaction {:?} has stayed undone due to {:?}", hash, e)); + return Err(format!( + "Database unmaintainable; payable fingerprint deletion for \ + transaction {:?} has stayed undone due to {:?}", + hash, e + )); }; }; @@ -199,7 +217,10 @@ pub(in crate::accountant) mod scanners { hash ) } else { - debug!(logger,"Forgetting a transaction attempt that even did not reach the signing stage") + debug!( + logger, + "Forgetting a transaction attempt that even did not reach the signing stage" + ) }; } From 1f5b60441dba8bd3917260b5dfe94ee89b1a8c93 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 15 Sep 2022 14:30:46 +0530 Subject: [PATCH 093/145] GH-611: refactor scan_finished() of PayableScanner --- node/src/accountant/scanners.rs | 80 ++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 0f24080ba..b8492f532 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -1,7 +1,7 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. pub(in crate::accountant) mod scanners { - use crate::accountant::payable_dao::PayableDao; + use crate::accountant::payable_dao::{Payable, PayableDao}; use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDaoFactory}; use crate::accountant::receivable_dao::ReceivableDao; use crate::accountant::tools::payable_scanner_tools::{ @@ -16,6 +16,7 @@ pub(in crate::accountant) mod scanners { }; use crate::banned_dao::BannedDao; use crate::blockchain::blockchain_bridge::RetrieveTransactions; + use crate::blockchain::blockchain_interface::BlockchainError; use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use crate::sub_lib::wallet::Wallet; @@ -168,6 +169,45 @@ pub(in crate::accountant) mod scanners { sent_payables.len() + blockchain_errors.len() ); + self.handle_sent_payables(sent_payables, logger)?; + self.handle_blockchain_errors(blockchain_errors, logger)?; + + let message_opt = match message.response_skeleton_opt { + Some(response_skeleton) => Some(NodeToUiMessage { + target: MessageTarget::ClientId(response_skeleton.client_id), + body: UiScanResponse {}.tmb(response_skeleton.context_id), + }), + None => None, + }; + + Ok(message_opt) + } + + fn scan_started_at(&self) -> Option { + self.common.initiated_at_opt + } + + as_any_impl!(); + } + + impl PayableScanner { + pub fn new( + dao: Box, + pending_payable_dao: Box, + payment_thresholds: Rc, + ) -> Self { + Self { + common: ScannerCommon::new(payment_thresholds), + dao, + pending_payable_dao, + } + } + + fn handle_sent_payables( + &self, + sent_payables: Vec, + logger: &Logger, + ) -> Result<(), String> { for payable in sent_payables { if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(payable.tx_hash) { if let Err(e) = self @@ -195,6 +235,14 @@ pub(in crate::accountant) mod scanners { ) } + Ok(()) + } + + fn handle_blockchain_errors( + &self, + blockchain_errors: Vec, + logger: &Logger, + ) -> Result<(), String> { for blockchain_error in blockchain_errors { if let Some(hash) = blockchain_error.carries_transaction_hash() { if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(hash) { @@ -224,35 +272,7 @@ pub(in crate::accountant) mod scanners { }; } - let message_opt = match message.response_skeleton_opt { - Some(response_skeleton) => Some(NodeToUiMessage { - target: MessageTarget::ClientId(response_skeleton.client_id), - body: UiScanResponse {}.tmb(response_skeleton.context_id), - }), - None => None, - }; - - Ok(message_opt) - } - - fn scan_started_at(&self) -> Option { - self.common.initiated_at_opt - } - - as_any_impl!(); - } - - impl PayableScanner { - pub fn new( - dao: Box, - pending_payable_dao: Box, - payment_thresholds: Rc, - ) -> Self { - Self { - common: ScannerCommon::new(payment_thresholds), - dao, - pending_payable_dao, - } + Ok(()) } } From ec5928f99acd84803a658cb00e45fe6d3fef939c Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 15 Sep 2022 16:07:21 +0530 Subject: [PATCH 094/145] GH-611: migration to scan_finished() for PendingPayableScanner in progress --- node/src/accountant/mod.rs | 21 ++++- node/src/accountant/scanners.rs | 141 +++++++++++++++++++++++++++++--- node/src/accountant/tools.rs | 11 +++ 3 files changed, 158 insertions(+), 15 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 1d0c90106..270de1890 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -49,7 +49,7 @@ use masq_lib::messages::UiFinancialsResponse; use masq_lib::messages::{FromMessageBody, ToMessageBody, UiFinancialsRequest}; use masq_lib::ui_gateway::MessageTarget::ClientId; use masq_lib::ui_gateway::{NodeFromUiMessage, NodeToUiMessage}; -use masq_lib::utils::{plus, ExpectValue}; +use masq_lib::utils::ExpectValue; use payable_dao::PayableDao; use receivable_dao::ReceivableDao; use std::default::Default; @@ -346,7 +346,18 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ReportTransactionReceipts, ctx: &mut Self::Context) -> Self::Result { - // TODO: PendingPayables scan ends here. + todo!("migration of this function is in progress"); + // if let Some(response_skeleton) = &msg.response_skeleton_opt { + // self.ui_message_sub + // .as_ref() + // .expect("UIGateway not bound") + // .try_send(NodeToUiMessage { + // target: MessageTarget::ClientId(response_skeleton.client_id), + // body: UiScanResponse {}.tmb(response_skeleton.context_id), + // }) + // .expect("UIGateway is dead"); + // } + // TODO: Make accountant to handle empty vector. Maybe log it as an error. debug!( self.logger, @@ -439,6 +450,7 @@ impl Accountant { .accountant_config_opt .take() .expect("Accountant config"); + let when_pending_too_long_sec = accountant_config.when_pending_too_long_sec; let payment_thresholds = Rc::new( config .payment_thresholds_opt @@ -462,6 +474,7 @@ impl Accountant { banned_dao_factory.make(), Rc::clone(&payment_thresholds), Rc::clone(&earning_wallet), + when_pending_too_long_sec, ), tools: TransactionConfirmationTools::default(), notify_later: NotifyLaterForScanners::default(), @@ -3378,7 +3391,7 @@ mod tests { "we slept over, sorry".to_string(), ))); let system = System::new("test"); - let mut subject = AccountantBuilder::default() + let subject = AccountantBuilder::default() .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant .pending_payable_dao(pending_payable_dao) // For Payable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner @@ -3793,7 +3806,7 @@ mod tests { //this is used during confirmation of the successful one .delete_fingerprint_result(Ok(())); scanner_pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; - let mut accountant_pending_payable_dao = PendingPayableDaoMock::default() + let accountant_pending_payable_dao = PendingPayableDaoMock::default() .fingerprint_rowid_result(Some(rowid_for_account_1)) .fingerprint_rowid_result(Some(rowid_for_account_2)); let accountant_addr = Arbiter::builder() diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index b8492f532..c10c0add8 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -7,15 +7,16 @@ pub(in crate::accountant) mod scanners { use crate::accountant::tools::payable_scanner_tools::{ investigate_debt_extremes, qualified_payables_and_summary, separate_early_errors, }; + use crate::accountant::tools::pending_payable_scanner_tools::elapsed_in_ms; use crate::accountant::tools::receivable_scanner_tools::balance_and_age; - use crate::accountant::ReportAccountsPayable; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, ReportTransactionReceipts, RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, ScanForPendingPayables, ScanForReceivables, SentPayable, }; + use crate::accountant::{PendingPayableId, PendingTransactionStatus, ReportAccountsPayable}; use crate::banned_dao::BannedDao; - use crate::blockchain::blockchain_bridge::RetrieveTransactions; + use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::BlockchainError; use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; @@ -24,10 +25,11 @@ pub(in crate::accountant) mod scanners { use masq_lib::logger::Logger; use masq_lib::messages::{ToMessageBody, UiScanResponse}; use masq_lib::ui_gateway::{MessageTarget, NodeToUiMessage}; + use masq_lib::utils::ExpectValue; use std::any::Any; - use std::borrow::Borrow; use std::rc::Rc; use std::time::SystemTime; + use web3::types::TransactionReceipt; #[derive(Debug, PartialEq, Eq)] pub enum ScannerError { @@ -53,6 +55,7 @@ pub(in crate::accountant) mod scanners { banned_dao: Box, payment_thresholds: Rc, earning_wallet: Rc, + when_pending_too_long_sec: u64, ) -> Self { Scanners { payables: Box::new(PayableScanner::new( @@ -63,6 +66,7 @@ pub(in crate::accountant) mod scanners { pending_payables: Box::new(PendingPayableScanner::new( pending_payable_dao_factory.make(), Rc::clone(&payment_thresholds), + when_pending_too_long_sec, )), receivables: Box::new(ReceivableScanner::new( receivable_dao, @@ -279,6 +283,7 @@ pub(in crate::accountant) mod scanners { pub struct PendingPayableScanner { common: ScannerCommon, dao: Box, + when_pending_too_long_sec: u64, } impl Scanner for PendingPayableScanner { @@ -318,10 +323,27 @@ pub(in crate::accountant) mod scanners { fn scan_finished( &mut self, - _message: ReportTransactionReceipts, + message: ReportTransactionReceipts, logger: &Logger, ) -> Result, String> { - todo!() + // TODO: Make accountant to handle empty vector. Maybe log it as an error. + debug!( + logger, + "Processing receipts for {} transactions", + message.fingerprints_with_receipts.len() + ); + let statuses = self.handle_pending_transaction_with_its_receipt(&message, logger); + // self.process_transaction_by_status(statuses, ctx); + + let message_opt = match message.response_skeleton_opt { + Some(response_skeleton) => Some(NodeToUiMessage { + target: MessageTarget::ClientId(response_skeleton.client_id), + body: UiScanResponse {}.tmb(response_skeleton.context_id), + }), + None => None, + }; + + Ok(message_opt) } fn scan_started_at(&self) -> Option { @@ -335,10 +357,100 @@ pub(in crate::accountant) mod scanners { pub fn new( dao: Box, payment_thresholds: Rc, + when_pending_too_long_sec: u64, ) -> Self { Self { common: ScannerCommon::new(payment_thresholds), dao, + when_pending_too_long_sec, + } + } + + fn handle_pending_transaction_with_its_receipt( + &self, + msg: &ReportTransactionReceipts, + logger: &Logger, + ) -> Vec { + fn handle_none_receipt( + payable: &PendingPayableFingerprint, + logger: &Logger, + ) -> PendingTransactionStatus { + debug!(logger, + "DEBUG: Accountant: Interpreting a receipt for transaction '{}' but none was given; attempt {}, {}ms since sending", + payable.hash, payable.attempt_opt.expectv("initialized attempt"), elapsed_in_ms(payable.timestamp) + ); + PendingTransactionStatus::StillPending(PendingPayableId { + hash: payable.hash, + rowid: payable.rowid_opt.expectv("initialized rowid"), + }) + } + msg.fingerprints_with_receipts + .iter() + .map(|(receipt_opt, fingerprint)| match receipt_opt { + Some(receipt) => { + self.interpret_transaction_receipt(receipt, fingerprint, logger) + } + None => handle_none_receipt(fingerprint, logger), + }) + .collect() + } + + fn interpret_transaction_receipt( + &self, + receipt: &TransactionReceipt, + fingerprint: &PendingPayableFingerprint, + logger: &Logger, + ) -> PendingTransactionStatus { + fn handle_none_status( + fingerprint: &PendingPayableFingerprint, + max_pending_interval: u64, + logger: &Logger, + ) -> PendingTransactionStatus { + info!(logger,"Pending transaction '{}' couldn't be confirmed at attempt {} at {}ms after its sending",fingerprint.hash, fingerprint.attempt_opt.expectv("initialized attempt"), elapsed_in_ms(fingerprint.timestamp)); + let elapsed = fingerprint + .timestamp + .elapsed() + .expect("we should be older now"); + let transaction_id = PendingPayableId { + hash: fingerprint.hash, + rowid: fingerprint.rowid_opt.expectv("initialized rowid"), + }; + if max_pending_interval <= elapsed.as_secs() { + error!(logger,"Pending transaction '{}' has exceeded the maximum pending time ({}sec) and the confirmation process is going to be aborted now at the final attempt {}; \ + manual resolution is required from the user to complete the transaction.", fingerprint.hash, max_pending_interval, fingerprint.attempt_opt.expectv("initialized attempt")); + PendingTransactionStatus::Failure(transaction_id) + } else { + PendingTransactionStatus::StillPending(transaction_id) + } + } + fn handle_status_with_success( + fingerprint: &PendingPayableFingerprint, + logger: &Logger, + ) -> PendingTransactionStatus { + info!( + logger, + "Transaction '{}' has been added to the blockchain; detected locally at attempt {} at {}ms after its sending", + fingerprint.hash, + fingerprint.attempt_opt.expectv("initialized attempt"), + elapsed_in_ms(fingerprint.timestamp) + ); + PendingTransactionStatus::Confirmed(fingerprint.clone()) + } + fn handle_status_with_failure( + fingerprint: &PendingPayableFingerprint, + logger: &Logger, + ) -> PendingTransactionStatus { + error!(logger,"Pending transaction '{}' announced as a failure, interpreting attempt {} after {}ms from the sending",fingerprint.hash,fingerprint.attempt_opt.expectv("initialized attempt"),elapsed_in_ms(fingerprint.timestamp)); + PendingTransactionStatus::Failure(fingerprint.into()) + } + match receipt.status { + None => handle_none_status(fingerprint, self.when_pending_too_long_sec, logger), + Some(status_code) => + match status_code.as_u64() { + 0 => handle_status_with_failure(fingerprint, logger), + 1 => handle_status_with_success(fingerprint, logger), + other => unreachable!("tx receipt for pending '{}' - tx status: code other than 0 or 1 shouldn't be possible, but was {}", fingerprint.hash, other) + } } } } @@ -404,7 +516,7 @@ pub(in crate::accountant) mod scanners { fn scan_finished( &mut self, _message: ReceivedPayments, - logger: &Logger, + _logger: &Logger, ) -> Result, String> { todo!() } @@ -451,7 +563,7 @@ pub(in crate::accountant) mod scanners { fn scan_finished( &mut self, _message: EndMessage, - logger: &Logger, + _logger: &Logger, ) -> Result, String> { todo!() } @@ -586,6 +698,7 @@ mod tests { Box::new(BannedDaoMock::new()), Rc::clone(&payment_thresholds), Rc::new(make_wallet("earning")), + 0, ); scanners @@ -781,8 +894,11 @@ mod tests { let pending_payable_dao = PendingPayableDaoMock::new().return_all_fingerprints_result(fingerprints.clone()); let payment_thresholds = make_payment_thresholds_with_defaults(); - let mut pending_payable_scanner = - PendingPayableScanner::new(Box::new(pending_payable_dao), Rc::new(payment_thresholds)); + let mut pending_payable_scanner = PendingPayableScanner::new( + Box::new(pending_payable_dao), + Rc::new(payment_thresholds), + 0, + ); let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); @@ -815,8 +931,11 @@ mod tests { let pending_payable_dao = PendingPayableDaoMock::new().return_all_fingerprints_result(vec![]); let payment_thresholds = make_payment_thresholds_with_defaults(); - let mut pending_payable_scanner = - PendingPayableScanner::new(Box::new(pending_payable_dao), Rc::new(payment_thresholds)); + let mut pending_payable_scanner = PendingPayableScanner::new( + Box::new(pending_payable_dao), + Rc::new(payment_thresholds), + 0, + ); let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index df1cbf85d..29c08e6e7 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -175,6 +175,17 @@ pub(crate) mod payable_scanner_tools { } } +pub(crate) mod pending_payable_scanner_tools { + use std::time::SystemTime; + + pub fn elapsed_in_ms(timestamp: SystemTime) -> u128 { + timestamp + .elapsed() + .expect("time calculation for elapsed failed") + .as_millis() + } +} + pub(crate) mod receivable_scanner_tools { use crate::accountant::receivable_dao::ReceivableAccount; use std::time::{Duration, SystemTime}; From f6a0c9a28e9b710b4852ba75d63f6e15d2945b0a Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 16 Sep 2022 11:39:06 +0530 Subject: [PATCH 095/145] GH-611: directly store fields of accountant config inside Accountant --- node/src/accountant/mod.rs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 270de1890..2b9ebfbff 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -25,12 +25,12 @@ use crate::blockchain::blockchain_interface::{BlockchainError, BlockchainTransac use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::DaoFactoryReal; use crate::database::db_migrations::MigratorConfig; -use crate::sub_lib::accountant::AccountantSubs; use crate::sub_lib::accountant::ReportExitServiceConsumedMessage; use crate::sub_lib::accountant::ReportExitServiceProvidedMessage; use crate::sub_lib::accountant::ReportRoutingServiceConsumedMessage; use crate::sub_lib::accountant::ReportRoutingServiceProvidedMessage; use crate::sub_lib::accountant::{AccountantConfig, FinancialStatistics, PaymentThresholds}; +use crate::sub_lib::accountant::{AccountantSubs, ScanIntervals}; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::sub_lib::peer_actors::{BindMessage, StartMessage}; use crate::sub_lib::utils::{handle_ui_crash_request, NODE_MAILBOX_CAPACITY}; @@ -64,7 +64,8 @@ pub const CRASH_KEY: &str = "ACCOUNTANT"; pub const DEFAULT_PENDING_TOO_LONG_SEC: u64 = 21_600; //6 hours pub struct Accountant { - accountant_config: AccountantConfig, + scan_intervals: ScanIntervals, + suppress_initial_scans: Option, consuming_wallet: Option, earning_wallet: Rc, payable_dao: Box, @@ -143,7 +144,11 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, _msg: StartMessage, ctx: &mut Self::Context) -> Self::Result { - if self.accountant_config.suppress_initial_scans { + let suppress_initial_scans = self + .suppress_initial_scans + .take() + .expect("Can't process StartMessage for Accountant."); + if suppress_initial_scans { info!( &self.logger, "Started with --scans off; declining to begin database and blockchain scans" @@ -204,7 +209,7 @@ impl Handler for Accountant { ScanForPayables { response_skeleton_opt: None, }, - self.accountant_config.scan_intervals.payable_scan_interval, + self.scan_intervals.payable_scan_interval, ctx, ); } @@ -219,9 +224,7 @@ impl Handler for Accountant { ScanForPendingPayables { response_skeleton_opt: None, // because scheduled scans don't respond }, - self.accountant_config - .scan_intervals - .pending_payable_scan_interval, + self.scan_intervals.pending_payable_scan_interval, ctx, ); } @@ -236,9 +239,7 @@ impl Handler for Accountant { ScanForReceivables { response_skeleton_opt: None, // because scheduled scans don't respond }, - self.accountant_config - .scan_intervals - .receivable_scan_interval, + self.scan_intervals.receivable_scan_interval, ctx, ); } @@ -450,7 +451,6 @@ impl Accountant { .accountant_config_opt .take() .expect("Accountant config"); - let when_pending_too_long_sec = accountant_config.when_pending_too_long_sec; let payment_thresholds = Rc::new( config .payment_thresholds_opt @@ -459,7 +459,8 @@ impl Accountant { ); let earning_wallet = Rc::new(config.earning_wallet.clone()); Accountant { - accountant_config, + scan_intervals: accountant_config.scan_intervals, + suppress_initial_scans: Some(accountant_config.suppress_initial_scans), consuming_wallet: config.consuming_wallet_opt.clone(), earning_wallet: Rc::clone(&earning_wallet), payable_dao: payable_dao_factory.make(), @@ -474,7 +475,7 @@ impl Accountant { banned_dao_factory.make(), Rc::clone(&payment_thresholds), Rc::clone(&earning_wallet), - when_pending_too_long_sec, + accountant_config.when_pending_too_long_sec, ), tools: TransactionConfirmationTools::default(), notify_later: NotifyLaterForScanners::default(), @@ -966,7 +967,7 @@ impl Accountant { PendingTransactionStatus::Failure(fingerprint.into()) } match receipt.status { - None => handle_none_status(fingerprint, self.accountant_config.when_pending_too_long_sec, logger), + None => todo!("code migration to scanners.rs in progress"), Some(status_code) => match status_code.as_u64() { 0 => handle_status_with_failure(fingerprint, logger), @@ -2601,10 +2602,7 @@ mod tests { .bootstrapper_config(config) .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - subject - .accountant_config - .scan_intervals - .payable_scan_interval = Duration::from_millis(10); + subject.scan_intervals.payable_scan_interval = Duration::from_millis(10); subject.logger = Logger::new(test_name); let addr = subject.start(); addr.try_send(ScanForPayables { From feda8072c9df4ef559442f2274583bf3f2e88eb5 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 16 Sep 2022 13:36:01 +0530 Subject: [PATCH 096/145] GH-611: pull fields of accountant config outside --- node/src/accountant/mod.rs | 419 +++++------------- node/src/accountant/test_utils.rs | 30 +- node/src/actor_system_factory.rs | 22 +- node/src/bootstrapper.rs | 32 +- .../unprivileged_parse_args_configuration.rs | 125 +++--- node/src/test_utils/mod.rs | 15 + 6 files changed, 229 insertions(+), 414 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 2b9ebfbff..708aa26f3 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -29,8 +29,8 @@ use crate::sub_lib::accountant::ReportExitServiceConsumedMessage; use crate::sub_lib::accountant::ReportExitServiceProvidedMessage; use crate::sub_lib::accountant::ReportRoutingServiceConsumedMessage; use crate::sub_lib::accountant::ReportRoutingServiceProvidedMessage; -use crate::sub_lib::accountant::{AccountantConfig, FinancialStatistics, PaymentThresholds}; use crate::sub_lib::accountant::{AccountantSubs, ScanIntervals}; +use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::sub_lib::peer_actors::{BindMessage, StartMessage}; use crate::sub_lib::utils::{handle_ui_crash_request, NODE_MAILBOX_CAPACITY}; @@ -65,7 +65,7 @@ pub const DEFAULT_PENDING_TOO_LONG_SEC: u64 = 21_600; //6 hours pub struct Accountant { scan_intervals: ScanIntervals, - suppress_initial_scans: Option, + suppress_initial_scans_opt: Option, consuming_wallet: Option, earning_wallet: Rc, payable_dao: Box, @@ -145,7 +145,7 @@ impl Handler for Accountant { fn handle(&mut self, _msg: StartMessage, ctx: &mut Self::Context) -> Self::Result { let suppress_initial_scans = self - .suppress_initial_scans + .suppress_initial_scans_opt .take() .expect("Can't process StartMessage for Accountant."); if suppress_initial_scans { @@ -447,20 +447,22 @@ impl Accountant { pending_payable_dao_factory: Box, banned_dao_factory: Box, ) -> Accountant { - let accountant_config = config - .accountant_config_opt - .take() - .expect("Accountant config"); let payment_thresholds = Rc::new( config .payment_thresholds_opt .take() .expectv("Payment thresholds"), ); + let scan_intervals = config.scan_intervals_opt.take().expectv("Scan Intervals"); + let when_pending_too_long_sec = config + .when_pending_too_long_opt + .take() + .expectv("When pending too long sec"); + let earning_wallet = Rc::new(config.earning_wallet.clone()); Accountant { - scan_intervals: accountant_config.scan_intervals, - suppress_initial_scans: Some(accountant_config.suppress_initial_scans), + scan_intervals, + suppress_initial_scans_opt: config.suppress_initial_scans_opt, consuming_wallet: config.consuming_wallet_opt.clone(), earning_wallet: Rc::clone(&earning_wallet), payable_dao: payable_dao_factory.make(), @@ -475,7 +477,7 @@ impl Accountant { banned_dao_factory.make(), Rc::clone(&payment_thresholds), Rc::clone(&earning_wallet), - accountant_config.when_pending_too_long_sec, + when_pending_too_long_sec, ), tools: TransactionConfirmationTools::default(), notify_later: NotifyLaterForScanners::default(), @@ -1115,10 +1117,9 @@ mod tests { use crate::accountant::receivable_dao::ReceivableAccount; use crate::accountant::scanners::scanners::NullScanner; use crate::accountant::test_utils::{ - bc_from_ac_plus_earning_wallet, bc_from_ac_plus_wallets, make_payables, - make_pending_payable_fingerprint, BannedDaoFactoryMock, PayableDaoFactoryMock, - PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, - ReceivableDaoFactoryMock, ReceivableDaoMock, + bc_from_earning_wallet, bc_from_wallets, make_payables, make_pending_payable_fingerprint, + BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, + PendingPayableDaoMock, ReceivableDaoFactoryMock, ReceivableDaoMock, }; use crate::accountant::test_utils::{AccountantBuilder, BannedDaoMock}; use crate::accountant::Accountant; @@ -1140,8 +1141,7 @@ mod tests { use crate::test_utils::recorder::peer_actors_builder; use crate::test_utils::recorder::Recorder; use crate::test_utils::unshared_test_utils::{ - make_accountant_config_null, make_payment_thresholds_with_defaults, - make_populated_accountant_config_with_defaults, + make_bc_with_defaults, make_payment_thresholds_with_defaults, prove_that_crash_request_handler_is_hooked_up, NotifyHandleMock, NotifyLaterHandleMock, SystemKillerActor, }; @@ -1156,9 +1156,7 @@ mod tests { #[test] fn new_calls_factories_properly() { - let mut config = BootstrapperConfig::new(); - config.accountant_config_opt = Some(make_accountant_config_null()); - config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); + let mut config = make_bc_with_defaults(); let payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let pending_payable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let receivable_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); @@ -1212,10 +1210,7 @@ mod tests { // to blockchain bridge (one received directly and other indirectly via notify_later). Make sure 6 messages are received in total. // The second message is received after test defined scan intervals. // Make sure to use a real database instead of using mock utilities. It'll require at least one row for each table of individual scanners. - let mut bootstrapper_config = BootstrapperConfig::new(); - bootstrapper_config.accountant_config_opt = - Some(make_populated_accountant_config_with_defaults()); - bootstrapper_config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); + let mut bootstrapper_config = make_bc_with_defaults(); let payable_dao_factory = Box::new( PayableDaoFactoryMock::new() .make_result(PayableDaoMock::new()) // For Accountant @@ -1287,19 +1282,12 @@ mod tests { #[test] fn scan_receivables_request() { - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_millis(10_000), - receivable_scan_interval: Duration::from_millis(10_000), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: true, - }, - Default::default(), - make_wallet("earning_wallet"), - ); + let mut config = bc_from_earning_wallet(make_wallet("earning_wallet")); + config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_millis(10_000), + receivable_scan_interval: Duration::from_millis(10_000), + pending_payable_scan_interval: Duration::from_secs(100), + }); let receivable_dao = ReceivableDaoMock::new() .new_delinquencies_result(vec![]) .paid_delinquencies_result(vec![]); @@ -1342,19 +1330,13 @@ mod tests { #[test] fn received_payments_with_response_skeleton_sends_response_to_ui_gateway() { - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_millis(10_000), - receivable_scan_interval: Duration::from_millis(10_000), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: true, - }, - make_payment_thresholds_with_defaults(), - make_wallet("earning_wallet"), - ); + let mut config = bc_from_earning_wallet(make_wallet("earning_wallet")); + config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_millis(10_000), + receivable_scan_interval: Duration::from_millis(10_000), + pending_payable_scan_interval: Duration::from_secs(100), + }); + config.suppress_initial_scans_opt = Some(true); let subject = AccountantBuilder::default() .bootstrapper_config(config) .build(); @@ -1387,19 +1369,7 @@ mod tests { #[test] fn scan_payables_request() { - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_millis(10_000), - receivable_scan_interval: Duration::from_millis(10_000), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: true, - }, - make_payment_thresholds_with_defaults(), - make_wallet("some_wallet_address"), - ); + let config = bc_from_earning_wallet(make_wallet("some_wallet_address")); let payable_account = PayableAccount { wallet: make_wallet("wallet"), balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 1, @@ -1449,19 +1419,7 @@ mod tests { #[test] fn sent_payable_with_response_skeleton_sends_scan_response_to_ui_gateway() { - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_millis(10_000), - receivable_scan_interval: Duration::from_millis(10_000), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: true, - }, - make_payment_thresholds_with_defaults(), - make_wallet("earning_wallet"), - ); + let config = bc_from_earning_wallet(make_wallet("earning_wallet")); let subject = AccountantBuilder::default() .bootstrapper_config(config) .build(); @@ -1494,19 +1452,13 @@ mod tests { #[test] fn scan_pending_payables_request() { - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_millis(10_000), - receivable_scan_interval: Duration::from_millis(10_000), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: true, - }, - make_payment_thresholds_with_defaults(), - make_wallet("some_wallet_address"), - ); + let mut config = bc_from_earning_wallet(make_wallet("some_wallet_address")); + config.suppress_initial_scans_opt = Some(true); + config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_millis(10_000), + receivable_scan_interval: Duration::from_millis(10_000), + pending_payable_scan_interval: Duration::from_secs(100), + }); let fingerprint = PendingPayableFingerprint { rowid_opt: Some(1234), timestamp: SystemTime::now(), @@ -1559,19 +1511,13 @@ mod tests { fn scan_request_from_ui_is_handled_in_case_the_scan_is_already_running() { init_test_logging(); let test_name = "scan_request_from_ui_is_handled_in_case_the_scan_is_already_running"; - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_millis(10_000), - receivable_scan_interval: Duration::from_millis(10_000), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: true, - }, - make_payment_thresholds_with_defaults(), - make_wallet("some_wallet_address"), - ); + let mut config = bc_from_earning_wallet(make_wallet("some_wallet_address")); + config.suppress_initial_scans_opt = Some(true); + config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_millis(10_000), + receivable_scan_interval: Duration::from_millis(10_000), + pending_payable_scan_interval: Duration::from_secs(100), + }); let fingerprint = PendingPayableFingerprint { rowid_opt: Some(1234), timestamp: SystemTime::now(), @@ -1626,19 +1572,12 @@ mod tests { #[test] fn report_transaction_receipts_with_response_skeleton_sends_scan_response_to_ui_gateway() { - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_millis(10_000), - receivable_scan_interval: Duration::from_millis(10_000), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: true, - }, - make_payment_thresholds_with_defaults(), - make_wallet("earning_wallet"), - ); + let mut config = bc_from_earning_wallet(make_wallet("earning_wallet")); + config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_millis(10_000), + receivable_scan_interval: Duration::from_millis(10_000), + pending_payable_scan_interval: Duration::from_secs(100), + }); let subject = AccountantBuilder::default() .bootstrapper_config(config) .build(); @@ -1686,11 +1625,7 @@ mod tests { .mark_pending_payable_rowid_result(Ok(())); let system = System::new("accountant_calls_payable_dao_to_mark_pending_payable"); let accountant = AccountantBuilder::default() - .bootstrapper_config(bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - make_wallet("some_wallet_address"), - )) + .bootstrapper_config(bc_from_earning_wallet(make_wallet("some_wallet_address"))) .payable_dao(PayableDaoMock::new()) // For Accountant .payable_dao(payable_dao) // For Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant @@ -1853,11 +1788,7 @@ mod tests { PayableDaoMock::new().non_pending_payables_result(all_non_pending_payables); let system = System::new("report_accounts_payable forwarded to blockchain_bridge"); let mut subject = AccountantBuilder::default() - .bootstrapper_config(bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - payment_thresholds, - make_wallet("some_wallet_address"), - )) + .bootstrapper_config(bc_from_earning_wallet(make_wallet("some_wallet_address"))) .payable_dao(PayableDaoMock::new()) // For Accountant .payable_dao(payable_dao) // For Scanner .build(); @@ -1898,11 +1829,7 @@ mod tests { .new_delinquencies_result(vec![]) .paid_delinquencies_result(vec![]); let mut subject = AccountantBuilder::default() - .bootstrapper_config(bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - earning_wallet.clone(), - )) + .bootstrapper_config(bc_from_earning_wallet(earning_wallet.clone())) .receivable_dao(ReceivableDaoMock::new()) // For Accountant .receivable_dao(receivable_dao) // For Scanner .build(); @@ -1950,11 +1877,7 @@ mod tests { .more_money_received_parameters(&more_money_received_params_arc) .more_money_received_result(Ok(())); let accountant = AccountantBuilder::default() - .bootstrapper_config(bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - earning_wallet.clone(), - )) + .bootstrapper_config(bc_from_earning_wallet(earning_wallet.clone())) .payable_dao(PayableDaoMock::new().non_pending_payables_result(vec![])) .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao) @@ -1989,12 +1912,7 @@ mod tests { let (blockchain_bridge, _, _) = make_recorder(); let earning_wallet = make_wallet("earning"); let system = System::new("accountant_scans_after_startup"); - let config = bc_from_ac_plus_wallets( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - make_wallet("buy"), - earning_wallet.clone(), - ); + let config = bc_from_wallets(make_wallet("buy"), earning_wallet.clone()); let payable_dao = PayableDaoMock::new() .non_pending_payables_params(&payable_params_arc) .non_pending_payables_result(vec![]); @@ -2066,19 +1984,12 @@ mod tests { let earning_wallet = make_wallet("earner3000"); let wallet_to_be_banned = make_wallet("bad_luck"); let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_secs(100), - receivable_scan_interval: Duration::from_millis(99), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: false, - }, - make_payment_thresholds_with_defaults(), - earning_wallet.clone(), - ); + let mut config = bc_from_earning_wallet(earning_wallet.clone()); + config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_secs(100), + receivable_scan_interval: Duration::from_millis(99), + pending_payable_scan_interval: Duration::from_secs(100), + }); let new_delinquent_account = ReceivableAccount { wallet: wallet_to_be_banned.clone(), balance: 4567, @@ -2186,19 +2097,12 @@ mod tests { let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let system = System::new("accountant_payable_scan_timer_triggers_scanning_for_pending_payable"); - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_secs(100), - receivable_scan_interval: Duration::from_secs(100), - pending_payable_scan_interval: Duration::from_millis(98), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: false, - }, - make_payment_thresholds_with_defaults(), - make_wallet("hi"), - ); + let mut config = bc_from_earning_wallet(make_wallet("hi")); + config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_secs(100), + receivable_scan_interval: Duration::from_secs(100), + pending_payable_scan_interval: Duration::from_millis(98), + }); // slightly above minimum balance, to the right of the curve (time intersection) let pending_payable_fingerprint_record = PendingPayableFingerprint { rowid_opt: Some(45454), @@ -2289,19 +2193,12 @@ mod tests { let notify_later_payables_params_arc = Arc::new(Mutex::new(vec![])); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let system = System::new(test_name); - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_millis(97), - receivable_scan_interval: Duration::from_secs(100), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: false, - }, - make_payment_thresholds_with_defaults(), - make_wallet("hi"), - ); + let mut config = bc_from_earning_wallet(make_wallet("hi")); + config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_millis(97), + receivable_scan_interval: Duration::from_secs(100), + pending_payable_scan_interval: Duration::from_secs(100), + }); let now = to_time_t(SystemTime::now()); // slightly above minimum balance, to the right of the curve (time intersection) let account = PayableAccount { @@ -2384,19 +2281,13 @@ mod tests { fn start_message_triggers_no_scans_in_suppress_mode() { init_test_logging(); let system = System::new("start_message_triggers_no_scans_in_suppress_mode"); - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_millis(1), - receivable_scan_interval: Duration::from_millis(1), - pending_payable_scan_interval: Duration::from_secs(100), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: true, - }, - make_payment_thresholds_with_defaults(), - make_wallet("hi"), - ); + let mut config = bc_from_earning_wallet(make_wallet("hi")); + config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_millis(1), + receivable_scan_interval: Duration::from_millis(1), + pending_payable_scan_interval: Duration::from_secs(100), + }); + config.suppress_initial_scans_opt = Some(true); let payable_dao = PayableDaoMock::new(); // No payables: demanding one would cause a panic let receivable_dao = ReceivableDaoMock::new(); // No delinquencies: demanding one would cause a panic let peer_actors = peer_actors_builder().build(); @@ -2424,7 +2315,6 @@ mod tests { #[test] fn scan_for_payables_message_does_not_trigger_payment_for_balances_below_the_curve() { init_test_logging(); - let accountant_config = make_populated_accountant_config_with_defaults(); let payment_thresholds = PaymentThresholds { threshold_interval_sec: 2_592_000, debt_threshold_gwei: 1_000_000_000, @@ -2433,11 +2323,7 @@ mod tests { permanent_debt_allowed_gwei: 10_000_000, unban_below_gwei: 10_000_000, }; - let config = bc_from_ac_plus_earning_wallet( - accountant_config, - payment_thresholds.clone(), - make_wallet("mine"), - ); + let config = bc_from_earning_wallet(make_wallet("mine")); let now = to_time_t(SystemTime::now()); let accounts = vec![ @@ -2501,19 +2387,12 @@ mod tests { #[test] fn scan_for_payable_message_triggers_payment_for_balances_over_the_curve() { init_test_logging(); - let config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - pending_payable_scan_interval: Duration::from_secs(50_000), - payable_scan_interval: Duration::from_millis(100), - receivable_scan_interval: Duration::from_secs(50_000), - }, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: false, - }, - make_payment_thresholds_with_defaults(), - make_wallet("mine"), - ); + let mut config = bc_from_earning_wallet(make_wallet("mine")); + config.scan_intervals_opt = Some(ScanIntervals { + pending_payable_scan_interval: Duration::from_secs(50_000), + payable_scan_interval: Duration::from_millis(100), + receivable_scan_interval: Duration::from_secs(50_000), + }); let now = to_time_t(SystemTime::now()); let accounts = vec![ // slightly above minimum balance, to the right of the curve (time intersection) @@ -2590,11 +2469,7 @@ mod tests { let mut payable_dao = payable_dao.non_pending_payables_result(vec![payable_account.clone()]); payable_dao.have_non_pending_payables_shut_down_the_system = true; - let config = bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - make_wallet("mine"), - ); + let config = bc_from_earning_wallet(make_wallet("mine")); let system = System::new(test_name); let mut subject = AccountantBuilder::default() .payable_dao(PayableDaoMock::new()) // For Accountant @@ -2651,11 +2526,7 @@ mod tests { payable_fingerprint_1.clone(), payable_fingerprint_2.clone(), ]); - let config = bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - make_wallet("mine"), - ); + let config = bc_from_earning_wallet(make_wallet("mine")); let system = System::new("pending payable scan"); let mut subject = AccountantBuilder::default() .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant @@ -2693,10 +2564,7 @@ mod tests { #[test] fn report_routing_service_provided_message_is_received() { init_test_logging(); - let mut bootstrapper_config = BootstrapperConfig::default(); - bootstrapper_config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); - bootstrapper_config.accountant_config_opt = Some(make_accountant_config_null()); - bootstrapper_config.earning_wallet = make_wallet("hi"); + let mut bootstrapper_config = bc_from_earning_wallet(make_wallet("hi")); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao_mock = ReceivableDaoMock::new() @@ -2744,12 +2612,7 @@ mod tests { fn report_routing_service_provided_message_is_received_from_our_consuming_wallet() { init_test_logging(); let consuming_wallet = make_wallet("our consuming wallet"); - let config = bc_from_ac_plus_wallets( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - consuming_wallet.clone(), - make_wallet("our earning wallet"), - ); + let config = bc_from_wallets(consuming_wallet.clone(), make_wallet("our earning wallet")); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao_mock = ReceivableDaoMock::new() @@ -2795,11 +2658,7 @@ mod tests { fn report_routing_service_provided_message_is_received_from_our_earning_wallet() { init_test_logging(); let earning_wallet = make_wallet("our earning wallet"); - let config = bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - earning_wallet.clone(), - ); + let config = bc_from_earning_wallet(earning_wallet.clone()); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao_mock = ReceivableDaoMock::new() @@ -2844,11 +2703,7 @@ mod tests { #[test] fn report_routing_service_consumed_message_is_received() { init_test_logging(); - let config = bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - make_wallet("hi"), - ); + let config = bc_from_earning_wallet(make_wallet("hi")); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new() .non_pending_payables_result(vec![]) @@ -2893,12 +2748,7 @@ mod tests { fn report_routing_service_consumed_message_is_received_for_our_consuming_wallet() { init_test_logging(); let consuming_wallet = make_wallet("the consuming wallet"); - let config = bc_from_ac_plus_wallets( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - consuming_wallet.clone(), - make_wallet("the earning wallet"), - ); + let config = bc_from_wallets(consuming_wallet.clone(), make_wallet("the earning wallet")); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new() .non_pending_payables_result(vec![]) @@ -2939,11 +2789,7 @@ mod tests { fn report_routing_service_consumed_message_is_received_for_our_earning_wallet() { init_test_logging(); let earning_wallet = make_wallet("the earning wallet"); - let config = bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - earning_wallet.clone(), - ); + let config = bc_from_earning_wallet(earning_wallet.clone()); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new() .non_pending_payables_result(vec![]) @@ -2982,11 +2828,7 @@ mod tests { #[test] fn report_exit_service_provided_message_is_received() { init_test_logging(); - let config = bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - make_wallet("hi"), - ); + let config = bc_from_earning_wallet(make_wallet("hi")); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao_mock = ReceivableDaoMock::new() @@ -3034,12 +2876,7 @@ mod tests { fn report_exit_service_provided_message_is_received_from_our_consuming_wallet() { init_test_logging(); let consuming_wallet = make_wallet("my consuming wallet"); - let config = bc_from_ac_plus_wallets( - make_accountant_config_null(), - make_payment_thresholds_with_defaults(), - consuming_wallet.clone(), - make_wallet("my earning wallet"), - ); + let config = bc_from_wallets(consuming_wallet.clone(), make_wallet("my earning wallet")); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao_mock = ReceivableDaoMock::new() @@ -3085,11 +2922,7 @@ mod tests { fn report_exit_service_provided_message_is_received_from_our_earning_wallet() { init_test_logging(); let earning_wallet = make_wallet("my earning wallet"); - let config = bc_from_ac_plus_earning_wallet( - make_accountant_config_null(), - make_payment_thresholds_with_defaults(), - earning_wallet.clone(), - ); + let config = bc_from_earning_wallet(earning_wallet.clone()); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao_mock = ReceivableDaoMock::new() @@ -3148,11 +2981,7 @@ mod tests { #[test] fn report_exit_service_consumed_message_is_received() { init_test_logging(); - let config = bc_from_ac_plus_earning_wallet( - make_accountant_config_null(), - make_payment_thresholds_with_defaults(), - make_wallet("hi"), - ); + let config = make_bc_with_defaults(); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new() .non_pending_payables_result(vec![]) @@ -3198,12 +3027,7 @@ mod tests { fn report_exit_service_consumed_message_is_received_for_our_consuming_wallet() { init_test_logging(); let consuming_wallet = make_wallet("own consuming wallet"); - let config = bc_from_ac_plus_wallets( - make_accountant_config_null(), - make_payment_thresholds_with_defaults(), - consuming_wallet.clone(), - make_wallet("own earning wallet"), - ); + let config = bc_from_wallets(consuming_wallet.clone(), make_wallet("own earning wallet")); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new() .non_pending_payables_result(vec![]) @@ -3244,11 +3068,7 @@ mod tests { fn report_exit_service_consumed_message_is_received_for_our_earning_wallet() { init_test_logging(); let earning_wallet = make_wallet("own earning wallet"); - let config = bc_from_ac_plus_earning_wallet( - make_accountant_config_null(), - make_payment_thresholds_with_defaults(), - earning_wallet.clone(), - ); + let config = bc_from_earning_wallet(earning_wallet.clone()); let more_money_payable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new() .non_pending_payables_result(vec![]) @@ -3613,10 +3433,8 @@ mod tests { expected = "panic message (processed with: node_lib::sub_lib::utils::crash_request_analyzer)" )] fn accountant_can_be_crashed_properly_but_not_improperly() { - let mut config = BootstrapperConfig::default(); - config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); + let mut config = make_bc_with_defaults(); config.crash_point = CrashPoint::Message; - config.accountant_config_opt = Some(make_accountant_config_null()); let accountant = AccountantBuilder::default() .bootstrapper_config(config) .build(); @@ -3720,21 +3538,12 @@ mod tests { .mark_pending_payable_rowid_params(&mark_pending_payable_params_arc) .mark_pending_payable_rowid_result(Ok(())) .mark_pending_payable_rowid_result(Ok(())); - let bootstrapper_config = bc_from_ac_plus_earning_wallet( - AccountantConfig { - scan_intervals: ScanIntervals { - payable_scan_interval: Duration::from_secs(1_000_000), //we don't care about this scan - receivable_scan_interval: Duration::from_secs(1_000_000), //we don't care about this scan - pending_payable_scan_interval: Duration::from_millis( - pending_payable_scan_interval, - ), - }, - suppress_initial_scans: false, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - }, - make_payment_thresholds_with_defaults(), - make_wallet("some_wallet_address"), - ); + let mut bootstrapper_config = bc_from_earning_wallet(make_wallet("some_wallet_address")); + bootstrapper_config.scan_intervals_opt = Some(ScanIntervals { + payable_scan_interval: Duration::from_secs(1_000_000), //we don't care about this scan + receivable_scan_interval: Duration::from_secs(1_000_000), //we don't care about this scan + pending_payable_scan_interval: Duration::from_millis(pending_payable_scan_interval), + }); let fingerprint_1_first_round = PendingPayableFingerprint { rowid_opt: Some(rowid_for_account_1), timestamp: this_payable_timestamp_1, @@ -4313,11 +4122,7 @@ mod tests { let receivable_dao = ReceivableDaoMock::new().total_result(98765432); let system = System::new("test"); let mut subject = AccountantBuilder::default() - .bootstrapper_config(bc_from_ac_plus_earning_wallet( - make_populated_accountant_config_with_defaults(), - make_payment_thresholds_with_defaults(), - make_wallet("some_wallet_address"), - )) + .bootstrapper_config(make_bc_with_defaults()) .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Scanner .receivable_dao(receivable_dao) // For Accountant diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index cf16ef05e..643355c9a 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -20,11 +20,11 @@ use crate::database::dao_utils; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::db_config::config_dao::{ConfigDao, ConfigDaoFactory}; use crate::db_config::mocks::ConfigDaoMock; -use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds}; +use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::wallet::Wallet; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::{ - make_payment_thresholds_with_defaults, make_populated_accountant_config_with_defaults, + configure_defaults_for_accountant, make_bc_with_defaults, }; use actix::System; use ethereum_types::{BigEndianHash, H256, U256}; @@ -157,12 +157,7 @@ impl AccountantBuilder { } pub fn build(self) -> Accountant { - let mut config = self.config.unwrap_or({ - let mut config = BootstrapperConfig::default(); - config.accountant_config_opt = Some(make_populated_accountant_config_with_defaults()); - config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); - config - }); + let mut config = self.config.unwrap_or(make_bc_with_defaults()); let payable_dao_factory = self.payable_dao_factory.unwrap_or( PayableDaoFactoryMock::new() .make_result(PayableDaoMock::new()) @@ -703,27 +698,16 @@ impl BannedDaoMock { } } -pub fn bc_from_ac_plus_earning_wallet( - accountant_config: AccountantConfig, - payment_thresholds: PaymentThresholds, - earning_wallet: Wallet, -) -> BootstrapperConfig { +pub fn bc_from_earning_wallet(earning_wallet: Wallet) -> BootstrapperConfig { let mut bc = BootstrapperConfig::new(); - bc.accountant_config_opt = Some(accountant_config); - bc.payment_thresholds_opt = Some(payment_thresholds); + bc = configure_defaults_for_accountant(bc); bc.earning_wallet = earning_wallet; bc } -pub fn bc_from_ac_plus_wallets( - accountant_config: AccountantConfig, - payment_thresholds: PaymentThresholds, - consuming_wallet: Wallet, - earning_wallet: Wallet, -) -> BootstrapperConfig { +pub fn bc_from_wallets(consuming_wallet: Wallet, earning_wallet: Wallet) -> BootstrapperConfig { let mut bc = BootstrapperConfig::new(); - bc.accountant_config_opt = Some(accountant_config); - bc.payment_thresholds_opt = Some(payment_thresholds); + bc = configure_defaults_for_accountant(bc); bc.consuming_wallet_opt = Some(consuming_wallet); bc.earning_wallet = earning_wallet; bc diff --git a/node/src/actor_system_factory.rs b/node/src/actor_system_factory.rs index ad6ba2792..94b9bc8da 100644 --- a/node/src/actor_system_factory.rs +++ b/node/src/actor_system_factory.rs @@ -600,6 +600,7 @@ impl LogRecipientSetter for LogRecipientSetterReal { #[cfg(test)] mod tests { use super::*; + use crate::accountant::DEFAULT_PENDING_TOO_LONG_SEC; use crate::bootstrapper::{Bootstrapper, RealUser}; use crate::database::connection_wrapper::ConnectionWrapper; use crate::node_test_utils::{ @@ -628,7 +629,8 @@ mod tests { }; use crate::test_utils::recorder::{make_recorder, Recorder}; use crate::test_utils::unshared_test_utils::{ - make_populated_accountant_config_with_defaults, ArbitraryIdStamp, SystemKillerActor, + make_payment_thresholds_with_defaults, make_scan_intervals_with_defaults, ArbitraryIdStamp, + SystemKillerActor, }; use crate::test_utils::{alias_cryptde, rate_pack}; use crate::test_utils::{main_cryptde, make_cryptde_pair}; @@ -1027,7 +1029,8 @@ mod tests { log_level: LevelFilter::Off, crash_point: CrashPoint::None, dns_servers: vec![], - accountant_config_opt: Some(make_populated_accountant_config_with_defaults()), + scan_intervals_opt: Some(make_scan_intervals_with_defaults()), + suppress_initial_scans_opt: Some(false), clandestine_discriminator_factories: Vec::new(), ui_gateway_config: UiGatewayConfig { ui_port: 5335 }, blockchain_bridge_config: BlockchainBridgeConfig { @@ -1053,7 +1056,8 @@ mod tests { rate_pack(100), ), }, - payment_thresholds_opt: Default::default(), + payment_thresholds_opt: Some(make_payment_thresholds_with_defaults()), + when_pending_too_long_opt: Some(DEFAULT_PENDING_TOO_LONG_SEC), }; let persistent_config = PersistentConfigurationMock::default().chain_name_result("eth-ropsten".to_string()); @@ -1098,7 +1102,8 @@ mod tests { log_level: LevelFilter::Off, crash_point: CrashPoint::None, dns_servers: vec![], - accountant_config_opt: None, + scan_intervals_opt: None, + suppress_initial_scans_opt: None, clandestine_discriminator_factories: Vec::new(), ui_gateway_config: UiGatewayConfig { ui_port: 5335 }, blockchain_bridge_config: BlockchainBridgeConfig { @@ -1125,6 +1130,7 @@ mod tests { ), }, payment_thresholds_opt: Default::default(), + when_pending_too_long_opt: None }; let add_mapping_params_arc = Arc::new(Mutex::new(vec![])); let mut subject = make_subject_with_null_setter(); @@ -1395,7 +1401,8 @@ mod tests { log_level: LevelFilter::Off, crash_point: CrashPoint::None, dns_servers: vec![], - accountant_config_opt: None, + scan_intervals_opt: None, + suppress_initial_scans_opt: None, clandestine_discriminator_factories: Vec::new(), ui_gateway_config: UiGatewayConfig { ui_port: 5335 }, blockchain_bridge_config: BlockchainBridgeConfig { @@ -1418,6 +1425,7 @@ mod tests { mode: NeighborhoodMode::ConsumeOnly(vec![]), }, payment_thresholds_opt: Default::default(), + when_pending_too_long_opt: None }; let system = System::new("MASQNode"); let mut subject = make_subject_with_null_setter(); @@ -1578,7 +1586,8 @@ mod tests { log_level: LevelFilter::Off, crash_point: CrashPoint::None, dns_servers: vec![], - accountant_config_opt: None, + scan_intervals_opt: None, + suppress_initial_scans_opt: None, clandestine_discriminator_factories: Vec::new(), ui_gateway_config: UiGatewayConfig { ui_port: 5335 }, blockchain_bridge_config: BlockchainBridgeConfig { @@ -1605,6 +1614,7 @@ mod tests { }, node_descriptor: Default::default(), payment_thresholds_opt: Default::default(), + when_pending_too_long_opt: None, }; let subject = make_subject_with_null_setter(); let system = System::new("MASQNode"); diff --git a/node/src/bootstrapper.rs b/node/src/bootstrapper.rs index 212be81a9..0c6ca2227 100644 --- a/node/src/bootstrapper.rs +++ b/node/src/bootstrapper.rs @@ -21,7 +21,7 @@ use crate::node_configurator::{initialize_database, DirsWrapper, NodeConfigurato use crate::privilege_drop::{IdWrapper, IdWrapperReal}; use crate::server_initializer::LoggerInitializerWrapper; use crate::sub_lib::accountant; -use crate::sub_lib::accountant::{AccountantConfig, PaymentThresholds}; +use crate::sub_lib::accountant::{PaymentThresholds, ScanIntervals}; use crate::sub_lib::blockchain_bridge::BlockchainBridgeConfig; use crate::sub_lib::cryptde::CryptDE; use crate::sub_lib::cryptde_null::CryptDENull; @@ -325,7 +325,9 @@ pub struct BootstrapperConfig { // These fields can be set while privileged without penalty pub log_level: LevelFilter, pub dns_servers: Vec, - pub accountant_config_opt: Option, + pub scan_intervals_opt: Option, + pub suppress_initial_scans_opt: Option, + pub when_pending_too_long_opt: Option, pub crash_point: CrashPoint, pub clandestine_discriminator_factories: Vec>, pub ui_gateway_config: UiGatewayConfig, @@ -359,7 +361,8 @@ impl BootstrapperConfig { // These fields can be set while privileged without penalty log_level: LevelFilter::Off, dns_servers: vec![], - accountant_config_opt: Default::default(), + scan_intervals_opt: None, + suppress_initial_scans_opt: None, crash_point: CrashPoint::None, clandestine_discriminator_factories: vec![], ui_gateway_config: UiGatewayConfig { @@ -387,6 +390,7 @@ impl BootstrapperConfig { neighborhood_config: NeighborhoodConfig { mode: NeighborhoodMode::ZeroHop, }, + when_pending_too_long_opt: None, } } @@ -400,7 +404,10 @@ impl BootstrapperConfig { self.earning_wallet = unprivileged.earning_wallet; self.consuming_wallet_opt = unprivileged.consuming_wallet_opt; self.db_password_opt = unprivileged.db_password_opt; - self.accountant_config_opt = unprivileged.accountant_config_opt; + self.scan_intervals_opt = unprivileged.scan_intervals_opt; + self.suppress_initial_scans_opt = unprivileged.suppress_initial_scans_opt; + self.payment_thresholds_opt = unprivileged.payment_thresholds_opt; + self.when_pending_too_long_opt = unprivileged.when_pending_too_long_opt; } pub fn exit_service_rate(&self) -> u64 { @@ -691,6 +698,7 @@ impl Bootstrapper { #[cfg(test)] mod tests { + use crate::accountant::DEFAULT_PENDING_TOO_LONG_SEC; use crate::actor_system_factory::{ActorFactory, ActorSystemFactory}; use crate::bootstrapper::{ main_cryptde_ref, Bootstrapper, BootstrapperConfig, EnvironmentWrapper, PortConfiguration, @@ -726,7 +734,7 @@ mod tests { use crate::test_utils::tokio_wrapper_mocks::ReadHalfWrapperMock; use crate::test_utils::tokio_wrapper_mocks::WriteHalfWrapperMock; use crate::test_utils::unshared_test_utils::{ - make_populated_accountant_config_with_defaults, make_simplified_multi_config, + make_scan_intervals_with_defaults, make_simplified_multi_config, }; use crate::test_utils::{assert_contains, rate_pack}; use crate::test_utils::{main_cryptde, make_wallet}; @@ -1224,8 +1232,9 @@ mod tests { unprivileged_config.earning_wallet = earning_wallet.clone(); unprivileged_config.consuming_wallet_opt = consuming_wallet_opt.clone(); unprivileged_config.db_password_opt = db_password_opt.clone(); - unprivileged_config.accountant_config_opt = - Some(make_populated_accountant_config_with_defaults()); + unprivileged_config.scan_intervals_opt = Some(make_scan_intervals_with_defaults()); + unprivileged_config.suppress_initial_scans_opt = Some(false); + unprivileged_config.when_pending_too_long_opt = Some(DEFAULT_PENDING_TOO_LONG_SEC); privileged_config.merge_unprivileged(unprivileged_config); @@ -1246,8 +1255,13 @@ mod tests { assert_eq!(privileged_config.consuming_wallet_opt, consuming_wallet_opt); assert_eq!(privileged_config.db_password_opt, db_password_opt); assert_eq!( - privileged_config.accountant_config_opt, - Some(make_populated_accountant_config_with_defaults()) + privileged_config.scan_intervals_opt, + Some(make_scan_intervals_with_defaults()) + ); + assert_eq!(privileged_config.suppress_initial_scans_opt, Some(false)); + assert_eq!( + privileged_config.when_pending_too_long_opt, + Some(DEFAULT_PENDING_TOO_LONG_SEC) ); //some values from the privileged config assert_eq!(privileged_config.log_level, Off); diff --git a/node/src/node_configurator/unprivileged_parse_args_configuration.rs b/node/src/node_configurator/unprivileged_parse_args_configuration.rs index 1b325b728..7ff277dca 100644 --- a/node/src/node_configurator/unprivileged_parse_args_configuration.rs +++ b/node/src/node_configurator/unprivileged_parse_args_configuration.rs @@ -4,9 +4,7 @@ use crate::accountant::DEFAULT_PENDING_TOO_LONG_SEC; use crate::blockchain::bip32::Bip32ECKeyProvider; use crate::bootstrapper::BootstrapperConfig; use crate::db_config::persistent_configuration::{PersistentConfigError, PersistentConfiguration}; -use crate::sub_lib::accountant::{ - AccountantConfig, PaymentThresholds, ScanIntervals, DEFAULT_EARNING_WALLET, -}; +use crate::sub_lib::accountant::{PaymentThresholds, ScanIntervals, DEFAULT_EARNING_WALLET}; use crate::sub_lib::cryptde::CryptDE; use crate::sub_lib::cryptde_null::CryptDENull; use crate::sub_lib::cryptde_real::CryptDEReal; @@ -479,22 +477,7 @@ fn configure_accountant_config( config: &mut BootstrapperConfig, persist_config: &mut dyn PersistentConfiguration, ) -> Result<(), ConfiguratorError> { - let suppress_initial_scans = - value_m!(multi_config, "scans", String).unwrap_or_else(|| "on".to_string()) == *"off"; - - let accountant_config = AccountantConfig { - scan_intervals: process_combined_params( - "scan-intervals", - multi_config, - persist_config, - |str: &str| ScanIntervals::try_from(str), - |pc: &dyn PersistentConfiguration| pc.scan_intervals(), - |pc: &mut dyn PersistentConfiguration, intervals| pc.set_scan_intervals(intervals), - )?, - suppress_initial_scans, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - }; - let scanners_config = process_combined_params( + let payment_thresholds = process_combined_params( "payment-thresholds", multi_config, persist_config, @@ -502,8 +485,21 @@ fn configure_accountant_config( |pc: &dyn PersistentConfiguration| pc.payment_thresholds(), |pc: &mut dyn PersistentConfiguration, curves| pc.set_payment_thresholds(curves), )?; - config.accountant_config_opt = Some(accountant_config); - config.payment_thresholds_opt = Some(scanners_config); + let scan_intervals = process_combined_params( + "scan-intervals", + multi_config, + persist_config, + |str: &str| ScanIntervals::try_from(str), + |pc: &dyn PersistentConfiguration| pc.scan_intervals(), + |pc: &mut dyn PersistentConfiguration, intervals| pc.set_scan_intervals(intervals), + )?; + let suppress_initial_scans = + value_m!(multi_config, "scans", String).unwrap_or_else(|| "on".to_string()) == *"off"; + let when_pending_too_long = DEFAULT_PENDING_TOO_LONG_SEC; + config.payment_thresholds_opt = Some(payment_thresholds); + config.scan_intervals_opt = Some(scan_intervals); + config.suppress_initial_scans_opt = Some(suppress_initial_scans); + config.when_pending_too_long_opt = Some(when_pending_too_long); Ok(()) } @@ -1739,18 +1735,12 @@ mod tests { ) .unwrap(); - let actual_accountant_config = config.accountant_config_opt.unwrap(); - let actual_scanners_config = config.payment_thresholds_opt.unwrap(); - let expected_accountant_config = AccountantConfig { - scan_intervals: ScanIntervals { - pending_payable_scan_interval: Duration::from_secs(180), - payable_scan_interval: Duration::from_secs(150), - receivable_scan_interval: Duration::from_secs(130), - }, - suppress_initial_scans: false, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, + let expected_scan_intervals = ScanIntervals { + pending_payable_scan_interval: Duration::from_secs(180), + payable_scan_interval: Duration::from_secs(150), + receivable_scan_interval: Duration::from_secs(130), }; - let expected_scanners_config = PaymentThresholds { + let expected_payment_thresholds = PaymentThresholds { threshold_interval_sec: 1000, debt_threshold_gwei: 10000, payment_grace_period_sec: 1000, @@ -1758,8 +1748,16 @@ mod tests { permanent_debt_allowed_gwei: 20000, unban_below_gwei: 20000, }; - assert_eq!(actual_accountant_config, expected_accountant_config); - assert_eq!(actual_scanners_config, expected_scanners_config); + assert_eq!( + config.payment_thresholds_opt, + Some(expected_payment_thresholds) + ); + assert_eq!(config.scan_intervals_opt, Some(expected_scan_intervals)); + assert_eq!(config.suppress_initial_scans_opt, Some(false)); + assert_eq!( + config.when_pending_too_long_opt, + Some(DEFAULT_PENDING_TOO_LONG_SEC) + ); let set_scan_intervals_params = set_scan_intervals_params_arc.lock().unwrap(); assert_eq!(*set_scan_intervals_params, vec!["180|150|130".to_string()]); let set_payment_thresholds_params = set_payment_thresholds_params_arc.lock().unwrap(); @@ -1809,18 +1807,7 @@ mod tests { ) .unwrap(); - let actual_accountant_config = config.accountant_config_opt.unwrap(); - let actual_scanners_config = config.payment_thresholds_opt.unwrap(); - let expected_accountant_config = AccountantConfig { - scan_intervals: ScanIntervals { - pending_payable_scan_interval: Duration::from_secs(180), - payable_scan_interval: Duration::from_secs(150), - receivable_scan_interval: Duration::from_secs(130), - }, - suppress_initial_scans: false, - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - }; - let expected_scanners_config = PaymentThresholds { + let expected_payment_thresholds = PaymentThresholds { threshold_interval_sec: 1000, debt_threshold_gwei: 100000, payment_grace_period_sec: 1000, @@ -1828,8 +1815,26 @@ mod tests { permanent_debt_allowed_gwei: 20000, unban_below_gwei: 20000, }; - assert_eq!(actual_accountant_config, expected_accountant_config); - assert_eq!(actual_scanners_config, expected_scanners_config); + let expected_scan_intervals = ScanIntervals { + pending_payable_scan_interval: Duration::from_secs(180), + payable_scan_interval: Duration::from_secs(150), + receivable_scan_interval: Duration::from_secs(130), + }; + let expected_suppress_initial_scans = false; + let expected_when_pending_too_long_sec = DEFAULT_PENDING_TOO_LONG_SEC; + assert_eq!( + config.payment_thresholds_opt, + Some(expected_payment_thresholds) + ); + assert_eq!(config.scan_intervals_opt, Some(expected_scan_intervals)); + assert_eq!( + config.suppress_initial_scans_opt, + Some(expected_suppress_initial_scans) + ); + assert_eq!( + config.when_pending_too_long_opt, + Some(expected_when_pending_too_long_sec) + ); //no prepared results for the setter methods, that is they were uncalled } @@ -2361,13 +2366,7 @@ mod tests { ) .unwrap(); - assert_eq!( - bootstrapper_config - .accountant_config_opt - .unwrap() - .suppress_initial_scans, - true - ); + assert_eq!(bootstrapper_config.suppress_initial_scans_opt, Some(true)); } #[test] @@ -2388,13 +2387,7 @@ mod tests { ) .unwrap(); - assert_eq!( - bootstrapper_config - .accountant_config_opt - .unwrap() - .suppress_initial_scans, - false - ); + assert_eq!(bootstrapper_config.suppress_initial_scans_opt, Some(false)); } #[test] @@ -2415,13 +2408,7 @@ mod tests { ) .unwrap(); - assert_eq!( - bootstrapper_config - .accountant_config_opt - .unwrap() - .suppress_initial_scans, - false - ); + assert_eq!(bootstrapper_config.suppress_initial_scans_opt, Some(false)); } fn make_persistent_config( diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index b913e76cc..ccbbf8307 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -513,6 +513,7 @@ pub struct TestRawTransaction { pub mod unshared_test_utils { use crate::accountant::DEFAULT_PENDING_TOO_LONG_SEC; use crate::apps::app_node; + use crate::bootstrapper::BootstrapperConfig; use crate::daemon::{ChannelFactory, DaemonBindMessage}; use crate::db_config::config_dao_null::ConfigDaoNull; use crate::db_config::persistent_configuration::PersistentConfigurationReal; @@ -602,6 +603,7 @@ pub mod unshared_test_utils { } pub fn make_populated_accountant_config_with_defaults() -> AccountantConfig { + todo!("replace it with configure_defaults_for_accountant"); AccountantConfig { scan_intervals: make_scan_intervals_with_defaults(), when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, @@ -609,6 +611,19 @@ pub mod unshared_test_utils { } } + pub fn configure_defaults_for_accountant(mut config: BootstrapperConfig) -> BootstrapperConfig { + config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); + config.scan_intervals_opt = Some(make_scan_intervals_with_defaults()); + config.suppress_initial_scans_opt = Some(false); + config.when_pending_too_long_opt = Some(DEFAULT_PENDING_TOO_LONG_SEC); + config + } + + pub fn make_bc_with_defaults() -> BootstrapperConfig { + let config = BootstrapperConfig::new(); + configure_defaults_for_accountant(config) + } + pub fn make_payment_thresholds_with_defaults() -> PaymentThresholds { DEFAULT_PAYMENT_THRESHOLDS.clone() } From 96a91d5701b5895b73e763c102e9ba2b5cb09461 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 16 Sep 2022 13:41:19 +0530 Subject: [PATCH 097/145] GH-611: refactor utility fn to build bootstrapper config with defaults --- node/src/accountant/test_utils.rs | 10 +++------- node/src/test_utils/mod.rs | 17 ++--------------- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 643355c9a..797fd9691 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -23,9 +23,7 @@ use crate::db_config::mocks::ConfigDaoMock; use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::wallet::Wallet; use crate::test_utils::make_wallet; -use crate::test_utils::unshared_test_utils::{ - configure_defaults_for_accountant, make_bc_with_defaults, -}; +use crate::test_utils::unshared_test_utils::make_bc_with_defaults; use actix::System; use ethereum_types::{BigEndianHash, H256, U256}; use rusqlite::{Connection, Error, OptionalExtension}; @@ -699,15 +697,13 @@ impl BannedDaoMock { } pub fn bc_from_earning_wallet(earning_wallet: Wallet) -> BootstrapperConfig { - let mut bc = BootstrapperConfig::new(); - bc = configure_defaults_for_accountant(bc); + let mut bc = make_bc_with_defaults(); bc.earning_wallet = earning_wallet; bc } pub fn bc_from_wallets(consuming_wallet: Wallet, earning_wallet: Wallet) -> BootstrapperConfig { - let mut bc = BootstrapperConfig::new(); - bc = configure_defaults_for_accountant(bc); + let mut bc = make_bc_with_defaults(); bc.consuming_wallet_opt = Some(consuming_wallet); bc.earning_wallet = earning_wallet; bc diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index ccbbf8307..7b41f9c3e 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -602,16 +602,8 @@ pub mod unshared_test_utils { PersistentConfigurationReal::new(Box::new(ConfigDaoNull::default())) } - pub fn make_populated_accountant_config_with_defaults() -> AccountantConfig { - todo!("replace it with configure_defaults_for_accountant"); - AccountantConfig { - scan_intervals: make_scan_intervals_with_defaults(), - when_pending_too_long_sec: DEFAULT_PENDING_TOO_LONG_SEC, - suppress_initial_scans: false, - } - } - - pub fn configure_defaults_for_accountant(mut config: BootstrapperConfig) -> BootstrapperConfig { + pub fn make_bc_with_defaults() -> BootstrapperConfig { + let mut config = BootstrapperConfig::new(); config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); config.scan_intervals_opt = Some(make_scan_intervals_with_defaults()); config.suppress_initial_scans_opt = Some(false); @@ -619,11 +611,6 @@ pub mod unshared_test_utils { config } - pub fn make_bc_with_defaults() -> BootstrapperConfig { - let config = BootstrapperConfig::new(); - configure_defaults_for_accountant(config) - } - pub fn make_payment_thresholds_with_defaults() -> PaymentThresholds { DEFAULT_PAYMENT_THRESHOLDS.clone() } From 1213b02037d920198aac165f5c6169d2ebfa9ce1 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 16 Sep 2022 13:46:11 +0530 Subject: [PATCH 098/145] GH-611: comment out AccountantConfig --- node/src/accountant/mod.rs | 3 +-- node/src/sub_lib/accountant.rs | 15 ++++++++------- node/src/test_utils/mod.rs | 12 +----------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 708aa26f3..0aa18af7f 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1128,7 +1128,6 @@ mod tests { use crate::blockchain::blockchain_interface::BlockchainTransaction; use crate::blockchain::test_utils::BlockchainInterfaceMock; use crate::blockchain::tool_wrappers::SendTransactionToolsWrapperNull; - use crate::bootstrapper::BootstrapperConfig; use crate::database::dao_utils::from_time_t; use crate::database::dao_utils::to_time_t; use crate::sub_lib::accountant::{ @@ -2564,7 +2563,7 @@ mod tests { #[test] fn report_routing_service_provided_message_is_received() { init_test_logging(); - let mut bootstrapper_config = bc_from_earning_wallet(make_wallet("hi")); + let bootstrapper_config = bc_from_earning_wallet(make_wallet("hi")); let more_money_receivable_parameters_arc = Arc::new(Mutex::new(vec![])); let payable_dao_mock = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao_mock = ReceivableDaoMock::new() diff --git a/node/src/sub_lib/accountant.rs b/node/src/sub_lib/accountant.rs index fa847081b..f5a7809d2 100644 --- a/node/src/sub_lib/accountant.rs +++ b/node/src/sub_lib/accountant.rs @@ -66,13 +66,14 @@ pub struct ScanIntervals { pub receivable_scan_interval: Duration, } -#[derive(Clone, PartialEq, Debug)] -pub struct AccountantConfig { - pub scan_intervals: ScanIntervals, - // pub payment_thresholds: PaymentThresholds, - pub suppress_initial_scans: bool, - pub when_pending_too_long_sec: u64, -} +// TODO: Remove it once you realise you don't want to know which fields was accountant config composed of +// #[derive(Clone, PartialEq, Debug)] +// pub struct AccountantConfig { +// pub scan_intervals: ScanIntervals, +// pub payment_thresholds: PaymentThresholds, +// pub suppress_initial_scans: bool, +// pub when_pending_too_long_sec: u64, +// } #[derive(Clone)] pub struct AccountantSubs { diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 7b41f9c3e..86367fa80 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -519,8 +519,7 @@ pub mod unshared_test_utils { use crate::db_config::persistent_configuration::PersistentConfigurationReal; use crate::node_test_utils::DirsWrapperMock; use crate::sub_lib::accountant::{ - AccountantConfig, PaymentThresholds, ScanIntervals, DEFAULT_PAYMENT_THRESHOLDS, - DEFAULT_SCAN_INTERVALS, + PaymentThresholds, ScanIntervals, DEFAULT_PAYMENT_THRESHOLDS, DEFAULT_SCAN_INTERVALS, }; use crate::sub_lib::neighborhood::DEFAULT_RATE_PACK; use crate::sub_lib::utils::{ @@ -604,7 +603,6 @@ pub mod unshared_test_utils { pub fn make_bc_with_defaults() -> BootstrapperConfig { let mut config = BootstrapperConfig::new(); - config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); config.scan_intervals_opt = Some(make_scan_intervals_with_defaults()); config.suppress_initial_scans_opt = Some(false); config.when_pending_too_long_opt = Some(DEFAULT_PENDING_TOO_LONG_SEC); @@ -619,14 +617,6 @@ pub mod unshared_test_utils { DEFAULT_SCAN_INTERVALS.clone() } - pub fn make_accountant_config_null() -> AccountantConfig { - AccountantConfig { - scan_intervals: Default::default(), - when_pending_too_long_sec: Default::default(), - suppress_initial_scans: false, - } - } - pub fn make_daemon_bind_message(ui_gateway: Recorder) -> DaemonBindMessage { let (stub, _, _) = make_recorder(); let stub_sub = stub.start().recipient::(); From bb439fbf81a3da59c1735cb7a5e35d6b034e1c7c Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 16 Sep 2022 15:58:59 +0530 Subject: [PATCH 099/145] GH-611: migrate process_transaction_by_status() to the scanners.rs --- node/src/accountant/scanners.rs | 86 ++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index c10c0add8..e0a467ebf 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -333,7 +333,7 @@ pub(in crate::accountant) mod scanners { message.fingerprints_with_receipts.len() ); let statuses = self.handle_pending_transaction_with_its_receipt(&message, logger); - // self.process_transaction_by_status(statuses, ctx); + self.process_transaction_by_status(statuses, logger); let message_opt = match message.response_skeleton_opt { Some(response_skeleton) => Some(NodeToUiMessage { @@ -453,6 +453,90 @@ pub(in crate::accountant) mod scanners { } } } + + fn process_transaction_by_status( + &mut self, + statuses: Vec, + logger: &Logger, + ) { + statuses.into_iter().for_each(|status| { + if let PendingTransactionStatus::StillPending(transaction_id) = status { + self.update_payable_fingerprint(transaction_id, logger) + } else if let PendingTransactionStatus::Failure(transaction_id) = status { + self.order_cancel_failed_transaction(transaction_id, logger) + } else if let PendingTransactionStatus::Confirmed(fingerprint) = status { + self.order_confirm_transaction(fingerprint, logger) + } + }); + } + + fn update_payable_fingerprint( + &self, + pending_payable_id: PendingPayableId, + logger: &Logger, + ) { + match self.dao.update_fingerprint(pending_payable_id.rowid) { + Ok(_) => trace!( + logger, + "Updated record for rowid: {} ", + pending_payable_id.rowid + ), + Err(e) => panic!( + "Failure on updating payable fingerprint '{:?}' due to {:?}", + pending_payable_id.hash, e + ), + } + } + + fn order_cancel_failed_transaction( + &self, + transaction_id: PendingPayableId, + logger: &Logger, + ) { + match self + .dao + .mark_failure(transaction_id.rowid) + { + Ok(_) => warning!( + logger, + "Broken transaction {} left with an error mark; you should take over the care of this transaction to make sure your debts will be paid because there is no automated process that can fix this without you", msg.id.hash), + Err(e) => panic!("Unsuccessful attempt for transaction {} to mark fatal error at payable fingerprint due to {:?}; database unreliable", msg.id.hash, e), + } + } + + fn order_confirm_transaction( + &mut self, + pending_payable_fingerprint: PendingPayableFingerprint, + logger: &Logger, + ) { + let hash = pending_payable_fingerprint.hash; + let amount = pending_payable_fingerprint.amount; + let rowid = pending_payable_fingerprint + .rowid_opt + .expectv("initialized rowid"); + + if let Err(e) = self.dao.transaction_confirmed(pending_payable_fingerprint) { + panic!( + "Was unable to uncheck pending payable '{}' after confirmation due to '{:?}'", + hash, e + ) + } else { + self.financial_statistics.total_paid_payable += amount; + debug!( + logger, + "Confirmation of transaction {}; record for payable was modified", hash + ); + if let Err(e) = self.dao.delete_fingerprint(rowid) { + panic!("Was unable to delete payable fingerprint '{}' after successful transaction due to '{:?}'", msg.pending_payable_fingerprint.hash, e) + } else { + info!( + logger, + "Transaction {:?} has gone through the whole confirmation process succeeding", + hash + ) + } + } + } } pub struct ReceivableScanner { From 534882147ca95c67248493178bc5f8a49cea431f Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 19 Sep 2022 12:52:31 +0530 Subject: [PATCH 100/145] GH-611: return errors instead of panicking inside PendingPayable Scanner --- node/src/accountant/scanners.rs | 118 ++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 45 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index e0a467ebf..c5d209c5b 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -114,7 +114,7 @@ pub(in crate::accountant) mod scanners { pub struct PayableScanner { common: ScannerCommon, - dao: Box, + payable_dao: Box, pending_payable_dao: Box, } @@ -130,7 +130,7 @@ pub(in crate::accountant) mod scanners { } self.common.initiated_at_opt = Some(timestamp); info!(logger, "Scanning for payables"); - let all_non_pending_payables = self.dao.non_pending_payables(); + let all_non_pending_payables = self.payable_dao.non_pending_payables(); debug!( logger, "{}", @@ -202,7 +202,7 @@ pub(in crate::accountant) mod scanners { ) -> Self { Self { common: ScannerCommon::new(payment_thresholds), - dao, + payable_dao: dao, pending_payable_dao, } } @@ -215,7 +215,7 @@ pub(in crate::accountant) mod scanners { for payable in sent_payables { if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(payable.tx_hash) { if let Err(e) = self - .dao + .payable_dao .as_ref() .mark_pending_payable_rowid(&payable.to, rowid) { @@ -282,7 +282,7 @@ pub(in crate::accountant) mod scanners { pub struct PendingPayableScanner { common: ScannerCommon, - dao: Box, + pending_payable_dao: Box, when_pending_too_long_sec: u64, } @@ -298,7 +298,7 @@ pub(in crate::accountant) mod scanners { } self.common.initiated_at_opt = Some(timestamp); info!(logger, "Scanning for pending payable"); - let filtered_pending_payable = self.dao.return_all_fingerprints(); + let filtered_pending_payable = self.pending_payable_dao.return_all_fingerprints(); match filtered_pending_payable.is_empty() { true => { debug!( @@ -333,7 +333,7 @@ pub(in crate::accountant) mod scanners { message.fingerprints_with_receipts.len() ); let statuses = self.handle_pending_transaction_with_its_receipt(&message, logger); - self.process_transaction_by_status(statuses, logger); + self.process_transaction_by_status(statuses, logger)?; let message_opt = match message.response_skeleton_opt { Some(response_skeleton) => Some(NodeToUiMessage { @@ -361,7 +361,7 @@ pub(in crate::accountant) mod scanners { ) -> Self { Self { common: ScannerCommon::new(payment_thresholds), - dao, + pending_payable_dao: dao, when_pending_too_long_sec, } } @@ -458,33 +458,45 @@ pub(in crate::accountant) mod scanners { &mut self, statuses: Vec, logger: &Logger, - ) { - statuses.into_iter().for_each(|status| { - if let PendingTransactionStatus::StillPending(transaction_id) = status { - self.update_payable_fingerprint(transaction_id, logger) - } else if let PendingTransactionStatus::Failure(transaction_id) = status { - self.order_cancel_failed_transaction(transaction_id, logger) - } else if let PendingTransactionStatus::Confirmed(fingerprint) = status { - self.order_confirm_transaction(fingerprint, logger) + ) -> Result<(), String> { + for status in statuses { + match status { + PendingTransactionStatus::StillPending(transaction_id) => { + self.update_payable_fingerprint(transaction_id, logger)?; + } + PendingTransactionStatus::Failure(transaction_id) => { + self.order_cancel_failed_transaction(transaction_id, logger)?; + } + PendingTransactionStatus::Confirmed(fingerprint) => { + self.order_confirm_transaction(fingerprint, logger)?; + } } - }); + } + + Ok(()) } fn update_payable_fingerprint( &self, pending_payable_id: PendingPayableId, logger: &Logger, - ) { - match self.dao.update_fingerprint(pending_payable_id.rowid) { - Ok(_) => trace!( - logger, - "Updated record for rowid: {} ", - pending_payable_id.rowid - ), - Err(e) => panic!( + ) -> Result<(), String> { + match self + .pending_payable_dao + .update_fingerprint(pending_payable_id.rowid) + { + Ok(_) => { + trace!( + logger, + "Updated record for rowid: {} ", + pending_payable_id.rowid + ); + Ok(()) + } + Err(e) => Err(format!( "Failure on updating payable fingerprint '{:?}' due to {:?}", pending_payable_id.hash, e - ), + )), } } @@ -492,15 +504,23 @@ pub(in crate::accountant) mod scanners { &self, transaction_id: PendingPayableId, logger: &Logger, - ) { - match self - .dao - .mark_failure(transaction_id.rowid) - { - Ok(_) => warning!( - logger, - "Broken transaction {} left with an error mark; you should take over the care of this transaction to make sure your debts will be paid because there is no automated process that can fix this without you", msg.id.hash), - Err(e) => panic!("Unsuccessful attempt for transaction {} to mark fatal error at payable fingerprint due to {:?}; database unreliable", msg.id.hash, e), + ) -> Result<(), String> { + match self.pending_payable_dao.mark_failure(transaction_id.rowid) { + Ok(_) => { + warning!( + logger, + "Broken transaction {} left with an error mark; you should take over the care \ + of this transaction to make sure your debts will be paid because there is no \ + automated process that can fix this without you", transaction_id.hash + ); + + Ok(()) + } + Err(e) => Err(format!( + "Unsuccessful attempt for transaction {} to mark fatal error at payable \ + fingerprint due to {:?}; database unreliable", + transaction_id.hash, e + )), } } @@ -508,32 +528,40 @@ pub(in crate::accountant) mod scanners { &mut self, pending_payable_fingerprint: PendingPayableFingerprint, logger: &Logger, - ) { + ) -> Result<(), String> { let hash = pending_payable_fingerprint.hash; let amount = pending_payable_fingerprint.amount; let rowid = pending_payable_fingerprint .rowid_opt .expectv("initialized rowid"); - if let Err(e) = self.dao.transaction_confirmed(pending_payable_fingerprint) { - panic!( + if let Err(e) = self + .pending_payable_dao + .transaction_confirmed(pending_payable_fingerprint) + { + Err(format!( "Was unable to uncheck pending payable '{}' after confirmation due to '{:?}'", hash, e - ) + )) } else { self.financial_statistics.total_paid_payable += amount; debug!( logger, "Confirmation of transaction {}; record for payable was modified", hash ); - if let Err(e) = self.dao.delete_fingerprint(rowid) { - panic!("Was unable to delete payable fingerprint '{}' after successful transaction due to '{:?}'", msg.pending_payable_fingerprint.hash, e) + if let Err(e) = self.pending_payable_dao.delete_fingerprint(rowid) { + Err(format!( + "Was unable to delete payable fingerprint '{}' after successful transaction \ + due to '{:?}'", hash, e + )) } else { info!( - logger, - "Transaction {:?} has gone through the whole confirmation process succeeding", - hash - ) + logger, + "Transaction {:?} has gone through the whole confirmation process succeeding", + hash + ); + + Ok(()) } } } From d529671d4cf6367023fa2b8e34ef7b0b2c3e8150 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 19 Sep 2022 13:06:45 +0530 Subject: [PATCH 101/145] GH-611: pass payable dao inside pending payable scanner --- node/src/accountant/mod.rs | 2 +- node/src/accountant/scanners.rs | 35 +++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 0aa18af7f..7e061fbc5 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -471,7 +471,7 @@ impl Accountant { banned_dao: banned_dao_factory.make(), crashable: config.crash_point == CrashPoint::Message, scanners: Scanners::new( - payable_dao_factory.make(), + payable_dao_factory, pending_payable_dao_factory, receivable_dao_factory.make(), banned_dao_factory.make(), diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index c5d209c5b..4cb66555d 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -1,7 +1,7 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. pub(in crate::accountant) mod scanners { - use crate::accountant::payable_dao::{Payable, PayableDao}; + use crate::accountant::payable_dao::{Payable, PayableDao, PayableDaoFactory}; use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDaoFactory}; use crate::accountant::receivable_dao::ReceivableDao; use crate::accountant::tools::payable_scanner_tools::{ @@ -49,7 +49,7 @@ pub(in crate::accountant) mod scanners { impl Scanners { pub fn new( - payable_dao: Box, + payable_dao_factory: Box, pending_payable_dao_factory: Box, receivable_dao: Box, banned_dao: Box, @@ -59,11 +59,12 @@ pub(in crate::accountant) mod scanners { ) -> Self { Scanners { payables: Box::new(PayableScanner::new( - payable_dao, + payable_dao_factory.make(), pending_payable_dao_factory.make(), Rc::clone(&payment_thresholds), )), pending_payables: Box::new(PendingPayableScanner::new( + payable_dao_factory.make(), pending_payable_dao_factory.make(), Rc::clone(&payment_thresholds), when_pending_too_long_sec, @@ -196,13 +197,13 @@ pub(in crate::accountant) mod scanners { impl PayableScanner { pub fn new( - dao: Box, + payable_dao: Box, pending_payable_dao: Box, payment_thresholds: Rc, ) -> Self { Self { common: ScannerCommon::new(payment_thresholds), - payable_dao: dao, + payable_dao, pending_payable_dao, } } @@ -282,6 +283,7 @@ pub(in crate::accountant) mod scanners { pub struct PendingPayableScanner { common: ScannerCommon, + payable_dao: Box, pending_payable_dao: Box, when_pending_too_long_sec: u64, } @@ -355,13 +357,15 @@ pub(in crate::accountant) mod scanners { impl PendingPayableScanner { pub fn new( - dao: Box, + payable_dao: Box, + pending_payable_dao: Box, payment_thresholds: Rc, when_pending_too_long_sec: u64, ) -> Self { Self { common: ScannerCommon::new(payment_thresholds), - pending_payable_dao: dao, + payable_dao, + pending_payable_dao, when_pending_too_long_sec, } } @@ -536,8 +540,8 @@ pub(in crate::accountant) mod scanners { .expectv("initialized rowid"); if let Err(e) = self - .pending_payable_dao - .transaction_confirmed(pending_payable_fingerprint) + .payable_dao + .transaction_confirmed(&pending_payable_fingerprint) { Err(format!( "Was unable to uncheck pending payable '{}' after confirmation due to '{:?}'", @@ -776,13 +780,13 @@ mod tests { PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, ScannerError, Scanners, }; use crate::accountant::test_utils::{ - make_payables, make_receivable_account, BannedDaoMock, PayableDaoMock, - PendingPayableDaoFactoryMock, PendingPayableDaoMock, ReceivableDaoMock, + make_payables, make_receivable_account, BannedDaoMock, PayableDaoFactoryMock, + PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, ReceivableDaoMock, }; use crate::accountant::{RequestTransactionReceipts, SentPayable}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; - use crate::accountant::payable_dao::{Payable, PayableDaoError}; + use crate::accountant::payable_dao::{Payable, PayableDaoError, PayableDaoFactory}; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::blockchain::blockchain_interface::BlockchainError; use crate::sub_lib::accountant::PaymentThresholds; @@ -800,11 +804,14 @@ mod tests { #[test] fn scanners_struct_can_be_constructed_with_the_respective_scanners() { let payment_thresholds = Rc::new(make_payment_thresholds_with_defaults()); + let payable_dao_factory = PayableDaoFactoryMock::new() + .make_result(PayableDaoMock::new()) + .make_result(PayableDaoMock::new()); let pending_payable_dao_factory = PendingPayableDaoFactoryMock::new() .make_result(PendingPayableDaoMock::new()) .make_result(PendingPayableDaoMock::new()); let scanners = Scanners::new( - Box::new(PayableDaoMock::new()), + Box::new(payable_dao_factory), Box::new(pending_payable_dao_factory), Box::new(ReceivableDaoMock::new()), Box::new(BannedDaoMock::new()), @@ -1007,6 +1014,7 @@ mod tests { PendingPayableDaoMock::new().return_all_fingerprints_result(fingerprints.clone()); let payment_thresholds = make_payment_thresholds_with_defaults(); let mut pending_payable_scanner = PendingPayableScanner::new( + Box::new(PayableDaoMock::new()), Box::new(pending_payable_dao), Rc::new(payment_thresholds), 0, @@ -1044,6 +1052,7 @@ mod tests { PendingPayableDaoMock::new().return_all_fingerprints_result(vec![]); let payment_thresholds = make_payment_thresholds_with_defaults(); let mut pending_payable_scanner = PendingPayableScanner::new( + Box::new(PayableDaoMock::new()), Box::new(pending_payable_dao), Rc::new(payment_thresholds), 0, From 13e9b3b64af9d4f6eb30b9697bb4c725edff67b7 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 20 Sep 2022 15:05:32 +0530 Subject: [PATCH 102/145] GH-611: share FinancialStatistics with the PendingPayableScanner --- node/src/accountant/mod.rs | 53 ++++++++++++++++++++++----------- node/src/accountant/scanners.rs | 20 ++++++++++--- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 7e061fbc5..5370d3f34 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -9,6 +9,8 @@ pub mod tools; pub mod test_utils; use masq_lib::constants::SCAN_ERROR; +use std::borrow::{Borrow, BorrowMut}; +use std::cell::RefCell; use masq_lib::messages::{ScanType, UiScanRequest, UiScanResponse}; use masq_lib::ui_gateway::{MessageBody, MessagePath, MessageTarget}; @@ -76,7 +78,7 @@ pub struct Accountant { scanners: Scanners, tools: TransactionConfirmationTools, notify_later: NotifyLaterForScanners, - financial_statistics: FinancialStatistics, + financial_statistics: Rc>, report_accounts_payable_sub_opt: Option>, retrieve_transactions_sub: Option>, request_transaction_receipts_subs_opt: Option>, @@ -460,6 +462,7 @@ impl Accountant { .expectv("When pending too long sec"); let earning_wallet = Rc::new(config.earning_wallet.clone()); + let financial_statistics = Rc::new(RefCell::new(FinancialStatistics::default())); Accountant { scan_intervals, suppress_initial_scans_opt: config.suppress_initial_scans_opt, @@ -478,10 +481,11 @@ impl Accountant { Rc::clone(&payment_thresholds), Rc::clone(&earning_wallet), when_pending_too_long_sec, + Rc::clone(&financial_statistics), ), tools: TransactionConfirmationTools::default(), notify_later: NotifyLaterForScanners::default(), - financial_statistics: FinancialStatistics::default(), + financial_statistics: Rc::clone(&financial_statistics), report_accounts_payable_sub_opt: None, retrieve_transactions_sub: None, request_transaction_receipts_subs_opt: None, @@ -613,7 +617,9 @@ impl Accountant { self.receivable_dao .as_mut() .more_money_received(msg.payments); - self.financial_statistics.total_paid_receivable += total_newly_paid_receivable; + let mut financial_statistics = self.financial_statistics(); + financial_statistics.total_paid_receivable += total_newly_paid_receivable; + self.financial_statistics.replace(financial_statistics); } if let Some(response_skeleton) = msg.response_skeleton_opt { self.ui_message_sub @@ -700,10 +706,11 @@ impl Accountant { } fn handle_financials(&mut self, client_id: u64, context_id: u64) { + let financial_statistics = self.financial_statistics(); let total_unpaid_and_pending_payable = self.payable_dao.total(); - let total_paid_payable = self.financial_statistics.total_paid_payable; + let total_paid_payable = financial_statistics.total_paid_payable; let total_unpaid_receivable = self.receivable_dao.total(); - let total_paid_receivable = self.financial_statistics.total_paid_receivable; + let total_paid_receivable = financial_statistics.total_paid_receivable; let body = UiFinancialsResponse { total_unpaid_and_pending_payable, total_paid_payable, @@ -870,7 +877,9 @@ impl Accountant { msg.pending_payable_fingerprint.hash, e ) } else { - self.financial_statistics.total_paid_payable += msg.pending_payable_fingerprint.amount; + let mut financial_statistics = self.financial_statistics.as_ref().borrow().clone(); + financial_statistics.total_paid_payable += msg.pending_payable_fingerprint.amount; + self.financial_statistics.replace(financial_statistics); debug!( self.logger, "Confirmation of transaction {}; record for payable was modified", @@ -1050,6 +1059,10 @@ impl Accountant { ), } } + + fn financial_statistics(&self) -> FinancialStatistics { + self.financial_statistics.as_ref().borrow().clone() + } } pub fn unsigned_to_signed(unsigned: u64) -> Result { @@ -1240,6 +1253,7 @@ mod tests { banned_dao_factory, ); + let financial_statistics = result.financial_statistics(); let transaction_confirmation_tools = result.tools; transaction_confirmation_tools .notify_confirm_transaction @@ -1275,8 +1289,8 @@ mod tests { // .downcast_ref::() // .unwrap(); assert_eq!(result.crashable, false); - assert_eq!(result.financial_statistics.total_paid_receivable, 0); - assert_eq!(result.financial_statistics.total_paid_payable, 0); + assert_eq!(financial_statistics.total_paid_receivable, 0); + assert_eq!(financial_statistics.total_paid_payable, 0); } #[test] @@ -4127,8 +4141,10 @@ mod tests { .receivable_dao(receivable_dao) // For Accountant .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); - subject.financial_statistics.total_paid_payable = 123456; - subject.financial_statistics.total_paid_receivable = 334455; + let mut financial_statistics = subject.financial_statistics(); + financial_statistics.total_paid_payable = 123456; + financial_statistics.total_paid_receivable = 334455; + subject.financial_statistics.replace(financial_statistics); let (ui_gateway, _, ui_gateway_recording_arc) = make_recorder(); let subject_addr = subject.start(); let peer_actors = peer_actors_builder().ui_gateway(ui_gateway).build(); @@ -4183,14 +4199,17 @@ mod tests { .pending_payable_dao(PendingPayableDaoMock::new()) .pending_payable_dao(PendingPayableDaoMock::new()) .build(); - subject.financial_statistics.total_paid_payable += 1111; + let mut financial_statistics = subject.financial_statistics(); + financial_statistics.total_paid_payable += 1111; + subject.financial_statistics.replace(financial_statistics); let msg = ConfirmPendingTransaction { pending_payable_fingerprint: fingerprint.clone(), }; subject.handle_confirm_pending_transaction(msg); - assert_eq!(subject.financial_statistics.total_paid_payable, 1111 + 5478); + let total_paid_payable = subject.financial_statistics().total_paid_payable; + assert_eq!(total_paid_payable, 1111 + 5478); let transaction_confirmed_params = transaction_confirmed_params_arc.lock().unwrap(); assert_eq!(*transaction_confirmed_params, vec![fingerprint]) } @@ -4205,7 +4224,9 @@ mod tests { .receivable_dao(receivable_dao) .receivable_dao(ReceivableDaoMock::new()) .build(); - subject.financial_statistics.total_paid_receivable += 2222; + let mut financial_statistics = subject.financial_statistics(); + financial_statistics.total_paid_receivable += 2222; + subject.financial_statistics.replace(financial_statistics); let receivables = vec![ BlockchainTransaction { block_number: 4578910, @@ -4224,10 +4245,8 @@ mod tests { response_skeleton_opt: None, }); - assert_eq!( - subject.financial_statistics.total_paid_receivable, - 2222 + 45780 + 33345 - ); + let total_paid_receivable = subject.financial_statistics().total_paid_receivable; + assert_eq!(total_paid_receivable, 2222 + 45780 + 33345); let more_money_received_params = more_money_received_params_arc.lock().unwrap(); assert_eq!(*more_money_received_params, vec![receivables]); } diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 4cb66555d..115359bf2 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -18,7 +18,7 @@ pub(in crate::accountant) mod scanners { use crate::banned_dao::BannedDao; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::BlockchainError; - use crate::sub_lib::accountant::PaymentThresholds; + use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; use crate::sub_lib::wallet::Wallet; use actix::Message; @@ -27,6 +27,8 @@ pub(in crate::accountant) mod scanners { use masq_lib::ui_gateway::{MessageTarget, NodeToUiMessage}; use masq_lib::utils::ExpectValue; use std::any::Any; + use std::borrow::{Borrow, BorrowMut}; + use std::cell::RefCell; use std::rc::Rc; use std::time::SystemTime; use web3::types::TransactionReceipt; @@ -56,6 +58,7 @@ pub(in crate::accountant) mod scanners { payment_thresholds: Rc, earning_wallet: Rc, when_pending_too_long_sec: u64, + financial_statistics: Rc>, ) -> Self { Scanners { payables: Box::new(PayableScanner::new( @@ -68,6 +71,7 @@ pub(in crate::accountant) mod scanners { pending_payable_dao_factory.make(), Rc::clone(&payment_thresholds), when_pending_too_long_sec, + financial_statistics, )), receivables: Box::new(ReceivableScanner::new( receivable_dao, @@ -286,6 +290,7 @@ pub(in crate::accountant) mod scanners { payable_dao: Box, pending_payable_dao: Box, when_pending_too_long_sec: u64, + financial_statistics: Rc>, } impl Scanner for PendingPayableScanner { @@ -361,12 +366,14 @@ pub(in crate::accountant) mod scanners { pending_payable_dao: Box, payment_thresholds: Rc, when_pending_too_long_sec: u64, + financial_statistics: Rc>, ) -> Self { Self { common: ScannerCommon::new(payment_thresholds), payable_dao, pending_payable_dao, when_pending_too_long_sec, + financial_statistics, } } @@ -548,7 +555,9 @@ pub(in crate::accountant) mod scanners { hash, e )) } else { - self.financial_statistics.total_paid_payable += amount; + let mut financial_statistics = self.financial_statistics.as_ref().borrow().clone(); + financial_statistics.total_paid_payable += amount; + self.financial_statistics.replace(financial_statistics); debug!( logger, "Confirmation of transaction {}; record for payable was modified", hash @@ -775,7 +784,6 @@ pub(in crate::accountant) mod scanners { #[cfg(test)] mod tests { - use crate::accountant::scanners::scanners::{ PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, ScannerError, Scanners, }; @@ -785,11 +793,12 @@ mod tests { }; use crate::accountant::{RequestTransactionReceipts, SentPayable}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; + use std::cell::RefCell; use crate::accountant::payable_dao::{Payable, PayableDaoError, PayableDaoFactory}; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::blockchain::blockchain_interface::BlockchainError; - use crate::sub_lib::accountant::PaymentThresholds; + use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; @@ -818,6 +827,7 @@ mod tests { Rc::clone(&payment_thresholds), Rc::new(make_wallet("earning")), 0, + Rc::new(RefCell::new(FinancialStatistics::default())), ); scanners @@ -1018,6 +1028,7 @@ mod tests { Box::new(pending_payable_dao), Rc::new(payment_thresholds), 0, + Rc::new(RefCell::new(FinancialStatistics::default())), ); let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); @@ -1056,6 +1067,7 @@ mod tests { Box::new(pending_payable_dao), Rc::new(payment_thresholds), 0, + Rc::new(RefCell::new(FinancialStatistics::default())), ); let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); From fe581628ac6bd52f94c93b816320fdbcbf399f72 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 20 Sep 2022 15:11:55 +0530 Subject: [PATCH 103/145] GH-611: fix AccountantBuilder's default configuration --- node/src/test_utils/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 86367fa80..cc81f1d36 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -606,6 +606,7 @@ pub mod unshared_test_utils { config.scan_intervals_opt = Some(make_scan_intervals_with_defaults()); config.suppress_initial_scans_opt = Some(false); config.when_pending_too_long_opt = Some(DEFAULT_PENDING_TOO_LONG_SEC); + config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); config } From 04a63e2ff76ba22d2562b69769cd14d6b7614744 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 20 Sep 2022 15:45:48 +0530 Subject: [PATCH 104/145] GH-611: supply PayableDAO for PendingPayableScanner inside tests --- node/src/accountant/mod.rs | 76 ++++++++++++++++++++++--------- node/src/accountant/test_utils.rs | 1 + 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 5370d3f34..aaebf8063 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1176,6 +1176,7 @@ mod tests { let payable_dao_factory = PayableDaoFactoryMock::new() .make_params(&payable_dao_factory_params_arc) .make_result(PayableDaoMock::new()) + .make_result(PayableDaoMock::new()) .make_result(PayableDaoMock::new()); let pending_payable_dao_factory = PendingPayableDaoFactoryMock::new() .make_params(&pending_payable_dao_factory_params_arc) @@ -1201,7 +1202,7 @@ mod tests { assert_eq!( *payable_dao_factory_params_arc.lock().unwrap(), - vec![(), ()] + vec![(), (), ()] ); assert_eq!( *pending_payable_dao_factory_params_arc.lock().unwrap(), @@ -1226,7 +1227,8 @@ mod tests { let payable_dao_factory = Box::new( PayableDaoFactoryMock::new() .make_result(PayableDaoMock::new()) // For Accountant - .make_result(PayableDaoMock::new()), // For Scanner + .make_result(PayableDaoMock::new()) // For Payable Scanner + .make_result(PayableDaoMock::new()), // For PendingPayable Scanner ); let pending_payable_dao_factory = Box::new( PendingPayableDaoFactoryMock::new() @@ -1396,7 +1398,8 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let subject_addr = subject.start(); @@ -1640,7 +1643,8 @@ mod tests { let accountant = AccountantBuilder::default() .bootstrapper_config(bc_from_earning_wallet(make_wallet("some_wallet_address"))) .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant .pending_payable_dao(pending_payable_dao) // For Payable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner @@ -1734,7 +1738,8 @@ mod tests { .delete_fingerprint_result(Ok(())); let subject = AccountantBuilder::default() .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant .pending_payable_dao(pending_payable_dao) // For Payable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner @@ -1803,7 +1808,8 @@ mod tests { let mut subject = AccountantBuilder::default() .bootstrapper_config(bc_from_earning_wallet(make_wallet("some_wallet_address"))) .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); subject.scanners.pending_payables = Box::new(NullScanner::new()); subject.scanners.receivables = Box::new(NullScanner::new()); @@ -1886,12 +1892,14 @@ mod tests { gwei_amount: 10000, }; let more_money_received_params_arc = Arc::new(Mutex::new(vec![])); + let payable_dao = PayableDaoMock::new().non_pending_payables_result(vec![]); let receivable_dao = ReceivableDaoMock::new() .more_money_received_parameters(&more_money_received_params_arc) .more_money_received_result(Ok(())); let accountant = AccountantBuilder::default() .bootstrapper_config(bc_from_earning_wallet(earning_wallet.clone())) - .payable_dao(PayableDaoMock::new().non_pending_payables_result(vec![])) + .payable_dao(payable_dao) + .payable_dao(PayableDaoMock::new()) .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao) .receivable_dao(ReceivableDaoMock::new()) @@ -1940,7 +1948,8 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner .pending_payable_dao(pending_payable_dao) // For PendingPayable Scanner @@ -2307,7 +2316,8 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .receivable_dao(receivable_dao) // For Accountant .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); @@ -2381,7 +2391,8 @@ mod tests { let mut subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); @@ -2441,7 +2452,8 @@ mod tests { let mut subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); subject.scanners.pending_payables = Box::new(NullScanner::new()); subject.scanners.receivables = Box::new(NullScanner::new()); @@ -2486,7 +2498,8 @@ mod tests { let system = System::new(test_name); let mut subject = AccountantBuilder::default() .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .bootstrapper_config(config) .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); @@ -2587,6 +2600,7 @@ mod tests { .bootstrapper_config(bootstrapper_config) .payable_dao(payable_dao_mock) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao_mock) .receivable_dao(ReceivableDaoMock::new()) .build(); @@ -2634,6 +2648,7 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao_mock) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao_mock) .receivable_dao(ReceivableDaoMock::new()) .build(); @@ -2680,6 +2695,7 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao_mock) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao_mock) .receivable_dao(ReceivableDaoMock::new()) .build(); @@ -2725,7 +2741,8 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao_mock) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); let system = System::new("report_routing_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -2770,6 +2787,7 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao_mock) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .build(); let system = System::new("report_routing_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -2810,7 +2828,8 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao_mock) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); let system = System::new("report_routing_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -2851,6 +2870,7 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao_mock) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao_mock) .receivable_dao(ReceivableDaoMock::new()) .build(); @@ -2898,6 +2918,7 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao_mock) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .receivable_dao(receivable_dao_mock) .receivable_dao(ReceivableDaoMock::new()) .build(); @@ -2943,7 +2964,8 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao_mock) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .receivable_dao(receivable_dao_mock) // For Accountant .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); @@ -3004,6 +3026,7 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao_mock) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .build(); let system = System::new("report_exit_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3048,7 +3071,8 @@ mod tests { let subject = AccountantBuilder::default() .bootstrapper_config(config) .payable_dao(payable_dao_mock) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); let system = System::new("report_exit_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3090,6 +3114,7 @@ mod tests { .bootstrapper_config(config) .payable_dao(payable_dao_mock) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .build(); let system = System::new("report_exit_service_consumed_message_is_received"); let subject_addr: Addr = subject.start(); @@ -3168,6 +3193,7 @@ mod tests { let subject = AccountantBuilder::default() .payable_dao(payable_dao) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .build(); let service_rate = i64::MAX as u64; @@ -3195,6 +3221,7 @@ mod tests { let subject = AccountantBuilder::default() .payable_dao(payable_dao) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .build(); let _ = subject.record_service_consumed(i64::MAX as u64, 1, 2, &wallet); @@ -3259,7 +3286,8 @@ mod tests { .fingerprint_rowid_result(Some(payable_2_rowid)); let mut subject = AccountantBuilder::default() .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Scanner + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant .pending_payable_dao(pending_payable_dao) // For Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner @@ -3293,7 +3321,8 @@ mod tests { .delete_fingerprint_result(Ok(())); let mut subject = AccountantBuilder::default() .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .pending_payable_dao(pending_payable_dao) // For Accountant .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner @@ -3344,6 +3373,7 @@ mod tests { let mut subject = AccountantBuilder::default() .payable_dao(payable_dao) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .build(); let mut payment = make_pending_payable_fingerprint(); payment.rowid_opt = Some(rowid); @@ -3371,7 +3401,8 @@ mod tests { )); let mut subject = AccountantBuilder::default() .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .pending_payable_dao(pending_payable_dao) // For Accountant .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner @@ -3428,7 +3459,8 @@ mod tests { )); let subject = AccountantBuilder::default() .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .pending_payable_dao(pending_payable_dao) .pending_payable_dao(PendingPayableDaoMock::new()) .pending_payable_dao(PendingPayableDaoMock::new()) @@ -4137,7 +4169,8 @@ mod tests { let mut subject = AccountantBuilder::default() .bootstrapper_config(make_bc_with_defaults()) .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Scanner + .payable_dao(PayableDaoMock::new()) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .receivable_dao(receivable_dao) // For Accountant .receivable_dao(ReceivableDaoMock::new()) // For Scanner .build(); @@ -4195,6 +4228,7 @@ mod tests { let mut subject = AccountantBuilder::default() .payable_dao(payable_dao) .payable_dao(PayableDaoMock::new()) + .payable_dao(PayableDaoMock::new()) .pending_payable_dao(pending_payable_dao) .pending_payable_dao(PendingPayableDaoMock::new()) .pending_payable_dao(PendingPayableDaoMock::new()) diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 797fd9691..257b6f601 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -158,6 +158,7 @@ impl AccountantBuilder { let mut config = self.config.unwrap_or(make_bc_with_defaults()); let payable_dao_factory = self.payable_dao_factory.unwrap_or( PayableDaoFactoryMock::new() + .make_result(PayableDaoMock::new()) .make_result(PayableDaoMock::new()) .make_result(PayableDaoMock::new()), ); From d664e24a8b5dd35ff5d909e80dcefcf38899c444 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 20 Sep 2022 16:19:23 +0530 Subject: [PATCH 105/145] GH-611: fix the handler for the PendingPayable Scanner --- node/src/accountant/mod.rs | 52 +++++++++++++-------------------- node/src/accountant/scanners.rs | 1 + 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index aaebf8063..df344bcba 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -186,12 +186,12 @@ impl Handler for Accountant { fn handle(&mut self, msg: SentPayable, _ctx: &mut Self::Context) -> Self::Result { match self.scanners.payables.scan_finished(msg, &self.logger) { - Ok(message_opt) => { - if let Some(message) = message_opt { + Ok(node_to_ui_msg_opt) => { + if let Some(node_to_ui_msg) = node_to_ui_msg_opt { self.ui_message_sub .as_ref() .expect("UIGateway is not bound") - .try_send(message) + .try_send(node_to_ui_msg) .expect("UIGateway is dead"); } } @@ -349,35 +349,23 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ReportTransactionReceipts, ctx: &mut Self::Context) -> Self::Result { - todo!("migration of this function is in progress"); - // if let Some(response_skeleton) = &msg.response_skeleton_opt { - // self.ui_message_sub - // .as_ref() - // .expect("UIGateway not bound") - // .try_send(NodeToUiMessage { - // target: MessageTarget::ClientId(response_skeleton.client_id), - // body: UiScanResponse {}.tmb(response_skeleton.context_id), - // }) - // .expect("UIGateway is dead"); - // } - - // TODO: Make accountant to handle empty vector. Maybe log it as an error. - debug!( - self.logger, - "Processing receipts for {} transactions", - msg.fingerprints_with_receipts.len() - ); - let statuses = self.handle_pending_transaction_with_its_receipt(&msg); - self.process_transaction_by_status(statuses, ctx); - if let Some(response_skeleton) = &msg.response_skeleton_opt { - self.ui_message_sub - .as_ref() - .expect("UIGateway not bound") - .try_send(NodeToUiMessage { - target: MessageTarget::ClientId(response_skeleton.client_id), - body: UiScanResponse {}.tmb(response_skeleton.context_id), - }) - .expect("UIGateway is dead"); + match self + .scanners + .pending_payables + .scan_finished(msg, &self.logger) + { + Ok(node_to_ui_msg_opt) => { + if let Some(node_to_ui_msg) = node_to_ui_msg_opt { + self.ui_message_sub + .as_ref() + .expect("UIGateway is not bound") + .try_send(node_to_ui_msg) + .expect("UIGateway is dead"); + } + } + Err(e) => { + panic!("{}", e); + } } } } diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 115359bf2..fada26b8d 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -333,6 +333,7 @@ pub(in crate::accountant) mod scanners { message: ReportTransactionReceipts, logger: &Logger, ) -> Result, String> { + todo!("now we're testing from the Scanners"); // TODO: Make accountant to handle empty vector. Maybe log it as an error. debug!( logger, From b8c92e0cadb7677b3556017c1a0e97bf19dcc553 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 20 Sep 2022 16:27:29 +0530 Subject: [PATCH 106/145] GH-611: rename individual scanner in Scanners struct --- node/src/accountant/mod.rs | 47 ++++++++++++++++----------------- node/src/accountant/scanners.rs | 18 ++++++------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index df344bcba..8567e9792 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -185,7 +185,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: SentPayable, _ctx: &mut Self::Context) -> Self::Result { - match self.scanners.payables.scan_finished(msg, &self.logger) { + match self.scanners.payable.scan_finished(msg, &self.logger) { Ok(node_to_ui_msg_opt) => { if let Some(node_to_ui_msg) = node_to_ui_msg_opt { self.ui_message_sub @@ -351,7 +351,7 @@ impl Handler for Accountant { fn handle(&mut self, msg: ReportTransactionReceipts, ctx: &mut Self::Context) -> Self::Result { match self .scanners - .pending_payables + .pending_payable .scan_finished(msg, &self.logger) { Ok(node_to_ui_msg_opt) => { @@ -717,7 +717,7 @@ impl Accountant { } fn handle_scan_for_payable_request(&mut self, response_skeleton_opt: Option) { - match self.scanners.payables.begin_scan( + match self.scanners.payable.begin_scan( SystemTime::now(), response_skeleton_opt, &self.logger, @@ -756,7 +756,7 @@ impl Accountant { &mut self, response_skeleton_opt: Option, ) { - match self.scanners.pending_payables.begin_scan( + match self.scanners.pending_payable.begin_scan( SystemTime::now(), response_skeleton_opt, &self.logger, @@ -793,7 +793,7 @@ impl Accountant { &mut self, response_skeleton_opt: Option, ) { - match self.scanners.receivables.begin_scan( + match self.scanners.receivable.begin_scan( SystemTime::now(), response_skeleton_opt, &self.logger, @@ -1799,8 +1799,8 @@ mod tests { .payable_dao(payable_dao) // For Payable Scanner .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); - subject.scanners.pending_payables = Box::new(NullScanner::new()); - subject.scanners.receivables = Box::new(NullScanner::new()); + subject.scanners.pending_payable = Box::new(NullScanner::new()); + subject.scanners.receivable = Box::new(NullScanner::new()); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() @@ -1840,8 +1840,8 @@ mod tests { .receivable_dao(ReceivableDaoMock::new()) // For Accountant .receivable_dao(receivable_dao) // For Scanner .build(); - subject.scanners.pending_payables = Box::new(NullScanner::new()); - subject.scanners.payables = Box::new(NullScanner::new()); + subject.scanners.pending_payable = Box::new(NullScanner::new()); + subject.scanners.payable = Box::new(NullScanner::new()); let accountant_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&accountant_addr); let peer_actors = peer_actors_builder() @@ -2024,8 +2024,8 @@ mod tests { .banned_dao(BannedDaoMock::new()) .banned_dao(banned_dao) .build(); - subject.scanners.pending_payables = Box::new(NullScanner::new()); - subject.scanners.payables = Box::new(NullScanner::new()); + subject.scanners.pending_payable = Box::new(NullScanner::new()); + subject.scanners.payable = Box::new(NullScanner::new()); subject.notify_later.scan_for_receivable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_receivable_params_arc) @@ -2135,8 +2135,8 @@ mod tests { .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant .pending_payable_dao(pending_payable_dao) // For Scanner .build(); - subject.scanners.receivables = Box::new(NullScanner::new()); //skipping - subject.scanners.payables = Box::new(NullScanner::new()); //skipping + subject.scanners.receivable = Box::new(NullScanner::new()); //skipping + subject.scanners.payable = Box::new(NullScanner::new()); //skipping subject.notify_later.scan_for_pending_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_pending_payable_params_arc) @@ -2233,8 +2233,8 @@ mod tests { .payable_dao(payable_dao) // For Accountant .build(); subject.logger = Logger::new(test_name); - subject.scanners.pending_payables = Box::new(NullScanner::new()); //skipping - subject.scanners.receivables = Box::new(NullScanner::new()); //skipping + subject.scanners.pending_payable = Box::new(NullScanner::new()); //skipping + subject.scanners.receivable = Box::new(NullScanner::new()); //skipping subject.notify_later.scan_for_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_payables_params_arc) @@ -2384,11 +2384,10 @@ mod tests { .build(); subject.report_accounts_payable_sub_opt = Some(report_accounts_payable_sub); - let _result = - subject - .scanners - .payables - .begin_scan(SystemTime::now(), None, &subject.logger); + let _result = subject + .scanners + .payable + .begin_scan(SystemTime::now(), None, &subject.logger); System::current().stop_with_code(0); system.run(); @@ -2443,8 +2442,8 @@ mod tests { .payable_dao(payable_dao) // For Payable Scanner .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); - subject.scanners.pending_payables = Box::new(NullScanner::new()); - subject.scanners.receivables = Box::new(NullScanner::new()); + subject.scanners.pending_payable = Box::new(NullScanner::new()); + subject.scanners.receivable = Box::new(NullScanner::new()); let subject_addr = subject.start(); let accountant_subs = Accountant::make_subs_from(&subject_addr); send_bind_message!(accountant_subs, peer_actors); @@ -3283,7 +3282,7 @@ mod tests { let _result = subject .scanners - .payables + .payable .scan_finished(sent_payable, &Logger::new("Accountant")); let fingerprint_rowid_params = fingerprint_rowid_params_arc.lock().unwrap(); @@ -3659,7 +3658,7 @@ mod tests { .pending_payable_dao(accountant_pending_payable_dao) .pending_payable_dao(scanner_pending_payable_dao) .build(); - subject.scanners.receivables = Box::new(NullScanner::new()); + subject.scanners.receivable = Box::new(NullScanner::new()); let notify_later_half_mock = NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_scan_for_pending_payable_arc_cloned) .permit_to_send_out(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index fada26b8d..7c53c22cb 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -43,10 +43,10 @@ pub(in crate::accountant) mod scanners { type Error = ScannerError; pub struct Scanners { - pub payables: Box>, - pub pending_payables: + pub payable: Box>, + pub pending_payable: Box>, - pub receivables: Box>, + pub receivable: Box>, } impl Scanners { @@ -61,19 +61,19 @@ pub(in crate::accountant) mod scanners { financial_statistics: Rc>, ) -> Self { Scanners { - payables: Box::new(PayableScanner::new( + payable: Box::new(PayableScanner::new( payable_dao_factory.make(), pending_payable_dao_factory.make(), Rc::clone(&payment_thresholds), )), - pending_payables: Box::new(PendingPayableScanner::new( + pending_payable: Box::new(PendingPayableScanner::new( payable_dao_factory.make(), pending_payable_dao_factory.make(), Rc::clone(&payment_thresholds), when_pending_too_long_sec, financial_statistics, )), - receivables: Box::new(ReceivableScanner::new( + receivable: Box::new(ReceivableScanner::new( receivable_dao, banned_dao, Rc::clone(&payment_thresholds), @@ -832,17 +832,17 @@ mod tests { ); scanners - .payables + .payable .as_any() .downcast_ref::() .unwrap(); scanners - .pending_payables + .pending_payable .as_any() .downcast_ref::() .unwrap(); scanners - .receivables + .receivable .as_any() .downcast_ref::() .unwrap(); From 9f942b608487a9a8ff051f99b2dad7774efd9d8b Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 20 Sep 2022 16:46:38 +0530 Subject: [PATCH 107/145] GH-611: migrate test interpret_transaction_receipt_when_transaction_status_is_none_and_outside_waiting_interval() to scanners.rs --- node/src/accountant/mod.rs | 38 +-------------------- node/src/accountant/scanners.rs | 60 ++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 8567e9792..48d9039a5 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1065,7 +1065,7 @@ fn elapsed_in_ms(timestamp: SystemTime) -> u128 { } #[derive(Debug, PartialEq, Clone)] -enum PendingTransactionStatus { +pub enum PendingTransactionStatus { StillPending(PendingPayableId), //updates slightly the record, waits an interval and starts a new round Failure(PendingPayableId), @@ -3932,42 +3932,6 @@ mod tests { ); } - #[test] - fn interpret_transaction_receipt_when_transaction_status_is_none_and_outside_waiting_interval() - { - init_test_logging(); - let hash = H256::from_uint(&U256::from(567)); - let rowid = 466; - let tx_receipt = TransactionReceipt::default(); //status defaulted to None - let when_sent = - SystemTime::now().sub(Duration::from_secs(DEFAULT_PENDING_TOO_LONG_SEC + 5)); //old transaction - let subject = AccountantBuilder::default().build(); - let fingerprint = PendingPayableFingerprint { - rowid_opt: Some(rowid), - timestamp: when_sent, - hash, - attempt_opt: Some(10), - amount: 123, - process_error: None, - }; - - let result = subject.interpret_transaction_receipt( - &tx_receipt, - &fingerprint, - &Logger::new("receipt_check_logger"), - ); - - assert_eq!( - result, - PendingTransactionStatus::Failure(PendingPayableId { hash, rowid }) - ); - TestLogHandler::new().exists_log_containing( - "ERROR: receipt_check_logger: Pending transaction '0x0000…0237' has exceeded the maximum \ - pending time (21600sec) and the confirmation process is going to be aborted now at the final attempt 10; manual resolution is required from the user to \ - complete the transaction", - ); - } - #[test] #[should_panic( expected = "tx receipt for pending '0x0000…007b' - tx status: code other than 0 or 1 shouldn't be possible, but was 456" diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 7c53c22cb..814366d8f 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -407,7 +407,7 @@ pub(in crate::accountant) mod scanners { .collect() } - fn interpret_transaction_receipt( + pub fn interpret_transaction_receipt( &self, receipt: &TransactionReceipt, fingerprint: &PendingPayableFingerprint, @@ -792,9 +792,13 @@ mod tests { make_payables, make_receivable_account, BannedDaoMock, PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, ReceivableDaoMock, }; - use crate::accountant::{RequestTransactionReceipts, SentPayable}; + use crate::accountant::{ + PendingPayableId, PendingTransactionStatus, RequestTransactionReceipts, SentPayable, + DEFAULT_PENDING_TOO_LONG_SEC, + }; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use std::cell::RefCell; + use std::ops::Sub; use crate::accountant::payable_dao::{Payable, PayableDaoError, PayableDaoFactory}; use crate::accountant::pending_payable_dao::PendingPayableDaoError; @@ -808,8 +812,20 @@ mod tests { use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; use std::rc::Rc; use std::sync::{Arc, Mutex, MutexGuard}; - use std::time::SystemTime; - use web3::types::{H256, U256}; + use std::time::{Duration, SystemTime}; + use web3::types::{TransactionReceipt, H256, U256}; + + impl Default for PendingPayableScanner { + fn default() -> Self { + PendingPayableScanner::new( + Box::new(PayableDaoMock::new()), + Box::new(PendingPayableDaoMock::new()), + Rc::new(make_payment_thresholds_with_defaults()), + DEFAULT_PENDING_TOO_LONG_SEC, + Rc::new(RefCell::new(FinancialStatistics::default())), + ) + } + } #[test] fn scanners_struct_can_be_constructed_with_the_respective_scanners() { @@ -1083,6 +1099,42 @@ mod tests { ]) } + #[test] + fn interpret_transaction_receipt_when_transaction_status_is_none_and_outside_waiting_interval() + { + init_test_logging(); + let hash = H256::from_uint(&U256::from(567)); + let rowid = 466; + let tx_receipt = TransactionReceipt::default(); //status defaulted to None + let when_sent = + SystemTime::now().sub(Duration::from_secs(DEFAULT_PENDING_TOO_LONG_SEC + 5)); //old transaction + let subject = PendingPayableScanner::default(); + let fingerprint = PendingPayableFingerprint { + rowid_opt: Some(rowid), + timestamp: when_sent, + hash, + attempt_opt: Some(10), + amount: 123, + process_error: None, + }; + + let result = subject.interpret_transaction_receipt( + &tx_receipt, + &fingerprint, + &Logger::new("receipt_check_logger"), + ); + + assert_eq!( + result, + PendingTransactionStatus::Failure(PendingPayableId { hash, rowid }) + ); + TestLogHandler::new().exists_log_containing( + "ERROR: receipt_check_logger: Pending transaction '0x0000…0237' has exceeded the maximum \ + pending time (21600sec) and the confirmation process is going to be aborted now at the final attempt 10; manual resolution is required from the user to \ + complete the transaction", + ); + } + #[test] fn receivable_scanner_can_initiate_a_scan() { init_test_logging(); From 839d1fbfc16e5938499d00bdec41153ae099c151 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 20 Sep 2022 16:50:46 +0530 Subject: [PATCH 108/145] GH-611: migrate test interpret_transaction_receipt_when_transaction_status_is_none_and_within_waiting_interval --- node/src/accountant/mod.rs | 33 --------------------------------- node/src/accountant/scanners.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 48d9039a5..31322a925 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -3899,39 +3899,6 @@ mod tests { transaction '0x0000…11d7' announced as a failure, interpreting attempt 5 after 1500\\d\\dms from the sending"); } - #[test] - fn interpret_transaction_receipt_when_transaction_status_is_none_and_within_waiting_interval() { - init_test_logging(); - let hash = H256::from_uint(&U256::from(567)); - let rowid = 466; - let tx_receipt = TransactionReceipt::default(); //status defaulted to None - let when_sent = SystemTime::now().sub(Duration::from_millis(100)); - let subject = AccountantBuilder::default().build(); - let fingerprint = PendingPayableFingerprint { - rowid_opt: Some(rowid), - timestamp: when_sent, - hash, - attempt_opt: Some(1), - amount: 123, - process_error: None, - }; - - let result = subject.interpret_transaction_receipt( - &tx_receipt, - &fingerprint, - &Logger::new("none_within_waiting"), - ); - - assert_eq!( - result, - PendingTransactionStatus::StillPending(PendingPayableId { hash, rowid }) - ); - TestLogHandler::new().exists_log_containing( - "INFO: none_within_waiting: Pending \ - transaction '0x0000…0237' couldn't be confirmed at attempt 1 at ", - ); - } - #[test] #[should_panic( expected = "tx receipt for pending '0x0000…007b' - tx status: code other than 0 or 1 shouldn't be possible, but was 456" diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 814366d8f..7944ddff6 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -1135,6 +1135,39 @@ mod tests { ); } + #[test] + fn interpret_transaction_receipt_when_transaction_status_is_none_and_within_waiting_interval() { + init_test_logging(); + let hash = H256::from_uint(&U256::from(567)); + let rowid = 466; + let tx_receipt = TransactionReceipt::default(); //status defaulted to None + let when_sent = SystemTime::now().sub(Duration::from_millis(100)); + let subject = PendingPayableScanner::default(); + let fingerprint = PendingPayableFingerprint { + rowid_opt: Some(rowid), + timestamp: when_sent, + hash, + attempt_opt: Some(1), + amount: 123, + process_error: None, + }; + + let result = subject.interpret_transaction_receipt( + &tx_receipt, + &fingerprint, + &Logger::new("none_within_waiting"), + ); + + assert_eq!( + result, + PendingTransactionStatus::StillPending(PendingPayableId { hash, rowid }) + ); + TestLogHandler::new().exists_log_containing( + "INFO: none_within_waiting: Pending \ + transaction '0x0000…0237' couldn't be confirmed at attempt 1 at ", + ); + } + #[test] fn receivable_scanner_can_initiate_a_scan() { init_test_logging(); From b9f050c4dfed5e29d9444a1b3d6e458973598b6b Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Tue, 20 Sep 2022 17:02:01 +0530 Subject: [PATCH 109/145] GH-611: migrate interpret_transaction_receipt_panics_at_undefined_status_code() to scanners.rs --- node/src/accountant/mod.rs | 19 +------------------ node/src/accountant/scanners.rs | 26 ++++++++++++++++++++++---- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 31322a925..7d423b625 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -923,6 +923,7 @@ impl Accountant { fingerprint: &PendingPayableFingerprint, logger: &Logger, ) -> PendingTransactionStatus { + todo!("migration to scanners.rs in progress"); fn handle_none_status( fingerprint: &PendingPayableFingerprint, max_pending_interval: u64, @@ -3899,24 +3900,6 @@ mod tests { transaction '0x0000…11d7' announced as a failure, interpreting attempt 5 after 1500\\d\\dms from the sending"); } - #[test] - #[should_panic( - expected = "tx receipt for pending '0x0000…007b' - tx status: code other than 0 or 1 shouldn't be possible, but was 456" - )] - fn interpret_transaction_receipt_panics_at_undefined_status_code() { - let mut tx_receipt = TransactionReceipt::default(); - tx_receipt.status = Some(U64::from(456)); - let mut fingerprint = make_pending_payable_fingerprint(); - fingerprint.hash = H256::from_uint(&U256::from(123)); - let subject = AccountantBuilder::default().build(); - - let _ = subject.interpret_transaction_receipt( - &tx_receipt, - &fingerprint, - &Logger::new("receipt_check_logger"), - ); - } - #[test] fn accountant_handles_pending_payable_fingerprint() { init_test_logging(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 7944ddff6..b7033b3de 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -333,7 +333,6 @@ pub(in crate::accountant) mod scanners { message: ReportTransactionReceipts, logger: &Logger, ) -> Result, String> { - todo!("now we're testing from the Scanners"); // TODO: Make accountant to handle empty vector. Maybe log it as an error. debug!( logger, @@ -789,8 +788,9 @@ mod tests { PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, ScannerError, Scanners, }; use crate::accountant::test_utils::{ - make_payables, make_receivable_account, BannedDaoMock, PayableDaoFactoryMock, - PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, ReceivableDaoMock, + make_payables, make_pending_payable_fingerprint, make_receivable_account, BannedDaoMock, + PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, + ReceivableDaoMock, }; use crate::accountant::{ PendingPayableId, PendingTransactionStatus, RequestTransactionReceipts, SentPayable, @@ -807,7 +807,7 @@ mod tests { use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; - use ethereum_types::BigEndianHash; + use ethereum_types::{BigEndianHash, U64}; use masq_lib::logger::Logger; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; use std::rc::Rc; @@ -1168,6 +1168,24 @@ mod tests { ); } + #[test] + #[should_panic( + expected = "tx receipt for pending '0x0000…007b' - tx status: code other than 0 or 1 shouldn't be possible, but was 456" + )] + fn interpret_transaction_receipt_panics_at_undefined_status_code() { + let mut tx_receipt = TransactionReceipt::default(); + tx_receipt.status = Some(U64::from(456)); + let mut fingerprint = make_pending_payable_fingerprint(); + fingerprint.hash = H256::from_uint(&U256::from(123)); + let subject = PendingPayableScanner::default(); + + let _ = subject.interpret_transaction_receipt( + &tx_receipt, + &fingerprint, + &Logger::new("receipt_check_logger"), + ); + } + #[test] fn receivable_scanner_can_initiate_a_scan() { init_test_logging(); From 3436aecb9b10a4a39e6d84a13ab26b5ea8b14b2a Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 10:18:46 +0530 Subject: [PATCH 110/145] GH-611: rename the panic message --- node/src/accountant/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 7d423b625..243d29b1a 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -195,9 +195,7 @@ impl Handler for Accountant { .expect("UIGateway is dead"); } } - Err(e) => { - panic!("{}", e); - } + Err(e) => panic!("Payable Scanner: {}", e), } } } @@ -363,9 +361,7 @@ impl Handler for Accountant { .expect("UIGateway is dead"); } } - Err(e) => { - panic!("{}", e); - } + Err(e) => panic!("PendingPayable Scanner: {}", e), } } } From 6bb2dfaa0c97f8503d60625b9b737eafd94387ab Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 10:20:56 +0530 Subject: [PATCH 111/145] GH-611: migrate test interpret_transaction_receipt_when_transaction_status_is_a_failure() to scanners.rs --- node/src/accountant/mod.rs | 33 --------------------------------- node/src/accountant/scanners.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 243d29b1a..bfdeaa62d 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -3863,39 +3863,6 @@ mod tests { ); } - #[test] - fn interpret_transaction_receipt_when_transaction_status_is_a_failure() { - init_test_logging(); - let subject = AccountantBuilder::default().build(); - let mut tx_receipt = TransactionReceipt::default(); - tx_receipt.status = Some(U64::from(0)); //failure - let hash = H256::from_uint(&U256::from(4567)); - let fingerprint = PendingPayableFingerprint { - rowid_opt: Some(777777), - timestamp: SystemTime::now().sub(Duration::from_millis(150000)), - hash, - attempt_opt: Some(5), - amount: 2222, - process_error: None, - }; - - let result = subject.interpret_transaction_receipt( - &tx_receipt, - &fingerprint, - &Logger::new("receipt_check_logger"), - ); - - assert_eq!( - result, - PendingTransactionStatus::Failure(PendingPayableId { - hash, - rowid: 777777, - }) - ); - TestLogHandler::new().exists_log_matching("ERROR: receipt_check_logger: Pending \ - transaction '0x0000…11d7' announced as a failure, interpreting attempt 5 after 1500\\d\\dms from the sending"); - } - #[test] fn accountant_handles_pending_payable_fingerprint() { init_test_logging(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index b7033b3de..b58197bc0 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -1186,6 +1186,39 @@ mod tests { ); } + #[test] + fn interpret_transaction_receipt_when_transaction_status_is_a_failure() { + init_test_logging(); + let subject = PendingPayableScanner::default(); + let mut tx_receipt = TransactionReceipt::default(); + tx_receipt.status = Some(U64::from(0)); //failure + let hash = H256::from_uint(&U256::from(4567)); + let fingerprint = PendingPayableFingerprint { + rowid_opt: Some(777777), + timestamp: SystemTime::now().sub(Duration::from_millis(150000)), + hash, + attempt_opt: Some(5), + amount: 2222, + process_error: None, + }; + + let result = subject.interpret_transaction_receipt( + &tx_receipt, + &fingerprint, + &Logger::new("receipt_check_logger"), + ); + + assert_eq!( + result, + PendingTransactionStatus::Failure(PendingPayableId { + hash, + rowid: 777777, + }) + ); + TestLogHandler::new().exists_log_matching("ERROR: receipt_check_logger: Pending \ + transaction '0x0000…11d7' announced as a failure, interpreting attempt 5 after 1500\\d\\dms from the sending"); + } + #[test] fn receivable_scanner_can_initiate_a_scan() { init_test_logging(); From 9d9f450a717fcd86b0def9eaedd2ceeb93a75679 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 10:34:37 +0530 Subject: [PATCH 112/145] GH-611: migrate handle_pending_tx_handles_none_returned_for_transaction_receipt() to scanners.rs --- node/src/accountant/mod.rs | 33 +------------------------- node/src/accountant/scanners.rs | 42 +++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index bfdeaa62d..2be572a51 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -889,6 +889,7 @@ impl Accountant { &self, msg: &ReportTransactionReceipts, ) -> Vec { + todo!("migration to scanners.rs in progress"); fn handle_none_receipt( payable: &PendingPayableFingerprint, logger: &Logger, @@ -3773,38 +3774,6 @@ mod tests { log_handler.exists_log_containing("INFO: Accountant: Transaction 0x0000000000000000000000000000000000000000000000000000000000000237 has gone through the whole confirmation process succeeding"); } - #[test] - fn handle_pending_tx_handles_none_returned_for_transaction_receipt() { - init_test_logging(); - let subject = AccountantBuilder::default().build(); - let tx_receipt_opt = None; - let rowid = 455; - let hash = H256::from_uint(&U256::from(2323)); - let fingerprint = PendingPayableFingerprint { - rowid_opt: Some(rowid), - timestamp: SystemTime::now().sub(Duration::from_millis(10000)), - hash, - attempt_opt: Some(3), - amount: 111, - process_error: None, - }; - let msg = ReportTransactionReceipts { - fingerprints_with_receipts: vec![(tx_receipt_opt, fingerprint.clone())], - response_skeleton_opt: None, - }; - - let result = subject.handle_pending_transaction_with_its_receipt(&msg); - - assert_eq!( - result, - vec![PendingTransactionStatus::StillPending(PendingPayableId { - hash, - rowid, - })] - ); - TestLogHandler::new().exists_log_matching("DEBUG: Accountant: Interpreting a receipt for transaction '0x0000…0913' but none was given; attempt 3, 100\\d\\dms since sending"); - } - #[test] fn accountant_receives_reported_transaction_receipts_and_processes_them_all() { let notify_handle_params_arc = Arc::new(Mutex::new(vec![])); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index b58197bc0..6afcb5704 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -377,7 +377,7 @@ pub(in crate::accountant) mod scanners { } } - fn handle_pending_transaction_with_its_receipt( + pub(crate) fn handle_pending_transaction_with_its_receipt( &self, msg: &ReportTransactionReceipts, logger: &Logger, @@ -387,7 +387,7 @@ pub(in crate::accountant) mod scanners { logger: &Logger, ) -> PendingTransactionStatus { debug!(logger, - "DEBUG: Accountant: Interpreting a receipt for transaction '{}' but none was given; attempt {}, {}ms since sending", + "Interpreting a receipt for transaction '{}' but none was given; attempt {}, {}ms since sending", payable.hash, payable.attempt_opt.expectv("initialized attempt"), elapsed_in_ms(payable.timestamp) ); PendingTransactionStatus::StillPending(PendingPayableId { @@ -793,8 +793,8 @@ mod tests { ReceivableDaoMock, }; use crate::accountant::{ - PendingPayableId, PendingTransactionStatus, RequestTransactionReceipts, SentPayable, - DEFAULT_PENDING_TOO_LONG_SEC, + PendingPayableId, PendingTransactionStatus, ReportTransactionReceipts, + RequestTransactionReceipts, SentPayable, DEFAULT_PENDING_TOO_LONG_SEC, }; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use std::cell::RefCell; @@ -1219,6 +1219,40 @@ mod tests { transaction '0x0000…11d7' announced as a failure, interpreting attempt 5 after 1500\\d\\dms from the sending"); } + #[test] + fn handle_pending_tx_handles_none_returned_for_transaction_receipt() { + init_test_logging(); + let subject = PendingPayableScanner::default(); + let tx_receipt_opt = None; + let rowid = 455; + let hash = H256::from_uint(&U256::from(2323)); + let fingerprint = PendingPayableFingerprint { + rowid_opt: Some(rowid), + timestamp: SystemTime::now().sub(Duration::from_millis(10000)), + hash, + attempt_opt: Some(3), + amount: 111, + process_error: None, + }; + let msg = ReportTransactionReceipts { + fingerprints_with_receipts: vec![(tx_receipt_opt, fingerprint.clone())], + response_skeleton_opt: None, + }; + + let result = subject + .handle_pending_transaction_with_its_receipt(&msg, &Logger::new("Handle Pending Tx")); + + assert_eq!( + result, + vec![PendingTransactionStatus::StillPending(PendingPayableId { + hash, + rowid, + })] + ); + TestLogHandler::new() + .exists_log_matching("DEBUG: Handle Pending Tx: Interpreting a receipt for transaction '0x0000…0913' but none was given; attempt 3, 100\\d\\dms since sending"); + } + #[test] fn receivable_scanner_can_initiate_a_scan() { init_test_logging(); From 3d14e076282b9bf54b75b4ceaa2030cd5b102369 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 11:38:39 +0530 Subject: [PATCH 113/145] GH-611: migrate test for report transaction receipts message into scanners.rs --- node/src/accountant/mod.rs | 58 -------------------------- node/src/accountant/scanners.rs | 72 +++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 58 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 2be572a51..5121585ce 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -3774,64 +3774,6 @@ mod tests { log_handler.exists_log_containing("INFO: Accountant: Transaction 0x0000000000000000000000000000000000000000000000000000000000000237 has gone through the whole confirmation process succeeding"); } - #[test] - fn accountant_receives_reported_transaction_receipts_and_processes_them_all() { - let notify_handle_params_arc = Arc::new(Mutex::new(vec![])); - let mut subject = AccountantBuilder::default().build(); - subject.tools.notify_confirm_transaction = - Box::new(NotifyHandleMock::default().notify_params(¬ify_handle_params_arc)); - let subject_addr = subject.start(); - let transaction_hash_1 = H256::from_uint(&U256::from(4545)); - let mut transaction_receipt_1 = TransactionReceipt::default(); - transaction_receipt_1.transaction_hash = transaction_hash_1; - transaction_receipt_1.status = Some(U64::from(1)); //success - let fingerprint_1 = PendingPayableFingerprint { - rowid_opt: Some(5), - timestamp: from_time_t(200_000_000), - hash: transaction_hash_1, - attempt_opt: Some(2), - amount: 444, - process_error: None, - }; - let transaction_hash_2 = H256::from_uint(&U256::from(3333333)); - let mut transaction_receipt_2 = TransactionReceipt::default(); - transaction_receipt_2.transaction_hash = transaction_hash_2; - transaction_receipt_2.status = Some(U64::from(1)); //success - let fingerprint_2 = PendingPayableFingerprint { - rowid_opt: Some(10), - timestamp: from_time_t(199_780_000), - hash: Default::default(), - attempt_opt: Some(15), - amount: 1212, - process_error: None, - }; - let msg = ReportTransactionReceipts { - fingerprints_with_receipts: vec![ - (Some(transaction_receipt_1), fingerprint_1.clone()), - (Some(transaction_receipt_2), fingerprint_2.clone()), - ], - response_skeleton_opt: None, - }; - - let _ = subject_addr.try_send(msg).unwrap(); - - let system = System::new("processing reported receipts"); - System::current().stop(); - system.run(); - let notify_handle_params = notify_handle_params_arc.lock().unwrap(); - assert_eq!( - *notify_handle_params, - vec![ - ConfirmPendingTransaction { - pending_payable_fingerprint: fingerprint_1 - }, - ConfirmPendingTransaction { - pending_payable_fingerprint: fingerprint_2 - }, - ] - ); - } - #[test] fn accountant_handles_pending_payable_fingerprint() { init_test_logging(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 6afcb5704..69058e3af 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -803,6 +803,7 @@ mod tests { use crate::accountant::payable_dao::{Payable, PayableDaoError, PayableDaoFactory}; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::blockchain::blockchain_interface::BlockchainError; + use crate::database::dao_utils::from_time_t; use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::test_utils::make_wallet; @@ -1253,6 +1254,77 @@ mod tests { .exists_log_matching("DEBUG: Handle Pending Tx: Interpreting a receipt for transaction '0x0000…0913' but none was given; attempt 3, 100\\d\\dms since sending"); } + #[test] + fn pending_payable_scanner_handles_report_transaction_receipts_message() { + init_test_logging(); + let test_name = "accountant_receives_reported_transaction_receipts_and_processes_them_all"; + let transaction_confirmed_params_arc = Arc::new(Mutex::new(vec![])); + let payable_dao = PayableDaoMock::new() + .transaction_confirmed_params(&transaction_confirmed_params_arc) + .transaction_confirmed_result(Ok(())) + .transaction_confirmed_result(Ok(())); + let pending_payable_dao = PendingPayableDaoMock::new() + .delete_fingerprint_result(Ok(())) + .delete_fingerprint_result(Ok(())); + let mut subject = PendingPayableScanner::new( + Box::new(payable_dao), + Box::new(pending_payable_dao), + Rc::new(make_payment_thresholds_with_defaults()), + DEFAULT_PENDING_TOO_LONG_SEC, + Rc::new(RefCell::new(FinancialStatistics::default())), + ); + let transaction_hash_1 = H256::from_uint(&U256::from(4545)); + let mut transaction_receipt_1 = TransactionReceipt::default(); + transaction_receipt_1.transaction_hash = transaction_hash_1; + transaction_receipt_1.status = Some(U64::from(1)); //success + let fingerprint_1 = PendingPayableFingerprint { + rowid_opt: Some(5), + timestamp: from_time_t(200_000_000), + hash: transaction_hash_1, + attempt_opt: Some(2), + amount: 444, + process_error: None, + }; + let transaction_hash_2 = H256::from_uint(&U256::from(1234)); + let mut transaction_receipt_2 = TransactionReceipt::default(); + transaction_receipt_2.transaction_hash = transaction_hash_2; + transaction_receipt_2.status = Some(U64::from(1)); //success + let fingerprint_2 = PendingPayableFingerprint { + rowid_opt: Some(10), + timestamp: from_time_t(199_780_000), + hash: transaction_hash_2, + attempt_opt: Some(15), + amount: 1212, + process_error: None, + }; + let msg = ReportTransactionReceipts { + fingerprints_with_receipts: vec![ + (Some(transaction_receipt_1), fingerprint_1.clone()), + (Some(transaction_receipt_2), fingerprint_2.clone()), + ], + response_skeleton_opt: None, + }; + + let result = subject.scan_finished(msg, &Logger::new(test_name)); + + let transaction_confirmed_params = transaction_confirmed_params_arc.lock().unwrap(); + assert_eq!(result, Ok(None)); + assert_eq!( + *transaction_confirmed_params, + vec![fingerprint_1, fingerprint_2] + ); + TestLogHandler::new().assert_logs_match_in_order(vec![ + &format!( + "INFO: {}: Transaction {:?} has gone through the whole confirmation process succeeding", + test_name, transaction_hash_1 + ), + &format!( + "INFO: {}: Transaction {:?} has gone through the whole confirmation process succeeding", + test_name, transaction_hash_2 + ), + ]); + } + #[test] fn receivable_scanner_can_initiate_a_scan() { init_test_logging(); From 47514ebeb8938f9c8d1e72ee51b949816a1f6fad Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 11:46:33 +0530 Subject: [PATCH 114/145] GH-611: remove unnecessary code from accountant.rs --- node/src/accountant/mod.rs | 140 +------------------------------- node/src/accountant/scanners.rs | 3 +- 2 files changed, 3 insertions(+), 140 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 5121585ce..179b31ada 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -9,7 +9,6 @@ pub mod tools; pub mod test_utils; use masq_lib::constants::SCAN_ERROR; -use std::borrow::{Borrow, BorrowMut}; use std::cell::RefCell; use masq_lib::messages::{ScanType, UiScanRequest, UiScanResponse}; @@ -346,7 +345,7 @@ pub struct ReportTransactionReceipts { impl Handler for Accountant { type Result = (); - fn handle(&mut self, msg: ReportTransactionReceipts, ctx: &mut Self::Context) -> Self::Result { + fn handle(&mut self, msg: ReportTransactionReceipts, _ctx: &mut Self::Context) -> Self::Result { match self .scanners .pending_payable @@ -885,95 +884,6 @@ impl Accountant { } } - fn handle_pending_transaction_with_its_receipt( - &self, - msg: &ReportTransactionReceipts, - ) -> Vec { - todo!("migration to scanners.rs in progress"); - fn handle_none_receipt( - payable: &PendingPayableFingerprint, - logger: &Logger, - ) -> PendingTransactionStatus { - debug!(logger, - "DEBUG: Accountant: Interpreting a receipt for transaction '{}' but none was given; attempt {}, {}ms since sending", - payable.hash, payable.attempt_opt.expectv("initialized attempt"),elapsed_in_ms(payable.timestamp) - ); - PendingTransactionStatus::StillPending(PendingPayableId { - hash: payable.hash, - rowid: payable.rowid_opt.expectv("initialized rowid"), - }) - } - msg.fingerprints_with_receipts - .iter() - .map(|(receipt_opt, fingerprint)| match receipt_opt { - Some(receipt) => { - self.interpret_transaction_receipt(receipt, fingerprint, &self.logger) - } - None => handle_none_receipt(fingerprint, &self.logger), - }) - .collect() - } - - fn interpret_transaction_receipt( - &self, - receipt: &TransactionReceipt, - fingerprint: &PendingPayableFingerprint, - logger: &Logger, - ) -> PendingTransactionStatus { - todo!("migration to scanners.rs in progress"); - fn handle_none_status( - fingerprint: &PendingPayableFingerprint, - max_pending_interval: u64, - logger: &Logger, - ) -> PendingTransactionStatus { - info!(logger,"Pending transaction '{}' couldn't be confirmed at attempt {} at {}ms after its sending",fingerprint.hash, fingerprint.attempt_opt.expectv("initialized attempt"), elapsed_in_ms(fingerprint.timestamp)); - let elapsed = fingerprint - .timestamp - .elapsed() - .expect("we should be older now"); - let transaction_id = PendingPayableId { - hash: fingerprint.hash, - rowid: fingerprint.rowid_opt.expectv("initialized rowid"), - }; - if max_pending_interval <= elapsed.as_secs() { - error!(logger,"Pending transaction '{}' has exceeded the maximum pending time ({}sec) and the confirmation process is going to be aborted now at the final attempt {}; \ - manual resolution is required from the user to complete the transaction.", fingerprint.hash, max_pending_interval, fingerprint.attempt_opt.expectv("initialized attempt")); - PendingTransactionStatus::Failure(transaction_id) - } else { - PendingTransactionStatus::StillPending(transaction_id) - } - } - fn handle_status_with_success( - fingerprint: &PendingPayableFingerprint, - logger: &Logger, - ) -> PendingTransactionStatus { - info!( - logger, - "Transaction '{}' has been added to the blockchain; detected locally at attempt {} at {}ms after its sending", - fingerprint.hash, - fingerprint.attempt_opt.expectv("initialized attempt"), - elapsed_in_ms(fingerprint.timestamp) - ); - PendingTransactionStatus::Confirmed(fingerprint.clone()) - } - fn handle_status_with_failure( - fingerprint: &PendingPayableFingerprint, - logger: &Logger, - ) -> PendingTransactionStatus { - error!(logger,"Pending transaction '{}' announced as a failure, interpreting attempt {} after {}ms from the sending",fingerprint.hash,fingerprint.attempt_opt.expectv("initialized attempt"),elapsed_in_ms(fingerprint.timestamp)); - PendingTransactionStatus::Failure(fingerprint.into()) - } - match receipt.status { - None => todo!("code migration to scanners.rs in progress"), - Some(status_code) => - match status_code.as_u64() { - 0 => handle_status_with_failure(fingerprint, logger), - 1 => handle_status_with_success(fingerprint, logger), - other => unreachable!("tx receipt for pending '{}' - tx status: code other than 0 or 1 shouldn't be possible, but was {}", fingerprint.hash, other) - } - } - } - fn update_payable_fingerprint(&self, pending_payable_id: PendingPayableId) { match self .pending_payable_dao @@ -991,45 +901,6 @@ impl Accountant { } } - fn process_transaction_by_status( - &self, - statuses: Vec, - ctx: &mut Context, - ) { - statuses.into_iter().for_each(|status| { - if let PendingTransactionStatus::StillPending(transaction_id) = status { - self.update_payable_fingerprint(transaction_id) - } else if let PendingTransactionStatus::Failure(transaction_id) = status { - self.order_cancel_failed_transaction(transaction_id, ctx) - } else if let PendingTransactionStatus::Confirmed(fingerprint) = status { - self.order_confirm_transaction(fingerprint, ctx) - } - }); - } - - fn order_cancel_failed_transaction( - &self, - transaction_id: PendingPayableId, - ctx: &mut Context, - ) { - self.tools - .notify_cancel_failed_transaction - .notify(CancelFailedPendingTransaction { id: transaction_id }, ctx) - } - - fn order_confirm_transaction( - &self, - pending_payable_fingerprint: PendingPayableFingerprint, - ctx: &mut Context, - ) { - self.tools.notify_confirm_transaction.notify( - ConfirmPendingTransaction { - pending_payable_fingerprint, - }, - ctx, - ); - } - fn handle_new_pending_payable_fingerprint(&self, msg: PendingPayableFingerprint) { match self .pending_payable_dao @@ -1055,13 +926,6 @@ pub fn unsigned_to_signed(unsigned: u64) -> Result { i64::try_from(unsigned).map_err(|_| unsigned) } -fn elapsed_in_ms(timestamp: SystemTime) -> u128 { - timestamp - .elapsed() - .expect("time calculation for elapsed failed") - .as_millis() -} - #[derive(Debug, PartialEq, Clone)] pub enum PendingTransactionStatus { StillPending(PendingPayableId), @@ -3941,7 +3805,7 @@ mod tests { let payable_dao = PayableDaoMock::new().total_result(23456789); let receivable_dao = ReceivableDaoMock::new().total_result(98765432); let system = System::new("test"); - let mut subject = AccountantBuilder::default() + let subject = AccountantBuilder::default() .bootstrapper_config(make_bc_with_defaults()) .payable_dao(payable_dao) // For Accountant .payable_dao(PayableDaoMock::new()) // For Payable Scanner diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 69058e3af..41e1358fb 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -27,7 +27,6 @@ pub(in crate::accountant) mod scanners { use masq_lib::ui_gateway::{MessageTarget, NodeToUiMessage}; use masq_lib::utils::ExpectValue; use std::any::Any; - use std::borrow::{Borrow, BorrowMut}; use std::cell::RefCell; use std::rc::Rc; use std::time::SystemTime; @@ -800,7 +799,7 @@ mod tests { use std::cell::RefCell; use std::ops::Sub; - use crate::accountant::payable_dao::{Payable, PayableDaoError, PayableDaoFactory}; + use crate::accountant::payable_dao::{Payable, PayableDaoError}; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::blockchain::blockchain_interface::BlockchainError; use crate::database::dao_utils::from_time_t; From 0c0432153667691d55a3468a85d49be0104c2a9e Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 12:00:49 +0530 Subject: [PATCH 115/145] GH-611: migrate some functions for PendingPayable Scanner to tools.rs --- node/src/accountant/scanners.rs | 74 ++++++++------------------------- node/src/accountant/tools.rs | 72 ++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 57 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 41e1358fb..a0c9bf2c9 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -7,7 +7,9 @@ pub(in crate::accountant) mod scanners { use crate::accountant::tools::payable_scanner_tools::{ investigate_debt_extremes, qualified_payables_and_summary, separate_early_errors, }; - use crate::accountant::tools::pending_payable_scanner_tools::elapsed_in_ms; + use crate::accountant::tools::pending_payable_scanner_tools::{ + elapsed_in_ms, handle_none_status, handle_status_with_failure, handle_status_with_success, + }; use crate::accountant::tools::receivable_scanner_tools::balance_and_age; use crate::accountant::{ Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, @@ -381,26 +383,26 @@ pub(in crate::accountant) mod scanners { msg: &ReportTransactionReceipts, logger: &Logger, ) -> Vec { - fn handle_none_receipt( - payable: &PendingPayableFingerprint, - logger: &Logger, - ) -> PendingTransactionStatus { - debug!(logger, - "Interpreting a receipt for transaction '{}' but none was given; attempt {}, {}ms since sending", - payable.hash, payable.attempt_opt.expectv("initialized attempt"), elapsed_in_ms(payable.timestamp) - ); - PendingTransactionStatus::StillPending(PendingPayableId { - hash: payable.hash, - rowid: payable.rowid_opt.expectv("initialized rowid"), - }) - } msg.fingerprints_with_receipts .iter() .map(|(receipt_opt, fingerprint)| match receipt_opt { Some(receipt) => { self.interpret_transaction_receipt(receipt, fingerprint, logger) } - None => handle_none_receipt(fingerprint, logger), + None => { + debug!( + logger, + "Interpreting a receipt for transaction '{}' but none was given; \ + attempt {}, {}ms since sending", + fingerprint.hash, + fingerprint.attempt_opt.expectv("initialized attempt"), + elapsed_in_ms(fingerprint.timestamp) + ); + PendingTransactionStatus::StillPending(PendingPayableId { + hash: fingerprint.hash, + rowid: fingerprint.rowid_opt.expectv("initialized rowid"), + }) + } }) .collect() } @@ -411,48 +413,6 @@ pub(in crate::accountant) mod scanners { fingerprint: &PendingPayableFingerprint, logger: &Logger, ) -> PendingTransactionStatus { - fn handle_none_status( - fingerprint: &PendingPayableFingerprint, - max_pending_interval: u64, - logger: &Logger, - ) -> PendingTransactionStatus { - info!(logger,"Pending transaction '{}' couldn't be confirmed at attempt {} at {}ms after its sending",fingerprint.hash, fingerprint.attempt_opt.expectv("initialized attempt"), elapsed_in_ms(fingerprint.timestamp)); - let elapsed = fingerprint - .timestamp - .elapsed() - .expect("we should be older now"); - let transaction_id = PendingPayableId { - hash: fingerprint.hash, - rowid: fingerprint.rowid_opt.expectv("initialized rowid"), - }; - if max_pending_interval <= elapsed.as_secs() { - error!(logger,"Pending transaction '{}' has exceeded the maximum pending time ({}sec) and the confirmation process is going to be aborted now at the final attempt {}; \ - manual resolution is required from the user to complete the transaction.", fingerprint.hash, max_pending_interval, fingerprint.attempt_opt.expectv("initialized attempt")); - PendingTransactionStatus::Failure(transaction_id) - } else { - PendingTransactionStatus::StillPending(transaction_id) - } - } - fn handle_status_with_success( - fingerprint: &PendingPayableFingerprint, - logger: &Logger, - ) -> PendingTransactionStatus { - info!( - logger, - "Transaction '{}' has been added to the blockchain; detected locally at attempt {} at {}ms after its sending", - fingerprint.hash, - fingerprint.attempt_opt.expectv("initialized attempt"), - elapsed_in_ms(fingerprint.timestamp) - ); - PendingTransactionStatus::Confirmed(fingerprint.clone()) - } - fn handle_status_with_failure( - fingerprint: &PendingPayableFingerprint, - logger: &Logger, - ) -> PendingTransactionStatus { - error!(logger,"Pending transaction '{}' announced as a failure, interpreting attempt {} after {}ms from the sending",fingerprint.hash,fingerprint.attempt_opt.expectv("initialized attempt"),elapsed_in_ms(fingerprint.timestamp)); - PendingTransactionStatus::Failure(fingerprint.into()) - } match receipt.status { None => handle_none_status(fingerprint, self.when_pending_too_long_sec, logger), Some(status_code) => diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 29c08e6e7..f428c8189 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -176,6 +176,10 @@ pub(crate) mod payable_scanner_tools { } pub(crate) mod pending_payable_scanner_tools { + use crate::accountant::{PendingPayableId, PendingTransactionStatus}; + use crate::blockchain::blockchain_bridge::PendingPayableFingerprint; + use masq_lib::logger::Logger; + use masq_lib::utils::ExpectValue; use std::time::SystemTime; pub fn elapsed_in_ms(timestamp: SystemTime) -> u128 { @@ -184,6 +188,74 @@ pub(crate) mod pending_payable_scanner_tools { .expect("time calculation for elapsed failed") .as_millis() } + + pub fn handle_none_status( + fingerprint: &PendingPayableFingerprint, + max_pending_interval: u64, + logger: &Logger, + ) -> PendingTransactionStatus { + info!( + logger, + "Pending transaction '{}' couldn't be confirmed at attempt \ + {} at {}ms after its sending", + fingerprint.hash, + fingerprint.attempt_opt.expectv("initialized attempt"), + elapsed_in_ms(fingerprint.timestamp) + ); + let elapsed = fingerprint + .timestamp + .elapsed() + .expect("we should be older now"); + let transaction_id = PendingPayableId { + hash: fingerprint.hash, + rowid: fingerprint.rowid_opt.expectv("initialized rowid"), + }; + if max_pending_interval <= elapsed.as_secs() { + error!( + logger, + "Pending transaction '{}' has exceeded the maximum pending time \ + ({}sec) and the confirmation process is going to be aborted now \ + at the final attempt {}; manual resolution is required from the \ + user to complete the transaction.", + fingerprint.hash, + max_pending_interval, + fingerprint.attempt_opt.expectv("initialized attempt") + ); + PendingTransactionStatus::Failure(transaction_id) + } else { + PendingTransactionStatus::StillPending(transaction_id) + } + } + + pub fn handle_status_with_success( + fingerprint: &PendingPayableFingerprint, + logger: &Logger, + ) -> PendingTransactionStatus { + info!( + logger, + "Transaction '{}' has been added to the blockchain; detected locally at attempt \ + {} at {}ms after its sending", + fingerprint.hash, + fingerprint.attempt_opt.expectv("initialized attempt"), + elapsed_in_ms(fingerprint.timestamp) + ); + PendingTransactionStatus::Confirmed(fingerprint.clone()) + } + + pub fn handle_status_with_failure( + fingerprint: &PendingPayableFingerprint, + logger: &Logger, + ) -> PendingTransactionStatus { + error!( + logger, + "Pending transaction '{}' announced as a failure, interpreting attempt \ + {} after {}ms from the sending", + fingerprint.hash, + fingerprint.attempt_opt.expectv("initialized attempt"), + elapsed_in_ms(fingerprint.timestamp) + ); + PendingTransactionStatus::Failure(fingerprint.into()) + } } pub(crate) mod receivable_scanner_tools { From 24c6a06de6c1c60cd602cda38bd3ca624cc39b7a Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 12:13:45 +0530 Subject: [PATCH 116/145] GH-611: reorder items inside accountant.rs --- node/src/accountant/mod.rs | 84 +++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 179b31ada..61e1037c4 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -98,18 +98,24 @@ pub struct ResponseSkeleton { pub context_id: u64, } -#[derive(Debug, Eq, Message, PartialEq)] -pub struct ReceivedPayments { - pub payments: Vec, - pub response_skeleton_opt: Option, -} - #[derive(Debug, Message, PartialEq)] pub struct SentPayable { pub payable: Vec>, pub response_skeleton_opt: Option, } +#[derive(Debug, PartialEq, Message, Clone)] +pub struct ReportTransactionReceipts { + pub fingerprints_with_receipts: Vec<(Option, PendingPayableFingerprint)>, + pub response_skeleton_opt: Option, +} + +#[derive(Debug, Eq, Message, PartialEq)] +pub struct ReceivedPayments { + pub payments: Vec, + pub response_skeleton_opt: Option, +} + #[derive(Debug, Eq, Message, PartialEq, Clone, Copy)] pub struct ScanForPayables { pub response_skeleton_opt: Option, @@ -172,19 +178,34 @@ impl Handler for Accountant { } } -impl Handler for Accountant { +impl Handler for Accountant { type Result = (); - fn handle(&mut self, msg: ReceivedPayments, _ctx: &mut Self::Context) -> Self::Result { - self.handle_received_payments(msg); + fn handle(&mut self, msg: SentPayable, _ctx: &mut Self::Context) -> Self::Result { + match self.scanners.payable.scan_finished(msg, &self.logger) { + Ok(node_to_ui_msg_opt) => { + if let Some(node_to_ui_msg) = node_to_ui_msg_opt { + self.ui_message_sub + .as_ref() + .expect("UIGateway is not bound") + .try_send(node_to_ui_msg) + .expect("UIGateway is dead"); + } + } + Err(e) => panic!("Payable Scanner: {}", e), + } } } -impl Handler for Accountant { +impl Handler for Accountant { type Result = (); - fn handle(&mut self, msg: SentPayable, _ctx: &mut Self::Context) -> Self::Result { - match self.scanners.payable.scan_finished(msg, &self.logger) { + fn handle(&mut self, msg: ReportTransactionReceipts, _ctx: &mut Self::Context) -> Self::Result { + match self + .scanners + .pending_payable + .scan_finished(msg, &self.logger) + { Ok(node_to_ui_msg_opt) => { if let Some(node_to_ui_msg) = node_to_ui_msg_opt { self.ui_message_sub @@ -194,11 +215,19 @@ impl Handler for Accountant { .expect("UIGateway is dead"); } } - Err(e) => panic!("Payable Scanner: {}", e), + Err(e) => panic!("PendingPayable Scanner: {}", e), } } } +impl Handler for Accountant { + type Result = (); + + fn handle(&mut self, msg: ReceivedPayments, _ctx: &mut Self::Context) -> Self::Result { + self.handle_received_payments(msg); + } +} + impl Handler for Accountant { type Result = (); @@ -336,35 +365,6 @@ impl SkeletonOptHolder for RequestTransactionReceipts { } } -#[derive(Debug, PartialEq, Message, Clone)] -pub struct ReportTransactionReceipts { - pub fingerprints_with_receipts: Vec<(Option, PendingPayableFingerprint)>, - pub response_skeleton_opt: Option, -} - -impl Handler for Accountant { - type Result = (); - - fn handle(&mut self, msg: ReportTransactionReceipts, _ctx: &mut Self::Context) -> Self::Result { - match self - .scanners - .pending_payable - .scan_finished(msg, &self.logger) - { - Ok(node_to_ui_msg_opt) => { - if let Some(node_to_ui_msg) = node_to_ui_msg_opt { - self.ui_message_sub - .as_ref() - .expect("UIGateway is not bound") - .try_send(node_to_ui_msg) - .expect("UIGateway is dead"); - } - } - Err(e) => panic!("PendingPayable Scanner: {}", e), - } - } -} - #[derive(Debug, PartialEq, Message, Clone)] pub struct CancelFailedPendingTransaction { pub id: PendingPayableId, From ee7ed6423d5c532013e1596023fa6729e1d79ae5 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 12:38:00 +0530 Subject: [PATCH 117/145] GH-611: migrate tests for CancelPendingTransactions inside scanners.rs --- node/src/accountant/mod.rs | 57 +-------------------------- node/src/accountant/scanners.rs | 69 ++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 61e1037c4..5497ee92b 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -839,6 +839,7 @@ impl Accountant { } fn handle_cancel_pending_transaction(&self, msg: CancelFailedPendingTransaction) { + todo!("break some tests"); match self .pending_payable_dao .mark_failure(msg.id.rowid) @@ -3266,62 +3267,6 @@ mod tests { let _ = subject.handle_confirm_pending_transaction(msg); } - #[test] - fn handle_cancel_pending_transaction_works() { - init_test_logging(); - let mark_failure_params_arc = Arc::new(Mutex::new(vec![])); - let pending_payable_dao = PendingPayableDaoMock::default() - .mark_failure_params(&mark_failure_params_arc) - .mark_failure_result(Ok(())); - let subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner - .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner - .build(); - let tx_hash = H256::from("sometransactionhash".keccak256()); - let rowid = 2; - let transaction_id = PendingPayableId { - hash: tx_hash, - rowid, - }; - - let _ = subject.handle_cancel_pending_transaction(CancelFailedPendingTransaction { - id: transaction_id, - }); - - let mark_failure_params = mark_failure_params_arc.lock().unwrap(); - assert_eq!(*mark_failure_params, vec![rowid]); - TestLogHandler::new().exists_log_containing( - "WARN: Accountant: Broken transaction 0x051a…8c19 left with an error mark; you should take over \ - the care of this transaction to make sure your debts will be paid because there is no automated process that can fix this without you", - ); - } - - #[test] - #[should_panic( - expected = "Unsuccessful attempt for transaction 0x051a…8c19 to mark fatal error at payable fingerprint due to UpdateFailed(\"no no no\")" - )] - fn handle_cancel_pending_transaction_panics_on_its_inability_to_mark_failure() { - let payable_dao = PayableDaoMock::default().transaction_canceled_result(Ok(())); - let pending_payable_dao = PendingPayableDaoMock::default().mark_failure_result(Err( - PendingPayableDaoError::UpdateFailed("no no no".to_string()), - )); - let subject = AccountantBuilder::default() - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Payable Scanner - .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner - .pending_payable_dao(pending_payable_dao) - .pending_payable_dao(PendingPayableDaoMock::new()) - .pending_payable_dao(PendingPayableDaoMock::new()) - .build(); - let rowid = 2; - let hash = H256::from("sometransactionhash".keccak256()); - - let _ = subject.handle_cancel_pending_transaction(CancelFailedPendingTransaction { - id: PendingPayableId { hash, rowid }, - }); - } - #[test] #[should_panic( expected = "panic message (processed with: node_lib::sub_lib::utils::crash_request_analyzer)" diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index a0c9bf2c9..16419e098 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -470,7 +470,7 @@ pub(in crate::accountant) mod scanners { } } - fn order_cancel_failed_transaction( + pub fn order_cancel_failed_transaction( &self, transaction_id: PendingPayableId, logger: &Logger, @@ -768,6 +768,7 @@ mod tests { use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; use ethereum_types::{BigEndianHash, U64}; + use ethsign_crypto::Keccak256; use masq_lib::logger::Logger; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; use std::rc::Rc; @@ -1213,6 +1214,59 @@ mod tests { .exists_log_matching("DEBUG: Handle Pending Tx: Interpreting a receipt for transaction '0x0000…0913' but none was given; attempt 3, 100\\d\\dms since sending"); } + #[test] + fn order_cancel_pending_transaction_works() { + init_test_logging(); + let mark_failure_params_arc = Arc::new(Mutex::new(vec![])); + let pending_payable_dao = PendingPayableDaoMock::default() + .mark_failure_params(&mark_failure_params_arc) + .mark_failure_result(Ok(())); + let subject = + make_pending_payable_scanner_from_daos(PayableDaoMock::new(), pending_payable_dao); + let tx_hash = H256::from("sometransactionhash".keccak256()); + let rowid = 2; + let transaction_id = PendingPayableId { + hash: tx_hash, + rowid, + }; + + let result = subject + .order_cancel_failed_transaction(transaction_id, &Logger::new("CancelPendingTxOk")); + + let mark_failure_params = mark_failure_params_arc.lock().unwrap(); + assert_eq!(result, Ok(())); + assert_eq!(*mark_failure_params, vec![rowid]); + TestLogHandler::new().exists_log_containing( + "WARN: CancelPendingTxOk: Broken transaction 0x051a…8c19 left with an error \ + mark; you should take over the care of this transaction to make sure your debts will \ + be paid because there is no automated process that can fix this without you", + ); + } + + #[test] + fn order_cancel_pending_transaction_throws_error_when_it_fails_to_mark_failure() { + let payable_dao = PayableDaoMock::default().transaction_canceled_result(Ok(())); + let pending_payable_dao = PendingPayableDaoMock::default().mark_failure_result(Err( + PendingPayableDaoError::UpdateFailed("no no no".to_string()), + )); + let subject = make_pending_payable_scanner_from_daos(payable_dao, pending_payable_dao); + let rowid = 2; + let hash = H256::from("sometransactionhash".keccak256()); + let transaction_id = PendingPayableId { hash, rowid }; + + let result = subject + .order_cancel_failed_transaction(transaction_id, &Logger::new("CancelPendingTxOk")); + + assert_eq!( + result, + Err( + "Unsuccessful attempt for transaction 0x051a…8c19 to mark fatal error at payable \ + fingerprint due to UpdateFailed(\"no no no\"); database unreliable" + .to_string() + ) + ) + } + #[test] fn pending_payable_scanner_handles_report_transaction_receipts_message() { init_test_logging(); @@ -1379,4 +1433,17 @@ mod tests { tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574333435366e \\(balance: 3456 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574343536376e \\(balance: 4567 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); } + + fn make_pending_payable_scanner_from_daos( + payable_dao: PayableDaoMock, + pending_payable_dao: PendingPayableDaoMock, + ) -> PendingPayableScanner { + PendingPayableScanner::new( + Box::new(payable_dao), + Box::new(pending_payable_dao), + Rc::new(make_payment_thresholds_with_defaults()), + DEFAULT_PENDING_TOO_LONG_SEC, + Rc::new(RefCell::new(FinancialStatistics::default())), + ) + } } From 54e71ed1124bef283423060517a45e9799b15d72 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 12:44:33 +0530 Subject: [PATCH 118/145] GH-611: remove the CancelFailedPendingTransaction message --- node/src/accountant/mod.rs | 42 --------------------------------- node/src/accountant/scanners.rs | 8 +++---- 2 files changed, 3 insertions(+), 47 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 5497ee92b..6f5724270 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -365,23 +365,6 @@ impl SkeletonOptHolder for RequestTransactionReceipts { } } -#[derive(Debug, PartialEq, Message, Clone)] -pub struct CancelFailedPendingTransaction { - pub id: PendingPayableId, -} - -impl Handler for Accountant { - type Result = (); - - fn handle( - &mut self, - msg: CancelFailedPendingTransaction, - _ctx: &mut Self::Context, - ) -> Self::Result { - self.handle_cancel_pending_transaction(msg) - } -} - #[derive(Debug, PartialEq, Message, Clone)] pub struct ConfirmPendingTransaction { pub pending_payable_fingerprint: PendingPayableFingerprint, @@ -838,19 +821,6 @@ impl Accountant { } } - fn handle_cancel_pending_transaction(&self, msg: CancelFailedPendingTransaction) { - todo!("break some tests"); - match self - .pending_payable_dao - .mark_failure(msg.id.rowid) - { - Ok(_) => warning!( - self.logger, - "Broken transaction {} left with an error mark; you should take over the care of this transaction to make sure your debts will be paid because there is no automated process that can fix this without you", msg.id.hash), - Err(e) => panic!("Unsuccessful attempt for transaction {} to mark fatal error at payable fingerprint due to {:?}; database unreliable", msg.id.hash, e), - } - } - fn handle_confirm_pending_transaction(&mut self, msg: ConfirmPendingTransaction) { if let Err(e) = self .payable_dao @@ -1113,11 +1083,6 @@ mod tests { .as_any() .downcast_ref::>() .unwrap(); - transaction_confirmation_tools - .notify_cancel_failed_transaction - .as_any() - .downcast_ref::>() - .unwrap(); let notify_later = result.notify_later; notify_later .scan_for_pending_payable @@ -3297,9 +3262,6 @@ mod tests { let notify_later_scan_for_pending_payable_params_arc = Arc::new(Mutex::new(vec![])); let notify_later_scan_for_pending_payable_arc_cloned = notify_later_scan_for_pending_payable_params_arc.clone(); //because it moves into a closure - let notify_cancel_failed_transaction_params_arc = Arc::new(Mutex::new(vec![])); - let notify_cancel_failed_transaction_params_arc_cloned = - notify_cancel_failed_transaction_params_arc.clone(); //because it moves into a closure let notify_confirm_transaction_params_arc = Arc::new(Mutex::new(vec![])); let notify_confirm_transaction_params_arc_cloned = notify_confirm_transaction_params_arc.clone(); //because it moves into a closure @@ -3470,10 +3432,6 @@ mod tests { .notify_later_params(¬ify_later_scan_for_pending_payable_arc_cloned) .permit_to_send_out(); subject.notify_later.scan_for_pending_payable = Box::new(notify_later_half_mock); - let notify_half_mock = NotifyHandleMock::default() - .notify_params(¬ify_cancel_failed_transaction_params_arc_cloned) - .permit_to_send_out(); - subject.tools.notify_cancel_failed_transaction = Box::new(notify_half_mock); let notify_half_mock = NotifyHandleMock::default() .notify_params(¬ify_confirm_transaction_params_arc_cloned) .permit_to_send_out(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 16419e098..8841b9a80 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -12,9 +12,9 @@ pub(in crate::accountant) mod scanners { }; use crate::accountant::tools::receivable_scanner_tools::balance_and_age; use crate::accountant::{ - Accountant, CancelFailedPendingTransaction, ConfirmPendingTransaction, ReceivedPayments, - ReportTransactionReceipts, RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, - ScanForPendingPayables, ScanForReceivables, SentPayable, + Accountant, ConfirmPendingTransaction, ReceivedPayments, ReportTransactionReceipts, + RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, ScanForPendingPayables, + ScanForReceivables, SentPayable, }; use crate::accountant::{PendingPayableId, PendingTransactionStatus, ReportAccountsPayable}; use crate::banned_dao::BannedDao; @@ -736,8 +736,6 @@ pub(in crate::accountant) mod scanners { pub struct TransactionConfirmationTools { pub notify_confirm_transaction: Box>, - pub notify_cancel_failed_transaction: - Box>, } } From d25e290a8cdc0334040112ad95e9a0608a680393 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 13:40:29 +0530 Subject: [PATCH 119/145] GH-611: migrate tests for update_payable_fingerprint() --- node/src/accountant/mod.rs | 59 --------------------------------- node/src/accountant/scanners.rs | 44 +++++++++++++++++++++++- 2 files changed, 43 insertions(+), 60 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 6f5724270..714c4d563 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -855,23 +855,6 @@ impl Accountant { } } - fn update_payable_fingerprint(&self, pending_payable_id: PendingPayableId) { - match self - .pending_payable_dao - .update_fingerprint(pending_payable_id.rowid) - { - Ok(_) => trace!( - self.logger, - "Updated record for rowid: {} ", - pending_payable_id.rowid - ), - Err(e) => panic!( - "Failure on updating payable fingerprint '{:?}' due to {:?}", - pending_payable_id.hash, e - ), - } - } - fn handle_new_pending_payable_fingerprint(&self, msg: PendingPayableFingerprint) { match self .pending_payable_dao @@ -3622,48 +3605,6 @@ mod tests { TestLogHandler::new().exists_log_containing("ERROR: Accountant: Failed to make a fingerprint for pending payable '0x0000…01c8' due to 'InsertionFailed(\"Crashed\")'"); } - #[test] - fn update_payable_fingerprint_happy_path() { - let update_after_cycle_params_arc = Arc::new(Mutex::new(vec![])); - let hash = H256::from_uint(&U256::from(444888)); - let rowid = 3456; - let pending_payable_dao = PendingPayableDaoMock::default() - .update_fingerprint_params(&update_after_cycle_params_arc) - .update_fingerprint_results(Ok(())); - let subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) - .pending_payable_dao(PendingPayableDaoMock::new()) - .pending_payable_dao(PendingPayableDaoMock::new()) - .build(); - let transaction_id = PendingPayableId { hash, rowid }; - - let _ = subject.update_payable_fingerprint(transaction_id); - - let update_after_cycle_params = update_after_cycle_params_arc.lock().unwrap(); - assert_eq!(*update_after_cycle_params, vec![rowid]) - } - - #[test] - #[should_panic( - expected = "Failure on updating payable fingerprint '0x000000000000000000000000000000000000000000000000000000000006c9d8' \ - due to UpdateFailed(\"yeah, bad\")" - )] - fn update_payable_fingerprint_sad_path() { - let hash = H256::from_uint(&U256::from(444888)); - let rowid = 3456; - let pending_payable_dao = PendingPayableDaoMock::default().update_fingerprint_results(Err( - PendingPayableDaoError::UpdateFailed("yeah, bad".to_string()), - )); - let subject = AccountantBuilder::default() - .pending_payable_dao(pending_payable_dao) - .pending_payable_dao(PendingPayableDaoMock::new()) - .pending_payable_dao(PendingPayableDaoMock::new()) - .build(); - let transaction_id = PendingPayableId { hash, rowid }; - - let _ = subject.update_payable_fingerprint(transaction_id); - } - #[test] fn handles_scan_error() { let (ui_gateway, _, ui_gateway_recording_arc) = make_recorder(); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 8841b9a80..9ca3eee63 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -446,7 +446,7 @@ pub(in crate::accountant) mod scanners { Ok(()) } - fn update_payable_fingerprint( + pub(crate) fn update_payable_fingerprint( &self, pending_payable_id: PendingPayableId, logger: &Logger, @@ -1212,6 +1212,48 @@ mod tests { .exists_log_matching("DEBUG: Handle Pending Tx: Interpreting a receipt for transaction '0x0000…0913' but none was given; attempt 3, 100\\d\\dms since sending"); } + #[test] + fn update_payable_fingerprint_happy_path() { + let test_name = "update_payable_fingerprint_happy_path"; + let update_after_cycle_params_arc = Arc::new(Mutex::new(vec![])); + let hash = H256::from_uint(&U256::from(444888)); + let rowid = 3456; + let pending_payable_dao = PendingPayableDaoMock::default() + .update_fingerprint_params(&update_after_cycle_params_arc) + .update_fingerprint_results(Ok(())); + let subject = + make_pending_payable_scanner_from_daos(PayableDaoMock::new(), pending_payable_dao); + let transaction_id = PendingPayableId { hash, rowid }; + + let result = subject.update_payable_fingerprint(transaction_id, &Logger::new(test_name)); + + let update_after_cycle_params = update_after_cycle_params_arc.lock().unwrap(); + assert_eq!(*update_after_cycle_params, vec![rowid]) + } + + #[test] + fn update_payable_fingerprint_sad_path() { + let test_name = "update_payable_fingerprint_sad_path"; + let hash = H256::from_uint(&U256::from(444888)); + let rowid = 3456; + let pending_payable_dao = PendingPayableDaoMock::default().update_fingerprint_results(Err( + PendingPayableDaoError::UpdateFailed("yeah, bad".to_string()), + )); + let subject = + make_pending_payable_scanner_from_daos(PayableDaoMock::new(), pending_payable_dao); + let transaction_id = PendingPayableId { hash, rowid }; + + let result = subject.update_payable_fingerprint(transaction_id, &Logger::new(test_name)); + + assert_eq!( + result, + Err("Failure on updating payable fingerprint \ + '0x000000000000000000000000000000000000000000000000000000000006c9d8' \ + due to UpdateFailed(\"yeah, bad\")" + .to_string()) + ) + } + #[test] fn order_cancel_pending_transaction_works() { init_test_logging(); From 6325fcd743120801f20fa3d01d1761cecdf24290 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 14:22:07 +0530 Subject: [PATCH 120/145] GH-611: migrate tests for confirming pending transactions to scanners.rs --- node/src/accountant/mod.rs | 151 +------------------------------ node/src/accountant/scanners.rs | 155 +++++++++++++++++++++++++++++++- 2 files changed, 154 insertions(+), 152 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 714c4d563..47f228cb6 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -822,6 +822,7 @@ impl Accountant { } fn handle_confirm_pending_transaction(&mut self, msg: ConfirmPendingTransaction) { + todo!("break some tests"); if let Err(e) = self .payable_dao .transaction_confirmed(&msg.pending_payable_fingerprint) @@ -3106,115 +3107,6 @@ mod tests { // TODO: Assert subject.scan_for_payables_in_progress [No scan in progress] } - #[test] - fn handle_confirm_transaction_works() { - init_test_logging(); - let transaction_confirmed_params_arc = Arc::new(Mutex::new(vec![])); - let delete_pending_payable_fingerprint_params_arc = Arc::new(Mutex::new(vec![])); - let payable_dao = PayableDaoMock::default() - .transaction_confirmed_params(&transaction_confirmed_params_arc) - .transaction_confirmed_result(Ok(())); - let pending_payable_dao = PendingPayableDaoMock::default() - .delete_fingerprint_params(&delete_pending_payable_fingerprint_params_arc) - .delete_fingerprint_result(Ok(())); - let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Payable Scanner - .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner - .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner - .build(); - let tx_hash = H256::from("sometransactionhash".keccak256()); - let amount = 4567; - let timestamp_from_time_of_payment = from_time_t(200_000_000); - let rowid = 2; - let pending_payable_fingerprint = PendingPayableFingerprint { - rowid_opt: Some(rowid), - timestamp: timestamp_from_time_of_payment, - hash: tx_hash, - attempt_opt: Some(1), - amount, - process_error: None, - }; - - let _ = subject.handle_confirm_pending_transaction(ConfirmPendingTransaction { - pending_payable_fingerprint: pending_payable_fingerprint.clone(), - }); - - let transaction_confirmed_params = transaction_confirmed_params_arc.lock().unwrap(); - assert_eq!( - *transaction_confirmed_params, - vec![pending_payable_fingerprint] - ); - let delete_pending_payable_fingerprint_params = - delete_pending_payable_fingerprint_params_arc - .lock() - .unwrap(); - assert_eq!(*delete_pending_payable_fingerprint_params, vec![rowid]); - let log_handler = TestLogHandler::new(); - log_handler.exists_log_containing("DEBUG: Accountant: Confirmation of transaction 0x051a…8c19; record for payable was modified"); - log_handler.exists_log_containing("INFO: Accountant: Transaction 0x051aae12b9595ccaa43c2eabfd5b86347c37fa0988167165b0b17b23fcaa8c19 has gone through the whole confirmation process succeeding"); - } - - #[test] - #[should_panic( - expected = "Was unable to uncheck pending payable '0x0000…0315' after confirmation due to 'RusqliteError(\"record change not successful\")" - )] - fn handle_confirm_pending_transaction_panics_on_unchecking_payable_table() { - init_test_logging(); - let hash = H256::from_uint(&U256::from(789)); - let rowid = 3; - let payable_dao = PayableDaoMock::new().transaction_confirmed_result(Err( - PayableDaoError::RusqliteError("record change not successful".to_string()), - )); - let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) - .payable_dao(PayableDaoMock::new()) - .payable_dao(PayableDaoMock::new()) - .build(); - let mut payment = make_pending_payable_fingerprint(); - payment.rowid_opt = Some(rowid); - payment.hash = hash; - let msg = ConfirmPendingTransaction { - pending_payable_fingerprint: payment.clone(), - }; - - let _ = subject.handle_confirm_pending_transaction(msg); - } - - #[test] - #[should_panic( - expected = "Was unable to delete payable fingerprint '0x0000…0315' after successful transaction due to 'RecordDeletion(\"the database is fooling around with us\")'" - )] - fn handle_confirm_pending_transaction_panics_on_deleting_pending_payable_fingerprint() { - init_test_logging(); - let hash = H256::from_uint(&U256::from(789)); - let rowid = 3; - let payable_dao = PayableDaoMock::new().transaction_confirmed_result(Ok(())); - let pending_payable_dao = PendingPayableDaoMock::default().delete_fingerprint_result(Err( - PendingPayableDaoError::RecordDeletion( - "the database is fooling around with us".to_string(), - ), - )); - let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) // For Accountant - .payable_dao(PayableDaoMock::new()) // For Payable Scanner - .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner - .pending_payable_dao(pending_payable_dao) // For Accountant - .pending_payable_dao(PendingPayableDaoMock::new()) // For Payable Scanner - .pending_payable_dao(PendingPayableDaoMock::new()) // For PendingPayable Scanner - .build(); - let mut pending_payable_fingerprint = make_pending_payable_fingerprint(); - pending_payable_fingerprint.rowid_opt = Some(rowid); - pending_payable_fingerprint.hash = hash; - let msg = ConfirmPendingTransaction { - pending_payable_fingerprint: pending_payable_fingerprint.clone(), - }; - - let _ = subject.handle_confirm_pending_transaction(msg); - } - #[test] #[should_panic( expected = "panic message (processed with: node_lib::sub_lib::utils::crash_request_analyzer)" @@ -3690,47 +3582,6 @@ mod tests { ); } - #[test] - fn total_paid_payable_rises_with_each_bill_paid() { - let transaction_confirmed_params_arc = Arc::new(Mutex::new(vec![])); - let fingerprint = PendingPayableFingerprint { - rowid_opt: Some(5), - timestamp: from_time_t(189_999_888), - hash: H256::from_uint(&U256::from(56789)), - attempt_opt: Some(1), - amount: 5478, - process_error: None, - }; - let mut pending_payable_dao = - PendingPayableDaoMock::default().delete_fingerprint_result(Ok(())); - let payable_dao = PayableDaoMock::default() - .transaction_confirmed_params(&transaction_confirmed_params_arc) - .transaction_confirmed_result(Ok(())) - .transaction_confirmed_result(Ok(())); - pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; - let mut subject = AccountantBuilder::default() - .payable_dao(payable_dao) - .payable_dao(PayableDaoMock::new()) - .payable_dao(PayableDaoMock::new()) - .pending_payable_dao(pending_payable_dao) - .pending_payable_dao(PendingPayableDaoMock::new()) - .pending_payable_dao(PendingPayableDaoMock::new()) - .build(); - let mut financial_statistics = subject.financial_statistics(); - financial_statistics.total_paid_payable += 1111; - subject.financial_statistics.replace(financial_statistics); - let msg = ConfirmPendingTransaction { - pending_payable_fingerprint: fingerprint.clone(), - }; - - subject.handle_confirm_pending_transaction(msg); - - let total_paid_payable = subject.financial_statistics().total_paid_payable; - assert_eq!(total_paid_payable, 1111 + 5478); - let transaction_confirmed_params = transaction_confirmed_params_arc.lock().unwrap(); - assert_eq!(*transaction_confirmed_params, vec![fingerprint]) - } - #[test] fn total_paid_receivable_rises_with_each_bill_paid() { let more_money_received_params_arc = Arc::new(Mutex::new(vec![])); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 9ca3eee63..c09dbce1e 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -291,7 +291,7 @@ pub(in crate::accountant) mod scanners { payable_dao: Box, pending_payable_dao: Box, when_pending_too_long_sec: u64, - financial_statistics: Rc>, + pub(crate) financial_statistics: Rc>, } impl Scanner for PendingPayableScanner { @@ -494,7 +494,7 @@ pub(in crate::accountant) mod scanners { } } - fn order_confirm_transaction( + pub fn order_confirm_transaction( &mut self, pending_payable_fingerprint: PendingPayableFingerprint, logger: &Logger, @@ -537,6 +537,10 @@ pub(in crate::accountant) mod scanners { } } } + + pub fn financial_statistics(&self) -> FinancialStatistics { + self.financial_statistics.as_ref().borrow().clone() + } } pub struct ReceivableScanner { @@ -1307,6 +1311,153 @@ mod tests { ) } + #[test] + fn handle_confirm_pending_transaction_throws_error_while_deleting_pending_payable_fingerprint() + { + init_test_logging(); + let test_name = "handle_confirm_pending_transaction_throws_error_while_deleting_pending_payable_fingerprint"; + let hash = H256::from_uint(&U256::from(789)); + let rowid = 3; + let payable_dao = PayableDaoMock::new().transaction_confirmed_result(Ok(())); + let pending_payable_dao = PendingPayableDaoMock::default().delete_fingerprint_result(Err( + PendingPayableDaoError::RecordDeletion( + "the database is fooling around with us".to_string(), + ), + )); + let mut subject = make_pending_payable_scanner_from_daos(payable_dao, pending_payable_dao); + let mut pending_payable_fingerprint = make_pending_payable_fingerprint(); + pending_payable_fingerprint.rowid_opt = Some(rowid); + pending_payable_fingerprint.hash = hash; + + let result = + subject.order_confirm_transaction(pending_payable_fingerprint, &Logger::new(test_name)); + + assert_eq!( + result, + Err( + "Was unable to delete payable fingerprint '0x0000…0315' after successful \ + transaction due to 'RecordDeletion(\"the database is fooling around with us\")'" + .to_string() + ) + ) + } + + #[test] + fn handle_confirm_transaction_works() { + init_test_logging(); + let test_name = "handle_confirm_transaction_works"; + let transaction_confirmed_params_arc = Arc::new(Mutex::new(vec![])); + let delete_pending_payable_fingerprint_params_arc = Arc::new(Mutex::new(vec![])); + let payable_dao = PayableDaoMock::default() + .transaction_confirmed_params(&transaction_confirmed_params_arc) + .transaction_confirmed_result(Ok(())); + let pending_payable_dao = PendingPayableDaoMock::default() + .delete_fingerprint_params(&delete_pending_payable_fingerprint_params_arc) + .delete_fingerprint_result(Ok(())); + let mut subject = make_pending_payable_scanner_from_daos(payable_dao, pending_payable_dao); + let tx_hash = H256::from("sometransactionhash".keccak256()); + let amount = 4567; + let timestamp_from_time_of_payment = from_time_t(200_000_000); + let rowid = 2; + let pending_payable_fingerprint = PendingPayableFingerprint { + rowid_opt: Some(rowid), + timestamp: timestamp_from_time_of_payment, + hash: tx_hash, + attempt_opt: Some(1), + amount, + process_error: None, + }; + + let result = subject.order_confirm_transaction( + pending_payable_fingerprint.clone(), + &Logger::new(test_name), + ); + + let transaction_confirmed_params = transaction_confirmed_params_arc.lock().unwrap(); + let delete_pending_payable_fingerprint_params = + delete_pending_payable_fingerprint_params_arc + .lock() + .unwrap(); + assert_eq!(result, Ok(())); + assert_eq!( + *transaction_confirmed_params, + vec![pending_payable_fingerprint] + ); + assert_eq!(*delete_pending_payable_fingerprint_params, vec![rowid]); + TestLogHandler::new().assert_logs_contain_in_order(vec![ + &format!( + "DEBUG: {test_name}: Confirmation of transaction 0x051a…8c19; \ + record for payable was modified" + ), + &format!( + "INFO: {test_name}: Transaction \ + 0x051aae12b9595ccaa43c2eabfd5b86347c37fa0988167165b0b17b23fcaa8c19 \ + has gone through the whole confirmation process succeeding" + ), + ]); + } + + #[test] + fn total_paid_payable_rises_with_each_bill_paid() { + let test_name = "total_paid_payable_rises_with_each_bill_paid"; + let transaction_confirmed_params_arc = Arc::new(Mutex::new(vec![])); + let fingerprint = PendingPayableFingerprint { + rowid_opt: Some(5), + timestamp: from_time_t(189_999_888), + hash: H256::from_uint(&U256::from(56789)), + attempt_opt: Some(1), + amount: 5478, + process_error: None, + }; + let payable_dao = PayableDaoMock::default() + .transaction_confirmed_params(&transaction_confirmed_params_arc) + .transaction_confirmed_result(Ok(())) + .transaction_confirmed_result(Ok(())); + let mut pending_payable_dao = + PendingPayableDaoMock::default().delete_fingerprint_result(Ok(())); + pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; + let mut subject = make_pending_payable_scanner_from_daos(payable_dao, pending_payable_dao); + let mut financial_statistics = subject.financial_statistics(); + financial_statistics.total_paid_payable += 1111; + subject.financial_statistics.replace(financial_statistics); + + let result = + subject.order_confirm_transaction(fingerprint.clone(), &Logger::new(test_name)); + + let total_paid_payable = subject.financial_statistics().total_paid_payable; + let transaction_confirmed_params = transaction_confirmed_params_arc.lock().unwrap(); + assert_eq!(result, Ok(())); + assert_eq!(total_paid_payable, 1111 + 5478); + assert_eq!(*transaction_confirmed_params, vec![fingerprint]) + } + + #[test] + fn order_confirm_transaction_throws_error_on_unchecking_payable_table() { + init_test_logging(); + let test_name = "order_confirm_transaction_throws_error_on_unchecking_payable_table"; + let hash = H256::from_uint(&U256::from(789)); + let rowid = 3; + let payable_dao = PayableDaoMock::new().transaction_confirmed_result(Err( + PayableDaoError::RusqliteError("record change not successful".to_string()), + )); + let mut subject = + make_pending_payable_scanner_from_daos(payable_dao, PendingPayableDaoMock::new()); + let mut fingerprint = make_pending_payable_fingerprint(); + fingerprint.rowid_opt = Some(rowid); + fingerprint.hash = hash; + + let result = subject.order_confirm_transaction(fingerprint, &Logger::new(test_name)); + + assert_eq!( + result, + Err( + "Was unable to uncheck pending payable '0x0000…0315' after confirmation due to \ + 'RusqliteError(\"record change not successful\")'" + .to_string() + ) + ) + } + #[test] fn pending_payable_scanner_handles_report_transaction_receipts_message() { init_test_logging(); From 9c342a1f47c7518ce2cfbd25137f5b0a99bf55d3 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 14:30:03 +0530 Subject: [PATCH 121/145] GH-611: remove transaction confirmation tools --- node/src/accountant/mod.rs | 87 +++------------------------------ node/src/accountant/scanners.rs | 14 ++---- 2 files changed, 10 insertions(+), 91 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 47f228cb6..09a0866dc 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -17,9 +17,7 @@ use masq_lib::ui_gateway::{MessageBody, MessagePath, MessageTarget}; use crate::accountant::payable_dao::{Payable, PayableAccount, PayableDaoError, PayableDaoFactory}; use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDaoFactory}; use crate::accountant::receivable_dao::{ReceivableDaoError, ReceivableDaoFactory}; -use crate::accountant::scanners::scanners::{ - NotifyLaterForScanners, ScannerError, Scanners, TransactionConfirmationTools, -}; +use crate::accountant::scanners::scanners::{NotifyLaterForScanners, ScannerError, Scanners}; use crate::banned_dao::{BannedDao, BannedDaoFactory}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::{BlockchainError, BlockchainTransaction}; @@ -75,7 +73,6 @@ pub struct Accountant { banned_dao: Box, crashable: bool, scanners: Scanners, - tools: TransactionConfirmationTools, notify_later: NotifyLaterForScanners, financial_statistics: Rc>, report_accounts_payable_sub_opt: Option>, @@ -365,19 +362,6 @@ impl SkeletonOptHolder for RequestTransactionReceipts { } } -#[derive(Debug, PartialEq, Message, Clone)] -pub struct ConfirmPendingTransaction { - pub pending_payable_fingerprint: PendingPayableFingerprint, -} - -impl Handler for Accountant { - type Result = (); - - fn handle(&mut self, msg: ConfirmPendingTransaction, _ctx: &mut Self::Context) -> Self::Result { - self.handle_confirm_pending_transaction(msg) - } -} - impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: PendingPayableFingerprint, _ctx: &mut Self::Context) -> Self::Result { @@ -449,7 +433,6 @@ impl Accountant { when_pending_too_long_sec, Rc::clone(&financial_statistics), ), - tools: TransactionConfirmationTools::default(), notify_later: NotifyLaterForScanners::default(), financial_statistics: Rc::clone(&financial_statistics), report_accounts_payable_sub_opt: None, @@ -821,41 +804,6 @@ impl Accountant { } } - fn handle_confirm_pending_transaction(&mut self, msg: ConfirmPendingTransaction) { - todo!("break some tests"); - if let Err(e) = self - .payable_dao - .transaction_confirmed(&msg.pending_payable_fingerprint) - { - panic!( - "Was unable to uncheck pending payable '{}' after confirmation due to '{:?}'", - msg.pending_payable_fingerprint.hash, e - ) - } else { - let mut financial_statistics = self.financial_statistics.as_ref().borrow().clone(); - financial_statistics.total_paid_payable += msg.pending_payable_fingerprint.amount; - self.financial_statistics.replace(financial_statistics); - debug!( - self.logger, - "Confirmation of transaction {}; record for payable was modified", - msg.pending_payable_fingerprint.hash - ); - if let Err(e) = self.pending_payable_dao.delete_fingerprint( - msg.pending_payable_fingerprint - .rowid_opt - .expectv("initialized rowid"), - ) { - panic!("Was unable to delete payable fingerprint '{}' after successful transaction due to '{:?}'", msg.pending_payable_fingerprint.hash, e) - } else { - info!( - self.logger, - "Transaction {:?} has gone through the whole confirmation process succeeding", - msg.pending_payable_fingerprint.hash - ) - } - } - } - fn handle_new_pending_payable_fingerprint(&self, msg: PendingPayableFingerprint) { match self .pending_payable_dao @@ -935,9 +883,9 @@ mod tests { use crate::accountant::receivable_dao::ReceivableAccount; use crate::accountant::scanners::scanners::NullScanner; use crate::accountant::test_utils::{ - bc_from_earning_wallet, bc_from_wallets, make_payables, make_pending_payable_fingerprint, - BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, - PendingPayableDaoMock, ReceivableDaoFactoryMock, ReceivableDaoMock, + bc_from_earning_wallet, bc_from_wallets, make_payables, BannedDaoFactoryMock, + PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, + ReceivableDaoFactoryMock, ReceivableDaoMock, }; use crate::accountant::test_utils::{AccountantBuilder, BannedDaoMock}; use crate::accountant::Accountant; @@ -952,15 +900,14 @@ mod tests { ReportRoutingServiceConsumedMessage, ScanIntervals, DEFAULT_PAYMENT_THRESHOLDS, }; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; - use crate::sub_lib::utils::{NotifyHandleReal, NotifyLaterHandleReal}; + use crate::sub_lib::utils::NotifyLaterHandleReal; use crate::test_utils::persistent_configuration_mock::PersistentConfigurationMock; use crate::test_utils::recorder::make_recorder; use crate::test_utils::recorder::peer_actors_builder; use crate::test_utils::recorder::Recorder; use crate::test_utils::unshared_test_utils::{ make_bc_with_defaults, make_payment_thresholds_with_defaults, - prove_that_crash_request_handler_is_hooked_up, NotifyHandleMock, NotifyLaterHandleMock, - SystemKillerActor, + prove_that_crash_request_handler_is_hooked_up, NotifyLaterHandleMock, SystemKillerActor, }; use crate::test_utils::{make_paying_wallet, make_wallet}; use web3::types::{TransactionReceipt, H256}; @@ -1061,12 +1008,6 @@ mod tests { ); let financial_statistics = result.financial_statistics(); - let transaction_confirmation_tools = result.tools; - transaction_confirmation_tools - .notify_confirm_transaction - .as_any() - .downcast_ref::>() - .unwrap(); let notify_later = result.notify_later; notify_later .scan_for_pending_payable @@ -3137,9 +3078,6 @@ mod tests { let notify_later_scan_for_pending_payable_params_arc = Arc::new(Mutex::new(vec![])); let notify_later_scan_for_pending_payable_arc_cloned = notify_later_scan_for_pending_payable_params_arc.clone(); //because it moves into a closure - let notify_confirm_transaction_params_arc = Arc::new(Mutex::new(vec![])); - let notify_confirm_transaction_params_arc_cloned = - notify_confirm_transaction_params_arc.clone(); //because it moves into a closure let pending_tx_hash_1 = H256::from_uint(&U256::from(123)); let pending_tx_hash_2 = H256::from_uint(&U256::from(567)); let rowid_for_account_1 = 3; @@ -3307,10 +3245,6 @@ mod tests { .notify_later_params(¬ify_later_scan_for_pending_payable_arc_cloned) .permit_to_send_out(); subject.notify_later.scan_for_pending_payable = Box::new(notify_later_half_mock); - let notify_half_mock = NotifyHandleMock::default() - .notify_params(¬ify_confirm_transaction_params_arc_cloned) - .permit_to_send_out(); - subject.tools.notify_confirm_transaction = Box::new(notify_half_mock); subject }); let mut peer_actors = peer_actors_builder().build(); @@ -3399,15 +3333,6 @@ mod tests { expected_scan_pending_payable_msg_and_interval, ] ); - let mut notify_confirm_transaction_params = - notify_confirm_transaction_params_arc.lock().unwrap(); - let actual_confirmed_payable: ConfirmPendingTransaction = - notify_confirm_transaction_params.remove(0); - assert!(notify_confirm_transaction_params.is_empty()); - let expected_confirmed_payable = ConfirmPendingTransaction { - pending_payable_fingerprint: fingerprint_2_fourth_round, - }; - assert_eq!(actual_confirmed_payable, expected_confirmed_payable); let log_handler = TestLogHandler::new(); log_handler.exists_log_containing( "WARN: Accountant: Broken transaction 0x0000…007b left with an error mark; you should take over the care of this transaction to make sure your debts will be paid because there \ diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index c09dbce1e..3b5c394f5 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -12,16 +12,15 @@ pub(in crate::accountant) mod scanners { }; use crate::accountant::tools::receivable_scanner_tools::balance_and_age; use crate::accountant::{ - Accountant, ConfirmPendingTransaction, ReceivedPayments, ReportTransactionReceipts, - RequestTransactionReceipts, ResponseSkeleton, ScanForPayables, ScanForPendingPayables, - ScanForReceivables, SentPayable, + Accountant, ReceivedPayments, ReportTransactionReceipts, RequestTransactionReceipts, + ResponseSkeleton, ScanForPayables, ScanForPendingPayables, ScanForReceivables, SentPayable, }; use crate::accountant::{PendingPayableId, PendingTransactionStatus, ReportAccountsPayable}; use crate::banned_dao::BannedDao; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::BlockchainError; use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; - use crate::sub_lib::utils::{NotifyHandle, NotifyLaterHandle}; + use crate::sub_lib::utils::NotifyLaterHandle; use crate::sub_lib::wallet::Wallet; use actix::Message; use masq_lib::logger::Logger; @@ -735,12 +734,6 @@ pub(in crate::accountant) mod scanners { pub scan_for_payable: Box>, pub scan_for_receivable: Box>, } - - #[derive(Default)] - pub struct TransactionConfirmationTools { - pub notify_confirm_transaction: - Box>, - } } #[cfg(test)] @@ -1232,6 +1225,7 @@ mod tests { let result = subject.update_payable_fingerprint(transaction_id, &Logger::new(test_name)); let update_after_cycle_params = update_after_cycle_params_arc.lock().unwrap(); + assert_eq!(result, Ok(())); assert_eq!(*update_after_cycle_params, vec![rowid]) } From 99d30dc57ff5180125589aa4ac6d41fb657bace6 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 21 Sep 2022 15:06:31 +0530 Subject: [PATCH 122/145] GH-611: migrate handling of ReceivedPayments message to the scan_finished() of scanners.rs --- node/src/accountant/mod.rs | 95 ++++---------------------- node/src/accountant/scanners.rs | 117 ++++++++++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 87 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 09a0866dc..4a838cf5b 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -11,7 +11,7 @@ pub mod test_utils; use masq_lib::constants::SCAN_ERROR; use std::cell::RefCell; -use masq_lib::messages::{ScanType, UiScanRequest, UiScanResponse}; +use masq_lib::messages::{ScanType, UiScanRequest}; use masq_lib::ui_gateway::{MessageBody, MessagePath, MessageTarget}; use crate::accountant::payable_dao::{Payable, PayableAccount, PayableDaoError, PayableDaoFactory}; @@ -221,7 +221,18 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ReceivedPayments, _ctx: &mut Self::Context) -> Self::Result { - self.handle_received_payments(msg); + match self.scanners.receivable.scan_finished(msg, &self.logger) { + Ok(node_to_ui_msg_opt) => { + if let Some(node_to_ui_msg) = node_to_ui_msg_opt { + self.ui_message_sub + .as_ref() + .expect("UIGateway is not bound") + .try_send(node_to_ui_msg) + .expect("UIGateway is dead"); + } + } + Err(e) => panic!("Receivable Scanner: {}", e), + } } } @@ -555,33 +566,6 @@ impl Accountant { info!(self.logger, "Accountant bound"); } - fn handle_received_payments(&mut self, msg: ReceivedPayments) { - if msg.payments.is_empty() { - warning!(self.logger, "Handling received payments we got zero payments but expected some, skipping database operations") - } else { - let total_newly_paid_receivable = msg - .payments - .iter() - .fold(0, |so_far, now| so_far + now.gwei_amount); - self.receivable_dao - .as_mut() - .more_money_received(msg.payments); - let mut financial_statistics = self.financial_statistics(); - financial_statistics.total_paid_receivable += total_newly_paid_receivable; - self.financial_statistics.replace(financial_statistics); - } - if let Some(response_skeleton) = msg.response_skeleton_opt { - self.ui_message_sub - .as_ref() - .expect("UIGateway is not bound") - .try_send(NodeToUiMessage { - target: MessageTarget::ClientId(response_skeleton.client_id), - body: UiScanResponse {}.tmb(response_skeleton.context_id), - }) - .expect("UIGateway is dead"); - } - } - fn handle_report_routing_service_provided_message( &mut self, msg: ReportRoutingServiceProvidedMessage, @@ -1642,8 +1626,8 @@ mod tests { .payable_dao(payable_dao) .payable_dao(PayableDaoMock::new()) .payable_dao(PayableDaoMock::new()) - .receivable_dao(receivable_dao) .receivable_dao(ReceivableDaoMock::new()) + .receivable_dao(receivable_dao) .build(); let system = System::new("accountant_receives_new_payments_to_the_receivables_dao"); let subject = accountant.start(); @@ -2739,20 +2723,6 @@ mod tests { )); } - #[test] - fn handle_received_payments_aborts_if_no_payments_supplied() { - init_test_logging(); - let mut subject = AccountantBuilder::default().build(); - let msg = ReceivedPayments { - payments: vec![], - response_skeleton_opt: None, - }; - - let _ = subject.handle_received_payments(msg); - - TestLogHandler::new().exists_log_containing("WARN: Accountant: Handling received payments we got zero payments but expected some, skipping database operations"); - } - #[test] fn report_exit_service_consumed_message_is_received() { init_test_logging(); @@ -3507,43 +3477,6 @@ mod tests { ); } - #[test] - fn total_paid_receivable_rises_with_each_bill_paid() { - let more_money_received_params_arc = Arc::new(Mutex::new(vec![])); - let receivable_dao = ReceivableDaoMock::new() - .more_money_received_parameters(&more_money_received_params_arc) - .more_money_receivable_result(Ok(())); - let mut subject = AccountantBuilder::default() - .receivable_dao(receivable_dao) - .receivable_dao(ReceivableDaoMock::new()) - .build(); - let mut financial_statistics = subject.financial_statistics(); - financial_statistics.total_paid_receivable += 2222; - subject.financial_statistics.replace(financial_statistics); - let receivables = vec![ - BlockchainTransaction { - block_number: 4578910, - from: make_wallet("wallet_1"), - gwei_amount: 45780, - }, - BlockchainTransaction { - block_number: 4569898, - from: make_wallet("wallet_2"), - gwei_amount: 33345, - }, - ]; - - subject.handle_received_payments(ReceivedPayments { - payments: receivables.clone(), - response_skeleton_opt: None, - }); - - let total_paid_receivable = subject.financial_statistics().total_paid_receivable; - assert_eq!(total_paid_receivable, 2222 + 45780 + 33345); - let more_money_received_params = more_money_received_params_arc.lock().unwrap(); - assert_eq!(*more_money_received_params, vec![receivables]); - } - #[test] fn unsigned_to_signed_handles_zero() { let result = unsigned_to_signed(0); diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 3b5c394f5..190cecafb 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -71,13 +71,14 @@ pub(in crate::accountant) mod scanners { pending_payable_dao_factory.make(), Rc::clone(&payment_thresholds), when_pending_too_long_sec, - financial_statistics, + Rc::clone(&financial_statistics), )), receivable: Box::new(ReceivableScanner::new( receivable_dao, banned_dao, Rc::clone(&payment_thresholds), earning_wallet, + financial_statistics, )), } } @@ -547,6 +548,7 @@ pub(in crate::accountant) mod scanners { dao: Box, banned_dao: Box, earning_wallet: Rc, + pub(crate) financial_statistics: Rc>, } impl Scanner for ReceivableScanner { @@ -602,10 +604,35 @@ pub(in crate::accountant) mod scanners { fn scan_finished( &mut self, - _message: ReceivedPayments, - _logger: &Logger, + message: ReceivedPayments, + logger: &Logger, ) -> Result, String> { - todo!() + if message.payments.is_empty() { + warning!( + logger, + "Handling received payments we got zero payments but expected some, \ + skipping database operations" + ) + } else { + let total_newly_paid_receivable = message + .payments + .iter() + .fold(0, |so_far, now| so_far + now.gwei_amount); + self.dao.as_mut().more_money_received(message.payments); + let mut financial_statistics = self.financial_statistics(); + financial_statistics.total_paid_receivable += total_newly_paid_receivable; + self.financial_statistics.replace(financial_statistics); + } + + let node_to_ui_message_opt = match message.response_skeleton_opt { + None => None, + Some(response_skeleton) => Some(NodeToUiMessage { + target: MessageTarget::ClientId(response_skeleton.client_id), + body: UiScanResponse {}.tmb(response_skeleton.context_id), + }), + }; + + Ok(node_to_ui_message_opt) } fn scan_started_at(&self) -> Option { @@ -621,14 +648,20 @@ pub(in crate::accountant) mod scanners { banned_dao: Box, payment_thresholds: Rc, earning_wallet: Rc, + financial_statistics: Rc>, ) -> Self { Self { common: ScannerCommon::new(payment_thresholds), earning_wallet, dao, banned_dao, + financial_statistics, } } + + pub fn financial_statistics(&self) -> FinancialStatistics { + self.financial_statistics.as_ref().borrow().clone() + } } pub struct NullScanner {} @@ -747,7 +780,7 @@ mod tests { ReceivableDaoMock, }; use crate::accountant::{ - PendingPayableId, PendingTransactionStatus, ReportTransactionReceipts, + PendingPayableId, PendingTransactionStatus, ReceivedPayments, ReportTransactionReceipts, RequestTransactionReceipts, SentPayable, DEFAULT_PENDING_TOO_LONG_SEC, }; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; @@ -756,7 +789,7 @@ mod tests { use crate::accountant::payable_dao::{Payable, PayableDaoError}; use crate::accountant::pending_payable_dao::PendingPayableDaoError; - use crate::blockchain::blockchain_interface::BlockchainError; + use crate::blockchain::blockchain_interface::{BlockchainError, BlockchainTransaction}; use crate::database::dao_utils::from_time_t; use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; @@ -1539,6 +1572,7 @@ mod tests { Box::new(banned_dao), Rc::new(payment_thresholds), Rc::new(earning_wallet.clone()), + Rc::new(RefCell::new(FinancialStatistics::default())), ); let result = receivable_scanner.begin_scan(now, None, &Logger::new(test_name)); @@ -1587,6 +1621,7 @@ mod tests { Box::new(banned_dao), Rc::new(payment_thresholds.clone()), Rc::new(make_wallet("earning")), + Rc::new(RefCell::new(FinancialStatistics::default())), ); let _result = receivable_scanner.begin_scan( @@ -1619,6 +1654,63 @@ mod tests { tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574343536376e \\(balance: 4567 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); } + #[test] + fn receivable_scanner_aborts_scan_if_no_payments_were_supplied() { + init_test_logging(); + let test_name = "receivable_scanner_aborts_scan_if_no_payments_were_supplied"; + let mut subject = + make_receivable_scanner_from_daos(ReceivableDaoMock::new(), BannedDaoMock::new()); + let msg = ReceivedPayments { + payments: vec![], + response_skeleton_opt: None, + }; + + let result = subject.scan_finished(msg, &Logger::new(test_name)); + + assert_eq!(result, Ok(None)); + TestLogHandler::new().exists_log_containing(&format!( + "WARN: {test_name}: Handling received payments we got zero payments but \ + expected some, skipping database operations" + )); + } + + #[test] + fn total_paid_receivable_rises_with_each_bill_paid() { + let test_name = "total_paid_receivable_rises_with_each_bill_paid"; + let more_money_received_params_arc = Arc::new(Mutex::new(vec![])); + let receivable_dao = ReceivableDaoMock::new() + .more_money_received_parameters(&more_money_received_params_arc) + .more_money_receivable_result(Ok(())); + let mut subject = make_receivable_scanner_from_daos(receivable_dao, BannedDaoMock::new()); + let mut financial_statistics = subject.financial_statistics(); + financial_statistics.total_paid_receivable += 2222; + subject.financial_statistics.replace(financial_statistics); + let receivables = vec![ + BlockchainTransaction { + block_number: 4578910, + from: make_wallet("wallet_1"), + gwei_amount: 45780, + }, + BlockchainTransaction { + block_number: 4569898, + from: make_wallet("wallet_2"), + gwei_amount: 33345, + }, + ]; + let msg = ReceivedPayments { + payments: receivables.clone(), + response_skeleton_opt: None, + }; + + let result = subject.scan_finished(msg, &Logger::new(test_name)); + + let total_paid_receivable = subject.financial_statistics().total_paid_receivable; + let more_money_received_params = more_money_received_params_arc.lock().unwrap(); + assert_eq!(result, Ok(None)); + assert_eq!(total_paid_receivable, 2222 + 45780 + 33345); + assert_eq!(*more_money_received_params, vec![receivables]); + } + fn make_pending_payable_scanner_from_daos( payable_dao: PayableDaoMock, pending_payable_dao: PendingPayableDaoMock, @@ -1631,4 +1723,17 @@ mod tests { Rc::new(RefCell::new(FinancialStatistics::default())), ) } + + fn make_receivable_scanner_from_daos( + receivable_dao: ReceivableDaoMock, + banned_dao: BannedDaoMock, + ) -> ReceivableScanner { + ReceivableScanner::new( + Box::new(receivable_dao), + Box::new(banned_dao), + Rc::new(make_payment_thresholds_with_defaults()), + Rc::new(make_wallet("earning")), + Rc::new(RefCell::new(FinancialStatistics::default())), + ) + } } From 86c4c222b0fba1d2bbb6e5c02ef290e8d5dc34de Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 22 Sep 2022 12:42:47 +0530 Subject: [PATCH 123/145] GH-611: use mark_as_started() to update the timestamp inside Scanners --- node/src/accountant/scanners.rs | 71 ++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 190cecafb..35c5d6a13 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -101,6 +101,8 @@ pub(in crate::accountant) mod scanners { logger: &Logger, ) -> Result, String>; fn scan_started_at(&self) -> Option; + fn mark_as_started(&mut self, timestamp: SystemTime); + fn mark_as_ended(&mut self); as_any_dcl!(); } @@ -134,7 +136,7 @@ pub(in crate::accountant) mod scanners { if let Some(timestamp) = self.scan_started_at() { return Err(ScannerError::ScanAlreadyRunning(timestamp)); } - self.common.initiated_at_opt = Some(timestamp); + self.mark_as_started(timestamp); info!(logger, "Scanning for payables"); let all_non_pending_payables = self.payable_dao.non_pending_payables(); debug!( @@ -197,6 +199,14 @@ pub(in crate::accountant) mod scanners { self.common.initiated_at_opt } + fn mark_as_started(&mut self, timestamp: SystemTime) { + self.common.initiated_at_opt = Some(timestamp); + } + + fn mark_as_ended(&mut self) { + self.common.initiated_at_opt = None; + } + as_any_impl!(); } @@ -304,7 +314,7 @@ pub(in crate::accountant) mod scanners { if let Some(timestamp) = self.scan_started_at() { return Err(ScannerError::ScanAlreadyRunning(timestamp)); } - self.common.initiated_at_opt = Some(timestamp); + self.mark_as_started(timestamp); info!(logger, "Scanning for pending payable"); let filtered_pending_payable = self.pending_payable_dao.return_all_fingerprints(); match filtered_pending_payable.is_empty() { @@ -358,6 +368,14 @@ pub(in crate::accountant) mod scanners { self.common.initiated_at_opt } + fn mark_as_started(&mut self, timestamp: SystemTime) { + self.common.initiated_at_opt = Some(timestamp); + } + + fn mark_as_ended(&mut self) { + self.common.initiated_at_opt = None; + } + as_any_impl!(); } @@ -561,7 +579,7 @@ pub(in crate::accountant) mod scanners { if let Some(timestamp) = self.scan_started_at() { return Err(ScannerError::ScanAlreadyRunning(timestamp)); } - self.common.initiated_at_opt = Some(timestamp); + self.mark_as_started(timestamp); info!( logger, "Scanning for receivables to {}", self.earning_wallet @@ -639,6 +657,14 @@ pub(in crate::accountant) mod scanners { self.common.initiated_at_opt } + fn mark_as_started(&mut self, timestamp: SystemTime) { + self.common.initiated_at_opt = Some(timestamp); + } + + fn mark_as_ended(&mut self) { + self.common.initiated_at_opt = None; + } + as_any_impl!(); } @@ -685,11 +711,19 @@ pub(in crate::accountant) mod scanners { _message: EndMessage, _logger: &Logger, ) -> Result, String> { - todo!() + panic!("Called from NullScanner"); } fn scan_started_at(&self) -> Option { - todo!() + panic!("Called from NullScanner"); + } + + fn mark_as_started(&mut self, _timestamp: SystemTime) { + panic!("Called from NullScanner"); + } + + fn mark_as_ended(&mut self) { + panic!("Called from NullScanner"); } as_any_impl!(); @@ -1711,6 +1745,33 @@ mod tests { assert_eq!(*more_money_received_params, vec![receivables]); } + // #[test] + // fn scan_finished_function_of_scanners_ends_the_scan() { + // let now = SystemTime::now(); + // let payment_thresholds = Rc::new(make_payment_thresholds_with_defaults()); + // let payable_dao_factory = PayableDaoFactoryMock::new() + // .make_result(PayableDaoMock::new()) + // .make_result(PayableDaoMock::new()); + // let pending_payable_dao_factory = PendingPayableDaoFactoryMock::new() + // .make_result(PendingPayableDaoMock::new()) + // .make_result(PendingPayableDaoMock::new()); + // let mut scanners = Scanners::new( + // Box::new(payable_dao_factory), + // Box::new(pending_payable_dao_factory), + // Box::new(ReceivableDaoMock::new()), + // Box::new(BannedDaoMock::new()), + // Rc::clone(&payment_thresholds), + // Rc::new(make_wallet("earning")), + // 0, + // Rc::new(RefCell::new(FinancialStatistics::default())), + // ); + // scanners.payable.mark_as_started(now); + // scanners.pending_payable.mark_as_started(now); + // scanners.receivable.mark_as_started(now); + // + // scanners.payable.begin_scan() + // } + fn make_pending_payable_scanner_from_daos( payable_dao: PayableDaoMock, pending_payable_dao: PendingPayableDaoMock, From 04bb7dad831742d8ede2e8dfead46f2b8051c433 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 22 Sep 2022 13:20:16 +0530 Subject: [PATCH 124/145] GH-611: reanme ScannerError to BeginScanError --- node/src/accountant/mod.rs | 20 ++++++------- node/src/accountant/scanners.rs | 50 ++++++++++++++++++--------------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 4a838cf5b..2e4594ada 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -17,7 +17,7 @@ use masq_lib::ui_gateway::{MessageBody, MessagePath, MessageTarget}; use crate::accountant::payable_dao::{Payable, PayableAccount, PayableDaoError, PayableDaoFactory}; use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDaoFactory}; use crate::accountant::receivable_dao::{ReceivableDaoError, ReceivableDaoFactory}; -use crate::accountant::scanners::scanners::{NotifyLaterForScanners, ScannerError, Scanners}; +use crate::accountant::scanners::scanners::{BeginScanError, NotifyLaterForScanners, Scanners}; use crate::banned_dao::{BannedDao, BannedDaoFactory}; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::{BlockchainError, BlockchainTransaction}; @@ -675,18 +675,18 @@ impl Accountant { .expect("BlockchainBridge is dead"); eprintln!("Message was sent to the blockchain bridge, {:?}", message); } - Err(ScannerError::CalledFromNullScanner) => { + Err(BeginScanError::CalledFromNullScanner) => { if cfg!(test) { eprintln!("Payable scan is disabled."); } else { panic!("Null Scanner shouldn't be running inside production code.") } } - Err(ScannerError::NothingToProcess) => { + Err(BeginScanError::NothingToProcess) => { eprintln!("No payable found to process. The Scan was ended."); // TODO: Do something better than just using eprintln } - Err(ScannerError::ScanAlreadyRunning(timestamp)) => { + Err(BeginScanError::ScanAlreadyRunning(timestamp)) => { info!( &self.logger, "Payable scan was already initiated at {}. \ @@ -712,18 +712,18 @@ impl Accountant { .expect("BlockchainBridge is unbound") .try_send(message) .expect("BlockchainBridge is dead"), - Err(ScannerError::CalledFromNullScanner) => { + Err(BeginScanError::CalledFromNullScanner) => { if cfg!(test) { eprintln!("Pending payable scan is disabled."); } else { panic!("Null Scanner shouldn't be running inside production code.") } } - Err(ScannerError::NothingToProcess) => { + Err(BeginScanError::NothingToProcess) => { eprintln!("No pending payable found to process. The Scan was ended."); // TODO: Do something better than just using eprintln } - Err(ScannerError::ScanAlreadyRunning(timestamp)) => { + Err(BeginScanError::ScanAlreadyRunning(timestamp)) => { info!( &self.logger, "Pending Payable scan was already initiated at {}. \ @@ -749,18 +749,18 @@ impl Accountant { .expect("BlockchainBridge is unbound") .try_send(message) .expect("BlockchainBridge is dead"), - Err(ScannerError::CalledFromNullScanner) => { + Err(BeginScanError::CalledFromNullScanner) => { if cfg!(test) { eprintln!("Receivable scan is disabled."); } else { panic!("Null Scanner shouldn't be running inside production code.") } } - Err(ScannerError::NothingToProcess) => { + Err(BeginScanError::NothingToProcess) => { eprintln!("The Scan was ended."); // TODO: Do something better than just using eprintln } - Err(ScannerError::ScanAlreadyRunning(timestamp)) => { + Err(BeginScanError::ScanAlreadyRunning(timestamp)) => { info!( &self.logger, "Receivable scan was already initiated at {}. \ diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 35c5d6a13..8495fd6a7 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -34,14 +34,12 @@ pub(in crate::accountant) mod scanners { use web3::types::TransactionReceipt; #[derive(Debug, PartialEq, Eq)] - pub enum ScannerError { + pub enum BeginScanError { NothingToProcess, ScanAlreadyRunning(SystemTime), CalledFromNullScanner, // Exclusive for tests } - type Error = ScannerError; - pub struct Scanners { pub payable: Box>, pub pending_payable: @@ -94,7 +92,7 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ) -> Result; + ) -> Result; fn scan_finished( &mut self, message: EndMessage, @@ -132,9 +130,9 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ) -> Result { + ) -> Result { if let Some(timestamp) = self.scan_started_at() { - return Err(ScannerError::ScanAlreadyRunning(timestamp)); + return Err(BeginScanError::ScanAlreadyRunning(timestamp)); } self.mark_as_started(timestamp); info!(logger, "Scanning for payables"); @@ -156,7 +154,7 @@ pub(in crate::accountant) mod scanners { ); debug!(logger, "{}", summary); match qualified_payables.is_empty() { - true => Err(ScannerError::NothingToProcess), + true => Err(BeginScanError::NothingToProcess), false => Ok(ReportAccountsPayable { accounts: qualified_payables, response_skeleton_opt, @@ -169,9 +167,6 @@ pub(in crate::accountant) mod scanners { message: SentPayable, logger: &Logger, ) -> Result, String> { - // Use the passed-in message and the internal DAO to finish the scan - // Ok(()) - let (sent_payables, blockchain_errors) = separate_early_errors(&message, logger); debug!( logger, @@ -310,9 +305,9 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ) -> Result { + ) -> Result { if let Some(timestamp) = self.scan_started_at() { - return Err(ScannerError::ScanAlreadyRunning(timestamp)); + return Err(BeginScanError::ScanAlreadyRunning(timestamp)); } self.mark_as_started(timestamp); info!(logger, "Scanning for pending payable"); @@ -323,7 +318,7 @@ pub(in crate::accountant) mod scanners { logger, "Pending payable scan ended. No pending payable found." ); - Err(ScannerError::NothingToProcess) + Err(BeginScanError::NothingToProcess) } false => { debug!( @@ -575,9 +570,9 @@ pub(in crate::accountant) mod scanners { timestamp: SystemTime, response_skeleton_opt: Option, logger: &Logger, - ) -> Result { + ) -> Result { if let Some(timestamp) = self.scan_started_at() { - return Err(ScannerError::ScanAlreadyRunning(timestamp)); + return Err(BeginScanError::ScanAlreadyRunning(timestamp)); } self.mark_as_started(timestamp); info!( @@ -702,8 +697,8 @@ pub(in crate::accountant) mod scanners { _timestamp: SystemTime, _response_skeleton_opt: Option, _logger: &Logger, - ) -> Result { - Err(ScannerError::CalledFromNullScanner) + ) -> Result { + Err(BeginScanError::CalledFromNullScanner) } fn scan_finished( @@ -806,7 +801,7 @@ pub(in crate::accountant) mod scanners { #[cfg(test)] mod tests { use crate::accountant::scanners::scanners::{ - PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, ScannerError, Scanners, + BeginScanError, PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, Scanners, }; use crate::accountant::test_utils::{ make_payables, make_pending_payable_fingerprint, make_receivable_account, BannedDaoMock, @@ -917,7 +912,10 @@ mod tests { }) ); assert_eq!(timestamp, Some(now)); - assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning(now))); + assert_eq!( + run_again_result, + Err(BeginScanError::ScanAlreadyRunning(now)) + ); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for payables", test_name), &format!( @@ -946,7 +944,7 @@ mod tests { let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); - assert_eq!(result, Err(ScannerError::NothingToProcess)); + assert_eq!(result, Err(BeginScanError::NothingToProcess)); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for payables", test_name), "Chose 0 qualified debts to pay", @@ -1084,7 +1082,10 @@ mod tests { }) ); assert_eq!(timestamp, Some(now)); - assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning(now))); + assert_eq!( + run_again_result, + Err(BeginScanError::ScanAlreadyRunning(now)) + ); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for pending payable", test_name), &format!( @@ -1112,7 +1113,7 @@ mod tests { let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); - assert_eq!(result, Err(ScannerError::NothingToProcess)); + assert_eq!(result, Err(BeginScanError::NothingToProcess)); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for pending payable", test_name), &format!( @@ -1622,7 +1623,10 @@ mod tests { }) ); assert_eq!(timestamp, Some(now)); - assert_eq!(run_again_result, Err(ScannerError::ScanAlreadyRunning(now))); + assert_eq!( + run_again_result, + Err(BeginScanError::ScanAlreadyRunning(now)) + ); TestLogHandler::new().exists_log_containing(&format!( "INFO: {}: Scanning for receivables to {}", test_name, earning_wallet From 0f0eafc86e8d2e02bd4cda76222167606eb5c348 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 22 Sep 2022 14:08:40 +0530 Subject: [PATCH 125/145] GH-611: replace Errors into panics inside scan_finished() of all the Scanners --- node/src/accountant/mod.rs | 51 +++---- node/src/accountant/scanners.rs | 248 ++++++++++++-------------------- 2 files changed, 112 insertions(+), 187 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 2e4594ada..ad308a241 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -179,17 +179,12 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: SentPayable, _ctx: &mut Self::Context) -> Self::Result { - match self.scanners.payable.scan_finished(msg, &self.logger) { - Ok(node_to_ui_msg_opt) => { - if let Some(node_to_ui_msg) = node_to_ui_msg_opt { - self.ui_message_sub - .as_ref() - .expect("UIGateway is not bound") - .try_send(node_to_ui_msg) - .expect("UIGateway is dead"); - } - } - Err(e) => panic!("Payable Scanner: {}", e), + if let Some(node_to_ui_msg) = self.scanners.payable.scan_finished(msg, &self.logger) { + self.ui_message_sub + .as_ref() + .expect("UIGateway is not bound") + .try_send(node_to_ui_msg) + .expect("UIGateway is dead"); } } } @@ -198,21 +193,16 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ReportTransactionReceipts, _ctx: &mut Self::Context) -> Self::Result { - match self + if let Some(node_to_ui_msg) = self .scanners .pending_payable .scan_finished(msg, &self.logger) { - Ok(node_to_ui_msg_opt) => { - if let Some(node_to_ui_msg) = node_to_ui_msg_opt { - self.ui_message_sub - .as_ref() - .expect("UIGateway is not bound") - .try_send(node_to_ui_msg) - .expect("UIGateway is dead"); - } - } - Err(e) => panic!("PendingPayable Scanner: {}", e), + self.ui_message_sub + .as_ref() + .expect("UIGateway is not bound") + .try_send(node_to_ui_msg) + .expect("UIGateway is dead"); } } } @@ -221,17 +211,12 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ReceivedPayments, _ctx: &mut Self::Context) -> Self::Result { - match self.scanners.receivable.scan_finished(msg, &self.logger) { - Ok(node_to_ui_msg_opt) => { - if let Some(node_to_ui_msg) = node_to_ui_msg_opt { - self.ui_message_sub - .as_ref() - .expect("UIGateway is not bound") - .try_send(node_to_ui_msg) - .expect("UIGateway is dead"); - } - } - Err(e) => panic!("Receivable Scanner: {}", e), + if let Some(node_to_ui_msg) = self.scanners.receivable.scan_finished(msg, &self.logger) { + self.ui_message_sub + .as_ref() + .expect("UIGateway is not bound") + .try_send(node_to_ui_msg) + .expect("UIGateway is dead"); } } } diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 8495fd6a7..f45f1bba2 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -97,7 +97,7 @@ pub(in crate::accountant) mod scanners { &mut self, message: EndMessage, logger: &Logger, - ) -> Result, String>; + ) -> Option; fn scan_started_at(&self) -> Option; fn mark_as_started(&mut self, timestamp: SystemTime); fn mark_as_ended(&mut self); @@ -166,7 +166,7 @@ pub(in crate::accountant) mod scanners { &mut self, message: SentPayable, logger: &Logger, - ) -> Result, String> { + ) -> Option { let (sent_payables, blockchain_errors) = separate_early_errors(&message, logger); debug!( logger, @@ -176,18 +176,16 @@ pub(in crate::accountant) mod scanners { sent_payables.len() + blockchain_errors.len() ); - self.handle_sent_payables(sent_payables, logger)?; - self.handle_blockchain_errors(blockchain_errors, logger)?; + self.handle_sent_payables(sent_payables, logger); + self.handle_blockchain_errors(blockchain_errors, logger); - let message_opt = match message.response_skeleton_opt { + match message.response_skeleton_opt { Some(response_skeleton) => Some(NodeToUiMessage { target: MessageTarget::ClientId(response_skeleton.client_id), body: UiScanResponse {}.tmb(response_skeleton.context_id), }), None => None, - }; - - Ok(message_opt) + } } fn scan_started_at(&self) -> Option { @@ -218,11 +216,7 @@ pub(in crate::accountant) mod scanners { } } - fn handle_sent_payables( - &self, - sent_payables: Vec, - logger: &Logger, - ) -> Result<(), String> { + fn handle_sent_payables(&self, sent_payables: Vec, logger: &Logger) { for payable in sent_payables { if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(payable.tx_hash) { if let Err(e) = self @@ -230,18 +224,18 @@ pub(in crate::accountant) mod scanners { .as_ref() .mark_pending_payable_rowid(&payable.to, rowid) { - return Err(format!( + panic!( "Was unable to create a mark in payables for a new pending payable \ '{}' due to '{:?}'", payable.tx_hash, e - )); + ); } } else { - return Err(format!( + panic!( "Payable fingerprint for {} doesn't exist but should by now; \ system unreliable", payable.tx_hash - )); + ); }; debug!( @@ -249,15 +243,13 @@ pub(in crate::accountant) mod scanners { "Payable '{}' has been marked as pending in the payable table", payable.tx_hash ) } - - Ok(()) } fn handle_blockchain_errors( &self, blockchain_errors: Vec, logger: &Logger, - ) -> Result<(), String> { + ) { for blockchain_error in blockchain_errors { if let Some(hash) = blockchain_error.carries_transaction_hash() { if let Some(rowid) = self.pending_payable_dao.fingerprint_rowid(hash) { @@ -266,11 +258,11 @@ pub(in crate::accountant) mod scanners { "Deleting an existing backup for a failed transaction {}", hash ); if let Err(e) = self.pending_payable_dao.delete_fingerprint(rowid) { - return Err(format!( + panic!( "Database unmaintainable; payable fingerprint deletion for \ transaction {:?} has stayed undone due to {:?}", hash, e - )); + ); }; }; @@ -286,8 +278,6 @@ pub(in crate::accountant) mod scanners { ) }; } - - Ok(()) } } @@ -338,7 +328,7 @@ pub(in crate::accountant) mod scanners { &mut self, message: ReportTransactionReceipts, logger: &Logger, - ) -> Result, String> { + ) -> Option { // TODO: Make accountant to handle empty vector. Maybe log it as an error. debug!( logger, @@ -346,17 +336,15 @@ pub(in crate::accountant) mod scanners { message.fingerprints_with_receipts.len() ); let statuses = self.handle_pending_transaction_with_its_receipt(&message, logger); - self.process_transaction_by_status(statuses, logger)?; + self.process_transaction_by_status(statuses, logger); - let message_opt = match message.response_skeleton_opt { + match message.response_skeleton_opt { Some(response_skeleton) => Some(NodeToUiMessage { target: MessageTarget::ClientId(response_skeleton.client_id), body: UiScanResponse {}.tmb(response_skeleton.context_id), }), None => None, - }; - - Ok(message_opt) + } } fn scan_started_at(&self) -> Option { @@ -441,45 +429,41 @@ pub(in crate::accountant) mod scanners { &mut self, statuses: Vec, logger: &Logger, - ) -> Result<(), String> { + ) { for status in statuses { match status { PendingTransactionStatus::StillPending(transaction_id) => { - self.update_payable_fingerprint(transaction_id, logger)?; + self.update_payable_fingerprint(transaction_id, logger); } PendingTransactionStatus::Failure(transaction_id) => { - self.order_cancel_failed_transaction(transaction_id, logger)?; + self.order_cancel_failed_transaction(transaction_id, logger); } PendingTransactionStatus::Confirmed(fingerprint) => { - self.order_confirm_transaction(fingerprint, logger)?; + self.order_confirm_transaction(fingerprint, logger); } } } - - Ok(()) } pub(crate) fn update_payable_fingerprint( &self, pending_payable_id: PendingPayableId, logger: &Logger, - ) -> Result<(), String> { - match self + ) { + if let Err(e) = self .pending_payable_dao .update_fingerprint(pending_payable_id.rowid) { - Ok(_) => { - trace!( - logger, - "Updated record for rowid: {} ", - pending_payable_id.rowid - ); - Ok(()) - } - Err(e) => Err(format!( + panic!( "Failure on updating payable fingerprint '{:?}' due to {:?}", pending_payable_id.hash, e - )), + ); + } else { + trace!( + logger, + "Updated record for rowid: {} ", + pending_payable_id.rowid + ); } } @@ -487,23 +471,20 @@ pub(in crate::accountant) mod scanners { &self, transaction_id: PendingPayableId, logger: &Logger, - ) -> Result<(), String> { - match self.pending_payable_dao.mark_failure(transaction_id.rowid) { - Ok(_) => { - warning!( + ) { + if let Err(e) = self.pending_payable_dao.mark_failure(transaction_id.rowid) { + panic!( + "Unsuccessful attempt for transaction {} to mark fatal error at payable \ + fingerprint due to {:?}; database unreliable", + transaction_id.hash, e + ) + } else { + warning!( logger, "Broken transaction {} left with an error mark; you should take over the care \ of this transaction to make sure your debts will be paid because there is no \ automated process that can fix this without you", transaction_id.hash ); - - Ok(()) - } - Err(e) => Err(format!( - "Unsuccessful attempt for transaction {} to mark fatal error at payable \ - fingerprint due to {:?}; database unreliable", - transaction_id.hash, e - )), } } @@ -511,7 +492,7 @@ pub(in crate::accountant) mod scanners { &mut self, pending_payable_fingerprint: PendingPayableFingerprint, logger: &Logger, - ) -> Result<(), String> { + ) { let hash = pending_payable_fingerprint.hash; let amount = pending_payable_fingerprint.amount; let rowid = pending_payable_fingerprint @@ -522,10 +503,10 @@ pub(in crate::accountant) mod scanners { .payable_dao .transaction_confirmed(&pending_payable_fingerprint) { - Err(format!( + panic!( "Was unable to uncheck pending payable '{}' after confirmation due to '{:?}'", hash, e - )) + ); } else { let mut financial_statistics = self.financial_statistics.as_ref().borrow().clone(); financial_statistics.total_paid_payable += amount; @@ -535,18 +516,16 @@ pub(in crate::accountant) mod scanners { "Confirmation of transaction {}; record for payable was modified", hash ); if let Err(e) = self.pending_payable_dao.delete_fingerprint(rowid) { - Err(format!( + panic!( "Was unable to delete payable fingerprint '{}' after successful transaction \ due to '{:?}'", hash, e - )) + ); } else { info!( logger, "Transaction {:?} has gone through the whole confirmation process succeeding", hash ); - - Ok(()) } } } @@ -619,7 +598,7 @@ pub(in crate::accountant) mod scanners { &mut self, message: ReceivedPayments, logger: &Logger, - ) -> Result, String> { + ) -> Option { if message.payments.is_empty() { warning!( logger, @@ -637,15 +616,13 @@ pub(in crate::accountant) mod scanners { self.financial_statistics.replace(financial_statistics); } - let node_to_ui_message_opt = match message.response_skeleton_opt { + match message.response_skeleton_opt { None => None, Some(response_skeleton) => Some(NodeToUiMessage { target: MessageTarget::ClientId(response_skeleton.client_id), body: UiScanResponse {}.tmb(response_skeleton.context_id), }), - }; - - Ok(node_to_ui_message_opt) + } } fn scan_started_at(&self) -> Option { @@ -705,7 +682,7 @@ pub(in crate::accountant) mod scanners { &mut self, _message: EndMessage, _logger: &Logger, - ) -> Result, String> { + ) -> Option { panic!("Called from NullScanner"); } @@ -952,6 +929,9 @@ mod tests { } #[test] + #[should_panic( + expected = "Payable fingerprint for 0x0000…0315 doesn't exist but should by now; system unreliable" + )] fn payable_scanner_throws_error_when_fingerprint_is_not_found() { init_test_logging(); let now_system = SystemTime::now(); @@ -969,12 +949,15 @@ mod tests { response_skeleton_opt: None, }; - let result = subject.scan_finished(sent_payable, &Logger::new("test")); - - assert_eq!(result, Err("Payable fingerprint for 0x0000…0315 doesn't exist but should by now; system unreliable".to_string())); + let _ = subject.scan_finished(sent_payable, &Logger::new("test")); } #[test] + #[should_panic( + expected = "Database unmaintainable; payable fingerprint deletion for transaction \ + 0x000000000000000000000000000000000000000000000000000000000000007b has stayed \ + undone due to RecordDeletion(\"we slept over, sorry\")" + )] fn payable_scanner_throws_error_when_dealing_with_failed_payment_fails_to_delete_the_existing_pending_payable_fingerprint( ) { let rowid = 4; @@ -997,20 +980,14 @@ mod tests { Rc::new(make_payment_thresholds_with_defaults()), ); - let result = subject.scan_finished(sent_payable, &Logger::new("test")); - - assert_eq!( - result, - Err( - "Database unmaintainable; payable fingerprint deletion for transaction \ - 0x000000000000000000000000000000000000000000000000000000000000007b has stayed \ - undone due to RecordDeletion(\"we slept over, sorry\")" - .to_string() - ) - ); + let _ = subject.scan_finished(sent_payable, &Logger::new("test")); } #[test] + #[should_panic( + expected = "Was unable to create a mark in payables for a new pending payable '0x0000…007b' \ + due to 'SignConversion(9999999999999)'" + )] fn payable_scanner_throws_error_when_it_fails_to_make_a_mark_in_payables() { let payable = Payable::new( make_wallet("blah"), @@ -1032,16 +1009,7 @@ mod tests { response_skeleton_opt: None, }; - let result = subject.scan_finished(sent_payable, &Logger::new("test")); - - assert_eq!( - result, - Err( - "Was unable to create a mark in payables for a new pending payable '0x0000…007b' \ - due to 'SignConversion(9999999999999)'" - .to_string() - ) - ) + let _ = subject.scan_finished(sent_payable, &Logger::new("test")); } #[test] @@ -1290,14 +1258,16 @@ mod tests { make_pending_payable_scanner_from_daos(PayableDaoMock::new(), pending_payable_dao); let transaction_id = PendingPayableId { hash, rowid }; - let result = subject.update_payable_fingerprint(transaction_id, &Logger::new(test_name)); + subject.update_payable_fingerprint(transaction_id, &Logger::new(test_name)); let update_after_cycle_params = update_after_cycle_params_arc.lock().unwrap(); - assert_eq!(result, Ok(())); assert_eq!(*update_after_cycle_params, vec![rowid]) } #[test] + #[should_panic(expected = "Failure on updating payable fingerprint \ + '0x000000000000000000000000000000000000000000000000000000000006c9d8' \ + due to UpdateFailed(\"yeah, bad\")")] fn update_payable_fingerprint_sad_path() { let test_name = "update_payable_fingerprint_sad_path"; let hash = H256::from_uint(&U256::from(444888)); @@ -1309,15 +1279,7 @@ mod tests { make_pending_payable_scanner_from_daos(PayableDaoMock::new(), pending_payable_dao); let transaction_id = PendingPayableId { hash, rowid }; - let result = subject.update_payable_fingerprint(transaction_id, &Logger::new(test_name)); - - assert_eq!( - result, - Err("Failure on updating payable fingerprint \ - '0x000000000000000000000000000000000000000000000000000000000006c9d8' \ - due to UpdateFailed(\"yeah, bad\")" - .to_string()) - ) + subject.update_payable_fingerprint(transaction_id, &Logger::new(test_name)); } #[test] @@ -1336,11 +1298,9 @@ mod tests { rowid, }; - let result = subject - .order_cancel_failed_transaction(transaction_id, &Logger::new("CancelPendingTxOk")); + subject.order_cancel_failed_transaction(transaction_id, &Logger::new("CancelPendingTxOk")); let mark_failure_params = mark_failure_params_arc.lock().unwrap(); - assert_eq!(result, Ok(())); assert_eq!(*mark_failure_params, vec![rowid]); TestLogHandler::new().exists_log_containing( "WARN: CancelPendingTxOk: Broken transaction 0x051a…8c19 left with an error \ @@ -1350,6 +1310,10 @@ mod tests { } #[test] + #[should_panic( + expected = "Unsuccessful attempt for transaction 0x051a…8c19 to mark fatal error at payable \ + fingerprint due to UpdateFailed(\"no no no\"); database unreliable" + )] fn order_cancel_pending_transaction_throws_error_when_it_fails_to_mark_failure() { let payable_dao = PayableDaoMock::default().transaction_canceled_result(Ok(())); let pending_payable_dao = PendingPayableDaoMock::default().mark_failure_result(Err( @@ -1360,20 +1324,14 @@ mod tests { let hash = H256::from("sometransactionhash".keccak256()); let transaction_id = PendingPayableId { hash, rowid }; - let result = subject - .order_cancel_failed_transaction(transaction_id, &Logger::new("CancelPendingTxOk")); - - assert_eq!( - result, - Err( - "Unsuccessful attempt for transaction 0x051a…8c19 to mark fatal error at payable \ - fingerprint due to UpdateFailed(\"no no no\"); database unreliable" - .to_string() - ) - ) + subject.order_cancel_failed_transaction(transaction_id, &Logger::new("CancelPendingTxOk")); } #[test] + #[should_panic( + expected = "Was unable to delete payable fingerprint '0x0000…0315' after successful \ + transaction due to 'RecordDeletion(\"the database is fooling around with us\")'" + )] fn handle_confirm_pending_transaction_throws_error_while_deleting_pending_payable_fingerprint() { init_test_logging(); @@ -1391,17 +1349,7 @@ mod tests { pending_payable_fingerprint.rowid_opt = Some(rowid); pending_payable_fingerprint.hash = hash; - let result = - subject.order_confirm_transaction(pending_payable_fingerprint, &Logger::new(test_name)); - - assert_eq!( - result, - Err( - "Was unable to delete payable fingerprint '0x0000…0315' after successful \ - transaction due to 'RecordDeletion(\"the database is fooling around with us\")'" - .to_string() - ) - ) + subject.order_confirm_transaction(pending_payable_fingerprint, &Logger::new(test_name)); } #[test] @@ -1430,7 +1378,7 @@ mod tests { process_error: None, }; - let result = subject.order_confirm_transaction( + subject.order_confirm_transaction( pending_payable_fingerprint.clone(), &Logger::new(test_name), ); @@ -1440,7 +1388,6 @@ mod tests { delete_pending_payable_fingerprint_params_arc .lock() .unwrap(); - assert_eq!(result, Ok(())); assert_eq!( *transaction_confirmed_params, vec![pending_payable_fingerprint] @@ -1483,17 +1430,19 @@ mod tests { financial_statistics.total_paid_payable += 1111; subject.financial_statistics.replace(financial_statistics); - let result = - subject.order_confirm_transaction(fingerprint.clone(), &Logger::new(test_name)); + subject.order_confirm_transaction(fingerprint.clone(), &Logger::new(test_name)); let total_paid_payable = subject.financial_statistics().total_paid_payable; let transaction_confirmed_params = transaction_confirmed_params_arc.lock().unwrap(); - assert_eq!(result, Ok(())); assert_eq!(total_paid_payable, 1111 + 5478); assert_eq!(*transaction_confirmed_params, vec![fingerprint]) } #[test] + #[should_panic( + expected = "Was unable to uncheck pending payable '0x0000…0315' after confirmation due to \ + 'RusqliteError(\"record change not successful\")'" + )] fn order_confirm_transaction_throws_error_on_unchecking_payable_table() { init_test_logging(); let test_name = "order_confirm_transaction_throws_error_on_unchecking_payable_table"; @@ -1508,16 +1457,7 @@ mod tests { fingerprint.rowid_opt = Some(rowid); fingerprint.hash = hash; - let result = subject.order_confirm_transaction(fingerprint, &Logger::new(test_name)); - - assert_eq!( - result, - Err( - "Was unable to uncheck pending payable '0x0000…0315' after confirmation due to \ - 'RusqliteError(\"record change not successful\")'" - .to_string() - ) - ) + subject.order_confirm_transaction(fingerprint, &Logger::new(test_name)); } #[test] @@ -1571,10 +1511,10 @@ mod tests { response_skeleton_opt: None, }; - let result = subject.scan_finished(msg, &Logger::new(test_name)); + let message_opt = subject.scan_finished(msg, &Logger::new(test_name)); let transaction_confirmed_params = transaction_confirmed_params_arc.lock().unwrap(); - assert_eq!(result, Ok(None)); + assert_eq!(message_opt, None); assert_eq!( *transaction_confirmed_params, vec![fingerprint_1, fingerprint_2] @@ -1703,9 +1643,9 @@ mod tests { response_skeleton_opt: None, }; - let result = subject.scan_finished(msg, &Logger::new(test_name)); + let message_opt = subject.scan_finished(msg, &Logger::new(test_name)); - assert_eq!(result, Ok(None)); + assert_eq!(message_opt, None); TestLogHandler::new().exists_log_containing(&format!( "WARN: {test_name}: Handling received payments we got zero payments but \ expected some, skipping database operations" @@ -1740,11 +1680,11 @@ mod tests { response_skeleton_opt: None, }; - let result = subject.scan_finished(msg, &Logger::new(test_name)); + let message_opt = subject.scan_finished(msg, &Logger::new(test_name)); let total_paid_receivable = subject.financial_statistics().total_paid_receivable; let more_money_received_params = more_money_received_params_arc.lock().unwrap(); - assert_eq!(result, Ok(None)); + assert_eq!(message_opt, None); assert_eq!(total_paid_receivable, 2222 + 45780 + 33345); assert_eq!(*more_money_received_params, vec![receivables]); } From 249097aef90870d94f4874d4e6099144eb867268 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 22 Sep 2022 14:32:01 +0530 Subject: [PATCH 126/145] GH-611: modify tests for Scanners to assert whether scan_finished() stops the scan --- node/src/accountant/mod.rs | 46 ---------------------------- node/src/accountant/scanners.rs | 54 +++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index ad308a241..cd58965cf 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -2957,52 +2957,6 @@ mod tests { assert_eq!(system.run(), 0); } - #[test] - fn handle_sent_payable_receives_two_payments_one_incorrect_and_one_correct() { - //the two failures differ in the logged messages - init_test_logging(); - let fingerprint_rowid_params_arc = Arc::new(Mutex::new(vec![])); - let now_system = SystemTime::now(); - let payable_1 = Err(BlockchainError::InvalidResponse); - let payable_2_rowid = 126; - let payable_hash_2 = H256::from_uint(&U256::from(166)); - let payable_2 = Payable::new(make_wallet("booga"), 6789, payable_hash_2, now_system); - let payable_3 = Err(BlockchainError::TransactionFailed { - msg: "closing hours, sorry".to_string(), - hash_opt: None, - }); - let sent_payable = SentPayable { - payable: vec![payable_1, Ok(payable_2.clone()), payable_3], - response_skeleton_opt: None, - }; - let payable_dao = PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(())); - let pending_payable_dao = PendingPayableDaoMock::default() - .fingerprint_rowid_params(&fingerprint_rowid_params_arc) - .fingerprint_rowid_result(Some(payable_2_rowid)); - let mut subject = AccountantBuilder::default() - .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Payable Scanner - .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner - .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant - .pending_payable_dao(pending_payable_dao) // For Scanner - .pending_payable_dao(PendingPayableDaoMock::new()) // For Scanner - .build(); - - let _result = subject - .scanners - .payable - .scan_finished(sent_payable, &Logger::new("Accountant")); - - let fingerprint_rowid_params = fingerprint_rowid_params_arc.lock().unwrap(); - assert_eq!(*fingerprint_rowid_params, vec![payable_hash_2]); //we know the other two errors are associated with an initiated transaction having a backup - let log_handler = TestLogHandler::new(); - log_handler.exists_log_containing("WARN: Accountant: Outbound transaction failure due to 'InvalidResponse'. Please check your blockchain service URL configuration."); - log_handler.exists_log_containing("DEBUG: Accountant: Payable '0x0000…00a6' has been marked as pending in the payable table"); - log_handler.exists_log_containing("WARN: Accountant: Encountered transaction error at this end: 'TransactionFailed { msg: \"closing hours, sorry\", hash_opt: None }'"); - log_handler.exists_log_containing("DEBUG: Accountant: Forgetting a transaction attempt that even did not reach the signing stage"); - // TODO: Assert subject.scan_for_payables_in_progress [No scan in progress] - } - #[test] #[should_panic( expected = "panic message (processed with: node_lib::sub_lib::utils::crash_request_analyzer)" diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index f45f1bba2..11191f4ce 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -179,6 +179,7 @@ pub(in crate::accountant) mod scanners { self.handle_sent_payables(sent_payables, logger); self.handle_blockchain_errors(blockchain_errors, logger); + self.mark_as_ended(); match message.response_skeleton_opt { Some(response_skeleton) => Some(NodeToUiMessage { target: MessageTarget::ClientId(response_skeleton.client_id), @@ -338,6 +339,7 @@ pub(in crate::accountant) mod scanners { let statuses = self.handle_pending_transaction_with_its_receipt(&message, logger); self.process_transaction_by_status(statuses, logger); + self.mark_as_ended(); match message.response_skeleton_opt { Some(response_skeleton) => Some(NodeToUiMessage { target: MessageTarget::ClientId(response_skeleton.client_id), @@ -616,6 +618,7 @@ pub(in crate::accountant) mod scanners { self.financial_statistics.replace(financial_statistics); } + self.mark_as_ended(); match message.response_skeleton_opt { None => None, Some(response_skeleton) => Some(NodeToUiMessage { @@ -1012,6 +1015,49 @@ mod tests { let _ = subject.scan_finished(sent_payable, &Logger::new("test")); } + #[test] + fn payable_scanner_handles_sent_payable_message() { + //the two failures differ in the logged messages + init_test_logging(); + let fingerprint_rowid_params_arc = Arc::new(Mutex::new(vec![])); + let now_system = SystemTime::now(); + let payable_1 = Err(BlockchainError::InvalidResponse); + let payable_2_rowid = 126; + let payable_hash_2 = H256::from_uint(&U256::from(166)); + let payable_2 = Payable::new(make_wallet("booga"), 6789, payable_hash_2, now_system); + let payable_3 = Err(BlockchainError::TransactionFailed { + msg: "closing hours, sorry".to_string(), + hash_opt: None, + }); + let sent_payable = SentPayable { + payable: vec![payable_1, Ok(payable_2.clone()), payable_3], + response_skeleton_opt: None, + }; + let payable_dao = PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(())); + let pending_payable_dao = PendingPayableDaoMock::default() + .fingerprint_rowid_params(&fingerprint_rowid_params_arc) + .fingerprint_rowid_result(Some(payable_2_rowid)); + let mut subject = PayableScanner::new( + Box::new(payable_dao), + Box::new(pending_payable_dao), + Rc::new(make_payment_thresholds_with_defaults()), + ); + subject.mark_as_started(SystemTime::now()); + + let message_opt = + subject.scan_finished(sent_payable, &Logger::new("PayableScannerScanFinished")); + + let fingerprint_rowid_params = fingerprint_rowid_params_arc.lock().unwrap(); + assert_eq!(message_opt, None); + assert_eq!(subject.scan_started_at(), None); + assert_eq!(*fingerprint_rowid_params, vec![payable_hash_2]); //we know the other two errors are associated with an initiated transaction having a backup + let log_handler = TestLogHandler::new(); + log_handler.exists_log_containing("WARN: PayableScannerScanFinished: Outbound transaction failure due to 'InvalidResponse'. Please check your blockchain service URL configuration."); + log_handler.exists_log_containing("DEBUG: PayableScannerScanFinished: Payable '0x0000…00a6' has been marked as pending in the payable table"); + log_handler.exists_log_containing("WARN: PayableScannerScanFinished: Encountered transaction error at this end: 'TransactionFailed { msg: \"closing hours, sorry\", hash_opt: None }'"); + log_handler.exists_log_containing("DEBUG: PayableScannerScanFinished: Forgetting a transaction attempt that even did not reach the signing stage"); + } + #[test] fn pending_payable_scanner_can_initiate_a_scan() { init_test_logging(); @@ -1510,6 +1556,7 @@ mod tests { ], response_skeleton_opt: None, }; + subject.mark_as_started(SystemTime::now()); let message_opt = subject.scan_finished(msg, &Logger::new(test_name)); @@ -1519,6 +1566,7 @@ mod tests { *transaction_confirmed_params, vec![fingerprint_1, fingerprint_2] ); + assert_eq!(subject.scan_started_at(), None); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!( "INFO: {}: Transaction {:?} has gone through the whole confirmation process succeeding", @@ -1653,7 +1701,7 @@ mod tests { } #[test] - fn total_paid_receivable_rises_with_each_bill_paid() { + fn receivable_scanner_handles_received_payments_message() { let test_name = "total_paid_receivable_rises_with_each_bill_paid"; let more_money_received_params_arc = Arc::new(Mutex::new(vec![])); let receivable_dao = ReceivableDaoMock::new() @@ -1679,12 +1727,14 @@ mod tests { payments: receivables.clone(), response_skeleton_opt: None, }; + subject.mark_as_started(SystemTime::now()); let message_opt = subject.scan_finished(msg, &Logger::new(test_name)); let total_paid_receivable = subject.financial_statistics().total_paid_receivable; let more_money_received_params = more_money_received_params_arc.lock().unwrap(); assert_eq!(message_opt, None); + assert_eq!(subject.scan_started_at(), None); assert_eq!(total_paid_receivable, 2222 + 45780 + 33345); assert_eq!(*more_money_received_params, vec![receivables]); } @@ -1713,7 +1763,7 @@ mod tests { // scanners.pending_payable.mark_as_started(now); // scanners.receivable.mark_as_started(now); // - // scanners.payable.begin_scan() + // scanners.payable.scan_finished() // } fn make_pending_payable_scanner_from_daos( From ff347d336eda7c0da234560f2910d89c8721e0fa Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 22 Sep 2022 15:53:00 +0530 Subject: [PATCH 127/145] GH-611: add logging when scan has ended --- node/src/accountant/scanners.rs | 69 ++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 11191f4ce..061525e45 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -100,7 +100,7 @@ pub(in crate::accountant) mod scanners { ) -> Option; fn scan_started_at(&self) -> Option; fn mark_as_started(&mut self, timestamp: SystemTime); - fn mark_as_ended(&mut self); + fn mark_as_ended(&mut self, logger: &Logger); as_any_dcl!(); } @@ -179,7 +179,7 @@ pub(in crate::accountant) mod scanners { self.handle_sent_payables(sent_payables, logger); self.handle_blockchain_errors(blockchain_errors, logger); - self.mark_as_ended(); + self.mark_as_ended(logger); match message.response_skeleton_opt { Some(response_skeleton) => Some(NodeToUiMessage { target: MessageTarget::ClientId(response_skeleton.client_id), @@ -197,8 +197,18 @@ pub(in crate::accountant) mod scanners { self.common.initiated_at_opt = Some(timestamp); } - fn mark_as_ended(&mut self) { - self.common.initiated_at_opt = None; + fn mark_as_ended(&mut self, logger: &Logger) { + match self.scan_started_at() { + Some(timestamp) => { + let elapsed_time = SystemTime::now() + .duration_since(timestamp) + .expect("Unable to calculate elapsed time for the scan.") + .as_millis(); + info!(logger, "The Payable scan ended in {elapsed_time}ms."); + self.common.initiated_at_opt = None; + } + None => error!(logger, "The scan_finished() was called for Payable scanner but timestamp was not found"), + }; } as_any_impl!(); @@ -339,7 +349,7 @@ pub(in crate::accountant) mod scanners { let statuses = self.handle_pending_transaction_with_its_receipt(&message, logger); self.process_transaction_by_status(statuses, logger); - self.mark_as_ended(); + self.mark_as_ended(logger); match message.response_skeleton_opt { Some(response_skeleton) => Some(NodeToUiMessage { target: MessageTarget::ClientId(response_skeleton.client_id), @@ -357,8 +367,21 @@ pub(in crate::accountant) mod scanners { self.common.initiated_at_opt = Some(timestamp); } - fn mark_as_ended(&mut self) { - self.common.initiated_at_opt = None; + fn mark_as_ended(&mut self, logger: &Logger) { + match self.scan_started_at() { + Some(timestamp) => { + let elapsed_time = SystemTime::now() + .duration_since(timestamp) + .expect("Unable to calculate elapsed time for the scan.") + .as_millis(); + info!( + logger, + "The Pending Payable scan ended in {elapsed_time}ms." + ); + self.common.initiated_at_opt = None; + } + None => error!(logger, "The scan_finished() was called for Pending Payable scanner but timestamp was not found"), + }; } as_any_impl!(); @@ -618,7 +641,7 @@ pub(in crate::accountant) mod scanners { self.financial_statistics.replace(financial_statistics); } - self.mark_as_ended(); + self.mark_as_ended(logger); match message.response_skeleton_opt { None => None, Some(response_skeleton) => Some(NodeToUiMessage { @@ -636,8 +659,18 @@ pub(in crate::accountant) mod scanners { self.common.initiated_at_opt = Some(timestamp); } - fn mark_as_ended(&mut self) { - self.common.initiated_at_opt = None; + fn mark_as_ended(&mut self, logger: &Logger) { + match self.scan_started_at() { + Some(timestamp) => { + let elapsed_time = SystemTime::now() + .duration_since(timestamp) + .expect("Unable to calculate elapsed time for the scan.") + .as_millis(); + info!(logger, "The Receivable scan ended in {elapsed_time}ms."); + self.common.initiated_at_opt = None; + } + None => error!(logger, "The scan_finished() was called for Receivable scanner but timestamp was not found"), + }; } as_any_impl!(); @@ -697,7 +730,7 @@ pub(in crate::accountant) mod scanners { panic!("Called from NullScanner"); } - fn mark_as_ended(&mut self) { + fn mark_as_ended(&mut self, _logger: &Logger) { panic!("Called from NullScanner"); } @@ -1019,6 +1052,7 @@ mod tests { fn payable_scanner_handles_sent_payable_message() { //the two failures differ in the logged messages init_test_logging(); + let elapsed_time = 10; let fingerprint_rowid_params_arc = Arc::new(Mutex::new(vec![])); let now_system = SystemTime::now(); let payable_1 = Err(BlockchainError::InvalidResponse); @@ -1042,7 +1076,7 @@ mod tests { Box::new(pending_payable_dao), Rc::new(make_payment_thresholds_with_defaults()), ); - subject.mark_as_started(SystemTime::now()); + subject.mark_as_started(SystemTime::now().sub(Duration::from_millis(elapsed_time))); let message_opt = subject.scan_finished(sent_payable, &Logger::new("PayableScannerScanFinished")); @@ -1056,6 +1090,8 @@ mod tests { log_handler.exists_log_containing("DEBUG: PayableScannerScanFinished: Payable '0x0000…00a6' has been marked as pending in the payable table"); log_handler.exists_log_containing("WARN: PayableScannerScanFinished: Encountered transaction error at this end: 'TransactionFailed { msg: \"closing hours, sorry\", hash_opt: None }'"); log_handler.exists_log_containing("DEBUG: PayableScannerScanFinished: Forgetting a transaction attempt that even did not reach the signing stage"); + log_handler + .exists_log_containing("INFO: PayableScannerScanFinished: The Payable scan ended"); } #[test] @@ -1567,7 +1603,7 @@ mod tests { vec![fingerprint_1, fingerprint_2] ); assert_eq!(subject.scan_started_at(), None); - TestLogHandler::new().assert_logs_match_in_order(vec![ + TestLogHandler::new().assert_logs_contain_in_order(vec![ &format!( "INFO: {}: Transaction {:?} has gone through the whole confirmation process succeeding", test_name, transaction_hash_1 @@ -1576,6 +1612,10 @@ mod tests { "INFO: {}: Transaction {:?} has gone through the whole confirmation process succeeding", test_name, transaction_hash_2 ), + &format!( + "INFO: {}: The Pending Payable scan ended", + test_name + ), ]); } @@ -1702,6 +1742,7 @@ mod tests { #[test] fn receivable_scanner_handles_received_payments_message() { + init_test_logging(); let test_name = "total_paid_receivable_rises_with_each_bill_paid"; let more_money_received_params_arc = Arc::new(Mutex::new(vec![])); let receivable_dao = ReceivableDaoMock::new() @@ -1737,6 +1778,8 @@ mod tests { assert_eq!(subject.scan_started_at(), None); assert_eq!(total_paid_receivable, 2222 + 45780 + 33345); assert_eq!(*more_money_received_params, vec![receivables]); + TestLogHandler::new() + .exists_log_containing(&format!("INFO: {}: The Receivable scan ended", test_name)); } // #[test] From 4faf4d41d83050be128f6039fa7d61cd1c48418e Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Thu, 22 Sep 2022 17:55:39 +0530 Subject: [PATCH 128/145] GH-611: fix test for the periodical scanning of Payable Scanner --- node/src/accountant/mod.rs | 50 +++++++-------------------------- node/src/accountant/scanners.rs | 7 +++-- 2 files changed, 15 insertions(+), 42 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index cd58965cf..faf44643f 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1916,43 +1916,30 @@ mod tests { } #[test] - #[ignore] fn periodical_scanning_for_payable_works() { //in the very first round we scan without waiting but we cannot find any payable records init_test_logging(); let test_name = "accountant_payable_scan_timer_triggers_periodical_scanning_for_payables"; let non_pending_payables_params_arc = Arc::new(Mutex::new(vec![])); let notify_later_payables_params_arc = Arc::new(Mutex::new(vec![])); - let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let system = System::new(test_name); let mut config = bc_from_earning_wallet(make_wallet("hi")); config.scan_intervals_opt = Some(ScanIntervals { payable_scan_interval: Duration::from_millis(97), - receivable_scan_interval: Duration::from_secs(100), - pending_payable_scan_interval: Duration::from_secs(100), + receivable_scan_interval: Duration::from_secs(100), // We'll never run this scanner + pending_payable_scan_interval: Duration::from_secs(100), // We'll never run this scanner }); - let now = to_time_t(SystemTime::now()); - // slightly above minimum balance, to the right of the curve (time intersection) - let account = PayableAccount { - wallet: make_wallet("wallet"), - balance: DEFAULT_PAYMENT_THRESHOLDS.debt_threshold_gwei + 5, - last_paid_timestamp: from_time_t( - now - DEFAULT_PAYMENT_THRESHOLDS.threshold_interval_sec - 10, - ), - pending_payable_opt: None, - }; let mut payable_dao = PayableDaoMock::new() .non_pending_payables_params(&non_pending_payables_params_arc) - .non_pending_payables_result(vec![]) - .non_pending_payables_result(vec![account.clone()]); + .non_pending_payables_result(vec![]); payable_dao.have_non_pending_payables_shut_down_the_system = true; - let peer_actors = peer_actors_builder() - .blockchain_bridge(blockchain_bridge) - .build(); + let peer_actors = peer_actors_builder().build(); + SystemKillerActor::new(Duration::from_secs(10)).start(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(PayableDaoMock::new()) // For Scanner - .payable_dao(payable_dao) // For Accountant + .payable_dao(PayableDaoMock::new()) // For Accountant + .payable_dao(payable_dao) // For Payable Scanner + .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); subject.logger = Logger::new(test_name); subject.scanners.pending_payable = Box::new(NullScanner::new()); //skipping @@ -1970,19 +1957,8 @@ mod tests { system.run(); let non_pending_payables_params = non_pending_payables_params_arc.lock().unwrap(); - //the third attempt is the one where the queue is empty and System::current.stop() ends the cycle - assert_eq!(*non_pending_payables_params, vec![(), (), ()]); - let blockchain_bridge_recorder = blockchain_bridge_recording_arc.lock().unwrap(); - assert_eq!(blockchain_bridge_recorder.len(), 1); - let report_accounts_payables_msg = - blockchain_bridge_recorder.get_record::(0); - assert_eq!( - report_accounts_payables_msg, - &ReportAccountsPayable { - accounts: vec![account], - response_skeleton_opt: None, - } - ); + //the second attempt is the one where the queue is empty and System::current.stop() ends the cycle + assert_eq!(*non_pending_payables_params, vec![(), ()]); let notify_later_payables_params = notify_later_payables_params_arc.lock().unwrap(); assert_eq!( *notify_later_payables_params, @@ -1999,12 +1975,6 @@ mod tests { }, Duration::from_millis(97) ), - ( - ScanForPayables { - response_skeleton_opt: None - }, - Duration::from_millis(97) - ), ] ) } diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 061525e45..9386724e6 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -20,7 +20,7 @@ pub(in crate::accountant) mod scanners { use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::BlockchainError; use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; - use crate::sub_lib::utils::NotifyLaterHandle; + use crate::sub_lib::utils::{NotifyLaterHandle, NotifyLaterHandleReal}; use crate::sub_lib::wallet::Wallet; use actix::Message; use masq_lib::logger::Logger; @@ -154,7 +154,10 @@ pub(in crate::accountant) mod scanners { ); debug!(logger, "{}", summary); match qualified_payables.is_empty() { - true => Err(BeginScanError::NothingToProcess), + true => { + self.mark_as_ended(logger); + Err(BeginScanError::NothingToProcess) + } false => Ok(ReportAccountsPayable { accounts: qualified_payables, response_skeleton_opt, From 40bd90e1bc41c12944e271174280cb819264020b Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 12:43:00 +0530 Subject: [PATCH 129/145] GH-611: use ScannerMock for testing periodical scanning for payables --- node/src/accountant/mod.rs | 31 +++--- node/src/accountant/scanners.rs | 166 +++++++++++++++----------------- 2 files changed, 96 insertions(+), 101 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index faf44643f..e04517aba 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -850,7 +850,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::accountant::receivable_dao::ReceivableAccount; - use crate::accountant::scanners::scanners::NullScanner; + use crate::accountant::scanners::scanners::{NullScanner, ScannerMock}; use crate::accountant::test_utils::{ bc_from_earning_wallet, bc_from_wallets, make_payables, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, @@ -1917,31 +1917,31 @@ mod tests { #[test] fn periodical_scanning_for_payable_works() { - //in the very first round we scan without waiting but we cannot find any payable records init_test_logging(); - let test_name = "accountant_payable_scan_timer_triggers_periodical_scanning_for_payables"; - let non_pending_payables_params_arc = Arc::new(Mutex::new(vec![])); + let test_name = "periodical_scanning_for_payable_works"; + let begin_scan_params_arc = Arc::new(Mutex::new(vec![])); let notify_later_payables_params_arc = Arc::new(Mutex::new(vec![])); let system = System::new(test_name); + SystemKillerActor::new(Duration::from_secs(10)).start(); // a safety net for GitHub Actions + let payable_scanner = ScannerMock::new() + .begin_scan_params(&begin_scan_params_arc) + .begin_scan_result(Err(BeginScanError::NothingToProcess)) + .begin_scan_result(Ok(ReportAccountsPayable { + accounts: vec![], + response_skeleton_opt: None, + })) + .stop_system_after_last_message(); let mut config = bc_from_earning_wallet(make_wallet("hi")); config.scan_intervals_opt = Some(ScanIntervals { payable_scan_interval: Duration::from_millis(97), receivable_scan_interval: Duration::from_secs(100), // We'll never run this scanner pending_payable_scan_interval: Duration::from_secs(100), // We'll never run this scanner }); - let mut payable_dao = PayableDaoMock::new() - .non_pending_payables_params(&non_pending_payables_params_arc) - .non_pending_payables_result(vec![]); - payable_dao.have_non_pending_payables_shut_down_the_system = true; - let peer_actors = peer_actors_builder().build(); - SystemKillerActor::new(Duration::from_secs(10)).start(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .payable_dao(PayableDaoMock::new()) // For Accountant - .payable_dao(payable_dao) // For Payable Scanner - .payable_dao(PayableDaoMock::new()) // For PendingPayable Scanner .build(); subject.logger = Logger::new(test_name); + subject.scanners.payable = Box::new(payable_scanner); subject.scanners.pending_payable = Box::new(NullScanner::new()); //skipping subject.scanners.receivable = Box::new(NullScanner::new()); //skipping subject.notify_later.scan_for_payable = Box::new( @@ -1951,15 +1951,16 @@ mod tests { ); let subject_addr = subject.start(); let subject_subs = Accountant::make_subs_from(&subject_addr); + let peer_actors = peer_actors_builder().build(); send_bind_message!(subject_subs, peer_actors); send_start_message!(subject_subs); system.run(); - let non_pending_payables_params = non_pending_payables_params_arc.lock().unwrap(); //the second attempt is the one where the queue is empty and System::current.stop() ends the cycle - assert_eq!(*non_pending_payables_params, vec![(), ()]); + let begin_scan_params = begin_scan_params_arc.lock().unwrap(); let notify_later_payables_params = notify_later_payables_params_arc.lock().unwrap(); + assert_eq!(*begin_scan_params, vec![(), ()]); assert_eq!( *notify_later_payables_params, vec![ diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 9386724e6..bef1fb94b 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -22,14 +22,17 @@ pub(in crate::accountant) mod scanners { use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; use crate::sub_lib::utils::{NotifyLaterHandle, NotifyLaterHandleReal}; use crate::sub_lib::wallet::Wallet; - use actix::Message; + use actix::{Message, System}; use masq_lib::logger::Logger; use masq_lib::messages::{ToMessageBody, UiScanResponse}; use masq_lib::ui_gateway::{MessageTarget, NodeToUiMessage}; use masq_lib::utils::ExpectValue; use std::any::Any; + use std::borrow::BorrowMut; use std::cell::RefCell; + use std::ops::Deref; use std::rc::Rc; + use std::sync::{Arc, Mutex}; use std::time::SystemTime; use web3::types::TransactionReceipt; @@ -746,64 +749,82 @@ pub(in crate::accountant) mod scanners { } } - // pub struct ScannerMock { - // begin_scan_params: RefCell)>>, - // begin_scan_results: Arc, Error>>>>, - // end_scan_params: RefCell>, - // end_scan_results: Arc>>>, - // } - // - // impl Scanner - // for ScannerMock - // where - // BeginMessage: Message, - // EndMessage: Message, - // { - // fn begin_scan( - // &mut self, - // _timestamp: SystemTime, - // _response_skeleton_opt: Option, - // _logger: &Logger, - // ) -> Result { - // todo!("Implement ScannerMock") - // } - // - // fn scan_finished(&mut self, _message: EndMessage) -> Result<(), Error> { - // todo!() - // } - // - // fn scan_started_at(&self) -> Option { - // todo!() - // } - // } - // - // impl ScannerMock { - // pub fn new() -> Self { - // Self { - // begin_scan_params: RefCell::new(vec![]), - // begin_scan_results: Arc::new(Mutex::new(vec![])), - // end_scan_params: RefCell::new(vec![]), - // end_scan_results: Arc::new(Mutex::new(vec![])), - // } - // } - // - // pub fn begin_scan_params( - // mut self, - // params: Vec<(SystemTime, Option)>, - // ) -> Self { - // self.begin_scan_params = RefCell::new(params); - // self - // } - // - // pub fn begin_scan_result(self, result: Result, Error>) -> Self { - // self.begin_scan_results - // .lock() - // .unwrap() - // .borrow_mut() - // .push(result); - // self - // } - // } + pub struct ScannerMock { + begin_scan_params: Arc>>, + begin_scan_results: RefCell>>, + end_scan_params: RefCell>, + end_scan_results: Arc>>>, + stop_system_after_last_message: RefCell, + } + + impl Scanner + for ScannerMock + where + BeginMessage: Message, + EndMessage: Message, + { + fn begin_scan( + &mut self, + _timestamp: SystemTime, + _response_skeleton_opt: Option, + _logger: &Logger, + ) -> Result { + self.begin_scan_params.lock().unwrap().push(()); + if self.stop_system_after_last_message.borrow().clone() + && self.begin_scan_results.borrow().len() == 1 + { + System::current().stop(); + } + self.begin_scan_results.borrow_mut().remove(0) + } + + fn scan_finished( + &mut self, + _message: EndMessage, + _logger: &Logger, + ) -> Option { + todo!("Implement ScannerMock") + } + + fn scan_started_at(&self) -> Option { + todo!("Implement ScannerMock") + } + + fn mark_as_started(&mut self, _timestamp: SystemTime) { + todo!("Implement ScannerMock") + } + + fn mark_as_ended(&mut self, _logger: &Logger) { + todo!("Implement ScannerMock") + } + } + + impl ScannerMock { + pub fn new() -> Self { + Self { + begin_scan_params: Arc::new(Mutex::new(vec![])), + begin_scan_results: RefCell::new(vec![]), + end_scan_params: RefCell::new(vec![]), + end_scan_results: Arc::new(Mutex::new(vec![])), + stop_system_after_last_message: RefCell::new(false), + } + } + + pub fn begin_scan_params(mut self, params: &Arc>>) -> Self { + self.begin_scan_params = params.clone(); + self + } + + pub fn begin_scan_result(self, result: Result) -> Self { + self.begin_scan_results.borrow_mut().push(result); + self + } + + pub fn stop_system_after_last_message(self) -> Self { + self.stop_system_after_last_message.replace(true); + self + } + } #[derive(Default)] pub struct NotifyLaterForScanners { @@ -1785,33 +1806,6 @@ mod tests { .exists_log_containing(&format!("INFO: {}: The Receivable scan ended", test_name)); } - // #[test] - // fn scan_finished_function_of_scanners_ends_the_scan() { - // let now = SystemTime::now(); - // let payment_thresholds = Rc::new(make_payment_thresholds_with_defaults()); - // let payable_dao_factory = PayableDaoFactoryMock::new() - // .make_result(PayableDaoMock::new()) - // .make_result(PayableDaoMock::new()); - // let pending_payable_dao_factory = PendingPayableDaoFactoryMock::new() - // .make_result(PendingPayableDaoMock::new()) - // .make_result(PendingPayableDaoMock::new()); - // let mut scanners = Scanners::new( - // Box::new(payable_dao_factory), - // Box::new(pending_payable_dao_factory), - // Box::new(ReceivableDaoMock::new()), - // Box::new(BannedDaoMock::new()), - // Rc::clone(&payment_thresholds), - // Rc::new(make_wallet("earning")), - // 0, - // Rc::new(RefCell::new(FinancialStatistics::default())), - // ); - // scanners.payable.mark_as_started(now); - // scanners.pending_payable.mark_as_started(now); - // scanners.receivable.mark_as_started(now); - // - // scanners.payable.scan_finished() - // } - fn make_pending_payable_scanner_from_daos( payable_dao: PayableDaoMock, pending_payable_dao: PendingPayableDaoMock, From 658c719aab851ce69499c8c500bb21d77e8d18c6 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 13:06:07 +0530 Subject: [PATCH 130/145] GH-611: fix test for the periodical scanning of receivables and deliquencies --- node/src/accountant/mod.rs | 90 +++++++++----------------------------- 1 file changed, 20 insertions(+), 70 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index e04517aba..12bac8cbd 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1707,93 +1707,49 @@ mod tests { } #[test] - #[ignore] fn periodical_scanning_for_receivables_and_delinquencies_works() { init_test_logging(); - let new_delinquencies_params_arc = Arc::new(Mutex::new(vec![])); - let ban_params_arc = Arc::new(Mutex::new(vec![])); + let test_name = "periodical_scanning_for_receivables_and_delinquencies_works"; + let begin_scan_params_arc = Arc::new(Mutex::new(vec![])); let notify_later_receivable_params_arc = Arc::new(Mutex::new(vec![])); - let earning_wallet = make_wallet("earner3000"); - let wallet_to_be_banned = make_wallet("bad_luck"); - let (blockchain_bridge, _, blockchain_bridge_recording) = make_recorder(); - let mut config = bc_from_earning_wallet(earning_wallet.clone()); + let system = System::new(test_name); + SystemKillerActor::new(Duration::from_secs(10)).start(); // a safety net for GitHub Actions + let receivable_scanner = ScannerMock::new() + .begin_scan_params(&begin_scan_params_arc) + .begin_scan_result(Err(BeginScanError::NothingToProcess)) + .begin_scan_result(Ok(RetrieveTransactions { + recipient: make_wallet("some_recipient"), + response_skeleton_opt: None, + })) + .stop_system_after_last_message(); + let mut config = make_bc_with_defaults(); config.scan_intervals_opt = Some(ScanIntervals { payable_scan_interval: Duration::from_secs(100), receivable_scan_interval: Duration::from_millis(99), pending_payable_scan_interval: Duration::from_secs(100), }); - let new_delinquent_account = ReceivableAccount { - wallet: wallet_to_be_banned.clone(), - balance: 4567, - last_received_timestamp: from_time_t(200_000_000), - }; - let system = System::new("periodical_scanning_for_receivables_and_delinquencies_works"); - let banned_dao = BannedDaoMock::new().ban_parameters(&ban_params_arc); - let mut receivable_dao = ReceivableDaoMock::new() - .new_delinquencies_parameters(&new_delinquencies_params_arc) - //this is the immediate try, not with our interval - .new_delinquencies_result(vec![]) - //after the interval we actually process data - .new_delinquencies_result(vec![new_delinquent_account]) - .paid_delinquencies_result(vec![]) - .paid_delinquencies_result(vec![]) - .paid_delinquencies_result(vec![]); - receivable_dao.have_new_delinquencies_shutdown_the_system = true; let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .receivable_dao(ReceivableDaoMock::new()) - .receivable_dao(receivable_dao) - .banned_dao(BannedDaoMock::new()) - .banned_dao(banned_dao) .build(); - subject.scanners.pending_payable = Box::new(NullScanner::new()); - subject.scanners.payable = Box::new(NullScanner::new()); + subject.scanners.payable = Box::new(NullScanner::new()); // Skipping + subject.scanners.pending_payable = Box::new(NullScanner::new()); // Skipping + subject.scanners.receivable = Box::new(receivable_scanner); subject.notify_later.scan_for_receivable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_receivable_params_arc) .permit_to_send_out(), ); - let peer_actors = peer_actors_builder() - .blockchain_bridge(blockchain_bridge) - .build(); - let subject_addr: Addr = subject.start(); + let subject_addr = subject.start(); let subject_subs = Accountant::make_subs_from(&subject_addr); + let peer_actors = peer_actors_builder().build(); send_bind_message!(subject_subs, peer_actors); send_start_message!(subject_subs); system.run(); - let retrieve_transactions_recording = blockchain_bridge_recording.lock().unwrap(); - assert_eq!(retrieve_transactions_recording.len(), 3); - let retrieve_transactions_msgs: Vec<&RetrieveTransactions> = (0 - ..retrieve_transactions_recording.len()) - .map(|index| retrieve_transactions_recording.get_record::(index)) - .collect(); - assert_eq!( - *retrieve_transactions_msgs, - vec![ - &RetrieveTransactions { - recipient: earning_wallet.clone(), - response_skeleton_opt: None, - }, - &RetrieveTransactions { - recipient: earning_wallet.clone(), - response_skeleton_opt: None, - }, - &RetrieveTransactions { - recipient: earning_wallet.clone(), - response_skeleton_opt: None, - }, - ] - ); - //sadly I cannot effectively assert on the exact params - //they are a) real timestamp of now, b) constant payment_thresholds - //the Rust type system gives me enough support to be okay with counting occurrences - let new_delinquencies_params = new_delinquencies_params_arc.lock().unwrap(); - assert_eq!(new_delinquencies_params.len(), 3); //the third one is the signal to shut the system down - let ban_params = ban_params_arc.lock().unwrap(); - assert_eq!(*ban_params, vec![wallet_to_be_banned]); + let begin_scan_params = begin_scan_params_arc.lock().unwrap(); let notify_later_receivable_params = notify_later_receivable_params_arc.lock().unwrap(); + assert_eq!(begin_scan_params.len(), 2); assert_eq!( *notify_later_receivable_params, vec![ @@ -1809,12 +1765,6 @@ mod tests { }, Duration::from_millis(99) ), - ( - ScanForReceivables { - response_skeleton_opt: None - }, - Duration::from_millis(99) - ), ] ) } From 40f9ba3058fe2be2ec0f287eda547495af11e5e9 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 13:16:04 +0530 Subject: [PATCH 131/145] GH-611: fix test for periodical scanning for pending payables --- node/src/accountant/mod.rs | 71 +++++++++++--------------------------- 1 file changed, 20 insertions(+), 51 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 12bac8cbd..c23ddd6b5 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -829,6 +829,7 @@ mod tests { use super::*; use std::any::TypeId; use std::collections::HashMap; + use std::iter::Scan; use std::ops::Sub; use std::sync::Arc; use std::sync::Mutex; @@ -850,7 +851,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; use crate::accountant::receivable_dao::ReceivableAccount; - use crate::accountant::scanners::scanners::{NullScanner, ScannerMock}; + use crate::accountant::scanners::scanners::{NullScanner, PendingPayableScanner, ScannerMock}; use crate::accountant::test_utils::{ bc_from_earning_wallet, bc_from_wallets, make_payables, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, @@ -1770,45 +1771,33 @@ mod tests { } #[test] - #[ignore] fn periodical_scanning_for_pending_payable_works() { - //in the very first round we scan without waiting but we cannot find any pending payable init_test_logging(); - let return_all_pending_payable_fingerprints_params_arc = Arc::new(Mutex::new(vec![])); + let test_name = "periodical_scanning_for_pending_payable_works"; + let begin_scan_params_arc = Arc::new(Mutex::new(vec![])); let notify_later_pending_payable_params_arc = Arc::new(Mutex::new(vec![])); - let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); - let system = - System::new("accountant_payable_scan_timer_triggers_scanning_for_pending_payable"); - let mut config = bc_from_earning_wallet(make_wallet("hi")); + let system = System::new(test_name); + SystemKillerActor::new(Duration::from_secs(10)).start(); // a safety net for GitHub Actions + let pending_payable_scanner = ScannerMock::new() + .begin_scan_params(&begin_scan_params_arc) + .begin_scan_result(Err(BeginScanError::NothingToProcess)) + .begin_scan_result(Ok(RequestTransactionReceipts { + pending_payable: vec![], + response_skeleton_opt: None, + })) + .stop_system_after_last_message(); + let mut config = make_bc_with_defaults(); config.scan_intervals_opt = Some(ScanIntervals { payable_scan_interval: Duration::from_secs(100), receivable_scan_interval: Duration::from_secs(100), pending_payable_scan_interval: Duration::from_millis(98), }); - // slightly above minimum balance, to the right of the curve (time intersection) - let pending_payable_fingerprint_record = PendingPayableFingerprint { - rowid_opt: Some(45454), - timestamp: SystemTime::now(), - hash: H256::from_uint(&U256::from(565)), - attempt_opt: Some(1), - amount: 4589, - process_error: None, - }; - let mut pending_payable_dao = PendingPayableDaoMock::default() - .return_all_fingerprints_params(&return_all_pending_payable_fingerprints_params_arc) - .return_all_fingerprints_result(vec![]) - .return_all_fingerprints_result(vec![pending_payable_fingerprint_record.clone()]); - pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; - let peer_actors = peer_actors_builder() - .blockchain_bridge(blockchain_bridge) - .build(); let mut subject = AccountantBuilder::default() .bootstrapper_config(config) - .pending_payable_dao(PendingPayableDaoMock::new()) // For Accountant - .pending_payable_dao(pending_payable_dao) // For Scanner .build(); - subject.scanners.receivable = Box::new(NullScanner::new()); //skipping subject.scanners.payable = Box::new(NullScanner::new()); //skipping + subject.scanners.pending_payable = Box::new(pending_payable_scanner); + subject.scanners.receivable = Box::new(NullScanner::new()); //skipping subject.notify_later.scan_for_pending_payable = Box::new( NotifyLaterHandleMock::default() .notify_later_params(¬ify_later_pending_payable_params_arc) @@ -1816,28 +1805,14 @@ mod tests { ); let subject_addr: Addr = subject.start(); let subject_subs = Accountant::make_subs_from(&subject_addr); + let peer_actors = peer_actors_builder().build(); send_bind_message!(subject_subs, peer_actors); send_start_message!(subject_subs); system.run(); - let return_all_pending_payable_fingerprints = - return_all_pending_payable_fingerprints_params_arc - .lock() - .unwrap(); - //the third attempt is the one where the queue is empty and System::current.stop() ends the cycle - assert_eq!(*return_all_pending_payable_fingerprints, vec![(), (), ()]); - let blockchain_bridge_recorder = blockchain_bridge_recording_arc.lock().unwrap(); - assert_eq!(blockchain_bridge_recorder.len(), 1); - let request_transaction_receipt_msg = - blockchain_bridge_recorder.get_record::(0); - assert_eq!( - request_transaction_receipt_msg, - &RequestTransactionReceipts { - pending_payable: vec![pending_payable_fingerprint_record], - response_skeleton_opt: None, - } - ); + let begin_scan_params = begin_scan_params_arc.lock().unwrap(); + assert_eq!(begin_scan_params.len(), 2); let notify_later_pending_payable_params = notify_later_pending_payable_params_arc.lock().unwrap(); assert_eq!( @@ -1855,12 +1830,6 @@ mod tests { }, Duration::from_millis(98) ), - ( - ScanForPendingPayables { - response_skeleton_opt: None - }, - Duration::from_millis(98) - ), ] ) } From bb2733cfe553d7441f92fb31017c434dc46af2c1 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 13:22:19 +0530 Subject: [PATCH 132/145] GH-611: rename the fn name for stopping the system inside ScannerMock --- node/src/accountant/mod.rs | 6 +++--- node/src/accountant/scanners.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index c23ddd6b5..a69df3456 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1722,7 +1722,7 @@ mod tests { recipient: make_wallet("some_recipient"), response_skeleton_opt: None, })) - .stop_system_after_last_message(); + .stop_the_system(); let mut config = make_bc_with_defaults(); config.scan_intervals_opt = Some(ScanIntervals { payable_scan_interval: Duration::from_secs(100), @@ -1785,7 +1785,7 @@ mod tests { pending_payable: vec![], response_skeleton_opt: None, })) - .stop_system_after_last_message(); + .stop_the_system(); let mut config = make_bc_with_defaults(); config.scan_intervals_opt = Some(ScanIntervals { payable_scan_interval: Duration::from_secs(100), @@ -1849,7 +1849,7 @@ mod tests { accounts: vec![], response_skeleton_opt: None, })) - .stop_system_after_last_message(); + .stop_the_system(); let mut config = bc_from_earning_wallet(make_wallet("hi")); config.scan_intervals_opt = Some(ScanIntervals { payable_scan_interval: Duration::from_millis(97), diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index bef1fb94b..8184b4c09 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -820,7 +820,7 @@ pub(in crate::accountant) mod scanners { self } - pub fn stop_system_after_last_message(self) -> Self { + pub fn stop_the_system(self) -> Self { self.stop_system_after_last_message.replace(true); self } From 38388263ad1405f4094c23f2b177a8d7054a3a94 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 13:24:27 +0530 Subject: [PATCH 133/145] GH-611: remove import warnings --- node/src/accountant/mod.rs | 4 +--- node/src/accountant/scanners.rs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index a69df3456..9d2cb9e1c 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -829,7 +829,6 @@ mod tests { use super::*; use std::any::TypeId; use std::collections::HashMap; - use std::iter::Scan; use std::ops::Sub; use std::sync::Arc; use std::sync::Mutex; @@ -850,8 +849,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; - use crate::accountant::receivable_dao::ReceivableAccount; - use crate::accountant::scanners::scanners::{NullScanner, PendingPayableScanner, ScannerMock}; + use crate::accountant::scanners::scanners::{NullScanner, ScannerMock}; use crate::accountant::test_utils::{ bc_from_earning_wallet, bc_from_wallets, make_payables, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 8184b4c09..36bcf44f3 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -20,7 +20,7 @@ pub(in crate::accountant) mod scanners { use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::BlockchainError; use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; - use crate::sub_lib::utils::{NotifyLaterHandle, NotifyLaterHandleReal}; + use crate::sub_lib::utils::NotifyLaterHandle; use crate::sub_lib::wallet::Wallet; use actix::{Message, System}; use masq_lib::logger::Logger; @@ -28,9 +28,7 @@ pub(in crate::accountant) mod scanners { use masq_lib::ui_gateway::{MessageTarget, NodeToUiMessage}; use masq_lib::utils::ExpectValue; use std::any::Any; - use std::borrow::BorrowMut; use std::cell::RefCell; - use std::ops::Deref; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::SystemTime; From c23448e15b7b429cd040c1233eaa1fc17460f570 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 13:43:00 +0530 Subject: [PATCH 134/145] GH-611: improve the implementation of ScannerMock --- node/src/accountant/scanners.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 36bcf44f3..7d8dc9b6e 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -750,8 +750,8 @@ pub(in crate::accountant) mod scanners { pub struct ScannerMock { begin_scan_params: Arc>>, begin_scan_results: RefCell>>, - end_scan_params: RefCell>, - end_scan_results: Arc>>>, + end_scan_params: Arc>>, + end_scan_results: RefCell>>, stop_system_after_last_message: RefCell, } @@ -768,9 +768,7 @@ pub(in crate::accountant) mod scanners { _logger: &Logger, ) -> Result { self.begin_scan_params.lock().unwrap().push(()); - if self.stop_system_after_last_message.borrow().clone() - && self.begin_scan_results.borrow().len() == 1 - { + if self.is_allowed_to_stop_the_system() && self.is_last_message() { System::current().stop(); } self.begin_scan_results.borrow_mut().remove(0) @@ -802,8 +800,8 @@ pub(in crate::accountant) mod scanners { Self { begin_scan_params: Arc::new(Mutex::new(vec![])), begin_scan_results: RefCell::new(vec![]), - end_scan_params: RefCell::new(vec![]), - end_scan_results: Arc::new(Mutex::new(vec![])), + end_scan_params: Arc::new(Mutex::new(vec![])), + end_scan_results: RefCell::new(vec![]), stop_system_after_last_message: RefCell::new(false), } } @@ -822,6 +820,22 @@ pub(in crate::accountant) mod scanners { self.stop_system_after_last_message.replace(true); self } + + pub fn is_allowed_to_stop_the_system(&self) -> bool { + self.stop_system_after_last_message.borrow().clone() + } + + pub fn is_last_message(&self) -> bool { + self.is_last_message_from_begin_scan() || self.is_last_message_from_end_scan() + } + + pub fn is_last_message_from_begin_scan(&self) -> bool { + self.begin_scan_results.borrow().len() == 1 && self.end_scan_results.borrow().is_empty() + } + + pub fn is_last_message_from_end_scan(&self) -> bool { + self.end_scan_results.borrow().len() == 1 && self.begin_scan_results.borrow().is_empty() + } } #[derive(Default)] From 167b27655abafbb2df9141af0137d8cd76e26a67 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 13:51:55 +0530 Subject: [PATCH 135/145] GH-611: end the scan in case begin_scan() returns an error of nothing to process --- node/src/accountant/scanners.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 7d8dc9b6e..8e502d9d5 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -323,6 +323,7 @@ pub(in crate::accountant) mod scanners { logger, "Pending payable scan ended. No pending payable found." ); + self.mark_as_ended(logger); Err(BeginScanError::NothingToProcess) } false => { @@ -993,7 +994,9 @@ mod tests { let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + let is_scan_running = payable_scanner.scan_started_at().is_some(); assert_eq!(result, Err(BeginScanError::NothingToProcess)); + assert_eq!(is_scan_running, false); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for payables", test_name), "Chose 0 qualified debts to pay", @@ -1199,7 +1202,9 @@ mod tests { let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + let is_scan_running = pending_payable_scanner.scan_started_at().is_some(); assert_eq!(result, Err(BeginScanError::NothingToProcess)); + assert_eq!(is_scan_running, false); TestLogHandler::new().assert_logs_match_in_order(vec![ &format!("INFO: {}: Scanning for pending payable", test_name), &format!( From 48a06af2660e5cfcd174dbe27c6fe7876396350f Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 14:49:50 +0530 Subject: [PATCH 136/145] GH-611: refactor begin_scan() for Receivable Scanner --- node/src/accountant/scanners.rs | 80 +++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 8e502d9d5..c8aa22c8f 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -567,7 +567,7 @@ pub(in crate::accountant) mod scanners { pub struct ReceivableScanner { common: ScannerCommon, - dao: Box, + receivable_dao: Box, banned_dao: Box, earning_wallet: Rc, pub(crate) financial_statistics: Rc>, @@ -588,35 +588,7 @@ pub(in crate::accountant) mod scanners { logger, "Scanning for receivables to {}", self.earning_wallet ); - info!(logger, "Scanning for delinquencies"); - self.dao - .new_delinquencies(timestamp, self.common.payment_thresholds.as_ref()) - .into_iter() - .for_each(|account| { - self.banned_dao.ban(&account.wallet); - let (balance, age) = balance_and_age(timestamp, &account); - info!( - logger, - "Wallet {} (balance: {} MASQ, age: {} sec) banned for delinquency", - account.wallet, - balance, - age.as_secs() - ) - }); - self.dao - .paid_delinquencies(self.common.payment_thresholds.as_ref()) - .into_iter() - .for_each(|account| { - self.banned_dao.unban(&account.wallet); - let (balance, age) = balance_and_age(timestamp, &account); - info!( - logger, - "Wallet {} (balance: {} MASQ, age: {} sec) is no longer delinquent: unbanned", - account.wallet, - balance, - age.as_secs() - ) - }); + self.scan_for_delinquencies(timestamp, logger); Ok(RetrieveTransactions { recipient: self.earning_wallet.as_ref().clone(), @@ -640,7 +612,9 @@ pub(in crate::accountant) mod scanners { .payments .iter() .fold(0, |so_far, now| so_far + now.gwei_amount); - self.dao.as_mut().more_money_received(message.payments); + self.receivable_dao + .as_mut() + .more_money_received(message.payments); let mut financial_statistics = self.financial_statistics(); financial_statistics.total_paid_receivable += total_newly_paid_receivable; self.financial_statistics.replace(financial_statistics); @@ -683,7 +657,7 @@ pub(in crate::accountant) mod scanners { impl ReceivableScanner { pub fn new( - dao: Box, + receivable_dao: Box, banned_dao: Box, payment_thresholds: Rc, earning_wallet: Rc, @@ -692,12 +666,52 @@ pub(in crate::accountant) mod scanners { Self { common: ScannerCommon::new(payment_thresholds), earning_wallet, - dao, + receivable_dao, banned_dao, financial_statistics, } } + pub fn scan_for_delinquencies(&self, timestamp: SystemTime, logger: &Logger) { + info!(logger, "Scanning for delinquencies"); + self.ban_nodes(timestamp, logger); + self.unban_nodes(timestamp, logger); + } + + pub fn ban_nodes(&self, timestamp: SystemTime, logger: &Logger) { + self.receivable_dao + .new_delinquencies(timestamp, self.common.payment_thresholds.as_ref()) + .into_iter() + .for_each(|account| { + self.banned_dao.ban(&account.wallet); + let (balance, age) = balance_and_age(timestamp, &account); + info!( + logger, + "Wallet {} (balance: {} MASQ, age: {} sec) banned for delinquency", + account.wallet, + balance, + age.as_secs() + ) + }); + } + + pub fn unban_nodes(&self, timestamp: SystemTime, logger: &Logger) { + self.receivable_dao + .paid_delinquencies(self.common.payment_thresholds.as_ref()) + .into_iter() + .for_each(|account| { + self.banned_dao.unban(&account.wallet); + let (balance, age) = balance_and_age(timestamp, &account); + info!( + logger, + "Wallet {} (balance: {} MASQ, age: {} sec) is no longer delinquent: unbanned", + account.wallet, + balance, + age.as_secs() + ) + }); + } + pub fn financial_statistics(&self) -> FinancialStatistics { self.financial_statistics.as_ref().borrow().clone() } From d5ffceac1fe17a91ea053701aadbd7ace4a02bcf Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 15:05:03 +0530 Subject: [PATCH 137/145] GH-611: remove an obsolete assert realted to threshold tools --- node/src/accountant/mod.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 9d2cb9e1c..30451b362 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -991,14 +991,6 @@ mod tests { .scan_for_receivable .as_any() .downcast_ref::>(); - // TODO: Write another test for it inside Scanner - // result - // .scanners - // .payables - // .payable_threshold_tools - // .as_any() - // .downcast_ref::() - // .unwrap(); assert_eq!(result.crashable, false); assert_eq!(financial_statistics.total_paid_receivable, 0); assert_eq!(financial_statistics.total_paid_payable, 0); From 52bfd0c6056e594b5cab5ebd47a03aa2eaea930b Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Fri, 23 Sep 2022 17:10:08 +0530 Subject: [PATCH 138/145] GH-611: fix the test pending_transaction_is_registered_and_monitored_until_it_gets_confirmed_or_canceled() --- node/src/accountant/mod.rs | 54 ++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 30451b362..52bc9e4db 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -849,7 +849,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; - use crate::accountant::scanners::scanners::{NullScanner, ScannerMock}; + use crate::accountant::scanners::scanners::{NullScanner, PendingPayableScanner, ScannerMock}; use crate::accountant::test_utils::{ bc_from_earning_wallet, bc_from_wallets, make_payables, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, @@ -2852,7 +2852,6 @@ mod tests { } #[test] - #[ignore] fn pending_transaction_is_registered_and_monitored_until_it_gets_confirmed_or_canceled() { init_test_logging(); let mark_pending_payable_params_arc = Arc::new(Mutex::new(vec![])); @@ -2932,15 +2931,17 @@ mod tests { pending_payable_opt: None, }; let pending_payable_scan_interval = 200; //should be slightly less than 1/5 of the time until shutting the system - let scanner_payable_dao = PayableDaoMock::new() + let payable_dao_for_accountant = PayableDaoMock::new(); + let payable_dao_for_payable_scanner = PayableDaoMock::new() + .mark_pending_payable_rowid_params(&mark_pending_payable_params_arc) + .mark_pending_payable_rowid_result(Ok(())) + .mark_pending_payable_rowid_result(Ok(())) .non_pending_payables_params(&non_pending_payables_params_arc) - .non_pending_payables_result(vec![account_1, account_2]) + .non_pending_payables_result(vec![account_1, account_2]); + let payable_dao_for_pending_payable_scanner = PayableDaoMock::new() .transaction_confirmed_params(&transaction_confirmed_params_arc) .transaction_confirmed_result(Ok(())); - let accountant_payable_dao = PayableDaoMock::new() - .mark_pending_payable_rowid_params(&mark_pending_payable_params_arc) - .mark_pending_payable_rowid_result(Ok(())) - .mark_pending_payable_rowid_result(Ok(())); + let mut bootstrapper_config = bc_from_earning_wallet(make_wallet("some_wallet_address")); bootstrapper_config.scan_intervals_opt = Some(ScanIntervals { payable_scan_interval: Duration::from_secs(1_000_000), //we don't care about this scan @@ -2983,7 +2984,14 @@ mod tests { attempt_opt: Some(4), ..fingerprint_2_first_round.clone() }; - let mut scanner_pending_payable_dao = PendingPayableDaoMock::default() + let pending_payable_dao_for_accountant = PendingPayableDaoMock::default(); + let mut pending_payable_dao_for_payable_scanner = PendingPayableDaoMock::default() + .fingerprint_rowid_result(Some(rowid_for_account_1)) + .fingerprint_rowid_result(Some(rowid_for_account_2)) + .insert_fingerprint_params(&insert_fingerprint_params_arc) + .insert_fingerprint_result(Ok(())) + .insert_fingerprint_result(Ok(())); + let mut pending_payable_dao_for_pending_payable_scanner = PendingPayableDaoMock::new() .return_all_fingerprints_params(&return_all_fingerprints_params_arc) .return_all_fingerprints_result(vec![]) .return_all_fingerprints_result(vec![ @@ -2999,9 +3007,6 @@ mod tests { fingerprint_2_third_round, ]) .return_all_fingerprints_result(vec![fingerprint_2_fourth_round.clone()]) - .insert_fingerprint_params(&insert_fingerprint_params_arc) - .insert_fingerprint_result(Ok(())) - .insert_fingerprint_result(Ok(())) .update_fingerprint_params(&update_fingerprint_params_arc) .update_fingerprint_results(Ok(())) .update_fingerprint_results(Ok(())) @@ -3015,19 +3020,28 @@ mod tests { .delete_fingerprint_params(&delete_record_params_arc) //this is used during confirmation of the successful one .delete_fingerprint_result(Ok(())); - scanner_pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; - let accountant_pending_payable_dao = PendingPayableDaoMock::default() - .fingerprint_rowid_result(Some(rowid_for_account_1)) - .fingerprint_rowid_result(Some(rowid_for_account_2)); + pending_payable_dao_for_pending_payable_scanner + .have_return_all_fingerprints_shut_down_the_system = true; + + // fingerprint_rowid_results ==> pending_payable_dao_for_payable_scanners [done] + // mark_pending_payable_rowid ==> payable_dao_for_payable_scanner [done] + // update_fingerprint ==> pending_payable_dao_for_pending_payable_scanner [done] + // mark_failure ==> pending_payable_dao_for_pending_payable_scanner [done] + // transaction_confirmed_results ==> payable_dao_for_pending_payable_scanner [done] + // delete_fingerprint ==> pending_payable_dao_for_pending_payable_scanner [done] + // return_all_fingerprints ==> pending_payable_dao_for_pending_payable_scanner + let accountant_addr = Arbiter::builder() .stop_system_on_panic(true) .start(move |_| { let mut subject = AccountantBuilder::default() .bootstrapper_config(bootstrapper_config) - .payable_dao(accountant_payable_dao) - .payable_dao(scanner_payable_dao) - .pending_payable_dao(accountant_pending_payable_dao) - .pending_payable_dao(scanner_pending_payable_dao) + .payable_dao(payable_dao_for_accountant) + .payable_dao(payable_dao_for_payable_scanner) + .payable_dao(payable_dao_for_pending_payable_scanner) + .pending_payable_dao(pending_payable_dao_for_accountant) + .pending_payable_dao(pending_payable_dao_for_payable_scanner) + .pending_payable_dao(pending_payable_dao_for_pending_payable_scanner) .build(); subject.scanners.receivable = Box::new(NullScanner::new()); let notify_later_half_mock = NotifyLaterHandleMock::default() From 53a66e6c5dd907266afa5bd6ca4659a649068098 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Mon, 26 Sep 2022 10:52:58 +0530 Subject: [PATCH 139/145] GH-611: refactor scanners.rs --- node/src/accountant/mod.rs | 4 +- node/src/accountant/scanners.rs | 609 ++++++++++++++++++-------------- node/src/accountant/tools.rs | 11 - node/src/sub_lib/accountant.rs | 2 +- node/src/test_utils/mod.rs | 6 + 5 files changed, 350 insertions(+), 282 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 52bc9e4db..4d363626c 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -849,7 +849,7 @@ mod tests { use crate::accountant::payable_dao::PayableDaoError; use crate::accountant::pending_payable_dao::PendingPayableDaoError; - use crate::accountant::scanners::scanners::{NullScanner, PendingPayableScanner, ScannerMock}; + use crate::accountant::scanners::scanners::{NullScanner, ScannerMock}; use crate::accountant::test_utils::{ bc_from_earning_wallet, bc_from_wallets, make_payables, BannedDaoFactoryMock, PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, @@ -2985,7 +2985,7 @@ mod tests { ..fingerprint_2_first_round.clone() }; let pending_payable_dao_for_accountant = PendingPayableDaoMock::default(); - let mut pending_payable_dao_for_payable_scanner = PendingPayableDaoMock::default() + let pending_payable_dao_for_payable_scanner = PendingPayableDaoMock::default() .fingerprint_rowid_result(Some(rowid_for_account_1)) .fingerprint_rowid_result(Some(rowid_for_account_2)) .insert_fingerprint_params(&insert_fingerprint_params_arc) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index c8aa22c8f..7142043e0 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -34,13 +34,6 @@ pub(in crate::accountant) mod scanners { use std::time::SystemTime; use web3::types::TransactionReceipt; - #[derive(Debug, PartialEq, Eq)] - pub enum BeginScanError { - NothingToProcess, - ScanAlreadyRunning(SystemTime), - CalledFromNullScanner, // Exclusive for tests - } - pub struct Scanners { pub payable: Box>, pub pending_payable: @@ -105,9 +98,16 @@ pub(in crate::accountant) mod scanners { as_any_dcl!(); } - struct ScannerCommon { + #[derive(Debug, PartialEq, Eq)] + pub enum BeginScanError { + NothingToProcess, + ScanAlreadyRunning(SystemTime), + CalledFromNullScanner, // Exclusive for tests + } + + pub struct ScannerCommon { initiated_at_opt: Option, - payment_thresholds: Rc, + pub payment_thresholds: Rc, } impl ScannerCommon { @@ -120,9 +120,9 @@ pub(in crate::accountant) mod scanners { } pub struct PayableScanner { - common: ScannerCommon, - payable_dao: Box, - pending_payable_dao: Box, + pub common: ScannerCommon, + pub payable_dao: Box, + pub pending_payable_dao: Box, } impl Scanner for PayableScanner { @@ -297,11 +297,11 @@ pub(in crate::accountant) mod scanners { } pub struct PendingPayableScanner { - common: ScannerCommon, - payable_dao: Box, - pending_payable_dao: Box, - when_pending_too_long_sec: u64, - pub(crate) financial_statistics: Rc>, + pub common: ScannerCommon, + pub payable_dao: Box, + pub pending_payable_dao: Box, + pub when_pending_too_long_sec: u64, + pub financial_statistics: Rc>, } impl Scanner for PendingPayableScanner { @@ -566,11 +566,11 @@ pub(in crate::accountant) mod scanners { } pub struct ReceivableScanner { - common: ScannerCommon, - receivable_dao: Box, - banned_dao: Box, - earning_wallet: Rc, - pub(crate) financial_statistics: Rc>, + pub common: ScannerCommon, + pub receivable_dao: Box, + pub banned_dao: Box, + pub earning_wallet: Rc, + pub financial_statistics: Rc>, } impl Scanner for ReceivableScanner { @@ -886,6 +886,7 @@ mod tests { use crate::database::dao_utils::from_time_t; use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; + use crate::sub_lib::wallet::Wallet; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; use ethereum_types::{BigEndianHash, U64}; @@ -897,18 +898,6 @@ mod tests { use std::time::{Duration, SystemTime}; use web3::types::{TransactionReceipt, H256, U256}; - impl Default for PendingPayableScanner { - fn default() -> Self { - PendingPayableScanner::new( - Box::new(PayableDaoMock::new()), - Box::new(PendingPayableDaoMock::new()), - Rc::new(make_payment_thresholds_with_defaults()), - DEFAULT_PENDING_TOO_LONG_SEC, - Rc::new(RefCell::new(FinancialStatistics::default())), - ) - } - } - #[test] fn scanners_struct_can_be_constructed_with_the_respective_scanners() { let payment_thresholds = Rc::new(make_payment_thresholds_with_defaults()); @@ -951,23 +940,18 @@ mod tests { init_test_logging(); let test_name = "payable_scanner_can_initiate_a_scan"; let now = SystemTime::now(); - let payment_thresholds = make_payment_thresholds_with_defaults(); let (qualified_payable_accounts, _, all_non_pending_payables) = - make_payables(now, &payment_thresholds); + make_payables(now, &PaymentThresholds::default()); + let len_of_qualified_payables = qualified_payable_accounts.len(); let payable_dao = PayableDaoMock::new().non_pending_payables_result(all_non_pending_payables); - let mut payable_scanner = PayableScanner::new( - Box::new(payable_dao), - Box::new(PendingPayableDaoMock::new()), - Rc::new(payment_thresholds), - ); + let mut subject = PayableScanner::default().payable_dao(payable_dao); - let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + let result = subject.begin_scan(now, None, &Logger::new(test_name)); - let timestamp = payable_scanner.scan_started_at(); - let run_again_result = - payable_scanner.begin_scan(SystemTime::now(), None, &Logger::new(test_name)); + let timestamp = subject.scan_started_at(); + assert_eq!(timestamp, Some(now)); assert_eq!( result, Ok(ReportAccountsPayable { @@ -975,19 +959,29 @@ mod tests { response_skeleton_opt: None, }) ); - assert_eq!(timestamp, Some(now)); + TestLogHandler::new().assert_logs_match_in_order(vec![ + &format!("INFO: {test_name}: Scanning for payables"), + &format!("INFO: {test_name}: Chose {len_of_qualified_payables} qualified debts to pay"), + ]) + } + + #[test] + fn payable_scanner_throws_error_when_a_scan_is_already_running() { + let now = SystemTime::now(); + let (_, _, all_non_pending_payables) = make_payables(now, &PaymentThresholds::default()); + let payable_dao = + PayableDaoMock::new().non_pending_payables_result(all_non_pending_payables); + let mut subject = PayableScanner::default().payable_dao(payable_dao); + let _result = subject.begin_scan(now, None, &Logger::new("test")); + + let run_again_result = subject.begin_scan(SystemTime::now(), None, &Logger::new("test")); + + let is_scan_running = subject.scan_started_at().is_some(); + assert_eq!(is_scan_running, true); assert_eq!( run_again_result, Err(BeginScanError::ScanAlreadyRunning(now)) ); - TestLogHandler::new().assert_logs_match_in_order(vec![ - &format!("INFO: {}: Scanning for payables", test_name), - &format!( - "INFO: {}: Chose {} qualified debts to pay", - test_name, - qualified_payable_accounts.len() - ), - ]) } #[test] @@ -995,24 +989,20 @@ mod tests { init_test_logging(); let test_name = "payable_scanner_throws_error_in_case_no_qualified_payable_is_found"; let now = SystemTime::now(); - let payment_thresholds = make_payment_thresholds_with_defaults(); - let (_, unqualified_payable_accounts, _) = make_payables(now, &payment_thresholds); + let (_, unqualified_payable_accounts, _) = + make_payables(now, &PaymentThresholds::default()); let payable_dao = PayableDaoMock::new().non_pending_payables_result(unqualified_payable_accounts); - let mut payable_scanner = PayableScanner::new( - Box::new(payable_dao), - Box::new(PendingPayableDaoMock::new()), - Rc::new(payment_thresholds), - ); + let mut subject = PayableScanner::default().payable_dao(payable_dao); - let result = payable_scanner.begin_scan(now, None, &Logger::new(test_name)); + let result = subject.begin_scan(now, None, &Logger::new(test_name)); - let is_scan_running = payable_scanner.scan_started_at().is_some(); - assert_eq!(result, Err(BeginScanError::NothingToProcess)); + let is_scan_running = subject.scan_started_at().is_some(); assert_eq!(is_scan_running, false); + assert_eq!(result, Err(BeginScanError::NothingToProcess)); TestLogHandler::new().assert_logs_match_in_order(vec![ - &format!("INFO: {}: Scanning for payables", test_name), + &format!("INFO: {test_name}: Scanning for payables"), "Chose 0 qualified debts to pay", ]); } @@ -1022,17 +1012,14 @@ mod tests { expected = "Payable fingerprint for 0x0000…0315 doesn't exist but should by now; system unreliable" )] fn payable_scanner_throws_error_when_fingerprint_is_not_found() { - init_test_logging(); - let now_system = SystemTime::now(); + let now = SystemTime::now(); let payment_hash = H256::from_uint(&U256::from(789)); - let payable = Payable::new(make_wallet("booga"), 6789, payment_hash, now_system); + let payable = Payable::new(make_wallet("booga"), 6789, payment_hash, now); let payable_dao = PayableDaoMock::new().mark_pending_payable_rowid_result(Ok(())); let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(None); - let mut subject = PayableScanner::new( - Box::new(payable_dao), - Box::new(pending_payable_dao), - Rc::new(make_payment_thresholds_with_defaults()), - ); + let mut subject = PayableScanner::default() + .payable_dao(payable_dao) + .pending_payable_dao(pending_payable_dao); let sent_payable = SentPayable { payable: vec![Ok(payable)], response_skeleton_opt: None, @@ -1047,7 +1034,7 @@ mod tests { 0x000000000000000000000000000000000000000000000000000000000000007b has stayed \ undone due to RecordDeletion(\"we slept over, sorry\")" )] - fn payable_scanner_throws_error_when_dealing_with_failed_payment_fails_to_delete_the_existing_pending_payable_fingerprint( + fn payable_scanner_panics_when_failed_payment_fails_to_delete_the_existing_pending_payable_fingerprint( ) { let rowid = 4; let hash = H256::from_uint(&U256::from(123)); @@ -1063,11 +1050,7 @@ mod tests { .delete_fingerprint_result(Err(PendingPayableDaoError::RecordDeletion( "we slept over, sorry".to_string(), ))); - let mut subject = PayableScanner::new( - Box::new(PayableDaoMock::new()), - Box::new(pending_payable_dao), - Rc::new(make_payment_thresholds_with_defaults()), - ); + let mut subject = PayableScanner::default().pending_payable_dao(pending_payable_dao); let _ = subject.scan_finished(sent_payable, &Logger::new("test")); } @@ -1077,7 +1060,7 @@ mod tests { expected = "Was unable to create a mark in payables for a new pending payable '0x0000…007b' \ due to 'SignConversion(9999999999999)'" )] - fn payable_scanner_throws_error_when_it_fails_to_make_a_mark_in_payables() { + fn payable_scanner_panics_when_it_fails_to_make_a_mark_in_payables() { let payable = Payable::new( make_wallet("blah"), 6789, @@ -1088,11 +1071,9 @@ mod tests { .mark_pending_payable_rowid_result(Err(PayableDaoError::SignConversion(9999999999999))); let pending_payable_dao = PendingPayableDaoMock::default().fingerprint_rowid_result(Some(7879)); - let mut subject = PayableScanner::new( - Box::new(payable_dao), - Box::new(pending_payable_dao), - Rc::new(make_payment_thresholds_with_defaults()), - ); + let mut subject = PayableScanner::default() + .payable_dao(payable_dao) + .pending_payable_dao(pending_payable_dao); let sent_payable = SentPayable { payable: vec![Ok(payable)], response_skeleton_opt: None, @@ -1105,13 +1086,13 @@ mod tests { fn payable_scanner_handles_sent_payable_message() { //the two failures differ in the logged messages init_test_logging(); - let elapsed_time = 10; + let test_name = "payable_scanner_handles_sent_payable_message"; let fingerprint_rowid_params_arc = Arc::new(Mutex::new(vec![])); - let now_system = SystemTime::now(); + let now = SystemTime::now(); let payable_1 = Err(BlockchainError::InvalidResponse); let payable_2_rowid = 126; - let payable_hash_2 = H256::from_uint(&U256::from(166)); - let payable_2 = Payable::new(make_wallet("booga"), 6789, payable_hash_2, now_system); + let payable_2_hash = H256::from_uint(&U256::from(166)); + let payable_2 = Payable::new(make_wallet("booga"), 6789, payable_2_hash, now); let payable_3 = Err(BlockchainError::TransactionFailed { msg: "closing hours, sorry".to_string(), hash_opt: None, @@ -1124,27 +1105,39 @@ mod tests { let pending_payable_dao = PendingPayableDaoMock::default() .fingerprint_rowid_params(&fingerprint_rowid_params_arc) .fingerprint_rowid_result(Some(payable_2_rowid)); - let mut subject = PayableScanner::new( - Box::new(payable_dao), - Box::new(pending_payable_dao), - Rc::new(make_payment_thresholds_with_defaults()), - ); - subject.mark_as_started(SystemTime::now().sub(Duration::from_millis(elapsed_time))); + let mut subject = PayableScanner::default() + .payable_dao(payable_dao) + .pending_payable_dao(pending_payable_dao); + subject.mark_as_started(SystemTime::now()); - let message_opt = - subject.scan_finished(sent_payable, &Logger::new("PayableScannerScanFinished")); + let message_opt = subject.scan_finished(sent_payable, &Logger::new(test_name)); + let is_scan_running = subject.scan_started_at().is_some(); let fingerprint_rowid_params = fingerprint_rowid_params_arc.lock().unwrap(); assert_eq!(message_opt, None); - assert_eq!(subject.scan_started_at(), None); - assert_eq!(*fingerprint_rowid_params, vec![payable_hash_2]); //we know the other two errors are associated with an initiated transaction having a backup + assert_eq!(is_scan_running, false); + //we know the other two errors are associated with an initiated transaction having a backup + assert_eq!(*fingerprint_rowid_params, vec![payable_2_hash]); let log_handler = TestLogHandler::new(); - log_handler.exists_log_containing("WARN: PayableScannerScanFinished: Outbound transaction failure due to 'InvalidResponse'. Please check your blockchain service URL configuration."); - log_handler.exists_log_containing("DEBUG: PayableScannerScanFinished: Payable '0x0000…00a6' has been marked as pending in the payable table"); - log_handler.exists_log_containing("WARN: PayableScannerScanFinished: Encountered transaction error at this end: 'TransactionFailed { msg: \"closing hours, sorry\", hash_opt: None }'"); - log_handler.exists_log_containing("DEBUG: PayableScannerScanFinished: Forgetting a transaction attempt that even did not reach the signing stage"); - log_handler - .exists_log_containing("INFO: PayableScannerScanFinished: The Payable scan ended"); + log_handler.assert_logs_contain_in_order(vec![ + &format!( + "WARN: {test_name}: Outbound transaction failure due to 'InvalidResponse'. \ + Please check your blockchain service URL configuration." + ), + &format!( + "WARN: {test_name}: Encountered transaction error at this end: 'TransactionFailed \ + {{ msg: \"closing hours, sorry\", hash_opt: None }}'" + ), + &format!( + "DEBUG: {test_name}: Payable '0x0000…00a6' has been marked as pending in the payable table" + ), + &format!( + "DEBUG: {test_name}: Forgetting a transaction attempt that even did not reach the signing stage" + ), + ]); + log_handler.exists_log_matching( + "INFO: payable_scanner_handles_sent_payable_message: The Payable scan ended in \\d+ms.", + ); } #[test] @@ -1163,20 +1156,13 @@ mod tests { let no_of_pending_payables = fingerprints.len(); let pending_payable_dao = PendingPayableDaoMock::new().return_all_fingerprints_result(fingerprints.clone()); - let payment_thresholds = make_payment_thresholds_with_defaults(); - let mut pending_payable_scanner = PendingPayableScanner::new( - Box::new(PayableDaoMock::new()), - Box::new(pending_payable_dao), - Rc::new(payment_thresholds), - 0, - Rc::new(RefCell::new(FinancialStatistics::default())), - ); + let mut pending_payable_scanner = + PendingPayableScanner::default().pending_payable_dao(pending_payable_dao); let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); - let timestamp = pending_payable_scanner.scan_started_at(); - let run_again_result = - pending_payable_scanner.begin_scan(SystemTime::now(), None, &Logger::new(test_name)); + let is_scan_running = pending_payable_scanner.scan_started_at().is_some(); + assert_eq!(is_scan_running, true); assert_eq!( result, Ok(RequestTransactionReceipts { @@ -1184,20 +1170,38 @@ mod tests { response_skeleton_opt: None }) ); - assert_eq!(timestamp, Some(now)); - assert_eq!( - run_again_result, - Err(BeginScanError::ScanAlreadyRunning(now)) - ); TestLogHandler::new().assert_logs_match_in_order(vec![ - &format!("INFO: {}: Scanning for pending payable", test_name), + &format!("INFO: {test_name}: Scanning for pending payable"), &format!( - "DEBUG: {}: Found {} pending payables to process", - test_name, no_of_pending_payables + "DEBUG: {test_name}: Found {no_of_pending_payables} pending payables to process" ), ]) } + #[test] + fn pending_payable_scanner_throws_error_in_case_scan_is_already_running() { + let now = SystemTime::now(); + let pending_payable_dao = + PendingPayableDaoMock::new().return_all_fingerprints_result(vec![ + PendingPayableFingerprint { + rowid_opt: Some(1234), + timestamp: SystemTime::now(), + hash: Default::default(), + attempt_opt: Some(1), + amount: 1_000_000, + process_error: None, + }, + ]); + let mut subject = PendingPayableScanner::default().pending_payable_dao(pending_payable_dao); + let _ = subject.begin_scan(now, None, &Logger::new("test")); + + let result = subject.begin_scan(SystemTime::now(), None, &Logger::new("test")); + + let is_scan_running = subject.scan_started_at().is_some(); + assert_eq!(is_scan_running, true); + assert_eq!(result, Err(BeginScanError::ScanAlreadyRunning(now))); + } + #[test] fn pending_payable_scanner_throws_an_error_when_no_fingerprint_is_found() { init_test_logging(); @@ -1205,14 +1209,8 @@ mod tests { let now = SystemTime::now(); let pending_payable_dao = PendingPayableDaoMock::new().return_all_fingerprints_result(vec![]); - let payment_thresholds = make_payment_thresholds_with_defaults(); - let mut pending_payable_scanner = PendingPayableScanner::new( - Box::new(PayableDaoMock::new()), - Box::new(pending_payable_dao), - Rc::new(payment_thresholds), - 0, - Rc::new(RefCell::new(FinancialStatistics::default())), - ); + let mut pending_payable_scanner = + PendingPayableScanner::default().pending_payable_dao(pending_payable_dao); let result = pending_payable_scanner.begin_scan(now, None, &Logger::new(test_name)); @@ -1220,11 +1218,8 @@ mod tests { assert_eq!(result, Err(BeginScanError::NothingToProcess)); assert_eq!(is_scan_running, false); TestLogHandler::new().assert_logs_match_in_order(vec![ - &format!("INFO: {}: Scanning for pending payable", test_name), - &format!( - "DEBUG: {}: Pending payable scan ended. No pending payable found.", - test_name - ), + &format!("INFO: {test_name}: Scanning for pending payable"), + &format!("DEBUG: {test_name}: Pending payable scan ended. No pending payable found."), ]) } @@ -1232,6 +1227,7 @@ mod tests { fn interpret_transaction_receipt_when_transaction_status_is_none_and_outside_waiting_interval() { init_test_logging(); + let test_name = "interpret_transaction_receipt_when_transaction_status_is_none_and_outside_waiting_interval"; let hash = H256::from_uint(&U256::from(567)); let rowid = 466; let tx_receipt = TransactionReceipt::default(); //status defaulted to None @@ -1250,28 +1246,30 @@ mod tests { let result = subject.interpret_transaction_receipt( &tx_receipt, &fingerprint, - &Logger::new("receipt_check_logger"), + &Logger::new(test_name), ); assert_eq!( result, PendingTransactionStatus::Failure(PendingPayableId { hash, rowid }) ); - TestLogHandler::new().exists_log_containing( - "ERROR: receipt_check_logger: Pending transaction '0x0000…0237' has exceeded the maximum \ - pending time (21600sec) and the confirmation process is going to be aborted now at the final attempt 10; manual resolution is required from the user to \ - complete the transaction", - ); + TestLogHandler::new().exists_log_containing(&format!( + "ERROR: {test_name}: Pending transaction '0x0000…0237' has exceeded the maximum \ + pending time (21600sec) and the confirmation process is going to be aborted now \ + at the final attempt 10; manual resolution is required from the user to complete \ + the transaction" + )); } #[test] fn interpret_transaction_receipt_when_transaction_status_is_none_and_within_waiting_interval() { init_test_logging(); + let test_name = "interpret_transaction_receipt_when_transaction_status_is_none_and_within_waiting_interval"; + let subject = PendingPayableScanner::default(); let hash = H256::from_uint(&U256::from(567)); let rowid = 466; let tx_receipt = TransactionReceipt::default(); //status defaulted to None let when_sent = SystemTime::now().sub(Duration::from_millis(100)); - let subject = PendingPayableScanner::default(); let fingerprint = PendingPayableFingerprint { rowid_opt: Some(rowid), timestamp: when_sent, @@ -1284,17 +1282,17 @@ mod tests { let result = subject.interpret_transaction_receipt( &tx_receipt, &fingerprint, - &Logger::new("none_within_waiting"), + &Logger::new(test_name), ); assert_eq!( result, PendingTransactionStatus::StillPending(PendingPayableId { hash, rowid }) ); - TestLogHandler::new().exists_log_containing( - "INFO: none_within_waiting: Pending \ + TestLogHandler::new().exists_log_containing(&format!( + "INFO: {test_name}: Pending \ transaction '0x0000…0237' couldn't be confirmed at attempt 1 at ", - ); + )); } #[test] @@ -1308,16 +1306,14 @@ mod tests { fingerprint.hash = H256::from_uint(&U256::from(123)); let subject = PendingPayableScanner::default(); - let _ = subject.interpret_transaction_receipt( - &tx_receipt, - &fingerprint, - &Logger::new("receipt_check_logger"), - ); + let _ = + subject.interpret_transaction_receipt(&tx_receipt, &fingerprint, &Logger::new("test")); } #[test] fn interpret_transaction_receipt_when_transaction_status_is_a_failure() { init_test_logging(); + let test_name = "interpret_transaction_receipt_when_transaction_status_is_a_failure"; let subject = PendingPayableScanner::default(); let mut tx_receipt = TransactionReceipt::default(); tx_receipt.status = Some(U64::from(0)); //failure @@ -1334,7 +1330,7 @@ mod tests { let result = subject.interpret_transaction_receipt( &tx_receipt, &fingerprint, - &Logger::new("receipt_check_logger"), + &Logger::new(test_name), ); assert_eq!( @@ -1344,13 +1340,16 @@ mod tests { rowid: 777777, }) ); - TestLogHandler::new().exists_log_matching("ERROR: receipt_check_logger: Pending \ - transaction '0x0000…11d7' announced as a failure, interpreting attempt 5 after 1500\\d\\dms from the sending"); + TestLogHandler::new().exists_log_matching(&format!( + "ERROR: {test_name}: Pending transaction '0x0000…11d7' announced as a failure, \ + interpreting attempt 5 after 1500\\d\\dms from the sending" + )); } #[test] fn handle_pending_tx_handles_none_returned_for_transaction_receipt() { init_test_logging(); + let test_name = "handle_pending_tx_handles_none_returned_for_transaction_receipt"; let subject = PendingPayableScanner::default(); let tx_receipt_opt = None; let rowid = 455; @@ -1368,8 +1367,8 @@ mod tests { response_skeleton_opt: None, }; - let result = subject - .handle_pending_transaction_with_its_receipt(&msg, &Logger::new("Handle Pending Tx")); + let result = + subject.handle_pending_transaction_with_its_receipt(&msg, &Logger::new(test_name)); assert_eq!( result, @@ -1378,24 +1377,24 @@ mod tests { rowid, })] ); - TestLogHandler::new() - .exists_log_matching("DEBUG: Handle Pending Tx: Interpreting a receipt for transaction '0x0000…0913' but none was given; attempt 3, 100\\d\\dms since sending"); + TestLogHandler::new().exists_log_matching(&format!( + "DEBUG: {test_name}: Interpreting a receipt for transaction '0x0000…0913' \ + but none was given; attempt 3, 100\\d\\dms since sending" + )); } #[test] fn update_payable_fingerprint_happy_path() { - let test_name = "update_payable_fingerprint_happy_path"; let update_after_cycle_params_arc = Arc::new(Mutex::new(vec![])); let hash = H256::from_uint(&U256::from(444888)); let rowid = 3456; let pending_payable_dao = PendingPayableDaoMock::default() .update_fingerprint_params(&update_after_cycle_params_arc) .update_fingerprint_results(Ok(())); - let subject = - make_pending_payable_scanner_from_daos(PayableDaoMock::new(), pending_payable_dao); + let subject = PendingPayableScanner::default().pending_payable_dao(pending_payable_dao); let transaction_id = PendingPayableId { hash, rowid }; - subject.update_payable_fingerprint(transaction_id, &Logger::new(test_name)); + subject.update_payable_fingerprint(transaction_id, &Logger::new("test")); let update_after_cycle_params = update_after_cycle_params_arc.lock().unwrap(); assert_eq!(*update_after_cycle_params, vec![rowid]) @@ -1406,28 +1405,26 @@ mod tests { '0x000000000000000000000000000000000000000000000000000000000006c9d8' \ due to UpdateFailed(\"yeah, bad\")")] fn update_payable_fingerprint_sad_path() { - let test_name = "update_payable_fingerprint_sad_path"; let hash = H256::from_uint(&U256::from(444888)); let rowid = 3456; let pending_payable_dao = PendingPayableDaoMock::default().update_fingerprint_results(Err( PendingPayableDaoError::UpdateFailed("yeah, bad".to_string()), )); - let subject = - make_pending_payable_scanner_from_daos(PayableDaoMock::new(), pending_payable_dao); + let subject = PendingPayableScanner::default().pending_payable_dao(pending_payable_dao); let transaction_id = PendingPayableId { hash, rowid }; - subject.update_payable_fingerprint(transaction_id, &Logger::new(test_name)); + subject.update_payable_fingerprint(transaction_id, &Logger::new("test")); } #[test] fn order_cancel_pending_transaction_works() { init_test_logging(); + let test_name = "order_cancel_pending_transaction_works"; let mark_failure_params_arc = Arc::new(Mutex::new(vec![])); let pending_payable_dao = PendingPayableDaoMock::default() .mark_failure_params(&mark_failure_params_arc) .mark_failure_result(Ok(())); - let subject = - make_pending_payable_scanner_from_daos(PayableDaoMock::new(), pending_payable_dao); + let subject = PendingPayableScanner::default().pending_payable_dao(pending_payable_dao); let tx_hash = H256::from("sometransactionhash".keccak256()); let rowid = 2; let transaction_id = PendingPayableId { @@ -1435,15 +1432,15 @@ mod tests { rowid, }; - subject.order_cancel_failed_transaction(transaction_id, &Logger::new("CancelPendingTxOk")); + subject.order_cancel_failed_transaction(transaction_id, &Logger::new(test_name)); let mark_failure_params = mark_failure_params_arc.lock().unwrap(); assert_eq!(*mark_failure_params, vec![rowid]); - TestLogHandler::new().exists_log_containing( - "WARN: CancelPendingTxOk: Broken transaction 0x051a…8c19 left with an error \ + TestLogHandler::new().exists_log_containing(&format!( + "WARN: {test_name}: Broken transaction 0x051a…8c19 left with an error \ mark; you should take over the care of this transaction to make sure your debts will \ be paid because there is no automated process that can fix this without you", - ); + )); } #[test] @@ -1451,17 +1448,19 @@ mod tests { expected = "Unsuccessful attempt for transaction 0x051a…8c19 to mark fatal error at payable \ fingerprint due to UpdateFailed(\"no no no\"); database unreliable" )] - fn order_cancel_pending_transaction_throws_error_when_it_fails_to_mark_failure() { + fn order_cancel_pending_transaction_panics_when_it_fails_to_mark_failure() { let payable_dao = PayableDaoMock::default().transaction_canceled_result(Ok(())); let pending_payable_dao = PendingPayableDaoMock::default().mark_failure_result(Err( PendingPayableDaoError::UpdateFailed("no no no".to_string()), )); - let subject = make_pending_payable_scanner_from_daos(payable_dao, pending_payable_dao); + let subject = PendingPayableScanner::default() + .payable_dao(payable_dao) + .pending_payable_dao(pending_payable_dao); let rowid = 2; let hash = H256::from("sometransactionhash".keccak256()); let transaction_id = PendingPayableId { hash, rowid }; - subject.order_cancel_failed_transaction(transaction_id, &Logger::new("CancelPendingTxOk")); + subject.order_cancel_failed_transaction(transaction_id, &Logger::new("test")); } #[test] @@ -1469,10 +1468,7 @@ mod tests { expected = "Was unable to delete payable fingerprint '0x0000…0315' after successful \ transaction due to 'RecordDeletion(\"the database is fooling around with us\")'" )] - fn handle_confirm_pending_transaction_throws_error_while_deleting_pending_payable_fingerprint() - { - init_test_logging(); - let test_name = "handle_confirm_pending_transaction_throws_error_while_deleting_pending_payable_fingerprint"; + fn handle_confirm_pending_transaction_panics_while_deleting_pending_payable_fingerprint() { let hash = H256::from_uint(&U256::from(789)); let rowid = 3; let payable_dao = PayableDaoMock::new().transaction_confirmed_result(Ok(())); @@ -1481,18 +1477,20 @@ mod tests { "the database is fooling around with us".to_string(), ), )); - let mut subject = make_pending_payable_scanner_from_daos(payable_dao, pending_payable_dao); + let mut subject = PendingPayableScanner::default() + .payable_dao(payable_dao) + .pending_payable_dao(pending_payable_dao); let mut pending_payable_fingerprint = make_pending_payable_fingerprint(); pending_payable_fingerprint.rowid_opt = Some(rowid); pending_payable_fingerprint.hash = hash; - subject.order_confirm_transaction(pending_payable_fingerprint, &Logger::new(test_name)); + subject.order_confirm_transaction(pending_payable_fingerprint, &Logger::new("test")); } #[test] - fn handle_confirm_transaction_works() { + fn order_confirm_transaction_works() { init_test_logging(); - let test_name = "handle_confirm_transaction_works"; + let test_name = "order_confirm_transaction_works"; let transaction_confirmed_params_arc = Arc::new(Mutex::new(vec![])); let delete_pending_payable_fingerprint_params_arc = Arc::new(Mutex::new(vec![])); let payable_dao = PayableDaoMock::default() @@ -1501,7 +1499,9 @@ mod tests { let pending_payable_dao = PendingPayableDaoMock::default() .delete_fingerprint_params(&delete_pending_payable_fingerprint_params_arc) .delete_fingerprint_result(Ok(())); - let mut subject = make_pending_payable_scanner_from_daos(payable_dao, pending_payable_dao); + let mut subject = PendingPayableScanner::default() + .payable_dao(payable_dao) + .pending_payable_dao(pending_payable_dao); let tx_hash = H256::from("sometransactionhash".keccak256()); let amount = 4567; let timestamp_from_time_of_payment = from_time_t(200_000_000); @@ -1559,10 +1559,11 @@ mod tests { .transaction_confirmed_params(&transaction_confirmed_params_arc) .transaction_confirmed_result(Ok(())) .transaction_confirmed_result(Ok(())); - let mut pending_payable_dao = + let pending_payable_dao = PendingPayableDaoMock::default().delete_fingerprint_result(Ok(())); - pending_payable_dao.have_return_all_fingerprints_shut_down_the_system = true; - let mut subject = make_pending_payable_scanner_from_daos(payable_dao, pending_payable_dao); + let mut subject = PendingPayableScanner::default() + .payable_dao(payable_dao) + .pending_payable_dao(pending_payable_dao); let mut financial_statistics = subject.financial_statistics(); financial_statistics.total_paid_payable += 1111; subject.financial_statistics.replace(financial_statistics); @@ -1580,27 +1581,24 @@ mod tests { expected = "Was unable to uncheck pending payable '0x0000…0315' after confirmation due to \ 'RusqliteError(\"record change not successful\")'" )] - fn order_confirm_transaction_throws_error_on_unchecking_payable_table() { - init_test_logging(); - let test_name = "order_confirm_transaction_throws_error_on_unchecking_payable_table"; + fn order_confirm_transaction_panics_on_unchecking_payable_table() { let hash = H256::from_uint(&U256::from(789)); let rowid = 3; let payable_dao = PayableDaoMock::new().transaction_confirmed_result(Err( PayableDaoError::RusqliteError("record change not successful".to_string()), )); - let mut subject = - make_pending_payable_scanner_from_daos(payable_dao, PendingPayableDaoMock::new()); + let mut subject = PendingPayableScanner::default().payable_dao(payable_dao); let mut fingerprint = make_pending_payable_fingerprint(); fingerprint.rowid_opt = Some(rowid); fingerprint.hash = hash; - subject.order_confirm_transaction(fingerprint, &Logger::new(test_name)); + subject.order_confirm_transaction(fingerprint, &Logger::new("test")); } #[test] fn pending_payable_scanner_handles_report_transaction_receipts_message() { init_test_logging(); - let test_name = "accountant_receives_reported_transaction_receipts_and_processes_them_all"; + let test_name = "pending_payable_scanner_handles_report_transaction_receipts_message"; let transaction_confirmed_params_arc = Arc::new(Mutex::new(vec![])); let payable_dao = PayableDaoMock::new() .transaction_confirmed_params(&transaction_confirmed_params_arc) @@ -1609,13 +1607,9 @@ mod tests { let pending_payable_dao = PendingPayableDaoMock::new() .delete_fingerprint_result(Ok(())) .delete_fingerprint_result(Ok(())); - let mut subject = PendingPayableScanner::new( - Box::new(payable_dao), - Box::new(pending_payable_dao), - Rc::new(make_payment_thresholds_with_defaults()), - DEFAULT_PENDING_TOO_LONG_SEC, - Rc::new(RefCell::new(FinancialStatistics::default())), - ); + let mut subject = PendingPayableScanner::default() + .payable_dao(payable_dao) + .pending_payable_dao(pending_payable_dao); let transaction_hash_1 = H256::from_uint(&U256::from(4545)); let mut transaction_receipt_1 = TransactionReceipt::default(); transaction_receipt_1.transaction_hash = transaction_hash_1; @@ -1658,7 +1652,7 @@ mod tests { vec![fingerprint_1, fingerprint_2] ); assert_eq!(subject.scan_started_at(), None); - TestLogHandler::new().assert_logs_contain_in_order(vec![ + TestLogHandler::new().assert_logs_match_in_order(vec![ &format!( "INFO: {}: Transaction {:?} has gone through the whole confirmation process succeeding", test_name, transaction_hash_1 @@ -1667,10 +1661,9 @@ mod tests { "INFO: {}: Transaction {:?} has gone through the whole confirmation process succeeding", test_name, transaction_hash_2 ), - &format!( - "INFO: {}: The Pending Payable scan ended", - test_name - ), + "INFO: pending_payable_scanner_handles_report_transaction_receipts_message: The \ + Pending Payable scan ended in \\d+ms.", + ]); } @@ -1682,22 +1675,15 @@ mod tests { let receivable_dao = ReceivableDaoMock::new() .new_delinquencies_result(vec![]) .paid_delinquencies_result(vec![]); - let banned_dao = BannedDaoMock::new(); - let payment_thresholds = make_payment_thresholds_with_defaults(); let earning_wallet = make_wallet("earning"); - let mut receivable_scanner = ReceivableScanner::new( - Box::new(receivable_dao), - Box::new(banned_dao), - Rc::new(payment_thresholds), - Rc::new(earning_wallet.clone()), - Rc::new(RefCell::new(FinancialStatistics::default())), - ); + let mut receivable_scanner = ReceivableScanner::default() + .receivable_dao(receivable_dao) + .earning_wallet(earning_wallet.clone()); let result = receivable_scanner.begin_scan(now, None, &Logger::new(test_name)); - let timestamp = receivable_scanner.scan_started_at(); - let run_again_result = - receivable_scanner.begin_scan(SystemTime::now(), None, &Logger::new(test_name)); + let is_scan_running = receivable_scanner.scan_started_at().is_some(); + assert_eq!(is_scan_running, true); assert_eq!( result, Ok(RetrieveTransactions { @@ -1705,17 +1691,30 @@ mod tests { response_skeleton_opt: None }) ); - assert_eq!(timestamp, Some(now)); - assert_eq!( - run_again_result, - Err(BeginScanError::ScanAlreadyRunning(now)) - ); TestLogHandler::new().exists_log_containing(&format!( - "INFO: {}: Scanning for receivables to {}", - test_name, earning_wallet + "INFO: {test_name}: Scanning for receivables to {earning_wallet}" )); } + #[test] + fn receivable_scanner_throws_error_in_case_scan_is_already_running() { + let now = SystemTime::now(); + let receivable_dao = ReceivableDaoMock::new() + .new_delinquencies_result(vec![]) + .paid_delinquencies_result(vec![]); + let earning_wallet = make_wallet("earning"); + let mut receivable_scanner = ReceivableScanner::default() + .receivable_dao(receivable_dao) + .earning_wallet(earning_wallet.clone()); + let _ = receivable_scanner.begin_scan(now, None, &Logger::new("test")); + + let result = receivable_scanner.begin_scan(SystemTime::now(), None, &Logger::new("test")); + + let is_scan_running = receivable_scanner.scan_started_at().is_some(); + assert_eq!(is_scan_running, true); + assert_eq!(result, Err(BeginScanError::ScanAlreadyRunning(now))); + } + #[test] fn receivable_scanner_scans_for_delinquencies() { init_test_logging(); @@ -1732,18 +1731,15 @@ mod tests { .paid_delinquencies_result(vec![newly_unbanned_1.clone(), newly_unbanned_2.clone()]); let ban_parameters_arc = Arc::new(Mutex::new(vec![])); let unban_parameters_arc = Arc::new(Mutex::new(vec![])); + let payment_thresholds = make_custom_payment_thresholds(); let banned_dao = BannedDaoMock::new() .ban_list_result(vec![]) .ban_parameters(&ban_parameters_arc) .unban_parameters(&unban_parameters_arc); - let payment_thresholds = make_payment_thresholds_with_defaults(); - let mut receivable_scanner = ReceivableScanner::new( - Box::new(receivable_dao), - Box::new(banned_dao), - Rc::new(payment_thresholds.clone()), - Rc::new(make_wallet("earning")), - Rc::new(RefCell::new(FinancialStatistics::default())), - ); + let mut receivable_scanner = ReceivableScanner::default() + .receivable_dao(receivable_dao) + .banned_dao(banned_dao) + .payment_thresholds(payment_thresholds.clone()); let _result = receivable_scanner.begin_scan( SystemTime::now(), @@ -1759,7 +1755,7 @@ mod tests { ); let paid_delinquencies_parameters: MutexGuard> = paid_delinquencies_parameters_arc.lock().unwrap(); - assert_eq!(payment_thresholds.clone(), paid_delinquencies_parameters[0]); + assert_eq!(payment_thresholds, paid_delinquencies_parameters[0]); let ban_parameters = ban_parameters_arc.lock().unwrap(); assert!(ban_parameters.contains(&newly_banned_1.wallet)); assert!(ban_parameters.contains(&newly_banned_2.wallet)); @@ -1769,18 +1765,29 @@ mod tests { assert!(unban_parameters.contains(&newly_unbanned_2.wallet)); assert_eq!(2, unban_parameters.len()); let tlh = TestLogHandler::new(); - tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c65743132333464 \\(balance: 1234 MASQ, age: \\d+ sec\\) banned for delinquency"); - tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c65743233343564 \\(balance: 2345 MASQ, age: \\d+ sec\\) banned for delinquency"); - tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574333435366e \\(balance: 3456 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); - tlh.exists_log_matching("INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574343536376e \\(balance: 4567 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned"); + tlh.exists_log_matching( + "INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c65743132333464 \ + \\(balance: 1234 MASQ, age: \\d+ sec\\) banned for delinquency", + ); + tlh.exists_log_matching( + "INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c65743233343564 \ + \\(balance: 2345 MASQ, age: \\d+ sec\\) banned for delinquency", + ); + tlh.exists_log_matching( + "INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574333435366e \ + \\(balance: 3456 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned", + ); + tlh.exists_log_matching( + "INFO: DELINQUENCY_TEST: Wallet 0x00000000000000000077616c6c6574343536376e \ + \\(balance: 4567 MASQ, age: \\d+ sec\\) is no longer delinquent: unbanned", + ); } #[test] fn receivable_scanner_aborts_scan_if_no_payments_were_supplied() { init_test_logging(); let test_name = "receivable_scanner_aborts_scan_if_no_payments_were_supplied"; - let mut subject = - make_receivable_scanner_from_daos(ReceivableDaoMock::new(), BannedDaoMock::new()); + let mut subject = ReceivableScanner::default(); let msg = ReceivedPayments { payments: vec![], response_skeleton_opt: None, @@ -1798,12 +1805,12 @@ mod tests { #[test] fn receivable_scanner_handles_received_payments_message() { init_test_logging(); - let test_name = "total_paid_receivable_rises_with_each_bill_paid"; + let test_name = "receivable_scanner_handles_received_payments_message"; let more_money_received_params_arc = Arc::new(Mutex::new(vec![])); let receivable_dao = ReceivableDaoMock::new() .more_money_received_parameters(&more_money_received_params_arc) .more_money_receivable_result(Ok(())); - let mut subject = make_receivable_scanner_from_daos(receivable_dao, BannedDaoMock::new()); + let mut subject = ReceivableScanner::default().receivable_dao(receivable_dao); let mut financial_statistics = subject.financial_statistics(); financial_statistics.total_paid_receivable += 2222; subject.financial_statistics.replace(financial_statistics); @@ -1833,33 +1840,99 @@ mod tests { assert_eq!(subject.scan_started_at(), None); assert_eq!(total_paid_receivable, 2222 + 45780 + 33345); assert_eq!(*more_money_received_params, vec![receivables]); - TestLogHandler::new() - .exists_log_containing(&format!("INFO: {}: The Receivable scan ended", test_name)); + TestLogHandler::new().exists_log_matching( + "INFO: receivable_scanner_handles_received_payments_message: The Receivable scan ended in \\d+ms.", + ); } - fn make_pending_payable_scanner_from_daos( - payable_dao: PayableDaoMock, - pending_payable_dao: PendingPayableDaoMock, - ) -> PendingPayableScanner { - PendingPayableScanner::new( - Box::new(payable_dao), - Box::new(pending_payable_dao), - Rc::new(make_payment_thresholds_with_defaults()), - DEFAULT_PENDING_TOO_LONG_SEC, - Rc::new(RefCell::new(FinancialStatistics::default())), - ) + impl Default for PayableScanner { + fn default() -> Self { + PayableScanner::new( + Box::new(PayableDaoMock::new()), + Box::new(PendingPayableDaoMock::new()), + Rc::new(make_payment_thresholds_with_defaults()), + ) + } } - fn make_receivable_scanner_from_daos( - receivable_dao: ReceivableDaoMock, - banned_dao: BannedDaoMock, - ) -> ReceivableScanner { - ReceivableScanner::new( - Box::new(receivable_dao), - Box::new(banned_dao), - Rc::new(make_payment_thresholds_with_defaults()), - Rc::new(make_wallet("earning")), - Rc::new(RefCell::new(FinancialStatistics::default())), - ) + impl PayableScanner { + pub fn payable_dao(mut self, payable_dao: PayableDaoMock) -> Self { + self.payable_dao = Box::new(payable_dao); + self + } + + pub fn pending_payable_dao(mut self, pending_payable_dao: PendingPayableDaoMock) -> Self { + self.pending_payable_dao = Box::new(pending_payable_dao); + self + } + } + + impl Default for PendingPayableScanner { + fn default() -> Self { + PendingPayableScanner::new( + Box::new(PayableDaoMock::new()), + Box::new(PendingPayableDaoMock::new()), + Rc::new(make_payment_thresholds_with_defaults()), + DEFAULT_PENDING_TOO_LONG_SEC, + Rc::new(RefCell::new(FinancialStatistics::default())), + ) + } + } + + impl PendingPayableScanner { + pub fn payable_dao(mut self, payable_dao: PayableDaoMock) -> Self { + self.payable_dao = Box::new(payable_dao); + self + } + + pub fn pending_payable_dao(mut self, pending_payable_dao: PendingPayableDaoMock) -> Self { + self.pending_payable_dao = Box::new(pending_payable_dao); + self + } + } + + impl Default for ReceivableScanner { + fn default() -> Self { + ReceivableScanner::new( + Box::new(ReceivableDaoMock::new()), + Box::new(BannedDaoMock::new()), + Rc::new(make_payment_thresholds_with_defaults()), + Rc::new(make_wallet("earning")), + Rc::new(RefCell::new(FinancialStatistics::default())), + ) + } + } + + impl ReceivableScanner { + pub fn receivable_dao(mut self, receivable_dao: ReceivableDaoMock) -> Self { + self.receivable_dao = Box::new(receivable_dao); + self + } + + pub fn banned_dao(mut self, banned_dao: BannedDaoMock) -> Self { + self.banned_dao = Box::new(banned_dao); + self + } + + pub fn payment_thresholds(mut self, payment_thresholds: PaymentThresholds) -> Self { + self.common.payment_thresholds = Rc::new(payment_thresholds); + self + } + + pub fn earning_wallet(mut self, earning_wallet: Wallet) -> Self { + self.earning_wallet = Rc::new(earning_wallet); + self + } + } + + fn make_custom_payment_thresholds() -> PaymentThresholds { + PaymentThresholds { + threshold_interval_sec: 2_592_000, + debt_threshold_gwei: 1_000_000_000, + payment_grace_period_sec: 86_400, + maturity_threshold_sec: 86_400, + permanent_debt_allowed_gwei: 10_000_000, + unban_below_gwei: 10_000_000, + } } } diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index f428c8189..6ea16e772 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -293,17 +293,6 @@ mod tests { use std::rc::Rc; use std::time::SystemTime; - // fn make_custom_payment_thresholds() -> PaymentThresholds { - // PaymentThresholds { - // threshold_interval_sec: 2_592_000, - // debt_threshold_gwei: 1_000_000_000, - // payment_grace_period_sec: 86_400, - // maturity_threshold_sec: 86_400, - // permanent_debt_allowed_gwei: 10_000_000, - // unban_below_gwei: 10_000_000, - // } - // } - #[test] fn payable_generated_before_maturity_time_limit_is_marked_unqualified() { let now = SystemTime::now(); diff --git a/node/src/sub_lib/accountant.rs b/node/src/sub_lib/accountant.rs index f5a7809d2..a96c0fb4a 100644 --- a/node/src/sub_lib/accountant.rs +++ b/node/src/sub_lib/accountant.rs @@ -38,7 +38,7 @@ lazy_static! { } //please, alphabetical order -#[derive(PartialEq, Debug, Clone, Default)] +#[derive(PartialEq, Debug, Clone)] pub struct PaymentThresholds { pub debt_threshold_gwei: i64, // Paybale pub maturity_threshold_sec: i64, // Payable diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index cc81f1d36..9c8a34f18 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -610,6 +610,12 @@ pub mod unshared_test_utils { config } + impl Default for PaymentThresholds { + fn default() -> Self { + DEFAULT_PAYMENT_THRESHOLDS.clone() + } + } + pub fn make_payment_thresholds_with_defaults() -> PaymentThresholds { DEFAULT_PAYMENT_THRESHOLDS.clone() } From 482b8aedc43bb36c079ed7e726ba9d0cd1a17829 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 28 Sep 2022 12:00:01 +0530 Subject: [PATCH 140/145] GH-611: use default implementation of PaymentThresholds --- node/src/accountant/mod.rs | 13 +++++-------- node/src/accountant/scanners.rs | 9 ++++----- node/src/accountant/tools.rs | 14 +++++++------- node/src/actor_system_factory.rs | 6 +++--- node/src/daemon/setup_reporter.rs | 10 +++++----- node/src/sub_lib/accountant.rs | 14 ++++++++++---- node/src/sub_lib/combined_parameters.rs | 13 +++++-------- node/src/test_utils/mod.rs | 14 ++------------ 8 files changed, 41 insertions(+), 52 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 4d363626c..888694290 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -874,8 +874,8 @@ mod tests { use crate::test_utils::recorder::peer_actors_builder; use crate::test_utils::recorder::Recorder; use crate::test_utils::unshared_test_utils::{ - make_bc_with_defaults, make_payment_thresholds_with_defaults, - prove_that_crash_request_handler_is_hooked_up, NotifyLaterHandleMock, SystemKillerActor, + make_bc_with_defaults, prove_that_crash_request_handler_is_hooked_up, + NotifyLaterHandleMock, SystemKillerActor, }; use crate::test_utils::{make_paying_wallet, make_wallet}; use web3::types::{TransactionReceipt, H256}; @@ -1500,7 +1500,7 @@ mod tests { { let (blockchain_bridge, _, blockchain_bridge_recording_arc) = make_recorder(); let now = SystemTime::now(); - let payment_thresholds = make_payment_thresholds_with_defaults(); + let payment_thresholds = PaymentThresholds::default(); let (qualified_payables, _, all_non_pending_payables) = make_payables(now, &payment_thresholds); let payable_dao = @@ -1689,12 +1689,9 @@ mod tests { captured_timestamp < SystemTime::now() && captured_timestamp >= from_time_t(to_time_t(SystemTime::now()) - 5) ); - assert_eq!(captured_curves, make_payment_thresholds_with_defaults()); + assert_eq!(captured_curves, PaymentThresholds::default()); assert_eq!(paid_delinquencies_params.len(), 1); - assert_eq!( - paid_delinquencies_params[0], - make_payment_thresholds_with_defaults() - ); + assert_eq!(paid_delinquencies_params[0], PaymentThresholds::default()); } #[test] diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 7142043e0..85e03202e 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -888,7 +888,6 @@ mod tests { use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; use crate::sub_lib::wallet::Wallet; use crate::test_utils::make_wallet; - use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; use ethereum_types::{BigEndianHash, U64}; use ethsign_crypto::Keccak256; use masq_lib::logger::Logger; @@ -900,7 +899,7 @@ mod tests { #[test] fn scanners_struct_can_be_constructed_with_the_respective_scanners() { - let payment_thresholds = Rc::new(make_payment_thresholds_with_defaults()); + let payment_thresholds = Rc::new(PaymentThresholds::default()); let payable_dao_factory = PayableDaoFactoryMock::new() .make_result(PayableDaoMock::new()) .make_result(PayableDaoMock::new()); @@ -1850,7 +1849,7 @@ mod tests { PayableScanner::new( Box::new(PayableDaoMock::new()), Box::new(PendingPayableDaoMock::new()), - Rc::new(make_payment_thresholds_with_defaults()), + Rc::new(PaymentThresholds::default()), ) } } @@ -1872,7 +1871,7 @@ mod tests { PendingPayableScanner::new( Box::new(PayableDaoMock::new()), Box::new(PendingPayableDaoMock::new()), - Rc::new(make_payment_thresholds_with_defaults()), + Rc::new(PaymentThresholds::default()), DEFAULT_PENDING_TOO_LONG_SEC, Rc::new(RefCell::new(FinancialStatistics::default())), ) @@ -1896,7 +1895,7 @@ mod tests { ReceivableScanner::new( Box::new(ReceivableDaoMock::new()), Box::new(BannedDaoMock::new()), - Rc::new(make_payment_thresholds_with_defaults()), + Rc::new(PaymentThresholds::default()), Rc::new(make_wallet("earning")), Rc::new(RefCell::new(FinancialStatistics::default())), ) diff --git a/node/src/accountant/tools.rs b/node/src/accountant/tools.rs index 6ea16e772..74d8472e6 100644 --- a/node/src/accountant/tools.rs +++ b/node/src/accountant/tools.rs @@ -287,8 +287,8 @@ mod tests { use crate::accountant::SentPayable; use crate::blockchain::blockchain_interface::BlockchainError; use crate::database::dao_utils::{from_time_t, to_time_t}; + use crate::sub_lib::accountant::PaymentThresholds; use crate::test_utils::make_wallet; - use crate::test_utils::unshared_test_utils::make_payment_thresholds_with_defaults; use masq_lib::logger::Logger; use std::rc::Rc; use std::time::SystemTime; @@ -296,7 +296,7 @@ mod tests { #[test] fn payable_generated_before_maturity_time_limit_is_marked_unqualified() { let now = SystemTime::now(); - let payment_thresholds = make_payment_thresholds_with_defaults(); + let payment_thresholds = PaymentThresholds::default(); let qualified_debt = payment_thresholds.permanent_debt_allowed_gwei + 1; let unqualified_time = to_time_t(now) - payment_thresholds.maturity_threshold_sec + 1; let unqualified_payable_account = PayableAccount { @@ -314,7 +314,7 @@ mod tests { #[test] fn payable_with_low_debt_is_marked_unqualified() { let now = SystemTime::now(); - let payment_thresholds = make_payment_thresholds_with_defaults(); + let payment_thresholds = PaymentThresholds::default(); let unqualified_debt = payment_thresholds.permanent_debt_allowed_gwei - 1; let qualified_time = to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1; let unqualified_payable_account = PayableAccount { @@ -332,7 +332,7 @@ mod tests { #[test] fn payable_with_low_payout_threshold_is_marked_unqualified() { let now = SystemTime::now(); - let payment_thresholds = make_payment_thresholds_with_defaults(); + let payment_thresholds = PaymentThresholds::default(); let debt = payment_thresholds.permanent_debt_allowed_gwei + 1; let time = to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1; let unqualified_payable_account = PayableAccount { @@ -350,7 +350,7 @@ mod tests { #[test] fn payable_above_threshold_values_is_marked_qualified_and_returns_threshold() { let now = SystemTime::now(); - let payment_thresholds = make_payment_thresholds_with_defaults(); + let payment_thresholds = PaymentThresholds::default(); let debt = payment_thresholds.permanent_debt_allowed_gwei + 1_000_000_000; let time = to_time_t(now) - payment_thresholds.maturity_threshold_sec - 1; let payment_thresholds_rc = Rc::new(payment_thresholds); @@ -374,7 +374,7 @@ mod tests { #[test] fn qualified_payables_can_be_filtered_out_from_non_pending_payables_along_with_their_summary() { let now = SystemTime::now(); - let payment_thresholds = make_payment_thresholds_with_defaults(); + let payment_thresholds = PaymentThresholds::default(); let unqualified_payable_accounts = vec![PayableAccount { wallet: make_wallet("wallet1"), balance: payment_thresholds.permanent_debt_allowed_gwei + 1, @@ -425,7 +425,7 @@ mod tests { #[test] fn returns_empty_array_and_summary_when_no_qualified_payables_are_found() { let now = SystemTime::now(); - let payment_thresholds = make_payment_thresholds_with_defaults(); + let payment_thresholds = PaymentThresholds::default(); let unqualified_payable_accounts = vec![PayableAccount { wallet: make_wallet("wallet1"), balance: payment_thresholds.permanent_debt_allowed_gwei + 1, diff --git a/node/src/actor_system_factory.rs b/node/src/actor_system_factory.rs index 94b9bc8da..ffb067fd8 100644 --- a/node/src/actor_system_factory.rs +++ b/node/src/actor_system_factory.rs @@ -607,6 +607,7 @@ mod tests { make_stream_handler_pool_subs_from, make_stream_handler_pool_subs_from_recorder, start_recorder_refcell_opt, }; + use crate::sub_lib::accountant::PaymentThresholds; use crate::sub_lib::blockchain_bridge::BlockchainBridgeConfig; use crate::sub_lib::cryptde::{PlainData, PublicKey}; use crate::sub_lib::cryptde_null::CryptDENull; @@ -629,8 +630,7 @@ mod tests { }; use crate::test_utils::recorder::{make_recorder, Recorder}; use crate::test_utils::unshared_test_utils::{ - make_payment_thresholds_with_defaults, make_scan_intervals_with_defaults, ArbitraryIdStamp, - SystemKillerActor, + make_scan_intervals_with_defaults, ArbitraryIdStamp, SystemKillerActor, }; use crate::test_utils::{alias_cryptde, rate_pack}; use crate::test_utils::{main_cryptde, make_cryptde_pair}; @@ -1056,7 +1056,7 @@ mod tests { rate_pack(100), ), }, - payment_thresholds_opt: Some(make_payment_thresholds_with_defaults()), + payment_thresholds_opt: Some(PaymentThresholds::default()), when_pending_too_long_opt: Some(DEFAULT_PENDING_TOO_LONG_SEC), }; let persistent_config = diff --git a/node/src/daemon/setup_reporter.rs b/node/src/daemon/setup_reporter.rs index 303561ac6..0fa74534d 100644 --- a/node/src/daemon/setup_reporter.rs +++ b/node/src/daemon/setup_reporter.rs @@ -19,14 +19,13 @@ use crate::node_configurator::unprivileged_parse_args_configuration::{ use crate::node_configurator::{ data_directory_from_context, determine_config_file_path, DirsWrapper, DirsWrapperReal, }; +use crate::sub_lib::accountant::PaymentThresholds as PaymentThresholdsFromAccountant; use crate::sub_lib::accountant::{DEFAULT_PAYMENT_THRESHOLDS, DEFAULT_SCAN_INTERVALS}; use crate::sub_lib::neighborhood::NodeDescriptor; use crate::sub_lib::neighborhood::{NeighborhoodMode as NeighborhoodModeEnum, DEFAULT_RATE_PACK}; use crate::sub_lib::utils::make_new_multi_config; use crate::test_utils::main_cryptde; -use crate::test_utils::unshared_test_utils::{ - make_payment_thresholds_with_defaults, make_scan_intervals_with_defaults, -}; +use crate::test_utils::unshared_test_utils::make_scan_intervals_with_defaults; use clap::value_t; use itertools::Itertools; use masq_lib::blockchains::chains::Chain as BlockChain; @@ -869,7 +868,7 @@ impl ValueRetriever for PaymentThresholds { let pc_value = pc.payment_thresholds().expectv("payment-thresholds"); payment_thresholds_rate_pack_and_scan_intervals( pc_value, - make_payment_thresholds_with_defaults(), + PaymentThresholdsFromAccountant::default(), ) } @@ -1051,6 +1050,7 @@ mod tests { }; use crate::node_configurator::{DirsWrapper, DirsWrapperReal}; use crate::node_test_utils::DirsWrapperMock; + use crate::sub_lib::accountant::PaymentThresholds as PaymentThresholdsFromAccountant; use crate::sub_lib::cryptde::PublicKey; use crate::sub_lib::node_addr::NodeAddr; use crate::sub_lib::wallet::Wallet; @@ -3122,7 +3122,7 @@ mod tests { #[test] fn payment_thresholds_computed_default_persistent_config_unequal_to_default() { - let mut payment_thresholds = make_payment_thresholds_with_defaults(); + let mut payment_thresholds = PaymentThresholdsFromAccountant::default(); payment_thresholds.maturity_threshold_sec += 12; payment_thresholds.unban_below_gwei -= 11; payment_thresholds.debt_threshold_gwei += 1111; diff --git a/node/src/sub_lib/accountant.rs b/node/src/sub_lib/accountant.rs index a96c0fb4a..39bfc01cd 100644 --- a/node/src/sub_lib/accountant.rs +++ b/node/src/sub_lib/accountant.rs @@ -40,14 +40,20 @@ lazy_static! { //please, alphabetical order #[derive(PartialEq, Debug, Clone)] pub struct PaymentThresholds { - pub debt_threshold_gwei: i64, // Paybale - pub maturity_threshold_sec: i64, // Payable + pub debt_threshold_gwei: i64, + pub maturity_threshold_sec: i64, pub payment_grace_period_sec: i64, - pub permanent_debt_allowed_gwei: i64, // Payable - pub threshold_interval_sec: i64, // Payable + pub permanent_debt_allowed_gwei: i64, + pub threshold_interval_sec: i64, pub unban_below_gwei: i64, } +impl Default for PaymentThresholds { + fn default() -> Self { + DEFAULT_PAYMENT_THRESHOLDS.clone() + } +} + //this code is used in tests in Accountant impl PaymentThresholds { pub fn sugg_and_grace(&self, now: i64) -> i64 { diff --git a/node/src/sub_lib/combined_parameters.rs b/node/src/sub_lib/combined_parameters.rs index 89ed54943..6fd7a20fb 100644 --- a/node/src/sub_lib/combined_parameters.rs +++ b/node/src/sub_lib/combined_parameters.rs @@ -292,9 +292,7 @@ mod tests { use super::*; use crate::sub_lib::combined_parameters::CombinedParamsDataTypes::U128; use crate::sub_lib::neighborhood::DEFAULT_RATE_PACK; - use crate::test_utils::unshared_test_utils::{ - make_payment_thresholds_with_defaults, make_scan_intervals_with_defaults, - }; + use crate::test_utils::unshared_test_utils::make_scan_intervals_with_defaults; use std::panic::catch_unwind; #[test] @@ -427,8 +425,7 @@ mod tests { let panic_2 = catch_unwind(|| { let _: &[(&str, CombinedParamsDataTypes)] = - (&CombinedParams::PaymentThresholds(Some(make_payment_thresholds_with_defaults()))) - .into(); + (&CombinedParams::PaymentThresholds(Some(PaymentThresholds::default()))).into(); }) .unwrap_err(); let panic_2_msg = panic_2.downcast_ref::().unwrap(); @@ -437,7 +434,7 @@ mod tests { panic_2_msg, &format!( "should be called only on uninitialized object, not: PaymentThresholds(Some({:?}))", - make_payment_thresholds_with_defaults() + PaymentThresholds::default() ) ); @@ -474,7 +471,7 @@ mod tests { ); let panic_2 = catch_unwind(|| { - (&CombinedParams::PaymentThresholds(Some(make_payment_thresholds_with_defaults()))) + (&CombinedParams::PaymentThresholds(Some(PaymentThresholds::default()))) .initiate_objects(HashMap::new()); }) .unwrap_err(); @@ -484,7 +481,7 @@ mod tests { panic_2_msg, &format!( "should be called only on uninitialized object, not: PaymentThresholds(Some({:?}))", - make_payment_thresholds_with_defaults() + PaymentThresholds::default() ) ); diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 9c8a34f18..3a9043cf7 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -593,7 +593,7 @@ pub mod unshared_test_utils { persistent_config_mock: PersistentConfigurationMock, ) -> PersistentConfigurationMock { persistent_config_mock - .payment_thresholds_result(Ok(make_payment_thresholds_with_defaults())) + .payment_thresholds_result(Ok(PaymentThresholds::default())) .scan_intervals_result(Ok(make_scan_intervals_with_defaults())) } @@ -606,20 +606,10 @@ pub mod unshared_test_utils { config.scan_intervals_opt = Some(make_scan_intervals_with_defaults()); config.suppress_initial_scans_opt = Some(false); config.when_pending_too_long_opt = Some(DEFAULT_PENDING_TOO_LONG_SEC); - config.payment_thresholds_opt = Some(make_payment_thresholds_with_defaults()); + config.payment_thresholds_opt = Some(PaymentThresholds::default()); config } - impl Default for PaymentThresholds { - fn default() -> Self { - DEFAULT_PAYMENT_THRESHOLDS.clone() - } - } - - pub fn make_payment_thresholds_with_defaults() -> PaymentThresholds { - DEFAULT_PAYMENT_THRESHOLDS.clone() - } - pub fn make_scan_intervals_with_defaults() -> ScanIntervals { DEFAULT_SCAN_INTERVALS.clone() } From 1af6f2b80b4ea4e616a972fad35ac3ef777dab7f Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 28 Sep 2022 12:08:18 +0530 Subject: [PATCH 141/145] GH-611: migrate the test utility functions of scanner.rs to accountant/test_utils.rs --- node/src/accountant/scanners.rs | 98 +------------------------------ node/src/accountant/test_utils.rs | 98 ++++++++++++++++++++++++++++++- node/src/test_utils/mod.rs | 4 +- 3 files changed, 100 insertions(+), 100 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 85e03202e..7bbcab0dc 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -868,9 +868,9 @@ mod tests { BeginScanError, PayableScanner, PendingPayableScanner, ReceivableScanner, Scanner, Scanners, }; use crate::accountant::test_utils::{ - make_payables, make_pending_payable_fingerprint, make_receivable_account, BannedDaoMock, - PayableDaoFactoryMock, PayableDaoMock, PendingPayableDaoFactoryMock, PendingPayableDaoMock, - ReceivableDaoMock, + make_custom_payment_thresholds, make_payables, make_pending_payable_fingerprint, + make_receivable_account, BannedDaoMock, PayableDaoFactoryMock, PayableDaoMock, + PendingPayableDaoFactoryMock, PendingPayableDaoMock, ReceivableDaoMock, }; use crate::accountant::{ PendingPayableId, PendingTransactionStatus, ReceivedPayments, ReportTransactionReceipts, @@ -886,7 +886,6 @@ mod tests { use crate::database::dao_utils::from_time_t; use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; use crate::sub_lib::blockchain_bridge::ReportAccountsPayable; - use crate::sub_lib::wallet::Wallet; use crate::test_utils::make_wallet; use ethereum_types::{BigEndianHash, U64}; use ethsign_crypto::Keccak256; @@ -1843,95 +1842,4 @@ mod tests { "INFO: receivable_scanner_handles_received_payments_message: The Receivable scan ended in \\d+ms.", ); } - - impl Default for PayableScanner { - fn default() -> Self { - PayableScanner::new( - Box::new(PayableDaoMock::new()), - Box::new(PendingPayableDaoMock::new()), - Rc::new(PaymentThresholds::default()), - ) - } - } - - impl PayableScanner { - pub fn payable_dao(mut self, payable_dao: PayableDaoMock) -> Self { - self.payable_dao = Box::new(payable_dao); - self - } - - pub fn pending_payable_dao(mut self, pending_payable_dao: PendingPayableDaoMock) -> Self { - self.pending_payable_dao = Box::new(pending_payable_dao); - self - } - } - - impl Default for PendingPayableScanner { - fn default() -> Self { - PendingPayableScanner::new( - Box::new(PayableDaoMock::new()), - Box::new(PendingPayableDaoMock::new()), - Rc::new(PaymentThresholds::default()), - DEFAULT_PENDING_TOO_LONG_SEC, - Rc::new(RefCell::new(FinancialStatistics::default())), - ) - } - } - - impl PendingPayableScanner { - pub fn payable_dao(mut self, payable_dao: PayableDaoMock) -> Self { - self.payable_dao = Box::new(payable_dao); - self - } - - pub fn pending_payable_dao(mut self, pending_payable_dao: PendingPayableDaoMock) -> Self { - self.pending_payable_dao = Box::new(pending_payable_dao); - self - } - } - - impl Default for ReceivableScanner { - fn default() -> Self { - ReceivableScanner::new( - Box::new(ReceivableDaoMock::new()), - Box::new(BannedDaoMock::new()), - Rc::new(PaymentThresholds::default()), - Rc::new(make_wallet("earning")), - Rc::new(RefCell::new(FinancialStatistics::default())), - ) - } - } - - impl ReceivableScanner { - pub fn receivable_dao(mut self, receivable_dao: ReceivableDaoMock) -> Self { - self.receivable_dao = Box::new(receivable_dao); - self - } - - pub fn banned_dao(mut self, banned_dao: BannedDaoMock) -> Self { - self.banned_dao = Box::new(banned_dao); - self - } - - pub fn payment_thresholds(mut self, payment_thresholds: PaymentThresholds) -> Self { - self.common.payment_thresholds = Rc::new(payment_thresholds); - self - } - - pub fn earning_wallet(mut self, earning_wallet: Wallet) -> Self { - self.earning_wallet = Rc::new(earning_wallet); - self - } - } - - fn make_custom_payment_thresholds() -> PaymentThresholds { - PaymentThresholds { - threshold_interval_sec: 2_592_000, - debt_threshold_gwei: 1_000_000_000, - payment_grace_period_sec: 86_400, - maturity_threshold_sec: 86_400, - permanent_debt_allowed_gwei: 10_000_000, - unban_below_gwei: 10_000_000, - } - } } diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index 257b6f601..c9e1a438c 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -11,7 +11,10 @@ use crate::accountant::pending_payable_dao::{ use crate::accountant::receivable_dao::{ ReceivableAccount, ReceivableDao, ReceivableDaoError, ReceivableDaoFactory, }; -use crate::accountant::{Accountant, PendingPayableId}; +use crate::accountant::scanners::scanners::{ + PayableScanner, PendingPayableScanner, ReceivableScanner, +}; +use crate::accountant::{Accountant, PendingPayableId, DEFAULT_PENDING_TOO_LONG_SEC}; use crate::banned_dao::{BannedDao, BannedDaoFactory}; use crate::blockchain::blockchain_bridge::PendingPayableFingerprint; use crate::blockchain::blockchain_interface::BlockchainTransaction; @@ -20,7 +23,7 @@ use crate::database::dao_utils; use crate::database::dao_utils::{from_time_t, to_time_t}; use crate::db_config::config_dao::{ConfigDao, ConfigDaoFactory}; use crate::db_config::mocks::ConfigDaoMock; -use crate::sub_lib::accountant::PaymentThresholds; +use crate::sub_lib::accountant::{FinancialStatistics, PaymentThresholds}; use crate::sub_lib::wallet::Wallet; use crate::test_utils::make_wallet; use crate::test_utils::unshared_test_utils::make_bc_with_defaults; @@ -883,6 +886,97 @@ impl PendingPayableDaoFactoryMock { } } +impl Default for PayableScanner { + fn default() -> Self { + PayableScanner::new( + Box::new(PayableDaoMock::new()), + Box::new(PendingPayableDaoMock::new()), + Rc::new(PaymentThresholds::default()), + ) + } +} + +impl PayableScanner { + pub fn payable_dao(mut self, payable_dao: PayableDaoMock) -> Self { + self.payable_dao = Box::new(payable_dao); + self + } + + pub fn pending_payable_dao(mut self, pending_payable_dao: PendingPayableDaoMock) -> Self { + self.pending_payable_dao = Box::new(pending_payable_dao); + self + } +} + +impl Default for PendingPayableScanner { + fn default() -> Self { + PendingPayableScanner::new( + Box::new(PayableDaoMock::new()), + Box::new(PendingPayableDaoMock::new()), + Rc::new(PaymentThresholds::default()), + DEFAULT_PENDING_TOO_LONG_SEC, + Rc::new(RefCell::new(FinancialStatistics::default())), + ) + } +} + +impl PendingPayableScanner { + pub fn payable_dao(mut self, payable_dao: PayableDaoMock) -> Self { + self.payable_dao = Box::new(payable_dao); + self + } + + pub fn pending_payable_dao(mut self, pending_payable_dao: PendingPayableDaoMock) -> Self { + self.pending_payable_dao = Box::new(pending_payable_dao); + self + } +} + +impl Default for ReceivableScanner { + fn default() -> Self { + ReceivableScanner::new( + Box::new(ReceivableDaoMock::new()), + Box::new(BannedDaoMock::new()), + Rc::new(PaymentThresholds::default()), + Rc::new(make_wallet("earning")), + Rc::new(RefCell::new(FinancialStatistics::default())), + ) + } +} + +impl ReceivableScanner { + pub fn receivable_dao(mut self, receivable_dao: ReceivableDaoMock) -> Self { + self.receivable_dao = Box::new(receivable_dao); + self + } + + pub fn banned_dao(mut self, banned_dao: BannedDaoMock) -> Self { + self.banned_dao = Box::new(banned_dao); + self + } + + pub fn payment_thresholds(mut self, payment_thresholds: PaymentThresholds) -> Self { + self.common.payment_thresholds = Rc::new(payment_thresholds); + self + } + + pub fn earning_wallet(mut self, earning_wallet: Wallet) -> Self { + self.earning_wallet = Rc::new(earning_wallet); + self + } +} + +pub fn make_custom_payment_thresholds() -> PaymentThresholds { + PaymentThresholds { + threshold_interval_sec: 2_592_000, + debt_threshold_gwei: 1_000_000_000, + payment_grace_period_sec: 86_400, + maturity_threshold_sec: 86_400, + permanent_debt_allowed_gwei: 10_000_000, + unban_below_gwei: 10_000_000, + } +} + pub fn make_pending_payable_fingerprint() -> PendingPayableFingerprint { PendingPayableFingerprint { rowid_opt: Some(33), diff --git a/node/src/test_utils/mod.rs b/node/src/test_utils/mod.rs index 3a9043cf7..f67a81048 100644 --- a/node/src/test_utils/mod.rs +++ b/node/src/test_utils/mod.rs @@ -518,9 +518,7 @@ pub mod unshared_test_utils { use crate::db_config::config_dao_null::ConfigDaoNull; use crate::db_config::persistent_configuration::PersistentConfigurationReal; use crate::node_test_utils::DirsWrapperMock; - use crate::sub_lib::accountant::{ - PaymentThresholds, ScanIntervals, DEFAULT_PAYMENT_THRESHOLDS, DEFAULT_SCAN_INTERVALS, - }; + use crate::sub_lib::accountant::{PaymentThresholds, ScanIntervals, DEFAULT_SCAN_INTERVALS}; use crate::sub_lib::neighborhood::DEFAULT_RATE_PACK; use crate::sub_lib::utils::{ NLSpawnHandleHolder, NLSpawnHandleHolderReal, NotifyHandle, NotifyLaterHandle, From 6e3dd005961f299299356de2ab8ed8c68ffa5e76 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 28 Sep 2022 12:22:52 +0530 Subject: [PATCH 142/145] GH-611: remove BannedDao and PaymentThresholds as a field of Accountant --- node/src/accountant/mod.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 888694290..4dd0b6bf3 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -18,7 +18,7 @@ use crate::accountant::payable_dao::{Payable, PayableAccount, PayableDaoError, P use crate::accountant::pending_payable_dao::{PendingPayableDao, PendingPayableDaoFactory}; use crate::accountant::receivable_dao::{ReceivableDaoError, ReceivableDaoFactory}; use crate::accountant::scanners::scanners::{BeginScanError, NotifyLaterForScanners, Scanners}; -use crate::banned_dao::{BannedDao, BannedDaoFactory}; +use crate::banned_dao::BannedDaoFactory; use crate::blockchain::blockchain_bridge::{PendingPayableFingerprint, RetrieveTransactions}; use crate::blockchain::blockchain_interface::{BlockchainError, BlockchainTransaction}; use crate::bootstrapper::BootstrapperConfig; @@ -70,7 +70,6 @@ pub struct Accountant { payable_dao: Box, receivable_dao: Box, pending_payable_dao: Box, - banned_dao: Box, crashable: bool, scanners: Scanners, notify_later: NotifyLaterForScanners, @@ -82,7 +81,6 @@ pub struct Accountant { report_sent_payments_sub: Option>, ui_message_sub: Option>, logger: Logger, - payment_thresholds: Rc, } impl Actor for Accountant { @@ -417,14 +415,13 @@ impl Accountant { payable_dao: payable_dao_factory.make(), receivable_dao: receivable_dao_factory.make(), pending_payable_dao: pending_payable_dao_factory.make(), - banned_dao: banned_dao_factory.make(), crashable: config.crash_point == CrashPoint::Message, scanners: Scanners::new( payable_dao_factory, pending_payable_dao_factory, receivable_dao_factory.make(), banned_dao_factory.make(), - Rc::clone(&payment_thresholds), + payment_thresholds, Rc::clone(&earning_wallet), when_pending_too_long_sec, Rc::clone(&financial_statistics), @@ -438,7 +435,6 @@ impl Accountant { report_sent_payments_sub: None, ui_message_sub: None, logger: Logger::new("Accountant"), - payment_thresholds, } } @@ -932,7 +928,7 @@ mod tests { *receivable_dao_factory_params_arc.lock().unwrap(), vec![(), ()] ); - assert_eq!(*banned_dao_factory_params_arc.lock().unwrap(), vec![(), ()]); + assert_eq!(*banned_dao_factory_params_arc.lock().unwrap(), vec![()]); } #[test] From 6ab9c9b9199fd79f38a70606512562c462271a78 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 28 Sep 2022 12:28:29 +0530 Subject: [PATCH 143/145] GH-611: implement scan_finished() for ScannerMock --- node/src/accountant/scanners.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 7bbcab0dc..5017bcf24 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -791,22 +791,26 @@ pub(in crate::accountant) mod scanners { fn scan_finished( &mut self, - _message: EndMessage, + message: EndMessage, _logger: &Logger, ) -> Option { - todo!("Implement ScannerMock") + self.end_scan_params.lock().unwrap().push(message); + if self.is_allowed_to_stop_the_system() && self.is_last_message() { + System::current().stop(); + } + self.end_scan_results.borrow_mut().remove(0) } fn scan_started_at(&self) -> Option { - todo!("Implement ScannerMock") + unimplemented!() } fn mark_as_started(&mut self, _timestamp: SystemTime) { - todo!("Implement ScannerMock") + unimplemented!() } fn mark_as_ended(&mut self, _logger: &Logger) { - todo!("Implement ScannerMock") + unimplemented!() } } From b4389cfa6a51ec6857fe2632f1fac9d9a556e3b0 Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 28 Sep 2022 12:41:24 +0530 Subject: [PATCH 144/145] GH-611: remove multiple occurences of BannedDao inside tests of accountant/mod.rs --- node/src/accountant/mod.rs | 26 +++++++++++--------------- node/src/accountant/test_utils.rs | 12 ++++-------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 4dd0b6bf3..48b53ae2b 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -891,22 +891,21 @@ mod tests { let banned_dao_factory_params_arc = Arc::new(Mutex::new(vec![])); let payable_dao_factory = PayableDaoFactoryMock::new() .make_params(&payable_dao_factory_params_arc) - .make_result(PayableDaoMock::new()) - .make_result(PayableDaoMock::new()) - .make_result(PayableDaoMock::new()); + .make_result(PayableDaoMock::new()) // For Accountant + .make_result(PayableDaoMock::new()) // For Payable Scanner + .make_result(PayableDaoMock::new()); // For PendingPayable Scanner let pending_payable_dao_factory = PendingPayableDaoFactoryMock::new() .make_params(&pending_payable_dao_factory_params_arc) - .make_result(PendingPayableDaoMock::new()) - .make_result(PendingPayableDaoMock::new()) - .make_result(PendingPayableDaoMock::new()); + .make_result(PendingPayableDaoMock::new()) // For Accountant + .make_result(PendingPayableDaoMock::new()) // For Payable Scanner + .make_result(PendingPayableDaoMock::new()); // For PendingPayable Scanner let receivable_dao_factory = ReceivableDaoFactoryMock::new() .make_params(&receivable_dao_factory_params_arc) - .make_result(ReceivableDaoMock::new()) - .make_result(ReceivableDaoMock::new()); + .make_result(ReceivableDaoMock::new()) // For Accountant + .make_result(ReceivableDaoMock::new()); // For Receivable Scanner let banned_dao_factory = BannedDaoFactoryMock::new() .make_params(&banned_dao_factory_params_arc) - .make_result(BannedDaoMock::new()) - .make_result(BannedDaoMock::new()); + .make_result(BannedDaoMock::new()); // For Receivable Scanner let _ = Accountant::new( &mut config, @@ -957,11 +956,8 @@ mod tests { .make_result(ReceivableDaoMock::new()) // For Accountant .make_result(ReceivableDaoMock::new()), // For Scanner ); - let banned_dao_factory = Box::new( - BannedDaoFactoryMock::new() - .make_result(BannedDaoMock::new()) - .make_result(BannedDaoMock::new()), - ); + let banned_dao_factory = + Box::new(BannedDaoFactoryMock::new().make_result(BannedDaoMock::new())); let result = Accountant::new( &mut bootstrapper_config, diff --git a/node/src/accountant/test_utils.rs b/node/src/accountant/test_utils.rs index c9e1a438c..effcfd681 100644 --- a/node/src/accountant/test_utils.rs +++ b/node/src/accountant/test_utils.rs @@ -176,11 +176,9 @@ impl AccountantBuilder { .make_result(PendingPayableDaoMock::new()) .make_result(PendingPayableDaoMock::new()), ); - let banned_dao_factory = self.banned_dao_factory.unwrap_or( - BannedDaoFactoryMock::new() - .make_result(BannedDaoMock::new()) - .make_result(BannedDaoMock::new()), - ); + let banned_dao_factory = self + .banned_dao_factory + .unwrap_or(BannedDaoFactoryMock::new().make_result(BannedDaoMock::new())); let accountant = Accountant::new( &mut config, Box::new(payable_dao_factory), @@ -272,9 +270,7 @@ pub struct BannedDaoFactoryMock { impl BannedDaoFactory for BannedDaoFactoryMock { fn make(&self) -> Box { if self.make_results.borrow().len() == 0 { - panic!( - "BannedDao Missing. This problem mostly occurs when BannedDao is only supplied for Accountant and not for the Scanner while building Accountant." - ) + panic!("BannedDao Missing.") }; self.make_params.lock().unwrap().push(()); self.make_results.borrow_mut().remove(0) From 8b73e9962aa91820723e06b46a317ce57ba0efca Mon Sep 17 00:00:00 2001 From: utkarshg6 Date: Wed, 28 Sep 2022 13:47:39 +0530 Subject: [PATCH 145/145] GH-611: rename scan_finished() to finish_scan() --- node/src/accountant/mod.rs | 10 +++------- node/src/accountant/scanners.rs | 30 +++++++++++++----------------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 48b53ae2b..f2493be96 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -177,7 +177,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: SentPayable, _ctx: &mut Self::Context) -> Self::Result { - if let Some(node_to_ui_msg) = self.scanners.payable.scan_finished(msg, &self.logger) { + if let Some(node_to_ui_msg) = self.scanners.payable.finish_scan(msg, &self.logger) { self.ui_message_sub .as_ref() .expect("UIGateway is not bound") @@ -191,11 +191,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ReportTransactionReceipts, _ctx: &mut Self::Context) -> Self::Result { - if let Some(node_to_ui_msg) = self - .scanners - .pending_payable - .scan_finished(msg, &self.logger) - { + if let Some(node_to_ui_msg) = self.scanners.pending_payable.finish_scan(msg, &self.logger) { self.ui_message_sub .as_ref() .expect("UIGateway is not bound") @@ -209,7 +205,7 @@ impl Handler for Accountant { type Result = (); fn handle(&mut self, msg: ReceivedPayments, _ctx: &mut Self::Context) -> Self::Result { - if let Some(node_to_ui_msg) = self.scanners.receivable.scan_finished(msg, &self.logger) { + if let Some(node_to_ui_msg) = self.scanners.receivable.finish_scan(msg, &self.logger) { self.ui_message_sub .as_ref() .expect("UIGateway is not bound") diff --git a/node/src/accountant/scanners.rs b/node/src/accountant/scanners.rs index 5017bcf24..851b1ead1 100644 --- a/node/src/accountant/scanners.rs +++ b/node/src/accountant/scanners.rs @@ -87,11 +87,7 @@ pub(in crate::accountant) mod scanners { response_skeleton_opt: Option, logger: &Logger, ) -> Result; - fn scan_finished( - &mut self, - message: EndMessage, - logger: &Logger, - ) -> Option; + fn finish_scan(&mut self, message: EndMessage, logger: &Logger) -> Option; fn scan_started_at(&self) -> Option; fn mark_as_started(&mut self, timestamp: SystemTime); fn mark_as_ended(&mut self, logger: &Logger); @@ -166,7 +162,7 @@ pub(in crate::accountant) mod scanners { } } - fn scan_finished( + fn finish_scan( &mut self, message: SentPayable, logger: &Logger, @@ -340,7 +336,7 @@ pub(in crate::accountant) mod scanners { } } - fn scan_finished( + fn finish_scan( &mut self, message: ReportTransactionReceipts, logger: &Logger, @@ -596,7 +592,7 @@ pub(in crate::accountant) mod scanners { }) } - fn scan_finished( + fn finish_scan( &mut self, message: ReceivedPayments, logger: &Logger, @@ -733,7 +729,7 @@ pub(in crate::accountant) mod scanners { Err(BeginScanError::CalledFromNullScanner) } - fn scan_finished( + fn finish_scan( &mut self, _message: EndMessage, _logger: &Logger, @@ -789,7 +785,7 @@ pub(in crate::accountant) mod scanners { self.begin_scan_results.borrow_mut().remove(0) } - fn scan_finished( + fn finish_scan( &mut self, message: EndMessage, _logger: &Logger, @@ -1027,7 +1023,7 @@ mod tests { response_skeleton_opt: None, }; - let _ = subject.scan_finished(sent_payable, &Logger::new("test")); + let _ = subject.finish_scan(sent_payable, &Logger::new("test")); } #[test] @@ -1054,7 +1050,7 @@ mod tests { ))); let mut subject = PayableScanner::default().pending_payable_dao(pending_payable_dao); - let _ = subject.scan_finished(sent_payable, &Logger::new("test")); + let _ = subject.finish_scan(sent_payable, &Logger::new("test")); } #[test] @@ -1081,7 +1077,7 @@ mod tests { response_skeleton_opt: None, }; - let _ = subject.scan_finished(sent_payable, &Logger::new("test")); + let _ = subject.finish_scan(sent_payable, &Logger::new("test")); } #[test] @@ -1112,7 +1108,7 @@ mod tests { .pending_payable_dao(pending_payable_dao); subject.mark_as_started(SystemTime::now()); - let message_opt = subject.scan_finished(sent_payable, &Logger::new(test_name)); + let message_opt = subject.finish_scan(sent_payable, &Logger::new(test_name)); let is_scan_running = subject.scan_started_at().is_some(); let fingerprint_rowid_params = fingerprint_rowid_params_arc.lock().unwrap(); @@ -1645,7 +1641,7 @@ mod tests { }; subject.mark_as_started(SystemTime::now()); - let message_opt = subject.scan_finished(msg, &Logger::new(test_name)); + let message_opt = subject.finish_scan(msg, &Logger::new(test_name)); let transaction_confirmed_params = transaction_confirmed_params_arc.lock().unwrap(); assert_eq!(message_opt, None); @@ -1795,7 +1791,7 @@ mod tests { response_skeleton_opt: None, }; - let message_opt = subject.scan_finished(msg, &Logger::new(test_name)); + let message_opt = subject.finish_scan(msg, &Logger::new(test_name)); assert_eq!(message_opt, None); TestLogHandler::new().exists_log_containing(&format!( @@ -1834,7 +1830,7 @@ mod tests { }; subject.mark_as_started(SystemTime::now()); - let message_opt = subject.scan_finished(msg, &Logger::new(test_name)); + let message_opt = subject.finish_scan(msg, &Logger::new(test_name)); let total_paid_receivable = subject.financial_statistics().total_paid_receivable; let more_money_received_params = more_money_received_params_arc.lock().unwrap();