diff --git a/CHANGELOG.md b/CHANGELOG.md index e6ead47c87..f12e3e234d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- bug: fix contract serialisation - fix: starknet_call errs if contract nonexistent - fix: txn hash calculation and refactor - chore: remove all da/settlement related code @@ -44,6 +45,7 @@ - feat(rpc/trace_api): add `trace_transaction` - fix(docker): fix dockerfile for `madara-node` - feat: Remove generic hasher from block hash computation +- dev: tx v3 tests ## v0.7.0 diff --git a/Cargo.lock b/Cargo.lock index 16a50047cc..0652aefc1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10931,6 +10931,7 @@ dependencies = [ "flate2", "reqwest", "rstest 0.18.2", + "serde", "serde_json", "starknet-accounts", "starknet-contract", diff --git a/crates/pallets/starknet/src/tests/invoke_tx.rs b/crates/pallets/starknet/src/tests/invoke_tx.rs index 7928ef8d8c..4beb072973 100644 --- a/crates/pallets/starknet/src/tests/invoke_tx.rs +++ b/crates/pallets/starknet/src/tests/invoke_tx.rs @@ -12,6 +12,7 @@ use sp_runtime::transaction_validity::{ InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction, }; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey}; +use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey; use starknet_api::transaction::{ @@ -28,9 +29,11 @@ use super::mock::default_mock::*; use super::mock::*; use super::utils::{get_contract_class, sign_message_hash}; use crate::tests::constants::{UDC_ADDRESS, UDC_SELECTOR}; +use crate::tests::utils::create_resource_bounds; use crate::tests::{ get_invoke_argent_dummy, get_invoke_braavos_dummy, get_invoke_dummy, get_invoke_emit_event_dummy, - get_invoke_nonce_dummy, get_invoke_openzeppelin_dummy, get_storage_read_write_dummy, set_infinite_tokens, + get_invoke_nonce_dummy, get_invoke_openzeppelin_dummy, get_invoke_v3_argent_dummy, get_invoke_v3_braavos_dummy, + get_invoke_v3_dummy, get_invoke_v3_openzeppelin_dummy, get_storage_read_write_dummy, set_infinite_tokens, set_nonce, }; use crate::{Call, Error, StorageView}; @@ -322,7 +325,7 @@ fn given_hardcoded_contract_run_invoke_on_argent_account_with_incorrect_signatur assert_err!(Starknet::invoke(none_origin, transaction), Error::::TransactionExecutionFailed); }); } - +// Down #[test] fn given_hardcoded_contract_run_invoke_on_braavos_account_then_it_works() { new_test_ext::().execute_with(|| { @@ -338,7 +341,7 @@ fn given_hardcoded_contract_run_invoke_on_braavos_account_then_it_works() { }); } -#[test] +#[test] //-------------- fn given_hardcoded_contract_run_invoke_on_braavos_account_with_incorrect_signature_then_it_fails() { new_test_ext::().execute_with(|| { basic_test_setup(2); @@ -359,7 +362,7 @@ fn given_hardcoded_contract_run_invoke_on_braavos_account_with_incorrect_signatu }); } -#[test] +#[test] // -------------- fn given_hardcoded_contract_run_invoke_with_inner_call_in_validate_then_it_fails() { new_test_ext::().execute_with(|| { basic_test_setup(2); @@ -387,7 +390,7 @@ fn given_hardcoded_contract_run_invoke_with_inner_call_in_validate_then_it_fails }); } -#[test] +#[test] // ------------ fn given_account_not_deployed_invoke_tx_validate_works_for_nonce_one() { new_test_ext::().execute_with(|| { basic_test_setup(2); @@ -411,7 +414,7 @@ fn given_account_not_deployed_invoke_tx_validate_works_for_nonce_one() { }) } -#[test] +#[test] //--------------- fn given_account_not_deployed_invoke_tx_fails_for_nonce_not_one() { new_test_ext::().execute_with(|| { basic_test_setup(2); @@ -617,3 +620,196 @@ fn storage_changes_should_revert_on_transaction_revert() { assert_eq!(balance_value, vec![Felt252Wrapper::ZERO]) }) } + +#[test] +fn given_hardcoded_contract_run_invoke_tx_v3_fails_sender_not_deployed() { + new_test_ext::().execute_with(|| { + basic_test_setup(2); + + let none_origin = RuntimeOrigin::none(); + + // Wrong address (not deployed) + let contract_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x03e437FB56Bb213f5708Fcd6966502070e276c093ec271aA33433b89E21fd32f").unwrap(), + )); + + let mut transaction = get_invoke_v3_dummy(Starknet::chain_id(), NONCE_ZERO); + if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx { + tx.sender_address = contract_address; + }; + + assert_err!(Starknet::invoke(none_origin, transaction), Error::::AccountNotDeployed); + }) +} + +#[test] +fn given_hardcoded_contract_run_invoke_tx_v3_on_argent_account_then_it_works() { + new_test_ext::().execute_with(|| { + basic_test_setup(2); + let none_origin = RuntimeOrigin::none(); + // NOT WORKING + let chain_id = Starknet::chain_id(); + let mut transaction = get_invoke_v3_argent_dummy(chain_id); + if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx { + tx.signature = sign_message_hash(transaction.tx_hash); + }; + + assert_ok!(Starknet::invoke(none_origin, transaction)); + }); +} + +#[test] +fn given_hardcoded_contract_run_invoke_tx_v3_on_openzeppelin_account_then_it_works() { + new_test_ext::().execute_with(|| { + basic_test_setup(2); + let none_origin = RuntimeOrigin::none(); + // NOT WORKING + let transaction = get_invoke_v3_openzeppelin_dummy(Starknet::chain_id()); + + assert_ok!(Starknet::invoke(none_origin, transaction)); + }); +} + +#[test] +fn given_hardcoded_contract_run_invoke_tx_v3_on_argent_account_with_incorrect_signature_then_it_fails() { + new_test_ext::().execute_with(|| { + basic_test_setup(2); + let none_origin = RuntimeOrigin::none(); + + let mut transaction = get_invoke_v3_argent_dummy(Starknet::chain_id()); + if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx { + tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]); + }; + + let validate_result = Starknet::validate_unsigned( + TransactionSource::InBlock, + &crate::Call::invoke { transaction: transaction.clone() }, + ); + assert!(matches!(validate_result.unwrap_err(), TransactionValidityError::Invalid(_))); + + assert_err!(Starknet::invoke(none_origin, transaction), Error::::TransactionExecutionFailed); + }); +} + +#[test] +fn given_hardcoded_contract_run_invoke_tx_v3_on_braavos_account_then_it_works() { + new_test_ext::().execute_with(|| { + basic_test_setup(2); + let none_origin = RuntimeOrigin::none(); + // NOT WORKING + let mut transaction = get_invoke_v3_braavos_dummy(Starknet::chain_id()); + if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx { + tx.signature = sign_message_hash(transaction.tx_hash); + }; + + assert_ok!(Starknet::invoke(none_origin, transaction)); + }); +} + +#[test] +fn given_hardcoded_contract_run_invoke_tx_v3_on_braavos_account_with_incorrect_signature_then_it_fails() { + new_test_ext::().execute_with(|| { + basic_test_setup(2); + let none_origin = RuntimeOrigin::none(); + + let mut transaction = get_invoke_v3_braavos_dummy(Starknet::chain_id()); + if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx { + tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]); + }; + + let validate_result = Starknet::validate_unsigned( + TransactionSource::InBlock, + &crate::Call::invoke { transaction: transaction.clone() }, + ); + assert!(matches!(validate_result.unwrap_err(), TransactionValidityError::Invalid(_))); + + assert_err!(Starknet::invoke(none_origin, transaction), Error::::TransactionExecutionFailed); + }); +} + +#[test] +fn given_hardcoded_contract_run_invoke_tx_v3_with_inner_call_in_validate_then_it_fails() { + new_test_ext::().execute_with(|| { + basic_test_setup(2); + let none_origin = RuntimeOrigin::none(); + + let sender_address = get_account_address(None, AccountType::V0(AccountTypeV0Inner::InnerCall)); + let mut transaction = get_invoke_v3_dummy(Starknet::chain_id(), NONCE_ZERO); + if let starknet_api::transaction::InvokeTransaction::V3(tx) = &mut transaction.tx { + tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]); + tx.sender_address = sender_address; + }; + + let storage_key = get_storage_var_address("destination", &[]); + let destination = StarkFelt::try_from(TEST_CONTRACT_ADDRESS).unwrap(); + StorageView::::insert((sender_address, storage_key), destination); + + let storage_key = get_storage_var_address("function_selector", &[]); + let selector = get_selector_from_name("without_arg").unwrap(); + StorageView::::insert( + (sender_address, storage_key), + StarkFelt::from(Felt252Wrapper::from(selector)), + ); + + assert_err!(Starknet::invoke(none_origin, transaction), Error::::TransactionExecutionFailed); + }); +} + +#[test] +fn given_account_not_deployed_invoke_tx_v3_validate_works_for_nonce_one() { + new_test_ext::().execute_with(|| { + basic_test_setup(2); + // Wrong address (not deployed) + let contract_address = ContractAddress(PatriciaKey(StarkFelt::try_from("0x13123131").unwrap())); + // NOT WORKING + let transaction = starknet_api::transaction::InvokeTransactionV3 { + resource_bounds: create_resource_bounds(), + tip: starknet_api::transaction::Tip::default(), + calldata: Calldata::default(), + sender_address: contract_address, + nonce: Nonce(StarkFelt::ZERO), + signature: TransactionSignature::default(), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: starknet_api::transaction::PaymasterData(vec![StarkFelt::ZERO]), + account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![StarkFelt::ZERO]), + }; + + set_infinite_tokens::(&contract_address); + assert_ok!(Starknet::validate_unsigned( + TransactionSource::InBlock, + &crate::Call::invoke { transaction: transaction.into() } + )); + }) +} + +#[test] +fn given_account_not_deployed_invoke_tx_v3_fails_for_nonce_not_one() { + new_test_ext::().execute_with(|| { + basic_test_setup(2); + + // Wrong address (not deployed) + let contract_address = ContractAddress(PatriciaKey(StarkFelt::try_from("0x13123131").unwrap())); + + let transaction = starknet_api::transaction::InvokeTransactionV3 { + resource_bounds: create_resource_bounds(), + tip: starknet_api::transaction::Tip::default(), + calldata: Calldata::default(), + sender_address: contract_address, + nonce: Nonce(StarkFelt::ZERO), + signature: TransactionSignature::default(), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: starknet_api::transaction::PaymasterData(vec![StarkFelt::ZERO]), + account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![StarkFelt::ZERO]), + }; + + assert_eq!( + Starknet::validate_unsigned( + TransactionSource::InBlock, + &crate::Call::invoke { transaction: transaction.into() } + ), + Err(TransactionValidityError::Invalid(InvalidTransaction::BadProof)) + ); + }) +} diff --git a/crates/pallets/starknet/src/tests/mod.rs b/crates/pallets/starknet/src/tests/mod.rs index c973e911ef..e5abd7d34c 100644 --- a/crates/pallets/starknet/src/tests/mod.rs +++ b/crates/pallets/starknet/src/tests/mod.rs @@ -9,6 +9,7 @@ use mp_transactions::compute_hash::ComputeTransactionHash; use starknet_api::core::{ calculate_contract_address, ClassHash, ContractAddress, EntryPointSelector, Nonce, PatriciaKey, }; +use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::hash::StarkFelt; use starknet_api::transaction::{ Calldata, ContractAddressSalt, DeclareTransactionV0V1, DeployAccountTransactionV1, Fee, TransactionSignature, @@ -20,7 +21,7 @@ use self::mock::{get_account_address, AccountType}; use self::utils::get_contract_class; use crate::blockifier_state_adapter::BlockifierStateAdapter; use crate::tests::mock::account_helper; -use crate::tests::utils::sign_message_hash; +use crate::tests::utils::{create_resource_bounds, sign_message_hash}; use crate::{Config, Nonces}; mod account_helper; @@ -78,6 +79,41 @@ pub fn get_invoke_dummy( blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } +pub fn get_invoke_v3_dummy( + chain_id: Felt252Wrapper, + nonce: Nonce, +) -> blockifier::transaction::transactions::InvokeTransaction { + let signature = TransactionSignature(vec![ + StarkFelt::try_from("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), + StarkFelt::try_from("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), + ]); + let sender_address = + ContractAddress(PatriciaKey(StarkFelt::try_from(constants::BLOCKIFIER_ACCOUNT_ADDRESS).unwrap())); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* contract_address */ + StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector for the `with_arg` external */ + StarkFelt::try_from("0x1").unwrap(), // calldata_len + StarkFelt::try_from("0x19").unwrap(), // calldata[0] + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V3(starknet_api::transaction::InvokeTransactionV3 { + resource_bounds: create_resource_bounds(), + tip: starknet_api::transaction::Tip::default(), + calldata, + sender_address, + nonce, + signature, + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: starknet_api::transaction::PaymasterData(vec![StarkFelt::ZERO]), + account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![StarkFelt::ZERO]), + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } +} + // ref: https://github.com/argentlabs/argent-contracts-starknet/blob/develop/contracts/account/ArgentAccount.cairo fn get_invoke_argent_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { let sender_address = ContractAddress(PatriciaKey( @@ -108,6 +144,40 @@ fn get_invoke_argent_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction: blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } +fn get_invoke_v3_argent_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { + let sender_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x02e63de215f650e9d7e2313c6e9ed26b4f920606fb08576b1663c21a7c4a28c5").unwrap(), + )); + let nonce = Nonce(StarkFelt::ZERO); + let signature = TransactionSignature::default(); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x1").unwrap(), // call_array_len + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to + StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), // selector + StarkFelt::try_from("0x0").unwrap(), // data_offset + StarkFelt::try_from("0x1").unwrap(), // data_len + StarkFelt::try_from("0x1").unwrap(), // calldata_len + StarkFelt::try_from("0x19").unwrap(), // calldata[0] + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V3(starknet_api::transaction::InvokeTransactionV3 { + resource_bounds: create_resource_bounds(), + tip: starknet_api::transaction::Tip::default(), + calldata, + sender_address, + nonce, + signature, + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: starknet_api::transaction::PaymasterData(vec![StarkFelt::ZERO]), + account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![StarkFelt::ZERO]), + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } +} + // ref: https://github.com/myBraavos/braavos-account-cairo/blob/develop/src/account/Account.cairo fn get_invoke_braavos_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { let signature = TransactionSignature(vec![ @@ -141,6 +211,44 @@ fn get_invoke_braavos_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } +// ref: https://github.com/myBraavos/braavos-account-cairo/blob/develop/src/account/Account.cairo +fn get_invoke_v3_braavos_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { + let signature = TransactionSignature(vec![ + StarkFelt::try_from("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), + StarkFelt::try_from("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), + ]); + let sender_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x05ef3fba22df259bf84890945352df711bcc9a4e3b6858cb93e9c90d053cf122").unwrap(), + )); + let nonce = Nonce(StarkFelt::ZERO); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x1").unwrap(), // call_array_len + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to + StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), // selector + StarkFelt::try_from("0x0").unwrap(), // data_offset + StarkFelt::try_from("0x1").unwrap(), // data_len + StarkFelt::try_from("0x1").unwrap(), // calldata_len + StarkFelt::try_from("0x19").unwrap(), // calldata[0] + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V3(starknet_api::transaction::InvokeTransactionV3 { + resource_bounds: create_resource_bounds(), + tip: starknet_api::transaction::Tip::default(), + calldata, + sender_address, + nonce, + signature, + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: starknet_api::transaction::PaymasterData(vec![StarkFelt::ZERO]), + account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![StarkFelt::ZERO]), + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } +} + // ref: https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/openzeppelin/token/erc20/IERC20.cairo fn get_invoke_emit_event_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { let signature = TransactionSignature(vec![ @@ -259,6 +367,46 @@ fn get_invoke_openzeppelin_dummy(chain_id: Felt252Wrapper) -> blockifier::transa blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } +// ref: https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/openzeppelin/account/IAccount.cairo +fn get_invoke_v3_openzeppelin_dummy( + chain_id: Felt252Wrapper, +) -> blockifier::transaction::transactions::InvokeTransaction { + let signature = TransactionSignature(vec![ + StarkFelt::try_from("0x028ef1ae6c37314bf9df65663db1cf68f95d67c4b4cf7f6590654933a84912b0").unwrap(), + StarkFelt::try_from("0x0625aae99c58b18e5161c719fef0f99579c6468ca6c1c866f9b2b968a5447e4").unwrap(), + ]); + let sender_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x06e2616a2dceff4355997369246c25a78e95093df7a49e5ca6a06ce1544ffd50").unwrap(), + )); + let nonce = Nonce(StarkFelt::ZERO); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x1").unwrap(), // call_array_len + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to + StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), // selector + StarkFelt::try_from("0x0").unwrap(), // data offset + StarkFelt::try_from("0x1").unwrap(), // data length + StarkFelt::try_from("0x1").unwrap(), // calldata_len + StarkFelt::try_from("0x19").unwrap(), // calldata[0] + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V3(starknet_api::transaction::InvokeTransactionV3 { + resource_bounds: create_resource_bounds(), + tip: starknet_api::transaction::Tip::default(), + calldata, + sender_address, + nonce, + signature, + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: starknet_api::transaction::PaymasterData(vec![StarkFelt::ZERO]), + account_deployment_data: starknet_api::transaction::AccountDeploymentData(vec![StarkFelt::ZERO]), + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } +} + /// Returns a dummy declare transaction for the given account type. /// The declared class hash is a ERC20 contract, class hash calculated /// with starkli. diff --git a/crates/pallets/starknet/src/tests/utils.rs b/crates/pallets/starknet/src/tests/utils.rs index a99d721d01..229b861968 100644 --- a/crates/pallets/starknet/src/tests/utils.rs +++ b/crates/pallets/starknet/src/tests/utils.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::path::PathBuf; use std::str::FromStr; use std::sync::Arc; @@ -29,6 +30,19 @@ pub fn get_contract_class(resource_path: &str, version: u8) -> ContractClass { read_contract_class_from_json(&raw_contract_class, version) } +pub fn create_resource_bounds() -> starknet_api::transaction::ResourceBoundsMapping { + let mut map = BTreeMap::new(); + map.insert( + starknet_api::transaction::Resource::L1Gas, + starknet_api::transaction::ResourceBounds { max_amount: 10000, max_price_per_unit: 12000 }, + ); + map.insert( + starknet_api::transaction::Resource::L1Gas, + starknet_api::transaction::ResourceBounds { max_amount: 50000, max_price_per_unit: 31000 }, + ); + starknet_api::transaction::ResourceBoundsMapping(map) +} + pub fn sign_message_hash_braavos( tx_hash: TransactionHash, actual_impl_hash: StarkHash, diff --git a/starknet-rpc-test/Cargo.toml b/starknet-rpc-test/Cargo.toml index 8eb30d6c60..75bfa4feb1 100644 --- a/starknet-rpc-test/Cargo.toml +++ b/starknet-rpc-test/Cargo.toml @@ -14,6 +14,7 @@ env_logger = "0.9" flate2 = { workspace = true } reqwest = "0.11.18" rstest = "0.18.1" +serde = "1.0.192" serde_json = "1.0.108" starknet-accounts = { workspace = true } starknet-contract = { workspace = true } diff --git a/starknet-rpc-test/get_class.rs b/starknet-rpc-test/get_class.rs index a679f72559..1275927b89 100644 --- a/starknet-rpc-test/get_class.rs +++ b/starknet-rpc-test/get_class.rs @@ -3,7 +3,7 @@ use std::io::Read; use assert_matches::assert_matches; use flate2::read::GzDecoder; use rstest::rstest; -use starknet_core::types::contract::legacy::{LegacyContractClass, LegacyProgram}; +use starknet_core::types::contract::legacy::LegacyContractClass; use starknet_core::types::contract::SierraClass; use starknet_core::types::{BlockId, ContractClass, FlattenedSierraClass, StarknetError}; use starknet_ff::FieldElement; @@ -11,6 +11,7 @@ use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; use starknet_rpc_test::constants::{CAIRO_1_ACCOUNT_CONTRACT_CLASS_HASH, TEST_CONTRACT_CLASS_HASH}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; +use starknet_rpc_test::LegacyProgramWrapper; #[rstest] #[tokio::test] @@ -46,7 +47,7 @@ async fn fail_non_existing_class_hash(madara: &ThreadSafeMadaraClient) -> Result #[rstest] #[tokio::test] -#[ignore = "Waiting for issue #1469 to be solved"] +#[ignore = "Waiting for issue #1585 to be solved"] async fn work_ok_retrieving_class_for_contract_version_0(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; @@ -67,7 +68,8 @@ async fn work_ok_retrieving_class_for_contract_version_0(madara: &ThreadSafeMada let mut gz = GzDecoder::new(&c.program[..]); let mut decompressed_bytes = Vec::new(); gz.read_to_end(&mut decompressed_bytes).unwrap(); - let program: LegacyProgram = serde_json::from_slice(decompressed_bytes.as_slice())?; + let legacy_program_wrapper: LegacyProgramWrapper = serde_json::from_slice(decompressed_bytes.as_slice())?; + let program = legacy_program_wrapper.legacy_program; assert_eq!( program.data.len(), test_contract_class.program.data.len(), diff --git a/starknet-rpc-test/get_class_at.rs b/starknet-rpc-test/get_class_at.rs index 20d2972ac8..5c5f998e69 100644 --- a/starknet-rpc-test/get_class_at.rs +++ b/starknet-rpc-test/get_class_at.rs @@ -3,7 +3,7 @@ use std::io::Read; use assert_matches::assert_matches; use flate2::read::GzDecoder; use rstest::rstest; -use starknet_core::types::contract::legacy::{LegacyContractClass, LegacyProgram}; +use starknet_core::types::contract::legacy::LegacyContractClass; use starknet_core::types::contract::SierraClass; use starknet_core::types::{BlockId, ContractClass, FlattenedSierraClass, StarknetError}; use starknet_ff::FieldElement; @@ -11,6 +11,7 @@ use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; use starknet_rpc_test::constants::{CAIRO_1_ACCOUNT_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; +use starknet_rpc_test::LegacyProgramWrapper; #[rstest] #[tokio::test] @@ -44,7 +45,7 @@ async fn fail_non_existing_contract(madara: &ThreadSafeMadaraClient) -> Result<( #[rstest] #[tokio::test] -#[ignore = "Waiting for issue #1469 to be solved"] +#[ignore = "Waiting for issue #1585 to be solved"] async fn work_ok_retrieving_class_for_contract_version_0(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; @@ -64,7 +65,8 @@ async fn work_ok_retrieving_class_for_contract_version_0(madara: &ThreadSafeMada let mut d = GzDecoder::new(&c.program[..]); let mut data = String::new(); d.read_to_string(&mut data).unwrap(); - let program: LegacyProgram = serde_json::from_str(data.as_str())?; + let legacy_program_wrapper: LegacyProgramWrapper = serde_json::from_str(data.as_str())?; + let program = legacy_program_wrapper.legacy_program; assert_eq!( program.data, test_contract_class.program.data, diff --git a/starknet-rpc-test/src/lib.rs b/starknet-rpc-test/src/lib.rs index 1cdc0a2242..0494678284 100644 --- a/starknet-rpc-test/src/lib.rs +++ b/starknet-rpc-test/src/lib.rs @@ -6,11 +6,13 @@ use std::fmt::Debug; use anyhow::anyhow; use reqwest::header::CONTENT_TYPE; use reqwest::{Client, Response}; +use serde::{de, Deserialize, Deserializer}; use serde_json::json; use starknet_accounts::{ Account, AccountDeployment, AccountError, AccountFactoryError, Declaration, Execution, LegacyDeclaration, OpenZeppelinAccountFactory, SingleOwnerAccount, }; +use starknet_core::types::contract::legacy::LegacyProgram; use starknet_core::types::{DeclareTransactionResult, DeployAccountTransactionResult, InvokeTransactionResult}; use starknet_providers::jsonrpc::{HttpTransport, JsonRpcClient}; use starknet_providers::Provider; @@ -214,3 +216,29 @@ impl MadaraClient { Ok(response.status().is_success()) } } + +pub struct LegacyProgramWrapper { + pub legacy_program: LegacyProgram, +} + +impl<'de> Deserialize<'de> for LegacyProgramWrapper { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value = serde_json::Value::deserialize(deserializer)?; + + // Ensure the required fields are present in the JSON data + let mut json_obj = value.as_object().ok_or_else(|| de::Error::custom("Expected JSON object"))?.clone(); + + // If 'main_scope' field is missing, set it to the default value + if !json_obj.contains_key("main_scope") { + json_obj.insert("main_scope".to_string(), serde_json::Value::String("__main__".to_string())); + } + + // Deserialize the modified JSON data into LegacyProgram + let legacy_program = serde_json::from_value(serde_json::Value::Object(json_obj)).map_err(de::Error::custom)?; + + Ok(LegacyProgramWrapper { legacy_program }) + } +}