Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debug-mode detailed output #125

Merged
merged 6 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions crates/client/derive/display_ix/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,33 @@ pub fn display_ix(input: TokenStream) -> TokenStream {

let display_impl = match &input.data {
Data::Enum(enum_data) => {
let to_context_string_match_arms = enum_data.variants.iter().map(|variant| {
let variant_name = &variant.ident;
quote! {
#enum_name::#variant_name (_) => String::from(stringify!(#variant_name)),
}
});
let display_match_arms = enum_data.variants.iter().map(|variant| {
let variant_name = &variant.ident;

quote! {
#enum_name::#variant_name (_) => write!(f, stringify!(#variant_name)),
match &variant.fields {
syn::Fields::Unnamed(fields) => {
if fields.unnamed.len() == 1 {
quote! {
#enum_name::#variant_name(ref content) => {
write!(f, stringify!(#variant_name))?;
write!(f, "({:#?})", content)
},
}
} else {
quote! {
#enum_name::#variant_name (_) => write!(f, stringify!(#variant_name)),
}
}
},
_ => quote! {
#enum_name::#variant_name => write!(f, stringify!(#variant_name)),
},
}
});

Expand All @@ -25,6 +47,13 @@ pub fn display_ix(input: TokenStream) -> TokenStream {
}
}
}
impl #enum_name {
fn to_context_string(&self)->String{
match self {
#(#to_context_string_match_arms)*
}
}
}
}
}
_ => panic!("DisplayIx can only be derived for enums"),
Expand Down
16 changes: 7 additions & 9 deletions crates/client/derive/fuzz_test_executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn fuzz_test_executor(input: TokenStream) -> TokenStream {
#enum_name::#variant_name (ix) => {
let (mut signers, metas) =
if let Ok(acc) = ix.get_accounts(client, &mut accounts.borrow_mut())
.map_err(|e| e.with_origin(Origin::Instruction(self.to_string()))) {
.map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string()))) {
acc
} else {
return Ok(());
Expand All @@ -25,7 +25,7 @@ pub fn fuzz_test_executor(input: TokenStream) -> TokenStream {
snaphot.capture_before(client).unwrap();
let data =
if let Ok(data) = ix.get_data(client, &mut accounts.borrow_mut())
.map_err(|e| e.with_origin(Origin::Instruction(self.to_string()))) {
.map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string()))) {
data
} else {
return Ok(());
Expand All @@ -42,19 +42,17 @@ pub fn fuzz_test_executor(input: TokenStream) -> TokenStream {
transaction.sign(&sig, client.get_last_blockhash());

let res = client.process_transaction(transaction)
.map_err(|e| e.with_origin(Origin::Instruction(self.to_string())));
.map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string())));

// this can return FuzzClientErrorWithOrigin
snaphot.capture_after(client).unwrap();
let (acc_before, acc_after) = snaphot.get_snapshot()
.map_err(|e| e.with_origin(Origin::Instruction(self.to_string()))).unwrap(); // we want to panic if we cannot unwrap to cause a crash
.map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string()))).unwrap(); // we want to panic if we cannot unwrap to cause a crash

if let Err(e) = ix.check(acc_before, acc_after, data).map_err(|e| e.with_origin(Origin::Instruction(self.to_string()))) {
if let Err(e) = ix.check(acc_before, acc_after, data).map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string()))) {
eprintln!(
"Custom check after the {} instruction did not pass with the error message: {}",
self, e
);
eprintln!("Instruction data submitted to the instruction were:"); // TODO data does not implement Debug trait -> derive Debug trait on InitializeIx and automaticaly implement conversion from Initialize to InitializeIx
"CRASH DETECTED! Custom check after the {} instruction did not pass!",
self.to_context_string());
panic!("{}", e)
}

Expand Down
48 changes: 46 additions & 2 deletions crates/client/src/fuzzer/data_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,17 @@ where
// fuzz_target=info",
// );

// #[cfg(fuzzing_debug)]
#[cfg(fuzzing_debug)]
{
eprintln!("Instructions sequence:");
for ix in self.iter() {
eprintln!("{}", ix);
}
eprintln!("------ End of Instructions sequence ------ ");
}

for fuzz_ix in &mut self.iter() {
// #[cfg(fuzzing_debug)]
#[cfg(fuzzing_debug)]
eprintln!("Currently processing: {}", fuzz_ix);

fuzz_ix.run_fuzzer(program_id, &self.accounts, client)?;
Expand Down Expand Up @@ -212,6 +213,49 @@ macro_rules! fuzz_trd {
});
};
}
/// Prints the details of a given account in a pretty-printed format.
///
/// This macro takes a single argument, which is an expression referring to the account
/// you want to print. The account data structure must implement or derive the [`Debug`]
/// trait for this macro to work, as it relies on `std::fmt::Debug` for formatting.
///
/// # Examples
///
/// ```rust,ignore
/// use trdelnik_client::fuzzing::show_account;
///
/// #[derive(Debug)]
/// #[account]
/// struct Escrow {
/// recipeint: Pubkey,
/// id: u32,
/// balance: f64,
/// name: String,
/// }
///
/// fn check(
/// &self,
/// pre_ix: Self::IxSnapshot,
/// post_ix: Self::IxSnapshot,
/// ix_data: Self::IxData,
/// ) -> Result<(), FuzzingError> {
/// if let Some(escrow) = pre_ix.escrow{
/// show_account!(escrow);
/// }
/// }
/// ```
///
/// # Requirements
///
/// The `account` passed to `show_account!` must implement or derive the [`Debug`] trait.
/// Attempting to use this macro with a type that does not meet this requirement will
/// result in a compilation error.
#[macro_export]
macro_rules! show_account {
($account:expr) => {
eprintln!("{:#?}", $account);
};
}

pub fn build_ix_fuzz_data<U: for<'a> Arbitrary<'a>, T: FuzzDataBuilder<U>, V: Default>(
_data_builder: T,
Expand Down
8 changes: 4 additions & 4 deletions crates/client/src/fuzzer/fuzzer_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub fn generate_source_code(idl: &Idl) -> String {
.collect::<Vec<_>>();

let ix_enum_variant: syn::ItemStruct = parse_quote! {
#[derive(Arbitrary, Clone)]
#[derive(Arbitrary, Debug)]
pub struct #instruction_name {
pub accounts: #instruction_accounts_name,
pub data: #instruction_data_name
Expand All @@ -88,14 +88,14 @@ pub fn generate_source_code(idl: &Idl) -> String {
};

let ix_accounts: syn::ItemStruct = parse_quote! {
#[derive(Arbitrary, Clone)]
#[derive(Arbitrary, Debug)]
pub struct #instruction_accounts_name {
#(pub #accounts),*
}

};
let ix_data: syn::ItemStruct = parse_quote! {
#[derive(Arbitrary, Clone)]
#[derive(Arbitrary, Debug)]
pub struct #instruction_data_name {
#(pub #parameters),*
}
Expand Down Expand Up @@ -208,7 +208,7 @@ pub fn generate_source_code(idl: &Idl) -> String {
use trdelnik_client::fuzzing::*;
use crate::accounts_snapshots::*;

#[derive(Arbitrary, Clone, DisplayIx, FuzzTestExecutor, FuzzDeserialize)]
#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)]
pub enum FuzzInstruction {
#(#instructions),*
}
Expand Down
4 changes: 2 additions & 2 deletions crates/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ pub mod fuzzing {
pub use super::{
anchor_lang, anchor_lang::system_program::ID as SYSTEM_PROGRAM_ID,
anchor_lang::InstructionData, anchor_lang::ToAccountInfo, anchor_lang::ToAccountMetas,
fuzz_trd, solana_sdk::account::Account, solana_sdk::transaction::Transaction, Instruction,
Keypair, Pubkey, Signer, TempClone,
fuzz_trd, show_account, solana_sdk::account::Account, solana_sdk::transaction::Transaction,
Instruction, Keypair, Pubkey, Signer, TempClone,
};
pub use anchor_client::anchor_lang::solana_program::account_info::AccountInfo;
pub use anchor_client::anchor_lang::solana_program::hash::Hash;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
pub mod fuzz_example3_fuzz_instructions {
use crate::accounts_snapshots::*;
use trdelnik_client::fuzzing::*;
#[derive(Arbitrary, Clone, DisplayIx, FuzzTestExecutor, FuzzDeserialize)]
#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)]
pub enum FuzzInstruction {
InitVesting(InitVesting),
WithdrawUnlocked(WithdrawUnlocked),
}
#[derive(Arbitrary, Clone)]
#[derive(Arbitrary, Debug)]
pub struct InitVesting {
pub accounts: InitVestingAccounts,
pub data: InitVestingData,
}
#[derive(Arbitrary, Clone)]
#[derive(Arbitrary, Debug)]
pub struct InitVestingAccounts {
pub sender: AccountId,
pub sender_token_account: AccountId,
Expand All @@ -21,7 +21,7 @@ pub mod fuzz_example3_fuzz_instructions {
pub token_program: AccountId,
pub system_program: AccountId,
}
#[derive(Arbitrary, Clone)]
#[derive(Arbitrary, Debug)]
pub struct InitVestingData {
pub recipient: AccountId,
pub _recipient: AccountId,
Expand All @@ -30,12 +30,12 @@ pub mod fuzz_example3_fuzz_instructions {
pub end_at: u64,
pub interval: u64,
}
#[derive(Arbitrary, Clone)]
#[derive(Arbitrary, Debug)]
pub struct WithdrawUnlocked {
pub accounts: WithdrawUnlockedAccounts,
pub data: WithdrawUnlockedData,
}
#[derive(Arbitrary, Clone)]
#[derive(Arbitrary, Debug)]
pub struct WithdrawUnlockedAccounts {
pub recipient: AccountId,
pub recipient_token_account: AccountId,
Expand All @@ -46,7 +46,7 @@ pub mod fuzz_example3_fuzz_instructions {
pub token_program: AccountId,
pub system_program: AccountId,
}
#[derive(Arbitrary, Clone)]
#[derive(Arbitrary, Debug)]
pub struct WithdrawUnlockedData {}
impl<'info> IxOps<'info> for InitVesting {
type IxData = fuzz_example3::instruction::InitVesting;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,22 @@ pub enum FuzzInstruction {
impl std::fmt::Display for FuzzInstruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FuzzInstruction::InitVesting(_) => f.write_fmt(format_args!("InitVesting")),
FuzzInstruction::WithdrawUnlocked(_) => {
f.write_fmt(format_args!("WithdrawUnlocked"))
FuzzInstruction::InitVesting(ref content) => {
f.write_fmt(format_args!("InitVesting"))?;
f.write_fmt(format_args!("({0:#?})", content))
}
FuzzInstruction::WithdrawUnlocked(ref content) => {
f.write_fmt(format_args!("WithdrawUnlocked"))?;
f.write_fmt(format_args!("({0:#?})", content))
}
}
}
}
impl FuzzInstruction {
fn to_context_string(&self) -> String {
match self {
FuzzInstruction::InitVesting(_) => String::from("InitVesting"),
FuzzInstruction::WithdrawUnlocked(_) => String::from("WithdrawUnlocked"),
}
}
}
Expand Down
Loading
Loading