From 32dc9248e1b2e99557c59089b2f15bdd83446fab Mon Sep 17 00:00:00 2001 From: AvivYossef-starkware <141143145+AvivYossef-starkware@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:46:30 +0300 Subject: [PATCH] build: blockifier regression test serde rpc tx to starknet api tx (#1021) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is [Reviewable](https://reviewable.io/reviews/starkware-libs/sequencer/1021) --- .../raw_rpc_json_objects/transactions.json | 73 +++++++++++++++++++ .../src/state_reader/raw_rpc_json_test.rs | 20 +++++ .../src/state_reader/rpc_https_test.rs | 20 ++++- .../src/state_reader/test_state_reader.rs | 26 ++++++- .../src/state_reader/utils.rs | 65 +++++++++++++++++ 5 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 crates/blockifier_regression_test/resources/raw_rpc_json_objects/transactions.json diff --git a/crates/blockifier_regression_test/resources/raw_rpc_json_objects/transactions.json b/crates/blockifier_regression_test/resources/raw_rpc_json_objects/transactions.json new file mode 100644 index 0000000000..fbdfc3e4aa --- /dev/null +++ b/crates/blockifier_regression_test/resources/raw_rpc_json_objects/transactions.json @@ -0,0 +1,73 @@ +{ + "invoke_v1": { + "calldata": [ + "0x1", + "0x422d33a3638dcc4c62e72e1d6942cd31eb643ef596ccac2351e0e21f6cd4bf4", + "0xcaffbd1bd76bd7f24a3fa1d69d1b2588a86d1f9d2359b13f6a84b7e1cbd126", + "0x5", + "0x5265736f6c766552616e646f6d4576656e74", + "0x3", + "0x0", + "0x1", + "0x10c3" + ], + "max_fee": "0x65f2d0057b2", + "nonce": "0x4d8", + "sender_address": "0x4e6989d518d5eb7e516dc5673f855fe7c5cfece1880a1047d6a8e8465be0d69", + "signature": [ + "0x59b7462ea9566750ab7d7d08acbb6d339bfda921b053f1f8a5fd6b96c3656f9", + "0x2f11c36d10a03f21be918a5feeeb9922c11a2713fecd51f5e6bac5167856ecb" + ], + "transaction_hash": "0x47165a9a9c97e8829a4778f2a4b6fae4366aefc35b51d484bf04c458168351b", + "type": "INVOKE", + "version": "0x1" + }, + "invoke_v3": { + "account_deployment_data": [], + "calldata": [ + "0x2", + "0x4878d1148318a31829523ee9c6a5ee563af6cd87f90a30809e5b0d27db8a9b", + "0xa72371689866be053cc37a071de4216af73c9ffff96319b2576f7bf1e15290", + "0x4", + "0x2cb8f1439c83d9856179cbeae626e676bbb9b68e0bdda5423aa1988018acebe", + "0xba43b7400", + "0x2750a0009", + "0x422d33a3638dcc4c62e72e1d6942cd31eb643ef596ccac2351e0e21f6cd4bf4", + "0x422d33a3638dcc4c62e72e1d6942cd31eb643ef596ccac2351e0e21f6cd4bf4", + "0xcaffbd1bd76bd7f24a3fa1d69d1b2588a86d1f9d2359b13f6a84b7e1cbd126", + "0x6", + "0x41636365707444656c6976657279", + "0x4", + "0x9", + "0x2750a", + "0x1", + "0xcf" + ], + "fee_data_availability_mode": "L1", + "nonce": "0x1412", + "nonce_data_availability_mode": "L1", + "paymaster_data": [], + "resource_bounds": { + "l1_gas": { + "max_amount": "0x368", + "max_price_per_unit": "0x13bca990eeea" + }, + "l2_gas": { + "max_amount": "0x0", + "max_price_per_unit": "0x0" + } + }, + "sender_address": "0x614872dd2f3324f3e9a047d0cfaab9e9573bbdfa6081877f49f7108116b8ae0", + "signature": [ + "0x1", + "0x0", + "0x61050eb8efaa6db97248c8c987c1a9df82527c26c204681396108cbd5babaf8", + "0x358bc995a221c3aa96cf2a1e6b5b8959b6d626b6fe89381d627f378dc39402a", + "0xf247079c5e0c5be56f4c0f37452304dc63b4b883b89d5a66e3202a855515ef" + ], + "tip": "0x0", + "transaction_hash": "0xa7c7db686c7f756ceb7ca85a759caef879d425d156da83d6a836f86851983", + "type": "INVOKE", + "version": "0x3" + } +} \ No newline at end of file diff --git a/crates/blockifier_regression_test/src/state_reader/raw_rpc_json_test.rs b/crates/blockifier_regression_test/src/state_reader/raw_rpc_json_test.rs index 8b799cc99d..96b6dcfce3 100644 --- a/crates/blockifier_regression_test/src/state_reader/raw_rpc_json_test.rs +++ b/crates/blockifier_regression_test/src/state_reader/raw_rpc_json_test.rs @@ -1,12 +1,15 @@ +use assert_matches::assert_matches; use blockifier::blockifier::block::BlockInfo; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; use starknet_api::block::BlockNumber; use starknet_api::test_utils::read_json_file; +use starknet_api::transaction::{InvokeTransaction, Transaction}; use starknet_core::types::ContractClass; use starknet_gateway::rpc_objects::BlockHeader; use crate::state_reader::compile::legacy_to_contract_class_v0; +use crate::state_reader::utils::deserialize_transaction_json_to_starknet_api_tx; #[fixture] fn block_header() -> BlockHeader { @@ -45,3 +48,20 @@ fn test_compile_deprecated_contract_class(deprecated_contract_class: ContractCla _ => panic!("Expected a legacy contract class"), } } + +#[test] +fn deserialize_invoke_txs() { + let invoke_tx_v1 = deserialize_transaction_json_to_starknet_api_tx( + read_json_file("raw_rpc_json_objects/transactions.json")["invoke_v1"].clone(), + ) + .expect("Failed to deserialize invoke v1 tx"); + + assert_matches!(invoke_tx_v1, Transaction::Invoke(InvokeTransaction::V1(..))); + + let invoke_tx_v3 = deserialize_transaction_json_to_starknet_api_tx( + read_json_file("raw_rpc_json_objects/transactions.json")["invoke_v3"].clone(), + ) + .expect("Failed to deserialize invoke v3 tx"); + + assert_matches!(invoke_tx_v3, Transaction::Invoke(InvokeTransaction::V3(..))); +} diff --git a/crates/blockifier_regression_test/src/state_reader/rpc_https_test.rs b/crates/blockifier_regression_test/src/state_reader/rpc_https_test.rs index 7bc7e60cb5..b0144724d7 100644 --- a/crates/blockifier_regression_test/src/state_reader/rpc_https_test.rs +++ b/crates/blockifier_regression_test/src/state_reader/rpc_https_test.rs @@ -6,15 +6,24 @@ use rstest::{fixture, rstest}; use starknet_api::block::BlockNumber; use starknet_api::core::ClassHash; use starknet_api::test_utils::read_json_file; +use starknet_api::transaction::Transaction; use starknet_api::{class_hash, felt}; use starknet_core::types::ContractClass::{Legacy, Sierra}; use crate::state_reader::compile::legacy_to_contract_class_v0; use crate::state_reader::test_state_reader::TestStateReader; +const EXAMPLE_INVOKE_TX_HASH: &str = + "0xa7c7db686c7f756ceb7ca85a759caef879d425d156da83d6a836f86851983"; + +const EXAMPLE_BLOCK_NUMBER: u64 = 700000; + +const EXAMPLE_CONTACT_CLASS_HASH: &str = + "0x3131fa018d520a037686ce3efddeab8f28895662f019ca3ca18a626650f7d1e"; + #[fixture] pub fn test_block_number() -> BlockNumber { - BlockNumber(700000) + BlockNumber(EXAMPLE_BLOCK_NUMBER) } #[fixture] @@ -38,8 +47,7 @@ pub fn test_get_starknet_version(test_state_reader: TestStateReader) { #[rstest] pub fn test_get_contract_class(test_state_reader: TestStateReader, test_block_number: BlockNumber) { // An example of existing class hash in Mainnet. - let class_hash = - class_hash!("0x3131fa018d520a037686ce3efddeab8f28895662f019ca3ca18a626650f7d1e"); + let class_hash = class_hash!(EXAMPLE_CONTACT_CLASS_HASH); // Test getting the contract class using RPC request. let deprecated_contract_class = @@ -74,3 +82,9 @@ pub fn test_get_tx_hashes(test_state_reader: TestStateReader, test_block_number: }); assert_eq!(actual_tx_hashes, expected_tx_hashes); } + +#[rstest] +pub fn test_get_tx_by_hash(test_state_reader: TestStateReader) { + let actual_tx = test_state_reader.get_tx_by_hash(EXAMPLE_INVOKE_TX_HASH).unwrap(); + assert_matches!(actual_tx, Transaction::Invoke(..)); +} diff --git a/crates/blockifier_regression_test/src/state_reader/test_state_reader.rs b/crates/blockifier_regression_test/src/state_reader/test_state_reader.rs index 17c89b436e..2bb67ac64e 100644 --- a/crates/blockifier_regression_test/src/state_reader/test_state_reader.rs +++ b/crates/blockifier_regression_test/src/state_reader/test_state_reader.rs @@ -12,6 +12,7 @@ use serde_json::{json, to_value}; use starknet_api::block::{BlockNumber, GasPrice}; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; +use starknet_api::transaction::Transaction; use starknet_core::types::ContractClass as StarknetContractClass; use starknet_core::types::ContractClass::{Legacy, Sierra}; use starknet_gateway::config::RpcStateReaderConfig; @@ -21,7 +22,11 @@ use starknet_gateway::rpc_state_reader::RpcStateReader; use starknet_types_core::felt::Felt; use crate::state_reader::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1}; -use crate::state_reader::utils::{get_chain_info, get_rpc_state_reader_config}; +use crate::state_reader::utils::{ + deserialize_transaction_json_to_starknet_api_tx, + get_chain_info, + get_rpc_state_reader_config, +}; pub struct TestStateReader(RpcStateReader); @@ -120,6 +125,15 @@ impl TestStateReader { serde_json::from_value(raw_tx_hashes).map_err(serde_err_to_state_err) } + pub fn get_tx_by_hash(&self, tx_hash: &str) -> StateResult { + let method = "starknet_getTransactionByHash"; + let params = json!({ + "transaction_hash": tx_hash, + }); + deserialize_transaction_json_to_starknet_api_tx(self.0.send_rpc_request(method, params)?) + .map_err(serde_err_to_state_err) + } + pub fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult { let params = json!({ "block_id": self.0.block_id, @@ -131,6 +145,16 @@ impl TestStateReader { Ok(contract_class) } + pub fn get_all_txs_in_block(&self) -> StateResult> { + // TODO(Aviv): Use batch request to get all txs in a block. + let txs: Vec<_> = self + .get_tx_hashes()? + .iter() + .map(|tx_hash| self.get_tx_by_hash(tx_hash)) + .collect::>()?; + Ok(txs) + } + pub fn get_versioned_constants(&self) -> StateResult<&'static VersionedConstants> { Ok(self.get_starknet_version()?.into()) } diff --git a/crates/blockifier_regression_test/src/state_reader/utils.rs b/crates/blockifier_regression_test/src/state_reader/utils.rs index 31b77b7eef..5f94c0b05a 100644 --- a/crates/blockifier_regression_test/src/state_reader/utils.rs +++ b/crates/blockifier_regression_test/src/state_reader/utils.rs @@ -1,6 +1,13 @@ use blockifier::context::{ChainInfo, FeeTokenAddresses}; use papyrus_execution::{ETH_FEE_CONTRACT_ADDRESS, STRK_FEE_CONTRACT_ADDRESS}; +use serde_json::Value; use starknet_api::core::{ChainId, ContractAddress, PatriciaKey}; +use starknet_api::transaction::{ + DeclareTransaction, + DeployAccountTransaction, + InvokeTransaction, + Transaction, +}; use starknet_api::{contract_address, felt, patricia_key}; use starknet_gateway::config::RpcStateReaderConfig; @@ -27,3 +34,61 @@ pub fn get_rpc_state_reader_config() -> RpcStateReaderConfig { pub fn get_chain_info() -> ChainInfo { ChainInfo { chain_id: ChainId::Mainnet, fee_token_addresses: get_fee_token_addresses() } } + +pub fn deserialize_transaction_json_to_starknet_api_tx( + mut raw_transaction: Value, +) -> serde_json::Result { + let tx_type: String = serde_json::from_value(raw_transaction["type"].clone())?; + let tx_version: String = serde_json::from_value(raw_transaction["version"].clone())?; + + match (tx_type.as_str(), tx_version.as_str()) { + ("INVOKE", "0x0") => { + Ok(Transaction::Invoke(InvokeTransaction::V0(serde_json::from_value(raw_transaction)?))) + } + ("INVOKE", "0x1") => { + Ok(Transaction::Invoke(InvokeTransaction::V1(serde_json::from_value(raw_transaction)?))) + } + ("INVOKE", "0x3") => { + let resource_bounds = raw_transaction + .get_mut("resource_bounds") + .expect("Invoke v3 tx should contain resource_bounds field") + .as_object_mut() + .expect("resource_bounds should be an object"); + + // In old invoke v3 transaction, the resource bounds names are lowercase. + // need to convert to uppercase for deserialization to work. + if let Some(l1_gas_value) = resource_bounds.remove("l1_gas") { + resource_bounds.insert("L1_GAS".to_string(), l1_gas_value); + + let l2_gas_value = resource_bounds + .remove("l2_gas") + .expect("If invoke v3 tx contains l1_gas, it should contain l2_gas"); + resource_bounds.insert("L2_GAS".to_string(), l2_gas_value); + } + + Ok(Transaction::Invoke(InvokeTransaction::V3(serde_json::from_value(raw_transaction)?))) + } + ("DEPLOY_ACCOUNT", "0x1") => Ok(Transaction::DeployAccount(DeployAccountTransaction::V1( + serde_json::from_value(raw_transaction)?, + ))), + ("DEPLOY_ACCOUNT", "0x3") => Ok(Transaction::DeployAccount(DeployAccountTransaction::V3( + serde_json::from_value(raw_transaction)?, + ))), + ("DECLARE", "0x0") => Ok(Transaction::Declare(DeclareTransaction::V0( + serde_json::from_value(raw_transaction)?, + ))), + ("DECLARE", "0x1") => Ok(Transaction::Declare(DeclareTransaction::V1( + serde_json::from_value(raw_transaction)?, + ))), + ("DECLARE", "0x2") => Ok(Transaction::Declare(DeclareTransaction::V2( + serde_json::from_value(raw_transaction)?, + ))), + ("DECLARE", "0x3") => Ok(Transaction::Declare(DeclareTransaction::V3( + serde_json::from_value(raw_transaction)?, + ))), + ("L1_HANDLER", _) => Ok(Transaction::L1Handler(serde_json::from_value(raw_transaction)?)), + (tx_type, tx_version) => Err(serde::de::Error::custom(format!( + "unimplemented transaction type: {tx_type} version: {tx_version}" + ))), + } +}