Skip to content

Commit 45c70c9

Browse files
feat(blockifier): add estimate_casm_blake_hash_computation_resources
1 parent f6f14cc commit 45c70c9

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
@@ -32,12 +32,19 @@ use starknet_api::execution_resources::GasAmount;
3232
use starknet_types_core::felt::Felt;
3333

3434
use crate::abi::constants::{self};
35+
use crate::blockifier_versioned_constants::VersionedConstants;
36+
use crate::bouncer::vm_resources_to_sierra_gas;
3537
use crate::execution::entry_point::{EntryPointExecutionContext, EntryPointTypeAndSelector};
3638
use crate::execution::errors::PreExecutionError;
37-
use crate::execution::execution_utils::{poseidon_hash_many_cost, sn_api_to_cairo_vm_program};
39+
use crate::execution::execution_utils::{
40+
cost_of_encode_felt252_data_and_calc_blake_hash,
41+
poseidon_hash_many_cost,
42+
sn_api_to_cairo_vm_program,
43+
};
3844
#[cfg(feature = "cairo_native")]
3945
use crate::execution::native::contract_class::NativeCompiledClassV1;
4046
use crate::transaction::errors::TransactionExecutionError;
47+
use crate::utils::safe_add_gas_panic_on_overflow;
4148

4249
#[cfg(test)]
4350
#[path = "contract_class_test.rs"]
@@ -288,7 +295,7 @@ impl CompiledClassV1 {
288295
/// This is an empiric measurement of several bytecode lengths, which constitutes as the
289296
/// dominant factor in it.
290297
fn estimate_casm_hash_computation_resources(&self) -> ExecutionResources {
291-
estimate_casm_hash_computation_resources(&self.bytecode_segment_lengths)
298+
estimate_casm_poseidon_hash_computation_resources(&self.bytecode_segment_lengths)
292299
}
293300

294301
/// Estimate the VM gas required to perform a CompiledClassHash migration,
@@ -323,7 +330,7 @@ impl CompiledClassV1 {
323330
///
324331
/// Note: the function focuses on the bytecode size, and currently ignores the cost handling the
325332
/// class entry points.
326-
pub fn estimate_casm_hash_computation_resources(
333+
pub fn estimate_casm_poseidon_hash_computation_resources(
327334
bytecode_segment_lengths: &NestedIntList,
328335
) -> ExecutionResources {
329336
// The constants in this function were computed by running the Casm code on a few values
@@ -363,6 +370,68 @@ pub fn estimate_casm_hash_computation_resources(
363370
}
364371
}
365372

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