Implement CLI front-end for loader-v4 commands (#33289)
* Implement CLI front-end for loader-v4 commands * remove dead_code clippy overrides * Add unit tests
This commit is contained in:
parent
bc38ef27d8
commit
62888d297a
|
@ -1,7 +1,8 @@
|
|||
use {
|
||||
crate::{
|
||||
address_lookup_table::AddressLookupTableSubCommands, cli::*, cluster_query::*, feature::*,
|
||||
inflation::*, nonce::*, program::*, stake::*, validator_info::*, vote::*, wallet::*,
|
||||
inflation::*, nonce::*, program::*, program_v4::ProgramV4SubCommands, stake::*,
|
||||
validator_info::*, vote::*, wallet::*,
|
||||
},
|
||||
clap::{App, AppSettings, Arg, ArgGroup, SubCommand},
|
||||
solana_clap_utils::{self, hidden_unless_forced, input_validators::*, keypair::*},
|
||||
|
@ -143,6 +144,7 @@ pub fn get_clap_app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> A
|
|||
.inflation_subcommands()
|
||||
.nonce_subcommands()
|
||||
.program_subcommands()
|
||||
.program_v4_subcommands()
|
||||
.address_lookup_table_subcommands()
|
||||
.stake_subcommands()
|
||||
.validator_info_subcommands()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
address_lookup_table::*, clap_app::*, cluster_query::*, feature::*, inflation::*, nonce::*,
|
||||
program::*, spend_utils::*, stake::*, validator_info::*, vote::*, wallet::*,
|
||||
program::*, program_v4::*, spend_utils::*, stake::*, validator_info::*, vote::*, wallet::*,
|
||||
},
|
||||
clap::{crate_description, crate_name, value_t_or_exit, ArgMatches, Shell},
|
||||
log::*,
|
||||
|
@ -175,6 +175,7 @@ pub enum CliCommand {
|
|||
// Program Deployment
|
||||
Deploy,
|
||||
Program(ProgramCliCommand),
|
||||
ProgramV4(ProgramV4CliCommand),
|
||||
// Stake Commands
|
||||
CreateStakeAccount {
|
||||
stake_account: SignerIndex,
|
||||
|
@ -687,6 +688,9 @@ pub fn parse_command(
|
|||
("program", Some(matches)) => {
|
||||
parse_program_subcommand(matches, default_signer, wallet_manager)
|
||||
}
|
||||
("program-v4", Some(matches)) => {
|
||||
parse_program_v4_subcommand(matches, default_signer, wallet_manager)
|
||||
}
|
||||
("address-lookup-table", Some(matches)) => {
|
||||
parse_address_lookup_table_subcommand(matches, default_signer, wallet_manager)
|
||||
}
|
||||
|
@ -1103,6 +1107,11 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||
process_program_subcommand(rpc_client, config, program_subcommand)
|
||||
}
|
||||
|
||||
// Deploy a custom program v4 to the chain
|
||||
CliCommand::ProgramV4(program_subcommand) => {
|
||||
process_program_v4_subcommand(rpc_client, config, program_subcommand)
|
||||
}
|
||||
|
||||
// Stake Commands
|
||||
|
||||
// Create stake account
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
use {
|
||||
crate::{
|
||||
checks::*,
|
||||
cli::{log_instruction_custom_error, CliConfig, ProcessResult},
|
||||
cli::{
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||
ProcessResult,
|
||||
},
|
||||
program::calculate_max_chunk_size,
|
||||
},
|
||||
clap::{App, AppSettings, Arg, ArgMatches, SubCommand},
|
||||
log::*,
|
||||
solana_clap_utils::{
|
||||
input_parsers::{pubkey_of, pubkey_of_signer, signer_of},
|
||||
input_validators::is_valid_signer,
|
||||
keypair::{DefaultSigner, SignerIndex},
|
||||
},
|
||||
solana_cli_output::CliProgramId,
|
||||
solana_client::{
|
||||
connection_cache::ConnectionCache,
|
||||
|
@ -13,6 +22,9 @@ use {
|
|||
},
|
||||
tpu_client::{TpuClient, TpuClientConfig},
|
||||
},
|
||||
solana_program_runtime::{compute_budget::ComputeBudget, invoke_context::InvokeContext},
|
||||
solana_rbpf::{elf::Executable, verifier::RequisiteVerifier},
|
||||
solana_remote_wallet::remote_wallet::RemoteWalletManager,
|
||||
solana_rpc_client::rpc_client::RpcClient,
|
||||
solana_rpc_client_api::config::RpcSendTransactionConfig,
|
||||
solana_sdk::{
|
||||
|
@ -29,9 +41,364 @@ use {
|
|||
system_instruction::{self, SystemError},
|
||||
transaction::Transaction,
|
||||
},
|
||||
std::{cmp::Ordering, sync::Arc},
|
||||
std::{cmp::Ordering, fs::File, io::Read, rc::Rc, sync::Arc},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ProgramV4CliCommand {
|
||||
Deploy {
|
||||
program_location: String,
|
||||
program_signer_index: SignerIndex,
|
||||
authority_signer_index: SignerIndex,
|
||||
},
|
||||
Redeploy {
|
||||
program_location: String,
|
||||
program_address: Pubkey,
|
||||
buffer_signer_index: Option<SignerIndex>,
|
||||
authority_signer_index: SignerIndex,
|
||||
},
|
||||
Undeploy {
|
||||
program_address: Pubkey,
|
||||
authority_signer_index: SignerIndex,
|
||||
},
|
||||
Finalize {
|
||||
program_address: Pubkey,
|
||||
authority_signer_index: SignerIndex,
|
||||
},
|
||||
}
|
||||
|
||||
pub trait ProgramV4SubCommands {
|
||||
fn program_v4_subcommands(self) -> Self;
|
||||
}
|
||||
|
||||
impl ProgramV4SubCommands for App<'_, '_> {
|
||||
fn program_v4_subcommands(self) -> Self {
|
||||
self.subcommand(
|
||||
SubCommand::with_name("program-v4")
|
||||
.about("Program V4 management")
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.subcommand(
|
||||
SubCommand::with_name("deploy")
|
||||
.about("Deploy a program")
|
||||
.arg(
|
||||
Arg::with_name("program_location")
|
||||
.index(1)
|
||||
.value_name("PROGRAM_FILEPATH")
|
||||
.takes_value(true)
|
||||
.help("/path/to/program.so"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("program")
|
||||
.long("program")
|
||||
.value_name("PROGRAM_SIGNER")
|
||||
.takes_value(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Program account signer. The program data is written to the associated account.")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authority")
|
||||
.long("authority")
|
||||
.value_name("AUTHORITY_SIGNER")
|
||||
.takes_value(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Program authority [default: the default configured keypair]")
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("redeploy")
|
||||
.about("Redeploy a previously deployed program")
|
||||
.arg(
|
||||
Arg::with_name("program_location")
|
||||
.index(1)
|
||||
.value_name("PROGRAM_FILEPATH")
|
||||
.takes_value(true)
|
||||
.help("/path/to/program.so"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("program-id")
|
||||
.long("program-id")
|
||||
.value_name("PROGRAM_ID")
|
||||
.takes_value(true)
|
||||
.help("Executable program's address")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("buffer")
|
||||
.long("buffer")
|
||||
.value_name("BUFFER_SIGNER")
|
||||
.takes_value(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Optional intermediate buffer account to write data to, which can be used to resume a failed deploy")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authority")
|
||||
.long("authority")
|
||||
.value_name("AUTHORITY_SIGNER")
|
||||
.takes_value(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Program authority [default: the default configured keypair]")
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("undeploy")
|
||||
.about("Undeploy/close a program")
|
||||
.arg(
|
||||
Arg::with_name("program-id")
|
||||
.long("program-id")
|
||||
.value_name("PROGRAM_ID")
|
||||
.takes_value(true)
|
||||
.help("Executable program's address")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authority")
|
||||
.long("authority")
|
||||
.value_name("AUTHORITY_SIGNER")
|
||||
.takes_value(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Program authority [default: the default configured keypair]")
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("finalize")
|
||||
.about("Finalize a program to make it immutable")
|
||||
.arg(
|
||||
Arg::with_name("program-id")
|
||||
.long("program-id")
|
||||
.value_name("PROGRAM_ID")
|
||||
.takes_value(true)
|
||||
.help("Executable program's address")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authority")
|
||||
.long("authority")
|
||||
.value_name("AUTHORITY_SIGNER")
|
||||
.takes_value(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Program authority [default: the default configured keypair]")
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_program_v4_subcommand(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer: &DefaultSigner,
|
||||
wallet_manager: &mut Option<Rc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let (subcommand, sub_matches) = matches.subcommand();
|
||||
let response = match (subcommand, sub_matches) {
|
||||
("deploy", Some(matches)) => {
|
||||
let mut bulk_signers = vec![Some(
|
||||
default_signer.signer_from_path(matches, wallet_manager)?,
|
||||
)];
|
||||
|
||||
let program_location = matches
|
||||
.value_of("program_location")
|
||||
.map(|location| location.to_string());
|
||||
|
||||
let program_pubkey = if let Ok((program_signer, Some(program_pubkey))) =
|
||||
signer_of(matches, "program", wallet_manager)
|
||||
{
|
||||
bulk_signers.push(program_signer);
|
||||
Some(program_pubkey)
|
||||
} else {
|
||||
pubkey_of_signer(matches, "program", wallet_manager)?
|
||||
};
|
||||
|
||||
let (authority, authority_pubkey) = signer_of(matches, "authority", wallet_manager)?;
|
||||
bulk_signers.push(authority);
|
||||
|
||||
let signer_info =
|
||||
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
||||
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ProgramV4(ProgramV4CliCommand::Deploy {
|
||||
program_location: program_location.expect("Program location is missing"),
|
||||
program_signer_index: signer_info
|
||||
.index_of(program_pubkey)
|
||||
.expect("Program signer is missing"),
|
||||
authority_signer_index: signer_info
|
||||
.index_of(authority_pubkey)
|
||||
.expect("Authority signer is missing"),
|
||||
}),
|
||||
signers: signer_info.signers,
|
||||
}
|
||||
}
|
||||
("redeploy", Some(matches)) => {
|
||||
let mut bulk_signers = vec![Some(
|
||||
default_signer.signer_from_path(matches, wallet_manager)?,
|
||||
)];
|
||||
|
||||
let program_location = matches
|
||||
.value_of("program_location")
|
||||
.map(|location| location.to_string());
|
||||
|
||||
let buffer_pubkey = if let Ok((buffer_signer, Some(buffer_pubkey))) =
|
||||
signer_of(matches, "buffer", wallet_manager)
|
||||
{
|
||||
bulk_signers.push(buffer_signer);
|
||||
Some(buffer_pubkey)
|
||||
} else {
|
||||
pubkey_of_signer(matches, "buffer", wallet_manager)?
|
||||
};
|
||||
|
||||
let (authority, authority_pubkey) = signer_of(matches, "authority", wallet_manager)?;
|
||||
bulk_signers.push(authority);
|
||||
|
||||
let signer_info =
|
||||
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
||||
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ProgramV4(ProgramV4CliCommand::Redeploy {
|
||||
program_location: program_location.expect("Program location is missing"),
|
||||
program_address: pubkey_of(matches, "program-id")
|
||||
.expect("Program address is missing"),
|
||||
buffer_signer_index: signer_info.index_of_or_none(buffer_pubkey),
|
||||
authority_signer_index: signer_info
|
||||
.index_of(authority_pubkey)
|
||||
.expect("Authority signer is missing"),
|
||||
}),
|
||||
signers: signer_info.signers,
|
||||
}
|
||||
}
|
||||
("undeploy", Some(matches)) => {
|
||||
let mut bulk_signers = vec![Some(
|
||||
default_signer.signer_from_path(matches, wallet_manager)?,
|
||||
)];
|
||||
|
||||
let (authority, authority_pubkey) = signer_of(matches, "authority", wallet_manager)?;
|
||||
bulk_signers.push(authority);
|
||||
|
||||
let signer_info =
|
||||
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
||||
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ProgramV4(ProgramV4CliCommand::Undeploy {
|
||||
program_address: pubkey_of(matches, "program-id")
|
||||
.expect("Program address is missing"),
|
||||
authority_signer_index: signer_info
|
||||
.index_of(authority_pubkey)
|
||||
.expect("Authority signer is missing"),
|
||||
}),
|
||||
signers: signer_info.signers,
|
||||
}
|
||||
}
|
||||
("finalize", Some(matches)) => {
|
||||
let mut bulk_signers = vec![Some(
|
||||
default_signer.signer_from_path(matches, wallet_manager)?,
|
||||
)];
|
||||
|
||||
let (authority, authority_pubkey) = signer_of(matches, "authority", wallet_manager)?;
|
||||
bulk_signers.push(authority);
|
||||
|
||||
let signer_info =
|
||||
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
||||
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ProgramV4(ProgramV4CliCommand::Finalize {
|
||||
program_address: pubkey_of(matches, "program-id")
|
||||
.expect("Program address is missing"),
|
||||
authority_signer_index: signer_info
|
||||
.index_of(authority_pubkey)
|
||||
.expect("Authority signer is missing"),
|
||||
}),
|
||||
signers: signer_info.signers,
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
fn read_and_verify_elf(program_location: &str) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
let mut file = File::open(program_location)
|
||||
.map_err(|err| format!("Unable to open program file: {err}"))?;
|
||||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data)
|
||||
.map_err(|err| format!("Unable to read program file: {err}"))?;
|
||||
|
||||
// Verify the program
|
||||
let program_runtime_environment =
|
||||
solana_loader_v4_program::create_program_runtime_environment_v2(
|
||||
&ComputeBudget::default(),
|
||||
false,
|
||||
);
|
||||
let executable =
|
||||
Executable::<InvokeContext>::from_elf(&program_data, Arc::new(program_runtime_environment))
|
||||
.map_err(|err| format!("ELF error: {err}"))?;
|
||||
|
||||
executable
|
||||
.verify::<RequisiteVerifier>()
|
||||
.map_err(|err| format!("ELF error: {err}"))?;
|
||||
|
||||
Ok(program_data)
|
||||
}
|
||||
|
||||
pub fn process_program_v4_subcommand(
|
||||
rpc_client: Arc<RpcClient>,
|
||||
config: &CliConfig,
|
||||
program_subcommand: &ProgramV4CliCommand,
|
||||
) -> ProcessResult {
|
||||
match program_subcommand {
|
||||
ProgramV4CliCommand::Deploy {
|
||||
program_location,
|
||||
program_signer_index,
|
||||
authority_signer_index,
|
||||
} => {
|
||||
let program_data = read_and_verify_elf(program_location)?;
|
||||
let program_len = program_data.len() as u32;
|
||||
|
||||
process_deploy_program(
|
||||
rpc_client,
|
||||
config,
|
||||
&program_data,
|
||||
program_len,
|
||||
&config.signers[*program_signer_index].pubkey(),
|
||||
Some(config.signers[*program_signer_index]),
|
||||
config.signers[*authority_signer_index],
|
||||
)
|
||||
}
|
||||
ProgramV4CliCommand::Redeploy {
|
||||
program_location,
|
||||
program_address,
|
||||
buffer_signer_index,
|
||||
authority_signer_index,
|
||||
} => {
|
||||
let program_data = read_and_verify_elf(program_location)?;
|
||||
let program_len = program_data.len() as u32;
|
||||
let buffer_signer = buffer_signer_index.map(|index| config.signers[index]);
|
||||
|
||||
process_deploy_program(
|
||||
rpc_client,
|
||||
config,
|
||||
&program_data,
|
||||
program_len,
|
||||
program_address,
|
||||
buffer_signer,
|
||||
config.signers[*authority_signer_index],
|
||||
)
|
||||
}
|
||||
ProgramV4CliCommand::Undeploy {
|
||||
program_address,
|
||||
authority_signer_index,
|
||||
} => process_undeploy_program(
|
||||
rpc_client,
|
||||
config,
|
||||
program_address,
|
||||
config.signers[*authority_signer_index],
|
||||
),
|
||||
ProgramV4CliCommand::Finalize {
|
||||
program_address,
|
||||
authority_signer_index,
|
||||
} => process_finalize_program(
|
||||
rpc_client,
|
||||
config,
|
||||
program_address,
|
||||
config.signers[*authority_signer_index],
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// This function can be used for the following use-cases
|
||||
// * Deploy a program
|
||||
// - buffer_signer argument must contain program signer information
|
||||
|
@ -41,7 +408,6 @@ use {
|
|||
// * Redeploy a program using a buffer account
|
||||
// - buffer_signer argument must contain the temporary buffer account information
|
||||
// (program_address must contain program ID and must NOT be same as buffer_signer.pubkey())
|
||||
#[allow(dead_code)]
|
||||
fn process_deploy_program(
|
||||
rpc_client: Arc<RpcClient>,
|
||||
config: &CliConfig,
|
||||
|
@ -142,7 +508,6 @@ fn process_deploy_program(
|
|||
Ok(config.output_format.formatted_string(&program_id))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn process_undeploy_program(
|
||||
rpc_client: Arc<RpcClient>,
|
||||
config: &CliConfig,
|
||||
|
@ -206,7 +571,6 @@ fn process_undeploy_program(
|
|||
Ok(config.output_format.formatted_string(&program_id))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn process_finalize_program(
|
||||
rpc_client: Arc<RpcClient>,
|
||||
config: &CliConfig,
|
||||
|
@ -243,7 +607,6 @@ fn process_finalize_program(
|
|||
Ok(config.output_format.formatted_string(&program_id))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn check_payer(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
|
@ -275,7 +638,6 @@ fn check_payer(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn send_messages(
|
||||
rpc_client: Arc<RpcClient>,
|
||||
config: &CliConfig,
|
||||
|
@ -394,7 +756,6 @@ fn send_messages(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn build_create_buffer_message(
|
||||
rpc_client: Arc<RpcClient>,
|
||||
config: &CliConfig,
|
||||
|
@ -563,7 +924,6 @@ fn build_retract_and_deploy_messages(
|
|||
Ok(messages)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn build_retract_instruction(
|
||||
account: &Account,
|
||||
buffer_address: &Pubkey,
|
||||
|
@ -595,7 +955,6 @@ fn build_retract_instruction(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn build_truncate_instructions(
|
||||
rpc_client: Arc<RpcClient>,
|
||||
payer: &Pubkey,
|
||||
|
@ -677,12 +1036,15 @@ fn build_truncate_instructions(
|
|||
mod tests {
|
||||
use {
|
||||
super::*,
|
||||
crate::{clap_app::get_clap_app, cli::parse_command},
|
||||
serde_json::json,
|
||||
solana_rpc_client_api::{
|
||||
request::RpcRequest,
|
||||
response::{Response, RpcResponseContext},
|
||||
},
|
||||
solana_sdk::signature::keypair_from_seed,
|
||||
solana_sdk::signature::{
|
||||
keypair_from_seed, read_keypair_file, write_keypair_file, Keypair,
|
||||
},
|
||||
std::collections::HashMap,
|
||||
};
|
||||
|
||||
|
@ -1001,4 +1363,225 @@ mod tests {
|
|||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
fn make_tmp_path(name: &str) -> String {
|
||||
let out_dir = std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string());
|
||||
let keypair = Keypair::new();
|
||||
|
||||
let path = format!("{}/tmp/{}-{}", out_dir, name, keypair.pubkey());
|
||||
|
||||
// whack any possible collision
|
||||
let _ignored = std::fs::remove_dir_all(&path);
|
||||
// whack any possible collision
|
||||
let _ignored = std::fs::remove_file(&path);
|
||||
|
||||
path
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn test_cli_parse_deploy() {
|
||||
let test_commands = get_clap_app("test", "desc", "version");
|
||||
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
|
||||
let program_keypair = Keypair::new();
|
||||
let program_keypair_file = make_tmp_path("program_keypair_file");
|
||||
write_keypair_file(&program_keypair, &program_keypair_file).unwrap();
|
||||
|
||||
let authority_keypair = Keypair::new();
|
||||
let authority_keypair_file = make_tmp_path("authority_keypair_file");
|
||||
write_keypair_file(&authority_keypair, &authority_keypair_file).unwrap();
|
||||
|
||||
let test_command = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"program-v4",
|
||||
"deploy",
|
||||
"/Users/test/program.so",
|
||||
"--program",
|
||||
&program_keypair_file,
|
||||
"--authority",
|
||||
&authority_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_command, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ProgramV4(ProgramV4CliCommand::Deploy {
|
||||
program_location: "/Users/test/program.so".to_string(),
|
||||
program_signer_index: 1,
|
||||
authority_signer_index: 2,
|
||||
}),
|
||||
signers: vec![
|
||||
read_keypair_file(&keypair_file).unwrap().into(),
|
||||
read_keypair_file(&program_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn test_cli_parse_redeploy() {
|
||||
let test_commands = get_clap_app("test", "desc", "version");
|
||||
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
|
||||
let program_keypair = Keypair::new();
|
||||
let program_keypair_file = make_tmp_path("program_keypair_file");
|
||||
write_keypair_file(&program_keypair, &program_keypair_file).unwrap();
|
||||
|
||||
let authority_keypair = Keypair::new();
|
||||
let authority_keypair_file = make_tmp_path("authority_keypair_file");
|
||||
write_keypair_file(&authority_keypair, &authority_keypair_file).unwrap();
|
||||
|
||||
let test_command = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"program-v4",
|
||||
"redeploy",
|
||||
"/Users/test/program.so",
|
||||
"--program-id",
|
||||
&program_keypair_file,
|
||||
"--authority",
|
||||
&authority_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_command, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ProgramV4(ProgramV4CliCommand::Redeploy {
|
||||
program_location: "/Users/test/program.so".to_string(),
|
||||
program_address: program_keypair.pubkey(),
|
||||
authority_signer_index: 1,
|
||||
buffer_signer_index: None,
|
||||
}),
|
||||
signers: vec![
|
||||
read_keypair_file(&keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
let buffer_keypair = Keypair::new();
|
||||
let buffer_keypair_file = make_tmp_path("buffer_keypair_file");
|
||||
write_keypair_file(&buffer_keypair, &buffer_keypair_file).unwrap();
|
||||
|
||||
let test_command = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"program-v4",
|
||||
"redeploy",
|
||||
"/Users/test/program.so",
|
||||
"--program-id",
|
||||
&program_keypair_file,
|
||||
"--buffer",
|
||||
&buffer_keypair_file,
|
||||
"--authority",
|
||||
&authority_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_command, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ProgramV4(ProgramV4CliCommand::Redeploy {
|
||||
program_location: "/Users/test/program.so".to_string(),
|
||||
program_address: program_keypair.pubkey(),
|
||||
buffer_signer_index: Some(1),
|
||||
authority_signer_index: 2,
|
||||
}),
|
||||
signers: vec![
|
||||
read_keypair_file(&keypair_file).unwrap().into(),
|
||||
read_keypair_file(&buffer_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn test_cli_parse_undeploy() {
|
||||
let test_commands = get_clap_app("test", "desc", "version");
|
||||
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
|
||||
let program_keypair = Keypair::new();
|
||||
let program_keypair_file = make_tmp_path("program_keypair_file");
|
||||
write_keypair_file(&program_keypair, &program_keypair_file).unwrap();
|
||||
|
||||
let authority_keypair = Keypair::new();
|
||||
let authority_keypair_file = make_tmp_path("authority_keypair_file");
|
||||
write_keypair_file(&authority_keypair, &authority_keypair_file).unwrap();
|
||||
|
||||
let test_command = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"program-v4",
|
||||
"undeploy",
|
||||
"--program-id",
|
||||
&program_keypair_file,
|
||||
"--authority",
|
||||
&authority_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_command, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ProgramV4(ProgramV4CliCommand::Undeploy {
|
||||
program_address: program_keypair.pubkey(),
|
||||
authority_signer_index: 1,
|
||||
}),
|
||||
signers: vec![
|
||||
read_keypair_file(&keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn test_cli_parse_finalize() {
|
||||
let test_commands = get_clap_app("test", "desc", "version");
|
||||
|
||||
let default_keypair = Keypair::new();
|
||||
let keypair_file = make_tmp_path("keypair_file");
|
||||
write_keypair_file(&default_keypair, &keypair_file).unwrap();
|
||||
let default_signer = DefaultSigner::new("", &keypair_file);
|
||||
|
||||
let program_keypair = Keypair::new();
|
||||
let program_keypair_file = make_tmp_path("program_keypair_file");
|
||||
write_keypair_file(&program_keypair, &program_keypair_file).unwrap();
|
||||
|
||||
let authority_keypair = Keypair::new();
|
||||
let authority_keypair_file = make_tmp_path("authority_keypair_file");
|
||||
write_keypair_file(&authority_keypair, &authority_keypair_file).unwrap();
|
||||
|
||||
let test_command = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"program-v4",
|
||||
"finalize",
|
||||
"--program-id",
|
||||
&program_keypair_file,
|
||||
"--authority",
|
||||
&authority_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_command, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ProgramV4(ProgramV4CliCommand::Finalize {
|
||||
program_address: program_keypair.pubkey(),
|
||||
authority_signer_index: 1,
|
||||
}),
|
||||
signers: vec![
|
||||
read_keypair_file(&keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue