@@ -5,9 +5,6 @@ pub mod mempool;
55pub  mod  payload; 
66mod  smoke_test; 
77
8- use  std:: { ops:: Div ,  time:: Instant } ; 
9- use  tracing:: info; 
10- 
118use  error:: { ChainError ,  InvalidBlockError } ; 
129use  ethrex_common:: constants:: GAS_PER_BLOB ; 
1310use  ethrex_common:: types:: requests:: { compute_requests_hash,  EncodedRequests ,  Requests } ; 
@@ -17,71 +14,142 @@ use ethrex_common::types::{
1714    BlockHeader ,  BlockNumber ,  ChainConfig ,  EIP4844Transaction ,  Receipt ,  Transaction , 
1815} ; 
1916use  ethrex_common:: H256 ; 
17+ use  std:: { ops:: Div ,  time:: Instant } ; 
2018
2119use  ethrex_storage:: error:: StoreError ; 
2220use  ethrex_storage:: Store ; 
21+ use  ethrex_vm:: backends:: BlockExecutionResult ; 
22+ use  ethrex_vm:: backends:: EVM ; 
2323use  ethrex_vm:: db:: evm_state; 
24- use  ethrex_vm:: { backends:: BlockExecutionResult ,  get_evm_backend_or_default} ; 
24+ use  fork_choice:: apply_fork_choice; 
25+ use  tracing:: { error,  info,  warn} ; 
2526
2627//TODO: Implement a struct Chain or BlockChain to encapsulate 
2728//functionality and canonical chain state and config 
2829
29- /// Adds a new block to the store. It may or may not be canonical, as long as its ancestry links 
30- /// with the canonical chain and its parent's post-state is calculated. It doesn't modify the 
31- /// canonical chain/head. Fork choice needs to be updated for that in a separate step. 
32- /// 
33- /// Performs pre and post execution validation, and updates the database with the post state. 
34- pub  fn  add_block ( block :  & Block ,  storage :  & Store )  -> Result < ( ) ,  ChainError >  { 
35-     let  since = Instant :: now ( ) ; 
36- 
37-     let  block_hash = block. header . compute_block_hash ( ) ; 
38- 
39-     // Validate if it can be the new head and find the parent 
40-     let  Ok ( parent_header)  = find_parent_header ( & block. header ,  storage)  else  { 
41-         // If the parent is not present, we store it as pending. 
42-         storage. add_pending_block ( block. clone ( ) ) ?; 
43-         return  Err ( ChainError :: ParentNotFound ) ; 
44-     } ; 
45-     let  mut  state = evm_state ( storage. clone ( ) ,  block. header . parent_hash ) ; 
46-     let  chain_config = state. chain_config ( ) . map_err ( ChainError :: from) ?; 
47- 
48-     // Validate the block pre-execution 
49-     validate_block ( block,  & parent_header,  & chain_config) ?; 
50-     let  BlockExecutionResult  { 
51-         receipts, 
52-         requests, 
53-         account_updates, 
54-     }  = get_evm_backend_or_default ( ) . execute_block ( block,  & mut  state) ?; 
55- 
56-     validate_gas_used ( & receipts,  & block. header ) ?; 
57- 
58-     // Apply the account updates over the last block's state and compute the new state root 
59-     let  new_state_root = state
60-         . database ( ) 
61-         . ok_or ( ChainError :: StoreError ( StoreError :: MissingStore ) ) ?
62-         . apply_account_updates ( block. header . parent_hash ,  & account_updates) ?
63-         . ok_or ( ChainError :: ParentStateNotFound ) ?; 
64- 
65-     // Check state root matches the one in block header after execution 
66-     validate_state_root ( & block. header ,  new_state_root) ?; 
67- 
68-     // Check receipts root matches the one in block header after execution 
69-     validate_receipts_root ( & block. header ,  & receipts) ?; 
70- 
71-     // Processes requests from receipts, computes the requests_hash and compares it against the header 
72-     validate_requests_hash ( & block. header ,  & chain_config,  & requests) ?; 
73- 
74-     store_block ( storage,  block. clone ( ) ) ?; 
75-     store_receipts ( storage,  receipts,  block_hash) ?; 
76- 
77-     let  interval = Instant :: now ( ) . duration_since ( since) . as_millis ( ) ; 
78-     if  interval != 0  { 
79-         let  as_gigas = ( block. header . gas_used  as  f64 ) . div ( 10_f64 . powf ( 9_f64 ) ) ; 
80-         let  throughput = ( as_gigas)  / ( interval as  f64 )  *  1000_f64 ; 
81-         info ! ( "[METRIC] BLOCK EXECUTION THROUGHPUT: {throughput} Gigagas/s TIME SPENT: {interval} msecs" ) ; 
30+ #[ derive( Debug ,  Clone ) ]  
31+ pub  struct  Blockchain  { 
32+     pub  vm :  EVM , 
33+     pub  storage :  Store , 
34+ } 
35+ 
36+ impl  Blockchain  { 
37+     pub  fn  new ( evm :  EVM ,  store :  Store )  -> Self  { 
38+         Self  { 
39+             vm :  evm, 
40+             storage :  store, 
41+         } 
8242    } 
8343
84-     Ok ( ( ) ) 
44+     pub  fn  default_with_store ( store :  Store )  -> Self  { 
45+         Self  { 
46+             vm :  Default :: default ( ) , 
47+             storage :  store, 
48+         } 
49+     } 
50+ 
51+     pub  fn  add_block ( & self ,  block :  & Block )  -> Result < ( ) ,  ChainError >  { 
52+         let  since = Instant :: now ( ) ; 
53+ 
54+         let  block_hash = block. header . compute_block_hash ( ) ; 
55+ 
56+         // Validate if it can be the new head and find the parent 
57+         let  Ok ( parent_header)  = find_parent_header ( & block. header ,  & self . storage )  else  { 
58+             // If the parent is not present, we store it as pending. 
59+             self . storage . add_pending_block ( block. clone ( ) ) ?; 
60+             return  Err ( ChainError :: ParentNotFound ) ; 
61+         } ; 
62+         let  mut  state = evm_state ( self . storage . clone ( ) ,  block. header . parent_hash ) ; 
63+         let  chain_config = state. chain_config ( ) . map_err ( ChainError :: from) ?; 
64+ 
65+         // Validate the block pre-execution 
66+         validate_block ( block,  & parent_header,  & chain_config) ?; 
67+         let  BlockExecutionResult  { 
68+             receipts, 
69+             requests, 
70+             account_updates, 
71+         }  = self . vm . execute_block ( block,  & mut  state) ?; 
72+ 
73+         validate_gas_used ( & receipts,  & block. header ) ?; 
74+ 
75+         // Apply the account updates over the last block's state and compute the new state root 
76+         let  new_state_root = state
77+             . database ( ) 
78+             . ok_or ( ChainError :: StoreError ( StoreError :: MissingStore ) ) ?
79+             . apply_account_updates ( block. header . parent_hash ,  & account_updates) ?
80+             . ok_or ( ChainError :: ParentStateNotFound ) ?; 
81+ 
82+         // Check state root matches the one in block header after execution 
83+         validate_state_root ( & block. header ,  new_state_root) ?; 
84+ 
85+         // Check receipts root matches the one in block header after execution 
86+         validate_receipts_root ( & block. header ,  & receipts) ?; 
87+ 
88+         // Processes requests from receipts, computes the requests_hash and compares it against the header 
89+         validate_requests_hash ( & block. header ,  & chain_config,  & requests) ?; 
90+ 
91+         store_block ( & self . storage ,  block. clone ( ) ) ?; 
92+         store_receipts ( & self . storage ,  receipts,  block_hash) ?; 
93+ 
94+         let  interval = Instant :: now ( ) . duration_since ( since) . as_millis ( ) ; 
95+         if  interval != 0  { 
96+             let  as_gigas = ( block. header . gas_used  as  f64 ) . div ( 10_f64 . powf ( 9_f64 ) ) ; 
97+             let  throughput = ( as_gigas)  / ( interval as  f64 )  *  1000_f64 ; 
98+             info ! ( "[METRIC] BLOCK EXECUTION THROUGHPUT: {throughput} Gigagas/s TIME SPENT: {interval} msecs" ) ; 
99+         } 
100+ 
101+         Ok ( ( ) ) 
102+     } 
103+ 
104+     //TODO: Forkchoice Update shouldn't be part of this function 
105+     pub  fn  import_blocks ( & self ,  blocks :  & Vec < Block > )  { 
106+         let  size = blocks. len ( ) ; 
107+         for  block in  blocks { 
108+             let  hash = block. hash ( ) ; 
109+             info ! ( 
110+                 "Adding block {} with hash {:#x}." , 
111+                 block. header. number,  hash
112+             ) ; 
113+             if  let  Err ( error)  = self . add_block ( block)  { 
114+                 warn ! ( 
115+                     "Failed to add block {} with hash {:#x}: {}." , 
116+                     block. header. number,  hash,  error
117+                 ) ; 
118+             } 
119+             if  self 
120+                 . storage 
121+                 . update_latest_block_number ( block. header . number ) 
122+                 . is_err ( ) 
123+             { 
124+                 error ! ( "Fatal: added block {} but could not update the block number -- aborting block import" ,  block. header. number) ; 
125+                 break ; 
126+             } ; 
127+             if  self 
128+                 . storage 
129+                 . set_canonical_block ( block. header . number ,  hash) 
130+                 . is_err ( ) 
131+             { 
132+                 error ! ( 
133+                     "Fatal: added block {} but could not set it as canonical -- aborting block import" , 
134+                     block. header. number
135+                 ) ; 
136+                 break ; 
137+             } ; 
138+         } 
139+         if  let  Some ( last_block)  = blocks. last ( )  { 
140+             let  hash = last_block. hash ( ) ; 
141+             match  self . vm  { 
142+                 EVM :: LEVM  => { 
143+                     // We are allowing this not to unwrap so that tests can run even if block execution results in the wrong root hash with LEVM. 
144+                     let  _ = apply_fork_choice ( & self . storage ,  hash,  hash,  hash) ; 
145+                 } 
146+                 EVM :: REVM  => { 
147+                     apply_fork_choice ( & self . storage ,  hash,  hash,  hash) . unwrap ( ) ; 
148+                 } 
149+             } 
150+         } 
151+         info ! ( "Added {size} blocks to blockchain" ) ; 
152+     } 
85153} 
86154
87155pub  fn  validate_requests_hash ( 
0 commit comments