55 solana_instruction:: error:: InstructionError ,
66 solana_program_error:: ProgramError ,
77 solana_pubkey:: Pubkey ,
8+ solana_rent:: Rent ,
89} ;
910
1011macro_rules! compare {
@@ -122,6 +123,19 @@ impl Default for Config {
122123 }
123124}
124125
126+ /// A trait for providing context to the checks.
127+ ///
128+ /// Developers who run checks on standalone results, rather than passing checks
129+ /// directly to methods like `Mollusk::process_and_validate_instruction`, may
130+ /// wish to customize the context in which the checks are run. For example,
131+ /// one may wish to evaluate resulting account lamports with a custom `Rent`
132+ /// configuration. This trait allows such customization.
133+ pub trait CheckContext {
134+ fn is_rent_exempt ( & self , lamports : u64 , space : usize ) -> bool {
135+ Rent :: default ( ) . is_exempt ( lamports, space)
136+ }
137+ }
138+
125139impl InstructionResult {
126140 /// Get an account from the resulting accounts by its pubkey.
127141 pub fn get_account ( & self , pubkey : & Pubkey ) -> Option < & Account > {
@@ -131,8 +145,17 @@ impl InstructionResult {
131145 . map ( |( _, a) | a)
132146 }
133147
134- /// Perform checks on the instruction result.
135- pub fn run_checks_with_config ( & self , checks : & [ Check ] , config : & Config ) -> bool {
148+ /// Perform checks on the instruction result with a custom context.
149+ /// See `CheckContext` for more details.
150+ ///
151+ /// Note: `Mollusk` implements `CheckContext`, in case you don't want to
152+ /// define a custom context.
153+ pub fn run_checks < C : CheckContext > (
154+ & self ,
155+ checks : & [ Check ] ,
156+ config : & Config ,
157+ context : & C ,
158+ ) -> bool {
136159 let c = config;
137160 let mut pass = true ;
138161 for check in checks {
@@ -199,6 +222,17 @@ impl InstructionResult {
199222 resulting_account == & Account :: default ( ) ,
200223 ) ;
201224 }
225+ AccountStateCheck :: RentExempt => {
226+ pass &= compare ! (
227+ c,
228+ "account_rent_exempt" ,
229+ true ,
230+ context. is_rent_exempt(
231+ resulting_account. lamports,
232+ resulting_account. data. len( )
233+ ) ,
234+ ) ;
235+ }
202236 }
203237 }
204238 if let Some ( ( offset, check_data_slice) ) = account. check_data_slice {
@@ -225,17 +259,6 @@ impl InstructionResult {
225259 pass
226260 }
227261
228- /// Perform checks on the instruction result, panicking on any mismatches.
229- pub fn run_checks ( & self , checks : & [ Check ] ) {
230- self . run_checks_with_config (
231- checks,
232- & Config {
233- panic : true ,
234- verbose : true ,
235- } ,
236- ) ;
237- }
238-
239262 pub ( crate ) fn absorb ( & mut self , other : Self ) {
240263 self . compute_units_consumed += other. compute_units_consumed ;
241264 self . execution_time += other. execution_time ;
@@ -484,6 +507,7 @@ impl<'a> Check<'a> {
484507
485508enum AccountStateCheck {
486509 Closed ,
510+ RentExempt ,
487511}
488512
489513struct AccountCheck < ' a > {
@@ -548,6 +572,11 @@ impl<'a> AccountCheckBuilder<'a> {
548572 self
549573 }
550574
575+ pub fn rent_exempt ( mut self ) -> Self {
576+ self . check . check_state = Some ( AccountStateCheck :: RentExempt ) ;
577+ self
578+ }
579+
551580 pub fn space ( mut self , space : usize ) -> Self {
552581 self . check . check_space = Some ( space) ;
553582 self
0 commit comments