diff --git a/masq_lib/src/test_utils/mock_blockchain_client_server.rs b/masq_lib/src/test_utils/mock_blockchain_client_server.rs index 96caf1d67..424a4433d 100644 --- a/masq_lib/src/test_utils/mock_blockchain_client_server.rs +++ b/masq_lib/src/test_utils/mock_blockchain_client_server.rs @@ -65,7 +65,7 @@ impl MBCSBuilder { self.store_response_string(raw_string) } - pub fn response(self, result: R, id: u64) -> Self + pub fn ok_response(self, result: R, id: u64) -> Self where R: Serialize, { diff --git a/multinode_integration_tests/src/mock_blockchain_client_server.rs b/multinode_integration_tests/src/mock_blockchain_client_server.rs index 2672ba196..2f0d7a9c5 100644 --- a/multinode_integration_tests/src/mock_blockchain_client_server.rs +++ b/multinode_integration_tests/src/mock_blockchain_client_server.rs @@ -29,7 +29,7 @@ mod tests { let _cluster = MASQNodeCluster::start(); let port = find_free_port(); let _subject = MockBlockchainClientServer::builder(port) - .response("Thank you and good night", 40) + .ok_response("Thank you and good night", 40) .run_in_docker() .start(); let mut client = connect(port); @@ -60,8 +60,8 @@ mod tests { let _cluster = MASQNodeCluster::start(); let port = find_free_port(); let _subject = MockBlockchainClientServer::builder(port) - .response("Welcome, and thanks for coming!", 39) - .response("Thank you and good night", 40) + .ok_response("Welcome, and thanks for coming!", 39) + .ok_response("Thank you and good night", 40) .run_in_docker() .start(); let mut client = connect(port); @@ -85,7 +85,7 @@ mod tests { let _cluster = MASQNodeCluster::start(); let port = find_free_port(); let _subject = MockBlockchainClientServer::builder(port) - .response("irrelevant".to_string(), 42) + .ok_response("irrelevant".to_string(), 42) .run_in_docker() .start(); let mut client = connect(port); @@ -102,7 +102,7 @@ mod tests { let _cluster = MASQNodeCluster::start(); let port = find_free_port(); let _subject = MockBlockchainClientServer::builder(port) - .response("irrelevant".to_string(), 42) + .ok_response("irrelevant".to_string(), 42) .run_in_docker() .start(); let mut client = connect(port); @@ -119,7 +119,7 @@ mod tests { let _cluster = MASQNodeCluster::start(); let port = find_free_port(); let _subject = MockBlockchainClientServer::builder(port) - .response("irrelevant".to_string(), 42) + .ok_response("irrelevant".to_string(), 42) .run_in_docker() .start(); let mut client = connect(port); @@ -138,10 +138,10 @@ mod tests { let subject = MockBlockchainClientServer::builder(port) .notifier(notifier) .begin_batch() - .response(1234u64, 40) + .ok_response(1234u64, 40) .error(1234, "My tummy hurts", None as Option<()>) .end_batch() - .response( + .ok_response( Person { name: "Billy".to_string(), age: 15, @@ -211,7 +211,7 @@ mod tests { let _cluster = MASQNodeCluster::start(); let port = find_free_port(); let subject = MockBlockchainClientServer::builder(port) - .response( + .ok_response( Person { name: "Billy".to_string(), age: 15, diff --git a/multinode_integration_tests/tests/blockchain_interaction_test.rs b/multinode_integration_tests/tests/blockchain_interaction_test.rs index 42381891c..05bc1f8b5 100644 --- a/multinode_integration_tests/tests/blockchain_interaction_test.rs +++ b/multinode_integration_tests/tests/blockchain_interaction_test.rs @@ -32,8 +32,8 @@ fn debtors_are_credited_once_but_not_twice() { // Create and initialize mock blockchain client: prepare a receivable at block 2000 eprintln!("Setting up mock blockchain client"); let blockchain_client_server = MBCSBuilder::new(mbcs_port) - .response("0x5DC", 1) // eth_blockNumber 1500 - .response( + .ok_response("0x5DC", 1) // eth_blockNumber 1500 + .ok_response( vec![LogObject { removed: false, log_index: Some("0x20".to_string()), diff --git a/multinode_integration_tests/tests/communication_failure_test.rs b/multinode_integration_tests/tests/communication_failure_test.rs index c5c70bbaf..b123d30cc 100644 --- a/multinode_integration_tests/tests/communication_failure_test.rs +++ b/multinode_integration_tests/tests/communication_failure_test.rs @@ -272,9 +272,7 @@ fn dns_resolution_failure_with_real_nodes() { ); } -// >>> TODO: GH-744: - Fix this test. #[test] -#[ignore] fn dns_resolution_failure_for_wildcard_ip_with_real_nodes() { let dns_server_that_fails = Ipv4Addr::new(1, 1, 1, 3).into(); let mut cluster = MASQNodeCluster::start().unwrap(); @@ -296,7 +294,7 @@ fn dns_resolution_failure_for_wildcard_ip_with_real_nodes() { thread::sleep(Duration::from_millis(1000)); let mut client = originating_node.make_client(8080, STANDARD_CLIENT_TIMEOUT_MILLIS); - client.send_chunk(b"GET / HTTP/1.1\r\nHost: www.xvideos.com\r\n\r\n"); + client.send_chunk(b"GET / HTTP/1.1\r\nHost: www.adomainthatdoesntexist.com\r\n\r\n"); let response = client.wait_for_chunk(); assert_eq!( @@ -306,7 +304,7 @@ fn dns_resolution_failure_for_wildcard_ip_with_real_nodes() { String::from_utf8(response.clone()).unwrap() ); assert_eq!( - index_of(&response, &b"

DNS Failure, We have tried multiple Exit Nodes and all have failed to resolve this address www.xvideos.com

"[..]).is_some(), + index_of(&response, &b"

DNS Failure, We have tried multiple Exit Nodes and all have failed to resolve this address www.adomainthatdoesntexsit.com

"[..]).is_some(), true, "Actual response:\n{}", String::from_utf8(response).unwrap() diff --git a/node/src/accountant/mod.rs b/node/src/accountant/mod.rs index 84a0c1274..a1510e8bd 100644 --- a/node/src/accountant/mod.rs +++ b/node/src/accountant/mod.rs @@ -1119,7 +1119,7 @@ mod tests { use std::sync::Mutex; use std::time::Duration; use std::vec; - use web3::types::TransactionReceipt; + use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{TransactionBlock, TxReceipt, TxStatus}; impl Handler> for Accountant { type Result = (); @@ -3446,16 +3446,16 @@ mod tests { .unwrap(); let _blockchain_client_server = MBCSBuilder::new(port) // Blockchain Agent Gas Price - .response("0x3B9ACA00".to_string(), 0) // 1000000000 + .ok_response("0x3B9ACA00".to_string(), 0) // 1000000000 // Blockchain Agent transaction fee balance - .response("0xFFF0".to_string(), 0) // 65520 + .ok_response("0xFFF0".to_string(), 0) // 65520 // Blockchain Agent masq balance - .response( + .ok_response( "0x000000000000000000000000000000000000000000000000000000000000FFFF".to_string(), 0, ) // Submit payments to blockchain - .response("0xFFF0".to_string(), 1) + .ok_response("0xFFF0".to_string(), 1) .begin_batch() .raw_response( ReceiptResponseBuilder::default() @@ -3510,6 +3510,8 @@ mod tests { ReceiptResponseBuilder::default() .transaction_hash(pending_tx_hash_2) .status(U64::from(1)) + .block_number(U64::from(1234)) + .block_hash(Default::default()) .build(), ) .end_batch() @@ -3797,9 +3799,13 @@ mod tests { .build(); let subject_addr = subject.start(); let transaction_hash_1 = make_tx_hash(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 transaction_receipt_1 = TxReceipt { + transaction_hash: transaction_hash_1, + status: TxStatus::Succeeded(TransactionBlock { + block_hash: Default::default(), + block_number: U64::from(100), + }), + }; let fingerprint_1 = PendingPayableFingerprint { rowid: 5, timestamp: from_time_t(200_000_000), @@ -3809,9 +3815,13 @@ mod tests { process_error: None, }; let transaction_hash_2 = make_tx_hash(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 transaction_receipt_2 = TxReceipt { + transaction_hash: transaction_hash_2, + status: TxStatus::Succeeded(TransactionBlock { + block_hash: Default::default(), + block_number: U64::from(200), + }), + }; let fingerprint_2 = PendingPayableFingerprint { rowid: 10, timestamp: from_time_t(199_780_000), @@ -3823,11 +3833,11 @@ mod tests { let msg = ReportTransactionReceipts { fingerprints_with_receipts: vec![ ( - TransactionReceiptResult::Found(transaction_receipt_1.into()), + TransactionReceiptResult::RpcResponse(transaction_receipt_1), fingerprint_1.clone(), ), ( - TransactionReceiptResult::Found(transaction_receipt_2.into()), + TransactionReceiptResult::RpcResponse(transaction_receipt_2), fingerprint_2.clone(), ), ], diff --git a/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/agent_null.rs b/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/agent_null.rs index 31f0758e4..e95673002 100644 --- a/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/agent_null.rs +++ b/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/agent_null.rs @@ -85,6 +85,7 @@ mod tests { use masq_lib::logger::Logger; use masq_lib::test_utils::logging::{init_test_logging, TestLogHandler}; + use masq_lib::test_utils::utils::TEST_DEFAULT_CHAIN; use web3::types::U256; fn blockchain_agent_null_constructor_works(constructor: C) @@ -178,4 +179,17 @@ mod tests { assert_eq!(result, &Wallet::null()); assert_error_log(test_name, "consuming_wallet") } + + #[test] + fn null_agent_get_chain() { + init_test_logging(); + let test_name = "null_agent_get_chain"; + let mut subject = BlockchainAgentNull::new(); + subject.logger = Logger::new(test_name); + + let result = subject.get_chain(); + + assert_eq!(result, TEST_DEFAULT_CHAIN); + assert_error_log(test_name, "get_chain") + } } diff --git a/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/agent_web3.rs b/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/agent_web3.rs index af49f3950..725e14f00 100644 --- a/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/agent_web3.rs +++ b/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/agent_web3.rs @@ -102,6 +102,7 @@ mod tests { subject.consuming_wallet_balances(), consuming_wallet_balances ); + assert_eq!(subject.get_chain(), TEST_DEFAULT_CHAIN); } #[test] diff --git a/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/test_utils.rs b/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/test_utils.rs index 836bb1d10..d3ab97284 100644 --- a/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/test_utils.rs +++ b/node/src/accountant/scanners/mid_scan_msg_handling/payable_scanner/test_utils.rs @@ -8,7 +8,6 @@ use crate::sub_lib::wallet::Wallet; use crate::test_utils::unshared_test_utils::arbitrary_id_stamp::ArbitraryIdStamp; use crate::{arbitrary_id_stamp_in_trait_impl, set_arbitrary_id_stamp_in_mock_impl}; use masq_lib::blockchains::chains::Chain; -use masq_lib::test_utils::utils::TEST_DEFAULT_CHAIN; use std::cell::RefCell; pub struct BlockchainAgentMock { @@ -26,7 +25,7 @@ impl Default for BlockchainAgentMock { agreed_fee_per_computation_unit_results: RefCell::new(vec![]), consuming_wallet_result_opt: None, arbitrary_id_stamp_opt: None, - get_chain_result_opt: Some(TEST_DEFAULT_CHAIN), + get_chain_result_opt: None, } } } diff --git a/node/src/accountant/scanners/mod.rs b/node/src/accountant/scanners/mod.rs index 5c6b2c772..572d36400 100644 --- a/node/src/accountant/scanners/mod.rs +++ b/node/src/accountant/scanners/mod.rs @@ -17,10 +17,7 @@ use crate::accountant::scanners::scanners_utils::payable_scanner_utils::{ separate_errors, separate_rowids_and_hashes, PayableThresholdsGauge, PayableThresholdsGaugeReal, PayableTransactingErrorEnum, PendingPayableMetadata, }; -use crate::accountant::scanners::scanners_utils::pending_payable_scanner_utils::{ - elapsed_in_ms, handle_status_with_failure, handle_status_with_success, - PendingPayableScanReport, -}; +use crate::accountant::scanners::scanners_utils::pending_payable_scanner_utils::{handle_none_receipt, handle_status_with_failure, handle_status_with_success, PendingPayableScanReport}; use crate::accountant::scanners::scanners_utils::receivable_scanner_utils::balance_and_age; use crate::accountant::PendingPayableId; use crate::accountant::{ @@ -55,7 +52,7 @@ use web3::types::H256; use masq_lib::type_obfuscation::Obfuscated; use crate::accountant::scanners::mid_scan_msg_handling::payable_scanner::{PreparedAdjustment, MultistagePayableScanner, SolvencySensitivePaymentInstructor}; use crate::accountant::scanners::mid_scan_msg_handling::payable_scanner::msgs::{BlockchainAgentWithContextMessage, QualifiedPayablesMessage}; -use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::TransactionReceiptResult; +use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{TransactionReceiptResult, TxStatus}; use crate::blockchain::blockchain_interface::data_structures::errors::PayableTransactionError; use crate::db_config::persistent_configuration::{PersistentConfiguration, PersistentConfigurationReal}; @@ -654,43 +651,28 @@ impl PendingPayableScanner { msg: ReportTransactionReceipts, logger: &Logger, ) -> PendingPayableScanReport { - fn handle_none_receipt( - mut scan_report: PendingPayableScanReport, - payable: PendingPayableFingerprint, - error_msg: String, - logger: &Logger, - ) -> PendingPayableScanReport { - debug!(logger, - "Interpreting a receipt for transaction {:?} but {}; attempt {}, {}ms since sending", - payable.hash, error_msg, payable.attempt,elapsed_in_ms(payable.timestamp) - ); - - scan_report - .still_pending - .push(PendingPayableId::new(payable.rowid, payable.hash)); - scan_report - } - let scan_report = PendingPayableScanReport::default(); msg.fingerprints_with_receipts.into_iter().fold( scan_report, |scan_report_so_far, (receipt_result, fingerprint)| match receipt_result { - TransactionReceiptResult::Found(_receipt) => { - handle_status_with_success(scan_report_so_far, fingerprint, logger) - } - TransactionReceiptResult::TransactionFailed(_receipt) => { - handle_status_with_failure(scan_report_so_far, fingerprint, logger) - } - TransactionReceiptResult::NotPresent => handle_none_receipt( - scan_report_so_far, - fingerprint, - "none was given".to_string(), - logger, - ), + TransactionReceiptResult::RpcResponse(tx_receipt) => match tx_receipt.status { + TxStatus::Pending => handle_none_receipt( + scan_report_so_far, + fingerprint, + "none was given", + logger, + ), + TxStatus::Failed => { + handle_status_with_failure(scan_report_so_far, fingerprint, logger) + } + TxStatus::Succeeded(_) => { + handle_status_with_success(scan_report_so_far, fingerprint, logger) + } + }, TransactionReceiptResult::LocalError(e) => handle_none_receipt( scan_report_so_far, fingerprint, - format!("failed due to {}", e), + &format!("failed due to {}", e), logger, ), }, @@ -885,10 +867,10 @@ impl ReceivableScanner { ), } } else { - let mut txn = self - .receivable_dao - .as_mut() - .more_money_received(received_payments_msg.timestamp, &received_payments_msg.transactions); + let mut txn = self.receivable_dao.as_mut().more_money_received( + received_payments_msg.timestamp, + &received_payments_msg.transactions, + ); let new_start_block = received_payments_msg.new_start_block; match self .persistent_configuration @@ -1133,7 +1115,7 @@ mod tests { use std::time::{Duration, SystemTime}; use web3::types::{TransactionReceipt, H256}; use web3::Error; - use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::TransactionReceiptResult; + use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{TransactionBlock, TransactionReceiptResult, TxReceipt, TxStatus}; #[test] fn scanners_struct_can_be_constructed_with_the_respective_scanners() { @@ -2498,7 +2480,10 @@ mod tests { }; let msg = ReportTransactionReceipts { fingerprints_with_receipts: vec![( - TransactionReceiptResult::NotPresent, + TransactionReceiptResult::RpcResponse(TxReceipt { + transaction_hash: hash, + status: TxStatus::Pending, + }), fingerprint.clone(), )], response_skeleton_opt: None, @@ -2818,9 +2803,13 @@ mod tests { .pending_payable_dao(pending_payable_dao) .build(); let transaction_hash_1 = make_tx_hash(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 transaction_receipt_1 = TxReceipt { + transaction_hash: transaction_hash_1, + status: TxStatus::Succeeded(TransactionBlock { + block_hash: Default::default(), + block_number: U64::from(1234), + }), + }; let fingerprint_1 = PendingPayableFingerprint { rowid: 5, timestamp: from_time_t(200_000_000), @@ -2830,9 +2819,13 @@ mod tests { process_error: None, }; let transaction_hash_2 = make_tx_hash(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 transaction_receipt_2 = TxReceipt { + transaction_hash: transaction_hash_2, + status: TxStatus::Succeeded(TransactionBlock { + block_hash: Default::default(), + block_number: U64::from(2345), + }), + }; let fingerprint_2 = PendingPayableFingerprint { rowid: 10, timestamp: from_time_t(199_780_000), @@ -2844,11 +2837,11 @@ mod tests { let msg = ReportTransactionReceipts { fingerprints_with_receipts: vec![ ( - TransactionReceiptResult::Found(transaction_receipt_1.into()), + TransactionReceiptResult::RpcResponse(transaction_receipt_1), fingerprint_1.clone(), ), ( - TransactionReceiptResult::Found(transaction_receipt_2.into()), + TransactionReceiptResult::RpcResponse(transaction_receipt_2), fingerprint_2.clone(), ), ], diff --git a/node/src/accountant/scanners/scanners_utils.rs b/node/src/accountant/scanners/scanners_utils.rs index 1876ca58d..30b3a3d2d 100644 --- a/node/src/accountant/scanners/scanners_utils.rs +++ b/node/src/accountant/scanners/scanners_utils.rs @@ -400,6 +400,27 @@ pub mod pending_payable_scanner_utils { scan_report.failures.push(fingerprint.into()); scan_report } + + pub fn handle_none_receipt( + mut scan_report: PendingPayableScanReport, + payable: PendingPayableFingerprint, + error_msg: &str, + logger: &Logger, + ) -> PendingPayableScanReport { + debug!( + logger, + "Interpreting a receipt for transaction {:?} but {}; attempt {}, {}ms since sending", + payable.hash, + error_msg, + payable.attempt, + elapsed_in_ms(payable.timestamp) + ); + + scan_report + .still_pending + .push(PendingPayableId::new(payable.rowid, payable.hash)); + scan_report + } } pub mod receivable_scanner_utils { diff --git a/node/src/blockchain/blockchain_bridge.rs b/node/src/blockchain/blockchain_bridge.rs index 91265b3b8..b204d9ccf 100644 --- a/node/src/blockchain/blockchain_bridge.rs +++ b/node/src/blockchain/blockchain_bridge.rs @@ -47,7 +47,7 @@ use ethabi::Hash; use web3::types::H256; use crate::accountant::db_access_objects::payable_dao::PayableAccount; use crate::accountant::scanners::mid_scan_msg_handling::payable_scanner::blockchain_agent::BlockchainAgent; -use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::TransactionReceiptResult; +use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{TransactionReceiptResult, TxStatus}; pub const CRASH_KEY: &str = "BLOCKCHAINBRIDGE"; pub const DEFAULT_BLOCKCHAIN_SERVICE_URL: &str = "https://0.0.0.0"; @@ -346,7 +346,7 @@ impl BlockchainBridge { { match persistent_config_arc .lock() - .expect("Unable to lock persistent config in BlockchainBridge") + .expect("Mutex with persistent configuration in BlockchainBridge was poisoned") .set_max_block_count(Some(max_block_count)) { Ok(()) => { @@ -366,7 +366,8 @@ impl BlockchainBridge { format!("Error while retrieving transactions: {:?}", e) }) .and_then(move |retrieved_blockchain_transactions| { - received_payments_subs.try_send(ReceivedPayments { + received_payments_subs + .try_send(ReceivedPayments { timestamp: SystemTime::now(), new_start_block: retrieved_blockchain_transactions.new_start_block, response_skeleton_opt: msg.response_skeleton_opt, @@ -378,6 +379,32 @@ impl BlockchainBridge { ) } + fn log_status_of_tx_receipts( + logger: &Logger, + transaction_receipts_results: &[TransactionReceiptResult], + ) { + logger.debug(|| { + let (successful_count, failed_count, pending_count) = + transaction_receipts_results.iter().fold( + (0, 0, 0), + |(success, fail, pending), transaction_receipt| match transaction_receipt { + TransactionReceiptResult::RpcResponse(tx_receipt) => { + match tx_receipt.status { + TxStatus::Failed => (success, fail + 1, pending), + TxStatus::Pending => (success, fail, pending + 1), + TxStatus::Succeeded(_) => (success + 1, fail, pending), + } + } + TransactionReceiptResult::LocalError(_) => (success, fail, pending + 1), + }, + ); + format!( + "Scan results: Successful: {}, Pending: {}, Failed: {}", + successful_count, pending_count, failed_count + ) + }); + } + fn handle_request_transaction_receipts( &mut self, msg: RequestTransactionReceipts, @@ -400,31 +427,20 @@ impl BlockchainBridge { .process_transaction_receipts(transaction_hashes) .map_err(move |e| e.to_string()) .and_then(move |transaction_receipts_results| { - let length = transaction_receipts_results.len(); - let mut transactions_found = 0; - for transaction_receipt in &transaction_receipts_results { - if let TransactionReceiptResult::Found(_) = transaction_receipt { - transactions_found += 1; - } - } + Self::log_status_of_tx_receipts(&logger, &transaction_receipts_results); + let pairs = transaction_receipts_results .into_iter() .zip(msg.pending_payable.into_iter()) .collect_vec(); + accountant_recipient .try_send(ReportTransactionReceipts { fingerprints_with_receipts: pairs, response_skeleton_opt: msg.response_skeleton_opt, }) .expect("Accountant is dead"); - if length != transactions_found { - debug!( - logger, - "Aborting scanning; {} transactions succeed and {} transactions failed", - transactions_found, - length - transactions_found - ); - }; + Ok(()) }), ) @@ -581,6 +597,7 @@ mod tests { use std::sync::{Arc, Mutex}; use std::time::{Duration, SystemTime}; use web3::types::{TransactionReceipt, H160}; + use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{TransactionBlock, TxReceipt}; impl Handler> for BlockchainBridge { type Result = (); @@ -668,9 +685,9 @@ mod tests { ); let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x230000000".to_string(), 1) // 9395240960 - .response("0x23".to_string(), 1) - .response( + .ok_response("0x230000000".to_string(), 1) // 9395240960 + .ok_response("0x23".to_string(), 1) + .ok_response( "0x000000000000000000000000000000000000000000000000000000000000FFFF".to_string(), 0, ) @@ -777,8 +794,8 @@ mod tests { let port = find_free_port(); // build blockchain agent fails by not providing the third response. let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x23".to_string(), 1) - .response("0x23".to_string(), 1) + .ok_response("0x23".to_string(), 1) + .ok_response("0x23".to_string(), 1) .start(); let (accountant, _, accountant_recording_arc) = make_recorder(); let accountant_recipient = accountant.start().recipient(); @@ -833,9 +850,9 @@ mod tests { ); let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x20".to_string(), 1) + .ok_response("0x20".to_string(), 1) .begin_batch() - .response("rpc result".to_string(), 1) + .ok_response("rpc result".to_string(), 1) .end_batch() .start(); let (accountant, _, accountant_recording_arc) = make_recorder(); @@ -927,7 +944,7 @@ mod tests { let port = find_free_port(); // To make submit_batch failed we didn't provide any responses for batch calls let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x20".to_string(), 1) + .ok_response("0x20".to_string(), 1) .start(); let (accountant, _, accountant_recording_arc) = make_recorder(); let accountant_addr = accountant @@ -1013,10 +1030,10 @@ mod tests { let test_name = "process_payments_works"; let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x01".to_string(), 1) + .ok_response("0x01".to_string(), 1) .begin_batch() - .response("rpc_result".to_string(), 7) - .response("rpc_result_2".to_string(), 7) + .ok_response("rpc_result".to_string(), 7) + .ok_response("rpc_result_2".to_string(), 7) .end_batch() .start(); let blockchain_interface_web3 = make_blockchain_interface_web3(port); @@ -1077,12 +1094,13 @@ mod tests { let test_name = "process_payments_fails_on_get_transaction_count"; let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("trash transaction id".to_string(), 1) + .ok_response("trash transaction id".to_string(), 1) .start(); let blockchain_interface_web3 = make_blockchain_interface_web3(port); let consuming_wallet = make_paying_wallet(b"consuming_wallet"); let system = System::new(test_name); let agent = BlockchainAgentMock::default() + .get_chain_result(TEST_DEFAULT_CHAIN) .consuming_wallet_result(consuming_wallet) .agreed_fee_per_computation_unit_result(123); let msg = OutboundPaymentsInstructions::new(vec![], Box::new(agent), None); @@ -1191,11 +1209,14 @@ mod tests { &ReportTransactionReceipts { fingerprints_with_receipts: vec![ ( - TransactionReceiptResult::Found(expected_receipt.into()), + TransactionReceiptResult::RpcResponse(expected_receipt.into()), pending_payable_fingerprint_1 ), ( - TransactionReceiptResult::NotPresent, + TransactionReceiptResult::RpcResponse(TxReceipt { + transaction_hash: hash_2, + status: TxStatus::Pending + }), pending_payable_fingerprint_2 ), ], @@ -1213,7 +1234,7 @@ mod tests { let port = find_free_port(); // We have intentionally left out responses to cause this error let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x3B9ACA00".to_string(), 0) + .ok_response("0x3B9ACA00".to_string(), 0) .start(); let (accountant, _, accountant_recording_arc) = make_recorder(); let accountant_addr = accountant @@ -1267,6 +1288,7 @@ mod tests { let contract_address = H160::from_low_u64_be(887766); let tx_receipt_response = ReceiptResponseBuilder::default() .block_number(block_number) + .block_hash(Default::default()) .status(U64::from(1)) .contract_address(contract_address) .build(); @@ -1320,10 +1342,13 @@ mod tests { amount: 7879, process_error: None, }; - let mut transaction_receipt = TransactionReceipt::default(); - transaction_receipt.block_number = Some(block_number); - transaction_receipt.contract_address = Some(contract_address); - transaction_receipt.status = Some(U64::from(1)); + let transaction_receipt = TxReceipt { + transaction_hash: Default::default(), + status: TxStatus::Succeeded(TransactionBlock { + block_hash: Default::default(), + block_number, + }), + }; let blockchain_interface = make_blockchain_interface_web3(port); let system = System::new("test_transaction_receipts"); let mut subject = BlockchainBridge::new( @@ -1359,9 +1384,9 @@ mod tests { *report_receipts_msg, ReportTransactionReceipts { fingerprints_with_receipts: vec![ - (TransactionReceiptResult::NotPresent, fingerprint_1), - (TransactionReceiptResult::Found(transaction_receipt.into()), fingerprint_2), - (TransactionReceiptResult::NotPresent, fingerprint_3), + (TransactionReceiptResult::RpcResponse(TxReceipt{ transaction_hash: hash_1, status: TxStatus::Pending }), fingerprint_1), + (TransactionReceiptResult::RpcResponse(transaction_receipt), fingerprint_2), + (TransactionReceiptResult::RpcResponse(TxReceipt{ transaction_hash: hash_3, status: TxStatus::Pending }), fingerprint_3), (TransactionReceiptResult::LocalError("RPC error: Error { code: ServerError(429), message: \"The requests per second (RPS) of your requests are higher than your plan allows.\", data: None }".to_string()), fingerprint_4) ], response_skeleton_opt: Some(ResponseSkeleton { @@ -1370,7 +1395,9 @@ mod tests { }), } ); - TestLogHandler::new().exists_log_containing("DEBUG: BlockchainBridge: Aborting scanning; 1 transactions succeed and 3 transactions failed"); + TestLogHandler::new().exists_log_containing( + "DEBUG: BlockchainBridge: Scan results: Successful: 1, Pending: 3, Failed: 0", + ); } #[test] @@ -1447,7 +1474,7 @@ mod tests { ); let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0xC8".to_string(), 0) + .ok_response("0xC8".to_string(), 0) .raw_response(r#"{ "jsonrpc": "2.0", "id": 1, @@ -1516,13 +1543,17 @@ mod tests { transactions: vec![ BlockchainTransaction { block_number: 6040059, - from: make_wallet("first_wallet"), // Relates to RPC response topics of 1 - wei_amount: 42, // Relates to RPC response field data + // Wallet represented in the RPC response by the first 'topic' as: 0x241ea03ca20251805084d27d4440371c34a0b85ff108f6bb5611248f73818b80 + from: make_wallet("first_wallet"), + // Paid amount read out from the field 'data' in the RPC + wei_amount: 42, }, BlockchainTransaction { block_number: 6040060, - from: make_wallet("second_wallet"), // Relates to RPC response topics of 1 - wei_amount: 55, // Relates to RPC response field data + // Wallet represented in the RPC response by the first 'topic' as: 0x241ea03ca20251805084d27d4440371c34a0b85ff108f6bb5611248f73818b80 + from: make_wallet("second_wallet"), + // Paid amount read out from the field 'data' in the RPC + wei_amount: 55, }, ], }; @@ -1552,8 +1583,8 @@ mod tests { ); let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x845FED".to_string(), 0) - .response( + .ok_response("0x845FED".to_string(), 0) + .ok_response( vec![LogObject { removed: false, log_index: Some("0x20".to_string()), @@ -1644,8 +1675,8 @@ mod tests { System::new("handle_retrieve_transactions_sends_received_payments_back_to_accountant"); let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x3B9ACA00".to_string(), 0) - .response( + .ok_response("0x3B9ACA00".to_string(), 0) + .ok_response( vec![LogObject { removed: false, log_index: Some("0x20".to_string()), @@ -1755,8 +1786,8 @@ mod tests { ], }]; let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x3B9ACA00".to_string(), 0) - .response(expected_response_logs, 1) + .ok_response("0x3B9ACA00".to_string(), 0) + .ok_response(expected_response_logs, 1) .start(); let (accountant, _, accountant_recording_arc) = make_recorder(); let accountant_addr = accountant.system_stop_conditions(match_every_type_id!(ScanError)); @@ -1814,7 +1845,7 @@ mod tests { let system = System::new(test_name); let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x3B9ACA00".to_string(), 0) + .ok_response("0x3B9ACA00".to_string(), 0) .err_response(-32005, "Blockheight too far in the past. Check params passed to eth_getLogs or eth_call requests.Range of blocks allowed for your plan: 1000", 0) .start(); let (accountant, _, accountant_recording_arc) = make_recorder(); @@ -1879,7 +1910,7 @@ mod tests { let system = System::new("test"); let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x3B9ACA00".to_string(), 0) + .ok_response("0x3B9ACA00".to_string(), 0) .err_response(-32005, "Blockheight too far in the past. Check params passed to eth_getLogs or eth_call requests.Range of blocks allowed for your plan: 1000", 0) .start(); let (accountant, _, _) = make_recorder(); @@ -1940,7 +1971,7 @@ mod tests { fn handle_scan_future_handles_success() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0xC8".to_string(), 0) + .ok_response("0xC8".to_string(), 0) .raw_response(r#"{ "jsonrpc": "2.0", "id": 1, @@ -2032,7 +2063,7 @@ mod tests { init_test_logging(); let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0xC8".to_string(), 0) + .ok_response("0xC8".to_string(), 0) .err_response(-32005, "My tummy hurts", 0) .start(); let (accountant, _, accountant_recording_arc) = make_recorder(); diff --git a/node/src/blockchain/blockchain_interface/blockchain_interface_web3/lower_level_interface_web3.rs b/node/src/blockchain/blockchain_interface/blockchain_interface_web3/lower_level_interface_web3.rs index fada38b51..58a8865eb 100644 --- a/node/src/blockchain/blockchain_interface/blockchain_interface_web3/lower_level_interface_web3.rs +++ b/node/src/blockchain/blockchain_interface/blockchain_interface_web3/lower_level_interface_web3.rs @@ -14,27 +14,45 @@ use web3::{Error, Web3}; #[derive(Debug, PartialEq, Eq, Clone)] pub enum TransactionReceiptResult { - NotPresent, - Found(TxReceipt), - TransactionFailed(TxReceipt), + RpcResponse(TxReceipt), LocalError(String), } +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum TxStatus { + Failed, + Pending, + Succeeded(TransactionBlock), +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct TxReceipt { pub transaction_hash: H256, - pub block_hash: Option, - pub block_number: Option, - pub status: Option, + pub status: TxStatus, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct TransactionBlock { + pub block_hash: H256, + pub block_number: U64, } impl From for TxReceipt { fn from(receipt: TransactionReceipt) -> Self { + let status = match (receipt.status, receipt.block_hash, receipt.block_number) { + (Some(status), Some(block_hash), Some(block_number)) if status == U64::from(1) => { + TxStatus::Succeeded(TransactionBlock { + block_hash, + block_number, + }) + } + (Some(status), _, _) if status == U64::from(0) => TxStatus::Failed, + _ => TxStatus::Pending, + }; + TxReceipt { transaction_hash: receipt.transaction_hash, - block_hash: receipt.block_hash, - block_number: receipt.block_number, - status: receipt.status.map(|s| s == U64::from(1)), + status, } } } @@ -164,13 +182,14 @@ mod tests { use masq_lib::test_utils::mock_blockchain_client_server::MBCSBuilder; use masq_lib::utils::find_free_port; use std::str::FromStr; - use web3::types::{BlockNumber, Bytes, FilterBuilder, Log, U256}; + use web3::types::{BlockNumber, Bytes, FilterBuilder, Log, TransactionReceipt, U256}; + use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{TxReceipt, TxStatus}; #[test] fn get_transaction_fee_balance_works() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x23".to_string(), 1) + .ok_response("0x23".to_string(), 1) .start(); let wallet = &Wallet::from_str("0x3f69f9efd4f2592fd70be8c32ecd9dce71c472fc").unwrap(); let subject = make_blockchain_interface_web3(port); @@ -188,7 +207,7 @@ mod tests { ) { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0xFFFQ".to_string(), 0) + .ok_response("0xFFFQ".to_string(), 0) .start(); let subject = make_blockchain_interface_web3(port); @@ -213,7 +232,7 @@ mod tests { fn get_gas_price_works() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x01".to_string(), 1) + .ok_response("0x01".to_string(), 1) .start(); let subject = make_blockchain_interface_web3(port); @@ -244,7 +263,7 @@ mod tests { fn get_block_number_works() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x23".to_string(), 1) + .ok_response("0x23".to_string(), 1) .start(); let subject = make_blockchain_interface_web3(port); @@ -257,7 +276,7 @@ mod tests { fn get_block_number_returns_an_error() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("trash".to_string(), 1) + .ok_response("trash".to_string(), 1) .start(); let subject = make_blockchain_interface_web3(port); @@ -279,7 +298,7 @@ mod tests { fn get_transaction_id_works() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x23".to_string(), 1) + .ok_response("0x23".to_string(), 1) .start(); let subject = make_blockchain_interface_web3(port); let wallet = &Wallet::from_str("0x3f69f9efd4f2592fd70be8c32ecd9dce71c472fc").unwrap(); @@ -296,7 +315,7 @@ mod tests { fn get_transaction_id_returns_an_error_for_unintelligible_response() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0xFFFQ".to_string(), 0) + .ok_response("0xFFFQ".to_string(), 0) .start(); let subject = make_blockchain_interface_web3(port); @@ -321,7 +340,7 @@ mod tests { fn get_token_balance_can_retrieve_token_balance_of_a_wallet() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response( + .ok_response( "0x000000000000000000000000000000000000000000000000000000000000FFFF".to_string(), 0, ) @@ -345,7 +364,7 @@ mod tests { fn get_token_balance_returns_error_for_unintelligible_response_to_token_balance() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response( + .ok_response( "0x000000000000000000000000000000000000000000000000000000000000FFFQ".to_string(), 0, ) @@ -524,4 +543,93 @@ mod tests { ) ); } + + #[test] + fn transaction_receipt_can_be_converted_to_successful_transaction() { + let tx_receipt: TxReceipt = create_tx_receipt( + Some(U64::from(1)), + Some(H256::from_low_u64_be(0x1234)), + Some(U64::from(10)), + H256::from_low_u64_be(0x5678), + ); + + assert_eq!(tx_receipt.transaction_hash, H256::from_low_u64_be(0x5678)); + match tx_receipt.status { + TxStatus::Succeeded(ref block) => { + assert_eq!(block.block_hash, H256::from_low_u64_be(0x1234)); + assert_eq!(block.block_number, U64::from(10)); + } + _ => panic!("Expected status to be Succeeded"), + } + } + + #[test] + fn transaction_receipt_can_be_converted_to_failed_transaction() { + let tx_receipt: TxReceipt = create_tx_receipt( + Some(U64::from(0)), + None, + None, + H256::from_low_u64_be(0x5678), + ); + + assert_eq!(tx_receipt.transaction_hash, H256::from_low_u64_be(0x5678)); + assert_eq!(tx_receipt.status, TxStatus::Failed); + } + + #[test] + fn transaction_receipt_can_be_converted_to_pending_transaction_no_status() { + let tx_receipt: TxReceipt = + create_tx_receipt(None, None, None, H256::from_low_u64_be(0x5678)); + + assert_eq!(tx_receipt.transaction_hash, H256::from_low_u64_be(0x5678)); + assert_eq!(tx_receipt.status, TxStatus::Pending); + } + + #[test] + fn transaction_receipt_can_be_converted_to_pending_transaction_no_block_info() { + let tx_receipt: TxReceipt = create_tx_receipt( + Some(U64::from(1)), + None, + None, + H256::from_low_u64_be(0x5678), + ); + + assert_eq!(tx_receipt.transaction_hash, H256::from_low_u64_be(0x5678)); + assert_eq!(tx_receipt.status, TxStatus::Pending); + } + + #[test] + fn transaction_receipt_can_be_converted_to_pending_transaction_no_status_and_block_info() { + let tx_receipt: TxReceipt = create_tx_receipt( + Some(U64::from(1)), + Some(H256::from_low_u64_be(0x1234)), + None, + H256::from_low_u64_be(0x5678), + ); + + assert_eq!(tx_receipt.transaction_hash, H256::from_low_u64_be(0x5678)); + assert_eq!(tx_receipt.status, TxStatus::Pending); + } + + fn create_tx_receipt( + status: Option, + block_hash: Option, + block_number: Option, + transaction_hash: H256, + ) -> TxReceipt { + let receipt = TransactionReceipt { + status, + root: None, + block_hash, + block_number, + cumulative_gas_used: Default::default(), + gas_used: None, + contract_address: None, + transaction_hash, + transaction_index: Default::default(), + logs: vec![], + logs_bloom: Default::default(), + }; + receipt.into() + } } diff --git a/node/src/blockchain/blockchain_interface/blockchain_interface_web3/mod.rs b/node/src/blockchain/blockchain_interface/blockchain_interface_web3/mod.rs index b4664553b..bea78e155 100644 --- a/node/src/blockchain/blockchain_interface/blockchain_interface_web3/mod.rs +++ b/node/src/blockchain/blockchain_interface/blockchain_interface_web3/mod.rs @@ -1,6 +1,8 @@ // Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. pub mod lower_level_interface_web3; +mod utils; + use crate::accountant::scanners::mid_scan_msg_handling::payable_scanner::blockchain_agent::BlockchainAgent; use crate::blockchain::blockchain_interface::data_structures::errors::{BlockchainError, PayableTransactionError}; use crate::blockchain::blockchain_interface::data_structures::{BlockchainTransaction, ProcessedPayableFallible}; @@ -20,8 +22,8 @@ use web3::transports::{EventLoopHandle, Http}; use web3::types::{Address, BlockNumber, Log, H256, U256, FilterBuilder, TransactionReceipt}; use crate::accountant::db_access_objects::payable_dao::PayableAccount; use crate::blockchain::blockchain_bridge::PendingPayableFingerprintSeeds; -use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{LowBlockchainIntWeb3, TransactionReceiptResult}; -use crate::blockchain::blockchain_interface_utils::{dynamically_create_blockchain_agent_web3, send_payables_within_batch, BlockchainAgentFutureResult}; +use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{LowBlockchainIntWeb3, TransactionReceiptResult, TxReceipt, TxStatus}; +use crate::blockchain::blockchain_interface::blockchain_interface_web3::utils::{create_blockchain_agent_web3, send_payables_within_batch, BlockchainAgentFutureResult}; const CONTRACT_ABI: &str = indoc!( r#"[{ @@ -184,7 +186,7 @@ impl BlockchainInterface for BlockchainInterfaceWeb3 { transaction_fee_balance, masq_token_balance, }; - Ok(dynamically_create_blockchain_agent_web3( + Ok(create_blockchain_agent_web3( gas_limit_const_part, blockchain_agent_future_result, consuming_wallet, @@ -202,29 +204,23 @@ impl BlockchainInterface for BlockchainInterfaceWeb3 { ) -> Box, Error = BlockchainError>> { Box::new( self.lower_interface() - .get_transaction_receipt_in_batch(transaction_hashes) - .map_err(|e| e) + .get_transaction_receipt_in_batch(transaction_hashes.clone()) .and_then(move |batch_response| { Ok(batch_response .into_iter() - .map(|response| match response { + .zip(transaction_hashes) + .map(|(response, hash)| match response { Ok(result) => { match serde_json::from_value::(result) { - Ok(receipt) => match receipt.status { - None => TransactionReceiptResult::NotPresent, - Some(status) => { - if status == U64::from(1) { - TransactionReceiptResult::Found(receipt.into()) - } else { - TransactionReceiptResult::TransactionFailed( - receipt.into(), - ) - } - } - }, + Ok(receipt) => { + TransactionReceiptResult::RpcResponse(receipt.into()) + } Err(e) => { if e.to_string().contains("invalid type: null") { - TransactionReceiptResult::NotPresent + TransactionReceiptResult::RpcResponse(TxReceipt { + transaction_hash: hash, + status: TxStatus::Pending, + }) } else { TransactionReceiptResult::LocalError(e.to_string()) } @@ -415,7 +411,7 @@ mod tests { use std::str::FromStr; use web3::transports::Http; use web3::types::{H256, U256}; - use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::TxReceipt; + use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{TransactionBlock, TxReceipt, TxStatus}; #[test] fn constants_are_correct() { @@ -471,7 +467,7 @@ mod tests { let port = find_free_port(); #[rustfmt::skip] let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x178def", 1) + .ok_response("0x178def", 1) .raw_response( r#"{ "jsonrpc":"2.0", @@ -543,24 +539,6 @@ mod tests { ] } ) - - // TODO: GH-543: Improve MBCS so we can confirm the calls we make are the correct ones. - // Example of older code - // let requests = test_server.requests_so_far(); - // let bodies: Vec = requests - // .into_iter() - // .map(|request| serde_json::from_slice(&request.body()).unwrap()) - // .map(|b: Value| serde_json::to_string(&b).unwrap()) - // .collect(); - // let expected_body_prefix = r#"[{"id":0,"jsonrpc":"2.0","method":"eth_blockNumber","params":[]},{"id":1,"jsonrpc":"2.0","method":"eth_getLogs","params":[{"address":"0x384dec25e03f94931767ce4c3556168468ba24c3","fromBlock":"0x2a","toBlock":"0x400","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",null,"0x000000000000000000000000"#; - // let expected_body_suffix = r#""]}]}]"#; - // let expected_body = format!( - // "{}{}{}", - // expected_body_prefix, - // &to[2..], - // expected_body_suffix - // ); - // assert_eq!(bodies, vec!(expected_body)); } #[test] @@ -569,18 +547,14 @@ mod tests { let port = find_free_port(); let empty_transactions_result: Vec = vec![]; let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x178def".to_string(), 2) - .response(empty_transactions_result, 2) + .ok_response("0x178def".to_string(), 2) + .ok_response(empty_transactions_result, 2) .start(); let subject = make_blockchain_interface_web3(port); let end_block_nbr = 1024u64; let result = subject - .retrieve_transactions( - 42u64, - end_block_nbr, - to_wallet.address(), - ) + .retrieve_transactions(42u64, end_block_nbr, to_wallet.address()) .wait(); assert_eq!( @@ -590,24 +564,6 @@ mod tests { transactions: vec![] }) ); - - // TODO: GH-543: Improve MBCS so we can confirm the calls we make are the correct ones. - // Example of older code - // let requests = test_server.requests_so_far(); - // let bodies: Vec = requests - // .into_iter() - // .map(|request| serde_json::from_slice(&request.body()).unwrap()) - // .map(|b: Value| serde_json::to_string(&b).unwrap()) - // .collect(); - // let expected_body_prefix = r#"[{"id":0,"jsonrpc":"2.0","method":"eth_blockNumber","params":[]},{"id":1,"jsonrpc":"2.0","method":"eth_getLogs","params":[{"address":"0x384dec25e03f94931767ce4c3556168468ba24c3","fromBlock":"0x2a","toBlock":"0x400","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",null,"0x000000000000000000000000"#; - // let expected_body_suffix = r#""]}]}]"#; - // let expected_body = format!( - // "{}{}{}", - // expected_body_prefix, - // &to[2..], - // expected_body_suffix - // ); - // assert_eq!(bodies, vec!(expected_body)); } #[test] @@ -623,7 +579,7 @@ mod tests { ) { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x178def", 1) + .ok_response("0x178def", 1) .raw_response(r#"{"jsonrpc":"2.0","id":3,"result":[{"address":"0xcd6c588e005032dd882cd43bf53a32129be81302","blockHash":"0x1a24b9169cbaec3f6effa1f600b70c7ab9e8e86db44062b49132a4415d26732a","blockNumber":"0x4be663","data":"0x0000000000000000000000000000000000000000000000056bc75e2d63100000","logIndex":"0x0","removed":false,"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],"transactionHash":"0x955cec6ac4f832911ab894ce16aa22c3003f46deff3f7165b32700d2f5ff0681","transactionIndex":"0x0"}]}"#.to_string()) .start(); let subject = make_blockchain_interface_web3(port); @@ -649,7 +605,7 @@ mod tests { ) { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x178def", 1) + .ok_response("0x178def", 1) .raw_response(r#"{"jsonrpc":"2.0","id":3,"result":[{"address":"0xcd6c588e005032dd882cd43bf53a32129be81302","blockHash":"0x1a24b9169cbaec3f6effa1f600b70c7ab9e8e86db44062b49132a4415d26732a","blockNumber":"0x4be663","data":"0x0000000000000000000000000000000000000000000000056bc75e2d6310000001","logIndex":"0x0","removed":false,"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000003f69f9efd4f2592fd70be8c32ecd9dce71c472fc","0x000000000000000000000000adc1853c7859369639eb414b6342b36288fe6092"],"transactionHash":"0x955cec6ac4f832911ab894ce16aa22c3003f46deff3f7165b32700d2f5ff0681","transactionIndex":"0x0"}]}"#.to_string()) .start(); let subject = make_blockchain_interface_web3(port); @@ -672,7 +628,7 @@ mod tests { ) { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x400", 1) + .ok_response("0x400", 1) .raw_response(r#"{"jsonrpc":"2.0","id":2,"result":[{"address":"0xcd6c588e005032dd882cd43bf53a32129be81302","blockHash":"0x1a24b9169cbaec3f6effa1f600b70c7ab9e8e86db44062b49132a4415d26732a","data":"0x0000000000000000000000000000000000000000000000000010000000000000","logIndex":"0x0","removed":false,"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000003f69f9efd4f2592fd70be8c32ecd9dce71c472fc","0x000000000000000000000000adc1853c7859369639eb414b6342b36288fe6092"],"transactionHash":"0x955cec6ac4f832911ab894ce16aa22c3003f46deff3f7165b32700d2f5ff0681","transactionIndex":"0x0"}]}"#.to_string()) .start(); init_test_logging(); @@ -714,7 +670,7 @@ mod tests { ) { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("trash", 1) + .ok_response("trash", 1) .raw_response(r#"{"jsonrpc":"2.0","id":2,"result":[{"address":"0xcd6c588e005032dd882cd43bf53a32129be81302","blockHash":"0x1a24b9169cbaec3f6effa1f600b70c7ab9e8e86db44062b49132a4415d26732a","data":"0x0000000000000000000000000000000000000000000000000010000000000000","logIndex":"0x0","removed":false,"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000003f69f9efd4f2592fd70be8c32ecd9dce71c472fc","0x000000000000000000000000adc1853c7859369639eb414b6342b36288fe6092"],"transactionHash":"0x955cec6ac4f832911ab894ce16aa22c3003f46deff3f7165b32700d2f5ff0681","transactionIndex":"0x0"}]}"#.to_string()) .start(); let subject = make_blockchain_interface_web3(port); @@ -746,11 +702,11 @@ mod tests { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) // gas_price - .response("0x3B9ACA00".to_string(), 0) // 1000000000 + .ok_response("0x3B9ACA00".to_string(), 0) // 1000000000 // transaction_fee_balance - .response("0xFFF0".to_string(), 0) // 65520 + .ok_response("0xFFF0".to_string(), 0) // 65520 // masq_balance - .response( + .ok_response( "0x000000000000000000000000000000000000000000000000000000000000FFFF".to_string(), // 65535 0, ) @@ -825,7 +781,7 @@ mod tests { fn build_of_the_blockchain_agent_fails_on_transaction_fee_balance() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x3B9ACA00".to_string(), 0) + .ok_response("0x3B9ACA00".to_string(), 0) .start(); let expected_err_factory = |wallet: &Wallet| { BlockchainAgentBuildError::TransactionFeeBalance( @@ -846,8 +802,8 @@ mod tests { fn build_of_the_blockchain_agent_fails_on_masq_balance() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x3B9ACA00".to_string(), 0) - .response("0xFFF0".to_string(), 0) + .ok_response("0x3B9ACA00".to_string(), 0) + .ok_response("0xFFF0".to_string(), 0) .start(); let expected_err_factory = |wallet: &Wallet| { BlockchainAgentBuildError::ServiceFeeBalance( @@ -920,7 +876,7 @@ mod tests { 7, ) .raw_response(r#"{ "jsonrpc": "2.0", "id": 1, "result": null }"#.to_string()) - .response("trash".to_string(), 0) + .ok_response("trash".to_string(), 0) .raw_response(tx_receipt_response_not_present) .raw_response(tx_receipt_response_failed) .raw_response(tx_receipt_response_success) @@ -934,30 +890,41 @@ mod tests { .unwrap(); assert_eq!(result[0], TransactionReceiptResult::LocalError("RPC error: Error { code: ServerError(429), message: \"The requests per second (RPS) of your requests are higher than your plan allows.\", data: None }".to_string())); - assert_eq!(result[1], TransactionReceiptResult::NotPresent); + assert_eq!( + result[1], + TransactionReceiptResult::RpcResponse(TxReceipt { + transaction_hash: tx_hash_2, + status: TxStatus::Pending + }) + ); assert_eq!( result[2], TransactionReceiptResult::LocalError( "invalid type: string \"trash\", expected struct Receipt".to_string() ) ); - assert_eq!(result[3], TransactionReceiptResult::NotPresent); + assert_eq!( + result[3], + TransactionReceiptResult::RpcResponse(TxReceipt { + transaction_hash: tx_hash_4, + status: TxStatus::Pending + }) + ); assert_eq!( result[4], - TransactionReceiptResult::TransactionFailed(TxReceipt { + TransactionReceiptResult::RpcResponse(TxReceipt { transaction_hash: tx_hash_5, - block_hash: None, - block_number: None, - status: Some(false), + status: TxStatus::Failed, }) ); assert_eq!( result[5], - TransactionReceiptResult::Found(TxReceipt { + TransactionReceiptResult::RpcResponse(TxReceipt { transaction_hash: tx_hash_6, - block_hash: Some(block_hash), - block_number: Some(block_number), - status: Some(true), + status: TxStatus::Succeeded(TransactionBlock { + block_hash, + block_number, + }), }) ); } @@ -975,14 +942,14 @@ mod tests { .unwrap(); let tx_hash_vec = vec![tx_hash_1, tx_hash_2]; - let result = subject + let error = subject .process_transaction_receipts(tx_hash_vec) .wait() .unwrap_err(); assert_eq!( - result, - BlockchainError::QueryFailed("Transport error: Error(IncompleteMessage)".to_string()) + error, + QueryFailed("Transport error: Error(IncompleteMessage)".to_string()) ); } diff --git a/node/src/blockchain/blockchain_interface_utils.rs b/node/src/blockchain/blockchain_interface/blockchain_interface_web3/utils.rs similarity index 98% rename from node/src/blockchain/blockchain_interface_utils.rs rename to node/src/blockchain/blockchain_interface/blockchain_interface_web3/utils.rs index 65597a246..2be7d5977 100644 --- a/node/src/blockchain/blockchain_interface_utils.rs +++ b/node/src/blockchain/blockchain_interface/blockchain_interface_web3/utils.rs @@ -1,8 +1,5 @@ // Copyright (c) 2024, MASQ (https://masq.ai) and/or its affiliates. All rights reserved. -// TODO: GH-744: At the end of the review rename this file to: web3_blockchain_interface_utils.rs -// Or we should move this file into blockchain_interface_web3 - use crate::accountant::db_access_objects::payable_dao::PayableAccount; use crate::accountant::db_access_objects::pending_payable_dao::PendingPayable; use crate::accountant::scanners::mid_scan_msg_handling::payable_scanner::agent_web3::BlockchainAgentWeb3; @@ -311,7 +308,7 @@ pub fn send_payables_within_batch( ) } -pub fn dynamically_create_blockchain_agent_web3( +pub fn create_blockchain_agent_web3( gas_limit_const_part: u128, blockchain_agent_future_result: BlockchainAgentFutureResult, wallet: Wallet, @@ -377,7 +374,7 @@ mod tests { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) .begin_batch() - .response( + .ok_response( "0x94881436a9c89f48b01651ff491c69e97089daf71ab8cfb240243d7ecf9b38b2".to_string(), 7, ) @@ -390,7 +387,7 @@ mod tests { .unwrap(); let pending_nonce = 1; let chain = DEFAULT_CHAIN; - let gas_price = DEFAULT_GAS_PRICE; + let gas_price_in_gwei = DEFAULT_GAS_PRICE; let consuming_wallet = make_paying_wallet(b"paying_wallet"); let account = make_payable_account(1); let web3_batch = Web3::new(Batch::new(transport)); @@ -401,7 +398,7 @@ mod tests { &account, consuming_wallet, pending_nonce.into(), - (gas_price * 1_000_000_000) as u128, + gwei_to_wei(gas_price_in_gwei), ); let mut batch_result = web3_batch.eth().transport().submit_batch().wait().unwrap(); @@ -434,7 +431,7 @@ mod tests { .unwrap(); let web3_batch = Web3::new(Batch::new(transport)); let chain = DEFAULT_CHAIN; - let gas_price = DEFAULT_GAS_PRICE; + let gas_price_in_gwei = DEFAULT_GAS_PRICE; let pending_nonce = 1; let consuming_wallet = make_paying_wallet(b"paying_wallet"); let account_1 = make_payable_account(1); @@ -446,7 +443,7 @@ mod tests { chain, &web3_batch, consuming_wallet, - (gas_price * 1_000_000_000) as u128, + gwei_to_wei(gas_price_in_gwei), pending_nonce.into(), &accounts, ); @@ -642,8 +639,9 @@ mod tests { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) .begin_batch() - .response("rpc_result".to_string(), 7) - .response("rpc_result_2".to_string(), 8) + // TODO: GH-547: This rpc_result should be validated in production code. + .ok_response("irrelevant_ok_rpc_response".to_string(), 7) + .ok_response("irrelevant_ok_rpc_response_2".to_string(), 8) .end_batch() .start(); let expected_result = Ok(vec![ @@ -748,7 +746,7 @@ mod tests { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) .begin_batch() - .response("rpc_result".to_string(), 7) + .ok_response("rpc_result".to_string(), 7) .err_response( 429, "The requests per second (RPS) of your requests are higher than your plan allows." @@ -1014,7 +1012,7 @@ mod tests { Wallet::from(address) }; let nonce_correct_type = U256::from(nonce); - let gas_price = match chain { + let gas_price_in_gwei = match chain { Chain::EthMainnet => TEST_GAS_PRICE_ETH, Chain::EthRopsten => TEST_GAS_PRICE_ETH, Chain::PolyMainnet => TEST_GAS_PRICE_POLYGON, @@ -1034,7 +1032,7 @@ mod tests { consuming_wallet, payable_account.balance_wei, nonce_correct_type, - (gas_price * 1_000_000_000) as u128, + gwei_to_wei(gas_price_in_gwei), ); let byte_set_to_compare = signed_transaction.raw_transaction.0; diff --git a/node/src/blockchain/blockchain_interface_initializer.rs b/node/src/blockchain/blockchain_interface_initializer.rs index 06fbf491b..ee87519a0 100644 --- a/node/src/blockchain/blockchain_interface_initializer.rs +++ b/node/src/blockchain/blockchain_interface_initializer.rs @@ -63,13 +63,13 @@ mod tests { fn initialize_web3_interface_works() { let port = find_free_port(); let _blockchain_client_server = MBCSBuilder::new(port) - .response("0x3B9ACA00".to_string(), 0) // gas_price = 10000000000 - .response("0xFF40".to_string(), 0) - .response( + .ok_response("0x3B9ACA00".to_string(), 0) // gas_price = 10000000000 + .ok_response("0xFF40".to_string(), 0) + .ok_response( "0x000000000000000000000000000000000000000000000000000000000000FFFF".to_string(), 0, ) - .response("0x23".to_string(), 1) + .ok_response("0x23".to_string(), 1) .start(); let wallet = make_wallet("123"); let chain = Chain::PolyMainnet; diff --git a/node/src/blockchain/mod.rs b/node/src/blockchain/mod.rs index 20435b48b..4c51e726e 100644 --- a/node/src/blockchain/mod.rs +++ b/node/src/blockchain/mod.rs @@ -4,7 +4,6 @@ pub mod bip39; pub mod blockchain_bridge; pub mod blockchain_interface; pub mod blockchain_interface_initializer; -mod blockchain_interface_utils; pub mod payer; pub mod signature; #[cfg(test)]