Skip to content

Conversation

@ddoktorski
Copy link
Contributor

Towards #3660

@ddoktorski ddoktorski requested a review from a team as a code owner October 21, 2025 11:50
@ddoktorski ddoktorski requested review from MKowalski8 and franciszekjob and removed request for a team October 21, 2025 11:50
@ddoktorski ddoktorski marked this pull request as draft October 21, 2025 11:52
@ddoktorski ddoktorski force-pushed the remove-fuzzing-fractional-part branch from d59ea90 to e22f8aa Compare October 22, 2025 09:29
Base automatically changed from remove-fuzzing-fractional-part to master October 22, 2025 09:59
@ddoktorski ddoktorski force-pushed the add-gas-report-logic branch from fc46288 to 8a9f925 Compare October 22, 2025 11:03
@ddoktorski ddoktorski force-pushed the add-gas-report-logic branch from 8a9f925 to 8f3b1f6 Compare October 22, 2025 18:37
@ddoktorski ddoktorski marked this pull request as ready for review October 22, 2025 18:57
@ddoktorski ddoktorski requested review from cptartur and ksew1 October 22, 2025 18:57
Comment on lines +43 to +50
#[must_use]
pub fn new_with_report(
gas_used: GasVector,
call_trace: &CallTrace,
contracts_data: &ContractsDataStore,
) -> Self {
Self::new(gas_used).collect_gas_data(call_trace, contracts_data)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Wdyt about a little refactor here? Seems better to me:

    #[must_use]
    pub fn new_with_report(
        gas_used: GasVector,
        call_trace: &CallTrace,
        contracts_data: &ContractsDataStore,
    ) -> Self {
        let mut info = Self::new(gas_used);
        info.collect_gas_data(call_trace, contracts_data);
        info.finalize();
        info
    }

and we don't call finalize in collect_gas_data

fn collect_gas_data(&mut self, trace: &CallTrace, contracts_data: &ContractsDataStore) {
        let mut stack = trace.nested_calls.clone();

        while let Some(call_trace_node) = stack.pop() {
            if let CallTraceNode::EntryPointCall(call) = call_trace_node {
                let call = call.borrow();
                let class_hash = call.entry_point.class_hash.expect(
                    "class_hash should be set in `fn execute_call_entry_point` in cheatnet",
                );

                let contract_name = get_contract_name(contracts_data, class_hash);
                let selector = get_selector(contracts_data, call.entry_point.entry_point_selector);
                let gas = call
                    .gas_report_data
                    .as_ref()
                    .expect("Gas report data must be updated after test execution")
                    .get_gas();

                self.update_entry(contract_name, selector, gas);
                stack.extend(call.nested_calls.clone());
            }
        }
    }

pub fn new(gas_used: GasVector) -> Self {
Self {
gas_used,
report_data: ReportData(BTreeMap::new()),
Copy link
Member

Choose a reason for hiding this comment

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

Bit weird to have a public constructor that doesn't have a gas report when collect_gas_data is private.

}

#[derive(Debug, Clone)]
pub struct ReportData(BTreeMap<ContractName, ContractInfo>);
Copy link
Member

Choose a reason for hiding this comment

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

Is there a point to this wrapper? It's used in a public field, but the inner BTreeMap<ContractName, ContractInfo>); is not public. So I understand it cannot be accessed by external modules anyway.

Why don't we just make the fields of GasSingleTestInfo not pub?

Comment on lines +95 to +101
fn finalize(&mut self) {
for contract_info in self.report_data.0.values_mut() {
for gas_info in contract_info.functions.values_mut() {
gas_info.gas_stats = GasStats::new(&gas_info.records);
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

I'd consider structuring this a bit different. Instead of having this struct technically accessible in non-final state, before finalized is called, I'd make it's internals private and changed the finalize method to return a new, different struct (some fields can probably be reused).

This way it is clear that this one is a "in progress" one and there's a separate struct representing a final result.

Copy link
Member

@ksew1 ksew1 Oct 23, 2025

Choose a reason for hiding this comment

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

You can even do this on the same struct using type state pattern

pub struct NoReport;
pub struct WithReport;

#[derive(Debug, Clone)]
pub struct GasSingleTestInfo<State> {
    pub gas_used: GasVector,
    pub report_data: ReportData,
    _state: PhantomData<State>,
}


pub fn finalize(self) -> GasSingleTestInfo<WithReport>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd consider structuring this a bit different. Instead of having this struct technically accessible in non-final state, before finalized is called

What do you mean by technically accessible in a non-final state? It's possible to modify the fields since they are public, but there's a distinction between new and new_with_report, both return "finalized" versions

Copy link
Member

Choose a reason for hiding this comment

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

I mean it's bit weird for me to share the same struct for gas data with and without raport, where report_data is typed as non-optional, and finalize method is private, so depending how the struct was constructed, there's no way to move it to a state with gas report non private.

I'd either represent these different states more explicitly, use separate structs or follow the pattern @ksew1 shared.

Copy link
Member

@ksew1 ksew1 left a comment

Choose a reason for hiding this comment

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

I do rest of review tomorrow as I am getting sleepy 😴

Comment on lines +95 to +101
fn finalize(&mut self) {
for contract_info in self.report_data.0.values_mut() {
for gas_info in contract_info.functions.values_mut() {
gas_info.gas_stats = GasStats::new(&gas_info.records);
}
}
}
Copy link
Member

@ksew1 ksew1 Oct 23, 2025

Choose a reason for hiding this comment

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

You can even do this on the same struct using type state pattern

pub struct NoReport;
pub struct WithReport;

#[derive(Debug, Clone)]
pub struct GasSingleTestInfo<State> {
    pub gas_used: GasVector,
    pub report_data: ReportData,
    _state: PhantomData<State>,
}


pub fn finalize(self) -> GasSingleTestInfo<WithReport>

mod trace;
mod tree;

pub use contracts_data_store::ContractsDataStore;
Copy link
Member

Choose a reason for hiding this comment

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

It is not a biggie right now, but we are beginning to leak implementation details, and this crate is becoming entangled with something unrelated—in this case, the gas report. Maybe ContractsData should contain better information so that we can use it here, as it is already used as the base in ContractsDataStore.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would it make sense to move ContractsDataStore out of the debugging crate?

Copy link
Member

Choose a reason for hiding this comment

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

It is one of the options, but now we would have three structures: ContractsData, ForkData, and ContractsDataStore. ContractsDataStore is most complete so maybe we could delete other 2?

@ddoktorski ddoktorski requested review from cptartur and ksew1 October 24, 2025 11:22
Copy link
Member

@cptartur cptartur left a comment

Choose a reason for hiding this comment

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

Looks good, let's agree on and resolve the open comments

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.

4 participants