Skip to content

Commit 5d11811

Browse files
authored
[Cairo1] Fix GasBuiltin handling (#1789)
* Load initial_gas & account for segment arena pointer * Remove initial_gas arg from create_entry_code * Account for gas builtin when serializing input * Load initial_gas even if no args * Remove debug code * Add test for reported case * remove program added by accident * Improve comment * Add CHANGELOG entry
1 parent 3f9428e commit 5d11811

File tree

5 files changed

+56
-15
lines changed

5 files changed

+56
-15
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
#### Upcoming Changes
44

5+
* fix: Handle `GasBuiltin` in cairo1-run crate [#1789](https://github.com/lambdaclass/cairo-vm/pull/1789)
6+
* Load `initial_gas` into vm instead of creating it via instructions.
7+
* Fix bug affecting programs with input arguments and gas builtin.
8+
59
* fix: Change (de)serialization of CairoPie's `OutputBuiltinAdditionalData`'s `PublicMemoryPage` to vectors of length 2. [#1781](https://github.com/lambdaclass/cairo-vm/pull/1781)
610

711
* fix: Fixed deserialization issue when signature additional data is empty, and the name of the builtin range_check96 [#1785](https://github.com/lambdaclass/cairo-vm/pull/1785)

cairo1-run/src/cairo_run.rs

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ pub fn cairo_run_program(
176176
&casm_program,
177177
&type_sizes,
178178
main_func,
179-
initial_gas,
180179
&cairo_run_config,
181180
)?;
182181

@@ -254,7 +253,7 @@ pub fn cairo_run_program(
254253
cairo_run_config.trace_enabled,
255254
)?;
256255
let end = runner.initialize(cairo_run_config.proof_mode)?;
257-
load_arguments(&mut runner, &cairo_run_config, main_func)?;
256+
load_arguments(&mut runner, &cairo_run_config, main_func, initial_gas)?;
258257

259258
// Run it until the end / infinite loop in proof_mode
260259
runner.run_until_pc(end, &mut hint_processor)?;
@@ -394,7 +393,7 @@ fn create_code_footer() -> Vec<Instruction> {
394393
}
395394

396395
// Loads the input arguments into the execution segment, leaving the necessary gaps for the values that will be written by
397-
// the instructions in the entry_code (produced by `create_entry_code`)
396+
// the instructions in the entry_code (produced by `create_entry_code`). Also loads the initial gas if the GasBuiltin is present
398397

399398
/* Example of execution segment before running the main function:
400399
Before calling this function (after runner.initialize):
@@ -441,19 +440,27 @@ After the entry_code (up until calling main) has been ran by the VM:
441440
builtin_base_0
442441
builtin_base_1
443442
(*2) segment_arena_ptr + 3 (segment_arena base)
443+
(*4) initial_gas
444444
(*3) arg_0
445445
(*3) arg_1
446446
]
447447
(*1) if output builtin is added (if either proof_mode or append_return_values is enabled)
448448
(*2) if segment arena is present
449449
(*3) if args are used
450+
(*4) if gas builtin is present
450451
*/
451452
fn load_arguments(
452453
runner: &mut CairoRunner,
453454
cairo_run_config: &Cairo1RunConfig,
454455
main_func: &Function,
456+
initial_gas: usize,
455457
) -> Result<(), Error> {
456-
if cairo_run_config.args.is_empty() {
458+
let got_gas_builtin = main_func
459+
.signature
460+
.param_types
461+
.iter()
462+
.any(|ty| ty.debug_name.as_ref().is_some_and(|n| n == "GasBuiltin"));
463+
if cairo_run_config.args.is_empty() && !got_gas_builtin {
457464
// Nothing to be done
458465
return Ok(());
459466
}
@@ -470,12 +477,21 @@ fn load_arguments(
470477
// * segment_arena_ptr
471478
// * info_segment_ptr
472479
// * 0
480+
// * segment_arena_ptr + 3
473481
let mut ap_offset = runner.get_program().builtins_len();
474482
if cairo_run_config.copy_to_output() {
475483
ap_offset += runner.get_program().builtins_len() - 1;
476484
}
477485
if got_segment_arena {
478-
ap_offset += 3;
486+
ap_offset += 4;
487+
}
488+
// Load initial gas if GasBuiltin is present
489+
if got_gas_builtin {
490+
runner.vm.insert_value(
491+
(runner.vm.get_ap() + ap_offset).map_err(VirtualMachineError::Math)?,
492+
Felt252::from(initial_gas),
493+
)?;
494+
ap_offset += 1;
479495
}
480496
for arg in cairo_run_config.args {
481497
match arg {
@@ -516,11 +532,20 @@ fn create_entry_code(
516532
casm_program: &CairoProgram,
517533
type_sizes: &UnorderedHashMap<ConcreteTypeId, i16>,
518534
func: &Function,
519-
initial_gas: usize,
520535
config: &Cairo1RunConfig,
521536
) -> Result<(CasmContext, Vec<BuiltinName>), Error> {
522537
let copy_to_output_builtin = config.copy_to_output();
523538
let signature = &func.signature;
539+
let got_segment_arena = signature.param_types.iter().any(|ty| {
540+
get_info(sierra_program_registry, ty)
541+
.map(|x| x.long_id.generic_id == SegmentArenaType::ID)
542+
.unwrap_or_default()
543+
});
544+
let got_gas_builtin = signature.param_types.iter().any(|ty| {
545+
get_info(sierra_program_registry, ty)
546+
.map(|x| x.long_id.generic_id == GasBuiltinType::ID)
547+
.unwrap_or_default()
548+
});
524549
// The builtins in the formatting expected by the runner.
525550
let (builtins, builtin_offset) =
526551
get_function_builtins(&signature.param_types, copy_to_output_builtin);
@@ -538,11 +563,6 @@ fn create_entry_code(
538563
let offset: i16 = 2 + builtins.len().into_or_panic::<i16>();
539564
ctx.add_var(CellExpression::Deref(deref!([fp - offset])))
540565
});
541-
let got_segment_arena = signature.param_types.iter().any(|ty| {
542-
get_info(sierra_program_registry, ty)
543-
.map(|x| x.long_id.generic_id == SegmentArenaType::ID)
544-
.unwrap_or_default()
545-
});
546566
if copy_to_output_builtin {
547567
// Leave a gap to write the builtin final pointers
548568
// We write them on a fixed cells relative to the starting FP pointer so we don't lose them after serializing outputs
@@ -583,9 +603,9 @@ fn create_entry_code(
583603
ap += 1;
584604
};
585605
} else if generic_ty == &GasBuiltinType::ID {
606+
// We already loaded the inital gas so we just advance AP
586607
casm_build_extend! {ctx,
587-
const initial_gas = initial_gas;
588-
tempvar _gas = initial_gas;
608+
ap += 1;
589609
};
590610
} else {
591611
let ty_size = type_sizes[ty];
@@ -703,8 +723,10 @@ fn create_entry_code(
703723
// We lost the output_ptr var after re-scoping, so we need to create it again
704724
// The last instruction will write the last output ptr so we can find it in [ap - 1]
705725
let output_ptr = ctx.add_var(CellExpression::Deref(deref!([ap - 1])));
706-
// len(builtins - output) + len(builtins) + if segment_arena: segment_arena_ptr + info_ptr + 0 + (segment_arena_ptr + 3)
707-
let offset = (2 * builtins.len() - 1 + 4 * got_segment_arena as usize) as i16;
726+
// len(builtins - output) + len(builtins) + if segment_arena: segment_arena_ptr + info_ptr + 0 + (segment_arena_ptr + 3) + (gas_builtin)
727+
let offset = (2 * builtins.len() - 1
728+
+ 4 * got_segment_arena as usize
729+
+ got_gas_builtin as usize) as i16;
708730
let array_start_ptr = ctx.add_var(CellExpression::Deref(deref!([fp + offset])));
709731
let array_end_ptr = ctx.add_var(CellExpression::Deref(deref!([fp + offset + 1])));
710732
casm_build_extend! {ctx,

cairo1-run/src/main.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,13 @@ mod tests {
414414
#[case("bitwise.cairo", "11772", "[11772]", None, None)]
415415
#[case("factorial.cairo", "3628800", "[3628800]", None, None)]
416416
#[case("fibonacci.cairo", "89", "[89]", None, None)]
417+
#[case(
418+
"with_input/dict_with_input.cairo",
419+
"[17 18]",
420+
"[17 18]",
421+
Some("[17 18]"),
422+
Some("[17 18]")
423+
)]
417424

418425
fn test_run_progarm(
419426
#[case] program: &str,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main(input:Array<felt252>) -> Array<felt252> {
2+
let _elements: Felt252Dict<Nullable<Span<u8>>> = Default::default();
3+
input
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main(input:Array<felt252>) -> Array<felt252> {
2+
let _elements: Felt252Dict<Nullable<Span<u8>>> = Default::default();
3+
input
4+
}

0 commit comments

Comments
 (0)