11use super :: InvariantContract ;
22use crate :: executors:: RawCallResult ;
3+ use alloy_json_abi:: Function ;
34use alloy_primitives:: { Address , Bytes } ;
4- use foundry_config:: InvariantConfig ;
55use foundry_evm_core:: decode:: RevertDecoder ;
66use foundry_evm_fuzz:: { BasicTxDetails , Reason , invariant:: FuzzRunIdentifiedContracts } ;
77use proptest:: test_runner:: TestError ;
8+ use std:: { collections:: HashMap , fmt} ;
89
910/// Stores information about failures and reverts of the invariant tests.
1011#[ derive( Clone , Default ) ]
@@ -14,16 +15,40 @@ pub struct InvariantFailures {
1415 /// The latest revert reason of a run.
1516 pub revert_reason : Option < String > ,
1617 /// Maps a broken invariant to its specific error.
17- pub error : Option < InvariantFuzzError > ,
18+ pub errors : HashMap < String , InvariantFuzzError > ,
1819}
1920
2021impl InvariantFailures {
2122 pub fn new ( ) -> Self {
2223 Self :: default ( )
2324 }
2425
25- pub fn into_inner ( self ) -> ( usize , Option < InvariantFuzzError > ) {
26- ( self . reverts , self . error )
26+ pub fn into_inner ( self ) -> ( usize , HashMap < String , InvariantFuzzError > ) {
27+ ( self . reverts , self . errors )
28+ }
29+
30+ pub fn record_failure ( & mut self , invariant : & Function , failure : InvariantFuzzError ) {
31+ self . errors . insert ( invariant. name . clone ( ) , failure) ;
32+ }
33+
34+ pub fn has_failure ( & self , invariant : & Function ) -> bool {
35+ self . errors . contains_key ( & invariant. name )
36+ }
37+
38+ pub fn get_failure ( & self , invariant : & Function ) -> Option < & InvariantFuzzError > {
39+ self . errors . get ( & invariant. name )
40+ }
41+
42+ pub fn can_continue ( & self , invariants : usize ) -> bool {
43+ self . errors . len ( ) < invariants
44+ }
45+ }
46+
47+ impl fmt:: Display for InvariantFailures {
48+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
49+ writeln ! ( f) ?;
50+ writeln ! ( f, " ❌ Failures: {}" , self . errors. len( ) ) ?;
51+ Ok ( ( ) )
2752 }
2853}
2954
@@ -70,10 +95,11 @@ pub struct FailedInvariantCaseData {
7095impl FailedInvariantCaseData {
7196 pub fn new (
7297 invariant_contract : & InvariantContract < ' _ > ,
73- invariant_config : & InvariantConfig ,
98+ shrink_run_limit : u32 ,
99+ fail_on_revert : bool ,
74100 targeted_contracts : & FuzzRunIdentifiedContracts ,
75101 calldata : & [ BasicTxDetails ] ,
76- call_result : RawCallResult ,
102+ call_result : & RawCallResult ,
77103 inner_sequence : & [ Option < BasicTxDetails > ] ,
78104 ) -> Self {
79105 // Collect abis of fuzzed and invariant contracts to decode custom error.
@@ -82,7 +108,7 @@ impl FailedInvariantCaseData {
82108 . with_abi ( invariant_contract. abi )
83109 . decode ( call_result. result . as_ref ( ) , call_result. exit_reason ) ;
84110
85- let func = invariant_contract. invariant_function ;
111+ let func = invariant_contract. invariant_fn ;
86112 debug_assert ! ( func. inputs. is_empty( ) ) ;
87113 let origin = func. name . as_str ( ) ;
88114 Self {
@@ -95,8 +121,8 @@ impl FailedInvariantCaseData {
95121 addr : invariant_contract. address ,
96122 calldata : func. selector ( ) . to_vec ( ) . into ( ) ,
97123 inner_sequence : inner_sequence. to_vec ( ) ,
98- shrink_run_limit : invariant_config . shrink_run_limit ,
99- fail_on_revert : invariant_config . fail_on_revert ,
124+ shrink_run_limit,
125+ fail_on_revert,
100126 }
101127 }
102128}
0 commit comments