magicsvm 0.2.0

A fast and lightweight Solana + MagicBlock VM simulator for testing solana programs
use {
    ephemeral_rollups_sdk::{
        access_control::structs::EphemeralPermission, consts::PERMISSION_PROGRAM_ID,
    },
    magicsvm::{MagicSVM, TransactionTarget},
    solana_address::Address,
    solana_keypair::Keypair,
    solana_signer::Signer,
};

const MEMBER_SIZE: usize = 33;

fn permission_account(
    permissioned_account: Address,
    private: bool,
    members: &[Address],
) -> magicblock_account::Account {
    let mut data = vec![0u8; 35 + members.len() * MEMBER_SIZE];
    data[0] = 1;
    data[2..34].copy_from_slice(permissioned_account.as_ref());
    data[34] = u8::from(private);
    for (index, member) in members.iter().enumerate() {
        let offset = 35 + index * MEMBER_SIZE;
        data[offset] = 1;
        data[offset + 1..offset + 33].copy_from_slice(member.as_ref());
    }
    magicblock_account::Account {
        lamports: 1_000_000,
        data,
        owner: PERMISSION_PROGRAM_ID,
        executable: false,
        rent_epoch: 0,
    }
}

fn secret_account() -> magicblock_account::Account {
    magicblock_account::Account {
        lamports: 1_000_000,
        data: vec![7, 8, 9],
        owner: Address::new_from_array([9; 32]),
        executable: false,
        rent_epoch: 0,
    }
}

fn put_ephemeral_account(
    svm: &mut MagicSVM,
    address: Address,
    account: magicblock_account::Account,
) {
    svm.ephemeral_mut().set_account(address, account).unwrap();
}

#[test_log::test]
fn private_account_is_hidden_until_authorized_user_is_a_member() {
    let member = Keypair::new().pubkey();
    let stranger = Keypair::new().pubkey();
    let secret = Address::new_from_array([3; 32]);
    let (permission_pda, _) = EphemeralPermission::find_pda(&secret);
    let mut svm = MagicSVM::new();
    put_ephemeral_account(&mut svm, secret, secret_account());
    put_ephemeral_account(
        &mut svm,
        permission_pda,
        permission_account(secret, true, &[member]),
    );

    assert!(svm
        .get_account_for(TransactionTarget::Ephemeral, &secret)
        .is_none());

    svm.set_authorized_user(Some(stranger));
    assert!(svm
        .get_account_for(TransactionTarget::Ephemeral, &secret)
        .is_none());

    svm.set_authorized_user(Some(member));
    let visible = svm
        .get_account_for(TransactionTarget::Ephemeral, &secret)
        .unwrap();
    assert_eq!(visible.data, vec![7, 8, 9]);

    svm.set_authorized_user(None);
    assert!(svm
        .get_account_for(TransactionTarget::Ephemeral, &secret)
        .is_none());
}

#[test_log::test]
fn public_permission_does_not_hide_ephemeral_accounts() {
    let secret = Address::new_from_array([4; 32]);
    let (permission_pda, _) = EphemeralPermission::find_pda(&secret);
    let mut svm = MagicSVM::new();
    put_ephemeral_account(&mut svm, secret, secret_account());
    put_ephemeral_account(
        &mut svm,
        permission_pda,
        permission_account(secret, false, &[]),
    );

    let visible = svm
        .get_account_for(TransactionTarget::Ephemeral, &secret)
        .unwrap();
    assert_eq!(visible.data, vec![7, 8, 9]);
}

#[test_log::test]
fn authorized_user_does_not_filter_base_accounts() {
    let member = Keypair::new().pubkey();
    let secret = Address::new_from_array([5; 32]);
    let (permission_pda, _) = EphemeralPermission::find_pda(&secret);
    let mut svm = MagicSVM::new();
    svm.set_account(
        secret,
        solana_account::Account {
            lamports: 1_000_000,
            data: vec![7, 8, 9],
            owner: Address::new_from_array([9; 32]),
            executable: false,
            rent_epoch: 0,
        },
    )
    .unwrap();
    put_ephemeral_account(
        &mut svm,
        permission_pda,
        permission_account(secret, true, &[member]),
    );

    assert!(svm
        .get_account_for(TransactionTarget::Base, &secret)
        .is_some());
}

#[test_log::test]
fn magic_svm_loads_permission_program_on_ephemeral() {
    let svm = MagicSVM::new();
    let program = svm.ephemeral().get_account(&PERMISSION_PROGRAM_ID).unwrap();
    assert!(program.executable);
}