use {
litesvm::LiteSVM,
solana_address::Address,
solana_hash::Hash,
solana_instruction::Instruction,
solana_keypair::{Keypair, Signature},
solana_message::{Message, MessageHeader},
solana_sdk_ids::system_program,
solana_signer::Signer,
solana_system_interface::instruction::SystemInstruction,
solana_transaction::{sanitized::MAX_TX_ACCOUNT_LOCKS, CompiledInstruction, Transaction},
solana_transaction_error::TransactionError,
wincode::Serialize,
};
#[test]
fn test_account_loaded_twice() {
let mut svm = LiteSVM::new();
let payer_kp = Keypair::new();
let payer_pk = payer_kp.pubkey();
svm.airdrop(&payer_pk, 1_000_000_000).unwrap();
let duplicate_account = Address::new_unique();
let data =
SystemInstruction::serialize(&SystemInstruction::Transfer { lamports: 500_000 }).unwrap();
let mut tx = Transaction {
signatures: vec![Signature::default()],
message: Message {
header: MessageHeader {
num_required_signatures: 1,
num_readonly_signed_accounts: 0,
num_readonly_unsigned_accounts: 1,
},
account_keys: vec![
payer_pk,
duplicate_account,
duplicate_account,
system_program::id(),
],
recent_blockhash: Hash::default(),
instructions: vec![
CompiledInstruction {
program_id_index: 3,
accounts: [0, 1].to_vec(),
data: data.clone(),
},
CompiledInstruction {
program_id_index: 3,
accounts: [0, 2].to_vec(),
data: data.clone(),
},
],
},
};
tx.sign(&[&payer_kp], svm.latest_blockhash());
let result = svm.send_transaction(tx);
assert_eq!(
result.unwrap_err().err,
TransactionError::AccountLoadedTwice,
"Expected AccountLoadedTwice error when same account is both writable and read-only"
);
}
#[test]
fn test_too_many_account_locks() {
use solana_system_interface::instruction::transfer;
let mut svm = LiteSVM::new();
let payer_kp = Keypair::new();
let payer_pk = payer_kp.pubkey();
svm.airdrop(&payer_pk, 1_000_000_000_000).unwrap();
let compute_budget_ix =
solana_compute_budget_interface::ComputeBudgetInstruction::set_compute_unit_limit(
1_000_000,
);
let mut instructions: Vec<Instruction> = vec![compute_budget_ix];
for _ in 0..MAX_TX_ACCOUNT_LOCKS {
let recipient = Address::new_unique();
let ix = transfer(&payer_pk, &recipient, 1_000_000);
instructions.push(ix);
}
let tx = Transaction::new(
&[&payer_kp],
Message::new(&instructions, Some(&payer_pk)),
svm.latest_blockhash(),
);
let result = svm.send_transaction(tx);
assert_eq!(
result.unwrap_err().err,
TransactionError::TooManyAccountLocks,
"Expected TooManyAccountLocks error when transaction has more than 64 accounts"
);
}
#[test]
fn test_too_many_account_locks_without_sigverify() {
use solana_system_interface::instruction::transfer;
let mut svm = LiteSVM::new().with_sigverify(false);
let payer_kp = Keypair::new();
let payer_pk = payer_kp.pubkey();
svm.airdrop(&payer_pk, 1_000_000_000_000).unwrap();
let compute_budget_ix =
solana_compute_budget_interface::ComputeBudgetInstruction::set_compute_unit_limit(
1_000_000,
);
let mut instructions: Vec<Instruction> = vec![compute_budget_ix];
for _ in 0..MAX_TX_ACCOUNT_LOCKS {
let recipient = Address::new_unique();
instructions.push(transfer(&payer_pk, &recipient, 1_000_000));
}
let tx = Transaction::new(
&[&payer_kp],
Message::new(&instructions, Some(&payer_pk)),
svm.latest_blockhash(),
);
let sim = svm.simulate_transaction(tx.clone());
assert_eq!(
sim.unwrap_err().err,
TransactionError::TooManyAccountLocks,
"simulate_transaction with sigverify disabled must still enforce the account-lock limit"
);
let result = svm.send_transaction(tx);
assert_eq!(
result.unwrap_err().err,
TransactionError::TooManyAccountLocks,
"send_transaction with sigverify disabled must still enforce the account-lock limit"
);
}