mollusk_svm_fuzz_fixture/
lib.rs1pub mod account;
9pub mod compute_budget;
10pub mod context;
11pub mod effects;
12pub mod feature_set;
13pub mod proto {
14 include!(concat!(env!("OUT_DIR"), "/org.mollusk.svm.rs"));
15}
16pub mod sysvars;
17
18use {
19 crate::{context::Context, effects::Effects, proto::InstrFixture as ProtoFixture},
20 mollusk_svm_fuzz_fs::{FsHandler, IntoSerializableFixture, SerializableFixture},
21 solana_keccak_hasher::{Hash, Hasher},
22};
23
24#[derive(Clone, Debug, PartialEq)]
27pub struct Fixture {
28 pub input: Context,
30 pub output: Effects,
32}
33
34impl Fixture {
35 pub fn decode(blob: &[u8]) -> Self {
36 let proto_fixture = <ProtoFixture as SerializableFixture>::decode(blob);
37 proto_fixture.into()
38 }
39
40 pub fn load_from_blob_file(file_path: &str) -> Self {
41 let proto_fixture: ProtoFixture = FsHandler::load_from_blob_file(file_path);
42 proto_fixture.into()
43 }
44
45 pub fn load_from_json_file(file_path: &str) -> Self {
46 let proto_fixture: ProtoFixture = FsHandler::load_from_json_file(file_path);
47 proto_fixture.into()
48 }
49}
50
51impl From<ProtoFixture> for Fixture {
52 fn from(value: ProtoFixture) -> Self {
53 Self {
55 input: value.input.unwrap().into(),
56 output: value.output.unwrap().into(),
57 }
58 }
59}
60
61impl From<Fixture> for ProtoFixture {
62 fn from(value: Fixture) -> Self {
63 Self {
64 input: Some(value.input.into()),
65 output: Some(value.output.into()),
66 }
67 }
68}
69
70impl SerializableFixture for ProtoFixture {
71 fn hash(&self) -> Hash {
73 let mut hasher = Hasher::default();
74 if let Some(input) = &self.input {
75 crate::context::hash_proto_context(&mut hasher, input);
76 }
77 if let Some(output) = &self.output {
78 crate::effects::hash_proto_effects(&mut hasher, output);
79 }
80 hasher.result()
81 }
82}
83
84impl IntoSerializableFixture for Fixture {
85 type Fixture = ProtoFixture;
86
87 fn into(self) -> Self::Fixture {
88 Into::into(self)
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use {
95 super::{proto::InstrFixture, Fixture},
96 crate::{context::Context, effects::Effects, sysvars::Sysvars},
97 agave_feature_set::FeatureSet,
98 mollusk_svm_fuzz_fs::SerializableFixture,
99 solana_account::Account,
100 solana_compute_budget::compute_budget::ComputeBudget,
101 solana_instruction::AccountMeta,
102 solana_keccak_hasher::Hash,
103 solana_pubkey::Pubkey,
104 };
105
106 fn produce_hash(fixture: &Fixture) -> Hash {
107 let proto_fixture: InstrFixture = fixture.clone().into();
108 proto_fixture.hash()
109 }
110
111 #[test]
112 fn test_consistent_hashing() {
113 const ITERATIONS: usize = 1000;
114
115 let compute_budget = ComputeBudget::new_with_defaults(true, true);
116
117 let feature_set = FeatureSet::all_enabled();
118 let sysvars = Sysvars::default();
119 let program_id = Pubkey::default();
120 let instruction_accounts = vec![
121 AccountMeta::new(Pubkey::new_unique(), false),
122 AccountMeta::new(Pubkey::new_unique(), false),
123 AccountMeta::new(Pubkey::new_unique(), false),
124 AccountMeta::new(Pubkey::new_unique(), false),
125 ];
126 let instruction_data = vec![4; 24];
127 let accounts = instruction_accounts
128 .iter()
129 .map(|meta| (meta.pubkey, Account::new(42, 42, &Pubkey::default())))
130 .collect::<Vec<_>>();
131
132 let context = Context {
133 compute_budget,
134 feature_set,
135 sysvars,
136 program_id,
137 instruction_accounts,
138 instruction_data,
139 accounts,
140 };
141 let effects = Effects::default();
142
143 let fixture = Fixture {
144 input: context,
145 output: effects,
146 };
147
148 let mut last_hash = produce_hash(&fixture);
149 for _ in 0..ITERATIONS {
150 let new_hash = produce_hash(&fixture);
151 assert_eq!(last_hash, new_hash);
152 last_hash = new_hash;
153 }
154 }
155}