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 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
12 changes: 10 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1004,13 +1004,21 @@ mod 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 real_casm_class_hash = declare_v2.compiled_class_hash;
let wrong_casm_class_hash = Felt252::from(1);
declare_v2.compiled_class_hash = wrong_casm_class_hash.clone();
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());
assert_eq!(
err.to_string(),
format!(
"Invalid compiled class, expected class hash: {}, but received: {}",
real_casm_class_hash, wrong_casm_class_hash
)
);
}
}
234 changes: 223 additions & 11 deletions src/transaction/declare_v2.rs
Original file line number Diff line number Diff line change
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,22 +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)?;
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 @@ -473,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 Down Expand Up @@ -502,6 +514,76 @@ mod tests {

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,
Expand Down Expand Up @@ -572,6 +654,7 @@ mod tests {
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,
Expand Down Expand Up @@ -609,4 +692,133 @@ mod tests {

assert_eq!(expected_casm_class, casm_class);
}

#[test]
fn create_declare_v2_with_casm_contract_class_none_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,
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_wrong_casm_class_hash_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();

let sended_class_hash = Felt252::from(5);
// create internal declare v2

let internal_declare = DeclareV2::new_with_tx_hash(
&sierra_contract_class,
None,
sended_class_hash.clone(),
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));

let expected_err = format!(
"Invalid compiled class, expected class hash: {}, but received: {}",
casm_class_hash, sended_class_hash
);
assert_eq!(
internal_declare
.compile_and_store_casm_class(&mut state)
.unwrap_err()
.to_string(),
expected_err
);
}
}
2 changes: 1 addition & 1 deletion src/transaction/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,6 @@ pub enum TransactionError {
CallInfoIsNone,
#[error("Unsupported version {0:?}")]
UnsupportedVersion(String),
#[error("Invalid compiled class, expected class hash: {0:?}, but received: {1:?}")]
#[error("Invalid compiled class, expected class hash: {0}, but received: {1}")]
InvalidCompiledClassHash(String, String),
}