diff --git a/Cargo.lock b/Cargo.lock index 4f8cb68eb50..3183a388002 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4882,6 +4882,7 @@ dependencies = [ "http 1.3.1", "serde_json", "starknet_api", + "starknet_committer", "starknet_patricia_storage", "tokio", ] diff --git a/crates/central_systest_blobs/Cargo.toml b/crates/central_systest_blobs/Cargo.toml index 78e7ab0c78d..7354b26064b 100644 --- a/crates/central_systest_blobs/Cargo.toml +++ b/crates/central_systest_blobs/Cargo.toml @@ -20,6 +20,7 @@ google-cloud-storage.workspace = true http.workspace = true serde_json.workspace = true starknet_api = { workspace = true, features = ["testing"] } +starknet_committer = { workspace = true, features = ["testing"] } starknet_patricia_storage = { workspace = true, features = ["testing"] } tokio.workspace = true diff --git a/crates/central_systest_blobs/src/cende_blob_regression_test.rs b/crates/central_systest_blobs/src/cende_blob_regression_test.rs index af8abaeef0f..abe9fcb9d65 100644 --- a/crates/central_systest_blobs/src/cende_blob_regression_test.rs +++ b/crates/central_systest_blobs/src/cende_blob_regression_test.rs @@ -1,12 +1,11 @@ use std::path::PathBuf; -use std::sync::{Arc, LazyLock}; +use std::sync::LazyLock; use std::{env, fs}; use apollo_batcher::cende_client_types::{CendeBlockMetadata, CendePreconfirmedBlock}; use apollo_batcher::pre_confirmed_cende_client::CendeWritePreconfirmedBlock; use apollo_batcher_types::batcher_types::Round; -use apollo_class_manager_types::{MockClassManagerClient, SharedClassManagerClient}; -use apollo_consensus::types::ProposalCommitment; +use apollo_class_manager_types::MockClassManagerClient; use apollo_consensus_orchestrator::cende::{ AerospikeBlob, BlobParameters, @@ -26,15 +25,16 @@ use google_cloud_storage::http::objects::download::Range; use google_cloud_storage::http::objects::get::GetObjectRequest; use google_cloud_storage::http::objects::upload::{Media, UploadObjectRequest, UploadType}; use google_cloud_storage::http::Error as GcsError; -use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockInfo, BlockNumber, BlockTimestamp}; +use starknet_api::block::{BlockHash, BlockInfo, BlockNumber, BlockTimestamp}; use starknet_api::block_hash::block_hash_calculator::PartialBlockHashComponents; use starknet_api::consensus_transaction::InternalConsensusTransaction; use starknet_api::contract_address; use starknet_api::core::{ChainId, OsChainInfo}; use starknet_api::executable_transaction::AccountTransaction as ExecutableAccountTx; use starknet_api::hash::StateRoots; -use starknet_api::state::ThinStateDiff; use starknet_api::test_utils::TEST_SEQUENCER_ADDRESS; +use starknet_committer::db::facts_db::FactsDb; +use starknet_committer::db::forest_trait::StorageInitializer; use starknet_patricia_storage::map_storage::MapStorage; const GCS_ERROR_CODE_NOT_FOUND: u16 = 404; @@ -45,11 +45,8 @@ static BLOBS_GENERATION_FILE: LazyLock = LazyLock::new(|| { PathBuf::from(compile_time_cargo_manifest_dir!()).join("resources/blob_file_generation") }); -const N_TXS_PER_BLOCK: usize = 1; static CHAIN_ID: LazyLock = LazyLock::new(|| ChainId::Other("SN_PREINTEGRATION_SEPOLIA".to_string())); -static CHAIN_INFO: LazyLock = - LazyLock::new(|| ChainInfo { chain_id: CHAIN_ID.clone(), ..ChainInfo::create_for_testing() }); const CHAIN_INFO_PATH: &str = "../resources/chain_info.json"; const PRECONFIRMED_BLOCK_PATH: &str = "../resources/preconfirmed_block.json"; @@ -69,145 +66,135 @@ fn blobs_object_path(generation: usize) -> String { format!("{generation}/{BLOBS_FILE_NAME}") } -// ===================== -// Tx generation -// ===================== - #[expect(dead_code)] -fn boostrap_declare_tx( - _class_manager: &mut MockClassManagerClient, - _contract: FeatureContract, -) -> TxPair { - unimplemented!() +struct BlockData { + block_context: BlockContext, + transactions_with_receipts: Vec, + partial_block_hash_components: PartialBlockHashComponents, + block_hash: BlockHash, + state_maps: StateMaps, + state_roots: StateRoots, } -fn make_txs() -> (MockClassManagerClient, Vec) { - // TODO(Dori): implement. - (MockClassManagerClient::default(), vec![]) -} +struct BlobFactory { + chain_info: ChainInfo, + #[expect(dead_code)] + class_manager: MockClassManagerClient, -// ===================== -// Data generation -// ===================== + // Finalized blocks. + blocks: Vec, -#[expect(dead_code)] -fn make_block_context(block_number: usize) -> BlockContext { - BlockContext::new( - BlockInfo { - block_number: BlockNumber(u64::try_from(block_number).unwrap()), - block_timestamp: BlockTimestamp(1000 + u64::try_from(block_number).unwrap()), - sequencer_address: contract_address!(TEST_SEQUENCER_ADDRESS), - ..Default::default() - }, - CHAIN_INFO.clone(), - VersionedConstants::create_for_testing(), - BouncerConfig::max(), - ) -} + // Transactions for the next block. + #[expect(dead_code)] + next_txs: Vec, -/// Executes the transactions and applies the changes to the state. -#[expect(dead_code)] -fn execute_block( - _state: &mut DictStateReader, - _block_context: &BlockContext, - _old_block_number_and_hash: Option, - _txs: &[TxPair], -) -> (Vec, StateMaps) { - unimplemented!() + // Context. + #[expect(dead_code)] + state: DictStateReader, + #[expect(dead_code)] + committer_storage: FactsDb, } -#[expect(dead_code)] -async fn compute_block_hash_components( - _block_info: &BlockInfo, - _state_diff: &ThinStateDiff, - _txs: &[InternalTransactionWithReceipt], -) -> PartialBlockHashComponents { - unimplemented!() -} +impl BlobFactory { + pub fn new() -> Self { + let chain_info = + ChainInfo { chain_id: CHAIN_ID.clone(), ..ChainInfo::create_for_testing() }; + Self { + chain_info, + class_manager: MockClassManagerClient::default(), + blocks: vec![], + next_txs: vec![], + state: DictStateReader::default(), + committer_storage: FactsDb::new(MapStorage::default()), + } + } -/// Given previous state and partial components, commits the changes and finalizes the block hash. -/// Returns the block hash, the new state roots and the updated committer storage. -#[expect(dead_code)] -async fn compute_block_commitments( - _committer_storage: MapStorage, - _prev_state_roots: &StateRoots, - _state_maps: &StateMaps, - _block_hash_components: PartialBlockHashComponents, - _prev_block_hash: BlockHash, -) -> (BlockHash, StateRoots, MapStorage) { - unimplemented!() -} + /// Executes the unblocked transactions and applies the changes to the state. + #[expect(dead_code)] + fn close_block(&mut self) { + unimplemented!() + } -/// Creates a blob for the given block. -/// If this is not the first block, also sets the parent proposal commitment and populates the -/// recent block hashes with the last block hash (of the previous block). -/// Returns the current proposal commitment and the block hash components (for use in block hash -/// computation of the current block). -#[expect(dead_code)] -async fn make_blob_parameters( - _block_context: &BlockContext, - _txs_with_exec: Vec, - _state_maps: &StateMaps, - _parent_data: (BlockHash, ProposalCommitment), -) -> (BlobParameters, PartialBlockHashComponents, ProposalCommitment) { - unimplemented!() -} + /// Creates blobs for all finalized blocks, and a preconfirmed block with the remaining txs that + /// were not included in a block. + async fn finalize(self) -> (Vec, CendeWritePreconfirmedBlock) { + // TODO(Dori): Create the blob vector. + let blobs = vec![]; -/// Creates a preconfirmed block for the given block. Should be called for the last block only - no -/// commitment is computed. -fn make_preconfirmed_block( - block_number: usize, - _state: &mut DictStateReader, - _txs: &[TxPair], -) -> CendeWritePreconfirmedBlock { - // TODO(Dori): implement. - CendeWritePreconfirmedBlock { - block_number: BlockNumber(u64::try_from(block_number).unwrap()), - round: Round::default(), - write_iteration: 0, - pre_confirmed_block: CendePreconfirmedBlock { - metadata: CendeBlockMetadata::new(BlockInfo::default()), - transactions: vec![], - transaction_receipts: vec![], - transaction_state_diffs: vec![], - }, + // For the last block, create a preconfirmed block. + let preconfirmed_block = self.make_preconfirmed_block_from_remaining_txs(); + + (blobs, preconfirmed_block) } -} -/// Given a list of blocks (block number and contents), executes the transactions and creates the -/// blobs. -async fn make_blobs( - _blocks_to_commit: &[(usize, &[TxPair])], - _state: &mut DictStateReader, - _shared_class_manager: SharedClassManagerClient, -) -> Vec { - // TODO(Dori): implement. - vec![] -} + #[expect(dead_code)] + fn last_finalized_block_hash(&self) -> BlockHash { + self.blocks.last().map(|block| block.block_hash).unwrap_or(BlockHash::GENESIS_PARENT_HASH) + } -/// Generates a fixed set of blob data, and one preconfirmed block, with a deterministic list of -/// transactions. -async fn make_data() -> (Vec, CendeWritePreconfirmedBlock) { - let (class_manager, transactions) = make_txs(); - let shared_class_manager = Arc::new(class_manager); - let mut state = DictStateReader::default(); + #[expect(dead_code)] + fn last_finalized_state_roots(&self) -> StateRoots { + self.blocks.last().map(|block| block.state_roots).unwrap_or_default() + } - // TODO(Dori): remove this case, it should never happen when the test is done. - if transactions.is_empty() { - (vec![], make_preconfirmed_block(0, &mut state, &[])) - } else { - let block_iterator = transactions.chunks(N_TXS_PER_BLOCK).enumerate().collect::>(); - // Split the block iterator into two iterators: one for the blocks to be committed, and one - // for the last block. - let (blocks_to_commit, last_block) = block_iterator.split_at(block_iterator.len() - 1); - let (last_block_number, last_block_txs) = last_block.last().unwrap(); + // ===================== + // Tx generation + // ===================== - let blobs = make_blobs(blocks_to_commit, &mut state, shared_class_manager.clone()).await; - // For the last block, create a preconfirmed block. - let preconfirmed_block = - make_preconfirmed_block(*last_block_number, &mut state, last_block_txs); + #[expect(dead_code)] + fn boostrap_declare_tx(&mut self, _contract: FeatureContract) { + unimplemented!() + } - (blobs, preconfirmed_block) + // ===================== + // Data generation + // ===================== + + fn next_block_number(&self) -> usize { + self.blocks.len() + } + + #[expect(dead_code)] + fn next_block_context(&self) -> BlockContext { + let block_number = BlockNumber(u64::try_from(self.blocks.len()).unwrap()); + BlockContext::new( + BlockInfo { + block_number, + block_timestamp: BlockTimestamp(1000 + block_number.0), + sequencer_address: contract_address!(TEST_SEQUENCER_ADDRESS), + ..Default::default() + }, + self.chain_info.clone(), + VersionedConstants::create_for_testing(), + BouncerConfig::max(), + ) + } + + /// Creates a blob for the given block. + /// If this is not the first block, also sets the parent proposal commitment and populates the + /// recent block hashes with the last block hash (of the previous block). + /// Returns the current proposal commitment and the block hash components (for use in block hash + /// computation of the current block). + #[expect(dead_code)] + async fn make_blob_parameters(&self, _block: &BlockData) -> BlobParameters { + unimplemented!() + } + + /// Creates a preconfirmed block for the given block. Should be called for the last block only - + /// no commitment is computed. + fn make_preconfirmed_block_from_remaining_txs(&self) -> CendeWritePreconfirmedBlock { + // TODO(Dori): implement. + CendeWritePreconfirmedBlock { + block_number: BlockNumber(u64::try_from(self.next_block_number()).unwrap()), + round: Round::default(), + write_iteration: 0, + pre_confirmed_block: CendePreconfirmedBlock { + metadata: CendeBlockMetadata::new(BlockInfo::default()), + transactions: vec![], + transaction_receipts: vec![], + transaction_state_diffs: vec![], + }, + } } } @@ -286,8 +273,10 @@ async fn fetch_blob_file(client: &Client) -> Vec { #[tokio::test] async fn test_make_data() { - let (blobs, preconfirmed_block) = make_data().await; - let chain_info = OsChainInfo::from(&*CHAIN_INFO).to_hex_map(); + let blob_factory = BlobFactory::new(); + let chain_info = OsChainInfo::from(&blob_factory.chain_info).to_hex_map(); + // TODO(Dori): create txs. + let (blobs, preconfirmed_block) = blob_factory.finalize().await; expect_file![CHAIN_INFO_PATH].assert_eq(&serde_json::to_string_pretty(&chain_info).unwrap()); expect_file![PRECONFIRMED_BLOCK_PATH] .assert_eq(&serde_json::to_string_pretty(&preconfirmed_block).unwrap());