Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
928d136
GH-605: pre review changes
utkarshg6 Aug 24, 2025
24e0a8a
GH-598-json-hotfix (#699)
bertllll Sep 9, 2025
093d7de
GH-605: review changes
utkarshg6 Sep 6, 2025
2fd4bcc
GH-605: eliminate new_fingerprints_recipient
utkarshg6 Sep 11, 2025
44be81d
GH-605: add commit hash to TODO
utkarshg6 Sep 11, 2025
cc7da7a
GH-605: add TODOs for GH-703
utkarshg6 Sep 11, 2025
d666e53
GH-605: refactor out the failed_tx
utkarshg6 Sep 11, 2025
2450508
GH-605: more review changes
utkarshg6 Sep 11, 2025
bb1a67d
GH-605: more refactoring of sql values
utkarshg6 Sep 11, 2025
074a40b
GH-605: further fixes
utkarshg6 Sep 11, 2025
070123a
GH-605: more changes
utkarshg6 Sep 11, 2025
52034fb
GH-605: change it to retrieved_payables
utkarshg6 Sep 12, 2025
8f63153
GH-605: rename to determine_next_scan_to_run
utkarshg6 Sep 12, 2025
1c2d773
GH-605: more changes
utkarshg6 Sep 12, 2025
e851f34
GH-605: improve the TODO
utkarshg6 Sep 12, 2025
ca6cb36
GH-642: Redesigning PendingPayableScanner (#677)
bertllll Sep 15, 2025
6e020c7
GH-689: Amend scanner scheduling: Handling ScanError msg (#691)
bertllll Sep 15, 2025
24396b1
GH-605: add TODO for the test
utkarshg6 Sep 16, 2025
647d61a
GH-606: Sweeping for ending the first stage (#706)
bertllll Sep 16, 2025
d2fd9cd
GH-605: more and more changes
utkarshg6 Sep 18, 2025
52411c9
GH-605: bit more refactoring
utkarshg6 Sep 18, 2025
398bdd9
GH-605: bit more changes
utkarshg6 Sep 18, 2025
e044dc4
GH-605: changing to & works
utkarshg6 Sep 18, 2025
8227dc8
GH-605: further changes
utkarshg6 Sep 18, 2025
ff6e400
GH-605: more TODOs
utkarshg6 Sep 18, 2025
dc863ef
GH-605: derive Copy for PayableScanType
utkarshg6 Sep 19, 2025
9fd9ee7
GH-605: add scan_type function
utkarshg6 Sep 19, 2025
9ba398e
GH-605: comment out unused code in test
utkarshg6 Sep 19, 2025
80711d4
GH-605: refactor the code a bit
utkarshg6 Sep 19, 2025
4ac6418
GH-605: refactor signable_tx_templates_can_be_created_from_priced_ret…
utkarshg6 Sep 19, 2025
83d6155
GH-605: the helper functions have more realistic args name
utkarshg6 Sep 19, 2025
141d10a
GH-605: more refactoring of signable_tx_templates_can_be_created_from…
utkarshg6 Sep 19, 2025
4f91045
GH-605: more refactored changes
utkarshg6 Sep 19, 2025
896f7d0
GH-605: further refactoring changes
utkarshg6 Sep 19, 2025
18e0a54
GH-605: handle_batch_results has been renamed
utkarshg6 Sep 19, 2025
cf0938a
GH-605: few more changes
utkarshg6 Sep 20, 2025
9308d37
GH-605: few more changes
utkarshg6 Sep 20, 2025
73395d8
GH-605: Review 4
utkarshg6 Sep 22, 2025
7522708
GH-605: Bug bot error
utkarshg6 Sep 22, 2025
e7c7716
GH-605: Just merged; 567 errors
utkarshg6 Sep 23, 2025
794d23a
GH-605: reduced errors to 97
utkarshg6 Sep 24, 2025
655830d
GH-605: only 37 errors remaining
utkarshg6 Sep 24, 2025
06106f7
GH-605: only 5 errors remaining
utkarshg6 Sep 25, 2025
8947136
GH-605: only 2 errors remaining
utkarshg6 Sep 25, 2025
b2df759
GH-605: all errors gone
utkarshg6 Sep 25, 2025
2828f80
GH-605: tests in sent_payable_dao are passing
utkarshg6 Sep 25, 2025
9a51af4
GH-605: all tests pass in payable scanner
utkarshg6 Sep 26, 2025
663c30e
GH-605: fix most of the clippy warnings
utkarshg6 Sep 26, 2025
6c84f82
GH-605: fix more of these problems
utkarshg6 Sep 26, 2025
2f07581
GH-605: write test for the ordering of ValidationStatus
utkarshg6 Sep 26, 2025
d6b8592
GH-605: implement ordering for ValidationStatus
utkarshg6 Sep 26, 2025
5838a52
GH-605: comment out unused code
utkarshg6 Sep 26, 2025
eab920d
GH-605: more changes fixed
utkarshg6 Sep 26, 2025
2cbdffe
GH-605: more fixing
utkarshg6 Sep 26, 2025
62f3542
GH-605: interim commit
Sep 26, 2025
97f54c8
GH-605: all tests in Node passing
Sep 27, 2025
d94d5cb
GH-605: last todo removed
Sep 28, 2025
b82e3d2
GH-605: fixed poor test coverage
Sep 28, 2025
76a857c
GH-605: free of unnecessary boilerplate code - erased manual impls fo…
Sep 28, 2025
b9ad935
GH-605: continuous impovement -- Ord and little refactoring
Sep 29, 2025
00f0223
GH-605: CI except MNT just fine
Sep 29, 2025
15a4de1
GH-605: MNT fixed
Sep 29, 2025
02d98fb
GH-605: small correction
Sep 29, 2025
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
106 changes: 49 additions & 57 deletions node/src/accountant/db_access_objects/failed_payable_dao.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025, MASQ (https://masq.ai) and/or its affiliates. All rights reserved.
use crate::accountant::db_access_objects::sent_payable_dao::Tx;
use crate::accountant::db_access_objects::utils::{
DaoFactoryReal, TxHash, TxIdentifiers, VigilantRusqliteFlatten,
sql_values_of_failed_tx, DaoFactoryReal, TxHash, TxIdentifiers, VigilantRusqliteFlatten,
};
use crate::accountant::db_access_objects::Transaction;
use crate::accountant::db_big_integer::big_int_divider::BigIntDivider;
Expand Down Expand Up @@ -96,31 +96,31 @@ pub struct FailedTx {

impl Transaction for FailedTx {
fn hash(&self) -> TxHash {
todo!()
self.hash
}

fn receiver_address(&self) -> Address {
self.receiver_address
}

fn amount(&self) -> u128 {
todo!()
self.amount
}

fn timestamp(&self) -> i64 {
todo!()
self.timestamp
}

fn gas_price_wei(&self) -> u128 {
todo!()
self.gas_price_wei
}

fn nonce(&self) -> u64 {
todo!()
self.nonce
}

fn is_failed(&self) -> bool {
todo!()
true
}
}

Expand All @@ -142,9 +142,9 @@ impl Ord for FailedTx {
}
}

impl FailedTx {
pub fn from_sent_tx_and_web3_err(sent_tx: &Tx, error: &Web3Error) -> Self {
FailedTx {
impl From<(&Tx, &Web3Error)> for FailedTx {
fn from((sent_tx, error): (&Tx, &Web3Error)) -> Self {
Self {
hash: sent_tx.hash,
receiver_address: sent_tx.receiver_address,
amount: sent_tx.amount,
Expand Down Expand Up @@ -260,30 +260,7 @@ impl FailedPayableDao for FailedPayableDaoReal<'_> {
reason, \
status
) VALUES {}",
join_with_separator(
txs,
|tx| {
let amount_checked = checked_conversion::<u128, i128>(tx.amount);
let gas_price_wei_checked = checked_conversion::<u128, i128>(tx.gas_price_wei);
let (amount_high_b, amount_low_b) = BigIntDivider::deconstruct(amount_checked);
let (gas_price_wei_high_b, gas_price_wei_low_b) =
BigIntDivider::deconstruct(gas_price_wei_checked);
format!(
"('{:?}', '{:?}', {}, {}, {}, {}, {}, {}, '{}', '{}')",
tx.hash,
tx.receiver_address,
amount_high_b,
amount_low_b,
tx.timestamp,
gas_price_wei_high_b,
gas_price_wei_low_b,
tx.nonce,
tx.reason,
tx.status
)
},
", "
)
join_with_separator(txs, |tx| sql_values_of_failed_tx(tx), ", ")
);

match self.conn.prepare(&sql).expect("Internal error").execute([]) {
Expand Down Expand Up @@ -452,13 +429,14 @@ mod tests {
Concluded, RecheckRequired, RetryRequired,
};
use crate::accountant::db_access_objects::failed_payable_dao::{
FailedPayableDao, FailedPayableDaoError, FailedPayableDaoReal, FailureReason,
FailedPayableDao, FailedPayableDaoError, FailedPayableDaoReal, FailedTx, FailureReason,
FailureRetrieveCondition, FailureStatus, ValidationStatus,
};
use crate::accountant::db_access_objects::test_utils::{
make_read_only_db_connection, FailedTxBuilder,
};
use crate::accountant::db_access_objects::utils::current_unix_timestamp;
use crate::accountant::db_access_objects::Transaction;
use crate::blockchain::errors::rpc_errors::LocalError::Decoder;
use crate::blockchain::errors::rpc_errors::{AppRpcError, AppRpcErrorKind};
use crate::blockchain::errors::validation_status::{
Expand Down Expand Up @@ -709,23 +687,6 @@ mod tests {
);
}

#[test]
fn show_str() {
let validation_failure_clock = ValidationFailureClockMock::default().now_result(
SystemTime::UNIX_EPOCH
.add(Duration::from_secs(1755080031))
.add(Duration::from_nanos(612180914)),
);
let a =
FailureStatus::RecheckRequired(ValidationStatus::Reattempting(PreviousAttempts::new(
BlockchainErrorKind::AppRpc(AppRpcErrorKind::Unreachable),
&validation_failure_clock,
)))
.to_string();

eprintln!("a: {}", a);
}

#[test]
fn failure_status_from_str_works() {
let validation_failure_clock = ValidationFailureClockMock::default().now_result(
Expand Down Expand Up @@ -988,12 +949,12 @@ mod tests {
]);

let result = subject.update_statuses(hashmap);

let updated_txs = subject.retrieve_txs(None);
let updated_tx1 = updated_txs.iter().find(|tx| tx.hash == hash1).unwrap();
let updated_tx2 = updated_txs.iter().find(|tx| tx.hash == hash2).unwrap();
let updated_tx3 = updated_txs.iter().find(|tx| tx.hash == hash3).unwrap();
let updated_tx4 = updated_txs.iter().find(|tx| tx.hash == hash4).unwrap();
let find_tx = |tx_hash| updated_txs.iter().find(|tx| tx.hash == tx_hash).unwrap();
let updated_tx1 = find_tx(hash1);
let updated_tx2 = find_tx(hash2);
let updated_tx3 = find_tx(hash3);
let updated_tx4 = find_tx(hash4);
assert_eq!(result, Ok(()));
assert_eq!(tx1.status, RetryRequired);
assert_eq!(updated_tx1.status, Concluded);
Expand Down Expand Up @@ -1206,4 +1167,35 @@ mod tests {
let expected_order = vec![tx4, tx3, tx2, tx1];
assert_eq!(set.into_iter().collect::<Vec<_>>(), expected_order);
}

#[test]
fn transaction_trait_methods_for_failed_tx() {
let hash = make_tx_hash(1);
let receiver_address = make_address(1);
let amount = 1000;
let timestamp = 1625247600;
let gas_price_wei = 2000;
let nonce = 42;
let reason = FailureReason::Reverted;
let status = FailureStatus::RetryRequired;

let failed_tx = FailedTx {
hash,
receiver_address,
amount,
timestamp,
gas_price_wei,
nonce,
reason,
status,
};

assert_eq!(failed_tx.receiver_address(), receiver_address);
assert_eq!(failed_tx.hash(), hash);
assert_eq!(failed_tx.amount(), amount);
assert_eq!(failed_tx.timestamp(), timestamp);
assert_eq!(failed_tx.gas_price_wei(), gas_price_wei);
assert_eq!(failed_tx.nonce(), nonce);
assert_eq!(failed_tx.is_failed(), true);
}
}
4 changes: 2 additions & 2 deletions node/src/accountant/db_access_objects/payable_dao.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1259,10 +1259,10 @@ mod tests {
}

#[test]
fn retrieve_payables_should_return_payables_with_no_pending_transaction_by_addresses() {
fn retrieve_payables_should_return_payables_by_addresses() {
let home_dir = ensure_node_home_directory_exists(
"payable_dao",
"retrieve_payables_should_return_payables_with_no_pending_transaction_by_addresses",
"retrieve_payables_should_return_payables_by_addresses",
);
let subject = PayableDaoReal::new(
DbInitializerReal::default()
Expand Down
68 changes: 38 additions & 30 deletions node/src/accountant/db_access_objects/sent_payable_dao.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use ethereum_types::{H256};
use web3::types::Address;
use masq_lib::utils::ExpectValue;
use crate::accountant::{checked_conversion, join_with_separator};
use crate::accountant::db_access_objects::utils::{DaoFactoryReal, TxHash, TxIdentifiers};
use crate::accountant::db_access_objects::utils::{sql_values_of_sent_tx, DaoFactoryReal, TxHash, TxIdentifiers};
use crate::accountant::db_big_integer::big_int_divider::BigIntDivider;
use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{TransactionBlock};
use crate::database::rusqlite_wrappers::ConnectionWrapper;
Expand Down Expand Up @@ -39,31 +39,31 @@ pub struct Tx {

impl Transaction for Tx {
fn hash(&self) -> TxHash {
todo!()
self.hash
}

fn receiver_address(&self) -> Address {
self.receiver_address
}

fn amount(&self) -> u128 {
todo!()
self.amount
}

fn timestamp(&self) -> i64 {
todo!()
self.timestamp
}

fn gas_price_wei(&self) -> u128 {
todo!()
self.gas_price_wei
}

fn nonce(&self) -> u64 {
todo!()
self.nonce
}

fn is_failed(&self) -> bool {
todo!()
false
}
}

Expand Down Expand Up @@ -238,29 +238,7 @@ impl SentPayableDao for SentPayableDaoReal<'_> {
nonce, \
status \
) VALUES {}",
join_with_separator(
txs,
|tx| {
let amount_checked = checked_conversion::<u128, i128>(tx.amount);
let gas_price_wei_checked = checked_conversion::<u128, i128>(tx.gas_price_wei);
let (amount_high_b, amount_low_b) = BigIntDivider::deconstruct(amount_checked);
let (gas_price_wei_high_b, gas_price_wei_low_b) =
BigIntDivider::deconstruct(gas_price_wei_checked);
format!(
"('{:?}', '{:?}', {}, {}, {}, {}, {}, {}, '{}')",
tx.hash,
tx.receiver_address,
amount_high_b,
amount_low_b,
tx.timestamp,
gas_price_wei_high_b,
gas_price_wei_low_b,
tx.nonce,
tx.status
)
},
", "
)
join_with_separator(txs, |tx| sql_values_of_sent_tx(tx), ", ")
);

match self.conn.prepare(&sql).expect("Internal error").execute([]) {
Expand Down Expand Up @@ -503,6 +481,7 @@ mod tests {
use crate::accountant::db_access_objects::sent_payable_dao::RetrieveCondition::{ByHash, IsPending};
use crate::accountant::db_access_objects::sent_payable_dao::SentPayableDaoError::{EmptyInput, PartialExecution};
use crate::accountant::db_access_objects::test_utils::{make_read_only_db_connection, TxBuilder};
use crate::accountant::db_access_objects::Transaction;
use crate::blockchain::blockchain_interface::blockchain_interface_web3::lower_level_interface_web3::{TransactionBlock};
use crate::blockchain::errors::BlockchainErrorKind;
use crate::blockchain::errors::rpc_errors::AppRpcErrorKind;
Expand Down Expand Up @@ -1401,4 +1380,33 @@ mod tests {
let expected_order = vec![tx3, tx2, tx1];
assert_eq!(set.into_iter().collect::<Vec<_>>(), expected_order);
}

#[test]
fn transaction_trait_methods_for_tx() {
let hash = make_tx_hash(1);
let receiver_address = make_address(1);
let amount = 1000;
let timestamp = 1625247600;
let gas_price_wei = 2000;
let nonce = 42;
let status = TxStatus::Pending(ValidationStatus::Waiting);

let tx = Tx {
hash,
receiver_address,
amount,
timestamp,
gas_price_wei,
nonce,
status,
};

assert_eq!(tx.receiver_address(), receiver_address);
assert_eq!(tx.hash(), hash);
assert_eq!(tx.amount(), amount);
assert_eq!(tx.timestamp(), timestamp);
assert_eq!(tx.gas_price_wei(), gas_price_wei);
assert_eq!(tx.nonce(), nonce);
assert_eq!(tx.is_failed(), false);
}
}
4 changes: 4 additions & 0 deletions node/src/accountant/db_access_objects/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ pub fn make_sent_tx(n: u32) -> Tx {
}

pub fn assert_on_sent_txs(left: Vec<Tx>, right: Vec<Tx>) {
assert_eq!(left.len(), right.len());

left.iter().zip(right).for_each(|(t1, t2)| {
assert_eq!(t1.hash, t2.hash);
assert_eq!(t1.receiver_address, t2.receiver_address);
Expand All @@ -175,6 +177,8 @@ pub fn assert_on_sent_txs(left: Vec<Tx>, right: Vec<Tx>) {
}

pub fn assert_on_failed_txs(left: Vec<FailedTx>, right: Vec<FailedTx>) {
assert_eq!(left.len(), right.len());

left.iter().zip(right).for_each(|(f1, f2)| {
assert_eq!(f1.hash, f2.hash);
assert_eq!(f1.receiver_address, f2.receiver_address);
Expand Down
43 changes: 43 additions & 0 deletions node/src/accountant/db_access_objects/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) 2019, MASQ (https://masq.ai) and/or its affiliates. All rights reserved.

use crate::accountant::db_access_objects::failed_payable_dao::FailedTx;
use crate::accountant::db_access_objects::payable_dao::PayableAccount;
use crate::accountant::db_access_objects::receivable_dao::ReceivableAccount;
use crate::accountant::db_big_integer::big_int_divider::BigIntDivider;
Expand All @@ -22,6 +23,7 @@ use std::path::{Path, PathBuf};
use std::string::ToString;
use std::time::Duration;
use std::time::SystemTime;
use crate::accountant::db_access_objects::sent_payable_dao::Tx;

pub type TxHash = H256;
pub type RowId = u64;
Expand All @@ -46,6 +48,47 @@ pub fn from_unix_timestamp(unix_timestamp: i64) -> SystemTime {
SystemTime::UNIX_EPOCH + interval
}

pub fn sql_values_of_failed_tx(failed_tx: &FailedTx) -> String {
let amount_checked = checked_conversion::<u128, i128>(failed_tx.amount);
let gas_price_wei_checked = checked_conversion::<u128, i128>(failed_tx.gas_price_wei);
let (amount_high_b, amount_low_b) = BigIntDivider::deconstruct(amount_checked);
let (gas_price_wei_high_b, gas_price_wei_low_b) =
BigIntDivider::deconstruct(gas_price_wei_checked);
format!(
"('{:?}', '{:?}', {}, {}, {}, {}, {}, {}, '{}', '{}')",
failed_tx.hash,
failed_tx.receiver_address,
amount_high_b,
amount_low_b,
failed_tx.timestamp,
gas_price_wei_high_b,
gas_price_wei_low_b,
failed_tx.nonce,
failed_tx.reason,
failed_tx.status
)
}

pub fn sql_values_of_sent_tx(sent_tx: &Tx) -> String {
let amount_checked = checked_conversion::<u128, i128>(sent_tx.amount);
let gas_price_wei_checked = checked_conversion::<u128, i128>(sent_tx.gas_price_wei);
let (amount_high_b, amount_low_b) = BigIntDivider::deconstruct(amount_checked);
let (gas_price_wei_high_b, gas_price_wei_low_b) =
BigIntDivider::deconstruct(gas_price_wei_checked);
format!(
"('{:?}', '{:?}', {}, {}, {}, {}, {}, {}, '{}')",
sent_tx.hash,
sent_tx.receiver_address,
amount_high_b,
amount_low_b,
sent_tx.timestamp,
gas_price_wei_high_b,
gas_price_wei_low_b,
sent_tx.nonce,
sent_tx.status
)
}

pub struct DaoFactoryReal {
pub data_directory: PathBuf,
pub init_config: DbInitializationConfig,
Expand Down
Loading