@@ -19,7 +19,7 @@ use crate::config::NodeConfig;
1919use crate :: execution_bridge:: { BlockExecutionResult , ExecutionBridge } ;
2020use crate :: network:: { TcpPrimaryNetwork , TcpWorkerNetwork } ;
2121use crate :: supervisor:: NodeSupervisor ;
22- use alloy_primitives:: Address ;
22+ use alloy_primitives:: { Address , B256 } ;
2323use anyhow:: { Context , Result } ;
2424use cipherbft_consensus:: {
2525 create_context, default_consensus_params, default_engine_config_single_part, spawn_host,
@@ -1133,30 +1133,41 @@ impl Node {
11331133
11341134 // Ensure genesis block (block 0) exists for Ethereum RPC compatibility
11351135 // Block explorers like Blockscout expect block 0 to exist
1136- match storage. block_store ( ) . get_block_by_number ( 0 ) . await {
1137- Ok ( Some ( _) ) => {
1138- debug ! ( "Genesis block (block 0) already exists in storage" ) ;
1139- }
1140- Ok ( None ) => {
1141- // Create and store genesis block
1142- let genesis_timestamp = std:: time:: SystemTime :: now ( )
1143- . duration_since ( std:: time:: UNIX_EPOCH )
1144- . unwrap_or_default ( )
1145- . as_secs ( ) ;
1146- let genesis_block =
1147- Self :: create_genesis_block ( genesis_timestamp, self . gas_limit ) ;
1148- if let Err ( e) = storage. block_store ( ) . put_block ( & genesis_block) . await {
1149- error ! ( "Failed to store genesis block: {}" , e) ;
1150- } else {
1151- info ! (
1152- "Created genesis block (block 0) with hash 0x{}" ,
1153- hex:: encode( & genesis_block. hash[ ..8 ] )
1154- ) ;
1136+ let genesis_hash: Option < [ u8 ; 32 ] > =
1137+ match storage. block_store ( ) . get_block_by_number ( 0 ) . await {
1138+ Ok ( Some ( existing_block) ) => {
1139+ debug ! ( "Genesis block (block 0) already exists in storage" ) ;
1140+ Some ( existing_block. hash )
11551141 }
1156- }
1157- Err ( e) => {
1158- warn ! ( "Failed to check for genesis block: {}" , e) ;
1159- }
1142+ Ok ( None ) => {
1143+ // Create and store genesis block
1144+ let genesis_timestamp = std:: time:: SystemTime :: now ( )
1145+ . duration_since ( std:: time:: UNIX_EPOCH )
1146+ . unwrap_or_default ( )
1147+ . as_secs ( ) ;
1148+ let genesis_block =
1149+ Self :: create_genesis_block ( genesis_timestamp, self . gas_limit ) ;
1150+ let hash = genesis_block. hash ;
1151+ if let Err ( e) = storage. block_store ( ) . put_block ( & genesis_block) . await {
1152+ error ! ( "Failed to store genesis block: {}" , e) ;
1153+ None
1154+ } else {
1155+ info ! (
1156+ "Created genesis block (block 0) with hash 0x{}" ,
1157+ hex:: encode( & genesis_block. hash[ ..8 ] )
1158+ ) ;
1159+ Some ( hash)
1160+ }
1161+ }
1162+ Err ( e) => {
1163+ warn ! ( "Failed to check for genesis block: {}" , e) ;
1164+ None
1165+ }
1166+ } ;
1167+
1168+ // Synchronize genesis block hash with execution bridge for correct parent_hash in block 1
1169+ if let ( Some ( hash) , Some ( ref bridge) ) = ( genesis_hash, & self . execution_bridge ) {
1170+ bridge. set_genesis_block_hash ( B256 :: from ( hash) ) ;
11601171 }
11611172
11621173 // Initialize latest_block from storage (important for restart scenarios)
@@ -1515,11 +1526,12 @@ impl Node {
15151526
15161527 // Store receipts for eth_getBlockReceipts queries
15171528 if !block_result. execution_result. receipts. is_empty( ) {
1529+ let block_hash_bytes = block_result. block_hash. 0 ;
15181530 let storage_receipts: Vec <StorageReceipt > = block_result
15191531 . execution_result
15201532 . receipts
15211533 . iter( )
1522- . map( Self :: execution_receipt_to_storage)
1534+ . map( |r| Self :: execution_receipt_to_storage( r , block_hash_bytes ) )
15231535 . collect( ) ;
15241536 if let Err ( e) = storage. receipt_store( ) . put_receipts( & storage_receipts) . await {
15251537 error!( "Failed to store {} receipts for block {}: {}" , storage_receipts. len( ) , height. 0 , e) ;
@@ -1781,7 +1793,12 @@ impl Node {
17811793 /// Convert an execution TransactionReceipt to a storage Receipt for MDBX persistence.
17821794 ///
17831795 /// This bridges the execution layer receipt format to the storage layer format.
1784- fn execution_receipt_to_storage ( receipt : & ExecutionReceipt ) -> StorageReceipt {
1796+ /// The block_hash parameter is passed explicitly because the execution receipt
1797+ /// is created before the block hash is computed, so it contains a placeholder value.
1798+ fn execution_receipt_to_storage (
1799+ receipt : & ExecutionReceipt ,
1800+ block_hash : [ u8 ; 32 ] ,
1801+ ) -> StorageReceipt {
17851802 // Convert logs
17861803 let logs: Vec < StorageLog > = receipt
17871804 . logs
@@ -1795,7 +1812,7 @@ impl Node {
17951812 StorageReceipt {
17961813 transaction_hash : receipt. transaction_hash . 0 ,
17971814 block_number : receipt. block_number ,
1798- block_hash : receipt . block_hash . 0 ,
1815+ block_hash,
17991816 transaction_index : receipt. transaction_index as u32 ,
18001817 from : receipt. from . 0 . 0 ,
18011818 to : receipt. to . map ( |a| a. 0 . 0 ) ,
0 commit comments