Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Check casm compilation #797

Closed
wants to merge 12 commits into from
Closed
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
3 changes: 2 additions & 1 deletion src/core/contract_address/sierra_contract_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ fn get_contract_entry_points_hashed(
let contract_entry_points = get_contract_entry_points(contract_class, entry_point_type)?;

// for each entry_point, we need to store 2 FieldElements: selector and offset.
let mut entry_points_flatted = Vec::with_capacity(contract_entry_points.len() * 2);
let mut entry_points_flatted: Vec<FieldElement> =
Vec::with_capacity(contract_entry_points.len() * 2);

for entry_point in contract_entry_points {
entry_points_flatted.push(
Expand Down
79 changes: 71 additions & 8 deletions src/transaction/declare_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub struct DeclareV2 {
pub sierra_contract_class: SierraContractClass,
pub sierra_class_hash: Felt252,
pub hash_value: Felt252,
pub casm_class: once_cell::unsync::OnceCell<CasmContractClass>,
pub casm_class: Option<CasmContractClass>,
pub skip_validate: bool,
pub skip_execute: bool,
pub skip_fee_transfer: bool,
Expand Down Expand Up @@ -159,7 +159,69 @@ impl DeclareV2 {
nonce,
compiled_class_hash,
hash_value,
casm_class: Default::default(),
casm_class: None,
skip_execute: false,
skip_validate: false,
skip_fee_transfer: false,
};

verify_version(
&internal_declare.version,
internal_declare.max_fee,
&internal_declare.nonce,
&internal_declare.signature,
)?;

Ok(internal_declare)
}

#[allow(clippy::too_many_arguments)]
pub fn new_with_casm(
sierra_contract_class: &SierraContractClass,
sierra_class_hash: Option<Felt252>,
compiled_class_hash: Felt252,
casm_contract_class: CasmContractClass,
chain_id: Felt252,
sender_address: Address,
max_fee: u128,
version: Felt252,
signature: Vec<Felt252>,
nonce: Felt252,
hash_value: Option<Felt252>,
) -> Result<Self, TransactionError> {
let validate_entry_point_selector = VALIDATE_DECLARE_ENTRY_POINT_SELECTOR.clone();

let sierra_class_hash = match sierra_class_hash {
Some(h) => h,
None => compute_sierra_class_hash(sierra_contract_class)?,
};

let hash_value = match hash_value {
Some(hash) => hash,
None => calculate_declare_v2_transaction_hash(
sierra_class_hash.clone(),
compiled_class_hash.clone(),
chain_id,
&sender_address,
max_fee,
version.clone(),
nonce.clone(),
)?,
};

let internal_declare = DeclareV2 {
sierra_contract_class: sierra_contract_class.to_owned(),
sender_address,
sierra_class_hash,
tx_type: TransactionType::Declare,
validate_entry_point_selector,
version,
max_fee,
signature,
nonce,
compiled_class_hash,
hash_value,
casm_class: Some(casm_contract_class),
skip_execute: false,
skip_validate: false,
skip_fee_transfer: false,
Expand Down Expand Up @@ -313,15 +375,16 @@ impl DeclareV2 {
&self,
state: &mut S,
) -> Result<(), TransactionError> {
let casm_class = self
.casm_class
.get_or_try_init(|| {
let casm_class = match self.casm_class.clone() {
Some(class) => class,
None => {
CasmContractClass::from_contract_class(self.sierra_contract_class.clone(), true)
})
.map_err(|e| TransactionError::SierraCompileError(e.to_string()))?;
.map_err(|e| TransactionError::SierraCompileError(e.to_string()))?
}
};

state.set_compiled_class_hash(&self.sierra_class_hash, &self.compiled_class_hash)?;
state.set_compiled_class(&self.compiled_class_hash, casm_class.clone())?;
state.set_compiled_class(&self.compiled_class_hash, casm_class)?;

Ok(())
}
Expand Down
110 changes: 109 additions & 1 deletion src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::core::errors::contract_address_errors::ContractAddressError;
use crate::services::api::contract_classes::compiled_class::CompiledClass;
use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType;
use crate::{
definitions::transaction_type::TransactionType,
Expand All @@ -11,14 +13,17 @@ use crate::{
syscalls::syscall_handler_errors::SyscallHandlerError,
transaction::error::TransactionError,
};
use cairo_lang_starknet::casm_contract_class::CasmContractClass;
use cairo_lang_starknet::contract::starknet_keccak;
use cairo_lang_starknet::contract_class::ContractEntryPoint;
use cairo_vm::{
felt::Felt252, serde::deserialize_program::BuiltinName, vm::runners::builtin_runner,
};
use cairo_vm::{types::relocatable::Relocatable, vm::vm_core::VirtualMachine};
use num_traits::{Num, ToPrimitive};
use serde::{Deserialize, Serialize};
use sha3::{Digest, Keccak256};
use starknet_crypto::FieldElement;
use starknet_crypto::{poseidon_hash_many, poseidon_hash_single, FieldElement};
use std::{
collections::{HashMap, HashSet},
hash::Hash,
Expand Down Expand Up @@ -307,6 +312,109 @@ pub fn calculate_sn_keccak(data: &[u8]) -> ClassHash {
result
}

//* -----------------------
//* Compute compile hash
//* -----------------------

fn get_contract_entrypoints(
casm: CasmContractClass,
entry_point_type: EntryPointType,
) -> Result<Vec<ContractEntryPoint>, ContractAddressError> {
let program_length = casm.bytecode.len();

let entry_points = match entry_point_type {
EntryPointType::Constructor => casm.entry_points_by_type.constructor.clone(),
EntryPointType::External => casm.entry_points_by_type.external.clone(),
EntryPointType::L1Handler => casm.entry_points_by_type.l1_handler.clone(),
};

let program_len = program_length;
for entry_point in &entry_points {
if entry_point.offset > program_len {
return Err(ContractAddressError::InvalidOffset(entry_point.offset));
}
}

Ok(entry_points
.iter()
.map(|entry_point| {
ContractEntryPoint::new(entry_point.selector.clone().into(), entry_point.offset)
})
.collect())
}

fn get_contract_entry_points_hashed(
casm: CasmContractClass,
entrypoint_type: &EntryPointType,
) -> Result<FieldElement, ContractAddressError> {
let contract_entry_points = get_contract_entrypoints(casm, *entrypoint_type)?;

let mut entry_points_flatted: Vec<FieldElement> =
Vec::with_capacity(contract_entry_points.len() * 2);

for entry_point in contract_entry_points {
entry_points_flatted.push(entry_point.selector.into());
entry_points_flatted.push(FieldElement::from(entry_point.function_idx));
}

Ok(poseidon_hash_many(&entry_points_flatted))
}

fn compute_class_hash(contract_class: CasmContractClass) -> Felt252 {
// Entrypoints by type, hashed.
let external_functions =
get_contract_entry_points_hashed(contract_class, &EntryPointType::External)?;
let l1_handlers = get_contract_entry_points_hashed(contract_class, &EntryPointType::L1Handler)?;
let constructors =
get_contract_entry_points_hashed(contract_class, &EntryPointType::Constructor)?;

// Hash abi_hash.
let abi = contract_class
.abi
.clone()
.ok_or(ContractAddressError::MissingAbi)?
.json();

let abi_hash =
FieldElement::from_bytes_be(&Felt252::from(starknet_keccak(abi.as_bytes())).to_be_bytes())
.map_err(|_err| {
ContractAddressError::Cast("Felt252".to_string(), "FieldElement".to_string())
})?;

let mut sierra_program_vector = Vec::with_capacity(contract_class.bytecode.len());
for number in &contract_class.bytecode {
sierra_program_vector.push(
FieldElement::from_bytes_be(&Felt252::from(number.value.clone()).to_be_bytes())
.map_err(|_err| {
ContractAddressError::Cast("Felt252".to_string(), "FieldElement".to_string())
})?,
);
}

// Hash Sierra program.
let sierra_program_ptr = poseidon_hash_many(&sierra_program_vector);

let flatted_contract_class = vec![
api_version,
external_functions,
l1_handlers,
constructors,
abi_hash,
sierra_program_ptr,
];

Ok(Felt252::from_bytes_be(
&poseidon_hash_many(&flatted_contract_class).to_bytes_be(),
))
}

pub fn compute_compiled_class_hash(compiled_class: CompiledClass) -> Felt252 {
match compiled_class {
CompiledClass::Casm(class) => compute_class_hash(*class),
_ => unreachable!(),
}
}

//* ------------------------
//* Other utils
//* ------------------------
Expand Down