@@ -29,6 +29,7 @@ struct GroupData {
2929 writes : Vec < SlotKey > ,
3030 balance_reads : Vec < Address > ,
3131 balance_writes : Vec < Address > ,
32+ code_reads : Vec < Address > ,
3233 code_writes : Vec < Address > ,
3334 conflicting_group_ids : HashSet < usize > ,
3435}
@@ -41,6 +42,7 @@ fn combine_groups(groups: Vec<GroupData>, removed_group_ids: Vec<usize>) -> Grou
4142 let mut writes = Vec :: default ( ) ;
4243 let mut balance_reads = Vec :: default ( ) ;
4344 let mut balance_writes = Vec :: default ( ) ;
45+ let mut code_reads = Vec :: default ( ) ;
4446 let mut code_writes = Vec :: default ( ) ;
4547 let mut conflicting_group_ids = removed_group_ids. into_iter ( ) . collect :: < HashSet < usize > > ( ) ;
4648 for group in groups {
@@ -49,6 +51,7 @@ fn combine_groups(groups: Vec<GroupData>, removed_group_ids: Vec<usize>) -> Grou
4951 writes. extend ( group. writes ) ;
5052 balance_reads. extend ( group. balance_reads ) ;
5153 balance_writes. extend ( group. balance_writes ) ;
54+ code_reads. extend ( group. code_reads ) ;
5255 code_writes. extend ( group. code_writes ) ;
5356 conflicting_group_ids. extend ( group. conflicting_group_ids ) ;
5457 }
@@ -60,6 +63,8 @@ fn combine_groups(groups: Vec<GroupData>, removed_group_ids: Vec<usize>) -> Grou
6063 balance_reads. dedup ( ) ;
6164 balance_writes. sort_unstable ( ) ;
6265 balance_writes. dedup ( ) ;
66+ code_reads. sort_unstable ( ) ;
67+ code_reads. dedup ( ) ;
6368 code_writes. sort_unstable ( ) ;
6469 code_writes. dedup ( ) ;
6570
@@ -69,6 +74,7 @@ fn combine_groups(groups: Vec<GroupData>, removed_group_ids: Vec<usize>) -> Grou
6974 writes,
7075 balance_reads,
7176 balance_writes,
77+ code_reads,
7278 code_writes,
7379 conflicting_group_ids,
7480 }
@@ -82,6 +88,7 @@ pub struct ConflictFinder {
8288 group_writes : HashMap < Address , HashMap < B256 , Vec < usize > > > , // same as above
8389 group_balance_reads : HashMap < Address , Vec < usize > > ,
8490 group_balance_writes : HashMap < Address , Vec < usize > > ,
91+ group_code_reads : HashMap < Address , Vec < usize > > ,
8592 group_code_writes : HashMap < Address , Vec < usize > > ,
8693 groups : HashMap < usize , GroupData > ,
8794 orders : HashSet < OrderId > ,
@@ -95,6 +102,7 @@ impl ConflictFinder {
95102 group_writes : HashMap :: default ( ) ,
96103 group_balance_reads : HashMap :: default ( ) ,
97104 group_balance_writes : HashMap :: default ( ) ,
105+ group_code_reads : HashMap :: default ( ) ,
98106 group_code_writes : HashMap :: default ( ) ,
99107 groups : HashMap :: default ( ) ,
100108 orders : HashSet :: default ( ) ,
@@ -176,6 +184,16 @@ impl ConflictFinder {
176184 let inner_groups = inner_mapping. values ( ) . flatten ( ) ;
177185 all_groups_in_conflict. extend ( inner_groups) ;
178186 }
187+ // trying to create / destroy a contract other order is reading code from
188+ if let Some ( group) = self . group_code_reads . get ( contract_addr) {
189+ all_groups_in_conflict. extend_from_slice ( group) ;
190+ }
191+ }
192+ // reading code of a contract other order is creating / destroying
193+ for code_read_addr in & used_state. read_code_addresses {
194+ if let Some ( group) = self . group_code_writes . get ( code_read_addr) {
195+ all_groups_in_conflict. extend_from_slice ( group) ;
196+ }
179197 }
180198 all_groups_in_conflict. sort ( ) ;
181199 all_groups_in_conflict. dedup ( ) ;
@@ -198,12 +216,18 @@ impl ConflictFinder {
198216 code_writes. sort_unstable ( ) ;
199217 code_writes. dedup ( ) ;
200218
219+ let mut code_reads: Vec < Address > =
220+ used_state. read_code_addresses . into_iter ( ) . collect ( ) ;
221+ code_reads. sort_unstable ( ) ;
222+ code_reads. dedup ( ) ;
223+
201224 GroupData {
202225 orders : vec ! [ order] ,
203226 reads : used_state. read_slot_values . into_keys ( ) . collect ( ) ,
204227 writes : used_state. written_slot_values . into_keys ( ) . collect ( ) ,
205228 balance_reads : used_state. read_balances . into_keys ( ) . collect ( ) ,
206229 balance_writes,
230+ code_reads,
207231 code_writes,
208232 conflicting_group_ids : HashSet :: default ( ) ,
209233 }
@@ -275,6 +299,12 @@ impl ConflictFinder {
275299 & group_data. balance_writes ,
276300 & mut self . group_balance_writes ,
277301 ) ;
302+ add_group_to_map (
303+ group_id,
304+ is_new_id,
305+ & group_data. code_reads ,
306+ & mut self . group_code_reads ,
307+ ) ;
278308 add_group_to_map (
279309 group_id,
280310 is_new_id,
@@ -302,6 +332,7 @@ impl ConflictFinder {
302332 & group_data. balance_writes ,
303333 & mut self . group_balance_writes ,
304334 ) ;
335+ remove_group_from_map ( group_id, & group_data. code_reads , & mut self . group_code_reads ) ;
305336 remove_group_from_map (
306337 group_id,
307338 & group_data. code_writes ,
@@ -440,6 +471,28 @@ mod tests {
440471 balance_write : Option < & Address > ,
441472 contract_creation : Option < & Address > ,
442473 contract_destruction : Option < & Address > ,
474+ ) -> Arc < SimulatedOrder > {
475+ self . create_order_with_code_read (
476+ read,
477+ write,
478+ balance_read,
479+ balance_write,
480+ contract_creation,
481+ contract_destruction,
482+ None ,
483+ )
484+ }
485+
486+ #[ allow( clippy:: too_many_arguments) ]
487+ pub fn create_order_with_code_read (
488+ & mut self ,
489+ read : Option < & SlotKey > ,
490+ write : Option < & SlotKey > ,
491+ balance_read : Option < & Address > ,
492+ balance_write : Option < & Address > ,
493+ contract_creation : Option < & Address > ,
494+ contract_destruction : Option < & Address > ,
495+ code_read : Option < & Address > ,
443496 ) -> Arc < SimulatedOrder > {
444497 let mut trace = UsedStateTrace :: default ( ) ;
445498 if let Some ( read) = read {
@@ -469,6 +522,9 @@ mod tests {
469522 if let Some ( contract_address) = contract_destruction {
470523 trace. destructed_contracts . push ( * contract_address) ;
471524 }
525+ if let Some ( code_read_addr) = code_read {
526+ trace. read_code_addresses . insert ( * code_read_addr) ;
527+ }
472528
473529 Arc :: new ( SimulatedOrder :: new (
474530 Arc :: new ( Order :: Tx ( MempoolTx {
@@ -595,4 +651,72 @@ mod tests {
595651 let groups = cached_groups. get_order_groups ( ) ;
596652 assert_eq ! ( groups. len( ) , 1 ) ;
597653 }
654+
655+ #[ test]
656+ fn two_code_reads_no_conflict ( ) {
657+ let mut data_gen = DataGenerator :: new ( ) ;
658+ let addr = Address :: random ( ) ;
659+ let oa =
660+ data_gen. create_order_with_code_read ( None , None , None , None , None , None , Some ( & addr) ) ;
661+ let ob =
662+ data_gen. create_order_with_code_read ( None , None , None , None , None , None , Some ( & addr) ) ;
663+ let mut cached_groups = ConflictFinder :: new ( ) ;
664+ cached_groups. add_orders ( vec ! [ oa, ob] ) ;
665+ let groups = cached_groups. get_order_groups ( ) ;
666+ assert_eq ! ( groups. len( ) , 2 ) ;
667+ }
668+
669+ #[ test]
670+ fn code_read_and_creation_conflict ( ) {
671+ let mut data_gen = DataGenerator :: new ( ) ;
672+ let addr = Address :: random ( ) ;
673+ let oa =
674+ data_gen. create_order_with_code_read ( None , None , None , None , None , None , Some ( & addr) ) ;
675+ let ob = data_gen. create_order ( None , None , None , None , Some ( & addr) , None ) ;
676+ let mut cached_groups = ConflictFinder :: new ( ) ;
677+ cached_groups. add_orders ( vec ! [ oa, ob] ) ;
678+ let groups = cached_groups. get_order_groups ( ) ;
679+ assert_eq ! ( groups. len( ) , 1 ) ;
680+ }
681+
682+ #[ test]
683+ fn code_read_and_destruction_conflict ( ) {
684+ let mut data_gen = DataGenerator :: new ( ) ;
685+ let addr = Address :: random ( ) ;
686+ let oa =
687+ data_gen. create_order_with_code_read ( None , None , None , None , None , None , Some ( & addr) ) ;
688+ let ob = data_gen. create_order ( None , None , None , None , None , Some ( & addr) ) ;
689+ let mut cached_groups = ConflictFinder :: new ( ) ;
690+ cached_groups. add_orders ( vec ! [ oa, ob] ) ;
691+ let groups = cached_groups. get_order_groups ( ) ;
692+ assert_eq ! ( groups. len( ) , 1 ) ;
693+ }
694+
695+ #[ test]
696+ fn creation_then_code_read_conflict ( ) {
697+ let mut data_gen = DataGenerator :: new ( ) ;
698+ let addr = Address :: random ( ) ;
699+ // code_write first, then code_read — tests the reverse direction
700+ let oa = data_gen. create_order ( None , None , None , None , Some ( & addr) , None ) ;
701+ let ob =
702+ data_gen. create_order_with_code_read ( None , None , None , None , None , None , Some ( & addr) ) ;
703+ let mut cached_groups = ConflictFinder :: new ( ) ;
704+ cached_groups. add_orders ( vec ! [ oa, ob] ) ;
705+ let groups = cached_groups. get_order_groups ( ) ;
706+ assert_eq ! ( groups. len( ) , 1 ) ;
707+ }
708+
709+ #[ test]
710+ fn destruction_then_code_read_conflict ( ) {
711+ let mut data_gen = DataGenerator :: new ( ) ;
712+ let addr = Address :: random ( ) ;
713+ // code_write first, then code_read — tests the reverse direction
714+ let oa = data_gen. create_order ( None , None , None , None , None , Some ( & addr) ) ;
715+ let ob =
716+ data_gen. create_order_with_code_read ( None , None , None , None , None , None , Some ( & addr) ) ;
717+ let mut cached_groups = ConflictFinder :: new ( ) ;
718+ cached_groups. add_orders ( vec ! [ oa, ob] ) ;
719+ let groups = cached_groups. get_order_groups ( ) ;
720+ assert_eq ! ( groups. len( ) , 1 ) ;
721+ }
598722}
0 commit comments