light_merkle_tree_program/transaction_merkle_tree/update_instructions/
insert_root.rs

1use std::ops::DerefMut;
2
3use anchor_lang::{
4    prelude::*,
5    solana_program::{clock::Clock, pubkey::Pubkey, sysvar::Sysvar},
6};
7
8use crate::{
9    errors::ErrorCode,
10    transaction_merkle_tree::{
11        instructions::insert_last_double,
12        state::{TransactionMerkleTree, TwoLeavesBytesPda},
13    },
14    utils::constants::{IX_ORDER, ROOT_INSERT, STORAGE_SEED},
15    MerkleTreeUpdateState,
16};
17#[derive(Accounts)]
18pub struct InsertRoot<'info> {
19    #[account(mut, address=merkle_tree_update_state.load()?.relayer @ErrorCode::InvalidAuthority)]
20    pub authority: Signer<'info>,
21    /// CHECK:` merkle_tree_update_state is derived correctly
22    /// Merkle tree is locked by merkle_tree_update_state
23    /// Is in correct instruction for root insert thus Merkle Tree update has been completed.
24    /// The account is closed to the authority at the end of the instruction.
25    #[account(
26        mut,
27        seeds = [authority.key().to_bytes().as_ref(), STORAGE_SEED],
28        bump,
29        constraint= transaction_merkle_tree.load()?.pubkey_locked == merkle_tree_update_state.key() @ErrorCode::ContractStillLocked,
30        constraint= IX_ORDER[usize::try_from(merkle_tree_update_state.load()?.current_instruction_index).unwrap()] == ROOT_INSERT @ErrorCode::MerkleTreeUpdateNotInRootInsert,
31        close = authority
32    )]
33    /// CHECK: we need to check it's a right recipient account.
34    // pub recipient: AccountInfo<'info>,
35    pub merkle_tree_update_state: AccountLoader<'info, MerkleTreeUpdateState>,
36    /// CHECK:` that the merkle tree is whitelisted and consistent with merkle_tree_update_state.
37    #[account(mut, address= merkle_tree_update_state.load()?.merkle_tree_pda_pubkey @ErrorCode::InvalidMerkleTree)]
38    pub transaction_merkle_tree: AccountLoader<'info, TransactionMerkleTree>,
39    /// CHECK:` checking manually in wrapper function
40    pub log_wrapper: UncheckedAccount<'info>,
41    pub system_program: Program<'info, System>,
42}
43
44pub fn close_account(account: &AccountInfo, dest_account: &AccountInfo) -> Result<()> {
45    //close account by draining lamports
46    let dest_starting_lamports = dest_account.lamports();
47    **dest_account.lamports.borrow_mut() = dest_starting_lamports
48        .checked_add(account.lamports())
49        .ok_or(ErrorCode::CloseAccountFailed)?;
50    **account.lamports.borrow_mut() = 0;
51    let mut data = account.try_borrow_mut_data()?;
52    for byte in data.deref_mut().iter_mut() {
53        *byte = 0;
54    }
55    Ok(())
56}
57
58pub fn process_insert_root<'a, 'b, 'c, 'info>(
59    ctx: &mut Context<'a, 'b, 'c, 'info, InsertRoot<'info>>,
60) -> Result<()> {
61    let merkle_tree_update_state_data = &mut ctx.accounts.merkle_tree_update_state.load_mut()?;
62    let merkle_tree_pda_data = &mut ctx.accounts.transaction_merkle_tree.load_mut()?;
63
64    let id =
65        IX_ORDER[usize::try_from(merkle_tree_update_state_data.current_instruction_index).unwrap()];
66    msg!("Root insert Instruction: {}", id);
67
68    msg!(
69        "merkle_tree_pda_data.pubkey_locked: {:?}",
70        merkle_tree_pda_data.pubkey_locked
71    );
72
73    msg!(
74        "ctx.accounts.merkle_tree_update_state.key(): {:?}",
75        ctx.accounts.merkle_tree_update_state.key()
76    );
77
78    let mut tmp_index = merkle_tree_pda_data.next_index;
79    msg!("tmp_index: {}", tmp_index);
80
81    // insert root into merkle tree
82
83    // Release lock
84    msg!("Lock set at slot: {}", merkle_tree_pda_data.time_locked);
85    msg!("Lock released at slot: {}", <Clock as Sysvar>::get()?.slot);
86    merkle_tree_pda_data.time_locked = 0;
87    merkle_tree_pda_data.pubkey_locked =
88        Pubkey::try_from([0; 32]).map_err(|_| ErrorCode::PubkeyTryFromFailed)?;
89
90    msg!("start loop {}", ctx.remaining_accounts.len());
91    // Leaves are passed in as pdas in remaining accounts to allow for flexibility in their
92    // number.
93    // Checks are:
94    //             - are not inserted yet
95    //             - belong to merkle_tree
96    //             - the lowest index is the next index of the merkle_tree
97    //             - indices increase incrementally by 2 for subsequent leaves
98    // Copying leaves to tmp account.
99    for (index, account) in ctx.remaining_accounts.iter().enumerate() {
100        msg!("Copying leaves pair {}", index);
101        msg!("account {:?}", account);
102        let leaves_pda_data: Account<'info, TwoLeavesBytesPda> = Account::try_from(account)?;
103
104        // Checking that leaves are not inserted already.
105        if leaves_pda_data.left_leaf_index < merkle_tree_pda_data.next_index {
106            msg!(
107                "Leaf pda state with address {:?} is already inserted",
108                *account.key
109            );
110            return err!(ErrorCode::LeafAlreadyInserted);
111        }
112
113        // Checking that the Merkle tree is the same as in leaves account.
114        if leaves_pda_data.merkle_tree_pubkey != ctx.accounts.transaction_merkle_tree.key() {
115            msg!(
116                "Leaf pda state merkle tree {} is different than passed in merkle tree {:?}",
117                leaves_pda_data.merkle_tree_pubkey,
118                ctx.accounts.transaction_merkle_tree.key()
119            );
120            return err!(ErrorCode::LeavesOfWrongTree);
121        }
122
123        // Checking that the lowest index is the next index of the merkle_tree.
124        // Check that following leaves are correct and in the right order.
125        if leaves_pda_data.left_leaf_index != tmp_index {
126            return err!(ErrorCode::FirstLeavesPdaIncorrectIndex);
127        }
128        close_account(account, &ctx.accounts.authority.to_account_info())?;
129
130        tmp_index += 2;
131    }
132
133    insert_last_double(merkle_tree_pda_data, merkle_tree_update_state_data)?;
134
135    Ok(())
136}