Skip to content

Commit 1baec85

Browse files
blockifier: add estimate_casm_blake_hash_computation_resources (#7212)
1 parent 4a832a9 commit 1baec85

File tree

2 files changed

+86
-8
lines changed

2 files changed

+86
-8
lines changed

crates/blockifier/src/execution/contract_class.rs

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ use starknet_types_core::felt::Felt;
3434
use crate::abi::constants::{self};
3535
use crate::execution::entry_point::{EntryPointExecutionContext, EntryPointTypeAndSelector};
3636
use crate::execution::errors::PreExecutionError;
37-
use crate::execution::execution_utils::{poseidon_hash_many_cost, sn_api_to_cairo_vm_program};
37+
use crate::execution::execution_utils::{
38+
cost_of_encode_felt252_data_and_calc_blake_hash,
39+
poseidon_hash_many_cost,
40+
sn_api_to_cairo_vm_program,
41+
};
3842
#[cfg(feature = "cairo_native")]
3943
use crate::execution::native::contract_class::NativeCompiledClassV1;
4044
use crate::transaction::errors::TransactionExecutionError;
@@ -287,7 +291,7 @@ impl CompiledClassV1 {
287291
/// This is an empiric measurement of several bytecode lengths, which constitutes as the
288292
/// dominant factor in it.
289293
fn estimate_casm_hash_computation_resources(&self) -> ExecutionResources {
290-
estimate_casm_hash_computation_resources(&self.bytecode_segment_lengths)
294+
estimate_casm_poseidon_hash_computation_resources(&self.bytecode_segment_lengths)
291295
}
292296

293297
/// Estimate the VM gas required to perform a CompiledClassHash migration,
@@ -321,7 +325,7 @@ impl CompiledClassV1 {
321325
///
322326
/// Note: the function focuses on the bytecode size, and currently ignores the cost handling the
323327
/// class entry points.
324-
pub fn estimate_casm_hash_computation_resources(
328+
pub fn estimate_casm_poseidon_hash_computation_resources(
325329
bytecode_segment_lengths: &NestedIntList,
326330
) -> ExecutionResources {
327331
// The constants in this function were computed by running the Casm code on a few values
@@ -361,6 +365,80 @@ pub fn estimate_casm_hash_computation_resources(
361365
}
362366
}
363367

368+
/// Cost to hash a single flat segment of `len` felts.
369+
fn leaf_cost<F>(len: usize, resources_to_gas_fn: F) -> GasAmount
370+
where
371+
F: Fn(&ExecutionResources) -> GasAmount,
372+
{
373+
// All `len` inputs treated as “big” felts; no small-felt optimization here.
374+
cost_of_encode_felt252_data_and_calc_blake_hash(len, 0, resources_to_gas_fn)
375+
}
376+
377+
/// Cost to hash a multi-segment contract:
378+
fn node_cost<F>(segs: &[NestedIntList], resources_to_gas_fn: F) -> GasAmount
379+
where
380+
F: Fn(&ExecutionResources) -> GasAmount,
381+
{
382+
// TODO(AvivG): Add base estimation for node.
383+
let mut gas = GasAmount::ZERO;
384+
385+
// TODO(AvivG): Add base estimation of each segment. Could this be part of 'leaf_cost'?
386+
let segment_overhead = GasAmount::ZERO;
387+
388+
// For each segment, hash its felts.
389+
for seg in segs {
390+
match seg {
391+
NestedIntList::Leaf(len) => {
392+
gas = gas.checked_add_panic_on_overflow(segment_overhead);
393+
gas = gas.checked_add_panic_on_overflow(leaf_cost(*len, &resources_to_gas_fn));
394+
}
395+
_ => panic!("Estimating hash cost only supports at most one level of segmentation."),
396+
}
397+
}
398+
399+
// Node‐level hash over (hash1, len1, hash2, len2, …): one segment hash (“big” felt))
400+
// and one segment length (“small” felt) per segment.
401+
let node_hash_cost = cost_of_encode_felt252_data_and_calc_blake_hash(
402+
segs.len(),
403+
segs.len(),
404+
resources_to_gas_fn,
405+
);
406+
407+
gas.checked_add_panic_on_overflow(node_hash_cost)
408+
}
409+
410+
/// Estimates the VM resources to compute the CASM Blake hash for a Cairo-1 contract:
411+
/// - Uses only bytecode size (treats all felts as “big”, ignores the small-felt optimization).
412+
pub fn estimate_casm_blake_hash_computation_resources<F>(
413+
bytecode_segment_lengths: &NestedIntList,
414+
resources_to_gas_fn: F,
415+
) -> GasAmount
416+
where
417+
F: Fn(&ExecutionResources) -> GasAmount,
418+
{
419+
// TODO(AvivG): Currently ignores entry-point hashing costs.
420+
// TODO(AvivG): Missing base overhead estimation for compiled_class_hash.
421+
422+
// Basic frame overhead.
423+
// TODO(AvivG): Once compiled_class_hash estimation is complete,
424+
// revisit whether this should be moved into cost_of_encode_felt252_data_and_calc_blake_hash.
425+
let resources = ExecutionResources {
426+
n_steps: 0,
427+
n_memory_holes: 0,
428+
builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 3)]),
429+
};
430+
let gas = resources_to_gas_fn(&resources);
431+
432+
// Add leaf vs node cost
433+
let added_gas = match bytecode_segment_lengths {
434+
// Single-segment contract (e.g., older Sierra contracts).
435+
NestedIntList::Leaf(len) => leaf_cost(*len, &resources_to_gas_fn),
436+
NestedIntList::Node(segs) => node_cost(segs, resources_to_gas_fn),
437+
};
438+
439+
gas.checked_add_panic_on_overflow(added_gas)
440+
}
441+
364442
// Returns the set of segments that were visited according to the given visited PCs and segment
365443
// lengths.
366444
// 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};
@@ -14,17 +14,17 @@ pub fn raise_error_for_testing() -> NativeBlockifierResult<()> {
1414
.into())
1515
}
1616

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

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

0 commit comments

Comments
 (0)