Skip to content
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/central_systest_blobs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
253 changes: 121 additions & 132 deletions crates/central_systest_blobs/src/cende_blob_regression_test.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand All @@ -45,11 +45,8 @@ static BLOBS_GENERATION_FILE: LazyLock<PathBuf> = 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<ChainId> =
LazyLock::new(|| ChainId::Other("SN_PREINTEGRATION_SEPOLIA".to_string()));
static CHAIN_INFO: LazyLock<ChainInfo> =
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";
Expand All @@ -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<InternalTransactionWithReceipt>,
partial_block_hash_components: PartialBlockHashComponents,
block_hash: BlockHash,
state_maps: StateMaps,
state_roots: StateRoots,
}

fn make_txs() -> (MockClassManagerClient, Vec<TxPair>) {
// TODO(Dori): implement.
(MockClassManagerClient::default(), vec![])
}
struct BlobFactory {
chain_info: ChainInfo,
#[expect(dead_code)]
class_manager: MockClassManagerClient,

// =====================
// Data generation
// =====================
// Finalized blocks.
blocks: Vec<BlockData>,

#[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<TxPair>,

/// 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<BlockHashAndNumber>,
_txs: &[TxPair],
) -> (Vec<InternalTransactionWithReceipt>, StateMaps) {
unimplemented!()
// Context.
#[expect(dead_code)]
state: DictStateReader,
#[expect(dead_code)]
committer_storage: FactsDb<MapStorage>,
}

#[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<InternalTransactionWithReceipt>,
_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<AerospikeBlob>, 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<AerospikeBlob> {
// 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<AerospikeBlob>, 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::<Vec<_>>();
// 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![],
},
}
}
}

Expand Down Expand Up @@ -286,8 +273,10 @@ async fn fetch_blob_file(client: &Client) -> Vec<AerospikeBlob> {

#[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());
Expand Down
Loading