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
use solana_sdk::{keyed_account::KeyedAccount, pubkey::Pubkey};

/// Helper structure that wrap all solana accounts, that is needed for evm loader.
/// It will restrict and provide access to needed solana accounts in:
/// 1. Instruction handlers (ExecuteTx, SwapToEvm, FreeOwnership) - full access to evm state.
/// 2. Builtin contracts (SwapToNative) - Full access to evm state.
/// 3. User written evm2native callbacks (SwapERCToSol, CallSolMethod) - Full access to specific users account,
///   call from users account, read/credit access to evm state. (TBD)
///
#[derive(Copy, Clone, Debug)]
pub struct AccountStructure<'a> {
    pub evm: &'a KeyedAccount<'a>,
    pub users: &'a [KeyedAccount<'a>],
}


impl<'a> AccountStructure<'a> {
    /// Create new account structure, from keyed accounts.
    pub fn new(evm: &'a KeyedAccount<'a>, users: &'a [KeyedAccount<'a>]) -> AccountStructure<'a> {
        AccountStructure { evm, users }
    }

    /// Returns account of the first user.
    pub fn first(&self) -> Option<&KeyedAccount> {
        self.users.first()
    }

    /// Find user by its public key.
    pub fn find_user(&self, key: &Pubkey) -> Option<&KeyedAccount> {
        self.users.iter().find(|keyed| keyed.unsigned_key() == key)
    }

    /// Create AccountStructure for testing purposes, with random accounts.
    #[cfg(test)]
    pub(crate) fn testing<F, U>(num_keys: usize, func: F) -> U
    where
        F: for<'r> Fn(AccountStructure<'r>) -> U,
    {
        use solana_sdk::account::Account;
        use std::cell::RefCell;

        let evm_key = Pubkey::new_unique();
        let evm_account = RefCell::new(crate::create_state_account(0));
        let evm_state = KeyedAccount::new(&evm_key, false, &evm_account);

        let keys: Vec<_> = std::iter::repeat_with(|| {
            let user_key = Pubkey::new_unique();
            let user_account = RefCell::new(Account {
                lamports: 1000,
                data: vec![],
                owner: crate::ID,
                executable: false,
                rent_epoch: 0,
            });
            (user_key, user_account)
        })
        .take(num_keys + 1)
        .collect();
        let keyed_accounts: Vec<_> = keys
            .iter()
            .map(|(user_key, user_account)| KeyedAccount::new(&user_key, false, &user_account))
            .collect();
        let borrowed_keys: &[_] = &keyed_accounts;
        let structure = AccountStructure::new(&evm_state, borrowed_keys);
        func(structure)
    }
}