Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
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
17 changes: 0 additions & 17 deletions corelib.patch
Original file line number Diff line number Diff line change
Expand Up @@ -1028,23 +1028,6 @@ diff --color=auto -crN cairo2/corelib/src/test.cairo cairo2/corelib_1/src/test.c
*** cairo2/corelib/src/test.cairo Mon Aug 25 09:50:36 2025
--- cairo2/corelib_1/src/test.cairo Wed Sep 3 12:26:58 2025
***************
*** 12,18 ****
mod ec_test;
mod felt_test;
mod fmt_test;
! mod gas_reserve_test;
mod hash_test;
mod integer_test;
mod iter_test;
--- 12,18 ----
mod ec_test;
mod felt_test;
mod fmt_test;
! // mod gas_reserve_test;
mod hash_test;
mod integer_test;
mod iter_test;
***************
*** 24,30 ****
mod option_test;
mod plugins_test;
Expand Down
2 changes: 1 addition & 1 deletion debug_utils/sierra-emu/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,9 @@ impl Value {
StarknetTypeConcrete::Sha256StateHandle(_) => matches!(self, Self::Struct { .. }),
},
CoreTypeConcrete::IntRange(_) => matches!(self, Self::IntRange { .. }),
CoreTypeConcrete::GasReserve(_) => matches!(self, Self::U128(_)),
CoreTypeConcrete::Blake(_) => todo!(),
CoreTypeConcrete::QM31(_) => todo!(),
CoreTypeConcrete::GasReserve(_) => todo!(),
};

if !res {
Expand Down
3 changes: 2 additions & 1 deletion debug_utils/sierra-emu/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ mod felt252_dict;
mod felt252_dict_entry;
mod function_call;
mod gas;
mod gas_reserve;
mod int;
mod int_range;
mod jump;
Expand Down Expand Up @@ -520,12 +521,12 @@ fn eval<'a>(
EvalAction::NormalBranch(0, smallvec![value])
}
CoreConcreteLibfunc::IntRange(selector) => self::int_range::eval(registry, selector, args),
CoreConcreteLibfunc::GasReserve(selector) => self::gas_reserve::eval(selector, args),
CoreConcreteLibfunc::Blake(_) => todo!(),
CoreConcreteLibfunc::QM31(_) => todo!(),
CoreConcreteLibfunc::Felt252SquashedDict(_) => todo!(),
CoreConcreteLibfunc::Trace(_) => todo!(),
CoreConcreteLibfunc::UnsafePanic(_) => todo!(),
CoreConcreteLibfunc::DummyFunctionCall(_) => todo!(),
CoreConcreteLibfunc::GasReserve(_) => todo!(),
}
}
39 changes: 39 additions & 0 deletions debug_utils/sierra-emu/src/vm/gas_reserve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use cairo_lang_sierra::extensions::gas_reserve::GasReserveConcreteLibfunc;
use smallvec::smallvec;

use crate::{vm::EvalAction, Value};

pub fn eval(selector: &GasReserveConcreteLibfunc, args: Vec<Value>) -> EvalAction {
match selector {
GasReserveConcreteLibfunc::Create(_) => eval_gas_reserve_create(args),
GasReserveConcreteLibfunc::Utilize(_) => eval_gas_reserve_utilize(args),
}
}

fn eval_gas_reserve_create(args: Vec<Value>) -> EvalAction {
let [range_check @ Value::Unit, Value::U64(gas), Value::U128(amount)]: [Value; 3] =
args.try_into().unwrap()
else {
panic!()
};

if amount <= gas.into() {
let spare_gas = gas - amount as u64;
EvalAction::NormalBranch(
0,
smallvec![range_check, Value::U64(spare_gas), Value::U128(amount)],
)
} else {
EvalAction::NormalBranch(1, smallvec![range_check, Value::U64(gas)])
}
}

fn eval_gas_reserve_utilize(args: Vec<Value>) -> EvalAction {
let [Value::U64(gas), Value::U128(amount)]: [Value; 2] = args.try_into().unwrap() else {
panic!()
};

let updated_gas = gas + amount as u64;

EvalAction::NormalBranch(0, smallvec![Value::U64(updated_gas)])
}
5 changes: 4 additions & 1 deletion src/libfuncs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ mod felt252_dict;
mod felt252_dict_entry;
mod function_call;
mod gas;
mod gas_reserve;
mod int;
mod int_range;
mod mem;
Expand Down Expand Up @@ -255,9 +256,11 @@ impl LibfuncBuilder for CoreConcreteLibfunc {
metadata,
&info.signature.param_signatures,
),
Self::GasReserve(selector) => self::gas_reserve::build(
context, registry, entry, location, helper, metadata, selector,
),
Self::QM31(_) => native_panic!("Implement QM31 libfunc"),
Self::UnsafePanic(_) => native_panic!("Implement unsafe_panic libfunc"),
Self::GasReserve(_) => native_panic!("Implement gas_reserve libfunc"),
Self::DummyFunctionCall(_) => native_panic!("Implement dummy_function_call libfunc"),
}
}
Expand Down
197 changes: 197 additions & 0 deletions src/libfuncs/gas_reserve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
use crate::libfuncs::LibfuncHelper;
use crate::{error::Result, metadata::MetadataStorage};
use cairo_lang_sierra::extensions::lib_func::SignatureOnlyConcreteLibfunc;
use cairo_lang_sierra::{
extensions::{
core::{CoreLibfunc, CoreType},
gas_reserve::GasReserveConcreteLibfunc,
},
program_registry::ProgramRegistry,
};
use melior::dialect::arith::{self, CmpiPredicate};
use melior::helpers::{ArithBlockExt, BuiltinBlockExt};
use melior::ir::r#type::IntegerType;
use melior::{
ir::{Block, Location},
Context,
};

pub fn build<'ctx, 'this>(
context: &'ctx Context,
registry: &ProgramRegistry<CoreType, CoreLibfunc>,
entry: &'this Block<'ctx>,
location: Location<'ctx>,
helper: &LibfuncHelper<'ctx, 'this>,
metadata: &mut MetadataStorage,
selector: &GasReserveConcreteLibfunc,
) -> Result<()> {
match selector {
GasReserveConcreteLibfunc::Create(info) => {
build_gas_reserve_create(context, registry, entry, location, helper, metadata, info)
}
GasReserveConcreteLibfunc::Utilize(info) => {
build_gas_reserve_utilize(context, registry, entry, location, helper, metadata, info)
}
}
}

/// Generate MLIR operations for the `gas_reserve_create` libfunc.
///
/// # Cairo Signature
///
/// ```cairo
/// pub extern fn gas_reserve_create(
/// amount: u128,
/// ) -> Option<GasReserve> implicits(RangeCheck, GasBuiltin) nopanic;
/// ```
fn build_gas_reserve_create<'ctx, 'this>(
context: &'ctx Context,
_registry: &ProgramRegistry<CoreType, CoreLibfunc>,
entry: &'this Block<'ctx>,
location: Location<'ctx>,
helper: &LibfuncHelper<'ctx, 'this>,
_metadata: &mut MetadataStorage,
_info: &SignatureOnlyConcreteLibfunc,
) -> Result<()> {
let range_check = super::increment_builtin_counter(context, entry, location, entry.arg(0)?)?;
let current_gas = entry.arg(1)?; // u64
let amount = entry.arg(2)?; // u128

let amount_ty = IntegerType::new(context, 128).into();
let current_gas_128 = entry.append_op_result(arith::extui(current_gas, amount_ty, location))?;
let enough_gas = entry.cmpi(
context,
CmpiPredicate::Uge,
current_gas_128,
amount,
location,
)?;

let gas_builtin_ty = IntegerType::new(context, 64).into();
let spare_gas = entry.append_op_result(arith::subi(current_gas_128, amount, location))?;
let spare_gas = entry.append_op_result(arith::trunci(spare_gas, gas_builtin_ty, location))?;

helper.cond_br(
context,
entry,
enough_gas,
[0, 1],
[
&[range_check, spare_gas, amount],
&[range_check, current_gas],
],
location,
)
}

/// Generate MLIR operations for the `gas_reserve_utilize` libfunc.
///
/// # Cairo Signature
///
/// ```cairo
/// pub extern fn gas_reserve_utilize(reserve: GasReserve) implicits(GasBuiltin) nopanic;
/// ```
fn build_gas_reserve_utilize<'ctx, 'this>(
context: &'ctx Context,
_registry: &ProgramRegistry<CoreType, CoreLibfunc>,
entry: &'this Block<'ctx>,
location: Location<'ctx>,
helper: &LibfuncHelper<'ctx, 'this>,
_metadata: &mut MetadataStorage,
_info: &SignatureOnlyConcreteLibfunc,
) -> Result<()> {
let current_gas = entry.arg(0)?; // u64
let gas_reserve = entry.arg(1)?; // u128

let trunc_reserve = entry.append_op_result(arith::trunci(
gas_reserve,
IntegerType::new(context, 64).into(),
location,
))?;
let updated_gas = entry.append_op_result(arith::addi(current_gas, trunc_reserve, location))?;

helper.br(entry, 0, &[updated_gas], location)
}

#[cfg(test)]
mod test {
use crate::{load_cairo, utils::testing::run_program, Value};

#[test]
fn run_create() {
let program = load_cairo!(
use core::gas::{GasReserve, gas_reserve_create, gas_reserve_utilize};

fn run_test_1() -> Option<GasReserve> {
gas_reserve_create(100)
}

fn run_test_2(amount: u128) -> u128 {
let initial_gas = core::testing::get_available_gas();
let reserve = gas_reserve_create(amount).unwrap();
let final_gas = core::testing::get_available_gas();
gas_reserve_utilize(reserve);

initial_gas - final_gas
}
);

let result = run_program(&program, "run_test_1", &[]).return_value;
if let Value::Enum { tag, value, .. } = result {
assert_eq!(tag, 0);
assert_eq!(value, Box::new(Value::Uint128(100)))
}

let amount = 100;
let result = run_program(&program, "run_test_2", &[Value::Uint128(amount)]).return_value;
if let Value::Enum { tag, value, .. } = result {
if let Value::Struct { fields, .. } = *value {
assert_eq!(tag, 0);
assert_eq!(fields[0], Value::Uint128(amount));
}
}

let amount = 700;
let result = run_program(&program, "run_test_2", &[Value::Uint128(amount)]).return_value;
if let Value::Enum { tag, value, .. } = result {
if let Value::Struct { fields, .. } = *value {
assert_eq!(tag, 0);
assert_eq!(fields[0], Value::Uint128(amount));
}
}
}

#[test]
fn run_utilize() {
let program = load_cairo!(
use core::gas::{GasReserve, gas_reserve_create, gas_reserve_utilize};

fn run_test(amount: u128) -> u128 {
let initial_gas = core::testing::get_available_gas();
let reserve = gas_reserve_create(amount).unwrap();
gas_reserve_utilize(reserve);
let final_gas = core::testing::get_available_gas();

initial_gas - final_gas
}
);

let gas_quant = 10;
let result = run_program(&program, "run_test", &[Value::Uint128(gas_quant)]).return_value;
if let Value::Enum { tag, value, .. } = result {
if let Value::Struct { fields, .. } = *value {
assert_eq!(tag, 0);
assert_eq!(fields[0], Value::Uint128(0));
}
}

let gas_quant = 1000;
let result = run_program(&program, "run_test", &[Value::Uint128(gas_quant)]).return_value;
if let Value::Enum { tag, value, .. } = result {
if let Value::Struct { fields, .. } = *value {
assert_eq!(tag, 0);
assert_eq!(fields[0], Value::Uint128(0));
}
}
}
}
23 changes: 12 additions & 11 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ mod felt252;
mod felt252_dict;
mod felt252_dict_entry;
mod gas_builtin;
mod gas_reserve;
mod int_range;
mod non_zero;
mod nullable;
Expand Down Expand Up @@ -437,9 +438,15 @@ impl TypeBuilder for CoreTypeConcrete {
metadata,
WithSelf::new(self_ty, info),
),
CoreTypeConcrete::GasReserve(info) => self::gas_reserve::build(
context,
module,
registry,
metadata,
WithSelf::new(self_ty, info),
),
Self::Blake(_) => native_panic!("Build Blake type"),
CoreTypeConcrete::QM31(_) => native_panic!("Build QM31 type"),
CoreTypeConcrete::GasReserve(_) => native_panic!("Build GasReserve type"),
}
}

Expand Down Expand Up @@ -546,9 +553,9 @@ impl TypeBuilder for CoreTypeConcrete {
CoreTypeConcrete::Circuit(info) => circuit::is_complex(info),

CoreTypeConcrete::IntRange(_info) => false,
CoreTypeConcrete::GasReserve(_info) => false,
CoreTypeConcrete::Blake(_info) => native_panic!("Implement is_complex for Blake type"),
CoreTypeConcrete::QM31(_info) => native_panic!("Implement is_complex for QM31 type"),
CoreTypeConcrete::GasReserve(_info) => native_panic!("Implement is_complex for GasReserve type"),
})
}

Expand Down Expand Up @@ -622,6 +629,7 @@ impl TypeBuilder for CoreTypeConcrete {
}

CoreTypeConcrete::BoundedInt(_) => false,
CoreTypeConcrete::GasReserve(_info) => false,
CoreTypeConcrete::Const(info) => {
let type_info = registry.get_type(&info.inner_ty)?;
type_info.is_zst(registry)?
Expand All @@ -635,9 +643,6 @@ impl TypeBuilder for CoreTypeConcrete {
}
CoreTypeConcrete::Blake(_info) => native_panic!("Implement is_zst for Blake type"),
CoreTypeConcrete::QM31(_info) => native_panic!("Implement is_zst for QM31 type"),
CoreTypeConcrete::GasReserve(_info) => {
native_panic!("Implement is_zst for GasReserve type")
}
})
}

Expand Down Expand Up @@ -736,6 +741,7 @@ impl TypeBuilder for CoreTypeConcrete {
CoreTypeConcrete::Sint128(_) => get_integer_layout(128),
CoreTypeConcrete::Bytes31(_) => get_integer_layout(248),
CoreTypeConcrete::BoundedInt(info) => get_integer_layout(info.range.offset_bit_width()),
CoreTypeConcrete::GasReserve(_info) => get_integer_layout(128),

CoreTypeConcrete::Const(const_type) => {
registry.get_type(&const_type.inner_ty)?.layout(registry)?
Expand All @@ -750,9 +756,6 @@ impl TypeBuilder for CoreTypeConcrete {
}
CoreTypeConcrete::Blake(_info) => native_panic!("Implement layout for Blake type"),
CoreTypeConcrete::QM31(_info) => native_panic!("Implement layout for QM31 type"),
CoreTypeConcrete::GasReserve(_info) => {
native_panic!("Implement layout for GasReserve type")
}
}
.pad_to_align())
}
Expand Down Expand Up @@ -843,10 +846,8 @@ impl TypeBuilder for CoreTypeConcrete {
.is_memory_allocated(registry)?,
CoreTypeConcrete::Coupon(_) => false,
CoreTypeConcrete::Circuit(_) => false,
CoreTypeConcrete::GasReserve(_) => false,
CoreTypeConcrete::QM31(_) => native_panic!("Implement is_memory_allocated for QM31"),
CoreTypeConcrete::GasReserve(_) => {
native_panic!("Implement is_memory_allocated for GasReserve")
}
})
}

Expand Down
Loading
Loading