Skip to content

Commit 9be9e3d

Browse files
Fix resources from syscalls in nested calls (#3506)
<!-- Reference any GitHub issues resolved by this PR --> Closes #3473 ## Introduced changes Fix bug calculation of resources from nested calls syscalls. The reason of malformed calculations was that during subtracting syscalls' resources in `remove_syscall_resources_and_exit_non_error_call`, they were only from current call and didn't include the ones from nested calls. ## Checklist <!-- Make sure all of these are complete --> - [x] Linked relevant issue - [x] Updated relevant documentation - [x] Added relevant tests - [x] Performed self-review of the code - [x] Added changes to `CHANGELOG.md`
1 parent 373da93 commit 9be9e3d

File tree

9 files changed

+155
-91
lines changed

9 files changed

+155
-91
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Forge
11+
12+
#### Fixed
13+
14+
- Bug where syscall execution resources from nested calls were being calculated twice
15+
1016
### Cast
1117

1218
#### Changed

crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/cairo1_execution.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use crate::runtime_extensions::call_to_blockifier_runtime_extension::execution::
55
};
66
use crate::runtime_extensions::cheatable_starknet_runtime_extension::CheatableStarknetRuntimeExtension;
77
use crate::runtime_extensions::common::get_relocated_vm_trace;
8-
use blockifier::execution::contract_class::CompiledClassV1;
8+
use blockifier::execution::contract_class::{CompiledClassV1, TrackedResource};
99
use blockifier::execution::entry_point::ExecutableCallEntryPoint;
1010
use blockifier::execution::entry_point_execution::{
1111
ExecutionRunnerMode, VmExecutionContext, finalize_execution,
1212
initialize_execution_context_with_runner_mode, prepare_call_arguments,
1313
};
14+
use blockifier::execution::syscalls::hint_processor::SyscallUsageMap;
1415
use blockifier::{
1516
execution::{
1617
contract_class::EntryPointV1, entry_point::EntryPointExecutionContext,
@@ -93,6 +94,8 @@ pub(crate) fn execute_entry_point_call_cairo1(
9394
})?;
9495

9596
let trace = get_relocated_vm_trace(&mut runner);
97+
98+
// Syscall usage here is flat, meaning it only includes syscalls from current call
9699
let syscall_usage = cheatable_runtime
97100
.extended_runtime
98101
.hint_handler
@@ -124,9 +127,15 @@ pub(crate) fn execute_entry_point_call_cairo1(
124127
.register_error(class_hash, pcs);
125128
}
126129

130+
let (syscall_usage_vm_resources, syscall_usage_sierra_gas) = match tracked_resource {
131+
TrackedResource::CairoSteps => (syscall_usage, SyscallUsageMap::default()),
132+
TrackedResource::SierraGas => (SyscallUsageMap::default(), syscall_usage),
133+
};
134+
127135
Ok(CallInfoWithExecutionData {
128136
call_info,
129-
syscall_usage,
137+
syscall_usage_vm_resources,
138+
syscall_usage_sierra_gas,
130139
vm_trace: Some(trace),
131140
})
132141
// endregion

crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/deprecated/cairo0_execution.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use blockifier::execution::deprecated_entry_point_execution::{
1414
use blockifier::execution::entry_point::{EntryPointExecutionContext, ExecutableCallEntryPoint};
1515
use blockifier::execution::errors::EntryPointExecutionError;
1616
use blockifier::execution::execution_utils::Args;
17+
use blockifier::execution::syscalls::hint_processor::SyscallUsageMap;
1718
use blockifier::state::state_api::State;
1819
use cairo_vm::hint_processor::hint_processor_definition::HintProcessor;
1920
use cairo_vm::vm::runners::cairo_runner::{CairoArg, CairoRunner};
@@ -82,7 +83,8 @@ pub(crate) fn execute_entry_point_call_cairo0(
8283

8384
Ok(CallInfoWithExecutionData {
8485
call_info: execution_result,
85-
syscall_usage,
86+
syscall_usage_vm_resources: syscall_usage,
87+
syscall_usage_sierra_gas: SyscallUsageMap::default(),
8688
vm_trace: None,
8789
})
8890
// endregion

crates/cheatnet/src/runtime_extensions/call_to_blockifier_runtime_extension/execution/entry_point.rs

Lines changed: 43 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use crate::runtime_extensions::call_to_blockifier_runtime_extension::execution::
33
use crate::runtime_extensions::call_to_blockifier_runtime_extension::rpc::{AddressOrClassHash, CallResult};
44
use crate::runtime_extensions::call_to_blockifier_runtime_extension::CheatnetState;
55
use crate::runtime_extensions::common::{get_relocated_vm_trace, get_syscalls_gas_consumed, sum_syscall_usage};
6-
use crate::state::{CallTrace, CallTraceNode, CheatStatus};
6+
use crate::runtime_extensions::forge_runtime_extension::{get_nested_calls_syscalls_sierra_gas, get_nested_calls_syscalls_vm_resources};
7+
use crate::state::{CheatStatus};
78
use blockifier::execution::call_info::{CallExecution, Retdata};
89
use blockifier::execution::contract_class::{RunnableCompiledClass, TrackedResource};
910
use blockifier::execution::syscalls::hint_processor::{SyscallUsageMap, ENTRYPOINT_NOT_FOUND_ERROR, OUT_OF_GAS_ERROR};
@@ -28,9 +29,7 @@ use starknet_api::{
2829
transaction::{fields::Calldata, TransactionVersion},
2930
};
3031
use starknet_types_core::felt::Felt;
31-
use std::cell::RefCell;
3232
use std::collections::{HashMap, HashSet};
33-
use std::rc::Rc;
3433
use blockifier::execution::entry_point::{EntryPointRevertInfo, ExecutableCallEntryPoint};
3534
use blockifier::execution::stack_trace::{extract_trailing_cairo1_revert_trace, Cairo1RevertHeader};
3635
use thiserror::Error;
@@ -42,7 +41,8 @@ pub(crate) type ContractClassEntryPointExecutionResult =
4241

4342
pub(crate) struct CallInfoWithExecutionData {
4443
pub call_info: CallInfo,
45-
pub syscall_usage: SyscallUsageMap,
44+
pub syscall_usage_vm_resources: SyscallUsageMap,
45+
pub syscall_usage_sierra_gas: SyscallUsageMap,
4646
pub vm_trace: Option<Vec<RelocatedTraceEntry>>,
4747
}
4848

@@ -82,7 +82,8 @@ pub fn execute_call_entry_point(
8282
cheatnet_state.trace_data.exit_nested_call(
8383
ExecutionResources::default(),
8484
u64::default(),
85-
HashMap::default(),
85+
SyscallUsageMap::default(),
86+
SyscallUsageMap::default(),
8687
CallResult::Success {
8788
ret_data: ret_data_f252,
8889
},
@@ -93,6 +94,7 @@ pub fn execute_call_entry_point(
9394
.tracked_resource_stack
9495
.last()
9596
.expect("Unexpected empty tracked resource.");
97+
9698
return Ok(mocked_call_info(
9799
entry_point.clone(),
98100
ret_data.clone(),
@@ -193,16 +195,17 @@ pub fn execute_call_entry_point(
193195
) {
194196
Ok(CallInfoWithExecutionData {
195197
call_info,
196-
syscall_usage,
198+
syscall_usage_vm_resources,
199+
syscall_usage_sierra_gas,
197200
vm_trace,
198201
}) => {
199202
remove_syscall_resources_and_exit_non_error_call(
200203
&call_info,
201-
&syscall_usage,
204+
&syscall_usage_vm_resources,
205+
&syscall_usage_sierra_gas,
202206
context,
203207
cheatnet_state,
204208
vm_trace,
205-
current_tracked_resource,
206209
);
207210
Ok(call_info)
208211
}
@@ -291,40 +294,55 @@ fn call_info_from_pre_execution_error(
291294
tracked_resource: current_tracked_resource,
292295
..Default::default()
293296
},
294-
syscall_usage: SyscallUsageMap::default(),
297+
syscall_usage_vm_resources: SyscallUsageMap::default(),
298+
syscall_usage_sierra_gas: SyscallUsageMap::default(),
295299
vm_trace: None,
296300
}
297301
}
298302

299303
fn remove_syscall_resources_and_exit_non_error_call(
300304
call_info: &CallInfo,
301-
syscall_usage: &SyscallUsageMap,
305+
syscall_usage_vm_resources: &SyscallUsageMap,
306+
syscall_usage_sierra_gas: &SyscallUsageMap,
302307
context: &mut EntryPointExecutionContext,
303308
cheatnet_state: &mut CheatnetState,
304309
vm_trace: Option<Vec<RelocatedTraceEntry>>,
305-
current_tracked_resource: TrackedResource,
306310
) {
307311
let versioned_constants = context.tx_context.block_context.versioned_constants();
308312
// We don't want the syscall resources to pollute the results
309313
let mut resources = call_info.resources.clone();
310314
let mut gas_consumed = call_info.execution.gas_consumed;
311315

312-
match current_tracked_resource {
313-
TrackedResource::CairoSteps => {
314-
resources -= &versioned_constants.get_additional_os_syscall_resources(syscall_usage);
315-
}
316-
TrackedResource::SierraGas => {
317-
gas_consumed -= get_syscalls_gas_consumed(syscall_usage, versioned_constants);
318-
}
319-
}
316+
// Remove resources consumed by syscalls from the current call
317+
// `syscall_usage_vm_resources` and `syscall_usage_sierra_gas` are flat, meaning they only include syscalls from the specific call
318+
resources -=
319+
&versioned_constants.get_additional_os_syscall_resources(syscall_usage_vm_resources);
320+
gas_consumed -= get_syscalls_gas_consumed(syscall_usage_sierra_gas, versioned_constants);
321+
322+
// Below syscall usages are cumulative.
323+
let nested_syscall_usage_vm_resources =
324+
get_nested_calls_syscalls_vm_resources(&cheatnet_state.trace_data.current_call_stack.top());
325+
let nested_syscall_usage_sierra_gas =
326+
get_nested_calls_syscalls_sierra_gas(&cheatnet_state.trace_data.current_call_stack.top());
327+
328+
// Remove resources consumed by syscalls from nested calls
329+
resources -= &versioned_constants
330+
.get_additional_os_syscall_resources(&nested_syscall_usage_vm_resources);
331+
gas_consumed -=
332+
get_syscalls_gas_consumed(&nested_syscall_usage_sierra_gas, versioned_constants);
333+
334+
let syscall_usage_vm_resources = sum_syscall_usage(
335+
nested_syscall_usage_vm_resources,
336+
syscall_usage_vm_resources,
337+
);
338+
let syscall_usage_sierra_gas =
339+
sum_syscall_usage(nested_syscall_usage_sierra_gas, syscall_usage_sierra_gas);
320340

321-
let nested_syscall_usage_sum =
322-
aggregate_nested_syscall_usage(&cheatnet_state.trace_data.current_call_stack.top());
323-
let syscall_usage = sum_syscall_usage(nested_syscall_usage_sum, syscall_usage);
324341
cheatnet_state.trace_data.exit_nested_call(
325342
resources,
326343
gas_consumed,
327-
syscall_usage,
344+
syscall_usage_vm_resources,
345+
syscall_usage_sierra_gas,
328346
CallResult::from_non_error(call_info),
329347
&call_info.execution.l2_to_l1_messages,
330348
vm_trace,
@@ -344,7 +362,8 @@ fn exit_error_call(
344362
cheatnet_state.trace_data.exit_nested_call(
345363
ExecutionResources::default(),
346364
u64::default(),
347-
HashMap::default(),
365+
SyscallUsageMap::default(),
366+
SyscallUsageMap::default(),
348367
CallResult::from_err(error, &identifier),
349368
&[],
350369
vm_trace,
@@ -435,28 +454,6 @@ fn mocked_call_info(
435454
}
436455
}
437456

438-
fn aggregate_nested_syscall_usage(trace: &Rc<RefCell<CallTrace>>) -> SyscallUsageMap {
439-
let mut result = SyscallUsageMap::new();
440-
for nested_call_node in &trace.borrow().nested_calls {
441-
if let CallTraceNode::EntryPointCall(nested_call) = nested_call_node {
442-
let sub_trace_counter = aggregate_syscall_usage(nested_call);
443-
result = sum_syscall_usage(result, &sub_trace_counter);
444-
}
445-
}
446-
result
447-
}
448-
449-
fn aggregate_syscall_usage(trace: &Rc<RefCell<CallTrace>>) -> SyscallUsageMap {
450-
let mut result = trace.borrow().used_syscalls.clone();
451-
for nested_call_node in &trace.borrow().nested_calls {
452-
if let CallTraceNode::EntryPointCall(nested_call) = nested_call_node {
453-
let sub_trace_counter = aggregate_nested_syscall_usage(nested_call);
454-
result = sum_syscall_usage(result, &sub_trace_counter);
455-
}
456-
}
457-
result
458-
}
459-
460457
#[derive(Debug, Error)]
461458
#[error("{}", source)]
462459
pub struct EntryPointExecutionErrorWithTrace {

crates/cheatnet/src/runtime_extensions/forge_runtime_extension/mod.rs

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,10 @@ pub fn add_resources_to_top_call(
602602
}
603603
}
604604

605-
pub fn update_top_call_resources(runtime: &mut ForgeRuntime) {
605+
pub fn update_top_call_resources(
606+
runtime: &mut ForgeRuntime,
607+
top_call_tracked_resource: TrackedResource,
608+
) {
606609
// call representing the test code
607610
let top_call = runtime
608611
.extended_runtime
@@ -616,10 +619,15 @@ pub fn update_top_call_resources(runtime: &mut ForgeRuntime) {
616619
let all_execution_resources = add_execution_resources(top_call.clone());
617620
let all_sierra_gas_consumed = add_sierra_gas_resources(&top_call);
618621

622+
// Below syscall usages are cumulative, meaning they include syscalls from their inner calls.
623+
let nested_calls_syscalls_vm_resources = get_nested_calls_syscalls_vm_resources(&top_call);
624+
let nested_calls_syscalls_sierra_gas = get_nested_calls_syscalls_sierra_gas(&top_call);
625+
619626
let mut top_call = top_call.borrow_mut();
620627
top_call.used_execution_resources = all_execution_resources;
621628
top_call.gas_consumed = all_sierra_gas_consumed;
622629

630+
// Syscall usage here is flat, meaning it only includes syscalls from current call (in this case the top-level call)
623631
let top_call_syscalls = runtime
624632
.extended_runtime
625633
.extended_runtime
@@ -628,16 +636,49 @@ pub fn update_top_call_resources(runtime: &mut ForgeRuntime) {
628636
.syscalls_usage
629637
.clone();
630638

639+
let mut total_syscalls_vm_resources = nested_calls_syscalls_vm_resources.clone();
640+
let mut total_syscalls_sierra_gas = nested_calls_syscalls_sierra_gas.clone();
641+
642+
// Based on the tracked resource of top call, we add the syscall usage to respective totals.
643+
match top_call_tracked_resource {
644+
TrackedResource::CairoSteps => {
645+
total_syscalls_vm_resources =
646+
sum_syscall_usage(total_syscalls_vm_resources, &top_call_syscalls);
647+
}
648+
TrackedResource::SierraGas => {
649+
total_syscalls_sierra_gas =
650+
sum_syscall_usage(total_syscalls_sierra_gas, &top_call_syscalls);
651+
}
652+
}
653+
654+
top_call.used_syscalls_vm_resources = total_syscalls_vm_resources;
655+
top_call.used_syscalls_sierra_gas = total_syscalls_sierra_gas;
656+
}
657+
658+
/// Calculates the total syscall usage from nested calls where the tracked resource is Cairo steps.
659+
pub fn get_nested_calls_syscalls_vm_resources(trace: &Rc<RefCell<CallTrace>>) -> SyscallUsageMap {
631660
// Only sum 1-level since these include syscalls from inner calls
632-
let nested_calls_syscalls = top_call
661+
trace
662+
.borrow()
633663
.nested_calls
634664
.iter()
635665
.filter_map(CallTraceNode::extract_entry_point_call)
636666
.fold(SyscallUsageMap::new(), |syscalls, trace| {
637-
sum_syscall_usage(syscalls, &trace.borrow().used_syscalls)
638-
});
667+
sum_syscall_usage(syscalls, &trace.borrow().used_syscalls_vm_resources)
668+
})
669+
}
639670

640-
top_call.used_syscalls = sum_syscall_usage(top_call_syscalls, &nested_calls_syscalls);
671+
/// Calculates the total syscall usage from nested calls where the tracked resource is Sierra gas.
672+
pub fn get_nested_calls_syscalls_sierra_gas(trace: &Rc<RefCell<CallTrace>>) -> SyscallUsageMap {
673+
// Only sum 1-level since these include syscalls from inner calls
674+
trace
675+
.borrow()
676+
.nested_calls
677+
.iter()
678+
.filter_map(CallTraceNode::extract_entry_point_call)
679+
.fold(SyscallUsageMap::new(), |syscalls, trace| {
680+
sum_syscall_usage(syscalls, &trace.borrow().used_syscalls_sierra_gas)
681+
})
641682
}
642683

643684
// Only top-level is considered relevant since we can't have l1 handlers deeper than 1 level of nesting
@@ -769,21 +810,17 @@ pub fn get_all_used_resources(
769810

770811
let mut execution_resources = top_call.borrow().used_execution_resources.clone();
771812
let mut sierra_gas_consumed = top_call.borrow().gas_consumed;
772-
let top_call_syscalls = top_call.borrow().used_syscalls.clone();
773-
774-
match tracked_resource {
775-
TrackedResource::CairoSteps => {
776-
execution_resources = add_syscall_execution_resources(
777-
versioned_constants,
778-
&execution_resources,
779-
&top_call_syscalls,
780-
);
781-
}
782-
TrackedResource::SierraGas => {
783-
sierra_gas_consumed +=
784-
get_syscalls_gas_consumed(&top_call_syscalls, versioned_constants);
785-
}
786-
}
813+
let top_call_syscalls = top_call.borrow().get_total_used_syscalls();
814+
815+
execution_resources = add_syscall_execution_resources(
816+
versioned_constants,
817+
&execution_resources,
818+
&top_call.borrow().used_syscalls_vm_resources,
819+
);
820+
sierra_gas_consumed += get_syscalls_gas_consumed(
821+
&top_call.borrow().used_syscalls_sierra_gas,
822+
versioned_constants,
823+
);
787824

788825
let events = runtime_call_info
789826
.iter() // This method iterates over inner calls as well

0 commit comments

Comments
 (0)