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

Add new constructor declare v2 #823

Merged
merged 16 commits into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from 14 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
17 changes: 16 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ mod test {
use std::path::PathBuf;

use crate::core::contract_address::{compute_deprecated_class_hash, compute_sierra_class_hash};
use crate::definitions::constants::INITIAL_GAS_COST;
use crate::definitions::{
block_context::StarknetChainId,
constants::{
Expand Down Expand Up @@ -836,7 +837,7 @@ mod test {
tx_type: TransactionType::Declare,
validate_entry_point_selector: VALIDATE_DECLARE_ENTRY_POINT_SELECTOR.clone(),
version: 1.into(),
max_fee: 2,
max_fee: INITIAL_GAS_COST,
signature: vec![],
nonce: 0.into(),
hash_value: 0.into(),
Expand Down Expand Up @@ -998,4 +999,18 @@ mod test {
[(0, 1224), (0, 0)]
);
}

#[test]
fn test_declare_v2_with_invalid_compiled_class_hash() {
let (block_context, mut state) = create_account_tx_test_state().unwrap();
let mut declare_v2 = declarev2_tx();
declare_v2.compiled_class_hash = Felt252::from(1);
let declare_tx = Transaction::DeclareV2(Box::new(declare_v2));

let err = declare_tx
.execute(&mut state, &block_context, INITIAL_GAS_COST)
.unwrap_err();

assert_eq!(err.to_string(), "Invalid compiled class, expected class hash: \"1948962768849191111780391610229754715773924969841143100991524171924131413970\", but received: \"1\"".to_string());
}
}
2 changes: 1 addition & 1 deletion src/testing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ lazy_static! {
pub static ref TEST_CLASS_HASH: Felt252 = felt_str!("272");
pub static ref TEST_EMPTY_CONTRACT_CLASS_HASH: Felt252 = felt_str!("274");
pub static ref TEST_ERC20_CONTRACT_CLASS_HASH: Felt252 = felt_str!("4112");
pub static ref TEST_FIB_COMPILED_CONTRACT_CLASS_HASH: Felt252 = felt_str!("27727");
pub static ref TEST_FIB_COMPILED_CONTRACT_CLASS_HASH: Felt252 = felt_str!("1948962768849191111780391610229754715773924969841143100991524171924131413970");

// Storage keys.
pub static ref TEST_ERC20_ACCOUNT_BALANCE_KEY: Felt252 =
Expand Down
123 changes: 110 additions & 13 deletions src/transaction/declare_v2.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{verify_version, Transaction};
use crate::core::contract_address::compute_sierra_class_hash;
use crate::core::contract_address::{compute_casm_class_hash, compute_sierra_class_hash};
use crate::definitions::constants::QUERY_VERSION_BASE;
use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType;

Expand Down Expand Up @@ -45,7 +45,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 All @@ -56,6 +56,7 @@ impl DeclareV2 {
/// It will calculate the sierra class hash and the transaction hash.
/// ## Parameters:
/// - sierra_contract_class: The sierra contract class of the contract to declare
/// - casm_contract_class: The casm contract class of the contract to declare. This is optional.
/// - compiled_class_hash: the class hash of the contract compiled with Cairo1 or newer.
/// - chain_id: Id of the network where is going to be declare, those can be: Mainnet, Testnet.
/// - sender_address: The address of the account declaring the contract.
Expand All @@ -66,6 +67,7 @@ impl DeclareV2 {
#[allow(clippy::too_many_arguments)]
pub fn new(
sierra_contract_class: &SierraContractClass,
casm_contract_class: Option<CasmContractClass>,
compiled_class_hash: Felt252,
chain_id: Felt252,
sender_address: Address,
Expand All @@ -89,6 +91,7 @@ impl DeclareV2 {
Self::new_with_sierra_class_hash_and_tx_hash(
sierra_contract_class,
sierra_class_hash,
casm_contract_class,
compiled_class_hash,
sender_address,
max_fee,
Expand All @@ -103,6 +106,7 @@ impl DeclareV2 {
/// ## Parameters:
/// - sierra_contract_class: The sierra contract class of the contract to declare
/// - sierra_class_hash: The precomputed hash for the sierra contract
/// - casm_contract_class: The casm contract class of the contract to declare. This is optional.
/// - compiled_class_hash: the class hash of the contract compiled with Cairo1 or newer.
/// - sender_address: The address of the account declaring the contract.
/// - max_fee: refers to max amount of fee that a declare takes.
Expand All @@ -116,6 +120,7 @@ impl DeclareV2 {
pub fn new_with_sierra_class_hash_and_tx_hash(
sierra_contract_class: &SierraContractClass,
sierra_class_hash: Felt252,
casm_contract_class: Option<CasmContractClass>,
compiled_class_hash: Felt252,
sender_address: Address,
max_fee: u128,
Expand All @@ -138,7 +143,7 @@ impl DeclareV2 {
nonce,
compiled_class_hash,
hash_value,
casm_class: Default::default(),
casm_class: casm_contract_class,
skip_execute: false,
skip_validate: false,
skip_fee_transfer: false,
Expand All @@ -156,7 +161,8 @@ impl DeclareV2 {

// creates a new instance of a declare but without the computation of the transaction hash.
/// ## Parameters:
/// - sierra_contract_class: The sierra contract class of the contract to declare
/// - sierra_contract_class: The sierra contract class of the contract to declare.
/// - casm_contract_class: The casm contract class of the contract to declare. This is optional.
/// - compiled_class_hash: the class hash of the contract compiled with Cairo1 or newer.
/// - sender_address: The address of the account declaring the contract.
/// - max_fee: refers to max amount of fee that a declare takes.
Expand All @@ -167,6 +173,7 @@ impl DeclareV2 {
#[allow(clippy::too_many_arguments)]
pub fn new_with_tx_hash(
sierra_contract_class: &SierraContractClass,
casm_contract_class: Option<CasmContractClass>,
compiled_class_hash: Felt252,
sender_address: Address,
max_fee: u128,
Expand All @@ -180,6 +187,7 @@ impl DeclareV2 {
Self::new_with_sierra_class_hash_and_tx_hash(
sierra_contract_class,
sierra_class_hash,
casm_contract_class,
compiled_class_hash,
sender_address,
max_fee,
Expand All @@ -194,6 +202,7 @@ impl DeclareV2 {
/// ## Parameters:
/// - sierra_contract_class: The sierra contract class of the contract to declare
/// - sierra_class_hash: The precomputed hash for the sierra contract
/// - casm_contract_class: The casm contract class of the contract to declare. This is optional.
/// - compiled_class_hash: the class hash of the contract compiled with Cairo1 or newer.
/// - chain_id: Id of the network where is going to be declare, those can be: Mainnet, Testnet.
/// - sender_address: The address of the account declaring the contract.
Expand All @@ -205,6 +214,7 @@ impl DeclareV2 {
pub fn new_with_sierra_class_hash(
sierra_contract_class: &SierraContractClass,
sierra_class_hash: Felt252,
casm_contract_class: Option<CasmContractClass>,
compiled_class_hash: Felt252,
chain_id: Felt252,
sender_address: Address,
Expand All @@ -226,6 +236,7 @@ impl DeclareV2 {
Self::new_with_sierra_class_hash_and_tx_hash(
sierra_contract_class,
sierra_class_hash,
casm_contract_class,
compiled_class_hash,
sender_address,
max_fee,
Expand Down Expand Up @@ -374,15 +385,23 @@ 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 {
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()))?
}
Some(casm_contract_class) => casm_contract_class.clone(),
};

let casm_class_hash = compute_casm_class_hash(&casm_class)?;
if casm_class_hash != self.compiled_class_hash {
return Err(TransactionError::InvalidCompiledClassHash(
casm_class_hash.to_string(),
self.compiled_class_hash.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 Expand Up @@ -453,7 +472,7 @@ mod tests {
use std::{collections::HashMap, fs::File, io::BufReader, path::PathBuf};

use super::DeclareV2;
use crate::core::contract_address::compute_sierra_class_hash;
use crate::core::contract_address::{compute_casm_class_hash, compute_sierra_class_hash};
use crate::definitions::constants::QUERY_VERSION_BASE;
use crate::services::api::contract_classes::compiled_class::CompiledClass;
use crate::state::state_api::StateReader;
Expand All @@ -466,7 +485,7 @@ mod tests {
use num_traits::{One, Zero};

#[test]
fn create_declare_v2_test() {
fn create_declare_v2_without_casm_contract_class_test() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a test with a none DeclareV2.casm_class to check that everything is working OK

// read file to create sierra contract class
let version;
let path;
Expand All @@ -487,12 +506,85 @@ mod tests {
let sierra_contract_class: cairo_lang_starknet::contract_class::ContractClass =
serde_json::from_reader(reader).unwrap();
let sender_address = Address(1.into());
let casm_class =
CasmContractClass::from_contract_class(sierra_contract_class.clone(), true).unwrap();
let casm_class_hash = compute_casm_class_hash(&casm_class).unwrap();

// create internal declare v2

let internal_declare = DeclareV2::new_with_tx_hash(
&sierra_contract_class,
None,
casm_class_hash,
sender_address,
0,
version,
[1.into()].to_vec(),
Felt252::zero(),
Felt252::one(),
)
.unwrap();

// crate state to store casm contract class
let casm_contract_class_cache = HashMap::new();
let state_reader = InMemoryStateReader::default();
let mut state = CachedState::new(state_reader, None, Some(casm_contract_class_cache));

// call compile and store
assert!(internal_declare
.compile_and_store_casm_class(&mut state)
.is_ok());

// test we can retreive the data
let expected_casm_class = CasmContractClass::from_contract_class(
internal_declare.sierra_contract_class.clone(),
true,
)
.unwrap();

let casm_class = match state
.get_contract_class(&internal_declare.compiled_class_hash.to_be_bytes())
.unwrap()
{
CompiledClass::Casm(casm) => *casm,
_ => unreachable!(),
};

assert_eq!(expected_casm_class, casm_class);
}

#[test]
fn create_declare_v2_with_casm_contract_class_test() {
// read file to create sierra contract class
let version;
let path;
#[cfg(not(feature = "cairo_1_tests"))]
{
version = Felt252::from(2);
path = PathBuf::from("starknet_programs/cairo2/fibonacci.sierra");
}

#[cfg(feature = "cairo_1_tests")]
{
version = Felt252::from(1);
path = PathBuf::from("starknet_programs/cairo1/fibonacci.sierra");
}

let file = File::open(path).unwrap();
let reader = BufReader::new(file);
let sierra_contract_class: cairo_lang_starknet::contract_class::ContractClass =
serde_json::from_reader(reader).unwrap();
let sender_address = Address(1.into());
let casm_class =
CasmContractClass::from_contract_class(sierra_contract_class.clone(), true).unwrap();
let casm_class_hash = compute_casm_class_hash(&casm_class).unwrap();

// create internal declare v2

let internal_declare = DeclareV2::new_with_tx_hash(
&sierra_contract_class,
Some(casm_class),
casm_class_hash,
sender_address,
0,
version,
Expand Down Expand Up @@ -553,12 +645,17 @@ mod tests {
serde_json::from_reader(reader).unwrap();
let sierra_class_hash = compute_sierra_class_hash(&sierra_contract_class).unwrap();
let sender_address = Address(1.into());
let casm_class =
CasmContractClass::from_contract_class(sierra_contract_class.clone(), true).unwrap();
let casm_class_hash = compute_casm_class_hash(&casm_class).unwrap();

// create internal declare v2

let internal_declare = DeclareV2::new_with_tx_hash(
let internal_declare = DeclareV2::new_with_sierra_class_hash_and_tx_hash(
&sierra_contract_class,
sierra_class_hash,
Some(casm_class),
casm_class_hash,
sender_address,
0,
version,
Expand Down
2 changes: 2 additions & 0 deletions src/transaction/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,6 @@ pub enum TransactionError {
CallInfoIsNone,
#[error("Unsupported version {0:?}")]
UnsupportedVersion(String),
#[error("Invalid compiled class, expected class hash: {0:?}, but received: {1:?}")]
InvalidCompiledClassHash(String, String),
}
3 changes: 2 additions & 1 deletion starknet_programs/cairo1/fibonacci_dispatcher.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ mod Dispatcher {
class_hash: felt252, selector: felt252, a: felt252, b: felt252, n: felt252
) -> felt252 {
FibonacciLibraryDispatcher {
class_hash: starknet::class_hash_const::<27727>(),
// THIS VALUE IS THE HASH OF THE FIBONACCI CASM CLASS HASH. THE SAME AS THE CONSTANT: TEST_FIB_COMPILED_CONTRACT_CLASS_HASH
class_hash: starknet::class_hash_const::<1948962768849191111780391610229754715773924969841143100991524171924131413970>(),
selector
}.fib(a, b, n)
}
Expand Down
3 changes: 2 additions & 1 deletion starknet_programs/cairo2/fibonacci_dispatcher.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ mod Dispatcher {
self: @ContractState, class_hash: felt252, selector: felt252, a: felt252, b: felt252, n: felt252
) -> felt252 {
FibonacciLibraryDispatcher {
class_hash: starknet::class_hash_const::<27727>(),
// THIS VALUE IS THE HASH OF THE FIBONACCI CASM CLASS HASH.
class_hash: starknet::class_hash_const::<2889767417435368609058888822622483550637539736178264636938129582300971548553>(),
selector
}.fib(a, b, n)
}
Expand Down
Loading