Skip to content

Commit eb55e23

Browse files
committed
Add gas_reserve_create libfunc.
commit-id:464dc795
1 parent 484bf38 commit eb55e23

File tree

13 files changed

+271
-0
lines changed

13 files changed

+271
-0
lines changed

corelib/src/gas.cairo

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,15 @@ pub extern fn get_builtin_costs() -> BuiltinCosts nopanic;
7777
pub fn get_builtin_costs() -> BuiltinCosts nopanic {
7878
BuiltinCosts {}
7979
}
80+
81+
/// Represents a gas reserve.
82+
///
83+
/// Gas reserves can be created at any point using gas from the gas counter,
84+
/// and can be utilized at a later point in time.
85+
pub extern type GasReserve;
86+
87+
/// Creates a new gas reserve by withdrawing the specified amount from the gas counter.
88+
/// Returns `Some(GasReserve)` if there is sufficient gas, otherwise returns `None`.
89+
pub extern fn gas_reserve_create(
90+
amount: u128,
91+
) -> Option<GasReserve> implicits(RangeCheck, GasBuiltin) nopanic;

crates/cairo-lang-sierra-ap-change/src/core_libfunc_ap_change.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use cairo_lang_sierra::extensions::felt252_dict::{
2323
Felt252DictConcreteLibfunc, Felt252DictEntryConcreteLibfunc,
2424
};
2525
use cairo_lang_sierra::extensions::gas::{BuiltinCostsType, CostTokenType, GasConcreteLibfunc};
26+
use cairo_lang_sierra::extensions::gas_reserve::GasReserveConcreteLibfunc;
2627
use cairo_lang_sierra::extensions::int::signed::{SintConcrete, SintTraits};
2728
use cairo_lang_sierra::extensions::int::signed128::Sint128Concrete;
2829
use cairo_lang_sierra::extensions::int::unsigned::{UintConcrete, UintTraits};
@@ -217,6 +218,11 @@ pub fn core_libfunc_ap_change<InfoProvider: InvocationApChangeInfoProvider>(
217218
}
218219
GasConcreteLibfunc::GetBuiltinCosts(_) => vec![ApChange::Known(3)],
219220
},
221+
GasReserve(libfunc) => match libfunc {
222+
GasReserveConcreteLibfunc::Create(_) => {
223+
vec![ApChange::Known(2), ApChange::Known(3)]
224+
}
225+
},
220226
Uint8(libfunc) => uint_ap_change(libfunc),
221227
Uint16(libfunc) => uint_ap_change(libfunc),
222228
Uint32(libfunc) => uint_ap_change(libfunc),

crates/cairo-lang-sierra-gas/src/core_libfunc_cost_base.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use cairo_lang_sierra::extensions::gas::GasConcreteLibfunc::{
2828
BuiltinWithdrawGas, GetAvailableGas, GetBuiltinCosts, GetUnspentGas, RedepositGas, WithdrawGas,
2929
};
3030
use cairo_lang_sierra::extensions::gas::{BuiltinCostsType, CostTokenType};
31+
use cairo_lang_sierra::extensions::gas_reserve::GasReserveConcreteLibfunc;
3132
use cairo_lang_sierra::extensions::int::signed::{SintConcrete, SintTraits};
3233
use cairo_lang_sierra::extensions::int::signed128::Sint128Concrete;
3334
use cairo_lang_sierra::extensions::int::unsigned::{UintConcrete, UintTraits};
@@ -266,6 +267,12 @@ pub fn core_libfunc_cost(
266267
}
267268
GetBuiltinCosts(_) => vec![ConstCost::steps(3).into()],
268269
},
270+
GasReserve(libfunc) => match libfunc {
271+
GasReserveConcreteLibfunc::Create(_) => vec![
272+
(ConstCost::steps(3) + ConstCost::range_checks(1)).into(),
273+
(ConstCost::steps(5) + ConstCost::range_checks(1)).into(),
274+
],
275+
},
269276
BranchAlign(_) => vec![BranchCost::BranchAlign],
270277
Array(libfunc) => match libfunc {
271278
ArrayConcreteLibfunc::New(_) => vec![ConstCost::steps(1).into()],
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use cairo_lang_casm::builder::CasmBuilder;
2+
use cairo_lang_casm::casm_build_extend;
3+
use cairo_lang_sierra::extensions::gas::CostTokenType;
4+
use cairo_lang_sierra::extensions::gas_reserve::GasReserveConcreteLibfunc;
5+
use num_bigint::BigInt;
6+
7+
use super::{CompiledInvocation, CompiledInvocationBuilder, InvocationError};
8+
use crate::invocations::{
9+
BuiltinInfo, CostValidationInfo, add_input_variables, get_non_fallthrough_statement_id,
10+
};
11+
12+
/// Builds instructions for Sierra `GasReserve` operations.
13+
pub fn build(
14+
libfunc: &GasReserveConcreteLibfunc,
15+
builder: CompiledInvocationBuilder<'_>,
16+
) -> Result<CompiledInvocation, InvocationError> {
17+
match libfunc {
18+
GasReserveConcreteLibfunc::Create(_) => build_gas_reserve_create(builder),
19+
}
20+
}
21+
22+
/// Handles the gas_reserve_create invocation.
23+
fn build_gas_reserve_create(
24+
builder: CompiledInvocationBuilder<'_>,
25+
) -> Result<CompiledInvocation, InvocationError> {
26+
let [range_check, gas_counter, amount] = builder.try_get_single_cells()?;
27+
let mut casm_builder = CasmBuilder::default();
28+
add_input_variables! {casm_builder,
29+
buffer(1) range_check;
30+
deref gas_counter;
31+
deref amount;
32+
};
33+
34+
casm_build_extend! {casm_builder,
35+
let orig_range_check = range_check;
36+
tempvar has_enough_gas;
37+
tempvar gas_minus_amount = gas_counter - amount;
38+
hint TestLessThanOrEqual {lhs: amount, rhs: gas_counter} into {dst: has_enough_gas};
39+
jump HasEnoughGas if has_enough_gas != 0;
40+
41+
// Failure. Prove that gas_minus_amount < 0.
42+
const u128_bound = (BigInt::from(u128::MAX) + 1) as BigInt;
43+
tempvar tmp = gas_minus_amount + u128_bound;
44+
assert tmp = *(range_check++);
45+
jump Failure;
46+
47+
HasEnoughGas:
48+
assert gas_minus_amount = *(range_check++);
49+
};
50+
51+
let failure_handle_statement_id = get_non_fallthrough_statement_id(&builder);
52+
Ok(builder.build_from_casm_builder(
53+
casm_builder,
54+
[
55+
("Fallthrough", &[&[range_check], &[gas_minus_amount], &[amount]], None),
56+
("Failure", &[&[range_check], &[gas_counter]], Some(failure_handle_statement_id)),
57+
],
58+
CostValidationInfo {
59+
builtin_infos: vec![BuiltinInfo {
60+
cost_token_ty: CostTokenType::RangeCheck,
61+
start: orig_range_check,
62+
end: range_check,
63+
}],
64+
extra_costs: None,
65+
},
66+
))
67+
}

crates/cairo-lang-sierra-to-casm/src/invocations/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ mod felt252;
5050
mod felt252_dict;
5151
mod function_call;
5252
mod gas;
53+
mod gas_reserve;
5354
mod int;
5455
mod mem;
5556
mod misc;
@@ -689,6 +690,7 @@ pub fn compile_invocation(
689690
}
690691
Sint128(libfunc) => int::signed128::build(libfunc, builder),
691692
Gas(libfunc) => gas::build(libfunc, builder),
693+
GasReserve(libfunc) => gas_reserve::build(libfunc, builder),
692694
BranchAlign(_) => misc::build_branch_align(builder),
693695
Array(libfunc) => array::build(libfunc, builder),
694696
Drop(_) => misc::build_drop(builder),

crates/cairo-lang-sierra-type-size/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ pub fn get_type_size_map(
1616
let mut type_sizes = TypeSizeMap::default();
1717
for declaration in &program.type_declarations {
1818
let size = match registry.get_type(&declaration.id).ok()? {
19+
// Size 0.
1920
CoreTypeConcrete::Coupon(_) => Some(0),
21+
// Size 1.
2022
CoreTypeConcrete::Felt252(_)
2123
| CoreTypeConcrete::GasBuiltin(_)
24+
| CoreTypeConcrete::GasReserve(_)
2225
| CoreTypeConcrete::Bitwise(_)
2326
| CoreTypeConcrete::BuiltinCosts(_)
2427
| CoreTypeConcrete::EcOp(_)
@@ -51,11 +54,13 @@ pub fn get_type_size_map(
5154
| CoreTypeConcrete::Bytes31(_)
5255
| CoreTypeConcrete::BoundedInt(_)
5356
| CoreTypeConcrete::QM31(_) => Some(1),
57+
// Size 2.
5458
CoreTypeConcrete::Array(_)
5559
| CoreTypeConcrete::Span(_)
5660
| CoreTypeConcrete::EcPoint(_)
5761
| CoreTypeConcrete::SquashedFelt252Dict(_)
5862
| CoreTypeConcrete::IntRange(_) => Some(2),
63+
// Other.
5964
CoreTypeConcrete::NonZero(wrapped_ty)
6065
| CoreTypeConcrete::Snapshot(wrapped_ty)
6166
| CoreTypeConcrete::Uninitialized(wrapped_ty) => {

crates/cairo-lang-sierra/src/extensions/core.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use super::modules::boxing::{BoxLibfunc, BoxType};
3636
use super::modules::felt252::{Felt252Libfunc, Felt252Type};
3737
use super::modules::function_call::FunctionCallLibfunc;
3838
use super::modules::gas::{GasBuiltinType, GasLibfunc};
39+
use super::modules::gas_reserve::{GasReserveLibfunc, GasReserveType};
3940
use super::modules::mem::MemLibfunc;
4041
use super::modules::non_zero::{NonZeroType, UnwrapNonZeroLibfunc};
4142
use super::modules::unconditional_jump::UnconditionalJumpLibfunc;
@@ -70,6 +71,7 @@ define_type_hierarchy! {
7071
EcState(EcStateType),
7172
Felt252(Felt252Type),
7273
GasBuiltin(GasBuiltinType),
74+
GasReserve(GasReserveType),
7375
IntRange(IntRangeType),
7476
BuiltinCosts(BuiltinCostsType),
7577
Uint8(Uint8Type),
@@ -125,6 +127,7 @@ define_libfunc_hierarchy! {
125127
Const(ConstLibfunc),
126128
FunctionCall(FunctionCallLibfunc),
127129
Gas(GasLibfunc),
130+
GasReserve(GasReserveLibfunc),
128131
IntRange(IntRangeLibfunc),
129132
Uint8(Uint8Libfunc),
130133
Uint16(Uint16Libfunc),
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use crate::define_libfunc_hierarchy;
2+
use crate::extensions::lib_func::{
3+
BranchSignature, LibfuncSignature, OutputVarInfo, ParamSignature, SierraApChange,
4+
SignatureSpecializationContext,
5+
};
6+
use crate::extensions::modules::gas::GasBuiltinType;
7+
use crate::extensions::modules::int::unsigned128::Uint128Type;
8+
use crate::extensions::modules::range_check::RangeCheckType;
9+
use crate::extensions::{
10+
NamedType, NoGenericArgsGenericLibfunc, NoGenericArgsGenericType, OutputVarReferenceInfo,
11+
SpecializationError,
12+
};
13+
use crate::ids::GenericTypeId;
14+
15+
/// Represents a gas reserve.
16+
///
17+
/// Gas reserves can be created at any point using gas from the gas counter,
18+
/// and can be utilized at a later point in time.
19+
#[derive(Default)]
20+
pub struct GasReserveType {}
21+
impl NoGenericArgsGenericType for GasReserveType {
22+
const ID: GenericTypeId = GenericTypeId::new_inline("GasReserve");
23+
const STORABLE: bool = true;
24+
const DUPLICATABLE: bool = false;
25+
const DROPPABLE: bool = true;
26+
const ZERO_SIZED: bool = false;
27+
}
28+
29+
define_libfunc_hierarchy! {
30+
pub enum GasReserveLibfunc {
31+
Create(GasReserveCreateLibfunc),
32+
}, GasReserveConcreteLibfunc
33+
}
34+
35+
/// Libfunc for creating a gas reserve.
36+
#[derive(Default)]
37+
pub struct GasReserveCreateLibfunc {}
38+
impl NoGenericArgsGenericLibfunc for GasReserveCreateLibfunc {
39+
const STR_ID: &'static str = "gas_reserve_create";
40+
41+
fn specialize_signature(
42+
&self,
43+
context: &dyn SignatureSpecializationContext,
44+
) -> Result<LibfuncSignature, SpecializationError> {
45+
let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
46+
let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
47+
let u128_type = context.get_concrete_type(Uint128Type::id(), &[])?;
48+
let gas_reserve_type = context.get_concrete_type(GasReserveType::id(), &[])?;
49+
50+
let rc_output_info = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
51+
Ok(LibfuncSignature {
52+
param_signatures: vec![
53+
ParamSignature::new(range_check_type).with_allow_add_const(),
54+
ParamSignature::new(gas_builtin_type.clone()),
55+
ParamSignature::new(u128_type),
56+
],
57+
branch_signatures: vec![
58+
// Success.
59+
BranchSignature {
60+
vars: vec![
61+
rc_output_info.clone(),
62+
OutputVarInfo {
63+
ty: gas_builtin_type.clone(),
64+
ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
65+
},
66+
OutputVarInfo {
67+
ty: gas_reserve_type.clone(),
68+
ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 2 },
69+
},
70+
],
71+
ap_change: SierraApChange::Known { new_vars_only: false },
72+
},
73+
// Failure.
74+
BranchSignature {
75+
vars: vec![
76+
rc_output_info,
77+
OutputVarInfo {
78+
ty: gas_builtin_type,
79+
ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 1 },
80+
},
81+
],
82+
ap_change: SierraApChange::Known { new_vars_only: false },
83+
},
84+
],
85+
fallthrough: Some(0),
86+
})
87+
}
88+
}

crates/cairo-lang-sierra/src/extensions/modules/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub mod felt252;
2929
pub mod felt252_dict;
3030
pub mod function_call;
3131
pub mod gas;
32+
pub mod gas_reserve;
3233
pub mod int;
3334
pub mod is_zero;
3435
pub mod mem;

crates/cairo-lang-sierra/src/simulation/core.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ pub fn simulate<
303303
CoreConcreteLibfunc::QM31(_) => unimplemented!(),
304304
CoreConcreteLibfunc::UnsafePanic(_) => unimplemented!(),
305305
CoreConcreteLibfunc::DummyFunctionCall(_) => unimplemented!(),
306+
CoreConcreteLibfunc::GasReserve(_) => unimplemented!(),
306307
})
307308
}
308309

crates/cairo-lang-starknet-classes/src/allowed_libfuncs_lists/all.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
"felt252_sub_const",
8787
"finalize_locals",
8888
"function_call",
89+
"gas_reserve_create",
8990
"get_block_hash_syscall",
9091
"get_builtin_costs",
9192
"get_circuit_descriptor",

tests/e2e_test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ cairo_lang_test_utils::test_file_test_with_runner!(
7272
felt252_downcast: "felt252_downcast",
7373
felt252: "felt252",
7474
fixed_size_array: "fixed_size_array",
75+
gas_reserve: "gas_reserve",
7576
i128: "i128",
7677
i16: "i16",
7778
i32: "i32",
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//! > gas_reserve_create libfunc
2+
3+
//! > test_runner_name
4+
SmallE2ETestRunner
5+
6+
//! > cairo_code
7+
fn foo() -> Option<gas::GasReserve> nopanic {
8+
gas::gas_reserve_create(100)
9+
}
10+
11+
//! > casm
12+
[ap + 0] = 100, ap++;
13+
[fp + -3] = [ap + 1] + [ap + -1], ap++;
14+
%{ memory[ap + -1] = memory[ap + -2] <= memory[fp + -3] %}
15+
jmp rel 7 if [ap + -1] != 0, ap++;
16+
[ap + 0] = [ap + -1] + 340282366920938463463374607431768211456, ap++;
17+
[ap + -1] = [[fp + -4] + 0];
18+
jmp rel 13;
19+
[ap + -1] = [[fp + -4] + 0];
20+
ap += 1;
21+
[ap + 0] = [fp + -4] + 1, ap++;
22+
[ap + 0] = [ap + -3] + 90, ap++;
23+
[ap + 0] = 0, ap++;
24+
[ap + 0] = [ap + -7], ap++;
25+
ret;
26+
[ap + 0] = [fp + -4] + 1, ap++;
27+
[ap + 0] = [fp + -3], ap++;
28+
[ap + 0] = 1, ap++;
29+
[ap + 0] = 0, ap++;
30+
ret;
31+
32+
//! > function_costs
33+
test::foo: OrderedHashMap({Const: 1070})
34+
35+
//! > sierra_code
36+
type u128 = u128 [storable: true, drop: true, dup: true, zero_sized: false];
37+
type Unit = Struct<ut@Tuple> [storable: true, drop: true, dup: true, zero_sized: true];
38+
type GasReserve = GasReserve [storable: true, drop: true, dup: false, zero_sized: false];
39+
type core::option::Option::<core::gas::GasReserve> = Enum<ut@core::option::Option::<core::gas::GasReserve>, GasReserve, Unit> [storable: true, drop: true, dup: false, zero_sized: false];
40+
type GasBuiltin = GasBuiltin [storable: true, drop: false, dup: false, zero_sized: false];
41+
type RangeCheck = RangeCheck [storable: true, drop: false, dup: false, zero_sized: false];
42+
type Const<u128, 100> = Const<u128, 100> [storable: false, drop: false, dup: false, zero_sized: false];
43+
44+
libfunc const_as_immediate<Const<u128, 100>> = const_as_immediate<Const<u128, 100>>;
45+
libfunc store_temp<u128> = store_temp<u128>;
46+
libfunc gas_reserve_create = gas_reserve_create;
47+
libfunc branch_align = branch_align;
48+
libfunc redeposit_gas = redeposit_gas;
49+
libfunc enum_init<core::option::Option::<core::gas::GasReserve>, 0> = enum_init<core::option::Option::<core::gas::GasReserve>, 0>;
50+
libfunc store_temp<RangeCheck> = store_temp<RangeCheck>;
51+
libfunc store_temp<GasBuiltin> = store_temp<GasBuiltin>;
52+
libfunc store_temp<core::option::Option::<core::gas::GasReserve>> = store_temp<core::option::Option::<core::gas::GasReserve>>;
53+
libfunc struct_construct<Unit> = struct_construct<Unit>;
54+
libfunc enum_init<core::option::Option::<core::gas::GasReserve>, 1> = enum_init<core::option::Option::<core::gas::GasReserve>, 1>;
55+
56+
F0:
57+
const_as_immediate<Const<u128, 100>>() -> ([2]);
58+
store_temp<u128>([2]) -> ([2]);
59+
gas_reserve_create([0], [1], [2]) { fallthrough([3], [4], [5]) F0_B0([6], [7]) };
60+
branch_align() -> ();
61+
redeposit_gas([4]) -> ([8]);
62+
enum_init<core::option::Option::<core::gas::GasReserve>, 0>([5]) -> ([9]);
63+
store_temp<RangeCheck>([3]) -> ([3]);
64+
store_temp<GasBuiltin>([8]) -> ([8]);
65+
store_temp<core::option::Option::<core::gas::GasReserve>>([9]) -> ([9]);
66+
return([3], [8], [9]);
67+
F0_B0:
68+
branch_align() -> ();
69+
redeposit_gas([7]) -> ([10]);
70+
struct_construct<Unit>() -> ([11]);
71+
enum_init<core::option::Option::<core::gas::GasReserve>, 1>([11]) -> ([12]);
72+
store_temp<RangeCheck>([6]) -> ([6]);
73+
store_temp<GasBuiltin>([10]) -> ([10]);
74+
store_temp<core::option::Option::<core::gas::GasReserve>>([12]) -> ([12]);
75+
return([6], [10], [12]);
76+
77+
test::foo@F0([0]: RangeCheck, [1]: GasBuiltin) -> (RangeCheck, GasBuiltin, core::option::Option::<core::gas::GasReserve>);

0 commit comments

Comments
 (0)