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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
357 changes: 269 additions & 88 deletions node/src/accountant/mod.rs

Large diffs are not rendered by default.

37 changes: 22 additions & 15 deletions node/src/accountant/scanners/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ use crate::accountant::payment_adjuster::{PaymentAdjuster, PaymentAdjusterReal};
use crate::accountant::scanners::scanners_utils::payable_scanner_utils::PayableTransactingErrorEnum::{
LocallyCausedError, RemotelyCausedErrors,
};
use crate::accountant::scanners::scanners_utils::payable_scanner_utils::{debugging_summary_after_error_separation, err_msg_for_failure_with_expected_but_missing_sent_tx_record, investigate_debt_extremes, payables_debug_summary, separate_errors, OperationOutcome, PayableScanResult, PayableThresholdsGauge, PayableThresholdsGaugeReal, PayableTransactingErrorEnum, PendingPayableMissingInDb};
use crate::accountant::scanners::scanners_utils::payable_scanner_utils::{
debugging_summary_after_error_separation, err_msg_for_failure_with_expected_but_missing_sent_tx_record,
investigate_debt_extremes, payables_debug_summary, separate_errors, OperationOutcome, PayableScanResult,
PayableThresholdsGauge, PayableThresholdsGaugeReal, PayableTransactingErrorEnum, PendingPayableMissingInDb};
use crate::accountant::{PendingPayable, ScanError, ScanForPendingPayables, ScanForRetryPayables};
use crate::accountant::{
comma_joined_stringifiable, gwei_to_wei, ReceivedPayments,
TxReceiptsMessage, RequestTransactionReceipts, ResponseSkeleton, ScanForNewPayables,
ScanForReceivables, SentPayables,
};
use crate::blockchain::blockchain_bridge::{RetrieveTransactions};
use crate::sub_lib::accountant::{
DaoFactories, FinancialStatistics, PaymentThresholds,
};
use crate::sub_lib::accountant::{DaoFactories, DetailedScanType, FinancialStatistics, PaymentThresholds};
use crate::sub_lib::blockchain_bridge::OutboundPaymentsInstructions;
use crate::sub_lib::wallet::Wallet;
use actix::{Message};
Expand Down Expand Up @@ -271,14 +272,14 @@ impl Scanners {

pub fn acknowledge_scan_error(&mut self, error: &ScanError, logger: &Logger) {
match error.scan_type {
ScanType::Payables => {
self.payable.mark_as_ended(logger);
DetailedScanType::NewPayables | DetailedScanType::RetryPayables => {
self.payable.mark_as_ended(logger)
}
ScanType::PendingPayables => {
DetailedScanType::PendingPayables => {
self.empty_caches(logger);
self.pending_payable.mark_as_ended(logger);
}
ScanType::Receivables => {
DetailedScanType::Receivables => {
self.receivable.mark_as_ended(logger);
}
};
Expand Down Expand Up @@ -1072,7 +1073,8 @@ mod tests {
use crate::db_config::mocks::ConfigDaoMock;
use crate::db_config::persistent_configuration::PersistentConfigError;
use crate::sub_lib::accountant::{
DaoFactories, FinancialStatistics, PaymentThresholds, DEFAULT_PAYMENT_THRESHOLDS,
DaoFactories, DetailedScanType, FinancialStatistics, PaymentThresholds,
DEFAULT_PAYMENT_THRESHOLDS,
};
use crate::test_utils::persistent_configuration_mock::PersistentConfigurationMock;
use crate::test_utils::unshared_test_utils::arbitrary_id_stamp::ArbitraryIdStamp;
Expand Down Expand Up @@ -3199,7 +3201,7 @@ mod tests {

#[test]
fn acknowledge_scan_error_works() {
fn scan_error(scan_type: ScanType) -> ScanError {
fn scan_error(scan_type: DetailedScanType) -> ScanError {
ScanError {
scan_type,
response_skeleton_opt: None,
Expand All @@ -3210,22 +3212,27 @@ mod tests {
init_test_logging();
let test_name = "acknowledge_scan_error_works";
let inputs: Vec<(
ScanType,
DetailedScanType,
Box<dyn Fn(&mut Scanners)>,
Box<dyn Fn(&Scanners) -> Option<SystemTime>>,
)> = vec![
(
ScanType::Payables,
DetailedScanType::NewPayables,
Box::new(|subject| subject.payable.mark_as_started(SystemTime::now())),
Box::new(|subject| subject.payable.scan_started_at()),
),
(
DetailedScanType::RetryPayables,
Box::new(|subject| subject.payable.mark_as_started(SystemTime::now())),
Box::new(|subject| subject.payable.scan_started_at()),
),
(
ScanType::PendingPayables,
DetailedScanType::PendingPayables,
Box::new(|subject| subject.pending_payable.mark_as_started(SystemTime::now())),
Box::new(|subject| subject.pending_payable.scan_started_at()),
),
(
ScanType::Receivables,
DetailedScanType::Receivables,
Box::new(|subject| subject.receivable.mark_as_started(SystemTime::now())),
Box::new(|subject| subject.receivable.scan_started_at()),
),
Expand Down Expand Up @@ -3258,7 +3265,7 @@ mod tests {
);
test_log_handler.exists_log_containing(&format!(
"INFO: {test_name}: The {:?} scan ended in",
scan_type
ScanType::from(scan_type)
));
})
}
Expand Down
10 changes: 5 additions & 5 deletions node/src/accountant/scanners/pending_payable_scanner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ mod tests {
let pending_payable_cache_before = subject.current_sent_payables.dump_cache();
let failed_payable_cache_before = subject.yet_unproven_failed_payables.dump_cache();

let result = subject.start_scan(&make_wallet("bluh"), SystemTime::now(), None, &logger);
let result = subject.start_scan(&make_wallet("blah"), SystemTime::now(), None, &logger);

assert_eq!(
result,
Expand Down Expand Up @@ -1344,7 +1344,7 @@ mod tests {
#[should_panic(
expected = "Unable to update pending-tx statuses for validation failures '[FailedValidation \
{ tx_hash: 0x00000000000000000000000000000000000000000000000000000000000001c8, validation_failure: \
AppRpc(Local(Internal)), current_status: Pending(Waiting) }]' due to: InvalidInput(\"bluh\")"
AppRpc(Local(Internal)), current_status: Pending(Waiting) }]' due to: InvalidInput(\"blah\")"
)]
fn update_validation_status_for_sent_txs_panics_on_update_statuses() {
let failed_validation = FailedValidation::new(
Expand All @@ -1353,7 +1353,7 @@ mod tests {
TxStatus::Pending(ValidationStatus::Waiting),
);
let sent_payable_dao = SentPayableDaoMock::default()
.update_statuses_result(Err(SentPayableDaoError::InvalidInput("bluh".to_string())));
.update_statuses_result(Err(SentPayableDaoError::InvalidInput("blah".to_string())));
let subject = PendingPayableScannerBuilder::new()
.sent_payable_dao(sent_payable_dao)
.validation_failure_clock(Box::new(ValidationFailureClockReal::default()))
Expand All @@ -1367,7 +1367,7 @@ mod tests {
#[should_panic(
expected = "Unable to update failed-tx statuses for validation failures '[FailedValidation \
{ tx_hash: 0x00000000000000000000000000000000000000000000000000000000000001c8, validation_failure: \
AppRpc(Local(Internal)), current_status: RecheckRequired(Waiting) }]' due to: InvalidInput(\"bluh\")"
AppRpc(Local(Internal)), current_status: RecheckRequired(Waiting) }]' due to: InvalidInput(\"blah\")"
)]
fn update_validation_status_for_failed_txs_panics_on_update_statuses() {
let failed_validation = FailedValidation::new(
Expand All @@ -1376,7 +1376,7 @@ mod tests {
FailureStatus::RecheckRequired(ValidationStatus::Waiting),
);
let failed_payable_dao = FailedPayableDaoMock::default()
.update_statuses_result(Err(FailedPayableDaoError::InvalidInput("bluh".to_string())));
.update_statuses_result(Err(FailedPayableDaoError::InvalidInput("blah".to_string())));
let subject = PendingPayableScannerBuilder::new()
.failed_payable_dao(failed_payable_dao)
.validation_failure_clock(Box::new(ValidationFailureClockReal::default()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ mod tests {
let mut sent_tx = make_sent_tx(456);
sent_tx.hash = tx_hash;
sent_tx.status = current_tx_status.clone();
let rpc_error = AppRpcError::Remote(RemoteError::InvalidResponse("bluh".to_string()));
let rpc_error = AppRpcError::Remote(RemoteError::InvalidResponse("blah".to_string()));
let scan_report = ReceiptScanReport::default();

let result = TxReceiptInterpreter::handle_rpc_failure(
Expand Down Expand Up @@ -635,7 +635,7 @@ mod tests {
);
TestLogHandler::new().exists_log_containing(
&format!("WARN: {test_name}: Failed to retrieve tx receipt for SentPayable(0x0000000000\
000000000000000000000000000000000000000000000000000391): Remote(InvalidResponse(\"bluh\")). \
000000000000000000000000000000000000000000000000000391): Remote(InvalidResponse(\"blah\")). \
Will retry receipt retrieval next cycle"));
}

Expand Down
77 changes: 37 additions & 40 deletions node/src/blockchain/blockchain_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::db_config::config_dao::ConfigDaoReal;
use crate::db_config::persistent_configuration::{
PersistentConfiguration, PersistentConfigurationReal,
};
use crate::sub_lib::accountant::DetailedScanType;
use crate::sub_lib::blockchain_bridge::{BlockchainBridgeSubs, OutboundPaymentsInstructions};
use crate::sub_lib::peer_actors::BindMessage;
use crate::sub_lib::utils::{db_connection_launch_panic, handle_ui_crash_request};
Expand Down Expand Up @@ -123,7 +124,7 @@ impl Handler<RetrieveTransactions> for BlockchainBridge {
) -> <Self as Handler<RetrieveTransactions>>::Result {
self.handle_scan_future(
Self::handle_retrieve_transactions,
ScanType::Receivables,
DetailedScanType::Receivables,
msg,
)
}
Expand All @@ -135,7 +136,7 @@ impl Handler<RequestTransactionReceipts> for BlockchainBridge {
fn handle(&mut self, msg: RequestTransactionReceipts, _ctx: &mut Self::Context) {
self.handle_scan_future(
Self::handle_request_transaction_receipts,
ScanType::PendingPayables,
DetailedScanType::PendingPayables,
msg,
)
}
Expand All @@ -145,7 +146,13 @@ impl Handler<QualifiedPayablesMessage> for BlockchainBridge {
type Result = ();

fn handle(&mut self, msg: QualifiedPayablesMessage, _ctx: &mut Self::Context) {
self.handle_scan_future(Self::handle_qualified_payable_msg, ScanType::Payables, msg);
self.handle_scan_future(
Self::handle_qualified_payable_msg,
todo!(
"This needs to be decided on GH-605. Look what mode you run and set it accordingly"
),
msg,
);
Copy link

Choose a reason for hiding this comment

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

Bug: Incomplete Handler Causes Runtime Panic

The Handler<QualifiedPayablesMessage> implementation contains a todo!() macro. This causes a runtime panic when processing qualified payables messages, making the code path non-functional. It replaced a previously working ScanType::Payables.

Fix in Cursor Fix in Web

}
}

Expand All @@ -155,7 +162,9 @@ impl Handler<OutboundPaymentsInstructions> for BlockchainBridge {
fn handle(&mut self, msg: OutboundPaymentsInstructions, _ctx: &mut Self::Context) {
self.handle_scan_future(
Self::handle_outbound_payments_instructions,
ScanType::Payables,
todo!(
"This needs to be decided on GH-605. Look what mode you run and set it accordingly"
),
Copy link

Choose a reason for hiding this comment

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

Bug: Outbound Payments Handler Contains Unresolved Todo

The OutboundPaymentsInstructions handler includes a todo!() macro, which will cause a runtime panic when processing outbound payments. This replaces a previously functional ScanType::Payables value, making this critical path non-functional. It looks like incomplete development work.

Fix in Cursor Fix in Web

msg,
)
}
Expand Down Expand Up @@ -440,7 +449,7 @@ impl BlockchainBridge {
)
}

fn handle_scan_future<M, F>(&mut self, handler: F, scan_type: ScanType, msg: M)
fn handle_scan_future<M, F>(&mut self, handler: F, scan_type: DetailedScanType, msg: M)
where
F: FnOnce(&mut BlockchainBridge, M) -> Box<dyn Future<Item = (), Error = String>>,
M: SkeletonOptHolder,
Expand Down Expand Up @@ -562,15 +571,10 @@ mod tests {
use crate::node_test_utils::check_timestamp;
use crate::sub_lib::blockchain_bridge::ConsumingWalletBalances;
use crate::test_utils::persistent_configuration_mock::PersistentConfigurationMock;
use crate::test_utils::recorder::{
make_accountant_subs_from_recorder, make_recorder, peer_actors_builder,
};
use crate::test_utils::recorder::{make_accountant_subs_from_recorder, make_blockchain_bridge_subs_from_recorder, make_recorder, peer_actors_builder};
use crate::test_utils::recorder_stop_conditions::StopConditions;
use crate::test_utils::unshared_test_utils::arbitrary_id_stamp::ArbitraryIdStamp;
use crate::test_utils::unshared_test_utils::{
assert_on_initialization_with_panic_on_migration, configure_default_persistent_config,
prove_that_crash_request_handler_is_hooked_up, AssertionsMessage, ZERO,
};
use crate::test_utils::unshared_test_utils::{assert_on_initialization_with_panic_on_migration, configure_default_persistent_config, prove_that_crash_request_handler_is_hooked_up, AssertionsMessage, SubsFactoryTestAddrLeaker, ZERO};
use crate::test_utils::{make_paying_wallet, make_wallet};
use actix::System;
use ethereum_types::U64;
Expand Down Expand Up @@ -601,6 +605,17 @@ mod tests {
}
}

impl SubsFactory<BlockchainBridge, BlockchainBridgeSubs>
for SubsFactoryTestAddrLeaker<BlockchainBridge>
{
fn make(&self, addr: &Addr<BlockchainBridge>) -> BlockchainBridgeSubs {
self.send_leaker_msg_and_return_meaningless_subs(
addr,
make_blockchain_bridge_subs_from_recorder,
)
}
}

#[test]
fn constants_have_correct_values() {
assert_eq!(CRASH_KEY, "BLOCKCHAINBRIDGE");
Expand Down Expand Up @@ -1016,7 +1031,7 @@ mod tests {
assert_eq!(
*scan_error_msg,
ScanError {
scan_type: ScanType::Payables,
scan_type: DetailedScanType::NewPayables,
response_skeleton_opt: Some(ResponseSkeleton {
client_id: 1234,
context_id: 4321
Expand Down Expand Up @@ -1267,7 +1282,7 @@ mod tests {
assert_eq!(
scan_error,
&ScanError {
scan_type: ScanType::Receivables,
scan_type: DetailedScanType::Receivables,
response_skeleton_opt: None,
msg: "Error while retrieving transactions: QueryFailed(\"Transport error: Error(IncompleteMessage)\")".to_string()
}
Expand Down Expand Up @@ -1403,7 +1418,7 @@ mod tests {

let _ = subject.handle_scan_future(
BlockchainBridge::handle_request_transaction_receipts,
ScanType::PendingPayables,
DetailedScanType::PendingPayables,
msg,
);

Expand All @@ -1412,7 +1427,7 @@ mod tests {
assert_eq!(
recording.get_record::<ScanError>(0),
&ScanError {
scan_type: ScanType::PendingPayables,
scan_type: DetailedScanType::PendingPayables,
response_skeleton_opt: None,
msg: "Blockchain error: Query failed: Transport error: Error(IncompleteMessage)"
.to_string()
Expand Down Expand Up @@ -1781,7 +1796,7 @@ mod tests {
assert_eq!(
scan_error_msg,
&ScanError {
scan_type: ScanType::Receivables,
scan_type: DetailedScanType::Receivables,
response_skeleton_opt: Some(ResponseSkeleton {
client_id: 1234,
context_id: 4321
Expand Down Expand Up @@ -1841,7 +1856,7 @@ mod tests {
assert_eq!(
scan_error_msg,
&ScanError {
scan_type: ScanType::Receivables,
scan_type: DetailedScanType::Receivables,
response_skeleton_opt: Some(ResponseSkeleton {
client_id: 1234,
context_id: 4321
Expand Down Expand Up @@ -1987,7 +2002,7 @@ mod tests {

subject.handle_scan_future(
BlockchainBridge::handle_retrieve_transactions,
ScanType::Receivables,
DetailedScanType::Receivables,
retrieve_transactions,
);

Expand Down Expand Up @@ -2041,7 +2056,7 @@ mod tests {

subject.handle_scan_future(
BlockchainBridge::handle_retrieve_transactions,
ScanType::Receivables,
DetailedScanType::Receivables,
msg.clone(),
);

Expand All @@ -2051,7 +2066,7 @@ mod tests {
assert_eq!(
message,
&ScanError {
scan_type: ScanType::Receivables,
scan_type: DetailedScanType::Receivables,
response_skeleton_opt: msg.response_skeleton_opt,
msg: "Error while retrieving transactions: QueryFailed(\"RPC error: Error { code: ServerError(-32005), message: \\\"My tummy hurts\\\", data: None }\")"
.to_string()
Expand Down Expand Up @@ -2190,22 +2205,4 @@ mod tests {
assert_eq!(increase_gas_price_by_margin(1_000_000_000), 1_300_000_000);
assert_eq!(increase_gas_price_by_margin(9_000_000_000), 11_700_000_000);
}
}

#[cfg(test)]
pub mod exportable_test_parts {
use super::*;
use crate::test_utils::recorder::make_blockchain_bridge_subs_from_recorder;
use crate::test_utils::unshared_test_utils::SubsFactoryTestAddrLeaker;

impl SubsFactory<BlockchainBridge, BlockchainBridgeSubs>
for SubsFactoryTestAddrLeaker<BlockchainBridge>
{
fn make(&self, addr: &Addr<BlockchainBridge>) -> BlockchainBridgeSubs {
self.send_leaker_msg_and_return_meaningless_subs(
addr,
make_blockchain_bridge_subs_from_recorder,
)
}
}
}
}
Loading