1use crate::address_merkle_tree_config::{get_address_bundle_config, get_state_bundle_config};
2use crate::create_account_instruction;
3use account_compression::{
4 AddressMerkleTreeConfig, AddressQueueConfig, NullifierQueueConfig, QueueAccount,
5 StateMerkleTreeConfig,
6};
7
8use crate::indexer::{AddressMerkleTreeAccounts, StateMerkleTreeAccounts};
9use light_client::rpc::{RpcConnection, RpcError};
10use light_registry::account_compression_cpi::sdk::{
11 create_rollover_state_merkle_tree_instruction, CreateRolloverMerkleTreeInstructionInputs,
12};
13use light_registry::protocol_config::state::ProtocolConfig;
14use light_registry::sdk::{
15 create_register_forester_instruction, create_update_forester_pda_instruction,
16};
17use light_registry::utils::get_forester_pda;
18use light_registry::{ForesterConfig, ForesterPda};
19use solana_sdk::{
20 instruction::Instruction,
21 pubkey::Pubkey,
22 signature::{Keypair, Signer},
23};
24
25pub async fn register_test_forester<R: RpcConnection>(
27 rpc: &mut R,
28 governance_authority: &Keypair,
29 forester_authority: &Pubkey,
30 config: ForesterConfig,
31) -> Result<(), RpcError> {
32 let ix = create_register_forester_instruction(
33 &governance_authority.pubkey(),
34 &governance_authority.pubkey(),
35 forester_authority,
36 config,
37 );
38 rpc.create_and_send_transaction(
39 &[ix],
40 &governance_authority.pubkey(),
41 &[governance_authority],
42 )
43 .await?;
44 assert_registered_forester(
45 rpc,
46 forester_authority,
47 ForesterPda {
48 authority: *forester_authority,
49 config,
50 active_weight: 1,
51 ..Default::default()
52 },
53 )
54 .await
55}
56
57pub async fn update_test_forester<R: RpcConnection>(
58 rpc: &mut R,
59 forester_authority: &Keypair,
60 derivation_key: &Pubkey,
61 new_forester_authority: Option<&Keypair>,
62 config: ForesterConfig,
63) -> Result<(), RpcError> {
64 let mut pre_account_state = rpc
65 .get_anchor_account::<ForesterPda>(&get_forester_pda(derivation_key).0)
66 .await?
67 .unwrap();
68 let (signers, new_forester_authority) = if let Some(new_authority) = new_forester_authority {
69 pre_account_state.authority = new_authority.pubkey();
70
71 (
72 vec![forester_authority, &new_authority],
73 Some(new_authority.pubkey()),
74 )
75 } else {
76 (vec![forester_authority], None)
77 };
78 let ix = create_update_forester_pda_instruction(
79 &forester_authority.pubkey(),
80 derivation_key,
81 new_forester_authority,
82 Some(config),
83 );
84
85 rpc.create_and_send_transaction(&[ix], &forester_authority.pubkey(), &signers)
86 .await?;
87
88 pre_account_state.config = config;
89 assert_registered_forester(rpc, derivation_key, pre_account_state).await
90}
91
92pub async fn assert_registered_forester<R: RpcConnection>(
93 rpc: &mut R,
94 forester: &Pubkey,
95 expected_account: ForesterPda,
96) -> Result<(), RpcError> {
97 let pda = get_forester_pda(forester).0;
98 let account_data = rpc.get_anchor_account::<ForesterPda>(&pda).await?.unwrap();
99 if account_data != expected_account {
100 return Err(RpcError::AssertRpcError(format!(
101 "Expected account data: {:?}, got: {:?}",
102 expected_account, account_data
103 )));
104 }
105 Ok(())
106}
107
108pub struct RentExemption {
109 pub size: usize,
110 pub lamports: u64,
111}
112
113pub async fn get_rent_exemption_for_address_merkle_tree_and_queue<R: RpcConnection>(
114 rpc: &mut R,
115 address_merkle_tree_config: &AddressMerkleTreeConfig,
116 address_queue_config: &AddressQueueConfig,
117) -> (RentExemption, RentExemption) {
118 let queue_size = QueueAccount::size(address_queue_config.capacity as usize).unwrap();
119
120 let queue_rent_exempt_lamports = rpc
121 .get_minimum_balance_for_rent_exemption(queue_size)
122 .await
123 .unwrap();
124 let tree_size = account_compression::state::AddressMerkleTreeAccount::size(
125 address_merkle_tree_config.height as usize,
126 address_merkle_tree_config.changelog_size as usize,
127 address_merkle_tree_config.roots_size as usize,
128 address_merkle_tree_config.canopy_depth as usize,
129 address_merkle_tree_config.address_changelog_size as usize,
130 );
131 let merkle_tree_rent_exempt_lamports = rpc
132 .get_minimum_balance_for_rent_exemption(tree_size)
133 .await
134 .unwrap();
135 (
136 RentExemption {
137 lamports: merkle_tree_rent_exempt_lamports,
138 size: tree_size,
139 },
140 RentExemption {
141 lamports: queue_rent_exempt_lamports,
142 size: queue_size,
143 },
144 )
145}
146
147pub async fn get_rent_exemption_for_state_merkle_tree_and_queue<R: RpcConnection>(
148 rpc: &mut R,
149 merkle_tree_config: &StateMerkleTreeConfig,
150 queue_config: &NullifierQueueConfig,
151) -> (RentExemption, RentExemption) {
152 let queue_size = QueueAccount::size(queue_config.capacity as usize).unwrap();
153
154 let queue_rent_exempt_lamports = rpc
155 .get_minimum_balance_for_rent_exemption(queue_size)
156 .await
157 .unwrap();
158 let tree_size = account_compression::state::StateMerkleTreeAccount::size(
159 merkle_tree_config.height as usize,
160 merkle_tree_config.changelog_size as usize,
161 merkle_tree_config.roots_size as usize,
162 merkle_tree_config.canopy_depth as usize,
163 );
164 let merkle_tree_rent_exempt_lamports = rpc
165 .get_minimum_balance_for_rent_exemption(tree_size)
166 .await
167 .unwrap();
168 (
169 RentExemption {
170 lamports: merkle_tree_rent_exempt_lamports,
171 size: tree_size,
172 },
173 RentExemption {
174 lamports: queue_rent_exempt_lamports,
175 size: queue_size,
176 },
177 )
178}
179
180#[allow(clippy::too_many_arguments)]
181pub async fn create_rollover_address_merkle_tree_instructions<R: RpcConnection>(
182 rpc: &mut R,
183 authority: &Pubkey,
184 new_nullifier_queue_keypair: &Keypair,
185 new_address_merkle_tree_keypair: &Keypair,
186 merkle_tree_pubkey: &Pubkey,
187 nullifier_queue_pubkey: &Pubkey,
188 epoch: u64,
189 is_metadata_forester: bool,
190) -> Vec<Instruction> {
191 let (merkle_tree_config, queue_config) = get_address_bundle_config(
192 rpc,
193 AddressMerkleTreeAccounts {
194 merkle_tree: *merkle_tree_pubkey,
195 queue: *nullifier_queue_pubkey,
196 },
197 )
198 .await;
199 let (merkle_tree_rent_exemption, queue_rent_exemption) =
200 get_rent_exemption_for_address_merkle_tree_and_queue(
201 rpc,
202 &merkle_tree_config,
203 &queue_config,
204 )
205 .await;
206 let create_nullifier_queue_instruction = create_account_instruction(
207 authority,
208 queue_rent_exemption.size,
209 queue_rent_exemption.lamports,
210 &account_compression::ID,
211 Some(new_nullifier_queue_keypair),
212 );
213 let create_state_merkle_tree_instruction = create_account_instruction(
214 authority,
215 merkle_tree_rent_exemption.size,
216 merkle_tree_rent_exemption.lamports,
217 &account_compression::ID,
218 Some(new_address_merkle_tree_keypair),
219 );
220 let instruction = light_registry::account_compression_cpi::sdk::create_rollover_address_merkle_tree_instruction(
221 CreateRolloverMerkleTreeInstructionInputs {
222 authority: *authority,
223 new_queue: new_nullifier_queue_keypair.pubkey(),
224 new_merkle_tree: new_address_merkle_tree_keypair.pubkey(),
225 old_queue: *nullifier_queue_pubkey,
226 old_merkle_tree: *merkle_tree_pubkey,
227 cpi_context_account: None,
228 is_metadata_forester,
229 },epoch
230 );
231 vec![
232 create_nullifier_queue_instruction,
233 create_state_merkle_tree_instruction,
234 instruction,
235 ]
236}
237
238#[allow(clippy::too_many_arguments)]
239pub async fn perform_state_merkle_tree_roll_over<R: RpcConnection>(
240 rpc: &mut R,
241 authority: &Keypair,
242 new_nullifier_queue_keypair: &Keypair,
243 new_state_merkle_tree_keypair: &Keypair,
244 merkle_tree_pubkey: &Pubkey,
245 nullifier_queue_pubkey: &Pubkey,
246 epoch: u64,
247 is_metadata_forester: bool,
248) -> Result<(), RpcError> {
249 let instructions = create_rollover_address_merkle_tree_instructions(
250 rpc,
251 &authority.pubkey(),
252 new_nullifier_queue_keypair,
253 new_state_merkle_tree_keypair,
254 merkle_tree_pubkey,
255 nullifier_queue_pubkey,
256 epoch,
257 is_metadata_forester,
258 )
259 .await;
260 rpc.create_and_send_transaction(
261 &instructions,
262 &authority.pubkey(),
263 &[
264 authority,
265 new_nullifier_queue_keypair,
266 new_state_merkle_tree_keypair,
267 ],
268 )
269 .await?;
270 Ok(())
271}
272#[allow(clippy::too_many_arguments)]
273pub async fn create_rollover_state_merkle_tree_instructions<R: RpcConnection>(
274 rpc: &mut R,
275 authority: &Pubkey,
276 new_nullifier_queue_keypair: &Keypair,
277 new_state_merkle_tree_keypair: &Keypair,
278 new_cpi_context_keypair: &Keypair,
279 merkle_tree_pubkey: &Pubkey,
280 nullifier_queue_pubkey: &Pubkey,
281 epoch: u64,
282 is_metadata_forester: bool,
283) -> Vec<Instruction> {
284 let (merkle_tree_config, queue_config) = get_state_bundle_config(
285 rpc,
286 StateMerkleTreeAccounts {
287 merkle_tree: *merkle_tree_pubkey,
288 nullifier_queue: *nullifier_queue_pubkey,
289 cpi_context: new_cpi_context_keypair.pubkey(),
290 },
291 )
292 .await;
293 let (state_merkle_tree_rent_exemption, queue_rent_exemption) =
294 get_rent_exemption_for_state_merkle_tree_and_queue(rpc, &merkle_tree_config, &queue_config)
295 .await;
296 let create_nullifier_queue_instruction = create_account_instruction(
297 authority,
298 queue_rent_exemption.size,
299 queue_rent_exemption.lamports,
300 &account_compression::ID,
301 Some(new_nullifier_queue_keypair),
302 );
303 let create_state_merkle_tree_instruction = create_account_instruction(
304 authority,
305 state_merkle_tree_rent_exemption.size,
306 state_merkle_tree_rent_exemption.lamports,
307 &account_compression::ID,
308 Some(new_state_merkle_tree_keypair),
309 );
310 let account_size: usize = ProtocolConfig::default().cpi_context_size as usize;
311 let create_cpi_context_account_instruction = create_account_instruction(
312 authority,
313 account_size,
314 rpc.get_minimum_balance_for_rent_exemption(account_size)
315 .await
316 .unwrap(),
317 &light_system_program::ID,
318 Some(new_cpi_context_keypair),
319 );
320 let instruction = create_rollover_state_merkle_tree_instruction(
321 CreateRolloverMerkleTreeInstructionInputs {
322 authority: *authority,
323 new_queue: new_nullifier_queue_keypair.pubkey(),
324 new_merkle_tree: new_state_merkle_tree_keypair.pubkey(),
325 old_queue: *nullifier_queue_pubkey,
326 old_merkle_tree: *merkle_tree_pubkey,
327 cpi_context_account: Some(new_cpi_context_keypair.pubkey()),
328 is_metadata_forester,
329 },
330 epoch,
331 );
332 vec![
333 create_nullifier_queue_instruction,
334 create_state_merkle_tree_instruction,
335 create_cpi_context_account_instruction,
336 instruction,
337 ]
338}