diff --git a/builtins/src/lib.rs b/builtins/src/lib.rs index 5ba11fbf1cd..53695f78a3b 100644 --- a/builtins/src/lib.rs +++ b/builtins/src/lib.rs @@ -141,7 +141,7 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { core_bpf_migration_config: None, name: loader_v4, - enable_feature_id: Some(feature_set::enable_program_runtime_v2_and_loader_v4::id()), + enable_feature_id: Some(feature_set::enable_loader_v4::id()), program_id: solana_sdk_ids::loader_v4::id(), entrypoint: solana_loader_v4_program::Entrypoint::vm, }), diff --git a/cli/tests/program.rs b/cli/tests/program.rs index a79606c15bc..b2d1a8e9e1f 100644 --- a/cli/tests/program.rs +++ b/cli/tests/program.rs @@ -14,7 +14,7 @@ use { solana_client::rpc_config::RpcSendTransactionConfig, solana_commitment_config::CommitmentConfig, solana_faucet::faucet::run_local_faucet, - solana_feature_set::enable_alt_bn128_syscall, + solana_feature_set::{enable_alt_bn128_syscall, enable_loader_v4}, solana_rpc::rpc::JsonRpcConfig, solana_rpc_client::rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient}, solana_rpc_client_api::config::RpcTransactionConfig, @@ -33,7 +33,7 @@ use { transaction::Transaction, }, solana_streamer::socket::SocketAddrSpace, - solana_test_validator::{TestValidator, TestValidatorGenesis}, + solana_test_validator::TestValidatorGenesis, solana_transaction_status::UiTransactionEncoding, std::{ env, @@ -45,6 +45,20 @@ use { test_case::test_case, }; +fn test_validator_genesis(mint_keypair: Keypair) -> TestValidatorGenesis { + let mut genesis = TestValidatorGenesis::default(); + genesis + .fee_rate_governor(FeeRateGovernor::new(0, 0)) + .rent(Rent { + lamports_per_byte_year: 1, + exemption_threshold: 1.0, + ..Rent::default() + }) + .faucet_addr(Some(run_local_faucet(mint_keypair, None))) + .deactivate_features(&[enable_loader_v4::id()]); + genesis +} + #[track_caller] fn expect_command_failure(config: &CliConfig, should_fail_because: &str, error_expected: &str) { let error_actual = process_command(config).expect_err(should_fail_because); @@ -81,9 +95,9 @@ fn test_cli_program_deploy_non_upgradeable() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -286,9 +300,9 @@ fn test_cli_program_deploy_no_authority() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -389,21 +403,11 @@ fn test_cli_program_deploy_feature(enable_feature: bool, skip_preflight: bool) { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let mut genesis = TestValidatorGenesis::default(); - let mut test_validator_builder = genesis - .fee_rate_governor(FeeRateGovernor::new(0, 0)) - .rent(Rent { - lamports_per_byte_year: 1, - exemption_threshold: 1.0, - ..Rent::default() - }) - .faucet_addr(Some(faucet_addr)); + let mut test_validator_builder = test_validator_genesis(mint_keypair); // Deactivate the enable alt bn128 syscall and try to submit a program with that syscall if !enable_feature { - test_validator_builder = - test_validator_builder.deactivate_features(&[enable_alt_bn128_syscall::id()]); + test_validator_builder.deactivate_features(&[enable_alt_bn128_syscall::id()]); } let test_validator = test_validator_builder @@ -524,22 +528,11 @@ fn test_cli_program_upgrade_with_feature(enable_feature: bool) { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - - let mut genesis = TestValidatorGenesis::default(); - let mut test_validator_builder = genesis - .fee_rate_governor(FeeRateGovernor::new(0, 0)) - .rent(Rent { - lamports_per_byte_year: 1, - exemption_threshold: 1.0, - ..Rent::default() - }) - .faucet_addr(Some(faucet_addr)); + let mut test_validator_builder = test_validator_genesis(mint_keypair); // Deactivate the enable alt bn128 syscall and try to submit a program with that syscall if !enable_feature { - test_validator_builder = - test_validator_builder.deactivate_features(&[enable_alt_bn128_syscall::id()]); + test_validator_builder.deactivate_features(&[enable_alt_bn128_syscall::id()]); } let test_validator = test_validator_builder @@ -690,9 +683,9 @@ fn test_cli_program_deploy_with_authority() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -1092,9 +1085,9 @@ fn test_cli_program_upgrade_auto_extend(skip_preflight: bool) { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -1254,9 +1247,9 @@ fn test_cli_program_close_program() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -1373,9 +1366,9 @@ fn test_cli_program_extend_program() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -1549,9 +1542,9 @@ fn test_cli_program_write_buffer() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -1932,21 +1925,11 @@ fn test_cli_program_write_buffer_feature(enable_feature: bool) { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let mut genesis = TestValidatorGenesis::default(); - let mut test_validator_builder = genesis - .fee_rate_governor(FeeRateGovernor::new(0, 0)) - .rent(Rent { - lamports_per_byte_year: 1, - exemption_threshold: 1.0, - ..Rent::default() - }) - .faucet_addr(Some(faucet_addr)); + let mut test_validator_builder = test_validator_genesis(mint_keypair); // Deactivate the enable alt bn128 syscall and try to submit a program with that syscall if !enable_feature { - test_validator_builder = - test_validator_builder.deactivate_features(&[enable_alt_bn128_syscall::id()]); + test_validator_builder.deactivate_features(&[enable_alt_bn128_syscall::id()]); } let test_validator = test_validator_builder @@ -2036,9 +2019,9 @@ fn test_cli_program_set_buffer_authority() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -2208,9 +2191,9 @@ fn test_cli_program_mismatch_buffer_authority() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -2334,9 +2317,9 @@ fn test_cli_program_deploy_with_offline_signing(use_offline_signer_as_fee_payer: let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -2527,9 +2510,9 @@ fn test_cli_program_show() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -2724,9 +2707,9 @@ fn test_cli_program_dump() { let mint_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); + let test_validator = test_validator_genesis(mint_keypair) + .start_with_mint_address(mint_pubkey, SocketAddrSpace::Unspecified) + .expect("validator start failed"); let rpc_client = RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); @@ -2864,6 +2847,7 @@ fn test_cli_program_deploy_with_args(compute_unit_price: Option, use_rpc: b exemption_threshold: 1.0, ..Rent::default() }) + .deactivate_features(&[enable_loader_v4::id()]) .rpc_config(JsonRpcConfig { enable_rpc_transaction_history: true, faucet_addr: Some(faucet_addr), diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 53954165194..1069238c6db 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -13,7 +13,7 @@ use { solana_compute_budget::compute_budget::MAX_INSTRUCTION_STACK_DEPTH, solana_feature_set::{ bpf_account_data_direct_mapping, enable_bpf_loader_set_authority_checked_ix, - remove_accounts_executable_flag_checks, + enable_loader_v4, remove_accounts_executable_flag_checks, }, solana_instruction::{error::InstructionError, AccountMeta}, solana_log_collector::{ic_logger_msg, ic_msg, LogCollector}, @@ -562,6 +562,14 @@ fn process_loader_upgradeable_instruction( )?; } UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => { + if invoke_context + .get_feature_set() + .is_active(&enable_loader_v4::id()) + { + ic_logger_msg!(log_collector, "Unsupported instruction"); + return Err(InstructionError::InvalidInstructionData); + } + instruction_context.check_number_of_instruction_accounts(4)?; let payer_key = *transaction_context.get_key_of_account_at_index( instruction_context.get_index_of_instruction_account_in_transaction(0)?, @@ -1683,6 +1691,9 @@ mod tests { expected_result, Entrypoint::vm, |invoke_context| { + let mut feature_set = invoke_context.get_feature_set().clone(); + feature_set.deactivate(&enable_loader_v4::id()); + invoke_context.mock_set_feature_set(Arc::new(feature_set)); test_utils::load_all_invoked_programs(invoke_context); }, |_invoke_context| {}, diff --git a/programs/sbf/benches/bpf_loader.rs b/programs/sbf/benches/bpf_loader.rs index c31a2d64f04..1af269ac303 100644 --- a/programs/sbf/benches/bpf_loader.rs +++ b/programs/sbf/benches/bpf_loader.rs @@ -28,7 +28,7 @@ use { bank::Bank, bank_client::BankClient, genesis_utils::{create_genesis_config, GenesisConfigInfo}, - loader_utils::{load_program_from_file, load_upgradeable_program_and_advance_slot}, + loader_utils::{load_program_from_file, load_program_of_loader_v4}, }, solana_sbpf::{ ebpf::MM_INPUT_START, elf::Executable, memory_region::MemoryRegion, @@ -201,9 +201,9 @@ fn bench_program_execute_noop(bencher: &mut Bencher) { let authority_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); - let (_, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "noop", diff --git a/programs/sbf/c/src/invoked/invoked.c b/programs/sbf/c/src/invoked/invoked.c index 37671cfb9fe..03c6e284a4a 100644 --- a/programs/sbf/c/src/invoked/invoked.c +++ b/programs/sbf/c/src/invoked/invoked.c @@ -31,11 +31,10 @@ extern uint64_t entrypoint(const uint8_t *input) { static const int INVOKED_PROGRAM_DUP_INDEX = 3; sol_assert(sol_deserialize(input, ¶ms, 4)); - SolPubkey sbf_loader_upgradeable_id = - (SolPubkey){.x = { - 2, 168, 246, 145, 78, 136, 161, 176, 226, 16, 21, 62, - 247, 99, 174, 43, 0, 194, 185, 61, 22, 193, 36, 210, 192, - 83, 122, 16, 4, 128, 0, 0}}; + SolPubkey loader_v4_id = + (SolPubkey){.x = { + 5, 18, 180, 17, 81, 81, 227, 122, 173, 10, 139, 197, 211, 136, 46, 123, 127, 218, 76, 243, 210, 192, 40, 200, 207, 131, 54, 24, 0, 0, 0, 0 + }}; for (int i = 0; i < params.data_len; i++) { sol_assert(params.data[i] == i); @@ -64,7 +63,7 @@ extern uint64_t entrypoint(const uint8_t *input) { sol_assert( SolPubkey_same(accounts[INVOKED_PROGRAM_INDEX].key, params.program_id)) sol_assert(SolPubkey_same(accounts[INVOKED_PROGRAM_INDEX].owner, - &sbf_loader_upgradeable_id)); + &loader_v4_id)); sol_assert(!accounts[INVOKED_PROGRAM_INDEX].is_signer); sol_assert(!accounts[INVOKED_PROGRAM_INDEX].is_writable); sol_assert(accounts[INVOKED_PROGRAM_INDEX].rent_epoch == UINT64_MAX); diff --git a/programs/sbf/c/src/read_program/read_program.c b/programs/sbf/c/src/read_program/read_program.c index 28d242efa7f..89eca3de9e2 100644 --- a/programs/sbf/c/src/read_program/read_program.c +++ b/programs/sbf/c/src/read_program/read_program.c @@ -10,10 +10,8 @@ extern uint64_t entrypoint(const uint8_t *input) { return ERROR_INVALID_ARGUMENT; } - char ka_data[] = {0x02, 0x00, 0x00, 0x00}; - sol_assert(params.ka_num == 1); - sol_assert(!sol_memcmp(params.ka[0].data, ka_data, 4)); + sol_assert(!sol_memcmp(params.ka[0].data, params.data, params.data_len)); sol_assert(params.ka[0].is_signer == false); sol_assert(params.ka[0].is_writable == false); sol_assert(params.ka[0].executable == true); diff --git a/programs/sbf/rust/invoked/src/lib.rs b/programs/sbf/rust/invoked/src/lib.rs index 1429cd71a7e..ab92368a87a 100644 --- a/programs/sbf/rust/invoked/src/lib.rs +++ b/programs/sbf/rust/invoked/src/lib.rs @@ -5,8 +5,8 @@ use { solana_program::{ account_info::AccountInfo, - bpf_loader_upgradeable, entrypoint::{ProgramResult, MAX_PERMITTED_DATA_INCREASE}, + loader_v4, log::sol_log_64, msg, program::{get_return_data, invoke, invoke_signed, set_return_data}, @@ -69,10 +69,7 @@ fn process_instruction( assert!(!accounts[INVOKED_ARGUMENT_INDEX].executable); assert_eq!(accounts[INVOKED_PROGRAM_INDEX].key, program_id); - assert_eq!( - accounts[INVOKED_PROGRAM_INDEX].owner, - &bpf_loader_upgradeable::id() - ); + assert_eq!(accounts[INVOKED_PROGRAM_INDEX].owner, &loader_v4::id()); assert!(!accounts[INVOKED_PROGRAM_INDEX].is_signer); assert!(!accounts[INVOKED_PROGRAM_INDEX].is_writable); assert_eq!(accounts[INVOKED_PROGRAM_INDEX].rent_epoch, u64::MAX); diff --git a/programs/sbf/tests/programs.rs b/programs/sbf/tests/programs.rs index 5a7877eeaa2..ea8a8bfc19c 100644 --- a/programs/sbf/tests/programs.rs +++ b/programs/sbf/tests/programs.rs @@ -10,38 +10,29 @@ #[cfg(feature = "sbf_rust")] use { borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize}, - itertools::izip, - solana_account_decoder::parse_bpf_loader::{ - parse_bpf_upgradeable_loader, BpfUpgradeableLoaderAccountType, - }, solana_compute_budget::compute_budget::ComputeBudget, solana_compute_budget_instruction::instructions_processor::process_compute_budget_instructions, solana_feature_set::{self as feature_set, FeatureSet}, - solana_ledger::token_balances::collect_token_balances, - solana_program_runtime::{ - invoke_context::mock_process_instruction, solana_sbpf::vm::ContextObject, - }, + solana_program_runtime::invoke_context::mock_process_instruction, solana_runtime::{ - bank::{Bank, TransactionBalancesSet}, + bank::Bank, bank_client::BankClient, - bank_forks::BankForks, genesis_utils::{ bootstrap_validator_stake_lamports, create_genesis_config, create_genesis_config_with_leader_ex, GenesisConfigInfo, }, loader_utils::{ - create_program, load_program_from_file, load_upgradeable_buffer, - load_upgradeable_program, load_upgradeable_program_and_advance_slot, - load_upgradeable_program_wrapper, set_upgrade_authority, upgrade_program, + create_program, instructions_to_load_program_of_loader_v4, load_program_from_file, + load_program_of_loader_v4, load_upgradeable_buffer, load_upgradeable_program, }, }, solana_runtime_transaction::runtime_transaction::RuntimeTransaction, solana_sbf_rust_invoke_dep::*, solana_sbf_rust_realloc_dep::*, solana_sbf_rust_realloc_invoke_dep::*, + solana_sbpf::vm::ContextObject, solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, - account_utils::StateMut, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, client::SyncClient, clock::{UnixTimestamp, MAX_PROCESSING_AGE}, @@ -52,16 +43,17 @@ use { genesis_config::ClusterType, hash::Hash, instruction::{AccountMeta, Instruction, InstructionError}, - message::{v0::LoadedAddresses, Message, SanitizedMessage}, + loader_v4, + message::{Message, SanitizedMessage}, pubkey::Pubkey, rent::Rent, reserved_account_keys::ReservedAccountKeys, - signature::{keypair_from_seed, Keypair, Signer}, + signature::{Keypair, Signer}, stake, - system_instruction::{self, MAX_PERMITTED_DATA_LENGTH}, + system_instruction::MAX_PERMITTED_DATA_LENGTH, system_program, sysvar::{self, clock}, - transaction::{Transaction, TransactionError, VersionedTransaction}, + transaction::{Transaction, TransactionError}, }, solana_svm::{ transaction_commit_result::{CommittedTransaction, TransactionCommitResult}, @@ -70,19 +62,8 @@ use { }, solana_svm_transaction::svm_message::SVMMessage, solana_timings::ExecuteTimings, - solana_transaction_status::{ - map_inner_instructions, ConfirmedTransactionWithStatusMeta, TransactionStatusMeta, - TransactionWithStatusMeta, VersionedTransactionWithStatusMeta, - }, solana_type_overrides::rand, - std::{ - assert_eq, - cell::RefCell, - collections::HashMap, - str::FromStr, - sync::{Arc, RwLock}, - time::Duration, - }, + std::{assert_eq, cell::RefCell, str::FromStr, sync::Arc, time::Duration}, }; #[cfg(feature = "sbf_rust")] @@ -129,94 +110,6 @@ fn load_execute_and_commit_transaction(bank: &Bank, tx: Transaction) -> Transact commit_results.pop().unwrap() } -#[cfg(feature = "sbf_rust")] -fn execute_transactions( - bank: &Bank, - txs: Vec, -) -> Vec> { - let batch = bank.prepare_batch_for_tests(txs.clone()); - let mut timings = ExecuteTimings::default(); - let mut mint_decimals = HashMap::new(); - let tx_pre_token_balances = collect_token_balances(&bank, &batch, &mut mint_decimals); - let ( - commit_results, - TransactionBalancesSet { - pre_balances, - post_balances, - .. - }, - ) = bank.load_execute_and_commit_transactions( - &batch, - usize::MAX, - true, - ExecutionRecordingConfig::new_single_setting(true), - &mut timings, - None, - ); - let tx_post_token_balances = collect_token_balances(&bank, &batch, &mut mint_decimals); - - izip!( - txs.iter(), - commit_results.into_iter(), - pre_balances.into_iter(), - post_balances.into_iter(), - tx_pre_token_balances.into_iter(), - tx_post_token_balances.into_iter(), - ) - .map( - |( - tx, - commit_result, - pre_balances, - post_balances, - pre_token_balances, - post_token_balances, - )| { - commit_result.map(|committed_tx| { - let CommittedTransaction { - status, - log_messages, - inner_instructions, - return_data, - executed_units, - fee_details, - .. - } = committed_tx; - - let inner_instructions = inner_instructions - .map(|inner_instructions| map_inner_instructions(inner_instructions).collect()); - - let tx_status_meta = TransactionStatusMeta { - status, - fee: fee_details.total_fee(), - pre_balances, - post_balances, - pre_token_balances: Some(pre_token_balances), - post_token_balances: Some(post_token_balances), - inner_instructions, - log_messages, - rewards: None, - loaded_addresses: LoadedAddresses::default(), - return_data, - compute_units_consumed: Some(executed_units), - }; - - ConfirmedTransactionWithStatusMeta { - slot: bank.slot(), - tx_with_meta: TransactionWithStatusMeta::Complete( - VersionedTransactionWithStatusMeta { - transaction: VersionedTransaction::from(tx.clone()), - meta: tx_status_meta, - }, - ), - block_time: None, - } - }) - }, - ) - .collect() -} - #[cfg(feature = "sbf_rust")] const LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST: u32 = 64 * 1024 * 1024; @@ -291,9 +184,9 @@ fn test_program_sbf_sanity() { let authority_keypair = Keypair::new(); // Call user program - let (_, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, program.0, @@ -357,7 +250,7 @@ fn test_program_sbf_loader_deprecated() { #[test] #[cfg(feature = "sbf_rust")] #[should_panic( - expected = "called `Result::unwrap()` on an `Err` value: TransactionError(InstructionError(1, InvalidAccountData))" + expected = "called `Result::unwrap()` on an `Err` value: TransactionError(InstructionError(0, InvalidAccountData))" )] fn test_sol_alloc_free_no_longer_deployable_with_upgradeable_loader() { solana_logger::setup(); @@ -385,9 +278,9 @@ fn test_sol_alloc_free_no_longer_deployable_with_upgradeable_loader() { // in elf inside syscall table. In this case, `sol_alloc_free_` can't be // found in syscall table. Hence, the verification fails and the deployment // fails. - let (_bank, _program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, _program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_deprecated_loader", @@ -422,9 +315,9 @@ fn test_program_sbf_duplicate_accounts() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, program, @@ -529,9 +422,9 @@ fn test_program_sbf_error_handling() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (_bank, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, program, @@ -639,9 +532,9 @@ fn test_return_data_and_log_data_syscall() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, program, @@ -708,23 +601,23 @@ fn test_program_sbf_invoke_sanity() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let invoke_program_id = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, invoke_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, program.1, ); - - let invoked_program_id = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, invoked_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, program.2, ); - - let (bank, noop_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, noop_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, program.3, @@ -1157,16 +1050,16 @@ fn test_program_sbf_program_id_spoofing() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let malicious_swap_pubkey = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, malicious_swap_pubkey) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_spoof1", ); - - let (bank, malicious_system_pubkey) = load_upgradeable_program_and_advance_slot( + let (bank, malicious_system_pubkey) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_spoof1_system", @@ -1211,16 +1104,16 @@ fn test_program_sbf_caller_has_access_to_cpi_program() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let caller_pubkey = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, caller_pubkey) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_caller_access", ); - - let (_bank, caller2_pubkey) = load_upgradeable_program_and_advance_slot( + let (_bank, caller2_pubkey) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_caller_access", @@ -1250,9 +1143,9 @@ fn test_program_sbf_ro_modify() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, program_pubkey) = load_upgradeable_program_and_advance_slot( + let (bank, program_pubkey) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_ro_modify", @@ -1307,9 +1200,9 @@ fn test_program_sbf_call_depth() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (_, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_call_depth", @@ -1344,9 +1237,9 @@ fn test_program_sbf_compute_budget() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (_, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_noop", @@ -1475,9 +1368,9 @@ fn test_program_sbf_instruction_introspection() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_instruction_introspection", @@ -1520,106 +1413,6 @@ fn test_program_sbf_instruction_introspection() { assert!(bank.get_account(&sysvar::instructions::id()).is_none()); } -#[test] -#[cfg(feature = "sbf_rust")] -fn test_program_sbf_upgrade() { - solana_logger::setup(); - - let GenesisConfigInfo { - genesis_config, - mint_keypair, - .. - } = create_genesis_config(50); - let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config); - let mut bank_client = BankClient::new_shared(bank); - - // Deploy upgrade program - let buffer_keypair = Keypair::new(); - let program_keypair = Keypair::new(); - let program_id = program_keypair.pubkey(); - let authority_keypair = Keypair::new(); - load_upgradeable_program( - &bank_client, - &mint_keypair, - &buffer_keypair, - &program_keypair, - &authority_keypair, - "solana_sbf_rust_upgradeable", - ); - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance the slot"); - - let mut instruction = - Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]); - - // Call upgrade program - let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); - assert_eq!( - result.unwrap_err().unwrap(), - TransactionError::InstructionError(0, InstructionError::Custom(42)) - ); - - // Upgrade program - let buffer_keypair = Keypair::new(); - upgrade_program( - &bank_client, - &mint_keypair, - &buffer_keypair, - &program_id, - &authority_keypair, - "solana_sbf_rust_upgraded", - ); - bank_client.set_sysvar_for_tests(&clock::Clock { - slot: 2, - ..clock::Clock::default() - }); - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance the slot"); - - // Call upgraded program - instruction.data[0] += 1; - let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); - assert_eq!( - result.unwrap_err().unwrap(), - TransactionError::InstructionError(0, InstructionError::Custom(43)) - ); - - // Set a new authority - let new_authority_keypair = Keypair::new(); - set_upgrade_authority( - &bank_client, - &mint_keypair, - &program_id, - &authority_keypair, - Some(&new_authority_keypair.pubkey()), - ); - - // Upgrade back to the original program - let buffer_keypair = Keypair::new(); - upgrade_program( - &bank_client, - &mint_keypair, - &buffer_keypair, - &program_id, - &new_authority_keypair, - "solana_sbf_rust_upgradeable", - ); - - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance the slot"); - - // Call original program - instruction.data[0] += 1; - let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction); - assert_eq!( - result.unwrap_err().unwrap(), - TransactionError::InstructionError(0, InstructionError::Custom(42)) - ); -} - fn get_stable_genesis_config() -> GenesisConfigInfo { let validator_pubkey = Pubkey::from_str("GLh546CXmtZdvpEzL8sxzqhhUf7KPvmGaRpFHB5W1sjV").unwrap(); @@ -1665,10 +1458,13 @@ fn test_program_sbf_invoke_stable_genesis_and_bank() { solana_logger::setup(); let GenesisConfigInfo { - genesis_config, + mut genesis_config, mint_keypair, .. } = get_stable_genesis_config(); + genesis_config + .accounts + .remove(&feature_set::enable_loader_v4::id()); let bank = Bank::new_for_tests(&genesis_config); let bank = Arc::new(bank); let bank_client = BankClient::new_shared(bank.clone()); @@ -1847,26 +1643,31 @@ fn test_program_sbf_invoke_in_same_tx_as_deployment() { let mut bank_client = BankClient::new_shared(bank.clone()); // Deploy upgradeable program - let buffer_keypair = Keypair::new(); - let program_keypair = Keypair::new(); - let program_id = program_keypair.pubkey(); let authority_keypair = Keypair::new(); + let (program_keypair, deployment_instructions) = instructions_to_load_program_of_loader_v4( + &bank_client, + &mint_keypair, + &authority_keypair, + "solana_sbf_rust_noop", + None, + None, + ); + let program_id = program_keypair.pubkey(); // Deploy indirect invocation program - let indirect_program_keypair = Keypair::new(); - load_upgradeable_program( - &bank_client, + let (bank, indirect_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, - &buffer_keypair, - &indirect_program_keypair, &authority_keypair, "solana_sbf_rust_invoke_and_return", ); + // Prepare invocations let invoke_instruction = Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]); let indirect_invoke_instruction = Instruction::new_with_bytes( - indirect_program_keypair.pubkey(), + indirect_program_id, &[0], vec![ AccountMeta::new_readonly(program_id, false), @@ -1874,34 +1675,6 @@ fn test_program_sbf_invoke_in_same_tx_as_deployment() { ], ); - // Prepare deployment - let program = load_upgradeable_buffer( - &bank_client, - &mint_keypair, - &buffer_keypair, - &authority_keypair, - "solana_sbf_rust_noop", - ); - let deployment_instructions = bpf_loader_upgradeable::deploy_with_max_program_len( - &mint_keypair.pubkey(), - &program_keypair.pubkey(), - &buffer_keypair.pubkey(), - &authority_keypair.pubkey(), - 1.max( - bank_client - .get_minimum_balance_for_rent_exemption( - bpf_loader_upgradeable::UpgradeableLoaderState::size_of_program(), - ) - .unwrap(), - ), - program.len() * 2, - ) - .unwrap(); - - let bank = bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance slot"); - // Deployment is invisible to both top-level-instructions and CPI instructions for (index, invoke_instruction) in [invoke_instruction, indirect_invoke_instruction] .into_iter() @@ -1924,7 +1697,7 @@ fn test_program_sbf_invoke_in_same_tx_as_deployment() { let (result, _, _, _) = process_transaction_and_record_inner(&bank, tx); assert_eq!( result.unwrap_err(), - TransactionError::InstructionError(2, InstructionError::UnsupportedProgramId), + TransactionError::InstructionError(38, InstructionError::UnsupportedProgramId), ); } } @@ -1944,45 +1717,54 @@ fn test_program_sbf_invoke_in_same_tx_as_redeployment() { let mut bank_client = BankClient::new_shared(bank.clone()); // Deploy upgradeable program - let buffer_keypair = Keypair::new(); - let program_keypair = Keypair::new(); - let program_id = program_keypair.pubkey(); let authority_keypair = Keypair::new(); - load_upgradeable_program( - &bank_client, + let (_bank, program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, - &buffer_keypair, - &program_keypair, &authority_keypair, "solana_sbf_rust_noop", ); + let (source_program_keypair, mut deployment_instructions) = + instructions_to_load_program_of_loader_v4( + &bank_client, + &mint_keypair, + &authority_keypair, + "solana_sbf_rust_panic", + None, + Some(&program_id), + ); + let undeployment_instruction = loader_v4::retract(&program_id, &authority_keypair.pubkey()); + let deployment_instruction = deployment_instructions.pop().unwrap(); + let signers: &[&[&Keypair]] = &[ + &[&mint_keypair, &source_program_keypair], + &[&mint_keypair, &source_program_keypair, &authority_keypair], + &[&mint_keypair, &authority_keypair], + ]; + let signers = std::iter::once(signers[0]) + .chain(std::iter::once(signers[1])) + .chain(std::iter::repeat(signers[2])); + for (instruction, signers) in deployment_instructions.into_iter().zip(signers) { + let message = Message::new(&[instruction], Some(&mint_keypair.pubkey())); + bank_client + .send_and_confirm_message(signers, message) + .unwrap(); + } // Deploy indirect invocation program - let indirect_program_keypair = Keypair::new(); - load_upgradeable_program( - &bank_client, + let (bank, indirect_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, - &buffer_keypair, - &indirect_program_keypair, &authority_keypair, "solana_sbf_rust_invoke_and_return", ); - // Deploy panic program - let panic_program_keypair = Keypair::new(); - load_upgradeable_program( - &bank_client, - &mint_keypair, - &buffer_keypair, - &panic_program_keypair, - &authority_keypair, - "solana_sbf_rust_panic", - ); - + // Prepare invocations let invoke_instruction = Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]); let indirect_invoke_instruction = Instruction::new_with_bytes( - indirect_program_keypair.pubkey(), + indirect_program_id, &[0], vec![ AccountMeta::new_readonly(program_id, false), @@ -1990,33 +1772,18 @@ fn test_program_sbf_invoke_in_same_tx_as_redeployment() { ], ); - // load_upgradeable_program sets clock sysvar to 1, which causes the program to be effective - // after 2 slots. They need to be called individually to create the correct fork graph in between. - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .unwrap(); - let bank = bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .unwrap(); - - // Prepare redeployment - let buffer_keypair = Keypair::new(); - load_upgradeable_buffer( - &bank_client, - &mint_keypair, - &buffer_keypair, - &authority_keypair, - "solana_sbf_rust_panic", - ); - let redeployment_instruction = bpf_loader_upgradeable::upgrade( - &program_id, - &buffer_keypair.pubkey(), - &authority_keypair.pubkey(), - &mint_keypair.pubkey(), - ); - - // Redeployment causes programs to be unavailable to both top-level-instructions and CPI instructions - for invoke_instruction in [invoke_instruction, indirect_invoke_instruction] { + // Redeployment fails when top-level-instructions invoke the program because of write lock demotion + // and the program becomes unavailable to CPI instructions + for (invoke_instruction, expected_error) in [ + ( + invoke_instruction, + TransactionError::InstructionError(0, InstructionError::InvalidArgument), + ), + ( + indirect_invoke_instruction, + TransactionError::InstructionError(2, InstructionError::UnsupportedProgramId), + ), + ] { // Call upgradeable program let result = bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone()); @@ -2024,7 +1791,11 @@ fn test_program_sbf_invoke_in_same_tx_as_redeployment() { // Upgrade the program and invoke in same tx let message = Message::new( - &[redeployment_instruction.clone(), invoke_instruction], + &[ + undeployment_instruction.clone(), + deployment_instruction.clone(), + invoke_instruction, + ], Some(&mint_keypair.pubkey()), ); let tx = Transaction::new( @@ -2033,10 +1804,7 @@ fn test_program_sbf_invoke_in_same_tx_as_redeployment() { bank.last_blockhash(), ); let (result, _, _, _) = process_transaction_and_record_inner(&bank, tx); - assert_eq!( - result.unwrap_err(), - TransactionError::InstructionError(1, InstructionError::UnsupportedProgramId), - ); + assert_eq!(result.unwrap_err(), expected_error,); } } @@ -2054,201 +1822,69 @@ fn test_program_sbf_invoke_in_same_tx_as_undeployment() { let mut bank_client = BankClient::new_shared(bank.clone()); // Deploy upgradeable program - let buffer_keypair = Keypair::new(); - let program_keypair = Keypair::new(); - let program_id = program_keypair.pubkey(); let authority_keypair = Keypair::new(); - load_upgradeable_program( - &bank_client, + let (_bank, program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, - &buffer_keypair, - &program_keypair, &authority_keypair, "solana_sbf_rust_noop", ); // Deploy indirect invocation program - let indirect_program_keypair = Keypair::new(); - load_upgradeable_program( - &bank_client, - &mint_keypair, - &buffer_keypair, - &indirect_program_keypair, - &authority_keypair, - "solana_sbf_rust_invoke_and_return", - ); - - let invoke_instruction = - Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]); - let indirect_invoke_instruction = Instruction::new_with_bytes( - indirect_program_keypair.pubkey(), - &[0], - vec![ - AccountMeta::new_readonly(program_id, false), - AccountMeta::new_readonly(clock::id(), false), - ], - ); - - // load_upgradeable_program sets clock sysvar to 1, which causes the program to be effective - // after 2 slots. They need to be called individually to create the correct fork graph in between. - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .unwrap(); - let bank = bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .unwrap(); - - // Prepare undeployment - let (programdata_address, _) = Pubkey::find_program_address( - &[program_keypair.pubkey().as_ref()], - &bpf_loader_upgradeable::id(), - ); - let undeployment_instruction = bpf_loader_upgradeable::close_any( - &programdata_address, - &mint_keypair.pubkey(), - Some(&authority_keypair.pubkey()), - Some(&program_id), - ); - - // Undeployment is visible to both top-level-instructions and CPI instructions - for invoke_instruction in [invoke_instruction, indirect_invoke_instruction] { - // Call upgradeable program - let result = - bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone()); - assert!(result.is_ok()); - - // Upgrade the program and invoke in same tx - let message = Message::new( - &[undeployment_instruction.clone(), invoke_instruction], - Some(&mint_keypair.pubkey()), - ); - let tx = Transaction::new( - &[&mint_keypair, &authority_keypair], - message.clone(), - bank.last_blockhash(), - ); - let (result, _, _, _) = process_transaction_and_record_inner(&bank, tx); - assert_eq!( - result.unwrap_err(), - TransactionError::InstructionError(1, InstructionError::UnsupportedProgramId), - ); - } -} - -#[test] -#[cfg(feature = "sbf_rust")] -fn test_program_sbf_invoke_upgradeable_via_cpi() { - solana_logger::setup(); - - let GenesisConfigInfo { - genesis_config, - mint_keypair, - .. - } = create_genesis_config(50); - - let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config); - let mut bank_client = BankClient::new_shared(bank); - let authority_keypair = Keypair::new(); - - let (_bank, invoke_and_return) = load_upgradeable_program_and_advance_slot( + let (bank, indirect_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke_and_return", ); - // Deploy upgradeable program - let program_id = load_upgradeable_program_wrapper( - &bank_client, - &mint_keypair, - &authority_keypair, - "solana_sbf_rust_upgradeable", - ); - bank_client.set_sysvar_for_tests(&clock::Clock { - slot: 2, - ..clock::Clock::default() - }); - - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance slot"); - - let mut instruction = Instruction::new_with_bytes( - invoke_and_return, - &[0], - vec![ - AccountMeta::new_readonly(program_id, false), - AccountMeta::new_readonly(clock::id(), false), - ], - ); - - // Call invoker program to invoke the upgradeable program - instruction.data[0] += 1; - let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); - assert_eq!( - result.unwrap_err().unwrap(), - TransactionError::InstructionError(0, InstructionError::Custom(42)) - ); - - // Upgrade program - let buffer_keypair = Keypair::new(); - upgrade_program( - &bank_client, - &mint_keypair, - &buffer_keypair, - &program_id, - &authority_keypair, - "solana_sbf_rust_upgraded", - ); - bank_client.set_sysvar_for_tests(&clock::Clock { - slot: 3, - ..clock::Clock::default() - }); - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance slot"); - - // Call the upgraded program - instruction.data[0] += 1; - let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); - assert_eq!( - result.unwrap_err().unwrap(), - TransactionError::InstructionError(0, InstructionError::Custom(43)) - ); - - // Set a new authority - let new_authority_keypair = Keypair::new(); - set_upgrade_authority( - &bank_client, - &mint_keypair, - &program_id, - &authority_keypair, - Some(&new_authority_keypair.pubkey()), - ); - - // Upgrade back to the original program - let buffer_keypair = Keypair::new(); - upgrade_program( - &bank_client, - &mint_keypair, - &buffer_keypair, - &program_id, - &new_authority_keypair, - "solana_sbf_rust_upgradeable", + // Prepare invocations + let invoke_instruction = + Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]); + let indirect_invoke_instruction = Instruction::new_with_bytes( + indirect_program_id, + &[0], + vec![ + AccountMeta::new_readonly(program_id, false), + AccountMeta::new_readonly(clock::id(), false), + ], ); - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance slot"); + // Prepare undeployment + let undeployment_instruction = loader_v4::retract(&program_id, &authority_keypair.pubkey()); + + // Undeployment fails when top-level-instructions invoke the program because of write lock demotion + // and the program becomes unavailable to CPI instructions + for (invoke_instruction, expected_error) in [ + ( + invoke_instruction, + TransactionError::InstructionError(0, InstructionError::InvalidArgument), + ), + ( + indirect_invoke_instruction, + TransactionError::InstructionError(1, InstructionError::UnsupportedProgramId), + ), + ] { + // Call upgradeable program + let result = + bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone()); + assert!(result.is_ok()); - // Call original program - instruction.data[0] += 1; - let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); - assert_eq!( - result.unwrap_err().unwrap(), - TransactionError::InstructionError(0, InstructionError::Custom(42)) - ); + // Upgrade the program and invoke in same tx + let message = Message::new( + &[undeployment_instruction.clone(), invoke_instruction], + Some(&mint_keypair.pubkey()), + ); + let tx = Transaction::new( + &[&mint_keypair, &authority_keypair], + message.clone(), + bank.last_blockhash(), + ); + let (result, _, _, _) = process_transaction_and_record_inner(&bank, tx); + assert_eq!(result.unwrap_err(), expected_error,); + } } #[test] @@ -2278,9 +1914,9 @@ fn test_program_sbf_disguised_as_sbf_loader() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (_bank, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, program, @@ -2311,15 +1947,20 @@ fn test_program_reads_from_program_account() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (_bank, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "read_program", ); + let data = bank_client.get_account_data(&program_id).unwrap().unwrap(); let account_metas = vec![AccountMeta::new_readonly(program_id, false)]; - let instruction = Instruction::new_with_bytes(program_id, &[], account_metas); + let instruction = Instruction::new_with_bytes( + program_id, + &data[0..loader_v4::LoaderV4State::program_data_offset()], + account_metas, + ); bank_client .send_and_confirm_instruction(&mint_keypair, instruction) .unwrap(); @@ -2344,9 +1985,9 @@ fn test_program_sbf_c_dup() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (_, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "ser", @@ -2363,7 +2004,7 @@ fn test_program_sbf_c_dup() { #[test] #[cfg(feature = "sbf_rust")] -fn test_program_sbf_upgrade_via_cpi() { +fn test_program_sbf_upgrade() { solana_logger::setup(); let GenesisConfigInfo { @@ -2371,113 +2012,91 @@ fn test_program_sbf_upgrade_via_cpi() { mint_keypair, .. } = create_genesis_config(50); - let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config); let mut bank_client = BankClient::new_shared(bank); - let authority_keypair = Keypair::new(); - - let (_bank, invoke_and_return) = load_upgradeable_program_and_advance_slot( - &mut bank_client, - bank_forks.as_ref(), - &mint_keypair, - &authority_keypair, - "solana_sbf_rust_invoke_and_return", - ); - // Deploy upgradeable program - let buffer_keypair = Keypair::new(); - let program_keypair = Keypair::new(); - let program_id = program_keypair.pubkey(); + // Deploy upgrade program let authority_keypair = Keypair::new(); - load_upgradeable_program( - &bank_client, + let (_bank, program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, - &buffer_keypair, - &program_keypair, &authority_keypair, "solana_sbf_rust_upgradeable", ); - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance the slot"); - let program_account = bank_client.get_account(&program_id).unwrap().unwrap(); - let Ok(bpf_loader_upgradeable::UpgradeableLoaderState::Program { - programdata_address, - }) = program_account.state() - else { - unreachable!() - }; - let original_programdata = bank_client - .get_account_data(&programdata_address) - .unwrap() - .unwrap(); - - let mut instruction = Instruction::new_with_bytes( - invoke_and_return, - &[0], - vec![ - AccountMeta::new_readonly(program_id, false), - AccountMeta::new_readonly(clock::id(), false), - ], - ); - // Call the upgradable program - instruction.data[0] += 1; + // Call upgradeable program + let mut instruction = + Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]); let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); assert_eq!( result.unwrap_err().unwrap(), TransactionError::InstructionError(0, InstructionError::Custom(42)) ); - // Load the buffer account - let buffer_keypair = Keypair::new(); - load_upgradeable_buffer( - &bank_client, - &mint_keypair, - &buffer_keypair, - &authority_keypair, - "solana_sbf_rust_upgraded", - ); - - // Upgrade program via CPI - let mut upgrade_instruction = bpf_loader_upgradeable::upgrade( + // Set authority + let new_authority_keypair = Keypair::new(); + let authority_instruction = loader_v4::transfer_authority( &program_id, - &buffer_keypair.pubkey(), &authority_keypair.pubkey(), - &mint_keypair.pubkey(), + &new_authority_keypair.pubkey(), ); - upgrade_instruction.program_id = invoke_and_return; - upgrade_instruction - .accounts - .insert(0, AccountMeta::new(bpf_loader_upgradeable::id(), false)); - let message = Message::new(&[upgrade_instruction], Some(&mint_keypair.pubkey())); + let message = Message::new(&[authority_instruction], Some(&mint_keypair.pubkey())); bank_client - .send_and_confirm_message(&[&mint_keypair, &authority_keypair], message) + .send_and_confirm_message( + &[&mint_keypair, &authority_keypair, &new_authority_keypair], + message, + ) .unwrap(); + // Upgrade program + let (source_program_keypair, mut deployment_instructions) = + instructions_to_load_program_of_loader_v4( + &bank_client, + &mint_keypair, + &new_authority_keypair, + "solana_sbf_rust_upgraded", + None, + Some(&program_id), + ); + deployment_instructions.insert( + deployment_instructions.len() - 1, + loader_v4::retract(&program_id, &new_authority_keypair.pubkey()), + ); + let signers: &[&[&Keypair]] = &[ + &[&mint_keypair, &source_program_keypair], + &[ + &mint_keypair, + &source_program_keypair, + &new_authority_keypair, + ], + &[&mint_keypair, &new_authority_keypair], + ]; + let signers = std::iter::once(signers[0]) + .chain(std::iter::once(signers[1])) + .chain(std::iter::repeat(signers[2])); + for (instruction, signers) in deployment_instructions.into_iter().zip(signers) { + let message = Message::new(&[instruction], Some(&mint_keypair.pubkey())); + bank_client + .send_and_confirm_message(signers, message) + .unwrap(); + } bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) + .advance_slot(1, &bank_forks, &Pubkey::default()) .expect("Failed to advance the slot"); - // Call the upgraded program + // Call upgraded program instruction.data[0] += 1; let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); assert_eq!( result.unwrap_err().unwrap(), TransactionError::InstructionError(0, InstructionError::Custom(43)) ); - - // Validate that the programdata was actually overwritten - let programdata = bank_client - .get_account_data(&programdata_address) - .unwrap() - .unwrap(); - assert_ne!(programdata, original_programdata); } #[test] #[cfg(feature = "sbf_rust")] -fn test_program_sbf_set_upgrade_authority_via_cpi() { +fn test_program_sbf_upgrade_via_cpi() { solana_logger::setup(); let GenesisConfigInfo { @@ -2490,200 +2109,115 @@ fn test_program_sbf_set_upgrade_authority_via_cpi() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - // Deploy CPI invoker program - let invoke_and_return = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, invoke_and_return) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke_and_return", ); // Deploy upgradeable program - let program_id = load_upgradeable_program_wrapper( - &bank_client, + let authority_keypair = Keypair::new(); + let (_bank, program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_upgradeable", ); - bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance the slot"); + // Call the upgradable program via CPI + let mut instruction = Instruction::new_with_bytes( + invoke_and_return, + &[0], + vec![ + AccountMeta::new_readonly(program_id, false), + AccountMeta::new_readonly(clock::id(), false), + ], + ); + instruction.data[0] += 1; + let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); + assert_eq!( + result.unwrap_err().unwrap(), + TransactionError::InstructionError(0, InstructionError::Custom(42)) + ); - // Set program upgrade authority instruction to invoke via CPI - let new_upgrade_authority_key = Keypair::new().pubkey(); - let mut set_upgrade_authority_instruction = bpf_loader_upgradeable::set_upgrade_authority( + // Set authority via CPI + let new_authority_keypair = Keypair::new(); + let mut authority_instruction = loader_v4::transfer_authority( &program_id, &authority_keypair.pubkey(), - Some(&new_upgrade_authority_key), + &new_authority_keypair.pubkey(), ); - - // Invoke set_upgrade_authority via CPI invoker program - set_upgrade_authority_instruction.program_id = invoke_and_return; - set_upgrade_authority_instruction + authority_instruction.program_id = invoke_and_return; + authority_instruction .accounts - .insert(0, AccountMeta::new(bpf_loader_upgradeable::id(), false)); - - let message = Message::new( - &[set_upgrade_authority_instruction], - Some(&mint_keypair.pubkey()), - ); + .insert(0, AccountMeta::new(loader_v4::id(), false)); + let message = Message::new(&[authority_instruction], Some(&mint_keypair.pubkey())); bank_client - .send_and_confirm_message(&[&mint_keypair, &authority_keypair], message) + .send_and_confirm_message( + &[&mint_keypair, &authority_keypair, &new_authority_keypair], + message, + ) .unwrap(); - // Assert upgrade authority was changed - let program_account_data = bank_client.get_account_data(&program_id).unwrap().unwrap(); - let program_account = parse_bpf_upgradeable_loader(&program_account_data).unwrap(); - - let upgrade_authority_key = match program_account { - BpfUpgradeableLoaderAccountType::Program(ui_program) => { - let program_data_account_key = Pubkey::from_str(&ui_program.program_data).unwrap(); - let program_data_account_data = bank_client - .get_account_data(&program_data_account_key) - .unwrap() - .unwrap(); - let program_data_account = - parse_bpf_upgradeable_loader(&program_data_account_data).unwrap(); - - match program_data_account { - BpfUpgradeableLoaderAccountType::ProgramData(ui_program_data) => ui_program_data - .authority - .map(|a| Pubkey::from_str(&a).unwrap()), - _ => None, - } - } - _ => None, - }; - - assert_eq!(Some(new_upgrade_authority_key), upgrade_authority_key); -} - -#[test] -#[cfg(feature = "sbf_rust")] -fn test_program_upgradeable_locks() { - fn setup_program_upgradeable_locks( - payer_keypair: &Keypair, - buffer_keypair: &Keypair, - program_keypair: &Keypair, - ) -> (Arc, Arc>, Transaction, Transaction) { - solana_logger::setup(); - - let GenesisConfigInfo { - genesis_config, - mint_keypair, - .. - } = create_genesis_config(2_000_000_000); - let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config); - let mut bank_client = BankClient::new_shared(bank.clone()); - - load_upgradeable_program( + // Upgrade program via CPI + let (source_program_keypair, mut deployment_instructions) = + instructions_to_load_program_of_loader_v4( &bank_client, &mint_keypair, - buffer_keypair, - program_keypair, - payer_keypair, - "solana_sbf_rust_panic", + &new_authority_keypair, + "solana_sbf_rust_upgraded", + None, + Some(&program_id), ); - - // Load the buffer account - load_upgradeable_buffer( - &bank_client, + deployment_instructions.insert( + deployment_instructions.len() - 1, + loader_v4::retract(&program_id, &new_authority_keypair.pubkey()), + ); + let mut upgrade_instruction = deployment_instructions.pop().unwrap(); + let signers: &[&[&Keypair]] = &[ + &[&mint_keypair, &source_program_keypair], + &[ &mint_keypair, - buffer_keypair, - &payer_keypair, - "solana_sbf_rust_noop", - ); - - let bank = bank_client - .advance_slot(1, bank_forks.as_ref(), &Pubkey::default()) - .expect("Failed to advance the slot"); - + &source_program_keypair, + &new_authority_keypair, + ], + &[&mint_keypair, &new_authority_keypair], + ]; + let signers = std::iter::once(signers[0]) + .chain(std::iter::once(signers[1])) + .chain(std::iter::repeat(signers[2])); + for (instruction, signers) in deployment_instructions.into_iter().zip(signers) { + let message = Message::new(&[instruction], Some(&mint_keypair.pubkey())); bank_client - .send_and_confirm_instruction( - &mint_keypair, - system_instruction::transfer( - &mint_keypair.pubkey(), - &payer_keypair.pubkey(), - 1_000_000_000, - ), - ) + .send_and_confirm_message(signers, message) .unwrap(); - - let invoke_tx = Transaction::new( - &[payer_keypair], - Message::new( - &[Instruction::new_with_bytes( - program_keypair.pubkey(), - &[0; 0], - vec![], - )], - Some(&payer_keypair.pubkey()), - ), - bank.last_blockhash(), - ); - let upgrade_tx = Transaction::new( - &[payer_keypair], - Message::new( - &[bpf_loader_upgradeable::upgrade( - &program_keypair.pubkey(), - &buffer_keypair.pubkey(), - &payer_keypair.pubkey(), - &payer_keypair.pubkey(), - )], - Some(&payer_keypair.pubkey()), - ), - bank.last_blockhash(), - ); - - (bank, bank_forks, invoke_tx, upgrade_tx) } + upgrade_instruction.program_id = invoke_and_return; + upgrade_instruction + .accounts + .insert(0, AccountMeta::new(loader_v4::id(), false)); + let message = Message::new(&[upgrade_instruction], Some(&mint_keypair.pubkey())); + let result = + bank_client.send_and_confirm_message(&[&mint_keypair, &new_authority_keypair], message); + // This fails for now because of the `callee_account.is_executable()` check in CPI `translate_and_update_accounts()` + assert_eq!( + result.unwrap_err().unwrap(), + TransactionError::InstructionError(0, InstructionError::AccountDataSizeChanged) + ); + bank_client + .advance_slot(1, &bank_forks, &Pubkey::default()) + .expect("Failed to advance the slot"); - let payer_keypair = keypair_from_seed(&[56u8; 32]).unwrap(); - let buffer_keypair = keypair_from_seed(&[11; 32]).unwrap(); - let program_keypair = keypair_from_seed(&[77u8; 32]).unwrap(); - - let results1 = { - let (bank, _bank_forks, invoke_tx, upgrade_tx) = - setup_program_upgradeable_locks(&payer_keypair, &buffer_keypair, &program_keypair); - execute_transactions(&bank, vec![upgrade_tx, invoke_tx]) - }; - - let results2 = { - let (bank, _bank_forks, invoke_tx, upgrade_tx) = - setup_program_upgradeable_locks(&payer_keypair, &buffer_keypair, &program_keypair); - execute_transactions(&bank, vec![invoke_tx, upgrade_tx]) - }; - - assert!(matches!( - results1[0], - Ok(ConfirmedTransactionWithStatusMeta { - tx_with_meta: TransactionWithStatusMeta::Complete(VersionedTransactionWithStatusMeta { - meta: TransactionStatusMeta { status: Ok(()), .. }, - .. - }), - .. - }) - )); - assert_eq!(results1[1], Err(TransactionError::AccountInUse)); - - assert!(matches!( - results2[0], - Ok(ConfirmedTransactionWithStatusMeta { - tx_with_meta: TransactionWithStatusMeta::Complete(VersionedTransactionWithStatusMeta { - meta: TransactionStatusMeta { - status: Err(TransactionError::InstructionError( - 0, - InstructionError::ProgramFailedToComplete - )), - .. - }, - .. - }), - .. - }) - )); - assert_eq!(results2[1], Err(TransactionError::AccountInUse)); + // Call the upgraded program via CPI + instruction.data[0] += 1; + let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone()); + assert_eq!( + result.unwrap_err().unwrap(), + TransactionError::InstructionError(0, InstructionError::UnsupportedProgramId) + ); } #[test] @@ -2701,9 +2235,9 @@ fn test_program_sbf_ro_account_modify() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_ro_account_modify", @@ -2775,9 +2309,9 @@ fn test_program_sbf_realloc() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_realloc", @@ -3192,16 +2726,16 @@ fn test_program_sbf_realloc_invoke() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let realloc_program_id = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, realloc_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_realloc", ); - - let (bank, realloc_invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, realloc_invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_realloc_invoke", @@ -3805,27 +3339,30 @@ fn test_program_sbf_processed_inner_instruction() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let sibling_program_id = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, sibling_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_sibling_instructions", ); - let sibling_inner_program_id = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, sibling_inner_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_sibling_inner_instructions", ); - let noop_program_id = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, noop_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, - "solana_sbf_rust_noop", + "noop", ); - let (_, invoke_and_return_program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, invoke_and_return_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke_and_return", @@ -3889,9 +3426,9 @@ fn test_program_fees() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (_bank, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_noop", @@ -3978,9 +3515,9 @@ fn test_get_minimum_delegation() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (_bank, program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_get_minimum_delegation", @@ -4053,23 +3590,23 @@ fn test_cpi_account_ownership_writability() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let invoke_program_id = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, invoke_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", ); - - let invoked_program_id = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, invoked_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoked", ); - - let (bank, realloc_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, realloc_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_realloc", @@ -4237,16 +3774,16 @@ fn test_cpi_account_data_updates() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let invoke_program_id = load_upgradeable_program_wrapper( - &bank_client, + let (_bank, invoke_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", ); - - let (bank, realloc_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, realloc_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_realloc", @@ -4395,9 +3932,9 @@ fn test_cpi_deprecated_loader_realloc() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (bank, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", @@ -4540,9 +4077,9 @@ fn test_cpi_change_account_data_memory_allocation() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (bank, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", @@ -4585,12 +4122,16 @@ fn test_cpi_invalid_account_info_pointers() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let c_invoke_program_id = - load_upgradeable_program_wrapper(&bank_client, &mint_keypair, &authority_keypair, "invoke"); - - let (bank, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, c_invoke_program_id) = load_program_of_loader_v4( + &mut bank_client, + &bank_forks, + &mint_keypair, + &authority_keypair, + "invoke", + ); + let (bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", @@ -4653,7 +4194,7 @@ fn test_deplete_cost_meter_with_access_violation() { let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests(); let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, bank_forks.as_ref(), &mint_keypair, @@ -4726,7 +4267,7 @@ fn test_program_sbf_deplete_cost_meter_with_divide_by_zero() { let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests(); let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, bank_forks.as_ref(), &mint_keypair, @@ -4783,9 +4324,9 @@ fn test_deny_executable_write() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (_bank, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", @@ -4838,9 +4379,9 @@ fn test_update_callee_account() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", @@ -5123,9 +4664,9 @@ fn test_account_info_in_account() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, program, @@ -5184,9 +4725,9 @@ fn test_account_info_rc_in_account() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", @@ -5273,27 +4814,21 @@ fn test_clone_account_data() { let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (_, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (_bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", ); - - let (bank, invoke_program_id2) = load_upgradeable_program_and_advance_slot( + let (bank, invoke_program_id2) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", ); - assert_ne!(invoke_program_id, invoke_program_id2); - - println!("invoke_program_id:{invoke_program_id}"); - println!("invoke_program_id2:{invoke_program_id2}"); - let account_keypair = Keypair::new(); let mint_pubkey = mint_keypair.pubkey(); @@ -5408,9 +4943,9 @@ fn test_stack_heap_zeroed() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (bank, invoke_program_id) = load_upgradeable_program_and_advance_slot( + let (bank, invoke_program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_invoke", @@ -5474,9 +5009,9 @@ fn test_function_call_args() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_call_args", @@ -5626,9 +5161,9 @@ fn test_mem_syscalls_overlap_account_begin_or_end() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_rust_account_mem", diff --git a/programs/sbf/tests/simulation.rs b/programs/sbf/tests/simulation.rs index 62732531065..e16d25eee29 100644 --- a/programs/sbf/tests/simulation.rs +++ b/programs/sbf/tests/simulation.rs @@ -6,7 +6,7 @@ use { bank::Bank, bank_client::BankClient, genesis_utils::{create_genesis_config, GenesisConfigInfo}, - loader_utils::load_upgradeable_program_and_advance_slot, + loader_utils::load_program_of_loader_v4, }, solana_runtime_transaction::runtime_transaction::RuntimeTransaction, solana_sdk::{ @@ -31,7 +31,7 @@ fn test_no_panic_banks_client() { let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config); let mut bank_client = BankClient::new_shared(bank.clone()); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, bank_forks.as_ref(), &mint_keypair, diff --git a/programs/sbf/tests/syscall_get_epoch_stake.rs b/programs/sbf/tests/syscall_get_epoch_stake.rs index 2cd7e20a1f3..d87a30eec7d 100644 --- a/programs/sbf/tests/syscall_get_epoch_stake.rs +++ b/programs/sbf/tests/syscall_get_epoch_stake.rs @@ -8,7 +8,7 @@ use { genesis_utils::{ create_genesis_config_with_vote_accounts, GenesisConfigInfo, ValidatorVoteKeypairs, }, - loader_utils::load_upgradeable_program_and_advance_slot, + loader_utils::load_program_of_loader_v4, }, solana_runtime_transaction::runtime_transaction::RuntimeTransaction, solana_sdk::{ @@ -70,9 +70,9 @@ fn test_syscall_get_epoch_stake() { let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, - bank_forks.as_ref(), + &bank_forks, &mint_keypair, &authority_keypair, "solana_sbf_syscall_get_epoch_stake", diff --git a/programs/sbf/tests/sysvar.rs b/programs/sbf/tests/sysvar.rs index 41a3d7016da..a54c89158bf 100644 --- a/programs/sbf/tests/sysvar.rs +++ b/programs/sbf/tests/sysvar.rs @@ -6,7 +6,7 @@ use { bank::Bank, bank_client::BankClient, genesis_utils::{create_genesis_config, GenesisConfigInfo}, - loader_utils::load_upgradeable_program_and_advance_slot, + loader_utils::load_program_of_loader_v4, }, solana_runtime_transaction::runtime_transaction::RuntimeTransaction, solana_sdk::{ @@ -62,7 +62,7 @@ fn test_sysvar_syscalls() { let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests(); let mut bank_client = BankClient::new_shared(bank); let authority_keypair = Keypair::new(); - let (bank, program_id) = load_upgradeable_program_and_advance_slot( + let (bank, program_id) = load_program_of_loader_v4( &mut bank_client, bank_forks.as_ref(), &mint_keypair, diff --git a/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs b/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs index 5b152b40b9e..117f75c295d 100644 --- a/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs +++ b/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs @@ -114,10 +114,7 @@ mod tests { #[test_case(solana_stake_program::id(), None)] #[test_case(solana_system_program::id(), None)] #[test_case(solana_vote_program::id(), None)] - #[test_case( - solana_sdk::loader_v4::id(), - Some(feature_set::enable_program_runtime_v2_and_loader_v4::id()) - )] + #[test_case(solana_sdk::loader_v4::id(), Some(feature_set::enable_loader_v4::id()))] #[test_case( solana_sdk_ids::zk_token_proof_program::id(), Some(feature_set::zk_token_sdk_enabled::id()) diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index 7aa0e305f4c..09dffdc8d6a 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -73,6 +73,7 @@ use { incinerator, instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}, loader_upgradeable_instruction::UpgradeableLoaderInstruction, + loader_v4::{self, LoaderV4State}, message::{Message, MessageHeader, SanitizedMessage}, native_loader, native_token::{sol_to_lamports, LAMPORTS_PER_SOL}, @@ -7247,6 +7248,7 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() { let (genesis_config, mint_keypair) = create_genesis_config_no_tx_fee(1_000_000_000); let mut bank = Bank::new_for_tests(&genesis_config); bank.feature_set = Arc::new(FeatureSet::all_enabled()); + bank.deactivate_feature(&solana_feature_set::enable_loader_v4::id()); let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests(); let mut bank_client = BankClient::new_shared(bank.clone()); @@ -13278,11 +13280,15 @@ fn test_deploy_last_epoch_slot() { // Bank Setup let (mut genesis_config, mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL); + activate_feature( + &mut genesis_config, + solana_feature_set::enable_loader_v4::id(), + ); genesis_config .accounts - .remove(&feature_set::disable_fees_sysvar::id()); + .remove(&feature_set::remove_accounts_executable_flag_checks::id()); let mut bank = Bank::new_for_tests(&genesis_config); - bank.activate_feature(&feature_set::disable_fees_sysvar::id()); + bank.activate_feature(&feature_set::remove_accounts_executable_flag_checks::id()); // go to the last slot in the epoch let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests(); @@ -13301,47 +13307,41 @@ fn test_deploy_last_epoch_slot() { 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 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(elf.len())); - let min_programdata_balance = bank.get_minimum_balance_for_rent_exemption( - UpgradeableLoaderState::size_of_programdata(elf.len()), - ); - let buffer_address = Pubkey::new_unique(); - let (programdata_address, _) = Pubkey::find_program_address( - &[program_keypair.pubkey().as_ref()], - &bpf_loader_upgradeable::id(), + let min_program_balance = bank.get_minimum_balance_for_rent_exemption( + LoaderV4State::program_data_offset().saturating_add(elf.len()), ); let upgrade_authority_keypair = Keypair::new(); - 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 + let mut program_account = AccountSharedData::new( + min_program_balance, + LoaderV4State::program_data_offset().saturating_add(elf.len()), + &loader_v4::id(), + ); + let program_state = <&mut [u8; LoaderV4State::program_data_offset()]>::try_from( + program_account .data_as_mut_slice() - .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..) - .unwrap() - .copy_from_slice(&elf); - account + .get_mut(0..LoaderV4State::program_data_offset()) + .unwrap(), + ) + .unwrap(); + let program_state = unsafe { + std::mem::transmute::<&mut [u8; LoaderV4State::program_data_offset()], &mut LoaderV4State>( + program_state, + ) }; + program_state.authority_address_or_next_version = upgrade_authority_keypair.pubkey(); + program_account + .data_as_mut_slice() + .get_mut(LoaderV4State::program_data_offset()..) + .unwrap() + .copy_from_slice(&elf); 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)); + let min_payer_balance = min_program_balance.saturating_add(deploy_fees); bank.store_account( &payer_keypair.pubkey(), &AccountSharedData::new( @@ -13350,22 +13350,15 @@ fn test_deploy_last_epoch_slot() { &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()); + bank.store_account(&program_keypair.pubkey(), &program_account); let message = Message::new( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &payer_keypair.pubkey(), + &[loader_v4::deploy( &program_keypair.pubkey(), - &buffer_address, &upgrade_authority_keypair.pubkey(), - min_program_balance, - elf.len(), - ) - .unwrap(), + )], Some(&payer_keypair.pubkey()), ); - let signers = &[&payer_keypair, &program_keypair, &upgrade_authority_keypair]; + let signers = &[&payer_keypair, &upgrade_authority_keypair]; let transaction = Transaction::new(signers, message.clone(), bank.last_blockhash()); let ret = bank.process_transaction(&transaction); assert!(ret.is_ok(), "ret: {:?}", ret); diff --git a/runtime/src/loader_utils.rs b/runtime/src/loader_utils.rs index 61404464bce..7c849560b29 100644 --- a/runtime/src/loader_utils.rs +++ b/runtime/src/loader_utils.rs @@ -273,7 +273,9 @@ pub fn instructions_to_load_program_of_loader_v4( &payer_keypair.pubkey(), &program_keypair.pubkey(), bank_client - .get_minimum_balance_for_rent_exemption(program.len()) + .get_minimum_balance_for_rent_exemption( + loader_v4::LoaderV4State::program_data_offset().saturating_add(program.len()), + ) .unwrap(), 0, loader_id, diff --git a/sdk/feature-set/src/lib.rs b/sdk/feature-set/src/lib.rs index 8fc7fb5d623..d2adb584ba3 100644 --- a/sdk/feature-set/src/lib.rs +++ b/sdk/feature-set/src/lib.rs @@ -688,8 +688,8 @@ pub mod remaining_compute_units_syscall_enabled { solana_pubkey::declare_id!("5TuppMutoyzhUSfuYdhgzD47F92GL1g89KpCZQKqedxP"); } -pub mod enable_program_runtime_v2_and_loader_v4 { - solana_pubkey::declare_id!("8oBxsYqnCvUTGzgEpxPcnVf7MLbWWPYddE33PftFeBBd"); +pub mod enable_loader_v4 { + solana_pubkey::declare_id!("8Cb77yHjPWe9wuWUfXeh6iszFGCDGNCoFk3tprViYHNm"); } pub mod require_rent_exempt_split_destination { @@ -1084,7 +1084,7 @@ lazy_static! { (enable_poseidon_syscall::id(), "Enable Poseidon syscall"), (timely_vote_credits::id(), "use timeliness of votes in determining credits to award"), (remaining_compute_units_syscall_enabled::id(), "enable the remaining_compute_units syscall"), - (enable_program_runtime_v2_and_loader_v4::id(), "Enable Program-Runtime-v2 and Loader-v4 #33293"), + (enable_loader_v4::id(), "Enable Loader-v4 SIMD-0167"), (require_rent_exempt_split_destination::id(), "Require stake split destination account to be rent exempt"), (better_error_codes_for_tx_lamport_check::id(), "better error codes for tx lamport check #33353"), (enable_alt_bn128_compression_syscall::id(), "add alt_bn128 compression syscalls"),