Skip to content

Commit f6f14cc

Browse files
feat(blockifier): add fn encode_felt252_data_and_calc_blake_hash_cost
1 parent a91a3e8 commit f6f14cc

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

crates/blockifier/src/bouncer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ fn n_steps_to_sierra_gas(n_steps: usize, versioned_constants: &VersionedConstant
373373
GasAmount(n_steps_gas_cost)
374374
}
375375

376-
fn vm_resources_to_sierra_gas(
376+
pub(crate) fn vm_resources_to_sierra_gas(
377377
resources: ExecutionResources,
378378
versioned_constants: &VersionedConstants,
379379
) -> GasAmount {

crates/blockifier/src/execution/execution_utils.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ use cairo_vm::vm::vm_core::VirtualMachine;
1818
use num_bigint::BigUint;
1919
use starknet_api::core::ClassHash;
2020
use starknet_api::deprecated_contract_class::Program as DeprecatedProgram;
21+
use starknet_api::execution_resources::GasAmount;
2122
use starknet_api::transaction::fields::Calldata;
2223
use starknet_types_core::felt::Felt;
2324

25+
use crate::blockifier_versioned_constants::VersionedConstants;
26+
use crate::bouncer::vm_resources_to_sierra_gas;
2427
use crate::execution::call_info::{CallExecution, CallInfo, Retdata};
2528
use crate::execution::contract_class::{RunnableCompiledClass, TrackedResource};
2629
use crate::execution::entry_point::{
@@ -44,6 +47,7 @@ use crate::execution::syscalls::hint_processor::{ENTRYPOINT_NOT_FOUND_ERROR, OUT
4447
use crate::execution::{deprecated_entry_point_execution, entry_point_execution};
4548
use crate::state::errors::StateError;
4649
use crate::state::state_api::State;
50+
use crate::utils::{safe_add_gas_panic_on_overflow, u64_from_usize};
4751

4852
pub type Args = Vec<CairoArg>;
4953

@@ -363,3 +367,68 @@ pub fn poseidon_hash_many_cost(data_length: usize) -> ExecutionResources {
363367
builtin_instance_counter: HashMap::from([(BuiltinName::poseidon, data_length / 2 + 1)]),
364368
}
365369
}
370+
371+
mod blake_cost {
372+
// U-32 counts
373+
pub const N_U32S_MESSAGE: usize = 16;
374+
pub const N_U32S_BIG_FELT: usize = 8;
375+
pub const N_U32S_SMALL_FELT: usize = 2;
376+
377+
// Steps counts
378+
pub const STEPS_BIG_FELT: usize = 45;
379+
pub const STEPS_SMALL_FELT: usize = 15;
380+
381+
// One-time segment setup cost (full vs partial)
382+
pub const BASE_STEPS_FULL_MSG: usize = 217;
383+
pub const BASE_STEPS_PARTIAL_MSG: usize = 195;
384+
pub const STEPS_PER_2_U32_REMINDER: usize = 3;
385+
386+
// TODO(AvivG): This is a placeholder, add the actual gas cost for the BLAKE opcode
387+
pub const BLAKE_OPCODE_GAS: usize = 0;
388+
}
389+
390+
fn compute_blake_hash_steps(n_big_felts: usize, n_small_felts: usize) -> usize {
391+
let total_u32s =
392+
n_big_felts * blake_cost::N_U32S_BIG_FELT + n_small_felts * blake_cost::N_U32S_SMALL_FELT;
393+
let rem_u32s = total_u32s % blake_cost::N_U32S_MESSAGE;
394+
let base = if rem_u32s == 0 {
395+
blake_cost::BASE_STEPS_FULL_MSG
396+
} else {
397+
blake_cost::BASE_STEPS_PARTIAL_MSG + blake_cost::STEPS_PER_2_U32_REMINDER * (rem_u32s / 2)
398+
};
399+
400+
n_big_felts * blake_cost::STEPS_BIG_FELT + n_small_felts * blake_cost::STEPS_SMALL_FELT + base
401+
}
402+
403+
fn count_blake_opcode(n_big_felts: usize, n_small_felts: usize) -> usize {
404+
// The BLAKE opcode is used once per 16 u32s.
405+
let total_u32s =
406+
n_big_felts * blake_cost::N_U32S_BIG_FELT + n_small_felts * blake_cost::N_U32S_SMALL_FELT;
407+
408+
let mut n_msgs = total_u32s / blake_cost::N_U32S_MESSAGE;
409+
n_msgs += if total_u32s % blake_cost::N_U32S_MESSAGE > 0 { 1 } else { 0 };
410+
411+
n_msgs
412+
}
413+
414+
/// Estimates the VM resources for `encode_felt252_data_and_calc_blake_hash` in the Starknet OS.
415+
/// Accounts for small felts unpack to 2-u32s and big felts to 8-u32s.
416+
pub fn cost_of_encode_felt252_data_and_calc_blake_hash(
417+
n_big_felts: usize,
418+
n_small_felts: usize,
419+
versioned_constants: &VersionedConstants,
420+
) -> GasAmount {
421+
let n_steps = compute_blake_hash_steps(n_big_felts, n_small_felts);
422+
let n_felts = n_big_felts + n_small_felts;
423+
// The OS uses one `range_check` per input felt to validate each element’s size constraints.
424+
let builtins = HashMap::from([(BuiltinName::range_check, n_felts)]);
425+
let resources =
426+
ExecutionResources { n_steps, n_memory_holes: 0, builtin_instance_counter: builtins };
427+
let blake_opcode_gas =
428+
count_blake_opcode(n_big_felts, n_small_felts) * blake_cost::BLAKE_OPCODE_GAS;
429+
430+
safe_add_gas_panic_on_overflow(
431+
vm_resources_to_sierra_gas(resources, versioned_constants),
432+
GasAmount(u64_from_usize(blake_opcode_gas)),
433+
)
434+
}

crates/blockifier/src/utils.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::collections::HashMap;
22

33
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
4+
use starknet_api::execution_resources::GasAmount;
45

56
use crate::blockifier_versioned_constants::{BaseGasCosts, BuiltinGasCosts};
67
use crate::transaction::errors::NumericConversionError;
@@ -86,3 +87,13 @@ pub fn get_gas_cost_from_vm_resources(
8687
+ n_memory_holes * base_costs.memory_hole_gas_cost
8788
+ total_builtin_gas_cost
8889
}
90+
91+
pub fn safe_add_gas_panic_on_overflow(gas: GasAmount, added_gas: GasAmount) -> GasAmount {
92+
gas.checked_add(added_gas).unwrap_or_else(|| {
93+
panic!(
94+
"Addition overflow while adding sierra gas. current gas: {}, try to add
95+
gas: {}.",
96+
gas, added_gas
97+
)
98+
})
99+
}

0 commit comments

Comments
 (0)