Skip to content

Commit 9a75d2e

Browse files
blockifier: add estimate_casm_blake_hash_computation_resources
1 parent abf1d51 commit 9a75d2e

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,10 +34,15 @@ 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;
45+
use crate::utils::add_gas;
4146

4247
#[cfg(test)]
4348
#[path = "contract_class_test.rs"]
@@ -287,7 +292,7 @@ impl CompiledClassV1 {
287292
/// This is an empiric measurement of several bytecode lengths, which constitutes as the
288293
/// dominant factor in it.
289294
fn estimate_casm_hash_computation_resources(&self) -> ExecutionResources {
290-
estimate_casm_hash_computation_resources(&self.bytecode_segment_lengths)
295+
estimate_casm_poseidon_hash_computation_resources(&self.bytecode_segment_lengths)
291296
}
292297

293298
/// Estimate the VM gas required to perform a CompiledClassHash migration,
@@ -321,7 +326,7 @@ impl CompiledClassV1 {
321326
///
322327
/// Note: the function focuses on the bytecode size, and currently ignores the cost handling the
323328
/// class entry points.
324-
pub fn estimate_casm_hash_computation_resources(
329+
pub fn estimate_casm_poseidon_hash_computation_resources(
325330
bytecode_segment_lengths: &NestedIntList,
326331
) -> ExecutionResources {
327332
// The constants in this function were computed by running the Casm code on a few values
@@ -361,6 +366,79 @@ pub fn estimate_casm_hash_computation_resources(
361366
}
362367
}
363368

369+
/// Cost to hash a single flat segment of `len` felts.
370+
fn leaf_cost<F>(len: usize, resources_to_gas_fn: F) -> GasAmount
371+
where
372+
F: Fn(&ExecutionResources) -> GasAmount,
373+
{
374+
// All `len` inputs treated as “big” felts; no small-felt optimization here.
375+
cost_of_encode_felt252_data_and_calc_blake_hash(len, 0, resources_to_gas_fn)
376+
}
377+
378+
/// Cost to hash a multi-segment contract:
379+
fn node_cost<F>(segs: &[NestedIntList], resources_to_gas_fn: F) -> GasAmount
380+
where
381+
F: Fn(&ExecutionResources) -> GasAmount,
382+
{
383+
// TODO(AvivG): Add base estimation for node.
384+
let mut gas = GasAmount::ZERO;
385+
386+
// TODO(AvivG): Add base estimation of each segment. Could this be part of 'leaf_cost'?
387+
let segment_overhead = GasAmount::ZERO;
388+
389+
// 2) For each segment, hash its felts.
390+
for seg in segs {
391+
match seg {
392+
NestedIntList::Leaf(len) => {
393+
add_gas(&mut gas, segment_overhead);
394+
add_gas(&mut gas, leaf_cost(*len, &resources_to_gas_fn));
395+
}
396+
_ => panic!("Estimating hash cost only supports at most one level of segmentation."),
397+
}
398+
}
399+
400+
// Node‐level hash over (hash1, len1, hash2, len2, …): one segment hash (“big” felt))
401+
// and one segment length (“small” felt) per segment.
402+
let node_hash_cost = cost_of_encode_felt252_data_and_calc_blake_hash(
403+
segs.len(),
404+
segs.len(),
405+
resources_to_gas_fn,
406+
);
407+
408+
add_gas(&mut gas, node_hash_cost);
409+
410+
gas
411+
}
412+
413+
/// Estimates the VM resources to compute the CASM Blake hash for a Cairo-1 contract:
414+
/// - Uses only bytecode size (treats all felts as “big”, ignores the small-felt optimization).
415+
pub fn estimate_casm_blake_hash_computation_resources<F>(
416+
bytecode_segment_lengths: &NestedIntList,
417+
resources_to_gas_fn: F,
418+
) -> GasAmount
419+
where
420+
F: Fn(&ExecutionResources) -> GasAmount,
421+
{
422+
// TODO(AvivG): Currently ignores entry-point costs.
423+
424+
// Basic frame overhead
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 mut gas = resources_to_gas_fn(&resources);
431+
432+
// Add leaf vs node cost
433+
match bytecode_segment_lengths {
434+
// Single-segment contract (e.g., older Sierra contracts).
435+
NestedIntList::Leaf(len) => add_gas(&mut gas, leaf_cost(*len, &resources_to_gas_fn)),
436+
NestedIntList::Node(segs) => add_gas(&mut gas, node_cost(segs, resources_to_gas_fn)),
437+
};
438+
439+
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)