@@ -337,15 +337,18 @@ fn validate_post_state(
337337 }
338338
339339 for ( address, expected_account) in expected_post_state {
340- // Load account from final state
341- let actual_account = state
342- . load_cache_account ( * address)
343- . map_err ( |e| TestExecutionError :: Database ( format ! ( "Account load failed: {e}" ) ) ) ?;
344- let info = actual_account
345- . account
346- . as_ref ( )
347- . map ( |a| a. info . clone ( ) )
348- . unwrap_or_default ( ) ;
340+ // Load account from final state. Info and storage are cloned so the borrow
341+ // of `state` ends here and it can be queried again below (e.g. for code).
342+ let ( info, actual_storage) = {
343+ let actual_account = state
344+ . load_cache_account ( * address)
345+ . map_err ( |e| TestExecutionError :: Database ( format ! ( "Account load failed: {e}" ) ) ) ?;
346+ let account = actual_account. account . as_ref ( ) ;
347+ (
348+ account. map ( |a| a. info . clone ( ) ) . unwrap_or_default ( ) ,
349+ account. map ( |a| a. storage . clone ( ) ) . unwrap_or_default ( ) ,
350+ )
351+ } ;
349352
350353 // Validate balance
351354 if info. balance != expected_account. balance {
@@ -376,9 +379,19 @@ fn validate_post_state(
376379 ) ;
377380 }
378381
379- // Validate code if present
382+ // Validate code if present. The account may carry only the code hash when the
383+ // code was never loaded during execution, so fall back to `code_by_hash`.
380384 if !expected_account. code . is_empty ( ) {
381- if let Some ( actual_code) = & info. code {
385+ let actual_code = match info. code . clone ( ) {
386+ Some ( code) => Some ( code) ,
387+ None if !info. is_empty_code_hash ( ) => {
388+ Some ( Database :: code_by_hash ( state, info. code_hash ) . map_err ( |e| {
389+ TestExecutionError :: Database ( format ! ( "Code load failed: {e}" ) )
390+ } ) ?)
391+ }
392+ None => None ,
393+ } ;
394+ if let Some ( actual_code) = & actual_code {
382395 if actual_code. original_bytes ( ) != expected_account. code {
383396 return make_failure (
384397 state,
@@ -405,23 +418,21 @@ fn validate_post_state(
405418 }
406419 }
407420
408- // Check for unexpected storage entries. Avoid allocating a temporary HashMap when the account is None.
409- if let Some ( acc) = actual_account. account . as_ref ( ) {
410- for ( slot, actual_value) in & acc. storage {
411- let slot = * slot;
412- let actual_value = * actual_value;
413- if !expected_account. storage . contains_key ( & slot) && !actual_value. is_zero ( ) {
414- return make_failure (
415- state,
416- debug_info,
417- expected_post_state,
418- print_env_on_error,
419- * address,
420- format ! ( "storage_unexpected[{slot}]" ) ,
421- "0x0" . to_string ( ) ,
422- format ! ( "{actual_value}" ) ,
423- ) ;
424- }
421+ // Check for unexpected storage entries.
422+ for ( slot, actual_value) in & actual_storage {
423+ let slot = * slot;
424+ let actual_value = * actual_value;
425+ if !expected_account. storage . contains_key ( & slot) && !actual_value. is_zero ( ) {
426+ return make_failure (
427+ state,
428+ debug_info,
429+ expected_post_state,
430+ print_env_on_error,
431+ * address,
432+ format ! ( "storage_unexpected[{slot}]" ) ,
433+ "0x0" . to_string ( ) ,
434+ format ! ( "{actual_value}" ) ,
435+ ) ;
425436 }
426437 }
427438
@@ -669,20 +680,38 @@ fn execute_blockchain_test(
669680 // Capture pre-state for debug info
670681 let mut pre_state_debug = AddressMap :: default ( ) ;
671682
672- // Insert genesis state into database
683+ // Insert genesis state into database. Bytecode is stored separately from the
684+ // account (in the contracts map, keyed by code hash) so that execution has to
685+ // fetch it through `Database::code_by_hash`, like a node's state provider would
686+ // serve it.
673687 let genesis_state = test_case. pre . clone ( ) . into_genesis_state ( ) ;
674688 for ( address, account) in genesis_state {
689+ let code_hash = revm:: primitives:: keccak256 ( & account. code ) ;
690+ let bytecode = ( !account. code . is_empty ( ) ) . then ( || Bytecode :: new_raw ( account. code . clone ( ) ) ) ;
675691 let account_info = AccountInfo {
676692 balance : account. balance ,
677693 nonce : account. nonce ,
678- code_hash : revm :: primitives :: keccak256 ( & account . code ) ,
679- code : Some ( Bytecode :: new_raw ( account . code . clone ( ) ) ) ,
694+ code_hash,
695+ code : None ,
680696 account_id : None ,
681697 } ;
682698
683- // Store for debug info
699+ if let Some ( bytecode) = & bytecode {
700+ state. cache . contracts . insert ( code_hash, bytecode. clone ( ) ) ;
701+ }
702+
703+ // Store for debug info, with the code inlined so it shows up in the debug print.
684704 if print_env_on_error {
685- pre_state_debug. insert ( address, ( account_info. clone ( ) , account. storage . clone ( ) ) ) ;
705+ pre_state_debug. insert (
706+ address,
707+ (
708+ AccountInfo {
709+ code : bytecode,
710+ ..account_info. clone ( )
711+ } ,
712+ account. storage . clone ( ) ,
713+ ) ,
714+ ) ;
686715 }
687716
688717 state. insert_account_with_storage ( address, account_info, account. storage ) ;
0 commit comments