From 5aca7df232d2d22b5363c20caaca1c8c7cf93cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Wed, 19 Oct 2022 22:28:57 +0200 Subject: [PATCH] Bank::create_executor() (#28474) * Moves the integration test test_bpf_loader_upgradeable_deploy_with_max_len() from the bpf_loader into the runtime. * Adds Bank::create_executor(). * Adds a test for Bank::create_executor(). --- Cargo.lock | 2 +- programs/bpf_loader/Cargo.toml | 1 - programs/bpf_loader/src/lib.rs | 719 +--------------------------- programs/sbf/Cargo.lock | 1 + runtime/Cargo.toml | 1 + runtime/src/bank.rs | 829 ++++++++++++++++++++++++++++++++- 6 files changed, 831 insertions(+), 722 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2479ef9b79..0fc81a8793 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4748,7 +4748,6 @@ dependencies = [ "solana-measure", "solana-metrics", "solana-program-runtime", - "solana-runtime", "solana-sdk 1.15.0", "solana-zk-token-sdk 1.15.0", "solana_rbpf", @@ -6150,6 +6149,7 @@ dependencies = [ "serde", "serde_derive", "solana-address-lookup-table-program", + "solana-bpf-loader-program", "solana-bucket-map", "solana-compute-budget-program", "solana-config-program", diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index acfd11badc..0765e7882c 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -24,7 +24,6 @@ thiserror = "1.0" [dev-dependencies] rand = "0.7.3" -solana-runtime = { path = "../../runtime", version = "=1.15.0" } [lib] crate-type = ["lib"] diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index f4e99f0611..f9835b7669 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -1525,27 +1525,19 @@ mod tests { rand::Rng, solana_program_runtime::invoke_context::mock_process_instruction, solana_rbpf::{ebpf::MM_INPUT_START, verifier::Verifier, vm::SyscallRegistry}, - solana_runtime::{bank::Bank, bank_client::BankClient}, solana_sdk::{ account::{ create_account_shared_data_for_test as create_account_for_test, AccountSharedData, ReadableAccount, WritableAccount, }, account_utils::StateMut, - client::SyncClient, clock::Clock, - feature_set::FeatureSet, - genesis_config::create_genesis_config, - instruction::{AccountMeta, Instruction, InstructionError}, - message::Message, - native_token::LAMPORTS_PER_SOL, + instruction::{AccountMeta, InstructionError}, pubkey::Pubkey, rent::Rent, - signature::{Keypair, Signer}, - system_program, sysvar, - transaction::TransactionError, + sysvar, }, - std::{fs::File, io::Read, ops::Range, sync::Arc}, + std::{fs::File, io::Read, ops::Range}, }; struct TestInstructionMeter { @@ -2260,711 +2252,6 @@ mod tests { account.set_data(data); } - #[test] - fn test_bpf_loader_upgradeable_deploy_with_max_len() { - let (genesis_config, mint_keypair) = create_genesis_config(1_000_000_000); - let mut bank = Bank::new_for_tests(&genesis_config); - bank.feature_set = Arc::new(FeatureSet::all_enabled()); - bank.add_builtin( - "solana_bpf_loader_upgradeable_program", - &bpf_loader_upgradeable::id(), - super::process_instruction, - ); - let bank = Arc::new(bank); - let bank_client = BankClient::new_shared(&bank); - - // Setup keypairs and addresses - let payer_keypair = Keypair::new(); - let program_keypair = Keypair::new(); - let buffer_address = Pubkey::new_unique(); - let (programdata_address, _) = Pubkey::find_program_address( - &[program_keypair.pubkey().as_ref()], - &bpf_loader_upgradeable::id(), - ); - let upgrade_authority_keypair = Keypair::new(); - - // Load program file - let mut file = File::open("test_elfs/out/noop_aligned.so").expect("file open failed"); - let mut elf = Vec::new(); - file.read_to_end(&mut elf).unwrap(); - - // Compute rent exempt balances - let program_len = elf.len(); - let min_program_balance = - bank.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::size_of_program()); - let min_buffer_balance = bank.get_minimum_balance_for_rent_exemption( - UpgradeableLoaderState::size_of_buffer(program_len), - ); - let min_programdata_balance = bank.get_minimum_balance_for_rent_exemption( - UpgradeableLoaderState::size_of_programdata(program_len), - ); - - // Setup accounts - let buffer_account = { - let mut account = AccountSharedData::new( - min_buffer_balance, - UpgradeableLoaderState::size_of_buffer(elf.len()), - &bpf_loader_upgradeable::id(), - ); - account - .set_state(&UpgradeableLoaderState::Buffer { - authority_address: Some(upgrade_authority_keypair.pubkey()), - }) - .unwrap(); - account - .data_as_mut_slice() - .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..) - .unwrap() - .copy_from_slice(&elf); - account - }; - let program_account = AccountSharedData::new( - min_programdata_balance, - UpgradeableLoaderState::size_of_program(), - &bpf_loader_upgradeable::id(), - ); - let programdata_account = AccountSharedData::new( - 1, - UpgradeableLoaderState::size_of_programdata(elf.len()), - &bpf_loader_upgradeable::id(), - ); - - // Test successful deploy - let payer_base_balance = LAMPORTS_PER_SOL; - let deploy_fees = { - let fee_calculator = genesis_config.fee_rate_governor.create_fee_calculator(); - 3 * fee_calculator.lamports_per_signature - }; - let min_payer_balance = min_program_balance - .saturating_add(min_programdata_balance) - .saturating_sub(min_buffer_balance.saturating_add(deploy_fees)); - bank.store_account( - &payer_keypair.pubkey(), - &AccountSharedData::new( - payer_base_balance.saturating_add(min_payer_balance), - 0, - &system_program::id(), - ), - ); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &payer_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(), - Some(&payer_keypair.pubkey()), - ); - assert!(bank_client - .send_and_confirm_message( - &[&payer_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .is_ok()); - assert_eq!( - bank.get_balance(&payer_keypair.pubkey()), - payer_base_balance - ); - assert_eq!(bank.get_balance(&buffer_address), 0); - assert_eq!(None, bank.get_account(&buffer_address)); - let post_program_account = bank.get_account(&program_keypair.pubkey()).unwrap(); - assert_eq!(post_program_account.lamports(), min_program_balance); - assert_eq!(post_program_account.owner(), &bpf_loader_upgradeable::id()); - assert_eq!( - post_program_account.data().len(), - UpgradeableLoaderState::size_of_program() - ); - let state: UpgradeableLoaderState = post_program_account.state().unwrap(); - assert_eq!( - state, - UpgradeableLoaderState::Program { - programdata_address - } - ); - let post_programdata_account = bank.get_account(&programdata_address).unwrap(); - assert_eq!(post_programdata_account.lamports(), min_programdata_balance); - assert_eq!( - post_programdata_account.owner(), - &bpf_loader_upgradeable::id() - ); - let state: UpgradeableLoaderState = post_programdata_account.state().unwrap(); - assert_eq!( - state, - UpgradeableLoaderState::ProgramData { - slot: bank_client.get_slot().unwrap(), - upgrade_authority_address: Some(upgrade_authority_keypair.pubkey()) - } - ); - for (i, byte) in post_programdata_account - .data() - .get(UpgradeableLoaderState::size_of_programdata_metadata()..) - .unwrap() - .iter() - .enumerate() - { - assert_eq!(*elf.get(i).unwrap(), *byte); - } - - // Invoke deployed program - process_instruction( - &bpf_loader_upgradeable::id(), - &[0, 1], - &[], - vec![ - (programdata_address, post_programdata_account), - (program_keypair.pubkey(), post_program_account), - ], - Vec::new(), - Ok(()), - ); - - // Test initialized program account - bank.clear_signatures(); - bank.store_account(&buffer_address, &buffer_account); - let message = Message::new( - &[Instruction::new_with_bincode( - bpf_loader_upgradeable::id(), - &UpgradeableLoaderInstruction::DeployWithMaxDataLen { - max_data_len: elf.len(), - }, - vec![ - AccountMeta::new(mint_keypair.pubkey(), true), - AccountMeta::new(programdata_address, false), - AccountMeta::new(program_keypair.pubkey(), false), - AccountMeta::new(buffer_address, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true), - ], - )], - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(0, InstructionError::AccountAlreadyInitialized), - bank_client - .send_and_confirm_message(&[&mint_keypair, &upgrade_authority_keypair], message) - .unwrap_err() - .unwrap() - ); - - // Test initialized ProgramData account - bank.clear_signatures(); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::Custom(0)), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Test deploy no authority - bank.clear_signatures(); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &program_account); - bank.store_account(&programdata_address, &programdata_account); - let message = Message::new( - &[Instruction::new_with_bincode( - bpf_loader_upgradeable::id(), - &UpgradeableLoaderInstruction::DeployWithMaxDataLen { - max_data_len: elf.len(), - }, - vec![ - AccountMeta::new(mint_keypair.pubkey(), true), - AccountMeta::new(programdata_address, false), - AccountMeta::new(program_keypair.pubkey(), false), - AccountMeta::new(buffer_address, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - ], - )], - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(0, InstructionError::NotEnoughAccountKeys), - bank_client - .send_and_confirm_message(&[&mint_keypair], message) - .unwrap_err() - .unwrap() - ); - - // Test deploy authority not a signer - bank.clear_signatures(); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &program_account); - bank.store_account(&programdata_address, &programdata_account); - let message = Message::new( - &[Instruction::new_with_bincode( - bpf_loader_upgradeable::id(), - &UpgradeableLoaderInstruction::DeployWithMaxDataLen { - max_data_len: elf.len(), - }, - vec![ - AccountMeta::new(mint_keypair.pubkey(), true), - AccountMeta::new(programdata_address, false), - AccountMeta::new(program_keypair.pubkey(), false), - AccountMeta::new(buffer_address, false), - AccountMeta::new_readonly(sysvar::rent::id(), false), - AccountMeta::new_readonly(sysvar::clock::id(), false), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), false), - ], - )], - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature), - bank_client - .send_and_confirm_message(&[&mint_keypair], message) - .unwrap_err() - .unwrap() - ); - - // Test invalid Buffer account state - bank.clear_signatures(); - bank.store_account(&buffer_address, &AccountSharedData::default()); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::InvalidAccountData), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Test program account not rent exempt - bank.clear_signatures(); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance.saturating_sub(1), - elf.len(), - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::ExecutableAccountNotRentExempt), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Test program account not rent exempt because data is larger than needed - bank.clear_signatures(); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(); - *instructions.get_mut(0).unwrap() = system_instruction::create_account( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - min_program_balance, - (UpgradeableLoaderState::size_of_program() as u64).saturating_add(1), - &id(), - ); - let message = Message::new(&instructions, Some(&mint_keypair.pubkey())); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::ExecutableAccountNotRentExempt), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Test program account too small - bank.clear_signatures(); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(); - *instructions.get_mut(0).unwrap() = system_instruction::create_account( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - min_program_balance, - (UpgradeableLoaderState::size_of_program() as u64).saturating_sub(1), - &id(), - ); - let message = Message::new(&instructions, Some(&mint_keypair.pubkey())); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::AccountDataTooSmall), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Test Insufficient payer funds (need more funds to cover the - // difference between buffer lamports and programdata lamports) - bank.clear_signatures(); - bank.store_account( - &mint_keypair.pubkey(), - &AccountSharedData::new( - deploy_fees.saturating_add(min_program_balance), - 0, - &system_program::id(), - ), - ); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::Custom(1)), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - bank.store_account( - &mint_keypair.pubkey(), - &AccountSharedData::new(1_000_000_000, 0, &system_program::id()), - ); - - // Test max_data_len - bank.clear_signatures(); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len().saturating_sub(1), - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::AccountDataTooSmall), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Test max_data_len too large - bank.clear_signatures(); - bank.store_account( - &mint_keypair.pubkey(), - &AccountSharedData::new(u64::MAX / 2, 0, &system_program::id()), - ); - let mut modified_buffer_account = buffer_account.clone(); - modified_buffer_account.set_lamports(u64::MAX / 2); - bank.store_account(&buffer_address, &modified_buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - usize::MAX, - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::InvalidArgument), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Test not the system account - bank.clear_signatures(); - bank.store_account(&buffer_address, &buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(); - *instructions - .get_mut(1) - .unwrap() - .accounts - .get_mut(6) - .unwrap() = AccountMeta::new_readonly(Pubkey::new_unique(), false); - let message = Message::new(&instructions, Some(&mint_keypair.pubkey())); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::MissingAccount), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Test Bad ELF data - bank.clear_signatures(); - let mut modified_buffer_account = buffer_account; - truncate_data( - &mut modified_buffer_account, - UpgradeableLoaderState::size_of_buffer(1), - ); - bank.store_account(&buffer_address, &modified_buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::InvalidAccountData), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Test small buffer account - bank.clear_signatures(); - let mut modified_buffer_account = AccountSharedData::new( - min_programdata_balance, - UpgradeableLoaderState::size_of_buffer(elf.len()), - &bpf_loader_upgradeable::id(), - ); - modified_buffer_account - .set_state(&UpgradeableLoaderState::Buffer { - authority_address: Some(upgrade_authority_keypair.pubkey()), - }) - .unwrap(); - modified_buffer_account - .data_as_mut_slice() - .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..) - .unwrap() - .copy_from_slice(&elf); - truncate_data(&mut modified_buffer_account, 5); - bank.store_account(&buffer_address, &modified_buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::InvalidAccountData), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Mismatched buffer and program authority - bank.clear_signatures(); - let mut modified_buffer_account = AccountSharedData::new( - min_programdata_balance, - UpgradeableLoaderState::size_of_buffer(elf.len()), - &bpf_loader_upgradeable::id(), - ); - modified_buffer_account - .set_state(&UpgradeableLoaderState::Buffer { - authority_address: Some(buffer_address), - }) - .unwrap(); - modified_buffer_account - .data_as_mut_slice() - .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..) - .unwrap() - .copy_from_slice(&elf); - bank.store_account(&buffer_address, &modified_buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::IncorrectAuthority), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - - // Deploy buffer with mismatched None authority - bank.clear_signatures(); - let mut modified_buffer_account = AccountSharedData::new( - min_programdata_balance, - UpgradeableLoaderState::size_of_buffer(elf.len()), - &bpf_loader_upgradeable::id(), - ); - modified_buffer_account - .set_state(&UpgradeableLoaderState::Buffer { - authority_address: None, - }) - .unwrap(); - modified_buffer_account - .data_as_mut_slice() - .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..) - .unwrap() - .copy_from_slice(&elf); - bank.store_account(&buffer_address, &modified_buffer_account); - bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); - bank.store_account(&programdata_address, &AccountSharedData::default()); - let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_address, - &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(), - Some(&mint_keypair.pubkey()), - ); - assert_eq!( - TransactionError::InstructionError(1, InstructionError::IncorrectAuthority), - bank_client - .send_and_confirm_message( - &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], - message - ) - .unwrap_err() - .unwrap() - ); - } - #[test] fn test_bpf_loader_upgradeable_upgrade() { let mut file = File::open("test_elfs/out/noop_aligned.so").expect("file open failed"); diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index e7f2fe86c6..af6b921d23 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5080,6 +5080,7 @@ dependencies = [ "serde", "serde_derive", "solana-address-lookup-table-program", + "solana-bpf-loader-program", "solana-bucket-map", "solana-compute-budget-program", "solana-config-program", diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 609e57b233..0c1fff0578 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -41,6 +41,7 @@ regex = "1.6.0" serde = { version = "1.0.144", features = ["rc"] } serde_derive = "1.0.103" solana-address-lookup-table-program = { path = "../programs/address-lookup-table", version = "=1.15.0" } +solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.15.0" } solana-bucket-map = { path = "../bucket_map", version = "=1.15.0" } solana-compute-budget-program = { path = "../programs/compute-budget", version = "=1.15.0" } solana-config-program = { path = "../programs/config", version = "=1.15.0" } diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 850562923f..a4de91ad90 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -87,7 +87,7 @@ use { accounts_data_meter::MAX_ACCOUNTS_DATA_LEN, compute_budget::{self, ComputeBudget}, executor_cache::{ - BankExecutorCache, TransactionExecutorCache, TxBankExecutorCacheDiff, + BankExecutorCache, Executor, TransactionExecutorCache, TxBankExecutorCacheDiff, MAX_CACHED_EXECUTORS, }, invoke_context::{BuiltinProgram, ProcessInstructionWithContext}, @@ -101,6 +101,7 @@ use { AccountSharedData, InheritableAccountFields, ReadableAccount, WritableAccount, }, account_utils::StateMut, + bpf_loader_upgradeable::{self, UpgradeableLoaderState}, clock::{ BankId, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE, MAX_TRANSACTION_FORWARDING_DELAY, @@ -4044,6 +4045,73 @@ impl Bank { }); } + #[allow(dead_code)] // Preparation for BankExecutorCache rework + fn create_executor(&self, pubkey: &Pubkey) -> Result> { + let program = if let Some(program) = self.get_account_with_fixed_root(pubkey) { + program + } else { + return Err(TransactionError::ProgramAccountNotFound); + }; + let mut transaction_accounts = vec![(*pubkey, program)]; + let is_upgradeable_loader = + bpf_loader_upgradeable::check_id(transaction_accounts[0].1.owner()); + if is_upgradeable_loader { + if let Ok(UpgradeableLoaderState::Program { + programdata_address, + }) = transaction_accounts[0].1.state() + { + if let Some(programdata_account) = + self.get_account_with_fixed_root(&programdata_address) + { + transaction_accounts.push((programdata_address, programdata_account)); + } else { + return Err(TransactionError::ProgramAccountNotFound); + } + } else { + return Err(TransactionError::ProgramAccountNotFound); + } + } + let mut transaction_context = TransactionContext::new( + transaction_accounts, + Some(sysvar::rent::Rent::default()), + 1, + 1, + ); + let instruction_context = transaction_context + .get_next_instruction_context() + .map_err(|err| TransactionError::InstructionError(0, err))?; + instruction_context.configure(if is_upgradeable_loader { &[0, 1] } else { &[0] }, &[], &[]); + transaction_context + .push() + .map_err(|err| TransactionError::InstructionError(0, err))?; + let instruction_context = transaction_context + .get_current_instruction_context() + .map_err(|err| TransactionError::InstructionError(0, err))?; + let program = instruction_context + .try_borrow_program_account(&transaction_context, 0) + .map_err(|err| TransactionError::InstructionError(0, err))?; + let programdata = if is_upgradeable_loader { + Some( + instruction_context + .try_borrow_program_account(&transaction_context, 1) + .map_err(|err| TransactionError::InstructionError(0, err))?, + ) + } else { + None + }; + solana_bpf_loader_program::create_executor_from_account( + &self.feature_set, + &self.runtime_config.compute_budget.unwrap_or_default(), + None, // log_collector + None, // tx_executor_cache + &program, + programdata.as_ref().unwrap_or(&program), + self.runtime_config.bpf_jit, + ) + .map(|(executor, _create_executor_metrics)| executor) + .map_err(|err| TransactionError::InstructionError(0, err)) + } + /// Remove an executor from the bank's cache fn remove_executor(&self, pubkey: &Pubkey) { let _ = self.executor_cache.write().unwrap().remove(pubkey); @@ -7852,6 +7920,7 @@ pub(crate) mod tests { accounts_db::DEFAULT_ACCOUNTS_SHRINK_RATIO, accounts_index::{AccountIndex, AccountSecondaryIndexes, ScanError, ITER_BATCH_SIZE}, ancestors::Ancestors, + bank_client::BankClient, genesis_utils::{ self, activate_all_features, bootstrap_validator_stake_lamports, create_genesis_config_with_leader, create_genesis_config_with_vote_accounts, @@ -7866,12 +7935,14 @@ pub(crate) mod tests { solana_program_runtime::{ compute_budget::MAX_COMPUTE_UNIT_LIMIT, executor_cache::Executor, - invoke_context::InvokeContext, + invoke_context::{mock_process_instruction, InvokeContext}, prioritization_fee::{PrioritizationFeeDetails, PrioritizationFeeType}, }, solana_sdk::{ account::Account, - bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, + bpf_loader, bpf_loader_deprecated, + bpf_loader_upgradeable::{self, UpgradeableLoaderState}, + client::SyncClient, clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT, MAX_RECENT_BLOCKHASHES}, compute_budget::ComputeBudgetInstruction, entrypoint::MAX_PERMITTED_DATA_INCREASE, @@ -7880,6 +7951,7 @@ pub(crate) mod tests { genesis_config::create_genesis_config, hash, instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}, + loader_upgradeable_instruction::UpgradeableLoaderInstruction, message::{Message, MessageHeader}, native_token::LAMPORTS_PER_SOL, nonce, @@ -7907,7 +7979,8 @@ pub(crate) mod tests { }, }, std::{ - result, str::FromStr, sync::atomic::Ordering::Release, thread::Builder, time::Duration, + fs::File, io::Read, result, str::FromStr, sync::atomic::Ordering::Release, + thread::Builder, time::Duration, }, test_utils::goto_end_of_slot, }; @@ -15136,6 +15209,39 @@ pub(crate) mod tests { assert!(stored_executors.borrow().executors.contains_key(&key2)); assert!(stored_executors.borrow().executors.contains_key(&key3)); + // Force compilation of an executor + let mut file = File::open("../programs/bpf_loader/test_elfs/out/noop_aligned.so").unwrap(); + let mut elf = Vec::new(); + file.read_to_end(&mut elf).unwrap(); + let programdata_key = solana_sdk::pubkey::new_rand(); + let mut program_account = AccountSharedData::new_data( + 40, + &UpgradeableLoaderState::Program { + programdata_address: programdata_key, + }, + &bpf_loader_upgradeable::id(), + ) + .unwrap(); + program_account.set_executable(true); + program_account.set_rent_epoch(1); + let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata(); + let mut programdata_account = AccountSharedData::new( + 40, + programdata_data_offset + elf.len(), + &bpf_loader_upgradeable::id(), + ); + programdata_account + .set_state(&UpgradeableLoaderState::ProgramData { + slot: 42, + upgrade_authority_address: None, + }) + .unwrap(); + programdata_account.data_mut()[programdata_data_offset..].copy_from_slice(&elf); + programdata_account.set_rent_epoch(1); + bank.store_account_and_update_capitalization(&key1, &program_account); + bank.store_account_and_update_capitalization(&programdata_key, &programdata_account); + bank.create_executor(&key1).unwrap(); + // Remove all bank.remove_executor(&key1); bank.remove_executor(&key2); @@ -15200,6 +15306,721 @@ pub(crate) mod tests { assert_eq!(executors.borrow().executors.len(), 1); } + #[test] + fn test_bpf_loader_upgradeable_deploy_with_max_len() { + let (genesis_config, mint_keypair) = create_genesis_config(1_000_000_000); + let mut bank = Bank::new_for_tests(&genesis_config); + bank.feature_set = Arc::new(FeatureSet::all_enabled()); + bank.add_builtin( + "solana_bpf_loader_upgradeable_program", + &bpf_loader_upgradeable::id(), + solana_bpf_loader_program::process_instruction, + ); + let bank = Arc::new(bank); + let bank_client = BankClient::new_shared(&bank); + + // Setup keypairs and addresses + let payer_keypair = Keypair::new(); + let program_keypair = Keypair::new(); + let buffer_address = Pubkey::new_unique(); + let (programdata_address, _) = Pubkey::find_program_address( + &[program_keypair.pubkey().as_ref()], + &bpf_loader_upgradeable::id(), + ); + let upgrade_authority_keypair = Keypair::new(); + + // Load program file + let mut file = File::open("../programs/bpf_loader/test_elfs/out/noop_aligned.so") + .expect("file open failed"); + let mut elf = Vec::new(); + file.read_to_end(&mut elf).unwrap(); + + // Compute rent exempt balances + let program_len = elf.len(); + let min_program_balance = + bank.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::size_of_program()); + let min_buffer_balance = bank.get_minimum_balance_for_rent_exemption( + UpgradeableLoaderState::size_of_buffer(program_len), + ); + let min_programdata_balance = bank.get_minimum_balance_for_rent_exemption( + UpgradeableLoaderState::size_of_programdata(program_len), + ); + + // Setup accounts + let buffer_account = { + let mut account = AccountSharedData::new( + min_buffer_balance, + UpgradeableLoaderState::size_of_buffer(elf.len()), + &bpf_loader_upgradeable::id(), + ); + account + .set_state(&UpgradeableLoaderState::Buffer { + authority_address: Some(upgrade_authority_keypair.pubkey()), + }) + .unwrap(); + account + .data_as_mut_slice() + .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..) + .unwrap() + .copy_from_slice(&elf); + account + }; + let program_account = AccountSharedData::new( + min_programdata_balance, + UpgradeableLoaderState::size_of_program(), + &bpf_loader_upgradeable::id(), + ); + let programdata_account = AccountSharedData::new( + 1, + UpgradeableLoaderState::size_of_programdata(elf.len()), + &bpf_loader_upgradeable::id(), + ); + + // Test successful deploy + let payer_base_balance = LAMPORTS_PER_SOL; + let deploy_fees = { + let fee_calculator = genesis_config.fee_rate_governor.create_fee_calculator(); + 3 * fee_calculator.lamports_per_signature + }; + let min_payer_balance = min_program_balance + .saturating_add(min_programdata_balance) + .saturating_sub(min_buffer_balance.saturating_add(deploy_fees)); + bank.store_account( + &payer_keypair.pubkey(), + &AccountSharedData::new( + payer_base_balance.saturating_add(min_payer_balance), + 0, + &system_program::id(), + ), + ); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &payer_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(), + Some(&payer_keypair.pubkey()), + ); + assert!(bank_client + .send_and_confirm_message( + &[&payer_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .is_ok()); + assert_eq!( + bank.get_balance(&payer_keypair.pubkey()), + payer_base_balance + ); + assert_eq!(bank.get_balance(&buffer_address), 0); + assert_eq!(None, bank.get_account(&buffer_address)); + let post_program_account = bank.get_account(&program_keypair.pubkey()).unwrap(); + assert_eq!(post_program_account.lamports(), min_program_balance); + assert_eq!(post_program_account.owner(), &bpf_loader_upgradeable::id()); + assert_eq!( + post_program_account.data().len(), + UpgradeableLoaderState::size_of_program() + ); + let state: UpgradeableLoaderState = post_program_account.state().unwrap(); + assert_eq!( + state, + UpgradeableLoaderState::Program { + programdata_address + } + ); + let post_programdata_account = bank.get_account(&programdata_address).unwrap(); + assert_eq!(post_programdata_account.lamports(), min_programdata_balance); + assert_eq!( + post_programdata_account.owner(), + &bpf_loader_upgradeable::id() + ); + let state: UpgradeableLoaderState = post_programdata_account.state().unwrap(); + assert_eq!( + state, + UpgradeableLoaderState::ProgramData { + slot: bank_client.get_slot().unwrap(), + upgrade_authority_address: Some(upgrade_authority_keypair.pubkey()) + } + ); + for (i, byte) in post_programdata_account + .data() + .get(UpgradeableLoaderState::size_of_programdata_metadata()..) + .unwrap() + .iter() + .enumerate() + { + assert_eq!(*elf.get(i).unwrap(), *byte); + } + + // Invoke deployed program + mock_process_instruction( + &bpf_loader_upgradeable::id(), + vec![0, 1], + &[], + vec![ + (programdata_address, post_programdata_account), + (program_keypair.pubkey(), post_program_account), + ], + Vec::new(), + None, + None, + Ok(()), + solana_bpf_loader_program::process_instruction, + ); + + // Test initialized program account + bank.clear_signatures(); + bank.store_account(&buffer_address, &buffer_account); + let message = Message::new( + &[Instruction::new_with_bincode( + bpf_loader_upgradeable::id(), + &UpgradeableLoaderInstruction::DeployWithMaxDataLen { + max_data_len: elf.len(), + }, + vec![ + AccountMeta::new(mint_keypair.pubkey(), true), + AccountMeta::new(programdata_address, false), + AccountMeta::new(program_keypair.pubkey(), false), + AccountMeta::new(buffer_address, false), + AccountMeta::new_readonly(sysvar::rent::id(), false), + AccountMeta::new_readonly(sysvar::clock::id(), false), + AccountMeta::new_readonly(system_program::id(), false), + AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true), + ], + )], + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(0, InstructionError::AccountAlreadyInitialized), + bank_client + .send_and_confirm_message(&[&mint_keypair, &upgrade_authority_keypair], message) + .unwrap_err() + .unwrap() + ); + + // Test initialized ProgramData account + bank.clear_signatures(); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::Custom(0)), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Test deploy no authority + bank.clear_signatures(); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &program_account); + bank.store_account(&programdata_address, &programdata_account); + let message = Message::new( + &[Instruction::new_with_bincode( + bpf_loader_upgradeable::id(), + &UpgradeableLoaderInstruction::DeployWithMaxDataLen { + max_data_len: elf.len(), + }, + vec![ + AccountMeta::new(mint_keypair.pubkey(), true), + AccountMeta::new(programdata_address, false), + AccountMeta::new(program_keypair.pubkey(), false), + AccountMeta::new(buffer_address, false), + AccountMeta::new_readonly(sysvar::rent::id(), false), + AccountMeta::new_readonly(sysvar::clock::id(), false), + AccountMeta::new_readonly(system_program::id(), false), + ], + )], + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(0, InstructionError::NotEnoughAccountKeys), + bank_client + .send_and_confirm_message(&[&mint_keypair], message) + .unwrap_err() + .unwrap() + ); + + // Test deploy authority not a signer + bank.clear_signatures(); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &program_account); + bank.store_account(&programdata_address, &programdata_account); + let message = Message::new( + &[Instruction::new_with_bincode( + bpf_loader_upgradeable::id(), + &UpgradeableLoaderInstruction::DeployWithMaxDataLen { + max_data_len: elf.len(), + }, + vec![ + AccountMeta::new(mint_keypair.pubkey(), true), + AccountMeta::new(programdata_address, false), + AccountMeta::new(program_keypair.pubkey(), false), + AccountMeta::new(buffer_address, false), + AccountMeta::new_readonly(sysvar::rent::id(), false), + AccountMeta::new_readonly(sysvar::clock::id(), false), + AccountMeta::new_readonly(system_program::id(), false), + AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), false), + ], + )], + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature), + bank_client + .send_and_confirm_message(&[&mint_keypair], message) + .unwrap_err() + .unwrap() + ); + + // Test invalid Buffer account state + bank.clear_signatures(); + bank.store_account(&buffer_address, &AccountSharedData::default()); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::InvalidAccountData), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Test program account not rent exempt + bank.clear_signatures(); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance.saturating_sub(1), + elf.len(), + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::ExecutableAccountNotRentExempt), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Test program account not rent exempt because data is larger than needed + bank.clear_signatures(); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(); + *instructions.get_mut(0).unwrap() = system_instruction::create_account( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + min_program_balance, + (UpgradeableLoaderState::size_of_program() as u64).saturating_add(1), + &bpf_loader_upgradeable::id(), + ); + let message = Message::new(&instructions, Some(&mint_keypair.pubkey())); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::ExecutableAccountNotRentExempt), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Test program account too small + bank.clear_signatures(); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(); + *instructions.get_mut(0).unwrap() = system_instruction::create_account( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + min_program_balance, + (UpgradeableLoaderState::size_of_program() as u64).saturating_sub(1), + &bpf_loader_upgradeable::id(), + ); + let message = Message::new(&instructions, Some(&mint_keypair.pubkey())); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::AccountDataTooSmall), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Test Insufficient payer funds (need more funds to cover the + // difference between buffer lamports and programdata lamports) + bank.clear_signatures(); + bank.store_account( + &mint_keypair.pubkey(), + &AccountSharedData::new( + deploy_fees.saturating_add(min_program_balance), + 0, + &system_program::id(), + ), + ); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::Custom(1)), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + bank.store_account( + &mint_keypair.pubkey(), + &AccountSharedData::new(1_000_000_000, 0, &system_program::id()), + ); + + // Test max_data_len + bank.clear_signatures(); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len().saturating_sub(1), + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::AccountDataTooSmall), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Test max_data_len too large + bank.clear_signatures(); + bank.store_account( + &mint_keypair.pubkey(), + &AccountSharedData::new(u64::MAX / 2, 0, &system_program::id()), + ); + let mut modified_buffer_account = buffer_account.clone(); + modified_buffer_account.set_lamports(u64::MAX / 2); + bank.store_account(&buffer_address, &modified_buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + usize::MAX, + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::InvalidArgument), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Test not the system account + bank.clear_signatures(); + bank.store_account(&buffer_address, &buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(); + *instructions + .get_mut(1) + .unwrap() + .accounts + .get_mut(6) + .unwrap() = AccountMeta::new_readonly(Pubkey::new_unique(), false); + let message = Message::new(&instructions, Some(&mint_keypair.pubkey())); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::MissingAccount), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + fn truncate_data(account: &mut AccountSharedData, len: usize) { + let mut data = account.data().to_vec(); + data.truncate(len); + account.set_data(data); + } + + // Test Bad ELF data + bank.clear_signatures(); + let mut modified_buffer_account = buffer_account; + truncate_data( + &mut modified_buffer_account, + UpgradeableLoaderState::size_of_buffer(1), + ); + bank.store_account(&buffer_address, &modified_buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::InvalidAccountData), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Test small buffer account + bank.clear_signatures(); + let mut modified_buffer_account = AccountSharedData::new( + min_programdata_balance, + UpgradeableLoaderState::size_of_buffer(elf.len()), + &bpf_loader_upgradeable::id(), + ); + modified_buffer_account + .set_state(&UpgradeableLoaderState::Buffer { + authority_address: Some(upgrade_authority_keypair.pubkey()), + }) + .unwrap(); + modified_buffer_account + .data_as_mut_slice() + .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..) + .unwrap() + .copy_from_slice(&elf); + truncate_data(&mut modified_buffer_account, 5); + bank.store_account(&buffer_address, &modified_buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::InvalidAccountData), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Mismatched buffer and program authority + bank.clear_signatures(); + let mut modified_buffer_account = AccountSharedData::new( + min_programdata_balance, + UpgradeableLoaderState::size_of_buffer(elf.len()), + &bpf_loader_upgradeable::id(), + ); + modified_buffer_account + .set_state(&UpgradeableLoaderState::Buffer { + authority_address: Some(buffer_address), + }) + .unwrap(); + modified_buffer_account + .data_as_mut_slice() + .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..) + .unwrap() + .copy_from_slice(&elf); + bank.store_account(&buffer_address, &modified_buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::IncorrectAuthority), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + + // Deploy buffer with mismatched None authority + bank.clear_signatures(); + let mut modified_buffer_account = AccountSharedData::new( + min_programdata_balance, + UpgradeableLoaderState::size_of_buffer(elf.len()), + &bpf_loader_upgradeable::id(), + ); + modified_buffer_account + .set_state(&UpgradeableLoaderState::Buffer { + authority_address: None, + }) + .unwrap(); + modified_buffer_account + .data_as_mut_slice() + .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..) + .unwrap() + .copy_from_slice(&elf); + bank.store_account(&buffer_address, &modified_buffer_account); + bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); + bank.store_account(&programdata_address, &AccountSharedData::default()); + let message = Message::new( + &bpf_loader_upgradeable::deploy_with_max_program_len( + &mint_keypair.pubkey(), + &program_keypair.pubkey(), + &buffer_address, + &upgrade_authority_keypair.pubkey(), + min_program_balance, + elf.len(), + ) + .unwrap(), + Some(&mint_keypair.pubkey()), + ); + assert_eq!( + TransactionError::InstructionError(1, InstructionError::IncorrectAuthority), + bank_client + .send_and_confirm_message( + &[&mint_keypair, &program_keypair, &upgrade_authority_keypair], + message + ) + .unwrap_err() + .unwrap() + ); + } + #[test] fn test_compute_active_feature_set() { let bank0 = create_simple_test_arc_bank(100_000);