Skip to content

Conversation

@bertllll
Copy link
Contributor

@bertllll bertllll commented Nov 4, 2025

Note

Adds accounting debug stats and message ID utilities, refactors pending-payables scanner and log wording, and updates address/test helpers.

  • Logging/Debugging:
    • Introduce logging_utils with accounting_msgs_debug (aggregate per-address debits over a window) and msg_id_generator.
    • Wire into Accountant (logging_utils, DEFAULT_ACCOUNTING_MSG_LOG_WINDOW, debug containers); msg_id() now uses new generator.
  • Accountant:
    • record_service_provided/consumed return u128; debug-posting collection for Report* handlers.
    • Improved trace/info wording for pending-payables reruns.
  • PendingPayableScanner:
    • Split into start_scan.rs and finish_scan.rs.
    • Rename caches/wording from "suspected" to "supposed"; log "Collected … supposed failures".
    • Simplify harvesting/merging APIs (use vectors, no Option), and tidy emptiness checks.
  • Tests/Strings:
    • Update expectations across tests and multinode integration to new log messages and behaviors.
    • Remove old MessageIdGenerator from sub_lib; add tests for new generator.
  • Utils:
    • Change blockchain::test_utils::make_address layout; adjust expected addresses in tests accordingly.

Written by Cursor Bugbot for commit e8dc244. This will update automatically on new commits. Configure here.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on November 14

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

accounting_msg_stats: self.stats.drain().collect(),
log_window_in_pcs_of_msgs: log_window_size,
})
} else {
Copy link

Choose a reason for hiding this comment

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

Bug: Misleading Debug Logs for Message Types

The loggable_stats method in AccountingMsgStats hardcodes AccountingMsgType::RoutingServiceProvided when generating debug logs. This causes logs for ExitServiceProvided and ServicesConsumed messages to incorrectly display "RoutingServiceProvided", making the debug output misleading.

Fix in Cursor Fix in Web

Copy link
Collaborator

@utkarshg6 utkarshg6 left a comment

Choose a reason for hiding this comment

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

Continue at node/src/accountant/mod.rs:833

MessageIdGenerator, MessageIdGeneratorReal,
};

pub struct LoggingUtils {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please consider the following renames:

pub struct AccountingLogger {
    pub debug_stats: AccountingMessageTracker,
    pub id_generator: Box<dyn MessageIdGenerator>,
}

pub struct AccountingMessageTracker {
    routing_stats: AccountingBuffer,
    exit_stats: AccountingBuffer,
    consumed_stats: AccountingBuffer,
}

struct AccountingBuffer {
    address_totals: HashMap<Address, u128>,
    message_count: usize,
}

report_sent_payables_sub_opt: Option<Recipient<SentPayables>>,
ui_message_sub_opt: Option<Recipient<NodeToUiMessage>>,
message_id_generator: Box<dyn MessageIdGenerator>,
logging_utils: LoggingUtils,
Copy link
Collaborator

Choose a reason for hiding this comment

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

In case you rename this structure, rename the field name too.

payload_size: usize,
wallet: &Wallet,
) {
) -> u128 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function is violating one principle: "A fn that mutates shouldn't return anything." These two responsibilities should be done by two different functions.

);
})

let new_postings = NewPostingsDebugContainer::new(&self.logger)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of "posting", can you please use "charges"?

Copy link
Collaborator

@utkarshg6 utkarshg6 left a comment

Choose a reason for hiding this comment

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

Continue at node/src/accountant/scanners/pending_payable_scanner/finish_scan.rs


let new_postings = self.handle_routing_services_consumed(msg, msg_id, new_postings);

self.logging_utils.accounting_msgs_stats.manage_debug_log(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd prefer if you directly log it here... that'll be clearer. From the outside, it only appears it's just a log, but after a deep dive, I see use of &mut, and I don't think it's ideal to do it this way, we should do mutations and logging separately, using different functions step by step. Give it a thought. I didn't give an absolute example, because there is nesting in the code and you would need to refactor on multiple levels to fix that. I'd appreciate if you do.

msg.routing_payload_size
);

let sum = self.record_service_consumed(
Copy link
Collaborator

Choose a reason for hiding this comment

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

It should be done in two steps rather than one. One function should just calculate total charge and other should update and log.

In accountant.rs:

pub struct ServicesConsumed {
    pub service_rate: u64,
    pub byte_rate: u64,
    pub payload_size: usize,
}

impl Display for ServicesConsumed {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "service rate {}, byte rate {}, payload size {}",
            self.service_rate, self.byte_rate, self.payload_size
        )
    }
}

impl ServicesConsumed {
    pub fn calculate_total_charge(&self) -> u128 {
        let byte_charge = self.byte_rate as u128 * (self.payload_size as u128);
        self.service_rate as u128 + byte_charge
    }
}

In accountant/mod.rs:

impl Accountant {

   ....

    fn update_records_in_payable(
        &self,
        total_charge: u128,
        services_consumed: &ServicesConsumed,
        timestamp: SystemTime,
        wallet: Wallet,
    ) {
        match self
            .payable_dao
            .as_ref()
            .more_money_payable(timestamp, wallet, total_charge)
        {
            Ok(_) => (),
            Err(PayableDaoError::SignConversion(_)) => error!(
                self.logger,
                "Overflow error recording consumed services from {}: total charge {}, {}. Skipping",
                wallet,
                total_charge,
                services_consumed
            ),
            Err(e) => panic!(
                "Recording services consumed from {} but has hit fatal database error: {:?}",
                wallet, e
            ),
        };
    }

    fn record_service_consumed(
        &self,
        services_consumed: ServicesConsumed,
        timestamp: SystemTime,
        wallet: &Wallet,
    ) -> u128 {
        if self.our_wallet(wallet) {
            warning!(
                self.logger,
                "Declining to record a payable against our wallet {} for service we provided",
                wallet
            );

            return 0;
        }

        let total_charge = services_consumed.calculate_total_charge();
        self.update_records_in_payable(total_charge, &services_consumed, timestamp, wallet);

        total_charge
    }
}

Copy link
Collaborator

@utkarshg6 utkarshg6 left a comment

Choose a reason for hiding this comment

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

Continue at node/src/accountant/logging_utils/accounting_msgs_debug.rs

}

fn handle_new_postings(&mut self, new_postings: Vec<NewPosting>) {
for new_posting in &new_postings {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of using the & here, you can call new_postings.iter()

Like this:

for new_posting in new_postings.iter() {
    *self.stats.entry(new_posting.address).or_default() += new_posting.amount_wei;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why should I? Isn't it indifferent? It doesn't help in anything.

Copy link
Collaborator

@utkarshg6 utkarshg6 left a comment

Choose a reason for hiding this comment

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

Continue at node/src/accountant/logging_utils/accounting_msgs_debug.rs:198

);
}

fn test_manage_debug_log(
Copy link
Collaborator

@utkarshg6 utkarshg6 Nov 5, 2025

Choose a reason for hiding this comment

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

This function is difficult to understand. It would be helpful if you could add comments that can act as a line of demarcation for different phases. It would be great to create those too (only refactor out such functions if you can find general purpose use case, otherwise don't bother yourself).

fn record_new_posting_feed_in(
first_expected_stats: Vec<(Address, u128)>,
second_new_posting: Vec<NewPosting>,
) -> Vec<(Address, u128)> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please do minor renames here:

record_new_posting_feed_in -> merge_stats_with_new_postings
first_expected_stats -> existing_stats
second_new_posting -> new_postings

second_expected_stats
}

fn generate_posting_feeds_representing_msgs(gap_size: u16) -> Vec<Vec<NewPosting>> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Consider the following renames:

gap_size -> window_size
outer_idx -> message_number
inner_idx -> posting_index

Copy link
Collaborator

@utkarshg6 utkarshg6 left a comment

Choose a reason for hiding this comment

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

Continue at node/src/accountant/logging_utils/accounting_msgs_debug.rs:358

new_postings_feeds
}

fn compute_expected_stats_from_new_posting_feeds(
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can do it far better here:

fn calculate_expected_accumulated_stats(
    message_batches: &[Vec<NewPosting>],
) -> Vec<(Address, u128)> {
    message_batches
        .iter()
        .flatten()
        .fold(HashMap::new(), |mut totals, posting| {
            *totals.entry(posting.address).or_default() += posting.amount_wei;
            totals
        })
        .into_iter()
        .sorted()
        .collect()
}

Copy link
Collaborator

@utkarshg6 utkarshg6 left a comment

Choose a reason for hiding this comment

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

Done!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants