diff --git a/Cargo.lock b/Cargo.lock index a42b9167b0..4208500e89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3595,6 +3595,7 @@ dependencies = [ "serde_derive", "serde_json", "solana-account-decoder", + "solana-clap-utils", "solana-logger 1.4.0", "solana-net-utils", "solana-sdk 1.4.0", diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 4ed26e5ec8..6abe5152ec 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1440,8 +1440,11 @@ fn process_transfer( return_signers(&tx, &config) } else { if let Some(nonce_account) = &nonce_account { - let nonce_account = - nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?; + 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)?; } diff --git a/cli/src/nonce.rs b/cli/src/nonce.rs index 56bc62fb78..91687223a9 100644 --- a/cli/src/nonce.rs +++ b/cli/src/nonce.rs @@ -11,19 +11,13 @@ use clap::{App, Arg, ArgMatches, SubCommand}; use solana_clap_utils::{ input_parsers::*, input_validators::*, offline::BLOCKHASH_ARG, ArgConstant, }; -use solana_client::{nonce_utils::Error, rpc_client::RpcClient}; +use solana_client::{nonce_utils::*, rpc_client::RpcClient}; use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_sdk::{ account::Account, - account_utils::StateMut, - commitment_config::CommitmentConfig, hash::Hash, message::Message, - nonce::{ - self, - state::{Data, Versions}, - State, - }, + nonce::{self, State}, pubkey::Pubkey, system_instruction::{ advance_nonce_account, authorize_nonce_account, create_nonce_account, @@ -201,58 +195,6 @@ impl NonceSubCommands for App<'_, '_> { } } -pub fn get_account(rpc_client: &RpcClient, nonce_pubkey: &Pubkey) -> Result { - get_account_with_commitment(rpc_client, nonce_pubkey, CommitmentConfig::default()) -} - -pub fn get_account_with_commitment( - rpc_client: &RpcClient, - nonce_pubkey: &Pubkey, - commitment: CommitmentConfig, -) -> Result { - rpc_client - .get_account_with_commitment(nonce_pubkey, commitment) - .map_err(|e| Error::Client(format!("{}", e))) - .and_then(|result| { - result - .value - .ok_or_else(|| Error::Client(format!("AccountNotFound: pubkey={}", nonce_pubkey))) - }) - .and_then(|a| match account_identity_ok(&a) { - Ok(()) => Ok(a), - Err(e) => Err(e), - }) -} - -pub fn account_identity_ok(account: &Account) -> Result<(), Error> { - if account.owner != system_program::id() { - Err(Error::InvalidAccountOwner) - } else if account.data.is_empty() { - Err(Error::UnexpectedDataSize) - } else { - Ok(()) - } -} - -pub fn state_from_account(account: &Account) -> Result { - account_identity_ok(account)?; - StateMut::::state(account) - .map_err(|_| Error::InvalidAccountData) - .map(|v| v.convert_to_current()) -} - -pub fn data_from_account(account: &Account) -> Result { - account_identity_ok(account)?; - state_from_account(account).and_then(|ref s| data_from_state(s).map(|d| d.clone())) -} - -pub fn data_from_state(state: &State) -> Result<&Data, Error> { - match state { - State::Uninitialized => Err(Error::InvalidStateForOperation), - State::Initialized(data) => Ok(data), - } -} - pub fn parse_authorize_nonce_account( matches: &ArgMatches<'_>, default_signer_path: &str, @@ -669,9 +611,10 @@ mod tests { use crate::cli::{app, parse_command}; use solana_sdk::{ account::Account, + account_utils::StateMut, fee_calculator::FeeCalculator, hash::hash, - nonce::{self, State}, + nonce::{self, state::Versions, State}, signature::{read_keypair_file, write_keypair, Keypair, Signer}, system_program, }; diff --git a/cli/src/offline/blockhash_query.rs b/cli/src/offline/blockhash_query.rs index 486a0817e5..a24d5e7484 100644 --- a/cli/src/offline/blockhash_query.rs +++ b/cli/src/offline/blockhash_query.rs @@ -1,4 +1,5 @@ use super::*; +use solana_client::nonce_utils; use solana_sdk::commitment_config::CommitmentConfig; #[derive(Debug, PartialEq)] @@ -21,8 +22,8 @@ impl Source { Ok((res.0, res.1)) } Self::NonceAccount(ref pubkey) => { - let data = nonce::get_account_with_commitment(rpc_client, pubkey, commitment) - .and_then(|ref a| nonce::data_from_account(a))?; + let data = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment) + .and_then(|ref a| nonce_utils::data_from_account(a))?; Ok((data.blockhash, data.fee_calculator)) } } @@ -42,8 +43,8 @@ impl Source { Ok(res) } Self::NonceAccount(ref pubkey) => { - let res = nonce::get_account_with_commitment(rpc_client, pubkey, commitment)?; - let res = nonce::data_from_account(&res)?; + let res = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)?; + let res = nonce_utils::data_from_account(&res)?; Ok(Some(res) .filter(|d| d.blockhash == *blockhash) .map(|d| d.fee_calculator)) diff --git a/cli/src/stake.rs b/cli/src/stake.rs index dd66f2faba..57668eb544 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -6,13 +6,15 @@ use crate::{ SignerIndex, FEE_PAYER_ARG, }, cli_output::{CliStakeHistory, CliStakeHistoryEntry, CliStakeState, CliStakeType}, - nonce::{self, check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG}, + nonce::{check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG}, offline::{blockhash_query::BlockhashQuery, *}, spend_utils::{resolve_spend_tx_and_check_account_balances, SpendAmount}, }; use clap::{App, Arg, ArgGroup, ArgMatches, SubCommand}; use solana_clap_utils::{input_parsers::*, input_validators::*, offline::*, ArgConstant}; -use solana_client::{rpc_client::RpcClient, rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE}; +use solana_client::{ + nonce_utils, rpc_client::RpcClient, rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE, +}; use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_sdk::{ account_utils::StateMut, @@ -934,8 +936,11 @@ pub fn process_create_stake_account( } if let Some(nonce_account) = &nonce_account { - let nonce_account = - nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?; + 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)?; } } @@ -1006,8 +1011,11 @@ pub fn process_stake_authorize( } else { tx.try_sign(&config.signers, recent_blockhash)?; if let Some(nonce_account) = &nonce_account { - let nonce_account = - nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?; + 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( @@ -1066,8 +1074,11 @@ pub fn process_deactivate_stake_account( } else { tx.try_sign(&config.signers, recent_blockhash)?; if let Some(nonce_account) = &nonce_account { - let nonce_account = - nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?; + 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( @@ -1135,8 +1146,11 @@ pub fn process_withdraw_stake( } else { tx.try_sign(&config.signers, recent_blockhash)?; if let Some(nonce_account) = &nonce_account { - let nonce_account = - nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?; + 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( @@ -1275,8 +1289,11 @@ pub fn process_split_stake( } else { tx.try_sign(&config.signers, recent_blockhash)?; if let Some(nonce_account) = &nonce_account { - let nonce_account = - nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?; + 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( @@ -1374,8 +1391,11 @@ pub fn process_merge_stake( } else { tx.try_sign(&config.signers, recent_blockhash)?; if let Some(nonce_account) = &nonce_account { - let nonce_account = - nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?; + 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( @@ -1437,8 +1457,11 @@ pub fn process_stake_set_lockup( } else { tx.try_sign(&config.signers, recent_blockhash)?; if let Some(nonce_account) = &nonce_account { - let nonce_account = - nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?; + 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( @@ -1722,8 +1745,11 @@ pub fn process_delegate_stake( } else { tx.try_sign(&config.signers, recent_blockhash)?; if let Some(nonce_account) = &nonce_account { - let nonce_account = - nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?; + 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( diff --git a/cli/tests/nonce.rs b/cli/tests/nonce.rs index baec3ed00f..ffd3fd261d 100644 --- a/cli/tests/nonce.rs +++ b/cli/tests/nonce.rs @@ -1,7 +1,6 @@ use solana_cli::{ cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig}, cli_output::OutputFormat, - nonce, offline::{ blockhash_query::{self, BlockhashQuery}, parse_sign_only_reply_string, @@ -9,7 +8,7 @@ use solana_cli::{ spend_utils::SpendAmount, test_utils::{check_ready, check_recent_balance}, }; -use solana_client::rpc_client::RpcClient; +use solana_client::{nonce_utils, rpc_client::RpcClient}; use solana_core::contact_info::ContactInfo; use solana_core::test_validator::{TestValidator, TestValidatorOptions}; use solana_faucet::faucet::run_local_faucet; @@ -302,11 +301,14 @@ fn test_create_account_with_seed() { check_recent_balance(0, &rpc_client, &to_address); // Fetch nonce hash - let nonce_hash = - nonce::get_account_with_commitment(&rpc_client, &nonce_address, CommitmentConfig::recent()) - .and_then(|ref a| nonce::data_from_account(a)) - .unwrap() - .blockhash; + let nonce_hash = nonce_utils::get_account_with_commitment( + &rpc_client, + &nonce_address, + CommitmentConfig::recent(), + ) + .and_then(|ref a| nonce_utils::data_from_account(a)) + .unwrap() + .blockhash; // Test by creating transfer TX with nonce, fully offline let mut authority_config = CliConfig::recent_for_tests(); diff --git a/cli/tests/stake.rs b/cli/tests/stake.rs index 6b6843aaeb..5ce9c9c571 100644 --- a/cli/tests/stake.rs +++ b/cli/tests/stake.rs @@ -1,7 +1,6 @@ use solana_cli::{ cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig}, cli_output::OutputFormat, - nonce, offline::{ blockhash_query::{self, BlockhashQuery}, parse_sign_only_reply_string, @@ -9,7 +8,7 @@ use solana_cli::{ spend_utils::SpendAmount, test_utils::{check_ready, check_recent_balance}, }; -use solana_client::rpc_client::RpcClient; +use solana_client::{nonce_utils, rpc_client::RpcClient}; use solana_core::test_validator::{TestValidator, TestValidatorOptions}; use solana_faucet::faucet::run_local_faucet; use solana_sdk::{ @@ -503,12 +502,12 @@ fn test_nonced_stake_delegation_and_deactivation() { process_command(&config).unwrap(); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; @@ -531,12 +530,12 @@ fn test_nonced_stake_delegation_and_deactivation() { process_command(&config).unwrap(); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; @@ -770,12 +769,12 @@ fn test_stake_authorize() { process_command(&config).unwrap(); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; @@ -824,12 +823,12 @@ fn test_stake_authorize() { }; assert_eq!(current_authority, online_authority_pubkey); - let new_nonce_hash = nonce::get_account_with_commitment( + let new_nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; assert_ne!(nonce_hash, new_nonce_hash); @@ -1069,12 +1068,12 @@ fn test_stake_split() { check_recent_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey()); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; @@ -1338,12 +1337,12 @@ fn test_stake_set_lockup() { check_recent_balance(minimum_nonce_balance, &rpc_client, &nonce_account_pubkey); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; @@ -1465,12 +1464,12 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { process_command(&config).unwrap(); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; @@ -1520,12 +1519,12 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { check_recent_balance(50_000, &rpc_client, &stake_pubkey); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; @@ -1568,12 +1567,12 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { check_recent_balance(42, &rpc_client, &recipient_pubkey); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; diff --git a/cli/tests/transfer.rs b/cli/tests/transfer.rs index 3c849b026a..3b0e15bbff 100644 --- a/cli/tests/transfer.rs +++ b/cli/tests/transfer.rs @@ -1,7 +1,6 @@ use solana_cli::{ cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig}, cli_output::OutputFormat, - nonce, offline::{ blockhash_query::{self, BlockhashQuery}, parse_sign_only_reply_string, @@ -9,7 +8,7 @@ use solana_cli::{ spend_utils::SpendAmount, test_utils::{check_ready, check_recent_balance}, }; -use solana_client::rpc_client::RpcClient; +use solana_client::{nonce_utils, rpc_client::RpcClient}; use solana_core::test_validator::{TestValidator, TestValidatorOptions}; use solana_faucet::faucet::run_local_faucet; use solana_sdk::{ @@ -153,12 +152,12 @@ fn test_transfer() { check_recent_balance(49_987 - minimum_nonce_balance, &rpc_client, &sender_pubkey); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; @@ -181,12 +180,12 @@ fn test_transfer() { process_command(&config).unwrap(); check_recent_balance(49_976 - minimum_nonce_balance, &rpc_client, &sender_pubkey); check_recent_balance(30, &rpc_client, &recipient_pubkey); - let new_nonce_hash = nonce::get_account_with_commitment( + let new_nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; assert_ne!(nonce_hash, new_nonce_hash); @@ -202,12 +201,12 @@ fn test_transfer() { check_recent_balance(49_975 - minimum_nonce_balance, &rpc_client, &sender_pubkey); // Fetch nonce hash - let nonce_hash = nonce::get_account_with_commitment( + let nonce_hash = nonce_utils::get_account_with_commitment( &rpc_client, &nonce_account.pubkey(), CommitmentConfig::recent(), ) - .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|ref a| nonce_utils::data_from_account(a)) .unwrap() .blockhash; diff --git a/client/Cargo.toml b/client/Cargo.toml index 21a0435956..2978bc8bea 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -20,6 +20,7 @@ serde = "1.0.112" serde_derive = "1.0.103" serde_json = "1.0.56" solana-account-decoder = { path = "../account-decoder", version = "1.4.0" } +solana-clap-utils = { path = "../clap-utils", version = "1.4.0" } solana-net-utils = { path = "../net-utils", version = "1.4.0" } solana-sdk = { path = "../sdk", version = "1.4.0" } solana-transaction-status = { path = "../transaction-status", version = "1.4.0" } diff --git a/client/src/nonce_utils.rs b/client/src/nonce_utils.rs index 6a92892a00..5a2d448380 100644 --- a/client/src/nonce_utils.rs +++ b/client/src/nonce_utils.rs @@ -1,3 +1,16 @@ +use crate::rpc_client::RpcClient; +use solana_sdk::{ + account::Account, + account_utils::StateMut, + commitment_config::CommitmentConfig, + nonce::{ + state::{Data, Versions}, + State, + }, + pubkey::Pubkey, + system_program, +}; + #[derive(Debug, thiserror::Error, PartialEq)] pub enum Error { #[error("invalid account owner")] @@ -15,3 +28,55 @@ pub enum Error { #[error("client error: {0}")] Client(String), } + +pub fn get_account(rpc_client: &RpcClient, nonce_pubkey: &Pubkey) -> Result { + get_account_with_commitment(rpc_client, nonce_pubkey, CommitmentConfig::default()) +} + +pub fn get_account_with_commitment( + rpc_client: &RpcClient, + nonce_pubkey: &Pubkey, + commitment: CommitmentConfig, +) -> Result { + rpc_client + .get_account_with_commitment(nonce_pubkey, commitment) + .map_err(|e| Error::Client(format!("{}", e))) + .and_then(|result| { + result + .value + .ok_or_else(|| Error::Client(format!("AccountNotFound: pubkey={}", nonce_pubkey))) + }) + .and_then(|a| match account_identity_ok(&a) { + Ok(()) => Ok(a), + Err(e) => Err(e), + }) +} + +pub fn account_identity_ok(account: &Account) -> Result<(), Error> { + if account.owner != system_program::id() { + Err(Error::InvalidAccountOwner) + } else if account.data.is_empty() { + Err(Error::UnexpectedDataSize) + } else { + Ok(()) + } +} + +pub fn state_from_account(account: &Account) -> Result { + account_identity_ok(account)?; + StateMut::::state(account) + .map_err(|_| Error::InvalidAccountData) + .map(|v| v.convert_to_current()) +} + +pub fn data_from_account(account: &Account) -> Result { + account_identity_ok(account)?; + state_from_account(account).and_then(|ref s| data_from_state(s).map(|d| d.clone())) +} + +pub fn data_from_state(state: &State) -> Result<&Data, Error> { + match state { + State::Uninitialized => Err(Error::InvalidStateForOperation), + State::Initialized(data) => Ok(data), + } +}