Skip to content

Commit b049eba

Browse files
feat(blockifier): add estimate_casm_blake_hash_computation_resources
1 parent 99054ea commit b049eba

File tree

2 files changed

+77
-8
lines changed

2 files changed

+77
-8
lines changed

crates/blockifier/src/execution/contract_class.rs

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,19 @@ use starknet_api::deprecated_contract_class::{
3131
use starknet_types_core::felt::Felt;
3232

3333
use crate::abi::constants::{self};
34+
use crate::blockifier_versioned_constants::VersionedConstants;
35+
use crate::bouncer::vm_resources_to_sierra_gas;
3436
use crate::execution::entry_point::{EntryPointExecutionContext, EntryPointTypeAndSelector};
3537
use crate::execution::errors::PreExecutionError;
36-
use crate::execution::execution_utils::{poseidon_hash_many_cost, sn_api_to_cairo_vm_program};
38+
use crate::execution::execution_utils::{
39+
cost_of_encode_felt252_data_and_calc_blake_hash,
40+
poseidon_hash_many_cost,
41+
sn_api_to_cairo_vm_program,
42+
};
3743
#[cfg(feature = "cairo_native")]
3844
use crate::execution::native::contract_class::NativeCompiledClassV1;
3945
use crate::transaction::errors::TransactionExecutionError;
46+
use crate::utils::safe_add_gas_panic_on_overflow;
4047

4148
#[cfg(test)]
4249
#[path = "contract_class_test.rs"]
@@ -272,7 +279,7 @@ impl CompiledClassV1 {
272279
/// This is an empiric measurement of several bytecode lengths, which constitutes as the
273280
/// dominant factor in it.
274281
fn estimate_casm_hash_computation_resources(&self) -> ExecutionResources {
275-
estimate_casm_hash_computation_resources(&self.bytecode_segment_lengths)
282+
estimate_casm_poseidon_hash_computation_resources(&self.bytecode_segment_lengths)
276283
}
277284

278285
// Returns the set of segments that were visited according to the given visited PCs.
@@ -300,7 +307,7 @@ impl CompiledClassV1 {
300307
///
301308
/// Note: the function focuses on the bytecode size, and currently ignores the cost handling the
302309
/// class entry points.
303-
pub fn estimate_casm_hash_computation_resources(
310+
pub fn estimate_casm_poseidon_hash_computation_resources(
304311
bytecode_segment_lengths: &NestedIntList,
305312
) -> ExecutionResources {
306313
// The constants in this function were computed by running the Casm code on a few values
@@ -340,6 +347,68 @@ pub fn estimate_casm_hash_computation_resources(
340347
}
341348
}
342349

350+
/// Cost to hash a single flat segment of `len` felts.
351+
fn leaf_cost(len: usize, versioned_constants: &VersionedConstants) -> GasAmount {
352+
// All `len` inputs treated as “big” felts; no small-felt optimization here.
353+
cost_of_encode_felt252_data_and_calc_blake_hash(len, 0, versioned_constants)
354+
}
355+
356+
/// Cost to hash a multi-segment contract:
357+
fn node_cost(segs: &[NestedIntList], versioned_constants: &VersionedConstants) -> GasAmount {
358+
// TODO(AvivG): Add base estimation for node.
359+
let mut gas = GasAmount::ZERO;
360+
361+
// TODO(AvivG): Add base estimation of each segment. Could this be part of 'leaf_cost'?
362+
let segment_overhead = GasAmount::ZERO;
363+
364+
// 2) For each segment, hash its felts.
365+
for seg in segs {
366+
match seg {
367+
NestedIntList::Leaf(len) => {
368+
gas = safe_add_gas_panic_on_overflow(gas, segment_overhead);
369+
gas = safe_add_gas_panic_on_overflow(gas, leaf_cost(*len, versioned_constants));
370+
}
371+
_ => panic!("Estimating hash cost only supports at most one level of segmentation."),
372+
}
373+
}
374+
// Node‐level hash over (hash1, len1, hash2, len2, …): one segment hash (“big” felt))
375+
// and one segment length (“small” felt) per segment.
376+
let node_hash_cost = cost_of_encode_felt252_data_and_calc_blake_hash(
377+
segs.len(),
378+
segs.len(),
379+
versioned_constants,
380+
);
381+
382+
safe_add_gas_panic_on_overflow(gas, node_hash_cost)
383+
}
384+
385+
/// Estimates the VM resources to compute the CASM Blake hash for a Cairo-1 contract:
386+
/// - Uses only bytecode size (treats all felts as “big”, ignores the small-felt optimization).
387+
pub fn estimate_casm_blake_hash_computation_resources(
388+
bytecode_segment_lengths: &NestedIntList,
389+
versioned_constants: &VersionedConstants,
390+
) -> GasAmount {
391+
// TODO(AvivG): Currently ignores entry-point costs.
392+
// Basic frame overhead
393+
let resources = ExecutionResources {
394+
n_steps: 0,
395+
n_memory_holes: 0,
396+
builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 3)]),
397+
};
398+
let gas = vm_resources_to_sierra_gas(resources, versioned_constants);
399+
400+
// Add leaf vs node cost
401+
match bytecode_segment_lengths {
402+
// Single-segment contract (e.g., older Sierra contracts).
403+
NestedIntList::Leaf(len) => {
404+
safe_add_gas_panic_on_overflow(gas, leaf_cost(*len, versioned_constants))
405+
}
406+
NestedIntList::Node(segs) => {
407+
safe_add_gas_panic_on_overflow(gas, node_cost(segs, versioned_constants))
408+
}
409+
}
410+
}
411+
343412
// Returns the set of segments that were visited according to the given visited PCs and segment
344413
// lengths.
345414
// Each visited segment must have its starting PC visited, and is represented by it.

crates/native_blockifier/src/py_testing_wrappers.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use blockifier::execution::contract_class::estimate_casm_hash_computation_resources;
1+
use blockifier::execution::contract_class::estimate_casm_poseidon_hash_computation_resources;
22
use blockifier::transaction::errors::{TransactionExecutionError, TransactionFeeError};
33
use cairo_lang_starknet_classes::NestedIntList;
44
use pyo3::{pyfunction, PyResult};
@@ -15,17 +15,17 @@ pub fn raise_error_for_testing() -> NativeBlockifierResult<()> {
1515
.into())
1616
}
1717

18-
/// Wrapper for [estimate_casm_hash_computation_resources] that can be used for testing.
18+
/// Wrapper for [estimate_casm_poseidon_hash_computation_resources] that can be used for testing.
1919
/// Takes a leaf.
2020
#[pyfunction]
2121
pub fn estimate_casm_hash_computation_resources_for_testing_single(
2222
bytecode_segment_lengths: usize,
2323
) -> PyResult<PyExecutionResources> {
2424
let node = NestedIntList::Leaf(bytecode_segment_lengths);
25-
Ok(estimate_casm_hash_computation_resources(&node).into())
25+
Ok(estimate_casm_poseidon_hash_computation_resources(&node).into())
2626
}
2727

28-
/// Wrapper for [estimate_casm_hash_computation_resources] that can be used for testing.
28+
/// Wrapper for [estimate_casm_poseidon_hash_computation_resources] that can be used for testing.
2929
/// Takes a node of leaves.
3030
#[pyfunction]
3131
pub fn estimate_casm_hash_computation_resources_for_testing_list(
@@ -34,5 +34,5 @@ pub fn estimate_casm_hash_computation_resources_for_testing_list(
3434
let node = NestedIntList::Node(
3535
bytecode_segment_lengths.into_iter().map(NestedIntList::Leaf).collect(),
3636
);
37-
Ok(estimate_casm_hash_computation_resources(&node).into())
37+
Ok(estimate_casm_poseidon_hash_computation_resources(&node).into())
3838
}

0 commit comments

Comments
 (0)