trident_svm/
trident_svm.rs1use std::sync::Arc;
2use std::sync::RwLock;
3
4use solana_bpf_loader_program::syscalls::create_program_runtime_environment_v1;
5use solana_bpf_loader_program::syscalls::create_program_runtime_environment_v2;
6
7use solana_program_runtime::loaded_programs::ProgramCacheEntry;
8
9use solana_account::AccountSharedData;
10use solana_account::ReadableAccount;
11use solana_clock::Clock;
12use solana_epoch_rewards::EpochRewards;
13use solana_epoch_schedule::EpochSchedule;
14use solana_hash::Hash;
15use solana_keypair::Keypair;
16use solana_pubkey::pubkey;
17use solana_pubkey::Pubkey;
18use solana_rent::Rent;
19use solana_signer::Signer;
20use solana_slot_hashes::SlotHashes;
21use solana_svm_feature_set::SVMFeatureSet;
22#[allow(deprecated)]
23use solana_sysvar::fees::Fees;
24#[allow(deprecated)]
25use solana_sysvar::recent_blockhashes::IterItem;
26#[allow(deprecated)]
27use solana_sysvar::recent_blockhashes::RecentBlockhashes;
28
29use solana_slot_history::SlotHistory;
30
31use solana_stake_interface::stake_history::StakeHistory;
32
33use solana_svm::transaction_processing_callback::TransactionProcessingCallback;
34use solana_svm::transaction_processor::TransactionBatchProcessor;
35
36use solana_svm_callback::InvokeContextCallback;
37#[cfg(feature = "syscall-v2")]
38use trident_syscall_stubs_v2::set_stubs_v2;
39
40use crate::accounts_database::accounts_db::AccountsDB;
41use crate::builder::TridentSVMBuilder;
42
43use crate::trident_fork_graphs::TridentForkGraph;
44use crate::utils;
45use solana_builtins::BUILTINS;
46
47use solana_program_runtime::execution_budget::SVMTransactionExecutionBudget;
48
49use crate::types::trident_program::TridentProgram;
50use crate::utils::get_current_timestamp;
51
52pub struct TridentSVM {
53 pub(crate) accounts: AccountsDB,
54 pub(crate) payer: Keypair,
55 pub(crate) feature_set: Arc<SVMFeatureSet>,
56 pub(crate) processor: TransactionBatchProcessor<TridentForkGraph>,
57 pub(crate) fork_graph: Arc<RwLock<TridentForkGraph>>,
58}
59
60impl TridentSVM {
61 #[cfg(feature = "syscall-v2")]
62 pub(crate) fn initialize_syscalls_v2(&mut self) {
63 set_stubs_v2();
64 }
65}
66
67impl InvokeContextCallback for TridentSVM {}
68
69impl TransactionProcessingCallback for TridentSVM {
70 fn account_matches_owners(&self, account: &Pubkey, owners: &[Pubkey]) -> Option<usize> {
71 self.get_account_shared_data(account)
72 .and_then(|account| owners.iter().position(|key| account.owner().eq(key)))
73 }
74
75 fn get_account_shared_data(&self, pubkey: &Pubkey) -> Option<AccountSharedData> {
76 self.accounts.get_account(pubkey, false)
77 }
78}
79
80impl Default for TridentSVM {
81 fn default() -> Self {
82 let payer = Keypair::new();
83
84 let mut client = Self {
85 accounts: Default::default(),
86 payer: payer.insecure_clone(),
87 feature_set: Arc::new(SVMFeatureSet::default()),
88 processor: TransactionBatchProcessor::<TridentForkGraph>::new(
89 1,
90 1,
91 Arc::downgrade(&Arc::new(RwLock::new(TridentForkGraph {}))),
92 None,
93 None,
94 ),
95 fork_graph: Arc::new(RwLock::new(TridentForkGraph {})),
96 };
97
98 let payer_account = AccountSharedData::new(
99 500_000_000 * 1_000_000_000,
100 0,
101 &solana_sdk_ids::system_program::id(),
102 );
103 client
104 .accounts
105 .set_permanent_account(&payer.pubkey(), &payer_account);
106
107 client
108 .with_processor()
109 .with_sysvars()
110 .with_builtins()
111 .with_solana_program_library()
112 }
113}
114
115impl TridentSVM {
116 pub fn builder() -> TridentSVMBuilder {
117 TridentSVMBuilder::new()
118 }
119 fn with_processor(self) -> Self {
120 {
121 let compute_budget = SVMTransactionExecutionBudget::default();
122
123 let mut cache: std::sync::RwLockWriteGuard<
124 '_,
125 solana_program_runtime::loaded_programs::ProgramCache<TridentForkGraph>,
126 > = self
127 .processor
128 .program_cache
129 .write()
130 .expect("Failed to write to program cache");
131
132 cache.fork_graph = Some(Arc::downgrade(&self.fork_graph));
133
134 cache.environments.program_runtime_v1 = Arc::new(
135 create_program_runtime_environment_v1(
136 &self.feature_set,
137 &compute_budget,
138 false,
139 false,
140 )
141 .expect("Failed to create program runtime environment"),
142 );
143 cache.environments.program_runtime_v2 =
144 Arc::new(create_program_runtime_environment_v2(&compute_budget, true));
145 }
146
147 self
148 }
149
150 fn with_sysvars(mut self) -> Self {
151 let clock = Clock {
152 unix_timestamp: get_current_timestamp() as i64,
153 ..Default::default()
154 };
155 self.set_sysvar(&clock);
156 self.set_sysvar(&EpochRewards::default());
157 self.set_sysvar(&EpochSchedule::default());
158 #[allow(deprecated)]
159 let fees = Fees::default();
160 self.set_sysvar(&fees);
161 let latest_blockhash = Hash::default();
162 #[allow(deprecated)]
163 self.set_sysvar(&RecentBlockhashes::from_iter([IterItem(
164 0,
165 &latest_blockhash,
166 fees.fee_calculator.lamports_per_signature,
167 )]));
168 self.set_sysvar(&Rent::default());
169 self.set_sysvar(&SlotHashes::new(&[(0, latest_blockhash)]));
170 self.set_sysvar(&SlotHistory::default());
171 self.set_sysvar(&StakeHistory::default());
172
173 self
174 }
175 fn with_builtins(mut self) -> Self {
176 BUILTINS.iter().for_each(|builtint| {
177 self.accounts.set_program(
178 &builtint.program_id,
179 &utils::create_loadable_account_for_test(builtint.name),
180 );
181
182 self.processor.add_builtin(
183 &self,
184 builtint.program_id,
185 builtint.name,
186 ProgramCacheEntry::new_builtin(0, builtint.name.len(), builtint.entrypoint),
187 );
188 });
189
190 self
191 }
192 fn with_solana_program_library(mut self) -> Self {
193 let spl_token = TridentProgram::new(
194 pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
195 None,
196 include_bytes!("solana-program-library/spl-token-mainnet.so").to_vec(),
197 );
198
199 self.deploy_binary_program(&spl_token);
200
201 let spl_token_2022 = TridentProgram::new(
203 pubkey!("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),
204 None,
205 include_bytes!("solana-program-library/spl-2022-token-mainnet.so").to_vec(),
206 );
207
208 self.deploy_binary_program(&spl_token_2022);
209
210 let associated_token_program = TridentProgram::new(
211 pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
212 None,
213 include_bytes!("solana-program-library/associated-token-program-mainnet.so").to_vec(),
214 );
215
216 self.deploy_binary_program(&associated_token_program);
217
218 let metaplex_token_metadata = TridentProgram::new(
219 pubkey!("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"),
220 None,
221 include_bytes!("solana-program-library/metaplex-token-metadata.so").to_vec(),
222 );
223
224 self.deploy_binary_program(&metaplex_token_metadata);
225
226 let chainlink_oracle = TridentProgram::new(
229 pubkey!("HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny"),
230 None,
231 include_bytes!("solana-program-library/chainlink-oracle.so").to_vec(),
232 );
233
234 self.deploy_binary_program(&chainlink_oracle);
235
236 let spl_stake_pool = TridentProgram::new(
239 pubkey!("SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy"),
240 None,
241 include_bytes!("solana-program-library/spl-stake-pool.so").to_vec(),
242 );
243 self.deploy_binary_program(&spl_stake_pool);
244
245 let metaplex_candy_machine_v3 = TridentProgram::new(
247 pubkey!("CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR"),
248 None,
249 include_bytes!("solana-program-library/metaplex-candy-machine-v3.so").to_vec(),
250 );
251 self.deploy_binary_program(&metaplex_candy_machine_v3);
252
253 self
254 }
255
256 pub fn clear_accounts(&mut self) {
257 self.accounts.reset_temp();
258 }
259}