1use crate::utils::resolve_path;
2use base64::{prelude::BASE64_STANDARD, Engine};
3use serde::{Deserialize, Serialize};
4use solana_sdk::{
5 account::{AccountSharedData, WritableAccount},
6 pubkey::Pubkey,
7};
8use std::{fs, str::FromStr};
9
10#[derive(Debug, Deserialize, Clone, Default)]
11pub struct Fuzz {
12 pub fuzzing_with_stats: Option<bool>,
13 pub allow_duplicate_txs: Option<bool>,
14 pub programs: Option<Vec<_FuzzProgram>>,
15 pub accounts: Option<Vec<_FuzzAccount>>,
16}
17
18impl Fuzz {
19 pub fn get_fuzzing_with_stats(&self) -> bool {
20 self.fuzzing_with_stats.unwrap_or(false)
21 }
22 pub fn get_allow_duplicate_txs(&self) -> bool {
23 self.allow_duplicate_txs.unwrap_or(false)
24 }
25}
26
27#[derive(Debug, Deserialize, Clone)]
28pub struct _FuzzProgram {
29 pub address: String,
30 pub program: String,
31}
32
33#[derive(Debug, Deserialize, Clone)]
34pub struct _FuzzAccount {
35 pub address: String,
36 pub filename: String,
37}
38
39#[derive(Debug, Deserialize, Clone)]
40pub struct FuzzProgram {
41 pub address: Pubkey,
42 pub data: Vec<u8>,
43}
44
45impl From<&_FuzzProgram> for FuzzProgram {
46 fn from(_f: &_FuzzProgram) -> Self {
47 let program_path = &_f.program;
48 let program_address = &_f.address;
49
50 let path = resolve_path(program_path);
51
52 let program_data =
53 fs::read(path).unwrap_or_else(|_| panic!("Failed to read file: {}", program_path));
54
55 let pubkey = Pubkey::from_str(program_address)
56 .unwrap_or_else(|_| panic!("Cannot parse the program address: {}", program_address));
57
58 FuzzProgram {
59 address: pubkey,
60 data: program_data,
61 }
62 }
63}
64
65#[derive(Debug, Deserialize, Clone)]
66pub struct FuzzAccount {
67 pub pubkey: Pubkey,
68 pub account: AccountSharedData,
69}
70
71impl From<&_FuzzAccount> for FuzzAccount {
72 fn from(_f: &_FuzzAccount) -> Self {
73 let account_path = &_f.filename;
74
75 let path = resolve_path(account_path);
76
77 let file_content = fs::read_to_string(path)
78 .unwrap_or_else(|_| panic!("Failed to read file: {}", account_path));
79
80 let account_raw: FuzzAccountRaw = serde_json::from_str(&file_content)
81 .unwrap_or_else(|_| panic!("Failed to parse JSON from file: {}", account_path));
82
83 let pubkey = Pubkey::from_str(&account_raw.pubkey)
84 .unwrap_or_else(|_| panic!("Cannot convert address for: {}", account_raw.pubkey));
85
86 let owner_address = Pubkey::from_str(&account_raw.account.owner).unwrap_or_else(|_| {
87 panic!(
88 "Cannot convert address for owner: {}",
89 account_raw.account.owner
90 )
91 });
92
93 let data_base_64 = account_raw.account.data.first().unwrap_or_else(|| {
94 panic!(
95 "Cannot read base64 data for account: {}",
96 account_raw.pubkey
97 )
98 });
99
100 let account = AccountSharedData::create(
101 account_raw.account.lamports,
102 BASE64_STANDARD
103 .decode(data_base_64)
104 .unwrap_or_else(|_| panic!("Failed to decode base64 data of {}", account_path)),
105 owner_address,
106 account_raw.account.executable,
107 account_raw.account.rent_epoch,
108 );
109
110 FuzzAccount { pubkey, account }
111 }
112}
113
114#[derive(Debug, Deserialize, Clone)]
115pub struct FuzzAccountRaw {
116 pub pubkey: String,
117 pub account: AccountRaw,
118}
119
120#[derive(Debug, Serialize, Deserialize, Clone)]
121pub struct AccountRaw {
122 pub lamports: u64,
123 pub data: Vec<String>,
124 pub owner: String,
125 pub executable: bool,
126 #[serde(rename = "rentEpoch")]
127 pub rent_epoch: u64,
128}