@@ -18,13 +18,18 @@ use apollo_consensus_orchestrator::cende::{
1818 InternalTransactionWithReceipt ,
1919} ;
2020use 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 ;
2124use blockifier:: blockifier_versioned_constants:: VersionedConstants ;
2225use blockifier:: bouncer:: BouncerConfig ;
2326use 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 ;
2529use blockifier:: test_utils:: contracts:: FeatureContractTrait ;
2630use blockifier:: test_utils:: dict_state_reader:: DictStateReader ;
2731use blockifier:: transaction:: account_transaction:: AccountTransaction as BlockifierAccountTx ;
32+ use blockifier:: transaction:: transaction_execution:: Transaction as BlockifierTx ;
2833use blockifier:: transaction:: transactions:: ExecutableTransaction ;
2934use blockifier_test_utils:: contracts:: FeatureContract ;
3035use expect_test:: expect_file;
@@ -35,23 +40,30 @@ use google_cloud_storage::http::objects::get::GetObjectRequest;
3540use google_cloud_storage:: http:: objects:: upload:: { Media , UploadObjectRequest , UploadType } ;
3641use google_cloud_storage:: http:: Error as GcsError ;
3742use 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+ } ;
4050use starknet_api:: consensus_transaction:: InternalConsensusTransaction ;
4151use starknet_api:: contract_address;
4252use starknet_api:: contract_class:: compiled_class_hash:: HashVersion ;
4353use starknet_api:: core:: { ChainId , Nonce , OsChainInfo } ;
44- use starknet_api:: data_availability:: DataAvailabilityMode ;
54+ use starknet_api:: data_availability:: { DataAvailabilityMode , L1DataAvailabilityMode } ;
4555use starknet_api:: executable_transaction:: {
4656 AccountTransaction as ExecutableAccountTx ,
4757 DeclareTransaction as ExecutableDeclareTransaction ,
58+ Transaction as ExecutableTx ,
4859} ;
4960use starknet_api:: hash:: StateRoots ;
5061use starknet_api:: rpc_transaction:: {
5162 InternalRpcDeclareTransactionV3 ,
5263 InternalRpcTransaction ,
5364 InternalRpcTransactionWithoutTxHash ,
5465} ;
66+ use starknet_api:: state:: ThinStateDiff ;
5567use starknet_api:: test_utils:: TEST_SEQUENCER_ADDRESS ;
5668use 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 ;
6982use starknet_committer:: db:: facts_db:: FactsDb ;
7083use starknet_committer:: db:: forest_trait:: StorageInitializer ;
7184use starknet_patricia_storage:: map_storage:: MapStorage ;
85+ use starknet_transaction_prover:: running:: committer_utils:: commit_state_diff;
7286
7387const 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