solana/programs/bpf/tests/programs.rs

509 lines
18 KiB
Rust
Raw Normal View History

2020-08-14 12:32:45 -07:00
#![cfg(any(feature = "bpf_c", feature = "bpf_rust"))]
#[macro_use]
extern crate solana_bpf_loader_program;
use solana_runtime::{
bank::Bank,
bank_client::BankClient,
genesis_utils::{create_genesis_config, GenesisConfigInfo},
loader_utils::load_program,
};
use solana_sdk::{
account::Account,
bpf_loader, bpf_loader_deprecated,
2020-08-14 12:32:45 -07:00
client::SyncClient,
clock::DEFAULT_SLOTS_PER_EPOCH,
entrypoint::MAX_PERMITTED_DATA_INCREASE,
2020-08-14 12:32:45 -07:00
instruction::{AccountMeta, Instruction, InstructionError},
message::Message,
pubkey::Pubkey,
signature::Keypair,
signature::Signer,
sysvar::{clock, fees, rent, rewards, slot_hashes, stake_history},
transaction::TransactionError,
};
use std::{env, fs::File, io::Read, path::PathBuf, sync::Arc};
/// BPF program file extension
const PLATFORM_FILE_EXTENSION_BPF: &str = "so";
/// Create a BPF program file name
fn create_bpf_path(name: &str) -> PathBuf {
let mut pathbuf = {
let current_exe = env::current_exe().unwrap();
PathBuf::from(current_exe.parent().unwrap().parent().unwrap())
2020-03-17 15:59:09 -07:00
};
2020-08-14 12:32:45 -07:00
pathbuf.push("bpf/");
pathbuf.push(name);
pathbuf.set_extension(PLATFORM_FILE_EXTENSION_BPF);
pathbuf
}
2019-03-02 21:33:02 -08:00
fn load_bpf_program(
bank_client: &BankClient,
loader_id: &Pubkey,
payer_keypair: &Keypair,
name: &str,
) -> Pubkey {
2020-08-14 12:32:45 -07:00
let path = create_bpf_path(name);
let mut file = File::open(path).unwrap();
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
load_program(bank_client, payer_keypair, loader_id, elf)
2020-08-14 12:32:45 -07:00
}
2020-03-17 15:59:09 -07:00
2020-08-14 12:32:45 -07:00
#[test]
#[cfg(any(feature = "bpf_c", feature = "bpf_rust"))]
fn test_program_bpf_sanity() {
solana_logger::setup();
let mut programs = Vec::new();
#[cfg(feature = "bpf_c")]
{
programs.extend_from_slice(&[
("bpf_to_bpf", true),
("multiple_static", true),
("noop", true),
("noop++", true),
("panic", false),
("relative_call", true),
("struct_pass", true),
("struct_ret", true),
]);
}
#[cfg(feature = "bpf_rust")]
{
programs.extend_from_slice(&[
("solana_bpf_rust_128bit", true),
("solana_bpf_rust_alloc", true),
("solana_bpf_rust_dep_crate", true),
("solana_bpf_rust_external_spend", false),
("solana_bpf_rust_iter", true),
("solana_bpf_rust_many_args", true),
("solana_bpf_rust_noop", true),
("solana_bpf_rust_panic", false),
("solana_bpf_rust_param_passing", true),
("solana_bpf_rust_sysval", true),
]);
2020-03-17 19:37:16 -07:00
}
2020-08-14 12:32:45 -07:00
for program in programs.iter() {
println!("Test program: {:?}", program.0);
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
let bank = Arc::new(bank);
// Create bank with a specific slot, used by solana_bpf_rust_sysvar test
let bank = Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1);
let bank_client = BankClient::new(bank);
// Call user program
let program_id =
load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program.0);
2020-08-14 12:32:45 -07:00
let account_metas = vec![
AccountMeta::new(mint_keypair.pubkey(), true),
AccountMeta::new(Keypair::new().pubkey(), false),
AccountMeta::new(clock::id(), false),
AccountMeta::new(fees::id(), false),
AccountMeta::new(rewards::id(), false),
AccountMeta::new(slot_hashes::id(), false),
AccountMeta::new(stake_history::id(), false),
AccountMeta::new(rent::id(), false),
];
let instruction = Instruction::new(program_id, &1u8, account_metas);
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
if program.1 {
assert!(result.is_ok());
2020-08-14 12:32:45 -07:00
} else {
assert!(result.is_err());
}
2020-03-17 15:59:09 -07:00
}
2020-08-14 12:32:45 -07:00
}
#[test]
#[cfg(any(feature = "bpf_c", feature = "bpf_rust"))]
fn test_program_bpf_loader_deprecated() {
solana_logger::setup();
let mut programs = Vec::new();
#[cfg(feature = "bpf_c")]
{
programs.extend_from_slice(&[("deprecated_loader")]);
}
#[cfg(feature = "bpf_rust")]
{
programs.extend_from_slice(&[("solana_bpf_rust_deprecated_loader")]);
}
for program in programs.iter() {
println!("Test program: {:?}", program);
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_deprecated_program!();
bank.add_builtin_loader(&name, id, entrypoint);
let bank_client = BankClient::new(bank);
let program_id = load_bpf_program(
&bank_client,
&bpf_loader_deprecated::id(),
&mint_keypair,
program,
);
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
let instruction = Instruction::new(program_id, &1u8, account_metas);
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert!(result.is_ok());
}
}
2020-08-14 12:32:45 -07:00
#[test]
fn test_program_bpf_duplicate_accounts() {
solana_logger::setup();
2020-08-14 12:32:45 -07:00
let mut programs = Vec::new();
#[cfg(feature = "bpf_c")]
{
programs.extend_from_slice(&[("dup_accounts")]);
}
#[cfg(feature = "bpf_rust")]
{
programs.extend_from_slice(&[("solana_bpf_rust_dup_accounts")]);
}
2020-03-17 15:59:09 -07:00
2020-08-14 12:32:45 -07:00
for program in programs.iter() {
println!("Test program: {:?}", program);
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program);
2020-08-14 12:32:45 -07:00
let payee_account = Account::new(10, 1, &program_id);
let payee_pubkey = Pubkey::new_rand();
bank.store_account(&payee_pubkey, &payee_account);
let account = Account::new(10, 1, &program_id);
let pubkey = Pubkey::new_rand();
let account_metas = vec![
AccountMeta::new(mint_keypair.pubkey(), true),
AccountMeta::new(payee_pubkey, false),
AccountMeta::new(pubkey, false),
AccountMeta::new(pubkey, false),
];
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &1u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
assert!(result.is_ok());
assert_eq!(data[0], 1);
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &2u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
assert!(result.is_ok());
assert_eq!(data[0], 2);
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &3u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
assert!(result.is_ok());
assert_eq!(data[0], 3);
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &4u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
let lamports = bank_client.get_balance(&pubkey).unwrap();
assert!(result.is_ok());
assert_eq!(lamports, 11);
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &5u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
let lamports = bank_client.get_balance(&pubkey).unwrap();
assert!(result.is_ok());
assert_eq!(lamports, 12);
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &6u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
let lamports = bank_client.get_balance(&pubkey).unwrap();
assert!(result.is_ok());
assert_eq!(lamports, 13);
}
}
2020-08-14 12:32:45 -07:00
#[test]
fn test_program_bpf_error_handling() {
solana_logger::setup();
2020-08-14 12:32:45 -07:00
let mut programs = Vec::new();
#[cfg(feature = "bpf_c")]
{
programs.extend_from_slice(&[("error_handling")]);
}
#[cfg(feature = "bpf_rust")]
{
programs.extend_from_slice(&[("solana_bpf_rust_error_handling")]);
}
2020-08-14 12:32:45 -07:00
for program in programs.iter() {
println!("Test program: {:?}", program);
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
let bank_client = BankClient::new(bank);
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program);
2020-08-14 12:32:45 -07:00
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
let instruction = Instruction::new(program_id, &1u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert!(result.is_ok());
let instruction = Instruction::new(program_id, &2u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert_eq!(
result.unwrap_err().unwrap(),
TransactionError::InstructionError(0, InstructionError::InvalidAccountData)
);
let instruction = Instruction::new(program_id, &3u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert_eq!(
result.unwrap_err().unwrap(),
TransactionError::InstructionError(0, InstructionError::Custom(0))
);
let instruction = Instruction::new(program_id, &4u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert_eq!(
result.unwrap_err().unwrap(),
TransactionError::InstructionError(0, InstructionError::Custom(42))
);
let instruction = Instruction::new(program_id, &5u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
let result = result.unwrap_err().unwrap();
if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) != result
{
assert_eq!(
2020-08-14 12:32:45 -07:00
result,
TransactionError::InstructionError(0, InstructionError::InvalidError)
);
2020-08-14 12:32:45 -07:00
}
2020-08-14 12:32:45 -07:00
let instruction = Instruction::new(program_id, &6u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
let result = result.unwrap_err().unwrap();
if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) != result
{
assert_eq!(
2020-08-14 12:32:45 -07:00
result,
TransactionError::InstructionError(0, InstructionError::InvalidError)
);
2020-08-14 12:32:45 -07:00
}
2020-08-14 12:32:45 -07:00
let instruction = Instruction::new(program_id, &7u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
let result = result.unwrap_err().unwrap();
if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) != result
{
assert_eq!(
2020-08-14 12:32:45 -07:00
result,
TransactionError::InstructionError(0, InstructionError::AccountBorrowFailed)
);
}
2020-08-14 12:32:45 -07:00
let instruction = Instruction::new(program_id, &8u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert_eq!(
result.unwrap_err().unwrap(),
TransactionError::InstructionError(0, InstructionError::InvalidInstructionData)
);
let instruction = Instruction::new(program_id, &9u8, account_metas.clone());
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert_eq!(
result.unwrap_err().unwrap(),
TransactionError::InstructionError(0, InstructionError::MaxSeedLengthExceeded)
);
}
2020-08-14 12:32:45 -07:00
}
2020-04-28 14:33:56 -07:00
2020-08-14 12:32:45 -07:00
#[test]
fn test_program_bpf_invoke() {
solana_logger::setup();
2020-04-28 14:33:56 -07:00
2020-08-14 12:32:45 -07:00
const TEST_SUCCESS: u8 = 1;
const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2;
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
2020-08-14 12:32:45 -07:00
let mut programs = Vec::new();
#[cfg(feature = "bpf_c")]
{
programs.extend_from_slice(&[("invoke", "invoked")]);
}
#[cfg(feature = "bpf_rust")]
{
programs.extend_from_slice(&[("solana_bpf_rust_invoke", "solana_bpf_rust_invoked")]);
}
2020-04-28 14:33:56 -07:00
2020-08-14 12:32:45 -07:00
for program in programs.iter() {
println!("Test program: {:?}", program);
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
let invoke_program_id =
load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program.0);
let invoked_program_id =
load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program.1);
2020-08-14 12:32:45 -07:00
let argument_keypair = Keypair::new();
let account = Account::new(42, 100, &invoke_program_id);
2020-08-14 12:32:45 -07:00
bank.store_account(&argument_keypair.pubkey(), &account);
let invoked_argument_keypair = Keypair::new();
let account = Account::new(10, 10, &invoked_program_id);
bank.store_account(&invoked_argument_keypair.pubkey(), &account);
let from_keypair = Keypair::new();
let account = Account::new(84, 0, &solana_sdk::system_program::id());
2020-08-14 12:32:45 -07:00
bank.store_account(&from_keypair.pubkey(), &account);
let (derived_key1, nonce1) =
Pubkey::find_program_address(&[b"You pass butter"], &invoke_program_id);
let (derived_key2, nonce2) =
Pubkey::find_program_address(&[b"Lil'", b"Bits"], &invoke_program_id);
2020-08-14 12:32:45 -07:00
let (derived_key3, nonce3) =
Pubkey::find_program_address(&[derived_key2.as_ref()], &invoke_program_id);
2020-08-14 12:32:45 -07:00
let mint_pubkey = mint_keypair.pubkey();
let account_metas = vec![
AccountMeta::new(mint_pubkey, true),
AccountMeta::new(argument_keypair.pubkey(), true),
AccountMeta::new_readonly(invoked_program_id, false),
AccountMeta::new(invoked_argument_keypair.pubkey(), true),
AccountMeta::new_readonly(invoked_program_id, false),
AccountMeta::new(argument_keypair.pubkey(), true),
AccountMeta::new(derived_key1, false),
AccountMeta::new(derived_key2, false),
AccountMeta::new_readonly(derived_key3, false),
AccountMeta::new_readonly(solana_sdk::system_program::id(), false),
AccountMeta::new(from_keypair.pubkey(), true),
];
// success cases
let instruction = Instruction::new(
invoke_program_id,
&[TEST_SUCCESS, nonce1, nonce2, nonce3],
account_metas.clone(),
);
let message = Message::new(&[instruction], Some(&mint_pubkey));
assert!(bank_client
.send_and_confirm_message(
&[
&mint_keypair,
&argument_keypair,
&invoked_argument_keypair,
&from_keypair
],
message,
)
.is_ok());
// failure cases
let instruction = Instruction::new(
invoke_program_id,
&TEST_PRIVILEGE_ESCALATION_SIGNER,
account_metas.clone(),
);
let message = Message::new(&[instruction], Some(&mint_pubkey));
assert_eq!(
bank_client
.send_and_confirm_message(
Multi-version snapshot support (#9980) * Multi-version snapshot support * rustfmt * Remove CLI options and runtime support for selection output snapshot version. Address some clippy complaints. * Muzzle clippy type complexity warning. Despite clippy's suggestion, it is not currently possible to create type aliases for traits and so everything within the 'Box<...>' cannot be type aliased. This then leaves creating full blown traits, and either implementing said traits by closure (somehow) or moving the closures into new structs implementing said traits which seems a bit of a palaver. Alternatively it is possible to define and use the type alias 'type ResultBox<T> = Result<Box<T>>' which does seems rather pointless and not a great reduction in complexity but is enough to keep clippy happy. In the end I simply went with squelching the clippy warning. * Remove now unused Serialize/Deserialize trait implementations for AccountStorageEntry and AppendVec * refactor versioned de/serialisers * rename serde_utils to serde_snapshot * move call to accounts_db.generate_index() back down to context_accountsdb_from_stream() * update version 1.1.1 to 1.2.0 remove nested use of serialize_bytes * cleanups * Add back measurement of account storage entry serialization. Remove construction of Vec and HashMap temporaries during serialization. * consolidate serialisation test cases into serde_snapshot. clean up leakage of implementation details in serde_snapshot. * move short term / legacy snapshot code into child module * add serialize_iter_as_tuple * preliminary integration of following commit commit 6d58b73c47294bfb93465d5a83cd2175660b6e6d Author: Ryo Onodera <ryoqun@gmail.com> Date: Wed May 20 14:02:02 2020 +0900 Confine snapshot 1.1 relic to versioned codepath * refactored serde_snapshot, rustfmt legacy accounts_db format now "owns" both leading u64s, legacy bank_rc format has none * reduce type complexity (clippy)
2020-05-22 10:54:24 -07:00
&[
&mint_keypair,
&argument_keypair,
&invoked_argument_keypair,
&from_keypair
],
2020-04-28 14:33:56 -07:00
message,
)
2020-08-14 12:32:45 -07:00
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(0, InstructionError::Custom(194969602))
);
let instruction = Instruction::new(
invoke_program_id,
&TEST_PRIVILEGE_ESCALATION_WRITABLE,
account_metas.clone(),
);
let message = Message::new(&[instruction], Some(&mint_pubkey));
assert_eq!(
bank_client
.send_and_confirm_message(
&[
&mint_keypair,
&argument_keypair,
&invoked_argument_keypair,
&from_keypair
],
message,
)
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(0, InstructionError::Custom(194969602))
);
assert_eq!(43, bank.get_balance(&derived_key1));
let account = bank.get_account(&derived_key1).unwrap();
assert_eq!(invoke_program_id, account.owner);
assert_eq!(
MAX_PERMITTED_DATA_INCREASE,
bank.get_account(&derived_key1).unwrap().data.len()
);
for i in 0..20 {
assert_eq!(i as u8, account.data[i]);
}
2020-04-28 14:33:56 -07:00
}
}