Skip to content

Commit

Permalink
svm: improve integration test program handling (#3094)
Browse files Browse the repository at this point in the history
* allow setting program upgrade authority
* ensure program accounts are rent-exempt
* set clock to execution epoch
  • Loading branch information
2501babe authored Oct 9, 2024
1 parent 07faf4a commit f9f8b60
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 36 deletions.
53 changes: 25 additions & 28 deletions svm/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

use {
crate::mock_bank::{
create_executable_environment, deploy_program, program_address, register_builtins,
MockBankCallback, MockForkGraph, WALLCLOCK_TIME,
create_executable_environment, deploy_program, deploy_program_with_upgrade_authority,
program_address, register_builtins, MockBankCallback, MockForkGraph, EXECUTION_EPOCH,
EXECUTION_SLOT, WALLCLOCK_TIME,
},
solana_sdk::{
account::{AccountSharedData, ReadableAccount, WritableAccount},
Expand Down Expand Up @@ -42,8 +43,6 @@ use {
mod mock_bank;

const DEPLOYMENT_SLOT: u64 = 0;
const EXECUTION_SLOT: u64 = 5; // The execution slot must be greater than the deployment slot
const EXECUTION_EPOCH: u64 = 2; // The execution epoch must be greater than the deployment epoch
const LAMPORTS_PER_SIGNATURE: u64 = 5000;
const LAST_BLOCKHASH: Hash = Hash::new_from_array([7; 32]); // Arbitrary constant hash for advancing nonces

Expand All @@ -55,8 +54,8 @@ pub struct SvmTestEntry {
// features are disabled by default; these will be enabled
pub enabled_features: Vec<Pubkey>,

// programs to deploy to the new svm before transaction execution
pub initial_programs: Vec<(String, Slot)>,
// programs to deploy to the new svm
pub initial_programs: Vec<(String, Slot, Option<Pubkey>)>,

// accounts to deploy to the new svm before transaction execution
pub initial_accounts: AccountsMap,
Expand All @@ -81,6 +80,12 @@ impl SvmTestEntry {
self.create_expected_account(pubkey, account);
}

// add an immutable program that will have been deployed before the slot we execute transactions in
pub fn add_initial_program(&mut self, program_name: &str) {
self.initial_programs
.push((program_name.to_string(), DEPLOYMENT_SLOT, None));
}

// add a new rent-exempt account that is created by the transaction
// inserts it only into the post account map
pub fn create_expected_account(&mut self, pubkey: Pubkey, account: &AccountSharedData) {
Expand Down Expand Up @@ -338,11 +343,9 @@ fn program_medley() -> Vec<SvmTestEntry> {

// 0: A transaction that works without any account
{
let program_name = "hello-solana".to_string();
let program_id = program_address(&program_name);
test_entry
.initial_programs
.push((program_name, DEPLOYMENT_SLOT));
let program_name = "hello-solana";
let program_id = program_address(program_name);
test_entry.add_initial_program(program_name);

let fee_payer_keypair = Keypair::new();
let fee_payer = fee_payer_keypair.pubkey();
Expand All @@ -369,11 +372,9 @@ fn program_medley() -> Vec<SvmTestEntry> {

// 1: A simple funds transfer between accounts
{
let program_name = "simple-transfer".to_string();
let program_id = program_address(&program_name);
test_entry
.initial_programs
.push((program_name, DEPLOYMENT_SLOT));
let program_name = "simple-transfer";
let program_id = program_address(program_name);
test_entry.add_initial_program(program_name);

let fee_payer_keypair = Keypair::new();
let sender_keypair = Keypair::new();
Expand Down Expand Up @@ -420,11 +421,9 @@ fn program_medley() -> Vec<SvmTestEntry> {

// 2: A program that utilizes a Sysvar
{
let program_name = "clock-sysvar".to_string();
let program_id = program_address(&program_name);
test_entry
.initial_programs
.push((program_name, DEPLOYMENT_SLOT));
let program_name = "clock-sysvar";
let program_id = program_address(program_name);
test_entry.add_initial_program(program_name);

let fee_payer_keypair = Keypair::new();
let fee_payer = fee_payer_keypair.pubkey();
Expand Down Expand Up @@ -656,11 +655,9 @@ fn simple_nonce(enable_fee_only_transactions: bool, fee_paying_nonce: bool) -> V
.push(feature_set::enable_transaction_loading_failure_fees::id());
}

let program_name = "hello-solana".to_string();
let real_program_id = program_address(&program_name);
test_entry
.initial_programs
.push((program_name, DEPLOYMENT_SLOT));
let program_name = "hello-solana";
let real_program_id = program_address(program_name);
test_entry.add_initial_program(program_name);

// create and return a transaction, fee payer, and nonce info
// sets up initial account states but not final ones
Expand Down Expand Up @@ -863,8 +860,8 @@ fn svm_integration(test_entries: Vec<SvmTestEntry>) {
fn execute_test_entry(test_entry: SvmTestEntry) {
let mock_bank = MockBankCallback::default();

for (name, slot) in &test_entry.initial_programs {
deploy_program(name.to_string(), *slot, &mock_bank);
for (name, slot, authority) in &test_entry.initial_programs {
deploy_program_with_upgrade_authority(name.to_string(), *slot, &mock_bank, *authority);
}

for (pubkey, account) in &test_entry.initial_accounts {
Expand Down
29 changes: 21 additions & 8 deletions svm/tests/mock_bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ use {
},
};

pub const EXECUTION_SLOT: u64 = 5; // The execution slot must be greater than the deployment slot
pub const EXECUTION_EPOCH: u64 = 2; // The execution epoch must be greater than the deployment epoch
pub const WALLCLOCK_TIME: i64 = 1704067200; // Arbitrarily Jan 1, 2024

pub struct MockForkGraph {}
Expand Down Expand Up @@ -138,6 +140,17 @@ pub fn program_address(program_name: &str) -> Pubkey {

#[allow(unused)]
pub fn deploy_program(name: String, deployment_slot: Slot, mock_bank: &MockBankCallback) -> Pubkey {
deploy_program_with_upgrade_authority(name, deployment_slot, mock_bank, None)
}

#[allow(unused)]
pub fn deploy_program_with_upgrade_authority(
name: String,
deployment_slot: Slot,
mock_bank: &MockBankCallback,
upgrade_authority_address: Option<Pubkey>,
) -> Pubkey {
let rent = Rent::default();
let program_account = program_address(&name);
let program_data_account = bpf_loader_upgradeable::get_program_data_address(&program_account);

Expand All @@ -147,10 +160,11 @@ pub fn deploy_program(name: String, deployment_slot: Slot, mock_bank: &MockBankC

// The program account must have funds and hold the executable binary
let mut account_data = AccountSharedData::default();
account_data.set_data(bincode::serialize(&state).unwrap());
account_data.set_lamports(25);
let buffer = bincode::serialize(&state).unwrap();
account_data.set_lamports(rent.minimum_balance(buffer.len()));
account_data.set_owner(bpf_loader_upgradeable::id());
account_data.set_executable(true);
account_data.set_data(buffer);
mock_bank
.account_shared_data
.write()
Expand All @@ -173,6 +187,8 @@ pub fn deploy_program(name: String, deployment_slot: Slot, mock_bank: &MockBankC
let mut buffer = load_program(name);
header.append(&mut complement);
header.append(&mut buffer);
account_data.set_lamports(rent.minimum_balance(header.len()));
account_data.set_owner(bpf_loader_upgradeable::id());
account_data.set_data(header);
mock_bank
.account_shared_data
Expand All @@ -189,9 +205,6 @@ pub fn create_executable_environment(
mock_bank: &MockBankCallback,
program_cache: &mut ProgramCache<MockForkGraph>,
) {
const DEPLOYMENT_EPOCH: u64 = 0;
const DEPLOYMENT_SLOT: u64 = 0;

program_cache.environments = ProgramRuntimeEnvironments {
program_runtime_v1: Arc::new(create_custom_environment()),
// We are not using program runtime v2
Expand All @@ -207,10 +220,10 @@ pub fn create_executable_environment(

// clock contents are important because we use them for a sysvar loading test
let clock = Clock {
slot: DEPLOYMENT_SLOT,
slot: EXECUTION_SLOT,
epoch_start_timestamp: WALLCLOCK_TIME.saturating_sub(10) as UnixTimestamp,
epoch: DEPLOYMENT_EPOCH,
leader_schedule_epoch: DEPLOYMENT_EPOCH,
epoch: EXECUTION_EPOCH,
leader_schedule_epoch: EXECUTION_EPOCH,
unix_timestamp: WALLCLOCK_TIME as UnixTimestamp,
};

Expand Down

0 comments on commit f9f8b60

Please sign in to comment.