light_merkle_tree_program/utils/
accounts.rs1use std::convert::TryInto;
2
3use anchor_lang::{
4 err,
5 prelude::AccountLoader,
6 solana_program::{
7 account_info::AccountInfo, msg, program::invoke_signed, program_error::ProgramError,
8 pubkey::Pubkey, system_instruction, sysvar::rent::Rent,
9 },
10 Key, Owner, ZeroCopy,
11};
12
13use crate::{errors::ErrorCode, indexed_merkle_tree::IndexedMerkleTree};
14
15#[allow(clippy::too_many_arguments)]
16pub fn create_and_check_pda<'a, 'b>(
17 program_id: &Pubkey,
18 signer_account: &'a AccountInfo<'b>,
19 passed_in_pda: &'a AccountInfo<'b>,
20 system_program: &'a AccountInfo<'b>,
21 rent: &Rent,
22 _instruction_data: &[u8],
23 domain_separation_seed: &[u8],
24 number_storage_bytes: u64,
25 lamports: u64,
26 rent_exempt: bool,
27) -> Result<(), ProgramError> {
28 let derived_pubkey =
29 Pubkey::find_program_address(&[_instruction_data, domain_separation_seed], program_id);
30
31 if derived_pubkey.0 != *passed_in_pda.key {
32 msg!("Passed-in pda pubkey != on-chain derived pda pubkey.");
33 msg!("On-chain derived pda pubkey {:?}", derived_pubkey);
34 msg!("Passed-in pda pubkey {:?}", *passed_in_pda.key);
35 msg!("Instruction data seed {:?}", _instruction_data);
36 return Err(ProgramError::InvalidInstructionData);
37 }
38
39 let mut account_lamports = lamports;
40 if rent_exempt {
41 account_lamports += rent.minimum_balance(number_storage_bytes.try_into().unwrap());
42 }
43
44 invoke_signed(
45 &system_instruction::create_account(
46 signer_account.key, passed_in_pda.key, account_lamports, number_storage_bytes, program_id, ),
52 &[
53 signer_account.clone(),
54 passed_in_pda.clone(),
55 system_program.clone(),
56 ],
57 &[&[
58 _instruction_data,
59 domain_separation_seed,
60 &[derived_pubkey.1],
61 ]],
62 )?;
63
64 if rent_exempt
66 && !rent.is_exempt(
67 **passed_in_pda.lamports.borrow(),
68 number_storage_bytes.try_into().unwrap(),
69 )
70 {
71 msg!("Account is not rent exempt.");
72 return Err(ProgramError::AccountNotRentExempt);
73 }
74 Ok(())
75}
76
77pub fn deserialize_and_update_old_merkle_tree<T>(
81 account: &AccountInfo,
82 seed: &[u8],
83 program_id: &Pubkey,
84) -> anchor_lang::Result<()>
85where
86 T: IndexedMerkleTree + ZeroCopy + Owner,
87{
88 let loader: AccountLoader<T> = AccountLoader::try_from(account)?;
89 let pubkey = loader.key();
90 let mut merkle_tree = loader.load_mut()?;
91 let index = merkle_tree.get_index();
92
93 let (expected_pubkey, _) =
94 Pubkey::find_program_address(&[seed, index.to_le_bytes().as_ref()], program_id);
95 if pubkey != expected_pubkey {
96 return err!(ErrorCode::InvalidOldMerkleTree);
97 }
98
99 if !merkle_tree.is_newest() {
100 return err!(ErrorCode::NotNewestOldMerkleTree);
101 }
102 merkle_tree.set_newest(false);
103
104 Ok(())
105}