Skip to content

Commit c72a3dc

Browse files
central_systest_blobs: implement block production, given txs
1 parent d63278f commit c72a3dc

3 files changed

Lines changed: 120 additions & 10 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/central_systest_blobs/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ serde_json.workspace = true
2323
starknet_api = { workspace = true, features = ["testing"] }
2424
starknet_committer = { workspace = true, features = ["testing"] }
2525
starknet_patricia_storage = { workspace = true, features = ["testing"] }
26+
starknet_transaction_prover.workspace = true
2627
tokio.workspace = true
2728

2829
[lints]

crates/central_systest_blobs/src/cende_blob_regression_test.rs

Lines changed: 118 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,18 @@ use apollo_consensus_orchestrator::cende::{
1818
InternalTransactionWithReceipt,
1919
};
2020
use apollo_infra_utils::compile_time_cargo_manifest_dir;
21+
use blockifier::abi::constants::STORED_BLOCK_HASH_BUFFER;
22+
use blockifier::blockifier::config::TransactionExecutorConfig;
23+
use blockifier::blockifier::transaction_executor::TransactionExecutor;
2124
use blockifier::blockifier_versioned_constants::VersionedConstants;
2225
use blockifier::bouncer::BouncerConfig;
2326
use blockifier::context::{BlockContext, ChainInfo};
24-
use blockifier::state::cached_state::{CachedState, StateMaps};
27+
use blockifier::state::cached_state::{CachedState, CommitmentStateDiff, StateMaps};
28+
use blockifier::state::state_api::UpdatableState;
2529
use blockifier::test_utils::contracts::FeatureContractTrait;
2630
use blockifier::test_utils::dict_state_reader::DictStateReader;
2731
use blockifier::transaction::account_transaction::AccountTransaction as BlockifierAccountTx;
32+
use blockifier::transaction::transaction_execution::Transaction as BlockifierTx;
2833
use blockifier::transaction::transactions::ExecutableTransaction;
2934
use blockifier_test_utils::contracts::FeatureContract;
3035
use expect_test::expect_file;
@@ -35,23 +40,30 @@ use google_cloud_storage::http::objects::get::GetObjectRequest;
3540
use google_cloud_storage::http::objects::upload::{Media, UploadObjectRequest, UploadType};
3641
use google_cloud_storage::http::Error as GcsError;
3742
use mockall::predicate::eq;
38-
use starknet_api::block::{BlockHash, BlockInfo, BlockNumber, BlockTimestamp};
39-
use starknet_api::block_hash::block_hash_calculator::PartialBlockHashComponents;
43+
use starknet_api::block::{BlockHash, BlockHashAndNumber, BlockInfo, BlockNumber, BlockTimestamp};
44+
use starknet_api::block_hash::block_hash_calculator::{
45+
calculate_block_commitments,
46+
calculate_block_hash,
47+
PartialBlockHashComponents,
48+
TransactionHashingData,
49+
};
4050
use starknet_api::consensus_transaction::InternalConsensusTransaction;
4151
use starknet_api::contract_address;
4252
use starknet_api::contract_class::compiled_class_hash::HashVersion;
4353
use starknet_api::core::{ChainId, Nonce, OsChainInfo};
44-
use starknet_api::data_availability::DataAvailabilityMode;
54+
use starknet_api::data_availability::{DataAvailabilityMode, L1DataAvailabilityMode};
4555
use starknet_api::executable_transaction::{
4656
AccountTransaction as ExecutableAccountTx,
4757
DeclareTransaction as ExecutableDeclareTransaction,
58+
Transaction as ExecutableTx,
4859
};
4960
use starknet_api::hash::StateRoots;
5061
use starknet_api::rpc_transaction::{
5162
InternalRpcDeclareTransactionV3,
5263
InternalRpcTransaction,
5364
InternalRpcTransactionWithoutTxHash,
5465
};
66+
use starknet_api::state::ThinStateDiff;
5567
use starknet_api::test_utils::TEST_SEQUENCER_ADDRESS;
5668
use starknet_api::transaction::fields::{
5769
AccountDeploymentData,
@@ -66,9 +78,11 @@ use starknet_api::transaction::{
6678
TransactionOffsetInBlock,
6779
TransactionVersion,
6880
};
81+
use starknet_committer::block_committer::input::StateDiff;
6982
use starknet_committer::db::facts_db::FactsDb;
7083
use starknet_committer::db::forest_trait::StorageInitializer;
7184
use starknet_patricia_storage::map_storage::MapStorage;
85+
use starknet_transaction_prover::running::committer_utils::commit_state_diff;
7286

7387
const GCS_ERROR_CODE_NOT_FOUND: u16 = 404;
7488

@@ -121,7 +135,6 @@ struct BlobFactory {
121135

122136
// Context.
123137
state: DictStateReader,
124-
#[expect(dead_code)]
125138
committer_storage: FactsDb<MapStorage>,
126139
}
127140

@@ -140,13 +153,110 @@ impl BlobFactory {
140153
}
141154

142155
/// Executes the unblocked transactions and applies the changes to the state.
156+
/// Any subsequent tx added will end up in the next block.
143157
#[expect(dead_code)]
144-
fn close_block(&mut self) {
145-
unimplemented!()
158+
async fn close_block(&mut self) {
159+
let block_context = self.next_block_context();
160+
let block_info = block_context.block_info().clone();
161+
let block_number = block_info.block_number;
162+
163+
// Execute the txs.
164+
// If the block number is after the block hash buffer, set the previous block hash and
165+
// number, so they appear in the state diff.
166+
let old_block_number_and_hash = if block_number.0 < STORED_BLOCK_HASH_BUFFER {
167+
None
168+
} else {
169+
let old_block_number = block_number.0 - STORED_BLOCK_HASH_BUFFER;
170+
Some(BlockHashAndNumber {
171+
number: BlockNumber(old_block_number),
172+
// If we are past the block hash buffer, this should never panic.
173+
hash: self.blocks[usize::try_from(old_block_number).unwrap()].block_hash,
174+
})
175+
};
176+
let state_clone = self.state.clone();
177+
let mut executor = TransactionExecutor::pre_process_and_create(
178+
state_clone,
179+
block_context.clone(),
180+
old_block_number_and_hash,
181+
TransactionExecutorConfig::create_for_testing(false),
182+
)
183+
.unwrap();
184+
let mut transactions_with_receipts = Vec::new();
185+
for (executable, internal) in self.next_txs.iter() {
186+
let (execution_info, _state_changes) = executor
187+
.execute(&BlockifierTx::new_for_sequencing(ExecutableTx::Account(
188+
executable.clone(),
189+
)))
190+
.unwrap();
191+
assert!(!execution_info.is_reverted(), "Got a reverted tx: {execution_info:?}");
192+
193+
transactions_with_receipts.push(InternalTransactionWithReceipt {
194+
transaction: internal.clone(),
195+
execution_info,
196+
});
197+
}
198+
let summary = executor.non_consuming_finalize().unwrap();
199+
200+
// Apply changes to state and create the multitude of state-diff-like objects required...
201+
// The [CommitterStateDiff] type is the blockifier representation of the committer's state
202+
// diff, whereas [StateDiff] is the committer's representation of the state diff.
203+
let committer_state_diff: CommitmentStateDiff = summary.state_diff.clone();
204+
let thin_state_diff = ThinStateDiff::from(committer_state_diff.clone());
205+
let state_diff = StateDiff::from(thin_state_diff.clone());
206+
let state_maps = StateMaps::from(committer_state_diff.clone());
207+
let class_mapping = executor.block_state.unwrap().class_hash_to_class.borrow().clone();
208+
self.state.apply_writes(&state_maps, &class_mapping);
209+
210+
// Commit the block.
211+
let prev_state_roots = self.current_state_roots();
212+
let state_roots = commit_state_diff(
213+
&mut self.committer_storage,
214+
prev_state_roots.contracts_trie_root_hash,
215+
prev_state_roots.classes_trie_root_hash,
216+
state_diff,
217+
)
218+
.await
219+
.expect("Failed to commit state diff.");
220+
221+
// Compute the block hash.
222+
let transaction_hashing_data: Vec<_> = transactions_with_receipts
223+
.iter()
224+
.map(|tx| TransactionHashingData {
225+
transaction_signature: tx.transaction.tx_signature_for_commitment().unwrap(),
226+
transaction_output: tx.execution_info.output_for_hashing(),
227+
transaction_hash: tx.transaction.tx_hash(),
228+
})
229+
.collect();
230+
let (block_header_commitments, _) = calculate_block_commitments(
231+
&transaction_hashing_data,
232+
thin_state_diff,
233+
L1DataAvailabilityMode::from_use_kzg_da(block_info.use_kzg_da),
234+
&block_info.starknet_version,
235+
)
236+
.await;
237+
let partial_block_hash_components =
238+
PartialBlockHashComponents::new(&block_info, block_header_commitments);
239+
let block_hash = calculate_block_hash(
240+
&partial_block_hash_components,
241+
state_roots.global_root(),
242+
self.parent_block_hash(),
243+
)
244+
.unwrap();
245+
246+
// Create block data, and update context.
247+
self.blocks.push(BlockData {
248+
block_context,
249+
transactions_with_receipts,
250+
partial_block_hash_components,
251+
block_hash,
252+
state_maps,
253+
state_roots,
254+
});
255+
self.next_txs.clear();
146256
}
147257

148258
/// Creates blobs for all finalized blocks, and a preconfirmed block with the remaining txs that
149-
/// were not included in a block.
259+
/// were not included in a block. See [Self::close_block] for details on how to close a block.
150260
async fn finalize(self) -> (Vec<AerospikeBlob>, CendeWritePreconfirmedBlock) {
151261
// TODO(Dori): Create the blob vector.
152262
let blobs = vec![];
@@ -157,12 +267,10 @@ impl BlobFactory {
157267
(blobs, preconfirmed_block)
158268
}
159269

160-
#[expect(dead_code)]
161270
fn parent_block_hash(&self) -> BlockHash {
162271
self.blocks.last().map(|block| block.block_hash).unwrap_or(BlockHash::GENESIS_PARENT_HASH)
163272
}
164273

165-
#[expect(dead_code)]
166274
fn current_state_roots(&self) -> StateRoots {
167275
self.blocks.last().map(|block| block.state_roots).unwrap_or_default()
168276
}

0 commit comments

Comments
 (0)