diff --git a/crates/blockifier/Cargo.toml b/crates/blockifier/Cargo.toml index 69bfac8392..80f8e7f912 100644 --- a/crates/blockifier/Cargo.toml +++ b/crates/blockifier/Cargo.toml @@ -10,6 +10,7 @@ description = "The transaction-executing component in the Starknet sequencer." workspace = true [features] +reexecution = [] cairo_native = ["dep:cairo-native"] jemalloc = ["dep:tikv-jemallocator"] testing = ["rand", "rstest", "starknet_api/testing"] diff --git a/crates/blockifier/src/state/cached_state.rs b/crates/blockifier/src/state/cached_state.rs index d9a4a598f6..f78f1b5307 100644 --- a/crates/blockifier/src/state/cached_state.rs +++ b/crates/blockifier/src/state/cached_state.rs @@ -294,6 +294,13 @@ impl Default for CachedState CachedState { + pub fn get_initial_reads(&self) -> StateResult { + Ok(self.cache.borrow().initial_reads.clone()) + } +} + pub type StorageEntry = (ContractAddress, StorageKey); #[derive(Debug, Default, derive_more::IntoIterator)] diff --git a/crates/blockifier_reexecution/Cargo.toml b/crates/blockifier_reexecution/Cargo.toml index a2c9aa164f..7a7c3f3d6d 100644 --- a/crates/blockifier_reexecution/Cargo.toml +++ b/crates/blockifier_reexecution/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true blockifier_regression_https_testing = [] [dependencies] -blockifier = { workspace = true, features = ["transaction_serde"] } +blockifier = { workspace = true, features = ["reexecution", "transaction_serde"] } cairo-lang-starknet-classes.workspace = true cairo-lang-utils.workspace = true clap = { workspace = true, features = ["cargo", "derive"] } diff --git a/crates/blockifier_reexecution/src/main.rs b/crates/blockifier_reexecution/src/main.rs index fabd5de409..03a981ec6a 100644 --- a/crates/blockifier_reexecution/src/main.rs +++ b/crates/blockifier_reexecution/src/main.rs @@ -1,6 +1,8 @@ +use blockifier_reexecution::state_reader::reexecution_state_reader::ReexecutionStateReader; use blockifier_reexecution::state_reader::test_state_reader::{ ConsecutiveStateReaders, ConsecutiveTestStateReaders, + SerializableOfflineReexecutionData, }; use blockifier_reexecution::state_reader::utils::JSON_RPC_VERSION; use clap::{Args, Parser, Subcommand}; @@ -93,6 +95,67 @@ fn main() { println!("RPC test passed successfully."); } - Command::WriteRpcRepliesToJson { .. } => todo!(), + + Command::WriteRpcRepliesToJson { + url_and_block_number: SharedArgs { node_url, block_number }, + directory_path, + } => { + let directory_path = directory_path.unwrap_or(format!( + "./crates/blockifier_reexecution/resources/block_{block_number}/" + )); + + // TODO(Aner): refactor to reduce code duplication. + let config = RpcStateReaderConfig { + url: node_url, + json_rpc_version: JSON_RPC_VERSION.to_string(), + }; + + let ConsecutiveTestStateReaders { last_block_state_reader, next_block_state_reader } = + ConsecutiveTestStateReaders::new(BlockNumber(block_number - 1), Some(config), true); + + let block_info_next_block = next_block_state_reader.get_block_info().unwrap(); + + let starknet_version = next_block_state_reader.get_starknet_version().unwrap(); + + let state_diff_next_block = next_block_state_reader.get_state_diff().unwrap(); + + let transactions_next_block = next_block_state_reader.get_all_txs_in_block().unwrap(); + + let blockifier_transactions_next_block = &last_block_state_reader + .api_txs_to_blockifier_txs_next_block(transactions_next_block.clone()) + .unwrap(); + + let mut transaction_executor = last_block_state_reader + .get_transaction_executor( + next_block_state_reader.get_block_context().unwrap(), + None, + ) + .unwrap(); + + transaction_executor.execute_txs(blockifier_transactions_next_block); + + let block_state = transaction_executor.block_state.unwrap(); + let initial_reads = block_state.get_initial_reads().unwrap(); + + let contract_class_mapping = + block_state.state.get_contract_class_mapping_dumper().unwrap(); + + let serializable_offline_reexecution_data = SerializableOfflineReexecutionData { + state_maps: initial_reads.into(), + block_info_next_block, + starknet_version, + transactions_next_block, + contract_class_mapping, + state_diff_next_block, + }; + + serializable_offline_reexecution_data + .write_to_file(&directory_path, "reexecution_data.json") + .unwrap(); + + println!( + "RPC replies required for reexecuting block {block_number} written to json file." + ); + } } } diff --git a/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs index e0b1b67734..7031825aea 100644 --- a/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/reexecution_state_reader.rs @@ -10,7 +10,7 @@ use super::compile::{legacy_to_contract_class_v0, sierra_to_contact_class_v1}; use crate::state_reader::errors::ReexecutionError; use crate::state_reader::test_state_reader::ReexecutionResult; -pub(crate) trait ReexecutionStateReader { +pub trait ReexecutionStateReader { fn get_contract_class(&self, class_hash: &ClassHash) -> StateResult; fn get_class_info(&self, class_hash: ClassHash) -> ReexecutionResult { @@ -33,7 +33,7 @@ pub(crate) trait ReexecutionStateReader { } // TODO(Aner): extend/refactor to accomodate all types of transactions. - fn api_txs_to_blockifier_txs( + fn api_txs_to_blockifier_txs_next_block( &self, txs_and_hashes: Vec<(Transaction, TransactionHash)>, ) -> ReexecutionResult> { diff --git a/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs b/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs index dbecf79a3f..24f3f0aa03 100644 --- a/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs +++ b/crates/blockifier_reexecution/src/state_reader/rpc_https_test.rs @@ -187,5 +187,7 @@ pub fn test_get_statediff_rpc(test_state_reader: TestStateReader) { #[case(EXAMPLE_DECLARE_V3_BLOCK_NUMBER)] pub fn test_get_all_blockifier_tx_in_block(#[case] block_number: u64) { let state_reader = TestStateReader::new_for_testing(BlockNumber(block_number)); - state_reader.api_txs_to_blockifier_txs(state_reader.get_all_txs_in_block().unwrap()).unwrap(); + state_reader + .api_txs_to_blockifier_txs_next_block(state_reader.get_all_txs_in_block().unwrap()) + .unwrap(); } diff --git a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs index 6bde27404c..cf17d22732 100644 --- a/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs +++ b/crates/blockifier_reexecution/src/state_reader/test_state_reader.rs @@ -54,12 +54,12 @@ pub struct OfflineReexecutionData { #[derive(Serialize, Deserialize)] pub struct SerializableOfflineReexecutionData { - state_maps: ReexecutionStateMaps, - contract_class_mapping: StarknetContractClassMapping, - block_info_next_block: BlockInfo, - starknet_version: StarknetVersion, - transactions_next_block: Vec<(Transaction, TransactionHash)>, - state_diff_next_block: CommitmentStateDiff, + pub state_maps: ReexecutionStateMaps, + pub block_info_next_block: BlockInfo, + pub starknet_version: StarknetVersion, + pub transactions_next_block: Vec<(Transaction, TransactionHash)>, + pub state_diff_next_block: CommitmentStateDiff, + pub contract_class_mapping: StarknetContractClassMapping, } impl SerializableOfflineReexecutionData { @@ -80,7 +80,7 @@ impl From for OfflineReexecutionData { contract_class_mapping: value.contract_class_mapping, }; let transactions_next_block = offline_state_reader_prev_block - .api_txs_to_blockifier_txs(value.transactions_next_block) + .api_txs_to_blockifier_txs_next_block(value.transactions_next_block) .expect("Failed to convert starknet-api transactions to blockifier transactions."); Self { offline_state_reader_prev_block, @@ -299,6 +299,10 @@ impl TestStateReader { class_hash_to_compiled_class_hash: declared_classes, }) } + + pub fn get_contract_class_mapping_dumper(&self) -> Option { + self.contract_class_mapping_dumper.lock().unwrap().clone() + } } impl ReexecutionStateReader for TestStateReader { @@ -372,8 +376,9 @@ impl ConsecutiveStateReaders for ConsecutiveTestStateReaders { } fn get_next_block_txs(&self) -> ReexecutionResult> { - self.next_block_state_reader - .api_txs_to_blockifier_txs(self.next_block_state_reader.get_all_txs_in_block()?) + self.next_block_state_reader.api_txs_to_blockifier_txs_next_block( + self.next_block_state_reader.get_all_txs_in_block()?, + ) } fn get_next_block_state_diff(&self) -> ReexecutionResult { diff --git a/crates/blockifier_reexecution/src/state_reader/utils.rs b/crates/blockifier_reexecution/src/state_reader/utils.rs index 9df4b4d1f6..8417eb5460 100644 --- a/crates/blockifier_reexecution/src/state_reader/utils.rs +++ b/crates/blockifier_reexecution/src/state_reader/utils.rs @@ -49,7 +49,7 @@ pub(crate) fn disjoint_hashmap_union( } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] -pub(crate) struct ReexecutionStateMaps { +pub struct ReexecutionStateMaps { nonces: HashMap, class_hashes: HashMap, storage: HashMap>,