1313use crate :: block_stm:: types:: {
1414 EvmStateKey , EvmStateValue , Incarnation , ReadResult , ResolvedBalance , TxnIndex , Version ,
1515} ;
16- use alloy_primitives:: { Address , U256 } ;
16+ use alloy_primitives:: { Address , B256 , Bytes , U256 } ;
1717use parking_lot:: RwLock ;
1818use std:: {
1919 collections:: { BTreeMap , HashMap , HashSet } ,
@@ -254,6 +254,10 @@ pub struct MVHashMap {
254254 /// Balance deltas indexed by address.
255255 /// These are commutative increments that don't conflict with each other.
256256 balance_deltas : RwLock < HashMap < Address , RwLock < VersionedDeltas > > > ,
257+ /// Bytecode cache for newly deployed contracts.
258+ /// Maps code_hash → (bytecode, txn_idx that deployed it).
259+ /// This allows parallel transactions to access code deployed in the same block.
260+ bytecode_cache : RwLock < HashMap < B256 , ( Bytes , TxnIndex ) > > ,
257261 /// Number of transactions in the block (reserved for future use).
258262 #[ allow( dead_code) ]
259263 num_txns : usize ,
@@ -265,10 +269,35 @@ impl MVHashMap {
265269 Self {
266270 data : RwLock :: new ( HashMap :: new ( ) ) ,
267271 balance_deltas : RwLock :: new ( HashMap :: new ( ) ) ,
272+ bytecode_cache : RwLock :: new ( HashMap :: new ( ) ) ,
268273 num_txns,
269274 }
270275 }
271276
277+ /// Store bytecode for a newly deployed contract.
278+ /// This makes the bytecode available to parallel transactions.
279+ pub fn store_bytecode ( & self , code_hash : B256 , bytecode : Bytes , txn_idx : TxnIndex ) {
280+ // Don't store empty bytecode or the KECCAK_EMPTY hash
281+ if bytecode. is_empty ( ) || code_hash == revm:: primitives:: KECCAK_EMPTY {
282+ return ;
283+ }
284+ let mut cache = self . bytecode_cache . write ( ) ;
285+ cache. insert ( code_hash, ( bytecode, txn_idx) ) ;
286+ }
287+
288+ /// Retrieve bytecode by hash, if it was deployed by a transaction before reader_txn_idx.
289+ pub fn get_bytecode ( & self , code_hash : B256 , reader_txn_idx : TxnIndex ) -> Option < Bytes > {
290+ let cache = self . bytecode_cache . read ( ) ;
291+ cache. get ( & code_hash) . and_then ( |( bytecode, writer_txn_idx) | {
292+ // Only return bytecode if it was written by an earlier transaction
293+ if * writer_txn_idx < reader_txn_idx {
294+ Some ( bytecode. clone ( ) )
295+ } else {
296+ None
297+ }
298+ } )
299+ }
300+
272301 /// Write a value at the given version.
273302 #[ instrument( level = "trace" , skip( self , value) , fields( txn_idx, incarnation, key = %key) ) ]
274303 pub fn write (
0 commit comments