@@ -85,12 +85,12 @@ enum MutationType {
8585 Repeat ,
8686 /// Interleave calls from two random call sequences.
8787 Interleave ,
88- /// Replace prefix of the original call sequence with new calls .
89- Prefix ,
90- /// Replace suffix of the original call sequence with new calls .
91- Suffix ,
92- /// ABI mutate random args of selected call in sequence.
93- Abi ,
88+ /// Generate new calls for a random prefix of the sequence .
89+ GenPrefix ,
90+ /// Generate new calls for a random suffix of the sequence .
91+ GenSuffix ,
92+ /// ABI mutate a random number of calls (1 to all) in the sequence.
93+ GenMutate ,
9494}
9595
9696/// Holds Corpus information.
@@ -286,9 +286,9 @@ impl WorkerCorpus {
286286 Just ( MutationType :: Splice ) ,
287287 Just ( MutationType :: Repeat ) ,
288288 Just ( MutationType :: Interleave ) ,
289- Just ( MutationType :: Prefix ) ,
290- Just ( MutationType :: Suffix ) ,
291- Just ( MutationType :: Abi ) ,
289+ Just ( MutationType :: GenPrefix ) ,
290+ Just ( MutationType :: GenSuffix ) ,
291+ Just ( MutationType :: GenMutate ) ,
292292 ]
293293 . boxed ( ) ;
294294
@@ -531,30 +531,33 @@ impl WorkerCorpus {
531531 new_seq. push ( tx) ;
532532 }
533533 }
534- MutationType :: Prefix => {
534+ MutationType :: GenPrefix => {
535535 let corpus = if rng. random :: < bool > ( ) { primary } else { secondary } ;
536- trace ! ( target: "corpus" , "overwrite prefix of {}" , corpus. uuid) ;
536+ trace ! ( target: "corpus" , "generate prefix of {}" , corpus. uuid) ;
537537
538538 self . current_mutated = Some ( corpus. uuid ) ;
539539
540540 new_seq = corpus. tx_seq . clone ( ) ;
541+ // Generate new calls for a random prefix (0 to all elements).
541542 for i in 0 ..rng. random_range ( 0 ..=new_seq. len ( ) ) {
542543 new_seq[ i] = self . new_tx ( test_runner) ?;
543544 }
544545 }
545- MutationType :: Suffix => {
546+ MutationType :: GenSuffix => {
546547 let corpus = if rng. random :: < bool > ( ) { primary } else { secondary } ;
547- trace ! ( target: "corpus" , "overwrite suffix of {}" , corpus. uuid) ;
548+ trace ! ( target: "corpus" , "generate suffix of {}" , corpus. uuid) ;
548549
549550 self . current_mutated = Some ( corpus. uuid ) ;
550551
551552 new_seq = corpus. tx_seq . clone ( ) ;
552- for i in new_seq. len ( ) - rng. random_range ( 0 ..new_seq. len ( ) ) ..corpus. tx_seq . len ( )
553- {
554- new_seq[ i] = self . new_tx ( test_runner) ?;
553+ // Generate new calls for a random suffix (0 to all elements).
554+ let len = new_seq. len ( ) ;
555+ let start = len - rng. random_range ( 0 ..len) ;
556+ for tx in new_seq. iter_mut ( ) . skip ( start) {
557+ * tx = self . new_tx ( test_runner) ?;
555558 }
556559 }
557- MutationType :: Abi => {
560+ MutationType :: GenMutate => {
558561 let targets = targeted_contracts. targets . lock ( ) ;
559562 let corpus = if rng. random :: < bool > ( ) { primary } else { secondary } ;
560563 trace ! ( target: "corpus" , "ABI mutate args of {}" , corpus. uuid) ;
@@ -563,20 +566,20 @@ impl WorkerCorpus {
563566
564567 new_seq = corpus. tx_seq . clone ( ) ;
565568
566- // 30% chance to mutate ALL calls in the sequence.
567- // This helps break multi-constraint bugs where any call could hit the target.
568- if rng . random_range ( 0 .. 10 ) < 3 {
569- for tx in & mut new_seq {
570- if let ( _ , Some ( function ) ) = targets . fuzzed_artifacts ( tx )
571- && !function . inputs . is_empty ( )
572- {
573- self . abi_mutate ( tx , function , test_runner , fuzz_state , senders ) ? ;
574- }
575- }
576- } else {
577- // Standard: mutate a single random call.
578- let idx = rng . random_range ( 0 ..new_seq . len ( ) ) ;
579- let tx = new_seq. get_mut ( idx ) . unwrap ( ) ;
569+ let len = new_seq . len ( ) ;
570+ // Mutate a random number of calls (1 to all), similar to how GenPrefix
571+ // generates a random number of new calls.
572+ let n_to_mutate = rng . random_range ( 1 ..=len ) ;
573+
574+ // Shuffle indices to select which calls to mutate.
575+ let mut indices : Vec < usize > = ( 0 ..len ) . collect ( ) ;
576+ for i in ( 1 ..len ) . rev ( ) {
577+ let j = rng . random_range ( 0 ..=i ) ;
578+ indices . swap ( i , j ) ;
579+ }
580+
581+ for i in indices . into_iter ( ) . take ( n_to_mutate ) {
582+ let tx = & mut new_seq[ i ] ;
580583 if let ( _, Some ( function) ) = targets. fuzzed_artifacts ( tx)
581584 && !function. inputs . is_empty ( )
582585 {
0 commit comments