diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 0bea8252a9..201f6331a3 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -298,13 +298,7 @@ pub enum CliCommand { authorized_voter: Option, authorized_withdrawer: Pubkey, commission: u8, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: BlockhashQuery, - nonce_account: Option, - nonce_authority: SignerIndex, memo: Option, - fee_payer: SignerIndex, }, ShowVoteAccount { pubkey: Pubkey, @@ -316,25 +310,13 @@ pub enum CliCommand { destination_account_pubkey: Pubkey, withdraw_authority: SignerIndex, withdraw_amount: SpendAmount, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: BlockhashQuery, - nonce_account: Option, - nonce_authority: SignerIndex, memo: Option, - fee_payer: SignerIndex, }, VoteAuthorize { vote_account_pubkey: Pubkey, new_authorized_pubkey: Pubkey, vote_authorize: VoteAuthorize, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: BlockhashQuery, - nonce_account: Option, - nonce_authority: SignerIndex, memo: Option, - fee_payer: SignerIndex, authorized: SignerIndex, new_authorized: Option, }, @@ -342,25 +324,13 @@ pub enum CliCommand { vote_account_pubkey: Pubkey, new_identity_account: SignerIndex, withdraw_authority: SignerIndex, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: BlockhashQuery, - nonce_account: Option, - nonce_authority: SignerIndex, memo: Option, - fee_payer: SignerIndex, }, VoteUpdateCommission { vote_account_pubkey: Pubkey, commission: u8, withdraw_authority: SignerIndex, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: BlockhashQuery, - nonce_account: Option, - nonce_authority: SignerIndex, memo: Option, - fee_payer: SignerIndex, }, // Wallet Commands Address, @@ -1405,13 +1375,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { authorized_voter, authorized_withdrawer, commission, - sign_only, - dump_transaction_message, - blockhash_query, - ref nonce_account, - nonce_authority, memo, - fee_payer, } => process_create_vote_account( &rpc_client, config, @@ -1421,13 +1385,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { authorized_voter, *authorized_withdrawer, *commission, - *sign_only, - *dump_transaction_message, - blockhash_query, - nonce_account.as_ref(), - *nonce_authority, memo.as_ref(), - *fee_payer, ), CliCommand::ShowVoteAccount { pubkey: vote_account_pubkey, @@ -1445,13 +1403,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { withdraw_authority, withdraw_amount, destination_account_pubkey, - sign_only, - dump_transaction_message, - blockhash_query, - ref nonce_account, - nonce_authority, memo, - fee_payer, } => process_withdraw_from_vote_account( &rpc_client, config, @@ -1459,25 +1411,13 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { *withdraw_authority, *withdraw_amount, destination_account_pubkey, - *sign_only, - *dump_transaction_message, - blockhash_query, - nonce_account.as_ref(), - *nonce_authority, memo.as_ref(), - *fee_payer, ), CliCommand::VoteAuthorize { vote_account_pubkey, new_authorized_pubkey, vote_authorize, - sign_only, - dump_transaction_message, - blockhash_query, - nonce_account, - nonce_authority, memo, - fee_payer, authorized, new_authorized, } => process_vote_authorize( @@ -1488,63 +1428,33 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { *vote_authorize, *authorized, *new_authorized, - *sign_only, - *dump_transaction_message, - blockhash_query, - *nonce_account, - *nonce_authority, memo.as_ref(), - *fee_payer, ), CliCommand::VoteUpdateValidator { vote_account_pubkey, new_identity_account, withdraw_authority, - sign_only, - dump_transaction_message, - blockhash_query, - nonce_account, - nonce_authority, memo, - fee_payer, } => process_vote_update_validator( &rpc_client, config, vote_account_pubkey, *new_identity_account, *withdraw_authority, - *sign_only, - *dump_transaction_message, - blockhash_query, - *nonce_account, - *nonce_authority, memo.as_ref(), - *fee_payer, ), CliCommand::VoteUpdateCommission { vote_account_pubkey, commission, withdraw_authority, - sign_only, - dump_transaction_message, - blockhash_query, - nonce_account, - nonce_authority, memo, - fee_payer, } => process_vote_update_commission( &rpc_client, config, vote_account_pubkey, *commission, *withdraw_authority, - *sign_only, - *dump_transaction_message, - blockhash_query, - *nonce_account, - *nonce_authority, memo.as_ref(), - *fee_payer, ), // Wallet Commands @@ -2043,13 +1953,7 @@ mod tests { authorized_voter: Some(bob_pubkey), authorized_withdrawer: bob_pubkey, commission: 0, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }; config.signers = vec![&keypair, &bob_keypair, &identity_keypair]; let result = process_command(&config); @@ -2080,13 +1984,7 @@ mod tests { vote_account_pubkey: bob_pubkey, new_authorized_pubkey, vote_authorize: VoteAuthorize::Withdrawer, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, authorized: 0, new_authorized: None, }; @@ -2099,13 +1997,7 @@ mod tests { vote_account_pubkey: bob_pubkey, new_identity_account: 2, withdraw_authority: 1, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }; let result = process_command(&config); assert!(result.is_ok()); @@ -2281,13 +2173,7 @@ mod tests { authorized_voter: Some(bob_pubkey), authorized_withdrawer: bob_pubkey, commission: 0, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }; config.signers = vec![&keypair, &bob_keypair, &identity_keypair]; assert!(process_command(&config).is_err()); @@ -2296,13 +2182,7 @@ mod tests { vote_account_pubkey: bob_pubkey, new_authorized_pubkey: bob_pubkey, vote_authorize: VoteAuthorize::Voter, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, authorized: 0, new_authorized: None, }; @@ -2312,13 +2192,7 @@ mod tests { vote_account_pubkey: bob_pubkey, new_identity_account: 1, withdraw_authority: 1, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }; assert!(process_command(&config).is_err()); diff --git a/cli/src/vote.rs b/cli/src/vote.rs index 7f8edca235..6f7c25ebab 100644 --- a/cli/src/vote.rs +++ b/cli/src/vote.rs @@ -6,25 +6,18 @@ use { ProcessResult, }, memo::WithMemo, - nonce::check_nonce_account, - spend_utils::{resolve_spend_tx_and_check_account_balances, SpendAmount}, + spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount}, stake::check_current_authority, }, clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand}, solana_clap_utils::{ - fee_payer::{fee_payer_arg, FEE_PAYER_ARG}, input_parsers::*, input_validators::*, keypair::{DefaultSigner, SignerIndex}, memo::{memo_arg, MEMO_ARG}, - nonce::*, - offline::*, }, - solana_cli_output::{ - return_signers_with_config, CliEpochVotingHistory, CliLockout, CliVoteAccount, - ReturnSignersConfig, - }, - solana_client::{blockhash_query::BlockhashQuery, nonce_utils, rpc_client::RpcClient}, + solana_cli_output::{CliEpochVotingHistory, CliLockout, CliVoteAccount}, + solana_client::rpc_client::RpcClient, solana_remote_wallet::remote_wallet::RemoteWalletManager, solana_sdk::{ account::Account, commitment_config::CommitmentConfig, message::Message, @@ -103,9 +96,6 @@ impl VoteSubCommands for App<'_, '_> { .takes_value(true) .help("Seed for address generation; if specified, the resulting account will be at a derived address of the VOTE ACCOUNT pubkey") ) - .offline_args() - .nonce_args(false) - .arg(fee_payer_arg()) .arg(memo_arg()) ) .subcommand( @@ -133,9 +123,6 @@ impl VoteSubCommands for App<'_, '_> { .required(true), "New authorized vote signer. "), ) - .offline_args() - .nonce_args(false) - .arg(fee_payer_arg()) .arg(memo_arg()) ) .subcommand( @@ -163,9 +150,6 @@ impl VoteSubCommands for App<'_, '_> { .required(true), "New authorized withdrawer. "), ) - .offline_args() - .nonce_args(false) - .arg(fee_payer_arg()) .arg(memo_arg()) ) .subcommand( @@ -195,9 +179,6 @@ impl VoteSubCommands for App<'_, '_> { .validator(is_valid_signer) .help("New authorized vote signer."), ) - .offline_args() - .nonce_args(false) - .arg(fee_payer_arg()) .arg(memo_arg()) ) .subcommand( @@ -227,9 +208,6 @@ impl VoteSubCommands for App<'_, '_> { .validator(is_valid_signer) .help("New authorized withdrawer."), ) - .offline_args() - .nonce_args(false) - .arg(fee_payer_arg()) .arg(memo_arg()) ) .subcommand( @@ -260,9 +238,6 @@ impl VoteSubCommands for App<'_, '_> { .validator(is_valid_signer) .help("Authorized withdrawer keypair"), ) - .offline_args() - .nonce_args(false) - .arg(fee_payer_arg()) .arg(memo_arg()) ) .subcommand( @@ -293,9 +268,6 @@ impl VoteSubCommands for App<'_, '_> { .validator(is_valid_signer) .help("Authorized withdrawer keypair"), ) - .offline_args() - .nonce_args(false) - .arg(fee_payer_arg()) .arg(memo_arg()) ) .subcommand( @@ -366,11 +338,7 @@ impl VoteSubCommands for App<'_, '_> { .validator(is_valid_signer) .help("Authorized withdrawer [default: cli config keypair]"), ) - .offline_args() - .nonce_args(false) - .arg(fee_payer_arg()) - .arg(memo_arg() - ) + .arg(memo_arg()) ) } } @@ -389,14 +357,7 @@ pub fn parse_create_vote_account( let authorized_withdrawer = pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?.unwrap(); let allow_unsafe = matches.is_present("allow_unsafe_authorized_withdrawer"); - let sign_only = matches.is_present(SIGN_ONLY_ARG.name); - let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name); - let blockhash_query = BlockhashQuery::new_from_matches(matches); - let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager)?; let memo = matches.value_of(MEMO_ARG.name).map(String::from); - let (nonce_authority, nonce_authority_pubkey) = - signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?; - let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?; if !allow_unsafe { if authorized_withdrawer == vote_account_pubkey.unwrap() { @@ -415,12 +376,12 @@ pub fn parse_create_vote_account( } } - let mut bulk_signers = vec![fee_payer, vote_account, identity_account]; - if nonce_account.is_some() { - bulk_signers.push(nonce_authority); - } - let signer_info = - default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?; + let payer_provided = None; + let signer_info = default_signer.generate_unique_signers( + vec![payer_provided, vote_account, identity_account], + matches, + wallet_manager, + )?; Ok(CliCommandInfo { command: CliCommand::CreateVoteAccount { @@ -430,13 +391,7 @@ pub fn parse_create_vote_account( authorized_voter, authorized_withdrawer, commission, - sign_only, - dump_transaction_message, - blockhash_query, - nonce_account, - nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(), memo, - fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(), }, signers: signer_info.signers, }) @@ -453,43 +408,27 @@ pub fn parse_vote_authorize( pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap(); let (authorized, authorized_pubkey) = signer_of(matches, "authorized", wallet_manager)?; - let sign_only = matches.is_present(SIGN_ONLY_ARG.name); - let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name); - let blockhash_query = BlockhashQuery::new_from_matches(matches); - let nonce_account = pubkey_of(matches, NONCE_ARG.name); - let memo = matches.value_of(MEMO_ARG.name).map(String::from); - let (nonce_authority, nonce_authority_pubkey) = - signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?; - let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?; - - let mut bulk_signers = vec![fee_payer, authorized]; + let payer_provided = None; + let mut signers = vec![payer_provided, authorized]; let new_authorized_pubkey = if checked { let (new_authorized_signer, new_authorized_pubkey) = signer_of(matches, "new_authorized", wallet_manager)?; - bulk_signers.push(new_authorized_signer); + signers.push(new_authorized_signer); new_authorized_pubkey.unwrap() } else { pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap() }; - if nonce_account.is_some() { - bulk_signers.push(nonce_authority); - } - let signer_info = - default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?; + + let signer_info = default_signer.generate_unique_signers(signers, matches, wallet_manager)?; + let memo = matches.value_of(MEMO_ARG.name).map(String::from); Ok(CliCommandInfo { command: CliCommand::VoteAuthorize { vote_account_pubkey, new_authorized_pubkey, vote_authorize, - sign_only, - dump_transaction_message, - blockhash_query, - nonce_account, - nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(), memo, - fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(), authorized: signer_info.index_of(authorized_pubkey).unwrap(), new_authorized: if checked { signer_info.index_of(Some(new_authorized_pubkey)) @@ -513,34 +452,20 @@ pub fn parse_vote_update_validator( let (authorized_withdrawer, authorized_withdrawer_pubkey) = signer_of(matches, "authorized_withdrawer", wallet_manager)?; - let sign_only = matches.is_present(SIGN_ONLY_ARG.name); - let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name); - let blockhash_query = BlockhashQuery::new_from_matches(matches); - let nonce_account = pubkey_of(matches, NONCE_ARG.name); + let payer_provided = None; + let signer_info = default_signer.generate_unique_signers( + vec![payer_provided, authorized_withdrawer, new_identity_account], + matches, + wallet_manager, + )?; let memo = matches.value_of(MEMO_ARG.name).map(String::from); - let (nonce_authority, nonce_authority_pubkey) = - signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?; - let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?; - - let mut bulk_signers = vec![fee_payer, authorized_withdrawer, new_identity_account]; - if nonce_account.is_some() { - bulk_signers.push(nonce_authority); - } - let signer_info = - default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?; Ok(CliCommandInfo { command: CliCommand::VoteUpdateValidator { vote_account_pubkey, new_identity_account: signer_info.index_of(new_identity_pubkey).unwrap(), withdraw_authority: signer_info.index_of(authorized_withdrawer_pubkey).unwrap(), - sign_only, - dump_transaction_message, - blockhash_query, - nonce_account, - nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(), memo, - fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(), }, signers: signer_info.signers, }) @@ -557,34 +482,20 @@ pub fn parse_vote_update_commission( signer_of(matches, "authorized_withdrawer", wallet_manager)?; let commission = value_t_or_exit!(matches, "commission", u8); - let sign_only = matches.is_present(SIGN_ONLY_ARG.name); - let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name); - let blockhash_query = BlockhashQuery::new_from_matches(matches); - let nonce_account = pubkey_of(matches, NONCE_ARG.name); + let payer_provided = None; + let signer_info = default_signer.generate_unique_signers( + vec![payer_provided, authorized_withdrawer], + matches, + wallet_manager, + )?; let memo = matches.value_of(MEMO_ARG.name).map(String::from); - let (nonce_authority, nonce_authority_pubkey) = - signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?; - let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?; - - let mut bulk_signers = vec![fee_payer, authorized_withdrawer]; - if nonce_account.is_some() { - bulk_signers.push(nonce_authority); - } - let signer_info = - default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?; Ok(CliCommandInfo { command: CliCommand::VoteUpdateCommission { vote_account_pubkey, commission, withdraw_authority: signer_info.index_of(authorized_withdrawer_pubkey).unwrap(), - sign_only, - dump_transaction_message, - blockhash_query, - nonce_account, - nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(), memo, - fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(), }, signers: signer_info.signers, }) @@ -626,21 +537,13 @@ pub fn parse_withdraw_from_vote_account( let (withdraw_authority, withdraw_authority_pubkey) = signer_of(matches, "authorized_withdrawer", wallet_manager)?; - let sign_only = matches.is_present(SIGN_ONLY_ARG.name); - let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name); - let blockhash_query = BlockhashQuery::new_from_matches(matches); - let nonce_account = pubkey_of(matches, NONCE_ARG.name); + let payer_provided = None; + let signer_info = default_signer.generate_unique_signers( + vec![payer_provided, withdraw_authority], + matches, + wallet_manager, + )?; let memo = matches.value_of(MEMO_ARG.name).map(String::from); - let (nonce_authority, nonce_authority_pubkey) = - signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?; - let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?; - - let mut bulk_signers = vec![fee_payer, withdraw_authority]; - if nonce_account.is_some() { - bulk_signers.push(nonce_authority); - } - let signer_info = - default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?; Ok(CliCommandInfo { command: CliCommand::WithdrawFromVoteAccount { @@ -648,19 +551,12 @@ pub fn parse_withdraw_from_vote_account( destination_account_pubkey, withdraw_authority: signer_info.index_of(withdraw_authority_pubkey).unwrap(), withdraw_amount, - sign_only, - dump_transaction_message, - blockhash_query, - nonce_account, - nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(), memo, - fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(), }, signers: signer_info.signers, }) } -#[allow(clippy::too_many_arguments)] pub fn process_create_vote_account( rpc_client: &RpcClient, config: &CliConfig, @@ -670,13 +566,7 @@ pub fn process_create_vote_account( authorized_voter: &Option, authorized_withdrawer: Pubkey, commission: u8, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: &BlockhashQuery, - nonce_account: Option<&Pubkey>, - nonce_authority: SignerIndex, memo: Option<&String>, - fee_payer: SignerIndex, ) -> ProcessResult { let vote_account = config.signers[vote_account]; let vote_account_pubkey = vote_account.pubkey(); @@ -702,9 +592,6 @@ pub fn process_create_vote_account( .max(1); let amount = SpendAmount::Some(required_balance); - let fee_payer = config.signers[fee_payer]; - let nonce_authority = config.signers[nonce_authority]; - let build_message = |lamports| { let vote_init = VoteInit { node_pubkey: identity_pubkey, @@ -732,77 +619,42 @@ pub fn process_create_vote_account( ) .with_memo(memo) }; - if let Some(nonce_account) = &nonce_account { - Message::new_with_nonce( - ixs, - Some(&fee_payer.pubkey()), - nonce_account, - &nonce_authority.pubkey(), - ) - } else { - Message::new(&ixs, Some(&fee_payer.pubkey())) - } + Message::new(&ixs, Some(&config.signers[0].pubkey())) }; - let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_and_fee_calculator(rpc_client, config.commitment)?; + if let Ok(response) = + rpc_client.get_account_with_commitment(&vote_account_address, config.commitment) + { + if let Some(vote_account) = response.value { + let err_msg = if vote_account.owner == solana_vote_program::id() { + format!("Vote account {} already exists", vote_account_address) + } else { + format!( + "Account {} already exists and is not a vote account", + vote_account_address + ) + }; + return Err(CliError::BadParameter(err_msg).into()); + } + } - let (message, _) = resolve_spend_tx_and_check_account_balances( + let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?; + + let (message, _) = resolve_spend_tx_and_check_account_balance( rpc_client, - sign_only, + false, amount, &fee_calculator, &config.signers[0].pubkey(), - &fee_payer.pubkey(), build_message, config.commitment, )?; - - if !sign_only { - if let Ok(response) = - rpc_client.get_account_with_commitment(&vote_account_address, config.commitment) - { - if let Some(vote_account) = response.value { - let err_msg = if vote_account.owner == solana_vote_program::id() { - format!("Vote account {} already exists", vote_account_address) - } else { - format!( - "Account {} already exists and is not a vote account", - vote_account_address - ) - }; - return Err(CliError::BadParameter(err_msg).into()); - } - } - - if let Some(nonce_account) = &nonce_account { - let nonce_account = nonce_utils::get_account_with_commitment( - rpc_client, - nonce_account, - config.commitment, - )?; - check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?; - } - } - let mut tx = Transaction::new_unsigned(message); - if sign_only { - tx.try_partial_sign(&config.signers, recent_blockhash)?; - return_signers_with_config( - &tx, - &config.output_format, - &ReturnSignersConfig { - dump_transaction_message, - }, - ) - } else { - tx.try_sign(&config.signers, recent_blockhash)?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); - log_instruction_custom_error::(result, config) - } + tx.try_sign(&config.signers, recent_blockhash)?; + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); + log_instruction_custom_error::(result, config) } -#[allow(clippy::too_many_arguments)] pub fn process_vote_authorize( rpc_client: &RpcClient, config: &CliConfig, @@ -811,42 +663,30 @@ pub fn process_vote_authorize( vote_authorize: VoteAuthorize, authorized: SignerIndex, new_authorized: Option, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: &BlockhashQuery, - nonce_account: Option, - nonce_authority: SignerIndex, memo: Option<&String>, - fee_payer: SignerIndex, ) -> ProcessResult { let authorized = config.signers[authorized]; let new_authorized_signer = new_authorized.map(|index| config.signers[index]); - let vote_state = if !sign_only { - Some(get_vote_account(rpc_client, vote_account_pubkey, config.commitment)?.1) - } else { - None - }; + let (_, vote_state) = get_vote_account(rpc_client, vote_account_pubkey, config.commitment)?; match vote_authorize { VoteAuthorize::Voter => { - if let Some(vote_state) = vote_state { - let current_epoch = rpc_client.get_epoch_info()?.epoch; - let current_authorized_voter = vote_state - .authorized_voters() - .get_authorized_voter(current_epoch) - .ok_or_else(|| { - CliError::RpcRequestError( - "Invalid vote account state; no authorized voters found".to_string(), - ) - })?; - check_current_authority(¤t_authorized_voter, &authorized.pubkey())?; - if let Some(signer) = new_authorized_signer { - if signer.is_interactive() { - return Err(CliError::BadParameter(format!( - "invalid new authorized vote signer {:?}. Interactive vote signers not supported", - new_authorized_pubkey - )).into()); - } + let current_epoch = rpc_client.get_epoch_info()?.epoch; + let current_authorized_voter = vote_state + .authorized_voters() + .get_authorized_voter(current_epoch) + .ok_or_else(|| { + CliError::RpcRequestError( + "Invalid vote account state; no authorized voters found".to_string(), + ) + })?; + check_current_authority(¤t_authorized_voter, &authorized.pubkey())?; + if let Some(signer) = new_authorized_signer { + if signer.is_interactive() { + return Err(CliError::BadParameter(format!( + "invalid new authorized vote signer {:?}. Interactive vote signers not supported", + new_authorized_pubkey + )).into()); } } } @@ -855,12 +695,11 @@ pub fn process_vote_authorize( (&authorized.pubkey(), "authorized_account".to_string()), (new_authorized_pubkey, "new_authorized_pubkey".to_string()), )?; - if let Some(vote_state) = vote_state { - check_current_authority(&vote_state.authorized_withdrawer, &authorized.pubkey())? - } + check_current_authority(&vote_state.authorized_withdrawer, &authorized.pubkey())? } } + let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?; let vote_ix = if new_authorized_signer.is_some() { vote_instruction::authorize_checked( vote_account_pubkey, // vote account to update @@ -878,69 +717,27 @@ pub fn process_vote_authorize( }; let ixs = vec![vote_ix].with_memo(memo); - let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_and_fee_calculator(rpc_client, config.commitment)?; - - let nonce_authority = config.signers[nonce_authority]; - let fee_payer = config.signers[fee_payer]; - - let message = if let Some(nonce_account) = &nonce_account { - Message::new_with_nonce( - ixs, - Some(&fee_payer.pubkey()), - nonce_account, - &nonce_authority.pubkey(), - ) - } else { - Message::new(&ixs, Some(&fee_payer.pubkey())) - }; + let message = Message::new(&ixs, Some(&config.signers[0].pubkey())); let mut tx = Transaction::new_unsigned(message); - - if sign_only { - tx.try_partial_sign(&config.signers, recent_blockhash)?; - return_signers_with_config( - &tx, - &config.output_format, - &ReturnSignersConfig { - dump_transaction_message, - }, - ) - } else { - tx.try_sign(&config.signers, recent_blockhash)?; - if let Some(nonce_account) = &nonce_account { - let nonce_account = nonce_utils::get_account_with_commitment( - rpc_client, - nonce_account, - config.commitment, - )?; - check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?; - } - check_account_for_fee_with_commitment( - rpc_client, - &config.signers[0].pubkey(), - &fee_calculator, - &tx.message, - config.commitment, - )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); - log_instruction_custom_error::(result, config) - } + tx.try_sign(&config.signers, recent_blockhash)?; + check_account_for_fee_with_commitment( + rpc_client, + &config.signers[0].pubkey(), + &fee_calculator, + &tx.message, + config.commitment, + )?; + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); + log_instruction_custom_error::(result, config) } -#[allow(clippy::too_many_arguments)] pub fn process_vote_update_validator( rpc_client: &RpcClient, config: &CliConfig, vote_account_pubkey: &Pubkey, new_identity_account: SignerIndex, withdraw_authority: SignerIndex, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: &BlockhashQuery, - nonce_account: Option, - nonce_authority: SignerIndex, memo: Option<&String>, - fee_payer: SignerIndex, ) -> ProcessResult { let authorized_withdrawer = config.signers[withdraw_authority]; let new_identity_account = config.signers[new_identity_account]; @@ -949,127 +746,57 @@ pub fn process_vote_update_validator( (vote_account_pubkey, "vote_account_pubkey".to_string()), (&new_identity_pubkey, "new_identity_account".to_string()), )?; - let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_and_fee_calculator(rpc_client, config.commitment)?; + let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?; let ixs = vec![vote_instruction::update_validator_identity( vote_account_pubkey, &authorized_withdrawer.pubkey(), &new_identity_pubkey, )] .with_memo(memo); - let nonce_authority = config.signers[nonce_authority]; - let fee_payer = config.signers[fee_payer]; - let message = if let Some(nonce_account) = &nonce_account { - Message::new_with_nonce( - ixs, - Some(&fee_payer.pubkey()), - nonce_account, - &nonce_authority.pubkey(), - ) - } else { - Message::new(&ixs, Some(&fee_payer.pubkey())) - }; + let message = Message::new(&ixs, Some(&config.signers[0].pubkey())); let mut tx = Transaction::new_unsigned(message); - - if sign_only { - tx.try_partial_sign(&config.signers, recent_blockhash)?; - return_signers_with_config( - &tx, - &config.output_format, - &ReturnSignersConfig { - dump_transaction_message, - }, - ) - } else { - tx.try_sign(&config.signers, recent_blockhash)?; - if let Some(nonce_account) = &nonce_account { - let nonce_account = nonce_utils::get_account_with_commitment( - rpc_client, - nonce_account, - config.commitment, - )?; - check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?; - } - check_account_for_fee_with_commitment( - rpc_client, - &config.signers[0].pubkey(), - &fee_calculator, - &tx.message, - config.commitment, - )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); - log_instruction_custom_error::(result, config) - } + tx.try_sign(&config.signers, recent_blockhash)?; + check_account_for_fee_with_commitment( + rpc_client, + &config.signers[0].pubkey(), + &fee_calculator, + &tx.message, + config.commitment, + )?; + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); + log_instruction_custom_error::(result, config) } -#[allow(clippy::too_many_arguments)] pub fn process_vote_update_commission( rpc_client: &RpcClient, config: &CliConfig, vote_account_pubkey: &Pubkey, commission: u8, withdraw_authority: SignerIndex, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: &BlockhashQuery, - nonce_account: Option, - nonce_authority: SignerIndex, memo: Option<&String>, - fee_payer: SignerIndex, ) -> ProcessResult { let authorized_withdrawer = config.signers[withdraw_authority]; - let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_and_fee_calculator(rpc_client, config.commitment)?; + let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?; let ixs = vec![vote_instruction::update_commission( vote_account_pubkey, &authorized_withdrawer.pubkey(), commission, )] .with_memo(memo); - let nonce_authority = config.signers[nonce_authority]; - let fee_payer = config.signers[fee_payer]; - let message = if let Some(nonce_account) = &nonce_account { - Message::new_with_nonce( - ixs, - Some(&fee_payer.pubkey()), - nonce_account, - &nonce_authority.pubkey(), - ) - } else { - Message::new(&ixs, Some(&fee_payer.pubkey())) - }; + let message = Message::new(&ixs, Some(&config.signers[0].pubkey())); let mut tx = Transaction::new_unsigned(message); - if sign_only { - tx.try_partial_sign(&config.signers, recent_blockhash)?; - return_signers_with_config( - &tx, - &config.output_format, - &ReturnSignersConfig { - dump_transaction_message, - }, - ) - } else { - tx.try_sign(&config.signers, recent_blockhash)?; - if let Some(nonce_account) = &nonce_account { - let nonce_account = nonce_utils::get_account_with_commitment( - rpc_client, - nonce_account, - config.commitment, - )?; - check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?; - } - check_account_for_fee_with_commitment( - rpc_client, - &config.signers[0].pubkey(), - &fee_calculator, - &tx.message, - config.commitment, - )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); - log_instruction_custom_error::(result, config) - } + tx.try_sign(&config.signers, recent_blockhash)?; + check_account_for_fee_with_commitment( + rpc_client, + &config.signers[0].pubkey(), + &fee_calculator, + &tx.message, + config.commitment, + )?; + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); + log_instruction_custom_error::(result, config) } fn get_vote_account( @@ -1160,7 +887,6 @@ pub fn process_show_vote_account( Ok(config.output_format.formatted_string(&vote_account_data)) } -#[allow(clippy::too_many_arguments)] pub fn process_withdraw_from_vote_account( rpc_client: &RpcClient, config: &CliConfig, @@ -1168,99 +894,47 @@ pub fn process_withdraw_from_vote_account( withdraw_authority: SignerIndex, withdraw_amount: SpendAmount, destination_account_pubkey: &Pubkey, - sign_only: bool, - dump_transaction_message: bool, - blockhash_query: &BlockhashQuery, - nonce_account: Option<&Pubkey>, - nonce_authority: SignerIndex, memo: Option<&String>, - fee_payer: SignerIndex, ) -> ProcessResult { + let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?; let withdraw_authority = config.signers[withdraw_authority]; - let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_and_fee_calculator(rpc_client, config.commitment)?; - let fee_payer = config.signers[fee_payer]; - let nonce_authority = config.signers[nonce_authority]; + let current_balance = rpc_client.get_balance(vote_account_pubkey)?; + let minimum_balance = rpc_client.get_minimum_balance_for_rent_exemption(VoteState::size_of())?; - let build_message = |lamports| { - let ixs = vec![withdraw( - vote_account_pubkey, - &withdraw_authority.pubkey(), - lamports, - destination_account_pubkey, - )] - .with_memo(memo); - - if let Some(nonce_account) = &nonce_account { - Message::new_with_nonce( - ixs, - Some(&fee_payer.pubkey()), - nonce_account, - &nonce_authority.pubkey(), - ) - } else { - Message::new(&ixs, Some(&fee_payer.pubkey())) - } - }; - - let (message, _) = resolve_spend_tx_and_check_account_balances( - rpc_client, - sign_only, - withdraw_amount, - &fee_calculator, - vote_account_pubkey, - &fee_payer.pubkey(), - build_message, - config.commitment, - )?; - - if !sign_only { - let current_balance = rpc_client.get_balance(vote_account_pubkey)?; - let minimum_balance = - rpc_client.get_minimum_balance_for_rent_exemption(VoteState::size_of())?; - if let SpendAmount::Some(withdraw_amount) = withdraw_amount { - let balance_remaining = current_balance.saturating_sub(withdraw_amount); - if balance_remaining < minimum_balance && balance_remaining != 0 { + let lamports = match withdraw_amount { + SpendAmount::All => current_balance.saturating_sub(minimum_balance), + SpendAmount::Some(withdraw_amount) => { + if current_balance.saturating_sub(withdraw_amount) < minimum_balance { return Err(CliError::BadParameter(format!( "Withdraw amount too large. The vote account balance must be at least {} SOL to remain rent exempt", lamports_to_sol(minimum_balance) )) .into()); } + withdraw_amount } - } + }; - let mut tx = Transaction::new_unsigned(message); + let ixs = vec![withdraw( + vote_account_pubkey, + &withdraw_authority.pubkey(), + lamports, + destination_account_pubkey, + )] + .with_memo(memo); - if sign_only { - tx.try_partial_sign(&config.signers, recent_blockhash)?; - return_signers_with_config( - &tx, - &config.output_format, - &ReturnSignersConfig { - dump_transaction_message, - }, - ) - } else { - tx.try_sign(&config.signers, recent_blockhash)?; - if let Some(nonce_account) = &nonce_account { - let nonce_account = nonce_utils::get_account_with_commitment( - rpc_client, - nonce_account, - config.commitment, - )?; - check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?; - } - check_account_for_fee_with_commitment( - rpc_client, - &tx.message.account_keys[0], - &fee_calculator, - &tx.message, - config.commitment, - )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); - log_instruction_custom_error::(result, config) - } + let message = Message::new(&ixs, Some(&config.signers[0].pubkey())); + let mut transaction = Transaction::new_unsigned(message); + transaction.try_sign(&config.signers, recent_blockhash)?; + check_account_for_fee_with_commitment( + rpc_client, + &config.signers[0].pubkey(), + &fee_calculator, + &transaction.message, + config.commitment, + )?; + let result = rpc_client.send_and_confirm_transaction_with_spinner(&transaction); + log_instruction_custom_error::(result, config) } #[cfg(test)] @@ -1268,12 +942,7 @@ mod tests { use { super::*, crate::{clap_app::get_clap_app, cli::parse_command}, - solana_client::blockhash_query, - solana_sdk::{ - hash::Hash, - signature::{read_keypair_file, write_keypair, Keypair, Signer}, - signer::presigner::Presigner, - }, + solana_sdk::signature::{read_keypair_file, write_keypair, Keypair, Signer}, tempfile::NamedTempFile, }; @@ -1291,19 +960,12 @@ mod tests { let keypair2 = Keypair::new(); let pubkey2 = keypair2.pubkey(); let pubkey2_string = pubkey2.to_string(); - let sig2 = keypair2.sign_message(&[0u8]); - let signer2 = format!("{}={}", keypair2.pubkey(), sig2); let default_keypair = Keypair::new(); let (default_keypair_file, mut tmp_file) = make_tmp_file(); write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap(); let default_signer = DefaultSigner::new("", &default_keypair_file); - let blockhash = Hash::default(); - let blockhash_string = format!("{}", blockhash); - let nonce_account = Pubkey::new_unique(); - - // Test VoteAuthorize SubCommand let test_authorize_voter = test_commands.clone().get_matches_from(vec![ "test", "vote-authorize-voter", @@ -1318,13 +980,7 @@ mod tests { vote_account_pubkey: pubkey, new_authorized_pubkey: pubkey2, vote_authorize: VoteAuthorize::Voter, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, authorized: 0, new_authorized: None, }, @@ -1350,13 +1006,7 @@ mod tests { vote_account_pubkey: pubkey, new_authorized_pubkey: pubkey2, vote_authorize: VoteAuthorize::Voter, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, authorized: 1, new_authorized: None, }, @@ -1367,89 +1017,6 @@ mod tests { } ); - let test_authorize_voter = test_commands.clone().get_matches_from(vec![ - "test", - "vote-authorize-voter", - &pubkey_string, - &authorized_keypair_file, - &pubkey2_string, - "--blockhash", - &blockhash_string, - "--sign-only", - ]); - assert_eq!( - parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(), - CliCommandInfo { - command: CliCommand::VoteAuthorize { - vote_account_pubkey: pubkey, - new_authorized_pubkey: pubkey2, - vote_authorize: VoteAuthorize::Voter, - sign_only: true, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::None(blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - authorized: 1, - new_authorized: None, - }, - signers: vec![ - read_keypair_file(&default_keypair_file).unwrap().into(), - read_keypair_file(&authorized_keypair_file).unwrap().into(), - ], - } - ); - - let authorized_sig = authorized_keypair.sign_message(&[0u8]); - let authorized_signer = format!("{}={}", authorized_keypair.pubkey(), authorized_sig); - let test_authorize_voter = test_commands.clone().get_matches_from(vec![ - "test", - "vote-authorize-voter", - &pubkey_string, - &authorized_keypair.pubkey().to_string(), - &pubkey2_string, - "--blockhash", - &blockhash_string, - "--signer", - &authorized_signer, - "--signer", - &signer2, - "--fee-payer", - &pubkey2_string, - "--nonce", - &nonce_account.to_string(), - "--nonce-authority", - &pubkey2_string, - ]); - assert_eq!( - parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(), - CliCommandInfo { - command: CliCommand::VoteAuthorize { - vote_account_pubkey: pubkey, - new_authorized_pubkey: pubkey2, - vote_authorize: VoteAuthorize::Voter, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::FeeCalculator( - blockhash_query::Source::NonceAccount(nonce_account), - blockhash - ), - nonce_account: Some(nonce_account), - nonce_authority: 0, - memo: None, - fee_payer: 0, - authorized: 1, - new_authorized: None, - }, - signers: vec![ - Presigner::new(&pubkey2, &sig2).into(), - Presigner::new(&authorized_keypair.pubkey(), &authorized_sig).into(), - ], - } - ); - - // Test checked VoteAuthorize SubCommand let (voter_keypair_file, mut tmp_file) = make_tmp_file(); let voter_keypair = Keypair::new(); write_keypair(&voter_keypair, tmp_file.as_file_mut()).unwrap(); @@ -1468,13 +1035,7 @@ mod tests { vote_account_pubkey: pubkey, new_authorized_pubkey: voter_keypair.pubkey(), vote_authorize: VoteAuthorize::Voter, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, authorized: 0, new_authorized: Some(1), }, @@ -1499,13 +1060,7 @@ mod tests { vote_account_pubkey: pubkey, new_authorized_pubkey: voter_keypair.pubkey(), vote_authorize: VoteAuthorize::Voter, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, authorized: 1, new_authorized: Some(2), }, @@ -1526,15 +1081,14 @@ mod tests { ]); assert!(parse_command(&test_authorize_voter, &default_signer, &mut None).is_err()); + let (keypair_file, mut tmp_file) = make_tmp_file(); + let keypair = Keypair::new(); + write_keypair(&keypair, tmp_file.as_file_mut()).unwrap(); // Test CreateVoteAccount SubCommand let (identity_keypair_file, mut tmp_file) = make_tmp_file(); let identity_keypair = Keypair::new(); let authorized_withdrawer = Keypair::new().pubkey(); write_keypair(&identity_keypair, tmp_file.as_file_mut()).unwrap(); - let (keypair_file, mut tmp_file) = make_tmp_file(); - let keypair = Keypair::new(); - write_keypair(&keypair, tmp_file.as_file_mut()).unwrap(); - let test_create_vote_account = test_commands.clone().get_matches_from(vec![ "test", "create-vote-account", @@ -1554,22 +1108,20 @@ mod tests { authorized_voter: None, authorized_withdrawer, commission: 10, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), - read_keypair_file(&keypair_file).unwrap().into(), + Box::new(keypair), read_keypair_file(&identity_keypair_file).unwrap().into(), ], } ); + let (keypair_file, mut tmp_file) = make_tmp_file(); + let keypair = Keypair::new(); + write_keypair(&keypair, tmp_file.as_file_mut()).unwrap(); + let test_create_vote_account2 = test_commands.clone().get_matches_from(vec![ "test", "create-vote-account", @@ -1587,115 +1139,16 @@ mod tests { authorized_voter: None, authorized_withdrawer, commission: 100, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), - read_keypair_file(&keypair_file).unwrap().into(), + Box::new(keypair), read_keypair_file(&identity_keypair_file).unwrap().into(), ], } ); - let test_create_vote_account = test_commands.clone().get_matches_from(vec![ - "test", - "create-vote-account", - &keypair_file, - &identity_keypair_file, - &authorized_withdrawer.to_string(), - "--commission", - "10", - "--blockhash", - &blockhash_string, - "--sign-only", - "--fee-payer", - &default_keypair.pubkey().to_string(), - ]); - assert_eq!( - parse_command(&test_create_vote_account, &default_signer, &mut None).unwrap(), - CliCommandInfo { - command: CliCommand::CreateVoteAccount { - vote_account: 1, - seed: None, - identity_account: 2, - authorized_voter: None, - authorized_withdrawer, - commission: 10, - sign_only: true, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::None(blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }, - signers: vec![ - read_keypair_file(&default_keypair_file).unwrap().into(), - read_keypair_file(&keypair_file).unwrap().into(), - read_keypair_file(&identity_keypair_file).unwrap().into(), - ], - } - ); - - let identity_sig = identity_keypair.sign_message(&[0u8]); - let identity_signer = format!("{}={}", identity_keypair.pubkey(), identity_sig); - let test_create_vote_account = test_commands.clone().get_matches_from(vec![ - "test", - "create-vote-account", - &keypair_file, - &identity_keypair.pubkey().to_string(), - &authorized_withdrawer.to_string(), - "--commission", - "10", - "--blockhash", - &blockhash_string, - "--signer", - &identity_signer, - "--signer", - &signer2, - "--fee-payer", - &default_keypair_file, - "--nonce", - &nonce_account.to_string(), - "--nonce-authority", - &pubkey2_string, - ]); - assert_eq!( - parse_command(&test_create_vote_account, &default_signer, &mut None).unwrap(), - CliCommandInfo { - command: CliCommand::CreateVoteAccount { - vote_account: 1, - seed: None, - identity_account: 2, - authorized_voter: None, - authorized_withdrawer, - commission: 10, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::FeeCalculator( - blockhash_query::Source::NonceAccount(nonce_account), - blockhash - ), - nonce_account: Some(nonce_account), - nonce_authority: 3, - memo: None, - fee_payer: 0, - }, - signers: vec![ - read_keypair_file(&default_keypair_file).unwrap().into(), - read_keypair_file(&keypair_file).unwrap().into(), - Presigner::new(&identity_keypair.pubkey(), &identity_sig).into(), - Presigner::new(&pubkey2, &sig2).into(), - ], - } - ); - // test init with an authed voter let authed = solana_sdk::pubkey::new_rand(); let (keypair_file, mut tmp_file) = make_tmp_file(); @@ -1721,13 +1174,7 @@ mod tests { authorized_voter: Some(authed), authorized_withdrawer, commission: 100, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), @@ -1759,17 +1206,11 @@ mod tests { authorized_voter: None, authorized_withdrawer: identity_keypair.pubkey(), commission: 100, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), - read_keypair_file(&keypair_file).unwrap().into(), + Box::new(keypair), read_keypair_file(&identity_keypair_file).unwrap().into(), ], } @@ -1789,13 +1230,7 @@ mod tests { vote_account_pubkey: pubkey, new_identity_account: 2, withdraw_authority: 1, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), @@ -1819,13 +1254,7 @@ mod tests { vote_account_pubkey: pubkey, commission: 42, withdraw_authority: 1, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), @@ -1850,13 +1279,7 @@ mod tests { destination_account_pubkey: pubkey, withdraw_authority: 0, withdraw_amount: SpendAmount::Some(42_000_000_000), - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }, signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()], } @@ -1878,13 +1301,7 @@ mod tests { destination_account_pubkey: pubkey, withdraw_authority: 0, withdraw_amount: SpendAmount::All, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }, signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()], } @@ -1911,13 +1328,7 @@ mod tests { destination_account_pubkey: pubkey, withdraw_authority: 1, withdraw_amount: SpendAmount::Some(42_000_000_000), - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }, signers: vec![ read_keypair_file(&default_keypair_file).unwrap().into(), @@ -1925,80 +1336,5 @@ mod tests { ], } ); - - // Test WithdrawFromVoteAccount subcommand with offline authority - let test_withdraw_from_vote_account = test_commands.clone().get_matches_from(vec![ - "test", - "withdraw-from-vote-account", - &keypair.pubkey().to_string(), - &pubkey_string, - "42", - "--authorized-withdrawer", - &withdraw_authority_file, - "--blockhash", - &blockhash_string, - "--sign-only", - "--fee-payer", - &withdraw_authority_file, - ]); - assert_eq!( - parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(), - CliCommandInfo { - command: CliCommand::WithdrawFromVoteAccount { - vote_account_pubkey: keypair.pubkey(), - destination_account_pubkey: pubkey, - withdraw_authority: 0, - withdraw_amount: SpendAmount::Some(42_000_000_000), - sign_only: true, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::None(blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }, - signers: vec![read_keypair_file(&withdraw_authority_file).unwrap().into()], - } - ); - - let authorized_sig = withdraw_authority.sign_message(&[0u8]); - let authorized_signer = format!("{}={}", withdraw_authority.pubkey(), authorized_sig); - let test_withdraw_from_vote_account = test_commands.clone().get_matches_from(vec![ - "test", - "withdraw-from-vote-account", - &keypair.pubkey().to_string(), - &pubkey_string, - "42", - "--authorized-withdrawer", - &withdraw_authority.pubkey().to_string(), - "--blockhash", - &blockhash_string, - "--signer", - &authorized_signer, - "--fee-payer", - &withdraw_authority.pubkey().to_string(), - ]); - assert_eq!( - parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(), - CliCommandInfo { - command: CliCommand::WithdrawFromVoteAccount { - vote_account_pubkey: keypair.pubkey(), - destination_account_pubkey: pubkey, - withdraw_authority: 0, - withdraw_amount: SpendAmount::Some(42_000_000_000), - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::FeeCalculator( - blockhash_query::Source::Cluster, - blockhash - ), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }, - signers: vec![Presigner::new(&withdraw_authority.pubkey(), &authorized_sig).into(),], - } - ); } } diff --git a/cli/tests/stake.rs b/cli/tests/stake.rs index 6d4632cc7d..e9d039ad40 100644 --- a/cli/tests/stake.rs +++ b/cli/tests/stake.rs @@ -58,13 +58,7 @@ fn test_stake_delegation_force() { authorized_voter: None, authorized_withdrawer, commission: 0, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }; process_command(&config).unwrap(); diff --git a/cli/tests/vote.rs b/cli/tests/vote.rs index d71d2b9d36..c0e6cb51cd 100644 --- a/cli/tests/vote.rs +++ b/cli/tests/vote.rs @@ -4,7 +4,6 @@ use { spend_utils::SpendAmount, test_utils::check_recent_balance, }, - solana_cli_output::{parse_sign_only_reply_string, OutputFormat}, solana_client::{ blockhash_query::{self, BlockhashQuery}, rpc_client::RpcClient, @@ -14,7 +13,7 @@ use { solana_sdk::{ account_utils::StateMut, commitment_config::CommitmentConfig, - signature::{Keypair, NullSigner, Signer}, + signature::{Keypair, Signer}, }, solana_streamer::socket::SocketAddrSpace, solana_vote_program::vote_state::{VoteAuthorize, VoteState, VoteStateVersions}, @@ -50,13 +49,7 @@ fn test_vote_authorize_and_withdraw() { authorized_voter: None, authorized_withdrawer: config.signers[0].pubkey(), commission: 0, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }; process_command(&config).unwrap(); let vote_account = rpc_client @@ -100,13 +93,7 @@ fn test_vote_authorize_and_withdraw() { vote_account_pubkey, new_authorized_pubkey: first_withdraw_authority.pubkey(), vote_authorize: VoteAuthorize::Withdrawer, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, authorized: 0, new_authorized: None, }; @@ -125,13 +112,7 @@ fn test_vote_authorize_and_withdraw() { vote_account_pubkey, new_authorized_pubkey: withdraw_authority.pubkey(), vote_authorize: VoteAuthorize::Withdrawer, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, authorized: 1, new_authorized: Some(1), }; @@ -145,13 +126,7 @@ fn test_vote_authorize_and_withdraw() { vote_account_pubkey, new_authorized_pubkey: withdraw_authority.pubkey(), vote_authorize: VoteAuthorize::Withdrawer, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, authorized: 1, new_authorized: Some(2), }; @@ -171,13 +146,7 @@ fn test_vote_authorize_and_withdraw() { withdraw_authority: 1, withdraw_amount: SpendAmount::Some(100), destination_account_pubkey: destination_account, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }; process_command(&config).unwrap(); check_recent_balance(expected_balance - 100, &rpc_client, &vote_account_pubkey); @@ -190,287 +159,7 @@ fn test_vote_authorize_and_withdraw() { vote_account_pubkey, new_identity_account: 2, withdraw_authority: 1, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, memo: None, - fee_payer: 0, }; process_command(&config).unwrap(); } - -#[test] -fn test_offline_vote_authorize_and_withdraw() { - let mint_keypair = Keypair::new(); - let mint_pubkey = mint_keypair.pubkey(); - let faucet_addr = run_local_faucet(mint_keypair, None); - let test_validator = - TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified); - - let rpc_client = - RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed()); - let default_signer = Keypair::new(); - - let mut config_payer = CliConfig::recent_for_tests(); - config_payer.json_rpc_url = test_validator.rpc_url(); - config_payer.signers = vec![&default_signer]; - - let mut config_offline = CliConfig::recent_for_tests(); - config_offline.json_rpc_url = String::default(); - config_offline.command = CliCommand::ClusterVersion; - let offline_keypair = Keypair::new(); - config_offline.signers = vec![&offline_keypair]; - // Verify that we cannot reach the cluster - process_command(&config_offline).unwrap_err(); - - request_and_confirm_airdrop( - &rpc_client, - &config_payer, - &config_payer.signers[0].pubkey(), - 100_000, - ) - .unwrap(); - check_recent_balance(100_000, &rpc_client, &config_payer.signers[0].pubkey()); - - request_and_confirm_airdrop( - &rpc_client, - &config_offline, - &config_offline.signers[0].pubkey(), - 100_000, - ) - .unwrap(); - check_recent_balance(100_000, &rpc_client, &config_offline.signers[0].pubkey()); - - // Create vote account with specific withdrawer - let vote_account_keypair = Keypair::new(); - let vote_account_pubkey = vote_account_keypair.pubkey(); - config_payer.signers = vec![&default_signer, &vote_account_keypair]; - config_payer.command = CliCommand::CreateVoteAccount { - vote_account: 1, - seed: None, - identity_account: 0, - authorized_voter: None, - authorized_withdrawer: offline_keypair.pubkey(), - commission: 0, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }; - process_command(&config_payer).unwrap(); - let vote_account = rpc_client - .get_account(&vote_account_keypair.pubkey()) - .unwrap(); - let vote_state: VoteStateVersions = vote_account.state().unwrap(); - let authorized_withdrawer = vote_state.convert_to_current().authorized_withdrawer; - assert_eq!(authorized_withdrawer, offline_keypair.pubkey()); - let expected_balance = rpc_client - .get_minimum_balance_for_rent_exemption(VoteState::size_of()) - .unwrap() - .max(1); - check_recent_balance(expected_balance, &rpc_client, &vote_account_pubkey); - - // Transfer in some more SOL - config_payer.signers = vec![&default_signer]; - config_payer.command = CliCommand::Transfer { - amount: SpendAmount::Some(1_000), - to: vote_account_pubkey, - from: 0, - sign_only: false, - dump_transaction_message: false, - allow_unfunded_recipient: true, - no_wait: false, - blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - derived_address_seed: None, - derived_address_program_id: None, - }; - process_command(&config_payer).unwrap(); - let expected_balance = expected_balance + 1_000; - check_recent_balance(expected_balance, &rpc_client, &vote_account_pubkey); - - // Authorize vote account withdrawal to another signer, offline - let withdraw_authority = Keypair::new(); - let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap(); - config_offline.command = CliCommand::VoteAuthorize { - vote_account_pubkey, - new_authorized_pubkey: withdraw_authority.pubkey(), - vote_authorize: VoteAuthorize::Withdrawer, - sign_only: true, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::None(blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - authorized: 0, - new_authorized: None, - }; - config_offline.output_format = OutputFormat::JsonCompact; - let sig_response = process_command(&config_offline).unwrap(); - let sign_only = parse_sign_only_reply_string(&sig_response); - assert!(sign_only.has_all_signers()); - let offline_presigner = sign_only - .presigner_of(&config_offline.signers[0].pubkey()) - .unwrap(); - config_payer.signers = vec![&offline_presigner]; - config_payer.command = CliCommand::VoteAuthorize { - vote_account_pubkey, - new_authorized_pubkey: withdraw_authority.pubkey(), - vote_authorize: VoteAuthorize::Withdrawer, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - authorized: 0, - new_authorized: None, - }; - process_command(&config_payer).unwrap(); - let vote_account = rpc_client - .get_account(&vote_account_keypair.pubkey()) - .unwrap(); - let vote_state: VoteStateVersions = vote_account.state().unwrap(); - let authorized_withdrawer = vote_state.convert_to_current().authorized_withdrawer; - assert_eq!(authorized_withdrawer, withdraw_authority.pubkey()); - - // Withdraw from vote account offline - let destination_account = solana_sdk::pubkey::new_rand(); // Send withdrawal to new account to make balance check easy - let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap(); - let fee_payer_null_signer = NullSigner::new(&default_signer.pubkey()); - config_offline.signers = vec![&fee_payer_null_signer, &withdraw_authority]; - config_offline.command = CliCommand::WithdrawFromVoteAccount { - vote_account_pubkey, - withdraw_authority: 1, - withdraw_amount: SpendAmount::Some(100), - destination_account_pubkey: destination_account, - sign_only: true, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::None(blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }; - config_offline.output_format = OutputFormat::JsonCompact; - let sig_response = process_command(&config_offline).unwrap(); - let sign_only = parse_sign_only_reply_string(&sig_response); - let offline_presigner = sign_only - .presigner_of(&config_offline.signers[1].pubkey()) - .unwrap(); - config_payer.signers = vec![&default_signer, &offline_presigner]; - config_payer.command = CliCommand::WithdrawFromVoteAccount { - vote_account_pubkey, - withdraw_authority: 1, - withdraw_amount: SpendAmount::Some(100), - destination_account_pubkey: destination_account, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }; - process_command(&config_payer).unwrap(); - let expected_balance = expected_balance - 100; - check_recent_balance(expected_balance, &rpc_client, &vote_account_pubkey); - check_recent_balance(100, &rpc_client, &destination_account); - - // Re-assign validator identity offline - let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap(); - let new_identity_keypair = Keypair::new(); - let new_identity_null_signer = NullSigner::new(&new_identity_keypair.pubkey()); - config_offline.signers = vec![ - &fee_payer_null_signer, - &withdraw_authority, - &new_identity_null_signer, - ]; - config_offline.command = CliCommand::VoteUpdateValidator { - vote_account_pubkey, - new_identity_account: 2, - withdraw_authority: 1, - sign_only: true, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::None(blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }; - process_command(&config_offline).unwrap(); - config_offline.output_format = OutputFormat::JsonCompact; - let sig_response = process_command(&config_offline).unwrap(); - let sign_only = parse_sign_only_reply_string(&sig_response); - let offline_presigner = sign_only - .presigner_of(&config_offline.signers[1].pubkey()) - .unwrap(); - config_payer.signers = vec![&default_signer, &offline_presigner, &new_identity_keypair]; - config_payer.command = CliCommand::VoteUpdateValidator { - vote_account_pubkey, - new_identity_account: 2, - withdraw_authority: 1, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }; - process_command(&config_payer).unwrap(); - - // Close vote account offline. Must use WithdrawFromVoteAccount and specify amount, since - // CloseVoteAccount requires RpcClient - let destination_account = solana_sdk::pubkey::new_rand(); // Send withdrawal to new account to make balance check easy - config_offline.signers = vec![&fee_payer_null_signer, &withdraw_authority]; - config_offline.command = CliCommand::WithdrawFromVoteAccount { - vote_account_pubkey, - withdraw_authority: 1, - withdraw_amount: SpendAmount::Some(expected_balance), - destination_account_pubkey: destination_account, - sign_only: true, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::None(blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }; - process_command(&config_offline).unwrap(); - config_offline.output_format = OutputFormat::JsonCompact; - let sig_response = process_command(&config_offline).unwrap(); - let sign_only = parse_sign_only_reply_string(&sig_response); - let offline_presigner = sign_only - .presigner_of(&config_offline.signers[1].pubkey()) - .unwrap(); - config_payer.signers = vec![&default_signer, &offline_presigner]; - config_payer.command = CliCommand::WithdrawFromVoteAccount { - vote_account_pubkey, - withdraw_authority: 1, - withdraw_amount: SpendAmount::Some(expected_balance), - destination_account_pubkey: destination_account, - sign_only: false, - dump_transaction_message: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), - nonce_account: None, - nonce_authority: 0, - memo: None, - fee_payer: 0, - }; - let result = process_command(&config_payer).unwrap(); - println!("{:?}", result); - check_recent_balance(0, &rpc_client, &vote_account_pubkey); - println!("what"); - check_recent_balance(expected_balance, &rpc_client, &destination_account); -} diff --git a/docs/src/offline-signing.md b/docs/src/offline-signing.md index afdf2651ef..1b4075552d 100644 --- a/docs/src/offline-signing.md +++ b/docs/src/offline-signing.md @@ -19,26 +19,14 @@ transaction. At present, the following commands support offline signing: - [`create-stake-account`](cli/usage.md#solana-create-stake-account) -- [`create-stake-account-checked`](cli/usage.md#solana-create-stake-account-checked) - [`deactivate-stake`](cli/usage.md#solana-deactivate-stake) - [`delegate-stake`](cli/usage.md#solana-delegate-stake) - [`split-stake`](cli/usage.md#solana-split-stake) - [`stake-authorize`](cli/usage.md#solana-stake-authorize) -- [`stake-authorize-checked`](cli/usage.md#solana-stake-authorize-checked) - [`stake-set-lockup`](cli/usage.md#solana-stake-set-lockup) -- [`stake-set-lockup-checked`](cli/usage.md#solana-stake-set-lockup-checked) - [`transfer`](cli/usage.md#solana-transfer) - [`withdraw-stake`](cli/usage.md#solana-withdraw-stake) -- [`create-vote-account`](cli/usage.md#solana-create-vote-account) -- [`vote-authorize-voter`](cli/usage.md#solana-vote-authorize-voter) -- [`vote-authorize-voter-checked`](cli/usage.md#solana-vote-authorize-voter-checked) -- [`vote-authorize-withdrawer`](cli/usage.md#solana-vote-authorize-withdrawer) -- [`vote-authorize-withdrawer-checked`](cli/usage.md#solana-vote-authorize-withdrawer-checked) -- [`vote-update-commission`](cli/usage.md#solana-vote-update-commission) -- [`vote-update-validator`](cli/usage.md#solana-vote-update-validator) -- [`withdraw-from-vote-account`](cli/usage.md#solana-withdraw-from-vote-account) - ## Signing Transactions Offline To sign a transaction offline, pass the following arguments on the command line