diff --git a/cli/src/program.rs b/cli/src/program.rs index 92c3c657adc40a..1a1234182f8ab7 100644 --- a/cli/src/program.rs +++ b/cli/src/program.rs @@ -13,6 +13,7 @@ use { solana_bpf_loader_program::syscalls::create_program_runtime_environment_v1, solana_clap_utils::{ self, + compute_unit_price::compute_unit_price_arg, fee_payer::{fee_payer_arg, FEE_PAYER_ARG}, hidden_unless_forced, input_parsers::*, @@ -48,6 +49,7 @@ use { account_utils::StateMut, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, + compute_budget::ComputeBudgetInstruction, feature_set::FeatureSet, instruction::{Instruction, InstructionError}, loader_instruction, @@ -90,6 +92,7 @@ pub enum ProgramCliCommand { max_len: Option, allow_excessive_balance: bool, skip_fee_check: bool, + compute_unit_price: Option, }, Upgrade { fee_payer_signer_index: SignerIndex, @@ -108,6 +111,7 @@ pub enum ProgramCliCommand { buffer_authority_signer_index: SignerIndex, max_len: Option, skip_fee_check: bool, + compute_unit_price: Option, }, SetBufferAuthority { buffer_pubkey: Pubkey, @@ -236,7 +240,8 @@ impl ProgramSubCommands for App<'_, '_> { "Use the designated program id even if the account already \ holds a large balance of SOL", ), - ), + ) + .arg(compute_unit_price_arg()), ) .subcommand( SubCommand::with_name("upgrade") @@ -308,7 +313,8 @@ impl ProgramSubCommands for App<'_, '_> { "Maximum length of the upgradeable program \ [default: the length of the original deployed program]", ), - ), + ) + .arg(compute_unit_price_arg()), ) .subcommand( SubCommand::with_name("set-buffer-authority") @@ -601,6 +607,8 @@ pub fn parse_program_subcommand( let signer_info = default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?; + let compute_unit_price = value_of(matches, "compute_unit_price"); + CliCommandInfo { command: CliCommand::Program(ProgramCliCommand::Deploy { program_location, @@ -616,6 +624,7 @@ pub fn parse_program_subcommand( max_len, allow_excessive_balance: matches.is_present("allow_excessive_balance"), skip_fee_check, + compute_unit_price, }), signers: signer_info.signers, } @@ -687,6 +696,8 @@ pub fn parse_program_subcommand( let signer_info = default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?; + let compute_unit_price = value_of(matches, "compute_unit_price"); + CliCommandInfo { command: CliCommand::Program(ProgramCliCommand::WriteBuffer { program_location: matches.value_of("program_location").unwrap().to_string(), @@ -698,6 +709,7 @@ pub fn parse_program_subcommand( .unwrap(), max_len, skip_fee_check, + compute_unit_price, }), signers: signer_info.signers, } @@ -899,6 +911,7 @@ pub fn process_program_subcommand( max_len, allow_excessive_balance, skip_fee_check, + compute_unit_price, } => process_program_deploy( rpc_client, config, @@ -913,6 +926,7 @@ pub fn process_program_subcommand( *max_len, *allow_excessive_balance, *skip_fee_check, + *compute_unit_price, ), ProgramCliCommand::Upgrade { fee_payer_signer_index, @@ -941,6 +955,7 @@ pub fn process_program_subcommand( buffer_authority_signer_index, max_len, skip_fee_check, + compute_unit_price, } => process_write_buffer( rpc_client, config, @@ -951,6 +966,7 @@ pub fn process_program_subcommand( *buffer_authority_signer_index, *max_len, *skip_fee_check, + *compute_unit_price, ), ProgramCliCommand::SetBufferAuthority { buffer_pubkey, @@ -1091,6 +1107,7 @@ fn process_program_deploy( max_len: Option, allow_excessive_balance: bool, skip_fee_check: bool, + compute_unit_price: Option, ) -> ProcessResult { let fee_payer_signer = config.signers[fee_payer_signer_index]; let upgrade_authority_signer = config.signers[upgrade_authority_signer_index]; @@ -1230,6 +1247,7 @@ fn process_program_deploy( upgrade_authority_signer, allow_excessive_balance, skip_fee_check, + compute_unit_price, ) } else { do_process_program_upgrade( @@ -1244,6 +1262,7 @@ fn process_program_deploy( &buffer_pubkey, buffer_signer, skip_fee_check, + compute_unit_price, ) }; if result.is_ok() && is_final { @@ -1391,6 +1410,7 @@ fn process_write_buffer( buffer_authority_signer_index: SignerIndex, max_len: Option, skip_fee_check: bool, + compute_unit_price: Option, ) -> ProcessResult { let fee_payer_signer = config.signers[fee_payer_signer_index]; let buffer_authority = config.signers[buffer_authority_signer_index]; @@ -1456,6 +1476,7 @@ fn process_write_buffer( buffer_authority, true, skip_fee_check, + compute_unit_price, ); if result.is_err() && buffer_signer_index.is_none() && buffer_signer.is_some() { report_ephemeral_mnemonic(words, mnemonic); @@ -2209,11 +2230,12 @@ fn do_process_program_write_and_deploy( buffer_authority_signer: &dyn Signer, allow_excessive_balance: bool, skip_fee_check: bool, + compute_unit_price: Option, ) -> ProcessResult { let blockhash = rpc_client.get_latest_blockhash()?; // Initialize buffer account or complete if already partially initialized - let (initial_instructions, balance_needed) = if let Some(account) = rpc_client + let (ixs, balance_needed) = if let Some(account) = rpc_client .get_account_with_commitment(buffer_pubkey, config.commitment)? .value { @@ -2253,6 +2275,11 @@ fn do_process_program_write_and_deploy( min_rent_exempt_program_data_balance, ) }; + + let mut initial_instructions: Vec = Vec::new(); + + set_compute_budget_ixs_if_needed(&mut initial_instructions, &compute_unit_price); + initial_instructions.extend(ixs); let initial_message = if !initial_instructions.is_empty() { Some(Message::new_with_blockhash( &initial_instructions, @@ -2265,7 +2292,8 @@ fn do_process_program_write_and_deploy( // Create and add write messages let create_msg = |offset: u32, bytes: Vec| { - let instruction = if loader_id == &bpf_loader_upgradeable::id() { + let mut write_ixs: Vec = Vec::new(); + let ix_to_add = if loader_id == &bpf_loader_upgradeable::id() { bpf_loader_upgradeable::write( buffer_pubkey, &buffer_authority_signer.pubkey(), @@ -2275,7 +2303,10 @@ fn do_process_program_write_and_deploy( } else { loader_instruction::write(buffer_pubkey, loader_id, offset, bytes) }; - Message::new_with_blockhash(&[instruction], Some(&fee_payer_signer.pubkey()), &blockhash) + + set_compute_budget_ixs_if_needed(&mut write_ixs, &compute_unit_price); + write_ixs.push(ix_to_add); + Message::new_with_blockhash(&write_ixs, Some(&fee_payer_signer.pubkey()), &blockhash) }; let mut write_messages = vec![]; @@ -2286,27 +2317,28 @@ fn do_process_program_write_and_deploy( // Create and add final message let final_message = if let Some(program_signers) = program_signers { + let mut final_ixs: Vec = Vec::new(); + let message = if loader_id == &bpf_loader_upgradeable::id() { - Message::new_with_blockhash( - &bpf_loader_upgradeable::deploy_with_max_program_len( - &fee_payer_signer.pubkey(), - &program_signers[0].pubkey(), - buffer_pubkey, - &program_signers[1].pubkey(), - rpc_client.get_minimum_balance_for_rent_exemption( - UpgradeableLoaderState::size_of_program(), - )?, - program_data_max_len, + let ixs_to_add = bpf_loader_upgradeable::deploy_with_max_program_len( + &fee_payer_signer.pubkey(), + &program_signers[0].pubkey(), + buffer_pubkey, + &program_signers[1].pubkey(), + rpc_client.get_minimum_balance_for_rent_exemption( + UpgradeableLoaderState::size_of_program(), )?, - Some(&fee_payer_signer.pubkey()), - &blockhash, - ) + program_data_max_len, + )?; + + set_compute_budget_ixs_if_needed(&mut final_ixs, &compute_unit_price); + final_ixs.extend(ixs_to_add); + Message::new_with_blockhash(&final_ixs, Some(&fee_payer_signer.pubkey()), &blockhash) } else { - Message::new_with_blockhash( - &[loader_instruction::finalize(buffer_pubkey, loader_id)], - Some(&fee_payer_signer.pubkey()), - &blockhash, - ) + set_compute_budget_ixs_if_needed(&mut final_ixs, &compute_unit_price); + + final_ixs.push(loader_instruction::finalize(buffer_pubkey, loader_id)); + Message::new_with_blockhash(&final_ixs, Some(&fee_payer_signer.pubkey()), &blockhash) }; Some(message) } else { @@ -2364,87 +2396,95 @@ fn do_process_program_upgrade( buffer_pubkey: &Pubkey, buffer_signer: Option<&dyn Signer>, skip_fee_check: bool, + compute_unit_price: Option, ) -> ProcessResult { let blockhash = rpc_client.get_latest_blockhash()?; - let (initial_message, write_messages, balance_needed) = - if let Some(buffer_signer) = buffer_signer { - // Check Buffer account to see if partial initialization has occurred - let (initial_instructions, balance_needed) = if let Some(account) = rpc_client - .get_account_with_commitment(&buffer_signer.pubkey(), config.commitment)? - .value - { - complete_partial_program_init( - &bpf_loader_upgradeable::id(), + let (initial_message, write_messages, balance_needed) = if let Some(buffer_signer) = + buffer_signer + { + // Check Buffer account to see if partial initialization has occurred + let (ixs, balance_needed) = if let Some(account) = rpc_client + .get_account_with_commitment(&buffer_signer.pubkey(), config.commitment)? + .value + { + complete_partial_program_init( + &bpf_loader_upgradeable::id(), + &fee_payer_signer.pubkey(), + &buffer_signer.pubkey(), + &account, + UpgradeableLoaderState::size_of_buffer(program_len), + min_rent_exempt_program_data_balance, + true, + )? + } else { + ( + bpf_loader_upgradeable::create_buffer( &fee_payer_signer.pubkey(), - &buffer_signer.pubkey(), - &account, - UpgradeableLoaderState::size_of_buffer(program_len), - min_rent_exempt_program_data_balance, - true, - )? - } else { - ( - bpf_loader_upgradeable::create_buffer( - &fee_payer_signer.pubkey(), - buffer_pubkey, - &upgrade_authority.pubkey(), - min_rent_exempt_program_data_balance, - program_len, - )?, + buffer_pubkey, + &upgrade_authority.pubkey(), min_rent_exempt_program_data_balance, - ) - }; + program_len, + )?, + min_rent_exempt_program_data_balance, + ) + }; + let mut initial_instructions: Vec = Vec::new(); - let initial_message = if !initial_instructions.is_empty() { - Some(Message::new_with_blockhash( - &initial_instructions, - Some(&fee_payer_signer.pubkey()), - &blockhash, - )) - } else { - None - }; + set_compute_budget_ixs_if_needed(&mut initial_instructions, &compute_unit_price); + initial_instructions.extend(ixs); + let initial_message = if !initial_instructions.is_empty() { + Some(Message::new_with_blockhash( + &initial_instructions, + Some(&fee_payer_signer.pubkey()), + &blockhash, + )) + } else { + None + }; - let buffer_signer_pubkey = buffer_signer.pubkey(); - let upgrade_authority_pubkey = upgrade_authority.pubkey(); - let create_msg = |offset: u32, bytes: Vec| { - let instruction = bpf_loader_upgradeable::write( - &buffer_signer_pubkey, - &upgrade_authority_pubkey, - offset, - bytes, - ); - Message::new_with_blockhash( - &[instruction], - Some(&fee_payer_signer.pubkey()), - &blockhash, - ) - }; + let buffer_signer_pubkey = buffer_signer.pubkey(); + let upgrade_authority_pubkey = upgrade_authority.pubkey(); + let create_msg = |offset: u32, bytes: Vec| { + let mut write_ixs: Vec = Vec::new(); + let ix_to_add = bpf_loader_upgradeable::write( + &buffer_signer_pubkey, + &upgrade_authority_pubkey, + offset, + bytes, + ); - // Create and add write messages - let mut write_messages = vec![]; - let chunk_size = calculate_max_chunk_size(&create_msg); - for (chunk, i) in program_data.chunks(chunk_size).zip(0..) { - write_messages.push(create_msg((i * chunk_size) as u32, chunk.to_vec())); - } + set_compute_budget_ixs_if_needed(&mut write_ixs, &compute_unit_price); + write_ixs.push(ix_to_add); - (initial_message, write_messages, balance_needed) - } else { - (None, vec![], 0) + Message::new_with_blockhash(&write_ixs, Some(&fee_payer_signer.pubkey()), &blockhash) }; + // Create and add write messages + let mut write_messages = vec![]; + let chunk_size = calculate_max_chunk_size(&create_msg); + for (chunk, i) in program_data.chunks(chunk_size).zip(0..) { + write_messages.push(create_msg((i * chunk_size) as u32, chunk.to_vec())); + } + + (initial_message, write_messages, balance_needed) + } else { + (None, vec![], 0) + }; + // Create and add final message - let final_message = Message::new_with_blockhash( - &[bpf_loader_upgradeable::upgrade( - program_id, - buffer_pubkey, - &upgrade_authority.pubkey(), - &fee_payer_signer.pubkey(), - )], - Some(&fee_payer_signer.pubkey()), - &blockhash, - ); + let mut final_ixs: Vec = Vec::new(); + + set_compute_budget_ixs_if_needed(&mut final_ixs, &compute_unit_price); + + final_ixs.push(bpf_loader_upgradeable::upgrade( + program_id, + buffer_pubkey, + &upgrade_authority.pubkey(), + &fee_payer_signer.pubkey(), + )); + let final_message = + Message::new_with_blockhash(&final_ixs, Some(&fee_payer_signer.pubkey()), &blockhash); let final_message = Some(final_message); if !skip_fee_check { @@ -2640,6 +2680,7 @@ fn send_deploy_messages( .send_and_confirm_messages_with_spinner( write_messages, &[fee_payer_signer, write_signer], + ), ConnectionCache::Quic(cache) => { let tpu_client_fut = solana_client::nonblocking::tpu_client::TpuClient::new_with_connection_cache( @@ -2730,6 +2771,30 @@ fn report_ephemeral_mnemonic(words: usize, mnemonic: bip39::Mnemonic) { eprintln!("[BUFFER_ACCOUNT_ADDRESS] argument to `solana program close`.\n{divider}"); } +fn set_compute_budget_ixs_if_needed(ixs: &mut Vec, compute_unit_price: &Option) { + let mut compute_units_required_for_ixs: u32 = 0; + for ix in ixs.iter() { + if ix.program_id == bpf_loader_upgradeable::id() { + compute_units_required_for_ixs += 2370u32; + } else if ix.program_id == system_program::id() { + compute_units_required_for_ixs += 150u32; + } else { + compute_units_required_for_ixs += 2000u32; + } + } + + let compute_units_for_compute_budget_ixs = 300u32; + + if let Some(compute_unit_price) = compute_unit_price { + ixs.push(ComputeBudgetInstruction::set_compute_unit_limit( + compute_units_required_for_ixs + compute_units_for_compute_budget_ixs, + )); + ixs.push(ComputeBudgetInstruction::set_compute_unit_price( + *compute_unit_price, + )); + } +} + #[cfg(test)] mod tests { use { @@ -2788,6 +2853,7 @@ mod tests { max_len: None, allow_excessive_balance: false, skip_fee_check: false, + compute_unit_price: None }), signers: vec![Box::new(read_keypair_file(&keypair_file).unwrap())], } @@ -2816,6 +2882,7 @@ mod tests { max_len: Some(42), allow_excessive_balance: false, skip_fee_check: false, + compute_unit_price: None }), signers: vec![Box::new(read_keypair_file(&keypair_file).unwrap())], } @@ -2846,6 +2913,7 @@ mod tests { max_len: None, allow_excessive_balance: false, skip_fee_check: false, + compute_unit_price: None }), signers: vec![ Box::new(read_keypair_file(&keypair_file).unwrap()), @@ -2878,6 +2946,7 @@ mod tests { max_len: None, allow_excessive_balance: false, skip_fee_check: false, + compute_unit_price: None }), signers: vec![Box::new(read_keypair_file(&keypair_file).unwrap())], } @@ -2909,6 +2978,7 @@ mod tests { max_len: None, allow_excessive_balance: false, skip_fee_check: false, + compute_unit_price: None }), signers: vec![ Box::new(read_keypair_file(&keypair_file).unwrap()), @@ -2943,6 +3013,7 @@ mod tests { max_len: None, allow_excessive_balance: false, skip_fee_check: false, + compute_unit_price: None }), signers: vec![ Box::new(read_keypair_file(&keypair_file).unwrap()), @@ -2973,6 +3044,7 @@ mod tests { max_len: None, skip_fee_check: false, allow_excessive_balance: false, + compute_unit_price: None }), signers: vec![Box::new(read_keypair_file(&keypair_file).unwrap())], } @@ -3007,6 +3079,7 @@ mod tests { buffer_authority_signer_index: 0, max_len: None, skip_fee_check: false, + compute_unit_price: None }), signers: vec![Box::new(read_keypair_file(&keypair_file).unwrap())], } @@ -3032,6 +3105,7 @@ mod tests { buffer_authority_signer_index: 0, max_len: Some(42), skip_fee_check: false, + compute_unit_price: None }), signers: vec![Box::new(read_keypair_file(&keypair_file).unwrap())], } @@ -3060,6 +3134,7 @@ mod tests { buffer_authority_signer_index: 0, max_len: None, skip_fee_check: false, + compute_unit_price: None }), signers: vec![ Box::new(read_keypair_file(&keypair_file).unwrap()), @@ -3091,6 +3166,7 @@ mod tests { buffer_authority_signer_index: 1, max_len: None, skip_fee_check: false, + compute_unit_price: None }), signers: vec![ Box::new(read_keypair_file(&keypair_file).unwrap()), @@ -3127,6 +3203,7 @@ mod tests { buffer_authority_signer_index: 2, max_len: None, skip_fee_check: false, + compute_unit_price: None }), signers: vec![ Box::new(read_keypair_file(&keypair_file).unwrap()), @@ -3685,6 +3762,7 @@ mod tests { max_len: None, allow_excessive_balance: false, skip_fee_check: false, + compute_unit_price: None, }), signers: vec![&default_keypair], output_format: OutputFormat::JsonCompact, diff --git a/cli/tests/program.rs b/cli/tests/program.rs index 039df1d64b8ae8..80cc613636e6ff 100644 --- a/cli/tests/program.rs +++ b/cli/tests/program.rs @@ -21,6 +21,7 @@ use { feature_set::FeatureSet, pubkey::Pubkey, signature::{Keypair, NullSigner, Signer}, + signer::EncodableKey, }, solana_streamer::socket::SocketAddrSpace, solana_test_validator::TestValidator, @@ -30,6 +31,7 @@ use { io::Read, path::{Path, PathBuf}, str::FromStr, + time::Instant, }, test_case::test_case, }; @@ -87,6 +89,7 @@ fn test_cli_program_deploy_non_upgradeable() { is_final: true, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; let response = process_command(&config); @@ -136,6 +139,7 @@ fn test_cli_program_deploy_non_upgradeable() { is_final: true, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap(); let account1 = rpc_client @@ -194,6 +198,7 @@ fn test_cli_program_deploy_non_upgradeable() { is_final: true, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); let err = process_command(&config).unwrap_err(); assert_eq!( @@ -217,6 +222,7 @@ fn test_cli_program_deploy_non_upgradeable() { is_final: true, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap_err(); } @@ -278,6 +284,7 @@ fn test_cli_program_deploy_no_authority() { is_final: true, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; let response = process_command(&config); @@ -305,6 +312,7 @@ fn test_cli_program_deploy_no_authority() { is_final: false, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap_err(); } @@ -367,6 +375,7 @@ fn test_cli_program_deploy_with_authority() { is_final: false, max_len: Some(max_len), skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; let response = process_command(&config); @@ -419,6 +428,7 @@ fn test_cli_program_deploy_with_authority() { is_final: false, max_len: Some(max_len), skip_fee_check: false, + compute_unit_price: None, }); let response = process_command(&config); let json: Value = serde_json::from_str(&response.unwrap()).unwrap(); @@ -465,6 +475,7 @@ fn test_cli_program_deploy_with_authority() { is_final: false, max_len: Some(max_len), skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap(); let program_account = rpc_client.get_account(&program_pubkey).unwrap(); @@ -543,6 +554,7 @@ fn test_cli_program_deploy_with_authority() { is_final: false, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap(); let program_account = rpc_client.get_account(&program_pubkey).unwrap(); @@ -625,6 +637,7 @@ fn test_cli_program_deploy_with_authority() { is_final: false, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap_err(); @@ -642,6 +655,7 @@ fn test_cli_program_deploy_with_authority() { is_final: true, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); let response = process_command(&config); let json: Value = serde_json::from_str(&response.unwrap()).unwrap(); @@ -746,6 +760,7 @@ fn test_cli_program_close_program() { is_final: false, max_len: Some(max_len), skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; process_command(&config).unwrap(); @@ -856,6 +871,7 @@ fn test_cli_program_extend_program() { is_final: false, max_len: None, // Use None to check that it defaults to the max length skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; process_command(&config).unwrap(); @@ -903,6 +919,7 @@ fn test_cli_program_extend_program() { is_final: false, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap_err(); @@ -935,6 +952,7 @@ fn test_cli_program_extend_program() { is_final: false, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap(); } @@ -999,6 +1017,8 @@ fn test_cli_program_write_buffer() { buffer_authority_signer_index: 0, max_len: None, skip_fee_check: false, + + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; let response = process_command(&config); @@ -1035,6 +1055,8 @@ fn test_cli_program_write_buffer() { buffer_authority_signer_index: 0, max_len: Some(max_len), skip_fee_check: false, + + compute_unit_price: None, }); let response = process_command(&config); let json: Value = serde_json::from_str(&response.unwrap()).unwrap(); @@ -1098,6 +1120,8 @@ fn test_cli_program_write_buffer() { buffer_authority_signer_index: 2, max_len: None, skip_fee_check: false, + + compute_unit_price: None, }); let response = process_command(&config); let json: Value = serde_json::from_str(&response.unwrap()).unwrap(); @@ -1137,6 +1161,8 @@ fn test_cli_program_write_buffer() { buffer_authority_signer_index: 2, max_len: None, skip_fee_check: false, + + compute_unit_price: None, }); let response = process_command(&config); let json: Value = serde_json::from_str(&response.unwrap()).unwrap(); @@ -1212,6 +1238,8 @@ fn test_cli_program_write_buffer() { buffer_authority_signer_index: 0, max_len: None, skip_fee_check: false, + + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; let response = process_command(&config); @@ -1254,6 +1282,8 @@ fn test_cli_program_write_buffer() { buffer_authority_signer_index: 0, max_len: None, //Some(max_len), skip_fee_check: false, + + compute_unit_price: None, }); process_command(&config).unwrap(); config.signers = vec![&keypair, &buffer_keypair]; @@ -1269,6 +1299,7 @@ fn test_cli_program_write_buffer() { is_final: true, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; let error = process_command(&config).unwrap_err(); @@ -1328,6 +1359,8 @@ fn test_cli_program_set_buffer_authority() { buffer_authority_signer_index: 0, max_len: None, skip_fee_check: false, + + compute_unit_price: None, }); process_command(&config).unwrap(); let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap(); @@ -1380,6 +1413,7 @@ fn test_cli_program_set_buffer_authority() { is_final: false, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; process_command(&config).unwrap_err(); @@ -1425,6 +1459,7 @@ fn test_cli_program_set_buffer_authority() { is_final: false, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; process_command(&config).unwrap(); @@ -1481,6 +1516,8 @@ fn test_cli_program_mismatch_buffer_authority() { buffer_authority_signer_index: 2, max_len: None, skip_fee_check: false, + + compute_unit_price: None, }); process_command(&config).unwrap(); let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap(); @@ -1505,6 +1542,7 @@ fn test_cli_program_mismatch_buffer_authority() { is_final: true, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap_err(); @@ -1522,6 +1560,7 @@ fn test_cli_program_mismatch_buffer_authority() { is_final: true, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(&config).unwrap(); } @@ -1605,6 +1644,7 @@ fn test_cli_program_deploy_with_offline_signing(use_offline_signer_as_fee_payer: is_final: false, max_len: Some(max_program_data_len), // allows for larger program size with future upgrades skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; process_command(&config).unwrap(); @@ -1772,6 +1812,8 @@ fn test_cli_program_show() { buffer_authority_signer_index: 2, max_len: None, skip_fee_check: false, + + compute_unit_price: None, }); process_command(&config).unwrap(); @@ -1833,6 +1875,7 @@ fn test_cli_program_show() { is_final: false, max_len: Some(max_len), skip_fee_check: false, + compute_unit_price: None, }); config.output_format = OutputFormat::JsonCompact; let min_slot = rpc_client.get_slot().unwrap(); @@ -1961,6 +2004,8 @@ fn test_cli_program_dump() { buffer_authority_signer_index: 2, max_len: None, skip_fee_check: false, + + compute_unit_price: None, }); process_command(&config).unwrap(); @@ -2004,6 +2049,7 @@ fn create_buffer_with_offline_authority<'a>( buffer_authority_signer_index: 0, max_len: None, skip_fee_check: false, + compute_unit_price: None, }); process_command(config).unwrap(); let buffer_account = rpc_client.get_account(&buffer_signer.pubkey()).unwrap(); @@ -2029,3 +2075,69 @@ fn create_buffer_with_offline_authority<'a>( panic!("not a buffer account"); } } + +fn program_deploy_with_args(compute_unit_price: Option) { + solana_logger::setup(); + + let mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + noop_path.push("tests"); + noop_path.push("fixtures"); + noop_path.push("noop"); + noop_path.set_extension("so"); + + let mut file = File::open(noop_path.to_str().unwrap()).unwrap(); + let mut program_data = Vec::new(); + file.read_to_end(&mut program_data).unwrap(); + + let mut config = CliConfig::recent_for_tests(); + let keypair = Keypair::read_from_file(&config.keypair_path).unwrap(); + + let upgrade_authority = Keypair::new(); + + config.json_rpc_url = "https://api.devnet.solana.com".to_string(); + + config.signers = vec![&keypair]; + + // Deploy a program + config.signers = vec![&keypair, &upgrade_authority]; + config.command = CliCommand::Program(ProgramCliCommand::Deploy { + program_location: Some(noop_path.to_str().unwrap().to_string()), + fee_payer_signer_index: 0, + program_signer_index: None, + program_pubkey: None, + buffer_signer_index: None, + buffer_pubkey: None, + allow_excessive_balance: false, + upgrade_authority_signer_index: 1, + is_final: true, + max_len: None, + skip_fee_check: false, + compute_unit_price, + }); + config.output_format = OutputFormat::JsonCompact; + let start = Instant::now(); + let response = process_command(&config); + let duration = start.elapsed(); + println!("Time elapsed: {:?}", duration); + let json: Value = serde_json::from_str(&response.unwrap()).unwrap(); + let program_pubkey_str = json + .as_object() + .unwrap() + .get("programId") + .unwrap() + .as_str() + .unwrap(); + println!( + "Program deployed successfully with id: {}", + program_pubkey_str + ); +} + +#[test] +fn test_cli_program_deploy_with_compute_unit_price() { + //test without compute_unit_price + program_deploy_with_args(None); + + //test with 1000 micro lamports as compute_unit_price + program_deploy_with_args(Some(1000)); +} diff --git a/transaction-dos/src/main.rs b/transaction-dos/src/main.rs index dedbcdab27ef79..bb3a4d8052e0ca 100644 --- a/transaction-dos/src/main.rs +++ b/transaction-dos/src/main.rs @@ -248,6 +248,7 @@ fn run_transactions_dos( is_final: true, max_len: None, skip_fee_check: true, // skip_fee_check + compute_unit_price: None, }); process_command(&config).expect("deploy didn't pass");