Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 81 additions & 3 deletions crates/blockifier/src/execution/contract_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ use starknet_types_core::felt::Felt;
use crate::abi::constants::{self};
use crate::execution::entry_point::{EntryPointExecutionContext, EntryPointTypeAndSelector};
use crate::execution::errors::PreExecutionError;
use crate::execution::execution_utils::{poseidon_hash_many_cost, sn_api_to_cairo_vm_program};
use crate::execution::execution_utils::{
cost_of_encode_felt252_data_and_calc_blake_hash,
poseidon_hash_many_cost,
sn_api_to_cairo_vm_program,
};
#[cfg(feature = "cairo_native")]
use crate::execution::native::contract_class::NativeCompiledClassV1;
use crate::transaction::errors::TransactionExecutionError;
Expand Down Expand Up @@ -287,7 +291,7 @@ impl CompiledClassV1 {
/// This is an empiric measurement of several bytecode lengths, which constitutes as the
/// dominant factor in it.
fn estimate_casm_hash_computation_resources(&self) -> ExecutionResources {
estimate_casm_hash_computation_resources(&self.bytecode_segment_lengths)
estimate_casm_poseidon_hash_computation_resources(&self.bytecode_segment_lengths)
}

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

/// Cost to hash a single flat segment of `len` felts.
fn leaf_cost<F>(len: usize, resources_to_gas_fn: F) -> GasAmount
where
F: Fn(&ExecutionResources) -> GasAmount,
{
// All `len` inputs treated as “big” felts; no small-felt optimization here.
cost_of_encode_felt252_data_and_calc_blake_hash(len, 0, resources_to_gas_fn)
}

/// Cost to hash a multi-segment contract:
fn node_cost<F>(segs: &[NestedIntList], resources_to_gas_fn: F) -> GasAmount
where
F: Fn(&ExecutionResources) -> GasAmount,
{
// TODO(AvivG): Add base estimation for node.
let mut gas = GasAmount::ZERO;

// TODO(AvivG): Add base estimation of each segment. Could this be part of 'leaf_cost'?
let segment_overhead = GasAmount::ZERO;

// For each segment, hash its felts.
for seg in segs {
match seg {
NestedIntList::Leaf(len) => {
gas = gas.checked_add_panic_on_overflow(segment_overhead);
gas = gas.checked_add_panic_on_overflow(leaf_cost(*len, &resources_to_gas_fn));
}
_ => panic!("Estimating hash cost only supports at most one level of segmentation."),
}
}

// Node‐level hash over (hash1, len1, hash2, len2, …): one segment hash (“big” felt))
// and one segment length (“small” felt) per segment.
let node_hash_cost = cost_of_encode_felt252_data_and_calc_blake_hash(
segs.len(),
segs.len(),
resources_to_gas_fn,
);

gas.checked_add_panic_on_overflow(node_hash_cost)
}

/// Estimates the VM resources to compute the CASM Blake hash for a Cairo-1 contract:
/// - Uses only bytecode size (treats all felts as “big”, ignores the small-felt optimization).
pub fn estimate_casm_blake_hash_computation_resources<F>(
bytecode_segment_lengths: &NestedIntList,
resources_to_gas_fn: F,
) -> GasAmount
where
F: Fn(&ExecutionResources) -> GasAmount,
{
// TODO(AvivG): Currently ignores entry-point hashing costs.
// TODO(AvivG): Missing base overhead estimation for compiled_class_hash.

// Basic frame overhead.
// TODO(AvivG): Once compiled_class_hash estimation is complete,
// revisit whether this should be moved into cost_of_encode_felt252_data_and_calc_blake_hash.
let resources = ExecutionResources {
n_steps: 0,
n_memory_holes: 0,
builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 3)]),
};
let gas = resources_to_gas_fn(&resources);

// Add leaf vs node cost
let added_gas = match bytecode_segment_lengths {
// Single-segment contract (e.g., older Sierra contracts).
NestedIntList::Leaf(len) => leaf_cost(*len, &resources_to_gas_fn),
NestedIntList::Node(segs) => node_cost(segs, resources_to_gas_fn),
};

gas.checked_add_panic_on_overflow(added_gas)
}

// Returns the set of segments that were visited according to the given visited PCs and segment
// lengths.
// Each visited segment must have its starting PC visited, and is represented by it.
Expand Down
10 changes: 5 additions & 5 deletions crates/native_blockifier/src/py_testing_wrappers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use blockifier::execution::contract_class::estimate_casm_hash_computation_resources;
use blockifier::execution::contract_class::estimate_casm_poseidon_hash_computation_resources;
use blockifier::transaction::errors::{TransactionExecutionError, TransactionFeeError};
use cairo_lang_starknet_classes::NestedIntList;
use pyo3::{pyfunction, PyResult};
Expand All @@ -14,17 +14,17 @@ pub fn raise_error_for_testing() -> NativeBlockifierResult<()> {
.into())
}

/// Wrapper for [estimate_casm_hash_computation_resources] that can be used for testing.
/// Wrapper for [estimate_casm_poseidon_hash_computation_resources] that can be used for testing.
/// Takes a leaf.
#[pyfunction]
pub fn estimate_casm_hash_computation_resources_for_testing_single(
bytecode_segment_lengths: usize,
) -> PyResult<PyExecutionResources> {
let node = NestedIntList::Leaf(bytecode_segment_lengths);
Ok(estimate_casm_hash_computation_resources(&node).into())
Ok(estimate_casm_poseidon_hash_computation_resources(&node).into())
}

/// Wrapper for [estimate_casm_hash_computation_resources] that can be used for testing.
/// Wrapper for [estimate_casm_poseidon_hash_computation_resources] that can be used for testing.
/// Takes a node of leaves.
#[pyfunction]
pub fn estimate_casm_hash_computation_resources_for_testing_list(
Expand All @@ -33,5 +33,5 @@ pub fn estimate_casm_hash_computation_resources_for_testing_list(
let node = NestedIntList::Node(
bytecode_segment_lengths.into_iter().map(NestedIntList::Leaf).collect(),
);
Ok(estimate_casm_hash_computation_resources(&node).into())
Ok(estimate_casm_poseidon_hash_computation_resources(&node).into())
}
Loading