2021-12-03 09:00:31 -08:00
use {
crate ::{
checks ::* ,
cli ::{
log_instruction_custom_error , CliCommand , CliCommandInfo , CliConfig , CliError ,
ProcessResult ,
} ,
} ,
bip39 ::{ Language , Mnemonic , MnemonicType , Seed } ,
clap ::{ App , AppSettings , Arg , ArgMatches , SubCommand } ,
log ::* ,
solana_account_decoder ::{ UiAccountEncoding , UiDataSliceConfig } ,
2022-12-11 23:47:09 -08:00
solana_bpf_loader_program ::syscalls ::create_loader ,
2021-12-03 09:00:31 -08:00
solana_clap_utils ::{ self , input_parsers ::* , input_validators ::* , keypair ::* } ,
solana_cli_output ::{
CliProgram , CliProgramAccountType , CliProgramAuthority , CliProgramBuffer , CliProgramId ,
CliUpgradeableBuffer , CliUpgradeableBuffers , CliUpgradeableProgram ,
CliUpgradeableProgramClosed , CliUpgradeablePrograms ,
} ,
2022-11-18 11:21:45 -08:00
solana_client ::{
connection_cache ::ConnectionCache ,
tpu_client ::{ TpuClient , TpuClientConfig } ,
} ,
2022-12-11 23:47:09 -08:00
solana_program_runtime ::{ compute_budget ::ComputeBudget , invoke_context ::InvokeContext } ,
solana_rbpf ::{ elf ::Executable , verifier ::RequisiteVerifier , vm ::VerifiedExecutable } ,
2021-12-03 09:00:31 -08:00
solana_remote_wallet ::remote_wallet ::RemoteWalletManager ,
2022-08-24 09:47:02 -07:00
solana_rpc_client ::rpc_client ::RpcClient ,
solana_rpc_client_api ::{
client_error ::ErrorKind as ClientErrorKind ,
config ::{ RpcAccountInfoConfig , RpcProgramAccountsConfig , RpcSendTransactionConfig } ,
filter ::{ Memcmp , RpcFilterType } ,
} ,
2021-12-03 09:00:31 -08:00
solana_sdk ::{
account ::Account ,
account_utils ::StateMut ,
bpf_loader , bpf_loader_deprecated ,
bpf_loader_upgradeable ::{ self , UpgradeableLoaderState } ,
instruction ::{ Instruction , InstructionError } ,
loader_instruction ,
message ::Message ,
native_token ::Sol ,
packet ::PACKET_DATA_SIZE ,
pubkey ::Pubkey ,
signature ::{ keypair_from_seed , read_keypair_file , Keypair , Signature , Signer } ,
system_instruction ::{ self , SystemError } ,
system_program ,
2022-07-15 00:31:34 -07:00
sysvar ::rent ::Rent ,
2021-12-03 09:00:31 -08:00
transaction ::{ Transaction , TransactionError } ,
2021-12-27 09:49:32 -08:00
transaction_context ::TransactionContext ,
2021-12-03 09:00:31 -08:00
} ,
std ::{
fs ::File ,
io ::{ Read , Write } ,
mem ::size_of ,
path ::PathBuf ,
str ::FromStr ,
sync ::Arc ,
2020-12-21 13:02:53 -08:00
} ,
} ;
2022-08-13 00:36:14 -07:00
pub const CLOSE_PROGRAM_WARNING : & str = " WARNING! \
Closed programs cannot be recreated at the same program id . \
Once a program is closed , it can never be invoked again . \
To proceed with closing , rerun the ` close ` command with the ` - - bypass - warning ` flag " ;
2022-05-22 18:00:42 -07:00
#[ derive(Debug, PartialEq, Eq) ]
2020-12-21 13:02:53 -08:00
pub enum ProgramCliCommand {
Deploy {
2021-01-08 09:37:57 -08:00
program_location : Option < String > ,
2020-12-21 13:02:53 -08:00
program_signer_index : Option < SignerIndex > ,
program_pubkey : Option < Pubkey > ,
buffer_signer_index : Option < SignerIndex > ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : Option < Pubkey > ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : SignerIndex ,
2021-01-08 09:37:57 -08:00
is_final : bool ,
2020-12-21 13:02:53 -08:00
max_len : Option < usize > ,
allow_excessive_balance : bool ,
2022-03-25 13:43:43 -07:00
skip_fee_check : bool ,
2020-12-21 13:02:53 -08:00
} ,
2021-01-08 09:37:57 -08:00
WriteBuffer {
program_location : String ,
buffer_signer_index : Option < SignerIndex > ,
buffer_pubkey : Option < Pubkey > ,
2023-01-02 23:32:04 -08:00
buffer_authority_signer_index : SignerIndex ,
2021-01-08 09:37:57 -08:00
max_len : Option < usize > ,
2022-03-25 13:43:43 -07:00
skip_fee_check : bool ,
2021-01-08 09:37:57 -08:00
} ,
SetBufferAuthority {
buffer_pubkey : Pubkey ,
buffer_authority_index : Option < SignerIndex > ,
2021-01-29 12:43:42 -08:00
new_buffer_authority : Pubkey ,
2021-01-08 09:37:57 -08:00
} ,
2020-12-21 13:02:53 -08:00
SetUpgradeAuthority {
2021-01-08 09:37:57 -08:00
program_pubkey : Pubkey ,
2020-12-21 13:02:53 -08:00
upgrade_authority_index : Option < SignerIndex > ,
new_upgrade_authority : Option < Pubkey > ,
} ,
2022-12-15 22:59:54 -08:00
SetUpgradeAuthorityChecked {
program_pubkey : Pubkey ,
upgrade_authority_index : SignerIndex ,
new_upgrade_authority_index : SignerIndex ,
} ,
2021-02-02 22:33:03 -08:00
Show {
2021-01-08 14:43:36 -08:00
account_pubkey : Option < Pubkey > ,
2021-03-17 21:39:29 -07:00
authority_pubkey : Pubkey ,
2021-08-25 17:03:55 -07:00
get_programs : bool ,
get_buffers : bool ,
2021-03-17 21:39:29 -07:00
all : bool ,
use_lamports_unit : bool ,
2021-01-08 14:43:36 -08:00
} ,
2021-02-02 22:33:03 -08:00
Dump {
2021-02-02 15:36:02 -08:00
account_pubkey : Option < Pubkey > ,
2021-02-02 22:33:03 -08:00
output_location : String ,
2021-02-02 15:36:02 -08:00
} ,
2021-03-17 21:39:29 -07:00
Close {
account_pubkey : Option < Pubkey > ,
recipient_pubkey : Pubkey ,
authority_index : SignerIndex ,
use_lamports_unit : bool ,
2022-08-13 00:36:14 -07:00
bypass_warning : bool ,
2021-03-17 21:39:29 -07:00
} ,
2020-12-21 13:02:53 -08:00
}
pub trait ProgramSubCommands {
fn program_subcommands ( self ) -> Self ;
}
impl ProgramSubCommands for App < '_ , '_ > {
fn program_subcommands ( self ) -> Self {
self . subcommand (
SubCommand ::with_name ( " program " )
. about ( " Program management " )
. setting ( AppSettings ::SubcommandRequiredElseHelp )
2022-03-25 13:43:43 -07:00
. arg (
Arg ::with_name ( " skip_fee_check " )
. long ( " skip-fee-check " )
. hidden ( true )
. takes_value ( false )
. global ( true )
)
2020-12-21 13:02:53 -08:00
. subcommand (
SubCommand ::with_name ( " deploy " )
2022-08-22 03:56:10 -07:00
. about ( " Deploy an upgradeable program " )
2020-12-21 13:02:53 -08:00
. arg (
Arg ::with_name ( " program_location " )
. index ( 1 )
. value_name ( " PROGRAM_FILEPATH " )
. takes_value ( true )
. help ( " /path/to/program.so " ) ,
)
. arg (
Arg ::with_name ( " buffer " )
2021-01-08 09:37:57 -08:00
. long ( " buffer " )
2020-12-21 13:02:53 -08:00
. value_name ( " BUFFER_SIGNER " )
. takes_value ( true )
. validator ( is_valid_signer )
2021-01-01 23:09:45 -08:00
. help ( " Intermediate buffer account to write data to, which can be used to resume a failed deploy \
[ default : random address ] " )
2020-12-21 13:02:53 -08:00
)
. arg (
2021-01-29 12:43:42 -08:00
Arg ::with_name ( " upgrade_authority " )
2020-12-21 13:02:53 -08:00
. long ( " upgrade-authority " )
2021-01-29 12:43:42 -08:00
. value_name ( " UPGRADE_AUTHORITY_SIGNER " )
. takes_value ( true )
. validator ( is_valid_signer )
. help ( " Upgrade authority [default: the default configured keypair] " )
2020-12-21 13:02:53 -08:00
)
. arg (
pubkey! ( Arg ::with_name ( " program_id " )
. long ( " program-id " )
. value_name ( " PROGRAM_ID " ) ,
2021-06-03 15:52:36 -07:00
" Executable program's address, must be a keypair for initial deploys, can be a pubkey for upgrades \
2021-01-01 23:09:45 -08:00
[ default : address of keypair at / path / to / program - keypair . json if present , otherwise a random address ] " ),
2020-12-21 13:02:53 -08:00
)
. arg (
Arg ::with_name ( " final " )
. long ( " final " )
. help ( " The program will not be upgradeable " )
)
. arg (
Arg ::with_name ( " max_len " )
. long ( " max-len " )
. value_name ( " max_len " )
. takes_value ( true )
. required ( false )
2021-01-01 23:09:45 -08:00
. help ( " Maximum length of the upgradeable program \
[ default : twice the length of the original deployed program ] " )
2020-12-21 13:02:53 -08:00
)
. arg (
Arg ::with_name ( " allow_excessive_balance " )
. long ( " allow-excessive-deploy-account-balance " )
. takes_value ( false )
2021-01-01 23:09:45 -08:00
. help ( " Use the designated program id even if the account already holds a large balance of SOL " )
2021-01-20 08:48:10 -08:00
) ,
2020-12-21 13:02:53 -08:00
)
2021-01-08 09:37:57 -08:00
. subcommand (
SubCommand ::with_name ( " write-buffer " )
. about ( " Writes a program into a buffer account " )
. arg (
Arg ::with_name ( " program_location " )
. index ( 1 )
. value_name ( " PROGRAM_FILEPATH " )
. takes_value ( true )
. required ( true )
. help ( " /path/to/program.so " ) ,
)
. arg (
Arg ::with_name ( " buffer " )
. long ( " buffer " )
. value_name ( " BUFFER_SIGNER " )
. takes_value ( true )
. validator ( is_valid_signer )
. help ( " Buffer account to write data into [default: random address] " )
)
. arg (
Arg ::with_name ( " buffer_authority " )
. long ( " buffer-authority " )
. value_name ( " BUFFER_AUTHORITY_SIGNER " )
. takes_value ( true )
. validator ( is_valid_signer )
. help ( " Buffer authority [default: the default configured keypair] " )
)
. arg (
Arg ::with_name ( " max_len " )
. long ( " max-len " )
. value_name ( " max_len " )
. takes_value ( true )
. required ( false )
. help ( " Maximum length of the upgradeable program \
[ default : twice the length of the original deployed program ] " )
2021-01-20 08:48:10 -08:00
) ,
2021-01-08 09:37:57 -08:00
)
. subcommand (
SubCommand ::with_name ( " set-buffer-authority " )
2021-03-17 21:39:29 -07:00
. about ( " Set a new buffer authority " )
2021-01-08 09:37:57 -08:00
. arg (
Arg ::with_name ( " buffer " )
. index ( 1 )
. value_name ( " BUFFER_PUBKEY " )
. takes_value ( true )
. required ( true )
. help ( " Public key of the buffer " )
)
. arg (
Arg ::with_name ( " buffer_authority " )
. long ( " buffer-authority " )
. value_name ( " BUFFER_AUTHORITY_SIGNER " )
. takes_value ( true )
. validator ( is_valid_signer )
. help ( " Buffer authority [default: the default configured keypair] " )
)
. arg (
pubkey! ( Arg ::with_name ( " new_buffer_authority " )
. long ( " new-buffer-authority " )
. value_name ( " NEW_BUFFER_AUTHORITY " )
2021-01-29 12:43:42 -08:00
. required ( true ) ,
2021-01-08 09:37:57 -08:00
" Address of the new buffer authority " ) ,
)
)
2020-12-21 13:02:53 -08:00
. subcommand (
SubCommand ::with_name ( " set-upgrade-authority " )
. about ( " Set a new program authority " )
. arg (
Arg ::with_name ( " program_id " )
. index ( 1 )
. value_name ( " PROGRAM_ADDRESS " )
. takes_value ( true )
. required ( true )
2021-02-02 22:33:03 -08:00
. help ( " Address of the program to upgrade " )
2020-12-21 13:02:53 -08:00
)
. arg (
Arg ::with_name ( " upgrade_authority " )
. long ( " upgrade-authority " )
. value_name ( " UPGRADE_AUTHORITY_SIGNER " )
. takes_value ( true )
. validator ( is_valid_signer )
. help ( " Upgrade authority [default: the default configured keypair] " )
)
. arg (
2022-12-15 22:59:54 -08:00
Arg ::with_name ( " new_upgrade_authority " )
2020-12-21 13:02:53 -08:00
. long ( " new-upgrade-authority " )
2022-12-15 22:59:54 -08:00
. value_name ( " NEW_UPGRADE_AUTHORITY " )
2020-12-21 13:02:53 -08:00
. required_unless ( " final " )
2022-12-15 22:59:54 -08:00
. takes_value ( true )
. help ( " New upgrade authority (keypair or pubkey). It is strongly recommended to pass in a keypair to prevent mistakes in setting the upgrade authority. You can opt out of this behavior by passing --skip-new-upgrade-authority-signer-check if you are really confident that you are setting the correct authority. Alternatively, If you wish to make the program immutable, you should ignore this arg and pass the --final flag. "
)
2020-12-21 13:02:53 -08:00
)
. arg (
Arg ::with_name ( " final " )
. long ( " final " )
. conflicts_with ( " new_upgrade_authority " )
. help ( " The program will not be upgradeable " )
)
2022-12-15 22:59:54 -08:00
. arg (
Arg ::with_name ( " skip_new_upgrade_authority_signer_check " )
. long ( " skip-new-upgrade-authority-signer-check " )
. requires ( " new_upgrade_authority " )
. takes_value ( false )
. help ( " Set this flag if you don't want the new authority to sign the set-upgrade-authority transaction. " ) ,
) ,
2021-01-08 14:43:36 -08:00
)
. subcommand (
2021-02-02 22:33:03 -08:00
SubCommand ::with_name ( " show " )
. about ( " Display information about a buffer or program " )
2021-01-08 14:43:36 -08:00
. arg (
Arg ::with_name ( " account " )
. index ( 1 )
. value_name ( " ACCOUNT_ADDRESS " )
. takes_value ( true )
2021-02-02 22:33:03 -08:00
. help ( " Address of the buffer or program to show " )
)
2021-08-25 17:03:55 -07:00
. arg (
Arg ::with_name ( " programs " )
. long ( " programs " )
. conflicts_with ( " account " )
. conflicts_with ( " buffers " )
. required_unless_one ( & [ " account " , " buffers " ] )
2021-08-26 12:05:05 -07:00
. help ( " Show every upgradeable program that matches the authority " )
2021-08-25 17:03:55 -07:00
)
2021-03-17 21:39:29 -07:00
. arg (
Arg ::with_name ( " buffers " )
. long ( " buffers " )
. conflicts_with ( " account " )
2021-08-25 17:03:55 -07:00
. conflicts_with ( " programs " )
. required_unless_one ( & [ " account " , " programs " ] )
. help ( " Show every upgradeable buffer that matches the authority " )
2021-03-17 21:39:29 -07:00
)
. arg (
Arg ::with_name ( " all " )
. long ( " all " )
. conflicts_with ( " account " )
2021-08-25 17:03:55 -07:00
. conflicts_with ( " buffer_authority " )
2021-03-17 21:39:29 -07:00
. help ( " Show accounts for all authorities " )
)
. arg (
pubkey! ( Arg ::with_name ( " buffer_authority " )
. long ( " buffer-authority " )
. value_name ( " AUTHORITY " )
. conflicts_with ( " all " ) ,
" Authority [default: the default configured keypair] " ) ,
)
. arg (
Arg ::with_name ( " lamports " )
. long ( " lamports " )
. takes_value ( false )
. help ( " Display balance in lamports instead of SOL " ) ,
) ,
2020-12-21 13:02:53 -08:00
)
2021-02-02 15:36:02 -08:00
. subcommand (
2021-02-02 22:33:03 -08:00
SubCommand ::with_name ( " dump " )
. about ( " Write the program data to a file " )
2021-02-02 15:36:02 -08:00
. arg (
Arg ::with_name ( " account " )
. index ( 1 )
. value_name ( " ACCOUNT_ADDRESS " )
. takes_value ( true )
. required ( true )
2021-02-02 22:33:03 -08:00
. help ( " Address of the buffer or program " )
2021-02-02 15:36:02 -08:00
)
. arg (
2021-02-02 22:33:03 -08:00
Arg ::with_name ( " output_location " )
. index ( 2 )
. value_name ( " OUTPUT_FILEPATH " )
. takes_value ( true )
. required ( true )
. help ( " /path/to/program.so " ) ,
2021-02-02 15:36:02 -08:00
) ,
)
2021-03-17 21:39:29 -07:00
. subcommand (
SubCommand ::with_name ( " close " )
2021-08-24 10:05:54 -07:00
. about ( " Close a program or buffer account and withdraw all lamports " )
2021-03-17 21:39:29 -07:00
. arg (
Arg ::with_name ( " account " )
. index ( 1 )
2021-08-24 10:05:54 -07:00
. value_name ( " ACCOUNT_ADDRESS " )
2021-03-17 21:39:29 -07:00
. takes_value ( true )
2021-08-24 10:05:54 -07:00
. help ( " Address of the program or buffer account to close " ) ,
2021-03-17 21:39:29 -07:00
)
. arg (
Arg ::with_name ( " buffers " )
. long ( " buffers " )
. conflicts_with ( " account " )
. required_unless ( " account " )
2021-08-24 10:05:54 -07:00
. help ( " Close all buffer accounts that match the authority " )
2021-03-17 21:39:29 -07:00
)
. arg (
2021-08-24 10:05:54 -07:00
Arg ::with_name ( " authority " )
. long ( " authority " )
. alias ( " buffer-authority " )
2021-03-17 21:39:29 -07:00
. value_name ( " AUTHORITY_SIGNER " )
. takes_value ( true )
. validator ( is_valid_signer )
2021-08-24 10:05:54 -07:00
. help ( " Upgrade or buffer authority [default: the default configured keypair] " )
2021-03-17 21:39:29 -07:00
)
2021-08-24 10:05:54 -07:00
2021-03-17 21:39:29 -07:00
. arg (
pubkey! ( Arg ::with_name ( " recipient_account " )
. long ( " recipient " )
. value_name ( " RECIPIENT_ADDRESS " ) ,
" Address of the account to deposit the closed account's lamports [default: the default configured keypair] " ) ,
)
. arg (
Arg ::with_name ( " lamports " )
. long ( " lamports " )
. takes_value ( false )
. help ( " Display balance in lamports instead of SOL " ) ,
2022-08-13 00:36:14 -07:00
)
. arg (
Arg ::with_name ( " bypass_warning " )
. long ( " bypass-warning " )
. takes_value ( false )
. help ( " Bypass the permanent program closure warning " ) ,
2021-03-17 21:39:29 -07:00
) ,
)
2020-12-21 13:02:53 -08:00
)
2021-07-28 23:19:34 -07:00
. subcommand (
SubCommand ::with_name ( " deploy " )
2022-10-21 00:29:37 -07:00
. about ( " Deploy has been removed. Use `solana program deploy` instead to deploy upgradeable programs " )
2021-10-25 09:53:21 -07:00
. setting ( AppSettings ::Hidden )
2021-07-28 23:19:34 -07:00
)
2020-12-21 13:02:53 -08:00
}
}
pub fn parse_program_subcommand (
matches : & ArgMatches < '_ > ,
default_signer : & DefaultSigner ,
wallet_manager : & mut Option < Arc < RemoteWalletManager > > ,
) -> Result < CliCommandInfo , CliError > {
2022-03-25 13:43:43 -07:00
let ( subcommand , sub_matches ) = matches . subcommand ( ) ;
let matches_skip_fee_check = matches . is_present ( " skip_fee_check " ) ;
let sub_matches_skip_fee_check = sub_matches
. map ( | m | m . is_present ( " skip_fee_check " ) )
. unwrap_or ( false ) ;
let skip_fee_check = matches_skip_fee_check | | sub_matches_skip_fee_check ;
let response = match ( subcommand , sub_matches ) {
2020-12-21 13:02:53 -08:00
( " deploy " , Some ( matches ) ) = > {
let mut bulk_signers = vec! [ Some (
default_signer . signer_from_path ( matches , wallet_manager ) ? ,
) ] ;
2021-04-08 11:40:37 -07:00
let program_location = matches
. value_of ( " program_location " )
. map ( | location | location . to_string ( ) ) ;
2021-01-08 09:37:57 -08:00
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 {
2021-04-08 11:40:37 -07:00
pubkey_of_signer ( matches , " buffer " , wallet_manager ) ?
2021-01-08 09:37:57 -08:00
} ;
2020-12-21 13:02:53 -08:00
let program_pubkey = if let Ok ( ( program_signer , Some ( program_pubkey ) ) ) =
signer_of ( matches , " program_id " , wallet_manager )
{
bulk_signers . push ( program_signer ) ;
Some ( program_pubkey )
} else {
2021-04-08 11:40:37 -07:00
pubkey_of_signer ( matches , " program_id " , wallet_manager ) ?
2020-12-21 13:02:53 -08:00
} ;
2023-01-02 23:32:04 -08:00
let ( upgrade_authority , upgrade_authority_pubkey ) =
signer_of ( matches , " upgrade_authority " , wallet_manager ) ? ;
bulk_signers . push ( upgrade_authority ) ;
2020-12-21 13:02:53 -08:00
let max_len = value_of ( matches , " max_len " ) ;
let signer_info =
default_signer . generate_unique_signers ( bulk_signers , matches , wallet_manager ) ? ;
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Deploy {
2021-01-08 09:37:57 -08:00
program_location ,
2020-12-21 13:02:53 -08:00
program_signer_index : signer_info . index_of_or_none ( program_pubkey ) ,
program_pubkey ,
buffer_signer_index : signer_info . index_of_or_none ( buffer_pubkey ) ,
2021-01-08 09:37:57 -08:00
buffer_pubkey ,
2020-12-21 13:02:53 -08:00
upgrade_authority_signer_index : signer_info
2021-01-29 12:43:42 -08:00
. index_of ( upgrade_authority_pubkey )
. unwrap ( ) ,
2021-01-08 09:37:57 -08:00
is_final : matches . is_present ( " final " ) ,
2020-12-21 13:02:53 -08:00
max_len ,
allow_excessive_balance : matches . is_present ( " allow_excessive_balance " ) ,
2022-03-25 13:43:43 -07:00
skip_fee_check ,
2020-12-21 13:02:53 -08:00
} ) ,
signers : signer_info . signers ,
}
}
2021-01-08 09:37:57 -08:00
( " write-buffer " , Some ( matches ) ) = > {
let mut bulk_signers = vec! [ Some (
default_signer . signer_from_path ( matches , wallet_manager ) ? ,
) ] ;
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 {
2021-04-08 11:40:37 -07:00
pubkey_of_signer ( matches , " buffer " , wallet_manager ) ?
2021-01-08 09:37:57 -08:00
} ;
2023-01-02 23:32:04 -08:00
let ( buffer_authority , buffer_authority_pubkey ) =
signer_of ( matches , " buffer_authority " , wallet_manager ) ? ;
bulk_signers . push ( buffer_authority ) ;
2021-01-08 09:37:57 -08:00
let max_len = value_of ( matches , " max_len " ) ;
let signer_info =
default_signer . generate_unique_signers ( bulk_signers , matches , wallet_manager ) ? ;
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::WriteBuffer {
program_location : matches . value_of ( " program_location " ) . unwrap ( ) . to_string ( ) ,
buffer_signer_index : signer_info . index_of_or_none ( buffer_pubkey ) ,
buffer_pubkey ,
buffer_authority_signer_index : signer_info
2023-01-02 23:32:04 -08:00
. index_of ( buffer_authority_pubkey )
. unwrap ( ) ,
2021-01-08 09:37:57 -08:00
max_len ,
2022-03-25 13:43:43 -07:00
skip_fee_check ,
2021-01-08 09:37:57 -08:00
} ) ,
signers : signer_info . signers ,
}
}
( " set-buffer-authority " , Some ( matches ) ) = > {
let buffer_pubkey = pubkey_of ( matches , " buffer " ) . unwrap ( ) ;
let ( buffer_authority_signer , buffer_authority_pubkey ) =
signer_of ( matches , " buffer_authority " , wallet_manager ) ? ;
2021-03-17 21:39:29 -07:00
let new_buffer_authority =
pubkey_of_signer ( matches , " new_buffer_authority " , wallet_manager ) ? . unwrap ( ) ;
2021-01-08 09:37:57 -08:00
let signer_info = default_signer . generate_unique_signers (
vec! [
Some ( default_signer . signer_from_path ( matches , wallet_manager ) ? ) ,
buffer_authority_signer ,
] ,
matches ,
wallet_manager ,
) ? ;
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetBufferAuthority {
buffer_pubkey ,
buffer_authority_index : signer_info . index_of ( buffer_authority_pubkey ) ,
new_buffer_authority ,
} ) ,
signers : signer_info . signers ,
}
}
2020-12-21 13:02:53 -08:00
( " set-upgrade-authority " , Some ( matches ) ) = > {
let ( upgrade_authority_signer , upgrade_authority_pubkey ) =
signer_of ( matches , " upgrade_authority " , wallet_manager ) ? ;
2021-01-08 09:37:57 -08:00
let program_pubkey = pubkey_of ( matches , " program_id " ) . unwrap ( ) ;
2022-12-15 22:59:54 -08:00
let is_final = matches . is_present ( " final " ) ;
let new_upgrade_authority = if is_final {
2020-12-21 13:02:53 -08:00
None
} else {
2021-03-17 21:39:29 -07:00
pubkey_of_signer ( matches , " new_upgrade_authority " , wallet_manager ) ?
2020-12-21 13:02:53 -08:00
} ;
2022-12-15 22:59:54 -08:00
let mut signers = vec! [
Some ( default_signer . signer_from_path ( matches , wallet_manager ) ? ) ,
upgrade_authority_signer ,
] ;
2020-12-21 13:02:53 -08:00
2022-12-15 22:59:54 -08:00
if ! is_final & & ! matches . is_present ( " skip_new_upgrade_authority_signer_check " ) {
let ( new_upgrade_authority_signer , _ ) =
signer_of ( matches , " new_upgrade_authority " , wallet_manager ) ? ;
signers . push ( new_upgrade_authority_signer ) ;
}
let signer_info =
default_signer . generate_unique_signers ( signers , matches , wallet_manager ) ? ;
if matches . is_present ( " skip_new_upgrade_authority_signer_check " ) | | is_final {
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetUpgradeAuthority {
program_pubkey ,
upgrade_authority_index : signer_info . index_of ( upgrade_authority_pubkey ) ,
new_upgrade_authority ,
} ) ,
signers : signer_info . signers ,
}
} else {
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetUpgradeAuthorityChecked {
program_pubkey ,
upgrade_authority_index : signer_info
. index_of ( upgrade_authority_pubkey )
. expect ( " upgrade authority is missing from signers " ) ,
new_upgrade_authority_index : signer_info
. index_of ( new_upgrade_authority )
. expect ( " new upgrade authority is missing from signers " ) ,
} ) ,
signers : signer_info . signers ,
}
2020-12-21 13:02:53 -08:00
}
}
2021-03-17 21:39:29 -07:00
( " show " , Some ( matches ) ) = > {
let authority_pubkey = if let Some ( authority_pubkey ) =
pubkey_of_signer ( matches , " buffer_authority " , wallet_manager ) ?
{
authority_pubkey
} else {
default_signer
. signer_from_path ( matches , wallet_manager ) ?
. pubkey ( )
} ;
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Show {
2021-08-25 17:03:55 -07:00
account_pubkey : pubkey_of ( matches , " account " ) ,
2021-03-17 21:39:29 -07:00
authority_pubkey ,
2021-08-25 17:03:55 -07:00
get_programs : matches . is_present ( " programs " ) ,
get_buffers : matches . is_present ( " buffers " ) ,
2021-03-17 21:39:29 -07:00
all : matches . is_present ( " all " ) ,
use_lamports_unit : matches . is_present ( " lamports " ) ,
} ) ,
signers : vec ! [ ] ,
}
}
2021-02-02 22:33:03 -08:00
( " dump " , Some ( matches ) ) = > CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Dump {
2021-02-02 15:36:02 -08:00
account_pubkey : pubkey_of ( matches , " account " ) ,
2021-02-02 22:33:03 -08:00
output_location : matches . value_of ( " output_location " ) . unwrap ( ) . to_string ( ) ,
2021-02-02 15:36:02 -08:00
} ) ,
signers : vec ! [ ] ,
} ,
2021-03-17 21:39:29 -07:00
( " close " , Some ( matches ) ) = > {
let account_pubkey = if matches . is_present ( " buffers " ) {
None
} else {
pubkey_of ( matches , " account " )
} ;
let recipient_pubkey = if let Some ( recipient_pubkey ) =
pubkey_of_signer ( matches , " recipient_account " , wallet_manager ) ?
{
recipient_pubkey
} else {
default_signer
. signer_from_path ( matches , wallet_manager ) ?
. pubkey ( )
} ;
let ( authority_signer , authority_pubkey ) =
2021-08-24 10:05:54 -07:00
signer_of ( matches , " authority " , wallet_manager ) ? ;
2021-03-17 21:39:29 -07:00
let signer_info = default_signer . generate_unique_signers (
vec! [
Some ( default_signer . signer_from_path ( matches , wallet_manager ) ? ) ,
authority_signer ,
] ,
matches ,
wallet_manager ,
) ? ;
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Close {
account_pubkey ,
recipient_pubkey ,
authority_index : signer_info . index_of ( authority_pubkey ) . unwrap ( ) ,
use_lamports_unit : matches . is_present ( " lamports " ) ,
2022-08-13 00:36:14 -07:00
bypass_warning : matches . is_present ( " bypass_warning " ) ,
2021-03-17 21:39:29 -07:00
} ) ,
signers : signer_info . signers ,
}
}
2020-12-21 13:02:53 -08:00
_ = > unreachable! ( ) ,
} ;
Ok ( response )
}
pub fn process_program_subcommand (
2021-04-22 18:35:12 -07:00
rpc_client : Arc < RpcClient > ,
2020-12-21 13:02:53 -08:00
config : & CliConfig ,
program_subcommand : & ProgramCliCommand ,
) -> ProcessResult {
match program_subcommand {
ProgramCliCommand ::Deploy {
program_location ,
program_signer_index ,
program_pubkey ,
buffer_signer_index ,
2021-01-08 09:37:57 -08:00
buffer_pubkey ,
2020-12-21 13:02:53 -08:00
upgrade_authority_signer_index ,
2021-01-08 09:37:57 -08:00
is_final ,
2020-12-21 13:02:53 -08:00
max_len ,
allow_excessive_balance ,
2022-03-25 13:43:43 -07:00
skip_fee_check ,
2020-12-21 13:02:53 -08:00
} = > process_program_deploy (
2021-04-22 18:35:12 -07:00
rpc_client ,
2020-12-21 13:02:53 -08:00
config ,
program_location ,
* program_signer_index ,
* program_pubkey ,
* buffer_signer_index ,
2021-01-08 09:37:57 -08:00
* buffer_pubkey ,
2020-12-21 13:02:53 -08:00
* upgrade_authority_signer_index ,
2021-01-08 09:37:57 -08:00
* is_final ,
2020-12-21 13:02:53 -08:00
* max_len ,
* allow_excessive_balance ,
2022-03-25 13:43:43 -07:00
* skip_fee_check ,
2020-12-21 13:02:53 -08:00
) ,
2021-01-08 09:37:57 -08:00
ProgramCliCommand ::WriteBuffer {
program_location ,
buffer_signer_index ,
buffer_pubkey ,
buffer_authority_signer_index ,
max_len ,
2022-03-25 13:43:43 -07:00
skip_fee_check ,
2021-01-08 09:37:57 -08:00
} = > process_write_buffer (
2021-04-22 18:35:12 -07:00
rpc_client ,
2021-01-08 09:37:57 -08:00
config ,
program_location ,
* buffer_signer_index ,
* buffer_pubkey ,
* buffer_authority_signer_index ,
* max_len ,
2022-03-25 13:43:43 -07:00
* skip_fee_check ,
2021-01-08 09:37:57 -08:00
) ,
ProgramCliCommand ::SetBufferAuthority {
buffer_pubkey ,
buffer_authority_index ,
new_buffer_authority ,
} = > process_set_authority (
& rpc_client ,
config ,
None ,
Some ( * buffer_pubkey ) ,
* buffer_authority_index ,
2021-01-29 12:43:42 -08:00
Some ( * new_buffer_authority ) ,
2021-01-08 09:37:57 -08:00
) ,
2020-12-21 13:02:53 -08:00
ProgramCliCommand ::SetUpgradeAuthority {
2021-01-08 09:37:57 -08:00
program_pubkey ,
2020-12-21 13:02:53 -08:00
upgrade_authority_index ,
new_upgrade_authority ,
2021-01-08 09:37:57 -08:00
} = > process_set_authority (
2020-12-21 13:02:53 -08:00
& rpc_client ,
config ,
2021-01-08 09:37:57 -08:00
Some ( * program_pubkey ) ,
None ,
2020-12-21 13:02:53 -08:00
* upgrade_authority_index ,
* new_upgrade_authority ,
) ,
2022-12-15 22:59:54 -08:00
ProgramCliCommand ::SetUpgradeAuthorityChecked {
program_pubkey ,
upgrade_authority_index ,
new_upgrade_authority_index ,
} = > process_set_authority_checked (
& rpc_client ,
config ,
* program_pubkey ,
* upgrade_authority_index ,
* new_upgrade_authority_index ,
) ,
2021-03-17 21:39:29 -07:00
ProgramCliCommand ::Show {
account_pubkey ,
authority_pubkey ,
2021-08-25 17:03:55 -07:00
get_programs ,
get_buffers ,
2021-03-17 21:39:29 -07:00
all ,
use_lamports_unit ,
} = > process_show (
& rpc_client ,
config ,
* account_pubkey ,
* authority_pubkey ,
2021-08-25 17:03:55 -07:00
* get_programs ,
* get_buffers ,
2021-03-17 21:39:29 -07:00
* all ,
* use_lamports_unit ,
) ,
2021-02-02 22:33:03 -08:00
ProgramCliCommand ::Dump {
2021-02-02 15:36:02 -08:00
account_pubkey ,
2021-02-02 22:33:03 -08:00
output_location ,
} = > process_dump ( & rpc_client , config , * account_pubkey , output_location ) ,
2021-03-17 21:39:29 -07:00
ProgramCliCommand ::Close {
account_pubkey ,
recipient_pubkey ,
authority_index ,
use_lamports_unit ,
2022-08-13 00:36:14 -07:00
bypass_warning ,
2021-03-17 21:39:29 -07:00
} = > process_close (
& rpc_client ,
config ,
* account_pubkey ,
* recipient_pubkey ,
* authority_index ,
* use_lamports_unit ,
2022-08-13 00:36:14 -07:00
* bypass_warning ,
2021-03-17 21:39:29 -07:00
) ,
2020-12-21 13:02:53 -08:00
}
}
2021-01-08 09:37:57 -08:00
fn get_default_program_keypair ( program_location : & Option < String > ) -> Keypair {
2020-12-21 13:02:53 -08:00
let program_keypair = {
2021-01-08 09:37:57 -08:00
if let Some ( program_location ) = program_location {
let mut keypair_file = PathBuf ::new ( ) ;
keypair_file . push ( program_location ) ;
let mut filename = keypair_file . file_stem ( ) . unwrap ( ) . to_os_string ( ) ;
filename . push ( " -keypair " ) ;
keypair_file . set_file_name ( filename ) ;
keypair_file . set_extension ( " json " ) ;
2022-09-22 15:23:03 -07:00
if let Ok ( keypair ) = read_keypair_file ( keypair_file . to_str ( ) . unwrap ( ) ) {
2021-01-08 09:37:57 -08:00
keypair
} else {
Keypair ::new ( )
}
2020-12-21 13:02:53 -08:00
} else {
Keypair ::new ( )
}
} ;
program_keypair
}
/// Deploy using upgradeable loader
#[ allow(clippy::too_many_arguments) ]
fn process_program_deploy (
2021-04-22 18:35:12 -07:00
rpc_client : Arc < RpcClient > ,
2020-12-21 13:02:53 -08:00
config : & CliConfig ,
2021-01-08 09:37:57 -08:00
program_location : & Option < String > ,
2020-12-21 13:02:53 -08:00
program_signer_index : Option < SignerIndex > ,
program_pubkey : Option < Pubkey > ,
buffer_signer_index : Option < SignerIndex > ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : Option < Pubkey > ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : SignerIndex ,
2021-01-08 09:37:57 -08:00
is_final : bool ,
2020-12-21 13:02:53 -08:00
max_len : Option < usize > ,
allow_excessive_balance : bool ,
2022-03-25 13:43:43 -07:00
skip_fee_check : bool ,
2020-12-21 13:02:53 -08:00
) -> ProcessResult {
let ( words , mnemonic , buffer_keypair ) = create_ephemeral_keypair ( ) ? ;
2021-02-02 13:35:37 -08:00
let ( buffer_provided , buffer_signer , buffer_pubkey ) = if let Some ( i ) = buffer_signer_index {
( true , Some ( config . signers [ i ] ) , config . signers [ i ] . pubkey ( ) )
2021-01-08 09:37:57 -08:00
} else if let Some ( pubkey ) = buffer_pubkey {
2021-02-02 13:35:37 -08:00
( true , None , pubkey )
2020-12-21 13:02:53 -08:00
} else {
2021-01-08 09:37:57 -08:00
(
2021-02-02 13:35:37 -08:00
false ,
2021-01-08 09:37:57 -08:00
Some ( & buffer_keypair as & dyn Signer ) ,
buffer_keypair . pubkey ( ) ,
)
2020-12-21 13:02:53 -08:00
} ;
2021-01-29 12:43:42 -08:00
let upgrade_authority_signer = config . signers [ upgrade_authority_signer_index ] ;
2020-12-21 13:02:53 -08:00
2021-06-18 06:34:46 -07:00
let default_program_keypair = get_default_program_keypair ( program_location ) ;
2021-01-08 09:37:57 -08:00
let ( program_signer , program_pubkey ) = if let Some ( i ) = program_signer_index {
2020-12-21 13:02:53 -08:00
( Some ( config . signers [ i ] ) , config . signers [ i ] . pubkey ( ) )
2021-01-08 09:37:57 -08:00
} else if let Some ( program_pubkey ) = program_pubkey {
( None , program_pubkey )
2020-12-21 13:02:53 -08:00
} else {
(
Some ( & default_program_keypair as & dyn Signer ) ,
default_program_keypair . pubkey ( ) ,
)
} ;
let do_deploy = if let Some ( account ) = rpc_client
2021-01-08 09:37:57 -08:00
. get_account_with_commitment ( & program_pubkey , config . commitment ) ?
2020-12-21 13:02:53 -08:00
. value
{
2021-03-11 13:44:21 -08:00
if account . owner ! = bpf_loader_upgradeable ::id ( ) {
return Err ( format! (
2022-12-06 06:30:06 -08:00
" Account {program_pubkey} is not an upgradeable program or already in use "
2021-03-11 13:44:21 -08:00
)
. into ( ) ) ;
}
2020-12-21 13:02:53 -08:00
if ! account . executable {
// Continue an initial deploy
true
2021-03-11 13:44:21 -08:00
} else if let Ok ( UpgradeableLoaderState ::Program {
2020-12-21 13:02:53 -08:00
programdata_address ,
2021-03-11 13:44:21 -08:00
} ) = account . state ( )
2020-12-21 13:02:53 -08:00
{
if let Some ( account ) = rpc_client
. get_account_with_commitment ( & programdata_address , config . commitment ) ?
. value
{
2021-03-11 13:44:21 -08:00
if let Ok ( UpgradeableLoaderState ::ProgramData {
2020-12-21 13:02:53 -08:00
slot : _ ,
2021-01-08 09:37:57 -08:00
upgrade_authority_address : program_authority_pubkey ,
2021-03-11 13:44:21 -08:00
} ) = account . state ( )
2020-12-21 13:02:53 -08:00
{
2021-01-08 09:37:57 -08:00
if program_authority_pubkey . is_none ( ) {
2021-03-11 13:44:21 -08:00
return Err (
2022-12-06 06:30:06 -08:00
format! ( " Program {program_pubkey} is no longer upgradeable " ) . into ( )
2021-03-11 13:44:21 -08:00
) ;
2020-12-21 13:02:53 -08:00
}
2021-01-29 12:43:42 -08:00
if program_authority_pubkey ! = Some ( upgrade_authority_signer . pubkey ( ) ) {
2020-12-21 13:02:53 -08:00
return Err ( format! (
" Program's authority {:?} does not match authority provided {:?} " ,
2021-01-29 12:43:42 -08:00
program_authority_pubkey ,
upgrade_authority_signer . pubkey ( ) ,
2020-12-21 13:02:53 -08:00
)
. into ( ) ) ;
}
// Do upgrade
false
} else {
2021-03-11 13:44:21 -08:00
return Err ( format! (
2022-12-06 06:30:06 -08:00
" Program {program_pubkey} has been closed, use a new Program Id "
2021-03-11 13:44:21 -08:00
)
. into ( ) ) ;
2020-12-21 13:02:53 -08:00
}
} else {
2021-08-24 10:05:54 -07:00
return Err ( format! (
2022-12-06 06:30:06 -08:00
" Program {program_pubkey} has been closed, use a new Program Id "
2021-08-24 10:05:54 -07:00
)
. into ( ) ) ;
2020-12-21 13:02:53 -08:00
}
} else {
2022-12-06 06:30:06 -08:00
return Err ( format! ( " {program_pubkey} is not an upgradeable program " ) . into ( ) ) ;
2020-12-21 13:02:53 -08:00
}
} else {
// do new deploy
true
} ;
2021-02-19 11:06:05 -08:00
let ( program_data , program_len ) = if let Some ( program_location ) = program_location {
2021-06-18 06:34:46 -07:00
let program_data = read_and_verify_elf ( program_location ) ? ;
2021-02-19 11:06:05 -08:00
let program_len = program_data . len ( ) ;
( program_data , program_len )
} else if buffer_provided {
2021-01-08 09:37:57 -08:00
// Check supplied buffer account
if let Some ( account ) = rpc_client
. get_account_with_commitment ( & buffer_pubkey , config . commitment ) ?
. value
{
2022-05-11 18:05:41 -07:00
if ! bpf_loader_upgradeable ::check_id ( & account . owner ) {
return Err ( format! (
" Buffer account {buffer_pubkey} is not owned by the BPF Upgradeable Loader " ,
)
. into ( ) ) ;
2021-01-08 09:37:57 -08:00
}
2022-05-11 18:05:41 -07:00
match account . state ( ) {
Ok ( UpgradeableLoaderState ::Buffer { .. } ) = > {
// continue if buffer is initialized
}
Ok ( UpgradeableLoaderState ::Program { .. } ) = > {
return Err (
format! ( " Cannot use program account {buffer_pubkey} as buffer " ) . into ( ) ,
) ;
}
Ok ( UpgradeableLoaderState ::ProgramData { .. } ) = > {
return Err ( format! (
" Cannot use program data account {buffer_pubkey} as buffer " ,
)
. into ( ) )
}
Ok ( UpgradeableLoaderState ::Uninitialized ) = > {
return Err ( format! ( " Buffer account {buffer_pubkey} is not initialized " ) . into ( ) ) ;
}
Err ( _ ) = > {
return Err (
format! ( " Buffer account {buffer_pubkey} could not be deserialized " ) . into ( ) ,
)
}
} ;
let program_len = account
. data
. len ( )
. saturating_sub ( UpgradeableLoaderState ::size_of_buffer_metadata ( ) ) ;
( vec! [ ] , program_len )
2021-01-08 09:37:57 -08:00
} else {
2021-03-11 13:44:21 -08:00
return Err ( format! (
2022-05-11 18:05:41 -07:00
" Buffer account {buffer_pubkey} not found, was it already consumed? " ,
2021-03-11 13:44:21 -08:00
)
. into ( ) ) ;
2021-01-08 09:37:57 -08:00
}
2020-12-21 13:02:53 -08:00
} else {
2021-01-08 09:37:57 -08:00
return Err ( " Program location required if buffer not supplied " . into ( ) ) ;
2020-12-21 13:02:53 -08:00
} ;
2021-03-02 00:45:53 -08:00
let programdata_len = if let Some ( len ) = max_len {
2021-02-02 17:20:42 -08:00
if program_len > len {
return Err ( " Max length specified not large enough " . into ( ) ) ;
}
len
} else if is_final {
program_len
} else {
program_len * 2
} ;
2020-12-21 13:02:53 -08:00
let minimum_balance = rpc_client . get_minimum_balance_for_rent_exemption (
2022-05-11 18:05:41 -07:00
UpgradeableLoaderState ::size_of_programdata ( program_len ) ,
2020-12-21 13:02:53 -08:00
) ? ;
let result = if do_deploy {
2021-06-03 15:52:36 -07:00
if program_signer . is_none ( ) {
return Err (
" Initial deployments require a keypair be provided for the program id " . into ( ) ,
) ;
}
2021-01-08 09:37:57 -08:00
do_process_program_write_and_deploy (
2021-04-22 18:35:12 -07:00
rpc_client . clone ( ) ,
2020-12-21 13:02:53 -08:00
config ,
& program_data ,
2022-05-11 18:05:41 -07:00
program_len ,
2021-03-02 00:45:53 -08:00
programdata_len ,
2020-12-21 13:02:53 -08:00
minimum_balance ,
& bpf_loader_upgradeable ::id ( ) ,
2021-01-29 12:43:42 -08:00
Some ( & [ program_signer . unwrap ( ) , upgrade_authority_signer ] ) ,
2020-12-21 13:02:53 -08:00
buffer_signer ,
2021-01-08 09:37:57 -08:00
& buffer_pubkey ,
2023-01-02 22:44:22 -08:00
upgrade_authority_signer ,
2020-12-21 13:02:53 -08:00
allow_excessive_balance ,
2022-03-25 13:43:43 -07:00
skip_fee_check ,
2020-12-21 13:02:53 -08:00
)
2021-01-29 12:43:42 -08:00
} else {
2020-12-21 13:02:53 -08:00
do_process_program_upgrade (
2021-04-22 18:35:12 -07:00
rpc_client . clone ( ) ,
2020-12-21 13:02:53 -08:00
config ,
& program_data ,
2021-01-08 09:37:57 -08:00
& program_pubkey ,
2021-01-29 12:43:42 -08:00
config . signers [ upgrade_authority_signer_index ] ,
2021-01-08 09:37:57 -08:00
& buffer_pubkey ,
2020-12-21 13:02:53 -08:00
buffer_signer ,
2022-03-25 13:43:43 -07:00
skip_fee_check ,
2020-12-21 13:02:53 -08:00
)
} ;
2021-01-08 09:37:57 -08:00
if result . is_ok ( ) & & is_final {
process_set_authority (
2021-04-22 18:35:12 -07:00
& rpc_client ,
2021-01-08 09:37:57 -08:00
config ,
Some ( program_pubkey ) ,
None ,
2021-01-29 12:43:42 -08:00
Some ( upgrade_authority_signer_index ) ,
2021-01-08 09:37:57 -08:00
None ,
) ? ;
}
2020-12-21 13:02:53 -08:00
if result . is_err ( ) & & buffer_signer_index . is_none ( ) {
report_ephemeral_mnemonic ( words , mnemonic ) ;
}
result
}
2021-01-08 09:37:57 -08:00
fn process_write_buffer (
2021-04-22 18:35:12 -07:00
rpc_client : Arc < RpcClient > ,
2020-12-21 13:02:53 -08:00
config : & CliConfig ,
2021-01-08 09:37:57 -08:00
program_location : & str ,
buffer_signer_index : Option < SignerIndex > ,
buffer_pubkey : Option < Pubkey > ,
2023-01-02 23:32:04 -08:00
buffer_authority_signer_index : SignerIndex ,
2021-01-08 09:37:57 -08:00
max_len : Option < usize > ,
2022-03-25 13:43:43 -07:00
skip_fee_check : bool ,
2020-12-21 13:02:53 -08:00
) -> ProcessResult {
2021-01-08 09:37:57 -08:00
// Create ephemeral keypair to use for Buffer account, if not provided
let ( words , mnemonic , buffer_keypair ) = create_ephemeral_keypair ( ) ? ;
let ( buffer_signer , buffer_pubkey ) = if let Some ( i ) = buffer_signer_index {
( Some ( config . signers [ i ] ) , config . signers [ i ] . pubkey ( ) )
} else if let Some ( pubkey ) = buffer_pubkey {
( None , pubkey )
} else {
(
Some ( & buffer_keypair as & dyn Signer ) ,
buffer_keypair . pubkey ( ) ,
)
} ;
2023-01-02 23:32:04 -08:00
let buffer_authority = config . signers [ buffer_authority_signer_index ] ;
2021-01-08 09:37:57 -08:00
if let Some ( account ) = rpc_client
. get_account_with_commitment ( & buffer_pubkey , config . commitment ) ?
. value
{
2021-03-11 13:44:21 -08:00
if let Ok ( UpgradeableLoaderState ::Buffer { authority_address } ) = account . state ( ) {
2021-01-08 09:37:57 -08:00
if authority_address . is_none ( ) {
2022-12-06 06:30:06 -08:00
return Err ( format! ( " Buffer {buffer_pubkey} is immutable " ) . into ( ) ) ;
2021-01-08 09:37:57 -08:00
}
if authority_address ! = Some ( buffer_authority . pubkey ( ) ) {
return Err ( format! (
2021-03-11 13:44:21 -08:00
" Buffer's authority {:?} does not match authority provided {} " ,
2021-01-08 09:37:57 -08:00
authority_address ,
buffer_authority . pubkey ( )
)
. into ( ) ) ;
}
} else {
2022-12-06 06:30:06 -08:00
return Err (
format! ( " {buffer_pubkey} is not an upgradeable loader buffer account " ) . into ( ) ,
) ;
2021-01-08 09:37:57 -08:00
}
}
let program_data = read_and_verify_elf ( program_location ) ? ;
let buffer_data_len = if let Some ( len ) = max_len {
len
} else {
2021-03-02 00:45:53 -08:00
program_data . len ( )
2021-01-08 09:37:57 -08:00
} ;
let minimum_balance = rpc_client . get_minimum_balance_for_rent_exemption (
2022-05-11 07:22:59 -07:00
UpgradeableLoaderState ::size_of_programdata ( buffer_data_len ) ,
2021-01-08 09:37:57 -08:00
) ? ;
let result = do_process_program_write_and_deploy (
rpc_client ,
config ,
& program_data ,
program_data . len ( ) ,
2021-03-02 00:45:53 -08:00
program_data . len ( ) ,
2021-01-08 09:37:57 -08:00
minimum_balance ,
& bpf_loader_upgradeable ::id ( ) ,
None ,
buffer_signer ,
& buffer_pubkey ,
2023-01-02 22:44:22 -08:00
buffer_authority ,
2021-01-08 09:37:57 -08:00
true ,
2022-03-25 13:43:43 -07:00
skip_fee_check ,
2021-01-08 09:37:57 -08:00
) ;
if result . is_err ( ) & & buffer_signer_index . is_none ( ) & & buffer_signer . is_some ( ) {
report_ephemeral_mnemonic ( words , mnemonic ) ;
}
result
}
fn process_set_authority (
rpc_client : & RpcClient ,
config : & CliConfig ,
program_pubkey : Option < Pubkey > ,
buffer_pubkey : Option < Pubkey > ,
authority : Option < SignerIndex > ,
new_authority : Option < Pubkey > ,
) -> ProcessResult {
let authority_signer = if let Some ( index ) = authority {
2020-12-21 13:02:53 -08:00
config . signers [ index ]
} else {
return Err ( " Set authority requires the current authority " . into ( ) ) ;
} ;
2021-01-08 09:37:57 -08:00
trace! ( " Set a new authority " ) ;
2021-08-13 09:08:20 -07:00
let blockhash = rpc_client . get_latest_blockhash ( ) ? ;
2020-12-21 13:02:53 -08:00
2021-01-29 12:43:42 -08:00
let mut tx = if let Some ( ref pubkey ) = program_pubkey {
2021-01-08 09:37:57 -08:00
Transaction ::new_unsigned ( Message ::new (
& [ bpf_loader_upgradeable ::set_upgrade_authority (
2021-01-29 12:43:42 -08:00
pubkey ,
2021-01-08 09:37:57 -08:00
& authority_signer . pubkey ( ) ,
new_authority . as_ref ( ) ,
) ] ,
Some ( & config . signers [ 0 ] . pubkey ( ) ) ,
) )
} else if let Some ( pubkey ) = buffer_pubkey {
2021-01-29 12:43:42 -08:00
if let Some ( ref new_authority ) = new_authority {
Transaction ::new_unsigned ( Message ::new (
& [ bpf_loader_upgradeable ::set_buffer_authority (
& pubkey ,
& authority_signer . pubkey ( ) ,
new_authority ,
) ] ,
Some ( & config . signers [ 0 ] . pubkey ( ) ) ,
) )
} else {
return Err ( " Buffer authority cannot be None " . into ( ) ) ;
}
2021-01-08 09:37:57 -08:00
} else {
return Err ( " Program or Buffer not provided " . into ( ) ) ;
} ;
tx . try_sign ( & [ config . signers [ 0 ] , authority_signer ] , blockhash ) ? ;
2020-12-21 13:02:53 -08:00
rpc_client
. send_and_confirm_transaction_with_spinner_and_config (
& tx ,
config . commitment ,
RpcSendTransactionConfig {
skip_preflight : true ,
preflight_commitment : Some ( config . commitment . commitment ) ,
.. RpcSendTransactionConfig ::default ( )
} ,
)
2022-12-06 06:30:06 -08:00
. map_err ( | e | format! ( " Setting authority failed: {e} " ) ) ? ;
2020-12-21 13:02:53 -08:00
2021-02-01 09:39:37 -08:00
let authority = CliProgramAuthority {
authority : new_authority
. map ( | pubkey | pubkey . to_string ( ) )
. unwrap_or_else ( | | " none " . to_string ( ) ) ,
account_type : if program_pubkey . is_some ( ) {
CliProgramAccountType ::Program
} else {
CliProgramAccountType ::Buffer
} ,
} ;
Ok ( config . output_format . formatted_string ( & authority ) )
2021-01-08 14:43:36 -08:00
}
2022-12-15 22:59:54 -08:00
fn process_set_authority_checked (
rpc_client : & RpcClient ,
config : & CliConfig ,
program_pubkey : Pubkey ,
authority_index : SignerIndex ,
new_authority_index : SignerIndex ,
) -> ProcessResult {
let authority_signer = config . signers [ authority_index ] ;
let new_authority_signer = config . signers [ new_authority_index ] ;
trace! ( " Set a new (checked) authority " ) ;
let blockhash = rpc_client . get_latest_blockhash ( ) ? ;
let mut tx = Transaction ::new_unsigned ( Message ::new (
& [ bpf_loader_upgradeable ::set_upgrade_authority_checked (
& program_pubkey ,
& authority_signer . pubkey ( ) ,
& new_authority_signer . pubkey ( ) ,
) ] ,
Some ( & config . signers [ 0 ] . pubkey ( ) ) ,
) ) ;
tx . try_sign (
& [ config . signers [ 0 ] , authority_signer , new_authority_signer ] ,
blockhash ,
) ? ;
rpc_client
. send_and_confirm_transaction_with_spinner_and_config (
& tx ,
config . commitment ,
RpcSendTransactionConfig {
skip_preflight : false ,
preflight_commitment : Some ( config . commitment . commitment ) ,
.. RpcSendTransactionConfig ::default ( )
} ,
)
. map_err ( | e | format! ( " Setting authority failed: {e} " ) ) ? ;
let authority = CliProgramAuthority {
authority : new_authority_signer . pubkey ( ) . to_string ( ) ,
account_type : CliProgramAccountType ::Program ,
} ;
Ok ( config . output_format . formatted_string ( & authority ) )
}
2021-08-25 17:03:55 -07:00
const ACCOUNT_TYPE_SIZE : usize = 4 ;
const SLOT_SIZE : usize = size_of ::< u64 > ( ) ;
const OPTION_SIZE : usize = 1 ;
const PUBKEY_LEN : usize = 32 ;
2021-03-17 21:39:29 -07:00
fn get_buffers (
rpc_client : & RpcClient ,
authority_pubkey : Option < Pubkey > ,
2021-08-25 17:03:55 -07:00
use_lamports_unit : bool ,
) -> Result < CliUpgradeableBuffers , Box < dyn std ::error ::Error > > {
2022-07-06 21:39:03 -07:00
let mut filters = vec! [ RpcFilterType ::Memcmp ( Memcmp ::new_base58_encoded (
0 ,
& [ 1 , 0 , 0 , 0 ] ,
) ) ] ;
2021-03-17 21:39:29 -07:00
if let Some ( authority_pubkey ) = authority_pubkey {
2022-07-06 21:39:03 -07:00
filters . push ( RpcFilterType ::Memcmp ( Memcmp ::new_base58_encoded (
ACCOUNT_TYPE_SIZE ,
& [ 1 ] ,
) ) ) ;
filters . push ( RpcFilterType ::Memcmp ( Memcmp ::new_base58_encoded (
ACCOUNT_TYPE_SIZE + OPTION_SIZE ,
authority_pubkey . as_ref ( ) ,
) ) ) ;
2021-03-17 21:39:29 -07:00
}
2021-08-25 17:03:55 -07:00
let results = get_accounts_with_filter (
rpc_client ,
filters ,
ACCOUNT_TYPE_SIZE + OPTION_SIZE + PUBKEY_LEN ,
) ? ;
let mut buffers = vec! [ ] ;
for ( address , account ) in results . iter ( ) {
if let Ok ( UpgradeableLoaderState ::Buffer { authority_address } ) = account . state ( ) {
buffers . push ( CliUpgradeableBuffer {
address : address . to_string ( ) ,
authority : authority_address
. map ( | pubkey | pubkey . to_string ( ) )
. unwrap_or_else ( | | " none " . to_string ( ) ) ,
data_len : 0 ,
lamports : account . lamports ,
use_lamports_unit ,
} ) ;
} else {
2022-12-06 06:30:06 -08:00
return Err ( format! ( " Error parsing Buffer account {address} " ) . into ( ) ) ;
2021-08-25 17:03:55 -07:00
}
}
Ok ( CliUpgradeableBuffers {
buffers ,
use_lamports_unit ,
} )
}
fn get_programs (
rpc_client : & RpcClient ,
authority_pubkey : Option < Pubkey > ,
use_lamports_unit : bool ,
) -> Result < CliUpgradeablePrograms , Box < dyn std ::error ::Error > > {
2022-07-06 21:39:03 -07:00
let mut filters = vec! [ RpcFilterType ::Memcmp ( Memcmp ::new_base58_encoded (
0 ,
& [ 3 , 0 , 0 , 0 ] ,
) ) ] ;
2021-08-25 17:03:55 -07:00
if let Some ( authority_pubkey ) = authority_pubkey {
2022-07-06 21:39:03 -07:00
filters . push ( RpcFilterType ::Memcmp ( Memcmp ::new_base58_encoded (
ACCOUNT_TYPE_SIZE + SLOT_SIZE ,
& [ 1 ] ,
) ) ) ;
filters . push ( RpcFilterType ::Memcmp ( Memcmp ::new_base58_encoded (
ACCOUNT_TYPE_SIZE + SLOT_SIZE + OPTION_SIZE ,
authority_pubkey . as_ref ( ) ,
) ) ) ;
2021-08-25 17:03:55 -07:00
}
let results = get_accounts_with_filter (
rpc_client ,
filters ,
ACCOUNT_TYPE_SIZE + SLOT_SIZE + OPTION_SIZE + PUBKEY_LEN ,
) ? ;
let mut programs = vec! [ ] ;
for ( programdata_address , programdata_account ) in results . iter ( ) {
if let Ok ( UpgradeableLoaderState ::ProgramData {
slot ,
upgrade_authority_address ,
} ) = programdata_account . state ( )
{
let mut bytes = vec! [ 2 , 0 , 0 , 0 ] ;
bytes . extend_from_slice ( programdata_address . as_ref ( ) ) ;
2022-07-06 21:39:03 -07:00
let filters = vec! [ RpcFilterType ::Memcmp ( Memcmp ::new_base58_encoded ( 0 , & bytes ) ) ] ;
2021-08-25 17:03:55 -07:00
let results = get_accounts_with_filter ( rpc_client , filters , 0 ) ? ;
if results . len ( ) ! = 1 {
return Err ( format! (
2022-12-06 06:30:06 -08:00
" Error: More than one Program associated with ProgramData account {programdata_address} "
2021-08-25 17:03:55 -07:00
)
. into ( ) ) ;
}
programs . push ( CliUpgradeableProgram {
program_id : results [ 0 ] . 0. to_string ( ) ,
owner : programdata_account . owner . to_string ( ) ,
programdata_address : programdata_address . to_string ( ) ,
authority : upgrade_authority_address
. map ( | pubkey | pubkey . to_string ( ) )
. unwrap_or_else ( | | " none " . to_string ( ) ) ,
last_deploy_slot : slot ,
data_len : programdata_account . data . len ( )
2022-05-11 07:22:59 -07:00
- UpgradeableLoaderState ::size_of_programdata_metadata ( ) ,
2021-08-25 17:03:55 -07:00
lamports : programdata_account . lamports ,
use_lamports_unit ,
} ) ;
} else {
2022-12-06 06:30:06 -08:00
return Err ( format! ( " Error parsing ProgramData account {programdata_address} " ) . into ( ) ) ;
2021-08-25 17:03:55 -07:00
}
}
Ok ( CliUpgradeablePrograms {
programs ,
use_lamports_unit ,
} )
}
fn get_accounts_with_filter (
rpc_client : & RpcClient ,
filters : Vec < RpcFilterType > ,
length : usize ,
) -> Result < Vec < ( Pubkey , Account ) > , Box < dyn std ::error ::Error > > {
let results = rpc_client . get_program_accounts_with_config (
& bpf_loader_upgradeable ::id ( ) ,
RpcProgramAccountsConfig {
filters : Some ( filters ) ,
2021-03-17 21:39:29 -07:00
account_config : RpcAccountInfoConfig {
encoding : Some ( UiAccountEncoding ::Base64 ) ,
data_slice : Some ( UiDataSliceConfig { offset : 0 , length } ) ,
.. RpcAccountInfoConfig ::default ( )
} ,
2021-05-22 00:12:21 -07:00
.. RpcProgramAccountsConfig ::default ( )
2021-03-17 21:39:29 -07:00
} ,
) ? ;
Ok ( results )
}
2021-02-02 22:33:03 -08:00
fn process_show (
2021-01-08 14:43:36 -08:00
rpc_client : & RpcClient ,
config : & CliConfig ,
account_pubkey : Option < Pubkey > ,
2021-03-17 21:39:29 -07:00
authority_pubkey : Pubkey ,
2021-08-25 17:03:55 -07:00
programs : bool ,
buffers : bool ,
2021-03-17 21:39:29 -07:00
all : bool ,
use_lamports_unit : bool ,
2021-01-08 14:43:36 -08:00
) -> ProcessResult {
if let Some ( account_pubkey ) = account_pubkey {
if let Some ( account ) = rpc_client
. get_account_with_commitment ( & account_pubkey , config . commitment ) ?
. value
{
2021-03-04 11:42:15 -08:00
if account . owner = = bpf_loader ::id ( ) | | account . owner = = bpf_loader_deprecated ::id ( ) {
Ok ( config . output_format . formatted_string ( & CliProgram {
program_id : account_pubkey . to_string ( ) ,
owner : account . owner . to_string ( ) ,
data_len : account . data . len ( ) ,
} ) )
} else if account . owner = = bpf_loader_upgradeable ::id ( ) {
if let Ok ( UpgradeableLoaderState ::Program {
programdata_address ,
} ) = account . state ( )
2021-01-08 14:43:36 -08:00
{
2021-03-04 11:42:15 -08:00
if let Some ( programdata_account ) = rpc_client
. get_account_with_commitment ( & programdata_address , config . commitment ) ?
. value
2021-01-08 14:43:36 -08:00
{
2021-03-04 11:42:15 -08:00
if let Ok ( UpgradeableLoaderState ::ProgramData {
upgrade_authority_address ,
slot ,
} ) = programdata_account . state ( )
{
Ok ( config
. output_format
. formatted_string ( & CliUpgradeableProgram {
program_id : account_pubkey . to_string ( ) ,
owner : account . owner . to_string ( ) ,
programdata_address : programdata_address . to_string ( ) ,
authority : upgrade_authority_address
. map ( | pubkey | pubkey . to_string ( ) )
. unwrap_or_else ( | | " none " . to_string ( ) ) ,
last_deploy_slot : slot ,
data_len : programdata_account . data . len ( )
2022-05-11 07:22:59 -07:00
- UpgradeableLoaderState ::size_of_programdata_metadata ( ) ,
2021-08-25 17:03:55 -07:00
lamports : programdata_account . lamports ,
use_lamports_unit ,
2021-03-04 11:42:15 -08:00
} ) )
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " Program {account_pubkey} has been closed " ) . into ( ) )
2021-03-04 11:42:15 -08:00
}
2021-01-08 14:43:36 -08:00
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " Program {account_pubkey} has been closed " ) . into ( ) )
2021-03-04 11:42:15 -08:00
}
} else if let Ok ( UpgradeableLoaderState ::Buffer { authority_address } ) =
account . state ( )
{
Ok ( config
. output_format
. formatted_string ( & CliUpgradeableBuffer {
address : account_pubkey . to_string ( ) ,
authority : authority_address
. map ( | pubkey | pubkey . to_string ( ) )
. unwrap_or_else ( | | " none " . to_string ( ) ) ,
data_len : account . data . len ( )
2022-05-11 07:22:59 -07:00
- UpgradeableLoaderState ::size_of_buffer_metadata ( ) ,
2021-03-17 21:39:29 -07:00
lamports : account . lamports ,
use_lamports_unit ,
2021-03-04 11:42:15 -08:00
} ) )
} else {
2021-03-11 13:44:21 -08:00
Err ( format! (
2022-12-06 06:30:06 -08:00
" {account_pubkey} is not an upgradeable loader Buffer or Program account "
2021-03-11 13:44:21 -08:00
)
. into ( ) )
2021-01-08 14:43:36 -08:00
}
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " {account_pubkey} is not an SBF program " ) . into ( ) )
2021-01-08 14:43:36 -08:00
}
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " Unable to find the account {account_pubkey} " ) . into ( ) )
2021-01-08 14:43:36 -08:00
}
2021-08-25 17:03:55 -07:00
} else if programs {
2021-03-17 21:39:29 -07:00
let authority_pubkey = if all { None } else { Some ( authority_pubkey ) } ;
2021-08-25 17:03:55 -07:00
let programs = get_programs ( rpc_client , authority_pubkey , use_lamports_unit ) ? ;
Ok ( config . output_format . formatted_string ( & programs ) )
} else if buffers {
let authority_pubkey = if all { None } else { Some ( authority_pubkey ) } ;
let buffers = get_buffers ( rpc_client , authority_pubkey , use_lamports_unit ) ? ;
Ok ( config . output_format . formatted_string ( & buffers ) )
} else {
Err ( " Invalid parameters " . to_string ( ) . into ( ) )
2020-12-21 13:02:53 -08:00
}
}
2021-02-02 22:33:03 -08:00
fn process_dump (
2021-02-02 15:36:02 -08:00
rpc_client : & RpcClient ,
config : & CliConfig ,
account_pubkey : Option < Pubkey > ,
2021-02-02 22:33:03 -08:00
output_location : & str ,
2021-02-02 15:36:02 -08:00
) -> ProcessResult {
if let Some ( account_pubkey ) = account_pubkey {
if let Some ( account ) = rpc_client
. get_account_with_commitment ( & account_pubkey , config . commitment ) ?
. value
{
2021-03-01 18:11:45 -08:00
if account . owner = = bpf_loader ::id ( ) | | account . owner = = bpf_loader_deprecated ::id ( ) {
let mut f = File ::create ( output_location ) ? ;
f . write_all ( & account . data ) ? ;
2022-12-06 06:30:06 -08:00
Ok ( format! ( " Wrote program to {output_location} " ) )
2021-03-01 18:11:45 -08:00
} else if account . owner = = bpf_loader_upgradeable ::id ( ) {
if let Ok ( UpgradeableLoaderState ::Program {
programdata_address ,
} ) = account . state ( )
2021-02-02 15:36:02 -08:00
{
2021-03-01 18:11:45 -08:00
if let Some ( programdata_account ) = rpc_client
. get_account_with_commitment ( & programdata_address , config . commitment ) ?
. value
2021-02-02 15:36:02 -08:00
{
2021-03-01 18:11:45 -08:00
if let Ok ( UpgradeableLoaderState ::ProgramData { .. } ) =
programdata_account . state ( )
{
2022-05-11 07:22:59 -07:00
let offset = UpgradeableLoaderState ::size_of_programdata_metadata ( ) ;
2021-03-01 18:11:45 -08:00
let program_data = & programdata_account . data [ offset .. ] ;
let mut f = File ::create ( output_location ) ? ;
2021-06-18 06:34:46 -07:00
f . write_all ( program_data ) ? ;
2022-12-06 06:30:06 -08:00
Ok ( format! ( " Wrote program to {output_location} " ) )
2021-03-01 18:11:45 -08:00
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " Program {account_pubkey} has been closed " ) . into ( ) )
2021-03-01 18:11:45 -08:00
}
2021-02-02 15:36:02 -08:00
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " Program {account_pubkey} has been closed " ) . into ( ) )
2021-03-01 18:11:45 -08:00
}
} else if let Ok ( UpgradeableLoaderState ::Buffer { .. } ) = account . state ( ) {
2022-05-11 07:22:59 -07:00
let offset = UpgradeableLoaderState ::size_of_buffer_metadata ( ) ;
2021-03-01 18:11:45 -08:00
let program_data = & account . data [ offset .. ] ;
let mut f = File ::create ( output_location ) ? ;
2021-06-18 06:34:46 -07:00
f . write_all ( program_data ) ? ;
2022-12-06 06:30:06 -08:00
Ok ( format! ( " Wrote program to {output_location} " ) )
2021-03-01 18:11:45 -08:00
} else {
2021-03-11 13:44:21 -08:00
Err ( format! (
2022-12-06 06:30:06 -08:00
" {account_pubkey} is not an upgradeable loader buffer or program account "
2021-03-11 13:44:21 -08:00
)
. into ( ) )
2021-02-02 15:36:02 -08:00
}
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " {account_pubkey} is not an SBF program " ) . into ( ) )
2021-02-02 15:36:02 -08:00
}
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " Unable to find the account {account_pubkey} " ) . into ( ) )
2021-02-02 15:36:02 -08:00
}
} else {
Err ( " No account specified " . into ( ) )
}
}
2021-03-17 21:39:29 -07:00
fn close (
rpc_client : & RpcClient ,
config : & CliConfig ,
account_pubkey : & Pubkey ,
recipient_pubkey : & Pubkey ,
authority_signer : & dyn Signer ,
2021-08-24 10:05:54 -07:00
program_pubkey : Option < & Pubkey > ,
2021-03-17 21:39:29 -07:00
) -> Result < ( ) , Box < dyn std ::error ::Error > > {
2021-08-13 09:08:20 -07:00
let blockhash = rpc_client . get_latest_blockhash ( ) ? ;
2021-03-17 21:39:29 -07:00
let mut tx = Transaction ::new_unsigned ( Message ::new (
2021-08-24 10:05:54 -07:00
& [ bpf_loader_upgradeable ::close_any (
2021-06-18 06:34:46 -07:00
account_pubkey ,
recipient_pubkey ,
2021-08-24 10:05:54 -07:00
Some ( & authority_signer . pubkey ( ) ) ,
program_pubkey ,
2021-03-17 21:39:29 -07:00
) ] ,
Some ( & config . signers [ 0 ] . pubkey ( ) ) ,
) ) ;
tx . try_sign ( & [ config . signers [ 0 ] , authority_signer ] , blockhash ) ? ;
let result = rpc_client . send_and_confirm_transaction_with_spinner_and_config (
& tx ,
config . commitment ,
RpcSendTransactionConfig {
skip_preflight : true ,
preflight_commitment : Some ( config . commitment . commitment ) ,
.. RpcSendTransactionConfig ::default ( )
} ,
) ;
if let Err ( err ) = result {
if let ClientErrorKind ::TransactionError ( TransactionError ::InstructionError (
_ ,
InstructionError ::InvalidInstructionData ,
) ) = err . kind ( )
{
return Err ( " Closing a buffer account is not supported by the cluster " . into ( ) ) ;
2021-08-25 17:03:55 -07:00
} else if let ClientErrorKind ::TransactionError ( TransactionError ::InstructionError (
_ ,
InstructionError ::InvalidArgument ,
) ) = err . kind ( )
{
return Err ( " Closing a program account is not supported by the cluster " . into ( ) ) ;
2021-03-17 21:39:29 -07:00
} else {
2022-12-06 06:30:06 -08:00
return Err ( format! ( " Close failed: {err} " ) . into ( ) ) ;
2021-03-17 21:39:29 -07:00
}
}
Ok ( ( ) )
}
fn process_close (
rpc_client : & RpcClient ,
config : & CliConfig ,
account_pubkey : Option < Pubkey > ,
recipient_pubkey : Pubkey ,
authority_index : SignerIndex ,
use_lamports_unit : bool ,
2022-08-13 00:36:14 -07:00
bypass_warning : bool ,
2021-03-17 21:39:29 -07:00
) -> ProcessResult {
let authority_signer = config . signers [ authority_index ] ;
if let Some ( account_pubkey ) = account_pubkey {
if let Some ( account ) = rpc_client
. get_account_with_commitment ( & account_pubkey , config . commitment ) ?
. value
{
2021-08-24 10:05:54 -07:00
match account . state ( ) {
Ok ( UpgradeableLoaderState ::Buffer { authority_address } ) = > {
if authority_address ! = Some ( authority_signer . pubkey ( ) ) {
return Err ( format! (
" Buffer account authority {:?} does not match {:?} " ,
authority_address ,
Some ( authority_signer . pubkey ( ) )
)
. into ( ) ) ;
} else {
close (
rpc_client ,
config ,
& account_pubkey ,
& recipient_pubkey ,
authority_signer ,
None ,
) ? ;
}
2021-08-25 17:03:55 -07:00
Ok ( config
. output_format
. formatted_string ( & CliUpgradeableBuffers {
buffers : vec ! [ CliUpgradeableBuffer {
address : account_pubkey . to_string ( ) ,
authority : authority_address
. map ( | pubkey | pubkey . to_string ( ) )
. unwrap_or_else ( | | " none " . to_string ( ) ) ,
data_len : 0 ,
lamports : account . lamports ,
use_lamports_unit ,
} ] ,
use_lamports_unit ,
} ) )
2021-08-24 10:05:54 -07:00
}
Ok ( UpgradeableLoaderState ::Program {
programdata_address : programdata_pubkey ,
} ) = > {
if let Some ( account ) = rpc_client
. get_account_with_commitment ( & programdata_pubkey , config . commitment ) ?
. value
{
if let Ok ( UpgradeableLoaderState ::ProgramData {
slot : _ ,
upgrade_authority_address : authority_pubkey ,
} ) = account . state ( )
{
if authority_pubkey ! = Some ( authority_signer . pubkey ( ) ) {
2022-06-21 13:26:51 -07:00
Err ( format! (
2021-08-24 10:05:54 -07:00
" Program authority {:?} does not match {:?} " ,
authority_pubkey ,
Some ( authority_signer . pubkey ( ) )
)
2022-06-21 13:26:51 -07:00
. into ( ) )
2021-08-24 10:05:54 -07:00
} else {
2022-08-13 00:36:14 -07:00
if ! bypass_warning {
return Err ( String ::from ( CLOSE_PROGRAM_WARNING ) . into ( ) ) ;
}
2021-08-24 10:05:54 -07:00
close (
rpc_client ,
config ,
& programdata_pubkey ,
& recipient_pubkey ,
authority_signer ,
Some ( & account_pubkey ) ,
) ? ;
2021-08-25 17:03:55 -07:00
Ok ( config . output_format . formatted_string (
2021-08-24 10:05:54 -07:00
& CliUpgradeableProgramClosed {
program_id : account_pubkey . to_string ( ) ,
lamports : account . lamports ,
use_lamports_unit ,
} ,
2021-08-25 17:03:55 -07:00
) )
2021-08-24 10:05:54 -07:00
}
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " Program {account_pubkey} has been closed " ) . into ( ) )
2021-08-24 10:05:54 -07:00
}
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " Program {account_pubkey} has been closed " ) . into ( ) )
2021-08-24 10:05:54 -07:00
}
}
2022-12-06 06:30:06 -08:00
_ = > Err ( format! ( " {account_pubkey} is not a Program or Buffer account " ) . into ( ) ) ,
2021-03-17 21:39:29 -07:00
}
} else {
2022-12-06 06:30:06 -08:00
Err ( format! ( " Unable to find the account {account_pubkey} " ) . into ( ) )
2021-03-17 21:39:29 -07:00
}
} else {
2021-08-25 17:03:55 -07:00
let buffers = get_buffers (
rpc_client ,
Some ( authority_signer . pubkey ( ) ) ,
use_lamports_unit ,
) ? ;
2021-03-17 21:39:29 -07:00
2021-08-25 17:03:55 -07:00
let mut closed = vec! [ ] ;
for buffer in buffers . buffers . iter ( ) {
2021-03-17 21:39:29 -07:00
if close (
rpc_client ,
config ,
2021-08-25 17:03:55 -07:00
& Pubkey ::from_str ( & buffer . address ) ? ,
2021-03-17 21:39:29 -07:00
& recipient_pubkey ,
authority_signer ,
2021-08-24 10:05:54 -07:00
None ,
2021-03-17 21:39:29 -07:00
)
. is_ok ( )
{
2021-08-25 17:03:55 -07:00
closed . push ( buffer . clone ( ) ) ;
2021-03-17 21:39:29 -07:00
}
}
2021-08-25 17:03:55 -07:00
Ok ( config
. output_format
. formatted_string ( & CliUpgradeableBuffers {
buffers : closed ,
use_lamports_unit ,
} ) )
2021-03-17 21:39:29 -07:00
}
}
2021-09-07 10:20:17 -07:00
fn calculate_max_chunk_size < F > ( create_msg : & F ) -> usize
where
F : Fn ( u32 , Vec < u8 > ) -> Message ,
{
let baseline_msg = create_msg ( 0 , Vec ::new ( ) ) ;
let tx_size = bincode ::serialized_size ( & Transaction {
signatures : vec ! [
Signature ::default ( ) ;
baseline_msg . header . num_required_signatures as usize
] ,
message : baseline_msg ,
} )
. unwrap ( ) as usize ;
// add 1 byte buffer to account for shortvec encoding
PACKET_DATA_SIZE . saturating_sub ( tx_size ) . saturating_sub ( 1 )
}
2020-12-21 13:02:53 -08:00
#[ allow(clippy::too_many_arguments) ]
2021-01-08 09:37:57 -08:00
fn do_process_program_write_and_deploy (
2021-04-22 18:35:12 -07:00
rpc_client : Arc < RpcClient > ,
2020-12-21 13:02:53 -08:00
config : & CliConfig ,
program_data : & [ u8 ] ,
2022-05-11 18:05:41 -07:00
program_len : usize ,
2021-03-02 00:45:53 -08:00
programdata_len : usize ,
2020-12-21 13:02:53 -08:00
minimum_balance : u64 ,
loader_id : & Pubkey ,
2021-01-29 12:43:42 -08:00
program_signers : Option < & [ & dyn Signer ] > ,
2021-01-08 09:37:57 -08:00
buffer_signer : Option < & dyn Signer > ,
buffer_pubkey : & Pubkey ,
2023-01-02 22:44:22 -08:00
buffer_authority_signer : & dyn Signer ,
2020-12-21 13:02:53 -08:00
allow_excessive_balance : bool ,
2022-03-25 13:43:43 -07:00
skip_fee_check : bool ,
2020-12-21 13:02:53 -08:00
) -> ProcessResult {
2021-10-29 13:52:59 -07:00
let blockhash = rpc_client . get_latest_blockhash ( ) ? ;
2020-12-21 13:02:53 -08:00
// Initialize buffer account or complete if already partially initialized
2023-01-02 22:44:22 -08:00
let ( initial_instructions , balance_needed ) = if let Some ( account ) = rpc_client
. get_account_with_commitment ( buffer_pubkey , config . commitment ) ?
. value
{
complete_partial_program_init (
loader_id ,
& config . signers [ 0 ] . pubkey ( ) ,
buffer_pubkey ,
& account ,
if loader_id = = & bpf_loader_upgradeable ::id ( ) {
UpgradeableLoaderState ::size_of_buffer ( program_len )
2021-01-08 09:37:57 -08:00
} else {
2023-01-02 22:44:22 -08:00
program_len
} ,
minimum_balance ,
allow_excessive_balance ,
) ?
} else if loader_id = = & bpf_loader_upgradeable ::id ( ) {
(
bpf_loader_upgradeable ::create_buffer (
& config . signers [ 0 ] . pubkey ( ) ,
buffer_pubkey ,
& buffer_authority_signer . pubkey ( ) ,
minimum_balance ,
program_len ,
) ? ,
minimum_balance ,
)
} else {
(
vec! [ system_instruction ::create_account (
& config . signers [ 0 ] . pubkey ( ) ,
buffer_pubkey ,
minimum_balance ,
program_len as u64 ,
loader_id ,
) ] ,
minimum_balance ,
)
} ;
let initial_message = if ! initial_instructions . is_empty ( ) {
Some ( Message ::new_with_blockhash (
& initial_instructions ,
Some ( & config . signers [ 0 ] . pubkey ( ) ) ,
& blockhash ,
) )
} else {
None
} ;
2020-12-21 13:02:53 -08:00
2023-01-02 22:44:22 -08:00
// Create and add write messages
let payer_pubkey = config . signers [ 0 ] . pubkey ( ) ;
let create_msg = | offset : u32 , bytes : Vec < u8 > | {
let instruction = if loader_id = = & bpf_loader_upgradeable ::id ( ) {
bpf_loader_upgradeable ::write (
buffer_pubkey ,
& buffer_authority_signer . pubkey ( ) ,
offset ,
bytes ,
)
2020-12-21 13:02:53 -08:00
} else {
2023-01-02 22:44:22 -08:00
loader_instruction ::write ( buffer_pubkey , loader_id , offset , bytes )
2020-12-21 13:02:53 -08:00
} ;
2023-01-02 22:44:22 -08:00
Message ::new_with_blockhash ( & [ instruction ] , Some ( & payer_pubkey ) , & blockhash )
} ;
2021-01-08 09:37:57 -08:00
2023-01-02 22:44:22 -08:00
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 ( ) ) ) ;
2020-12-21 13:02:53 -08:00
}
// Create and add final message
2021-01-29 12:43:42 -08:00
let final_message = if let Some ( program_signers ) = program_signers {
2021-01-08 09:37:57 -08:00
let message = if loader_id = = & bpf_loader_upgradeable ::id ( ) {
2021-10-29 13:52:59 -07:00
Message ::new_with_blockhash (
2021-01-08 09:37:57 -08:00
& bpf_loader_upgradeable ::deploy_with_max_program_len (
& config . signers [ 0 ] . pubkey ( ) ,
2021-01-29 12:43:42 -08:00
& program_signers [ 0 ] . pubkey ( ) ,
2021-01-08 09:37:57 -08:00
buffer_pubkey ,
2021-01-29 12:43:42 -08:00
& program_signers [ 1 ] . pubkey ( ) ,
2021-01-08 09:37:57 -08:00
rpc_client . get_minimum_balance_for_rent_exemption (
2022-05-11 07:22:59 -07:00
UpgradeableLoaderState ::size_of_program ( ) ,
2021-01-08 09:37:57 -08:00
) ? ,
2021-03-02 00:45:53 -08:00
programdata_len ,
2020-12-21 13:02:53 -08:00
) ? ,
2021-01-08 09:37:57 -08:00
Some ( & config . signers [ 0 ] . pubkey ( ) ) ,
2021-10-29 13:52:59 -07:00
& blockhash ,
2021-01-08 09:37:57 -08:00
)
} else {
2021-10-29 13:52:59 -07:00
Message ::new_with_blockhash (
2021-06-18 06:34:46 -07:00
& [ loader_instruction ::finalize ( buffer_pubkey , loader_id ) ] ,
2021-01-08 09:37:57 -08:00
Some ( & config . signers [ 0 ] . pubkey ( ) ) ,
2021-10-29 13:52:59 -07:00
& blockhash ,
2021-01-08 09:37:57 -08:00
)
} ;
Some ( message )
2020-12-21 13:02:53 -08:00
} else {
2021-01-08 09:37:57 -08:00
None
2020-12-21 13:02:53 -08:00
} ;
2022-03-25 13:43:43 -07:00
if ! skip_fee_check {
2022-06-02 02:54:26 -07:00
check_payer (
& rpc_client ,
config ,
balance_needed ,
& initial_message ,
& write_messages ,
& final_message ,
) ? ;
2022-03-25 13:43:43 -07:00
}
2020-12-21 13:02:53 -08:00
send_deploy_messages (
rpc_client ,
config ,
& initial_message ,
& write_messages ,
& final_message ,
buffer_signer ,
2023-01-02 22:44:22 -08:00
Some ( buffer_authority_signer ) ,
2021-01-29 12:43:42 -08:00
program_signers ,
2020-12-21 13:02:53 -08:00
) ? ;
2021-01-29 12:43:42 -08:00
if let Some ( program_signers ) = program_signers {
2021-02-01 09:39:37 -08:00
let program_id = CliProgramId {
program_id : program_signers [ 0 ] . pubkey ( ) . to_string ( ) ,
} ;
Ok ( config . output_format . formatted_string ( & program_id ) )
2021-01-08 09:37:57 -08:00
} else {
2021-02-01 09:39:37 -08:00
let buffer = CliProgramBuffer {
buffer : buffer_pubkey . to_string ( ) ,
} ;
Ok ( config . output_format . formatted_string ( & buffer ) )
2021-01-08 09:37:57 -08:00
}
2020-12-21 13:02:53 -08:00
}
fn do_process_program_upgrade (
2021-04-22 18:35:12 -07:00
rpc_client : Arc < RpcClient > ,
2020-12-21 13:02:53 -08:00
config : & CliConfig ,
program_data : & [ u8 ] ,
2021-01-08 09:37:57 -08:00
program_id : & Pubkey ,
2020-12-21 13:02:53 -08:00
upgrade_authority : & dyn Signer ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : & Pubkey ,
buffer_signer : Option < & dyn Signer > ,
2022-03-25 13:43:43 -07:00
skip_fee_check : bool ,
2020-12-21 13:02:53 -08:00
) -> ProcessResult {
let loader_id = bpf_loader_upgradeable ::id ( ) ;
let data_len = program_data . len ( ) ;
let minimum_balance = rpc_client . get_minimum_balance_for_rent_exemption (
2022-05-11 07:22:59 -07:00
UpgradeableLoaderState ::size_of_programdata ( data_len ) ,
2020-12-21 13:02:53 -08:00
) ? ;
// Build messages to calculate fees
2021-10-29 13:52:59 -07:00
let blockhash = rpc_client . get_latest_blockhash ( ) ? ;
2020-12-21 13:02:53 -08:00
2021-01-08 09:37:57 -08:00
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 (
& loader_id ,
& config . signers [ 0 ] . pubkey ( ) ,
& buffer_signer . pubkey ( ) ,
& account ,
2022-05-11 07:22:59 -07:00
UpgradeableLoaderState ::size_of_buffer ( data_len ) ,
2021-01-08 09:37:57 -08:00
minimum_balance ,
true ,
) ?
} else {
(
bpf_loader_upgradeable ::create_buffer (
& config . signers [ 0 ] . pubkey ( ) ,
buffer_pubkey ,
2021-01-29 12:43:42 -08:00
& upgrade_authority . pubkey ( ) ,
2021-01-08 09:37:57 -08:00
minimum_balance ,
data_len ,
) ? ,
minimum_balance ,
)
} ;
2020-12-21 13:02:53 -08:00
2021-01-08 09:37:57 -08:00
let initial_message = if ! initial_instructions . is_empty ( ) {
2021-10-29 13:52:59 -07:00
Some ( Message ::new_with_blockhash (
2021-01-08 09:37:57 -08:00
& initial_instructions ,
Some ( & config . signers [ 0 ] . pubkey ( ) ) ,
2021-10-29 13:52:59 -07:00
& blockhash ,
2021-01-08 09:37:57 -08:00
) )
} else {
None
} ;
2021-09-07 10:20:17 -07:00
let buffer_signer_pubkey = buffer_signer . pubkey ( ) ;
let upgrade_authority_pubkey = upgrade_authority . pubkey ( ) ;
let payer_pubkey = config . signers [ 0 ] . pubkey ( ) ;
let create_msg = | offset : u32 , bytes : Vec < u8 > | {
2021-01-08 09:37:57 -08:00
let instruction = bpf_loader_upgradeable ::write (
2021-09-07 10:20:17 -07:00
& buffer_signer_pubkey ,
& upgrade_authority_pubkey ,
offset ,
bytes ,
2021-01-08 09:37:57 -08:00
) ;
2021-10-29 13:52:59 -07:00
Message ::new_with_blockhash ( & [ instruction ] , Some ( & payer_pubkey ) , & blockhash )
2021-09-07 10:20:17 -07:00
} ;
// 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 ( ) ) ) ;
2021-01-08 09:37:57 -08:00
}
2023-01-02 22:44:22 -08:00
( initial_message , write_messages , balance_needed )
2021-01-08 09:37:57 -08:00
} else {
2023-01-02 22:44:22 -08:00
( None , vec! [ ] , 0 )
2021-01-08 09:37:57 -08:00
} ;
2020-12-21 13:02:53 -08:00
// Create and add final message
2021-10-29 13:52:59 -07:00
let final_message = Message ::new_with_blockhash (
2020-12-21 13:02:53 -08:00
& [ bpf_loader_upgradeable ::upgrade (
2021-06-18 06:34:46 -07:00
program_id ,
buffer_pubkey ,
2020-12-21 13:02:53 -08:00
& upgrade_authority . pubkey ( ) ,
& config . signers [ 0 ] . pubkey ( ) ,
) ] ,
Some ( & config . signers [ 0 ] . pubkey ( ) ) ,
2021-10-29 13:52:59 -07:00
& blockhash ,
2020-12-21 13:02:53 -08:00
) ;
2022-06-02 02:54:26 -07:00
let final_message = Some ( final_message ) ;
2020-12-21 13:02:53 -08:00
2022-03-25 13:43:43 -07:00
if ! skip_fee_check {
2022-06-02 02:54:26 -07:00
check_payer (
& rpc_client ,
config ,
balance_needed ,
& initial_message ,
& write_messages ,
& final_message ,
) ? ;
2022-03-25 13:43:43 -07:00
}
2020-12-21 13:02:53 -08:00
send_deploy_messages (
rpc_client ,
config ,
& initial_message ,
& write_messages ,
2022-06-02 02:54:26 -07:00
& final_message ,
2020-12-21 13:02:53 -08:00
buffer_signer ,
2021-01-08 09:37:57 -08:00
Some ( upgrade_authority ) ,
2021-01-29 12:43:42 -08:00
Some ( & [ upgrade_authority ] ) ,
2020-12-21 13:02:53 -08:00
) ? ;
2021-02-01 09:39:37 -08:00
let program_id = CliProgramId {
program_id : program_id . to_string ( ) ,
} ;
Ok ( config . output_format . formatted_string ( & program_id ) )
2020-12-21 13:02:53 -08:00
}
fn read_and_verify_elf ( program_location : & str ) -> Result < Vec < u8 > , Box < dyn std ::error ::Error > > {
let mut file = File ::open ( program_location )
2022-12-06 06:30:06 -08:00
. map_err ( | err | format! ( " Unable to open program file: {err} " ) ) ? ;
2020-12-21 13:02:53 -08:00
let mut program_data = Vec ::new ( ) ;
file . read_to_end ( & mut program_data )
2022-12-06 06:30:06 -08:00
. map_err ( | err | format! ( " Unable to read program file: {err} " ) ) ? ;
2022-07-15 00:31:34 -07:00
let mut transaction_context = TransactionContext ::new ( Vec ::new ( ) , Some ( Rent ::default ( ) ) , 1 , 1 ) ;
2022-10-18 01:22:39 -07:00
let invoke_context = InvokeContext ::new_mock ( & mut transaction_context , & [ ] ) ;
2020-12-21 13:02:53 -08:00
// Verify the program
2022-12-11 23:47:09 -08:00
let loader = create_loader (
& invoke_context . feature_set ,
& ComputeBudget ::default ( ) ,
true ,
true ,
false ,
2020-12-21 13:02:53 -08:00
)
2022-12-11 23:47:09 -08:00
. unwrap ( ) ;
let executable = Executable ::< InvokeContext > ::from_elf ( & program_data , loader )
. map_err ( | err | format! ( " ELF error: {err} " ) ) ? ;
2020-12-21 13:02:53 -08:00
2022-11-15 06:21:11 -08:00
let _ = VerifiedExecutable ::< RequisiteVerifier , InvokeContext > ::from_executable ( executable )
2022-12-06 06:30:06 -08:00
. map_err ( | err | format! ( " ELF error: {err} " ) ) ? ;
2022-06-07 04:45:07 -07:00
2020-12-21 13:02:53 -08:00
Ok ( program_data )
}
fn complete_partial_program_init (
loader_id : & Pubkey ,
payer_pubkey : & Pubkey ,
elf_pubkey : & Pubkey ,
account : & Account ,
account_data_len : usize ,
minimum_balance : u64 ,
allow_excessive_balance : bool ,
) -> Result < ( Vec < Instruction > , u64 ) , Box < dyn std ::error ::Error > > {
let mut instructions : Vec < Instruction > = vec! [ ] ;
let mut balance_needed = 0 ;
if account . executable {
return Err ( " Buffer account is already executable " . into ( ) ) ;
}
if account . owner ! = * loader_id & & ! system_program ::check_id ( & account . owner ) {
2021-09-30 19:47:26 -07:00
return Err ( " Buffer account passed is already in use by another program " . into ( ) ) ;
}
if ! account . data . is_empty ( ) & & account . data . len ( ) < account_data_len {
return Err (
" Buffer account passed is not large enough, may have been for a different deploy? "
. into ( ) ,
) ;
2020-12-21 13:02:53 -08:00
}
if account . data . is_empty ( ) & & system_program ::check_id ( & account . owner ) {
instructions . push ( system_instruction ::allocate (
elf_pubkey ,
account_data_len as u64 ,
) ) ;
2021-11-11 15:43:35 -08:00
instructions . push ( system_instruction ::assign ( elf_pubkey , loader_id ) ) ;
2021-09-29 09:27:18 -07:00
if account . lamports < minimum_balance {
let balance = minimum_balance - account . lamports ;
instructions . push ( system_instruction ::transfer (
payer_pubkey ,
elf_pubkey ,
balance ,
) ) ;
balance_needed = balance ;
} else if account . lamports > minimum_balance
& & system_program ::check_id ( & account . owner )
& & ! allow_excessive_balance
{
return Err ( format! (
" Buffer account has a balance: {:?}; it may already be in use " ,
Sol ( account . lamports )
)
. into ( ) ) ;
}
2020-12-21 13:02:53 -08:00
}
Ok ( ( instructions , balance_needed ) )
}
fn check_payer (
rpc_client : & RpcClient ,
config : & CliConfig ,
balance_needed : u64 ,
2022-06-02 02:54:26 -07:00
initial_message : & Option < Message > ,
2023-01-02 22:44:22 -08:00
write_messages : & [ Message ] ,
2022-06-02 02:54:26 -07:00
final_message : & Option < Message > ,
2020-12-21 13:02:53 -08:00
) -> Result < ( ) , Box < dyn std ::error ::Error > > {
2022-06-02 02:54:26 -07:00
let mut fee = 0 ;
if let Some ( message ) = initial_message {
fee + = rpc_client . get_fee_for_message ( message ) ? ;
}
2023-01-02 22:44:22 -08:00
if ! write_messages . is_empty ( ) {
2022-06-02 02:54:26 -07:00
// Assume all write messages cost the same
if let Some ( message ) = write_messages . get ( 0 ) {
fee + = rpc_client . get_fee_for_message ( message ) ? * ( write_messages . len ( ) as u64 ) ;
}
}
if let Some ( message ) = final_message {
fee + = rpc_client . get_fee_for_message ( message ) ? ;
}
check_account_for_spend_and_fee_with_commitment (
2020-12-21 13:02:53 -08:00
rpc_client ,
& config . signers [ 0 ] . pubkey ( ) ,
balance_needed ,
2022-06-02 02:54:26 -07:00
fee ,
2020-12-21 13:02:53 -08:00
config . commitment ,
) ? ;
Ok ( ( ) )
}
fn send_deploy_messages (
2021-04-22 18:35:12 -07:00
rpc_client : Arc < RpcClient > ,
2020-12-21 13:02:53 -08:00
config : & CliConfig ,
initial_message : & Option < Message > ,
2023-01-02 22:44:22 -08:00
write_messages : & [ Message ] ,
2021-01-08 09:37:57 -08:00
final_message : & Option < Message > ,
initial_signer : Option < & dyn Signer > ,
write_signer : Option < & dyn Signer > ,
2021-01-29 12:43:42 -08:00
final_signers : Option < & [ & dyn Signer ] > ,
2020-12-21 13:02:53 -08:00
) -> Result < ( ) , Box < dyn std ::error ::Error > > {
let payer_signer = config . signers [ 0 ] ;
2021-01-29 12:43:42 -08:00
2020-12-21 13:02:53 -08:00
if let Some ( message ) = initial_message {
2021-01-08 09:37:57 -08:00
if let Some ( initial_signer ) = initial_signer {
trace! ( " Preparing the required accounts " ) ;
2021-08-13 09:08:20 -07:00
let blockhash = rpc_client . get_latest_blockhash ( ) ? ;
2021-01-08 09:37:57 -08:00
let mut initial_transaction = Transaction ::new_unsigned ( message . clone ( ) ) ;
// Most of the initial_transaction combinations require both the fee-payer and new program
// account to sign the transaction. One (transfer) only requires the fee-payer signature.
// This check is to ensure signing does not fail on a KeypairPubkeyMismatch error from an
// extraneous signature.
if message . header . num_required_signatures = = 2 {
initial_transaction . try_sign ( & [ payer_signer , initial_signer ] , blockhash ) ? ;
} else {
initial_transaction . try_sign ( & [ payer_signer ] , blockhash ) ? ;
}
2021-01-19 14:33:03 -08:00
let result = rpc_client . send_and_confirm_transaction_with_spinner ( & initial_transaction ) ;
2021-06-18 06:34:46 -07:00
log_instruction_custom_error ::< SystemError > ( result , config )
2022-12-06 06:30:06 -08:00
. map_err ( | err | format! ( " Account allocation failed: {err} " ) ) ? ;
2020-12-21 13:02:53 -08:00
} else {
2021-01-08 09:37:57 -08:00
return Err ( " Buffer account not created yet, must provide a key pair " . into ( ) ) ;
2020-12-21 13:02:53 -08:00
}
}
2023-01-02 22:44:22 -08:00
if ! write_messages . is_empty ( ) {
2021-01-08 09:37:57 -08:00
if let Some ( write_signer ) = write_signer {
trace! ( " Writing program data " ) ;
2022-08-25 09:26:12 -07:00
let connection_cache = if config . use_quic {
2023-02-03 17:47:50 -08:00
ConnectionCache ::new ( 1 )
2022-08-25 09:26:12 -07:00
} else {
2023-02-03 17:47:50 -08:00
ConnectionCache ::with_udp ( 1 )
2022-08-25 09:26:12 -07:00
} ;
2022-06-08 04:57:12 -07:00
let tpu_client = TpuClient ::new_with_connection_cache (
2021-04-22 18:35:12 -07:00
rpc_client . clone ( ) ,
& config . websocket_url ,
2021-10-26 13:54:26 -07:00
TpuClientConfig ::default ( ) ,
2023-02-03 17:47:50 -08:00
Arc ::new ( connection_cache . into ( ) ) ,
2021-10-26 13:54:26 -07:00
) ? ;
let transaction_errors = tpu_client
. send_and_confirm_messages_with_spinner (
write_messages ,
& [ payer_signer , write_signer ] ,
)
2022-12-06 06:30:06 -08:00
. map_err ( | err | format! ( " Data writes to account failed: {err} " ) ) ?
2021-10-26 13:54:26 -07:00
. into_iter ( )
. flatten ( )
. collect ::< Vec < _ > > ( ) ;
2021-09-03 22:46:01 -07:00
if ! transaction_errors . is_empty ( ) {
for transaction_error in & transaction_errors {
error! ( " {:?} " , transaction_error ) ;
}
return Err (
format! ( " {} write transactions failed " , transaction_errors . len ( ) ) . into ( ) ,
) ;
}
2021-01-08 09:37:57 -08:00
}
}
if let Some ( message ) = final_message {
2021-01-29 12:43:42 -08:00
if let Some ( final_signers ) = final_signers {
2021-01-08 09:37:57 -08:00
trace! ( " Deploying program " ) ;
2021-08-13 09:08:20 -07:00
let blockhash = rpc_client . get_latest_blockhash ( ) ? ;
2021-01-08 09:37:57 -08:00
let mut final_tx = Transaction ::new_unsigned ( message . clone ( ) ) ;
2021-01-29 12:43:42 -08:00
let mut signers = final_signers . to_vec ( ) ;
signers . push ( payer_signer ) ;
final_tx . try_sign ( & signers , blockhash ) ? ;
2021-01-08 09:37:57 -08:00
rpc_client
. send_and_confirm_transaction_with_spinner_and_config (
& final_tx ,
config . commitment ,
RpcSendTransactionConfig {
skip_preflight : true ,
preflight_commitment : Some ( config . commitment . commitment ) ,
.. RpcSendTransactionConfig ::default ( )
} ,
)
2022-12-06 06:30:06 -08:00
. map_err ( | e | format! ( " Deploying program failed: {e} " ) ) ? ;
2021-01-08 09:37:57 -08:00
}
}
2020-12-21 13:02:53 -08:00
Ok ( ( ) )
}
fn create_ephemeral_keypair (
) -> Result < ( usize , bip39 ::Mnemonic , Keypair ) , Box < dyn std ::error ::Error > > {
const WORDS : usize = 12 ;
let mnemonic = Mnemonic ::new ( MnemonicType ::for_word_count ( WORDS ) ? , Language ::English ) ;
let seed = Seed ::new ( & mnemonic , " " ) ;
let new_keypair = keypair_from_seed ( seed . as_bytes ( ) ) ? ;
Ok ( ( WORDS , mnemonic , new_keypair ) )
}
fn report_ephemeral_mnemonic ( words : usize , mnemonic : bip39 ::Mnemonic ) {
let phrase : & str = mnemonic . phrase ( ) ;
let divider = String ::from_utf8 ( vec! [ b '=' ; phrase . len ( ) ] ) . unwrap ( ) ;
2022-12-06 06:30:06 -08:00
eprintln! ( " {divider} \n Recover the intermediate account's ephemeral keypair file with " ) ;
eprintln! ( " `solana-keygen recover` and the following {words} -word seed phrase: " ) ;
eprintln! ( " {divider} \n {phrase} \n {divider} " ) ;
2021-10-25 09:53:21 -07:00
eprintln! ( " To resume a deploy, pass the recovered keypair as the " ) ;
2022-04-17 01:10:22 -07:00
eprintln! ( " [BUFFER_SIGNER] to `solana program deploy` or `solana program write-buffer'. " ) ;
2021-03-17 21:39:29 -07:00
eprintln! ( " Or to recover the account's lamports, pass it as the " ) ;
2022-12-06 06:30:06 -08:00
eprintln! ( " [BUFFER_ACCOUNT_ADDRESS] argument to `solana program close`. \n {divider} " ) ;
2020-12-21 13:02:53 -08:00
}
#[ cfg(test) ]
mod tests {
2021-12-03 09:00:31 -08:00
use {
super ::* ,
crate ::{
clap_app ::get_clap_app ,
cli ::{ parse_command , process_command } ,
} ,
serde_json ::Value ,
solana_cli_output ::OutputFormat ,
solana_sdk ::signature ::write_keypair_file ,
2021-07-28 08:43:32 -07:00
} ;
2020-12-21 13:02:53 -08:00
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 ( ) {
2021-07-28 08:43:32 -07:00
let test_commands = get_clap_app ( " test " , " desc " , " version " ) ;
2020-12-21 13:02:53 -08:00
let default_keypair = Keypair ::new ( ) ;
let keypair_file = make_tmp_path ( " keypair_file " ) ;
write_keypair_file ( & default_keypair , & keypair_file ) . unwrap ( ) ;
2021-05-28 00:42:55 -07:00
let default_signer = DefaultSigner ::new ( " " , & keypair_file ) ;
2020-12-21 13:02:53 -08:00
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2020-12-21 13:02:53 -08:00
" test " ,
" program " ,
" deploy " ,
" /Users/test/program.so " ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2020-12-21 13:02:53 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Deploy {
2021-01-08 09:37:57 -08:00
program_location : Some ( " /Users/test/program.so " . to_string ( ) ) ,
2020-12-21 13:02:53 -08:00
buffer_signer_index : None ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : None ,
2020-12-21 13:02:53 -08:00
program_signer_index : None ,
program_pubkey : None ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
is_final : false ,
2020-12-21 13:02:53 -08:00
max_len : None ,
allow_excessive_balance : false ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2020-12-21 13:02:53 -08:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2020-12-21 13:02:53 -08:00
" test " ,
" program " ,
" deploy " ,
" /Users/test/program.so " ,
" --max-len " ,
" 42 " ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2020-12-21 13:02:53 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Deploy {
2021-01-08 09:37:57 -08:00
program_location : Some ( " /Users/test/program.so " . to_string ( ) ) ,
2020-12-21 13:02:53 -08:00
buffer_signer_index : None ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : None ,
2020-12-21 13:02:53 -08:00
program_signer_index : None ,
program_pubkey : None ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
is_final : false ,
2020-12-21 13:02:53 -08:00
max_len : Some ( 42 ) ,
allow_excessive_balance : false ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2020-12-21 13:02:53 -08:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
2021-01-08 09:37:57 -08:00
let buffer_keypair = Keypair ::new ( ) ;
let buffer_keypair_file = make_tmp_path ( " buffer_keypair_file " ) ;
write_keypair_file ( & buffer_keypair , & buffer_keypair_file ) . unwrap ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2020-12-21 13:02:53 -08:00
" test " ,
" program " ,
" deploy " ,
" --buffer " ,
2021-01-08 09:37:57 -08:00
& buffer_keypair_file ,
2020-12-21 13:02:53 -08:00
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2020-12-21 13:02:53 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Deploy {
2021-01-08 09:37:57 -08:00
program_location : None ,
2020-12-21 13:02:53 -08:00
buffer_signer_index : Some ( 1 ) ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : Some ( buffer_keypair . pubkey ( ) ) ,
2020-12-21 13:02:53 -08:00
program_signer_index : None ,
program_pubkey : None ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
is_final : false ,
2020-12-21 13:02:53 -08:00
max_len : None ,
allow_excessive_balance : false ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2020-12-21 13:02:53 -08:00
} ) ,
signers : vec ! [
read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ,
2021-01-08 09:37:57 -08:00
read_keypair_file ( & buffer_keypair_file ) . unwrap ( ) . into ( ) ,
2020-12-21 13:02:53 -08:00
] ,
}
) ;
2021-01-08 09:37:57 -08:00
let program_pubkey = Pubkey ::new_unique ( ) ;
2020-12-21 13:02:53 -08:00
let test = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" deploy " ,
" /Users/test/program.so " ,
" --program-id " ,
2021-01-08 09:37:57 -08:00
& program_pubkey . to_string ( ) ,
2020-12-21 13:02:53 -08:00
] ) ;
assert_eq! (
parse_command ( & test , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Deploy {
2021-01-08 09:37:57 -08:00
program_location : Some ( " /Users/test/program.so " . to_string ( ) ) ,
2020-12-21 13:02:53 -08:00
buffer_signer_index : None ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : None ,
2020-12-21 13:02:53 -08:00
program_signer_index : None ,
2021-01-08 09:37:57 -08:00
program_pubkey : Some ( program_pubkey ) ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
is_final : false ,
2020-12-21 13:02:53 -08:00
max_len : None ,
allow_excessive_balance : false ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2020-12-21 13:02:53 -08:00
} ) ,
2021-01-08 09:37:57 -08:00
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
2020-12-21 13:02:53 -08:00
}
) ;
2021-01-08 09:37:57 -08:00
let program_keypair = Keypair ::new ( ) ;
let program_keypair_file = make_tmp_path ( " program_keypair_file " ) ;
write_keypair_file ( & program_keypair , & program_keypair_file ) . unwrap ( ) ;
2020-12-21 13:02:53 -08:00
let test = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" deploy " ,
" /Users/test/program.so " ,
" --program-id " ,
2021-01-08 09:37:57 -08:00
& program_keypair_file ,
2020-12-21 13:02:53 -08:00
] ) ;
assert_eq! (
parse_command ( & test , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Deploy {
2021-01-08 09:37:57 -08:00
program_location : Some ( " /Users/test/program.so " . to_string ( ) ) ,
2020-12-21 13:02:53 -08:00
buffer_signer_index : None ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : None ,
2020-12-21 13:02:53 -08:00
program_signer_index : Some ( 1 ) ,
2021-01-08 09:37:57 -08:00
program_pubkey : Some ( program_keypair . pubkey ( ) ) ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
is_final : false ,
2020-12-21 13:02:53 -08:00
max_len : None ,
allow_excessive_balance : false ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2020-12-21 13:02:53 -08:00
} ) ,
signers : vec ! [
read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ,
2021-01-08 09:37:57 -08:00
read_keypair_file ( & program_keypair_file ) . unwrap ( ) . into ( ) ,
2020-12-21 13:02:53 -08:00
] ,
}
) ;
2021-01-08 09:37:57 -08:00
let authority_keypair = Keypair ::new ( ) ;
let authority_keypair_file = make_tmp_path ( " authority_keypair_file " ) ;
write_keypair_file ( & authority_keypair , & authority_keypair_file ) . unwrap ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2020-12-21 13:02:53 -08:00
" test " ,
" program " ,
" deploy " ,
" /Users/test/program.so " ,
" --upgrade-authority " ,
2021-01-08 09:37:57 -08:00
& authority_keypair_file ,
2020-12-21 13:02:53 -08:00
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2020-12-21 13:02:53 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Deploy {
2021-01-08 09:37:57 -08:00
program_location : Some ( " /Users/test/program.so " . to_string ( ) ) ,
2020-12-21 13:02:53 -08:00
buffer_signer_index : None ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : None ,
2020-12-21 13:02:53 -08:00
program_signer_index : None ,
program_pubkey : None ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : 1 ,
2021-01-08 09:37:57 -08:00
is_final : false ,
2020-12-21 13:02:53 -08:00
max_len : None ,
allow_excessive_balance : false ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2020-12-21 13:02:53 -08:00
} ) ,
signers : vec ! [
read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ,
2021-01-08 09:37:57 -08:00
read_keypair_file ( & authority_keypair_file ) . unwrap ( ) . into ( ) ,
2020-12-21 13:02:53 -08:00
] ,
}
) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2020-12-21 13:02:53 -08:00
" test " ,
" program " ,
" deploy " ,
" /Users/test/program.so " ,
" --final " ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2020-12-21 13:02:53 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Deploy {
2021-01-08 09:37:57 -08:00
program_location : Some ( " /Users/test/program.so " . to_string ( ) ) ,
2020-12-21 13:02:53 -08:00
buffer_signer_index : None ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : None ,
2020-12-21 13:02:53 -08:00
program_signer_index : None ,
program_pubkey : None ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
is_final : true ,
2020-12-21 13:02:53 -08:00
max_len : None ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2020-12-21 13:02:53 -08:00
allow_excessive_balance : false ,
} ) ,
2021-01-08 09:37:57 -08:00
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
}
#[ test ]
#[ allow(clippy::cognitive_complexity) ]
fn test_cli_parse_write_buffer ( ) {
2021-07-28 08:43:32 -07:00
let test_commands = get_clap_app ( " test " , " desc " , " version " ) ;
2021-01-08 09:37:57 -08:00
let default_keypair = Keypair ::new ( ) ;
let keypair_file = make_tmp_path ( " keypair_file " ) ;
write_keypair_file ( & default_keypair , & keypair_file ) . unwrap ( ) ;
2021-05-28 00:42:55 -07:00
let default_signer = DefaultSigner ::new ( " " , & keypair_file ) ;
2021-01-08 09:37:57 -08:00
// defaults
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2021-01-08 09:37:57 -08:00
" test " ,
" program " ,
" write-buffer " ,
" /Users/test/program.so " ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2021-01-08 09:37:57 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::WriteBuffer {
program_location : " /Users/test/program.so " . to_string ( ) ,
buffer_signer_index : None ,
buffer_pubkey : None ,
2023-01-02 23:32:04 -08:00
buffer_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
max_len : None ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2021-01-08 09:37:57 -08:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
// specify max len
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2021-01-08 09:37:57 -08:00
" test " ,
" program " ,
" write-buffer " ,
" /Users/test/program.so " ,
" --max-len " ,
" 42 " ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2021-01-08 09:37:57 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::WriteBuffer {
program_location : " /Users/test/program.so " . to_string ( ) ,
buffer_signer_index : None ,
buffer_pubkey : None ,
2023-01-02 23:32:04 -08:00
buffer_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
max_len : Some ( 42 ) ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2021-01-08 09:37:57 -08:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
// specify buffer
let buffer_keypair = Keypair ::new ( ) ;
let buffer_keypair_file = make_tmp_path ( " buffer_keypair_file " ) ;
write_keypair_file ( & buffer_keypair , & buffer_keypair_file ) . unwrap ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2021-01-08 09:37:57 -08:00
" test " ,
" program " ,
" write-buffer " ,
" /Users/test/program.so " ,
" --buffer " ,
& buffer_keypair_file ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2021-01-08 09:37:57 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::WriteBuffer {
program_location : " /Users/test/program.so " . to_string ( ) ,
buffer_signer_index : Some ( 1 ) ,
buffer_pubkey : Some ( buffer_keypair . pubkey ( ) ) ,
2023-01-02 23:32:04 -08:00
buffer_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
max_len : None ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2021-01-08 09:37:57 -08:00
} ) ,
signers : vec ! [
read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ,
read_keypair_file ( & buffer_keypair_file ) . unwrap ( ) . into ( ) ,
] ,
}
) ;
// specify authority
let authority_keypair = Keypair ::new ( ) ;
let authority_keypair_file = make_tmp_path ( " authority_keypair_file " ) ;
write_keypair_file ( & authority_keypair , & authority_keypair_file ) . unwrap ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2021-01-08 09:37:57 -08:00
" test " ,
" program " ,
" write-buffer " ,
" /Users/test/program.so " ,
" --buffer-authority " ,
& authority_keypair_file ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2021-01-08 09:37:57 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::WriteBuffer {
program_location : " /Users/test/program.so " . to_string ( ) ,
buffer_signer_index : None ,
buffer_pubkey : None ,
2023-01-02 23:32:04 -08:00
buffer_authority_signer_index : 1 ,
2021-01-08 09:37:57 -08:00
max_len : None ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2021-01-08 09:37:57 -08:00
} ) ,
signers : vec ! [
read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ,
read_keypair_file ( & authority_keypair_file ) . unwrap ( ) . into ( ) ,
] ,
}
) ;
// specify both buffer and authority
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 authority_keypair = Keypair ::new ( ) ;
let authority_keypair_file = make_tmp_path ( " authority_keypair_file " ) ;
write_keypair_file ( & authority_keypair , & authority_keypair_file ) . unwrap ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2021-01-08 09:37:57 -08:00
" test " ,
" program " ,
" write-buffer " ,
" /Users/test/program.so " ,
" --buffer " ,
& buffer_keypair_file ,
" --buffer-authority " ,
& authority_keypair_file ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2021-01-08 09:37:57 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::WriteBuffer {
program_location : " /Users/test/program.so " . to_string ( ) ,
buffer_signer_index : Some ( 1 ) ,
buffer_pubkey : Some ( buffer_keypair . pubkey ( ) ) ,
2023-01-02 23:32:04 -08:00
buffer_authority_signer_index : 2 ,
2021-01-08 09:37:57 -08:00
max_len : None ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2021-01-08 09:37:57 -08:00
} ) ,
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 ( ) ,
] ,
}
) ;
2020-12-21 13:02:53 -08:00
}
#[ test ]
#[ allow(clippy::cognitive_complexity) ]
fn test_cli_parse_set_upgrade_authority ( ) {
2021-07-28 08:43:32 -07:00
let test_commands = get_clap_app ( " test " , " desc " , " version " ) ;
2020-12-21 13:02:53 -08:00
let default_keypair = Keypair ::new ( ) ;
let keypair_file = make_tmp_path ( " keypair_file " ) ;
write_keypair_file ( & default_keypair , & keypair_file ) . unwrap ( ) ;
2021-05-28 00:42:55 -07:00
let default_signer = DefaultSigner ::new ( " " , & keypair_file ) ;
2020-12-21 13:02:53 -08:00
2021-01-08 09:37:57 -08:00
let program_pubkey = Pubkey ::new_unique ( ) ;
let new_authority_pubkey = Pubkey ::new_unique ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2020-12-21 13:02:53 -08:00
" test " ,
" program " ,
" set-upgrade-authority " ,
2021-01-08 09:37:57 -08:00
& program_pubkey . to_string ( ) ,
2020-12-21 13:02:53 -08:00
" --new-upgrade-authority " ,
2021-01-08 09:37:57 -08:00
& new_authority_pubkey . to_string ( ) ,
2022-12-15 22:59:54 -08:00
" --skip-new-upgrade-authority-signer-check " ,
2020-12-21 13:02:53 -08:00
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2020-12-21 13:02:53 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetUpgradeAuthority {
2021-01-08 09:37:57 -08:00
program_pubkey ,
2020-12-21 13:02:53 -08:00
upgrade_authority_index : Some ( 0 ) ,
2021-01-08 09:37:57 -08:00
new_upgrade_authority : Some ( new_authority_pubkey ) ,
2020-12-21 13:02:53 -08:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
2021-01-08 09:37:57 -08:00
let program_pubkey = Pubkey ::new_unique ( ) ;
let new_authority_pubkey = Keypair ::new ( ) ;
let new_authority_pubkey_file = make_tmp_path ( " authority_keypair_file " ) ;
write_keypair_file ( & new_authority_pubkey , & new_authority_pubkey_file ) . unwrap ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2020-12-21 13:02:53 -08:00
" test " ,
" program " ,
" set-upgrade-authority " ,
2021-01-08 09:37:57 -08:00
& program_pubkey . to_string ( ) ,
2020-12-21 13:02:53 -08:00
" --new-upgrade-authority " ,
2021-01-08 09:37:57 -08:00
& new_authority_pubkey_file ,
2022-12-15 22:59:54 -08:00
" --skip-new-upgrade-authority-signer-check " ,
2020-12-21 13:02:53 -08:00
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2020-12-21 13:02:53 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetUpgradeAuthority {
2021-01-08 09:37:57 -08:00
program_pubkey ,
2020-12-21 13:02:53 -08:00
upgrade_authority_index : Some ( 0 ) ,
2021-01-08 09:37:57 -08:00
new_upgrade_authority : Some ( new_authority_pubkey . pubkey ( ) ) ,
2020-12-21 13:02:53 -08:00
} ) ,
2021-01-08 09:37:57 -08:00
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
2020-12-21 13:02:53 -08:00
}
) ;
2022-12-15 22:59:54 -08:00
let program_pubkey = Pubkey ::new_unique ( ) ;
let new_authority_pubkey = Keypair ::new ( ) ;
let new_authority_pubkey_file = make_tmp_path ( " authority_keypair_file " ) ;
write_keypair_file ( & new_authority_pubkey , & new_authority_pubkey_file ) . unwrap ( ) ;
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" set-upgrade-authority " ,
& program_pubkey . to_string ( ) ,
" --new-upgrade-authority " ,
& new_authority_pubkey_file ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetUpgradeAuthorityChecked {
program_pubkey ,
upgrade_authority_index : 0 ,
new_upgrade_authority_index : 1 ,
} ) ,
signers : vec ! [
read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ,
read_keypair_file ( & new_authority_pubkey_file )
. unwrap ( )
. into ( ) ,
] ,
}
) ;
2021-01-08 09:37:57 -08:00
let program_pubkey = Pubkey ::new_unique ( ) ;
let new_authority_pubkey = Keypair ::new ( ) ;
let new_authority_pubkey_file = make_tmp_path ( " authority_keypair_file " ) ;
2023-01-05 10:21:56 -08:00
write_keypair_file ( & new_authority_pubkey , new_authority_pubkey_file ) . unwrap ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2020-12-21 13:02:53 -08:00
" test " ,
" program " ,
" set-upgrade-authority " ,
2021-01-08 09:37:57 -08:00
& program_pubkey . to_string ( ) ,
2020-12-21 13:02:53 -08:00
" --final " ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2020-12-21 13:02:53 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetUpgradeAuthority {
2021-01-08 09:37:57 -08:00
program_pubkey ,
2020-12-21 13:02:53 -08:00
upgrade_authority_index : Some ( 0 ) ,
new_upgrade_authority : None ,
} ) ,
2021-01-08 09:37:57 -08:00
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
2020-12-21 13:02:53 -08:00
}
) ;
2021-01-08 09:37:57 -08:00
let program_pubkey = Pubkey ::new_unique ( ) ;
let authority = Keypair ::new ( ) ;
let authority_keypair_file = make_tmp_path ( " authority_keypair_file " ) ;
write_keypair_file ( & authority , & authority_keypair_file ) . unwrap ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2020-12-21 13:02:53 -08:00
" test " ,
" program " ,
" set-upgrade-authority " ,
2021-01-08 09:37:57 -08:00
& program_pubkey . to_string ( ) ,
2020-12-21 13:02:53 -08:00
" --upgrade-authority " ,
2021-01-08 09:37:57 -08:00
& authority_keypair_file ,
2020-12-21 13:02:53 -08:00
" --final " ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2020-12-21 13:02:53 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetUpgradeAuthority {
2021-01-08 09:37:57 -08:00
program_pubkey ,
2020-12-21 13:02:53 -08:00
upgrade_authority_index : Some ( 1 ) ,
new_upgrade_authority : None ,
} ) ,
signers : vec ! [
read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ,
2021-01-08 09:37:57 -08:00
read_keypair_file ( & authority_keypair_file ) . unwrap ( ) . into ( ) ,
] ,
}
) ;
}
#[ test ]
#[ allow(clippy::cognitive_complexity) ]
fn test_cli_parse_set_buffer_authority ( ) {
2021-07-28 08:43:32 -07:00
let test_commands = get_clap_app ( " test " , " desc " , " version " ) ;
2021-01-08 09:37:57 -08:00
let default_keypair = Keypair ::new ( ) ;
let keypair_file = make_tmp_path ( " keypair_file " ) ;
write_keypair_file ( & default_keypair , & keypair_file ) . unwrap ( ) ;
2021-05-28 00:42:55 -07:00
let default_signer = DefaultSigner ::new ( " " , & keypair_file ) ;
2021-01-08 09:37:57 -08:00
let buffer_pubkey = Pubkey ::new_unique ( ) ;
let new_authority_pubkey = Pubkey ::new_unique ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2021-01-08 09:37:57 -08:00
" test " ,
" program " ,
" set-buffer-authority " ,
& buffer_pubkey . to_string ( ) ,
" --new-buffer-authority " ,
& new_authority_pubkey . to_string ( ) ,
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2021-01-08 09:37:57 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetBufferAuthority {
buffer_pubkey ,
buffer_authority_index : Some ( 0 ) ,
2021-01-29 12:43:42 -08:00
new_buffer_authority : new_authority_pubkey ,
2021-01-08 09:37:57 -08:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
let buffer_pubkey = Pubkey ::new_unique ( ) ;
2021-03-17 21:39:29 -07:00
let new_authority_keypair = Keypair ::new ( ) ;
let new_authority_keypair_file = make_tmp_path ( " authority_keypair_file " ) ;
write_keypair_file ( & new_authority_keypair , & new_authority_keypair_file ) . unwrap ( ) ;
2021-03-31 23:18:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
2021-01-08 09:37:57 -08:00
" test " ,
" program " ,
" set-buffer-authority " ,
& buffer_pubkey . to_string ( ) ,
" --new-buffer-authority " ,
2021-03-17 21:39:29 -07:00
& new_authority_keypair_file ,
2021-01-08 09:37:57 -08:00
] ) ;
assert_eq! (
2021-03-31 23:18:29 -07:00
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
2021-01-08 09:37:57 -08:00
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::SetBufferAuthority {
buffer_pubkey ,
buffer_authority_index : Some ( 0 ) ,
2021-03-17 21:39:29 -07:00
new_buffer_authority : new_authority_keypair . pubkey ( ) ,
2021-01-08 09:37:57 -08:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
2020-12-21 13:02:53 -08:00
}
2021-03-17 21:39:29 -07:00
#[ test ]
#[ allow(clippy::cognitive_complexity) ]
fn test_cli_parse_show ( ) {
2021-07-28 08:43:32 -07:00
let test_commands = get_clap_app ( " test " , " desc " , " version " ) ;
2021-03-17 21:39:29 -07:00
let default_keypair = Keypair ::new ( ) ;
let keypair_file = make_tmp_path ( " keypair_file " ) ;
write_keypair_file ( & default_keypair , & keypair_file ) . unwrap ( ) ;
2021-05-28 00:42:55 -07:00
let default_signer = DefaultSigner ::new ( " " , & keypair_file ) ;
2021-03-17 21:39:29 -07:00
// defaults
let buffer_pubkey = Pubkey ::new_unique ( ) ;
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 " ,
" show " ,
& buffer_pubkey . to_string ( ) ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Show {
account_pubkey : Some ( buffer_pubkey ) ,
authority_pubkey : default_keypair . pubkey ( ) ,
2021-08-25 17:03:55 -07:00
get_programs : false ,
get_buffers : false ,
2021-03-17 21:39:29 -07:00
all : false ,
use_lamports_unit : false ,
} ) ,
signers : vec ! [ ] ,
}
) ;
2021-08-25 17:03:55 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" show " ,
" --programs " ,
" --all " ,
" --lamports " ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Show {
account_pubkey : None ,
authority_pubkey : default_keypair . pubkey ( ) ,
get_programs : true ,
get_buffers : false ,
all : true ,
use_lamports_unit : true ,
} ) ,
signers : vec ! [ ] ,
}
) ;
2021-03-17 21:39:29 -07:00
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" show " ,
" --buffers " ,
" --all " ,
" --lamports " ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Show {
account_pubkey : None ,
authority_pubkey : default_keypair . pubkey ( ) ,
2021-08-25 17:03:55 -07:00
get_programs : false ,
get_buffers : true ,
2021-03-17 21:39:29 -07:00
all : true ,
use_lamports_unit : true ,
} ) ,
signers : vec ! [ ] ,
}
) ;
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" show " ,
" --buffers " ,
" --buffer-authority " ,
& authority_keypair . pubkey ( ) . to_string ( ) ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Show {
account_pubkey : None ,
authority_pubkey : authority_keypair . pubkey ( ) ,
2021-08-25 17:03:55 -07:00
get_programs : false ,
get_buffers : true ,
2021-03-17 21:39:29 -07:00
all : false ,
use_lamports_unit : false ,
} ) ,
signers : vec ! [ ] ,
}
) ;
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" show " ,
" --buffers " ,
" --buffer-authority " ,
& authority_keypair_file ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Show {
account_pubkey : None ,
authority_pubkey : authority_keypair . pubkey ( ) ,
2021-08-25 17:03:55 -07:00
get_programs : false ,
get_buffers : true ,
2021-03-17 21:39:29 -07:00
all : false ,
use_lamports_unit : false ,
} ) ,
signers : vec ! [ ] ,
}
) ;
}
#[ test ]
#[ allow(clippy::cognitive_complexity) ]
fn test_cli_parse_close ( ) {
2021-07-28 08:43:32 -07:00
let test_commands = get_clap_app ( " test " , " desc " , " version " ) ;
2021-03-17 21:39:29 -07:00
let default_keypair = Keypair ::new ( ) ;
let keypair_file = make_tmp_path ( " keypair_file " ) ;
write_keypair_file ( & default_keypair , & keypair_file ) . unwrap ( ) ;
2021-05-28 00:42:55 -07:00
let default_signer = DefaultSigner ::new ( " " , & keypair_file ) ;
2021-03-17 21:39:29 -07:00
// defaults
let buffer_pubkey = Pubkey ::new_unique ( ) ;
let recipient_pubkey = Pubkey ::new_unique ( ) ;
let authority_keypair = Keypair ::new ( ) ;
let authority_keypair_file = make_tmp_path ( " authority_keypair_file " ) ;
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" close " ,
& buffer_pubkey . to_string ( ) ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Close {
account_pubkey : Some ( buffer_pubkey ) ,
recipient_pubkey : default_keypair . pubkey ( ) ,
authority_index : 0 ,
use_lamports_unit : false ,
2022-08-13 00:36:14 -07:00
bypass_warning : false ,
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
// with bypass-warning
write_keypair_file ( & authority_keypair , & authority_keypair_file ) . unwrap ( ) ;
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" close " ,
& buffer_pubkey . to_string ( ) ,
" --bypass-warning " ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Close {
account_pubkey : Some ( buffer_pubkey ) ,
recipient_pubkey : default_keypair . pubkey ( ) ,
authority_index : 0 ,
use_lamports_unit : false ,
bypass_warning : true ,
2021-03-17 21:39:29 -07:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ] ,
}
) ;
// with authority
write_keypair_file ( & authority_keypair , & authority_keypair_file ) . unwrap ( ) ;
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" close " ,
& buffer_pubkey . to_string ( ) ,
" --buffer-authority " ,
& authority_keypair_file ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Close {
account_pubkey : Some ( buffer_pubkey ) ,
recipient_pubkey : default_keypair . pubkey ( ) ,
authority_index : 1 ,
use_lamports_unit : false ,
2022-08-13 00:36:14 -07:00
bypass_warning : false ,
2021-03-17 21:39:29 -07:00
} ) ,
signers : vec ! [
read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) ,
read_keypair_file ( & authority_keypair_file ) . unwrap ( ) . into ( ) ,
] ,
}
) ;
// with recipient
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" close " ,
& buffer_pubkey . to_string ( ) ,
" --recipient " ,
& recipient_pubkey . to_string ( ) ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Close {
account_pubkey : Some ( buffer_pubkey ) ,
recipient_pubkey ,
authority_index : 0 ,
use_lamports_unit : false ,
2022-08-13 00:36:14 -07:00
bypass_warning : false ,
2021-03-17 21:39:29 -07:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) , ] ,
}
) ;
// --buffers and lamports
let test_command = test_commands . clone ( ) . get_matches_from ( vec! [
" test " ,
" program " ,
" close " ,
" --buffers " ,
" --lamports " ,
] ) ;
assert_eq! (
parse_command ( & test_command , & default_signer , & mut None ) . unwrap ( ) ,
CliCommandInfo {
command : CliCommand ::Program ( ProgramCliCommand ::Close {
account_pubkey : None ,
recipient_pubkey : default_keypair . pubkey ( ) ,
authority_index : 0 ,
use_lamports_unit : true ,
2022-08-13 00:36:14 -07:00
bypass_warning : false ,
2021-03-17 21:39:29 -07:00
} ) ,
signers : vec ! [ read_keypair_file ( & keypair_file ) . unwrap ( ) . into ( ) , ] ,
}
) ;
}
2021-01-08 14:43:36 -08:00
2020-12-21 13:02:53 -08:00
#[ test ]
fn test_cli_keypair_file ( ) {
solana_logger ::setup ( ) ;
let default_keypair = Keypair ::new ( ) ;
2021-01-08 09:37:57 -08:00
let program_pubkey = Keypair ::new ( ) ;
2020-12-21 13:02:53 -08:00
let deploy_path = make_tmp_path ( " deploy " ) ;
let mut program_location = PathBuf ::from ( deploy_path . clone ( ) ) ;
program_location . push ( " noop " ) ;
program_location . set_extension ( " so " ) ;
let mut pathbuf = PathBuf ::from ( env! ( " CARGO_MANIFEST_DIR " ) ) ;
pathbuf . push ( " tests " ) ;
pathbuf . push ( " fixtures " ) ;
pathbuf . push ( " noop " ) ;
pathbuf . set_extension ( " so " ) ;
let program_keypair_location = program_location . with_file_name ( " noop-keypair.json " ) ;
std ::fs ::create_dir_all ( deploy_path ) . unwrap ( ) ;
std ::fs ::copy ( pathbuf , program_location . as_os_str ( ) ) . unwrap ( ) ;
2023-01-05 10:21:56 -08:00
write_keypair_file ( & program_pubkey , program_keypair_location ) . unwrap ( ) ;
2020-12-21 13:02:53 -08:00
let config = CliConfig {
2021-04-22 18:35:12 -07:00
rpc_client : Some ( Arc ::new ( RpcClient ::new_mock ( " " . to_string ( ) ) ) ) ,
2020-12-21 13:02:53 -08:00
command : CliCommand ::Program ( ProgramCliCommand ::Deploy {
2021-01-08 09:37:57 -08:00
program_location : Some ( program_location . to_str ( ) . unwrap ( ) . to_string ( ) ) ,
2020-12-21 13:02:53 -08:00
buffer_signer_index : None ,
2021-01-08 09:37:57 -08:00
buffer_pubkey : None ,
2020-12-21 13:02:53 -08:00
program_signer_index : None ,
program_pubkey : None ,
2021-01-29 12:43:42 -08:00
upgrade_authority_signer_index : 0 ,
2021-01-08 09:37:57 -08:00
is_final : false ,
2020-12-21 13:02:53 -08:00
max_len : None ,
allow_excessive_balance : false ,
2022-03-25 13:43:43 -07:00
skip_fee_check : false ,
2020-12-21 13:02:53 -08:00
} ) ,
signers : vec ! [ & default_keypair ] ,
2021-02-01 09:39:37 -08:00
output_format : OutputFormat ::JsonCompact ,
2020-12-21 13:02:53 -08:00
.. CliConfig ::default ( )
} ;
let result = process_command ( & config ) ;
let json : Value = serde_json ::from_str ( & result . unwrap ( ) ) . unwrap ( ) ;
let program_id = json
. as_object ( )
. unwrap ( )
2021-01-29 14:52:26 -08:00
. get ( " programId " )
2020-12-21 13:02:53 -08:00
. unwrap ( )
. as_str ( )
. unwrap ( ) ;
assert_eq! (
program_id . parse ::< Pubkey > ( ) . unwrap ( ) ,
2021-01-08 09:37:57 -08:00
program_pubkey . pubkey ( )
2020-12-21 13:02:53 -08:00
) ;
}
}