1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use std::ops::DerefMut;

use anchor_lang::{
    prelude::*,
    solana_program::{clock::Clock, pubkey::Pubkey, sysvar::Sysvar},
};

use crate::{
    errors::ErrorCode,
    transaction_merkle_tree::{
        instructions::insert_last_double,
        state::{TransactionMerkleTree, TwoLeavesBytesPda},
    },
    utils::constants::{IX_ORDER, ROOT_INSERT, STORAGE_SEED},
    MerkleTreeUpdateState,
};
#[derive(Accounts)]
pub struct InsertRoot<'info> {
    #[account(mut, address=merkle_tree_update_state.load()?.relayer @ErrorCode::InvalidAuthority)]
    pub authority: Signer<'info>,
    /// CHECK:` merkle_tree_update_state is derived correctly
    /// Merkle tree is locked by merkle_tree_update_state
    /// Is in correct instruction for root insert thus Merkle Tree update has been completed.
    /// The account is closed to the authority at the end of the instruction.
    #[account(
        mut,
        seeds = [authority.key().to_bytes().as_ref(), STORAGE_SEED],
        bump,
        constraint= transaction_merkle_tree.load()?.pubkey_locked == merkle_tree_update_state.key() @ErrorCode::ContractStillLocked,
        constraint= IX_ORDER[usize::try_from(merkle_tree_update_state.load()?.current_instruction_index).unwrap()] == ROOT_INSERT @ErrorCode::MerkleTreeUpdateNotInRootInsert,
        close = authority
    )]
    /// CHECK: we need to check it's a right recipient account.
    // pub recipient: AccountInfo<'info>,
    pub merkle_tree_update_state: AccountLoader<'info, MerkleTreeUpdateState>,
    /// CHECK:` that the merkle tree is whitelisted and consistent with merkle_tree_update_state.
    #[account(mut, address= merkle_tree_update_state.load()?.merkle_tree_pda_pubkey @ErrorCode::InvalidMerkleTree)]
    pub transaction_merkle_tree: AccountLoader<'info, TransactionMerkleTree>,
    /// CHECK:` checking manually in wrapper function
    pub log_wrapper: UncheckedAccount<'info>,
    pub system_program: Program<'info, System>,
}

pub fn close_account(account: &AccountInfo, dest_account: &AccountInfo) -> Result<()> {
    //close account by draining lamports
    let dest_starting_lamports = dest_account.lamports();
    **dest_account.lamports.borrow_mut() = dest_starting_lamports
        .checked_add(account.lamports())
        .ok_or(ErrorCode::CloseAccountFailed)?;
    **account.lamports.borrow_mut() = 0;
    let mut data = account.try_borrow_mut_data()?;
    for byte in data.deref_mut().iter_mut() {
        *byte = 0;
    }
    Ok(())
}

pub fn process_insert_root<'a, 'b, 'c, 'info>(
    ctx: &mut Context<'a, 'b, 'c, 'info, InsertRoot<'info>>,
) -> Result<()> {
    let merkle_tree_update_state_data = &mut ctx.accounts.merkle_tree_update_state.load_mut()?;
    let merkle_tree_pda_data = &mut ctx.accounts.transaction_merkle_tree.load_mut()?;

    let id =
        IX_ORDER[usize::try_from(merkle_tree_update_state_data.current_instruction_index).unwrap()];
    msg!("Root insert Instruction: {}", id);

    msg!(
        "merkle_tree_pda_data.pubkey_locked: {:?}",
        merkle_tree_pda_data.pubkey_locked
    );

    msg!(
        "ctx.accounts.merkle_tree_update_state.key(): {:?}",
        ctx.accounts.merkle_tree_update_state.key()
    );

    let mut tmp_index = merkle_tree_pda_data.next_index;
    msg!("tmp_index: {}", tmp_index);

    // insert root into merkle tree

    // Release lock
    msg!("Lock set at slot: {}", merkle_tree_pda_data.time_locked);
    msg!("Lock released at slot: {}", <Clock as Sysvar>::get()?.slot);
    merkle_tree_pda_data.time_locked = 0;
    merkle_tree_pda_data.pubkey_locked =
        Pubkey::try_from([0; 32]).map_err(|_| ErrorCode::PubkeyTryFromFailed)?;

    msg!("start loop {}", ctx.remaining_accounts.len());
    // Leaves are passed in as pdas in remaining accounts to allow for flexibility in their
    // number.
    // Checks are:
    //             - are not inserted yet
    //             - belong to merkle_tree
    //             - the lowest index is the next index of the merkle_tree
    //             - indices increase incrementally by 2 for subsequent leaves
    // Copying leaves to tmp account.
    for (index, account) in ctx.remaining_accounts.iter().enumerate() {
        msg!("Copying leaves pair {}", index);
        msg!("account {:?}", account);
        let leaves_pda_data: Account<'info, TwoLeavesBytesPda> = Account::try_from(account)?;

        // Checking that leaves are not inserted already.
        if leaves_pda_data.left_leaf_index < merkle_tree_pda_data.next_index {
            msg!(
                "Leaf pda state with address {:?} is already inserted",
                *account.key
            );
            return err!(ErrorCode::LeafAlreadyInserted);
        }

        // Checking that the Merkle tree is the same as in leaves account.
        if leaves_pda_data.merkle_tree_pubkey != ctx.accounts.transaction_merkle_tree.key() {
            msg!(
                "Leaf pda state merkle tree {} is different than passed in merkle tree {:?}",
                leaves_pda_data.merkle_tree_pubkey,
                ctx.accounts.transaction_merkle_tree.key()
            );
            return err!(ErrorCode::LeavesOfWrongTree);
        }

        // Checking that the lowest index is the next index of the merkle_tree.
        // Check that following leaves are correct and in the right order.
        if leaves_pda_data.left_leaf_index != tmp_index {
            return err!(ErrorCode::FirstLeavesPdaIncorrectIndex);
        }
        close_account(account, &ctx.accounts.authority.to_account_info())?;

        tmp_index += 2;
    }

    insert_last_double(merkle_tree_pda_data, merkle_tree_update_state_data)?;

    Ok(())
}