From 0422af2aaeb4ee747afff43971b02db913ef204d Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Wed, 11 Mar 2020 12:14:15 -0600 Subject: [PATCH] CLI: Plumb nonce-stored fees (#8750) automerge --- cli/src/cli.rs | 118 +++------ cli/src/offline.rs | 253 ------------------ cli/src/offline/blockhash_query.rs | 394 +++++++++++++++++++++++++++++ cli/src/offline/mod.rs | 70 +++++ cli/src/stake.rs | 107 +++++--- cli/tests/pay.rs | 15 +- cli/tests/stake.rs | 94 ++++--- cli/tests/transfer.rs | 24 +- 8 files changed, 660 insertions(+), 415 deletions(-) delete mode 100644 cli/src/offline.rs create mode 100644 cli/src/offline/blockhash_query.rs create mode 100644 cli/src/offline/mod.rs diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 1f492c8a31..70b75f4a43 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -2,7 +2,7 @@ use crate::{ cluster_query::*, display::{println_name_value, println_signers}, nonce::{self, *}, - offline::*, + offline::{blockhash_query::BlockhashQuery, *}, stake::*, storage::*, validator_info::*, @@ -990,7 +990,7 @@ pub fn check_unique_pubkeys( } } -pub fn get_blockhash_fee_calculator( +pub fn get_blockhash_and_fee_calculator( rpc_client: &RpcClient, sign_only: bool, blockhash: Option, @@ -1283,7 +1283,8 @@ fn process_pay( (to, "to".to_string()), )?; - let (blockhash, fee_calculator) = blockhash_query.get_blockhash_fee_calculator(rpc_client)?; + let (blockhash, fee_calculator) = + blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?; let cancelable = if cancelable { Some(config.signers[0].pubkey()) @@ -1471,7 +1472,7 @@ fn process_transfer( )?; let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_fee_calculator(rpc_client)?; + blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?; let ixs = vec![system_instruction::transfer(&from.pubkey(), to, lamports)]; let nonce_authority = config.signers[nonce_authority]; @@ -2485,20 +2486,13 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, ' mod tests { use super::*; use serde_json::Value; - use solana_client::{ - mock_rpc_client_request::SIGNATURE, - rpc_request::RpcRequest, - rpc_response::{Response, RpcAccount, RpcResponseContext}, - }; + use solana_client::mock_rpc_client_request::SIGNATURE; use solana_sdk::{ - account::Account, - nonce, pubkey::Pubkey, signature::{keypair_from_seed, read_keypair_file, write_keypair_file, Presigner}, - system_program, transaction::TransactionError, }; - use std::{collections::HashMap, path::PathBuf}; + use std::path::PathBuf; fn make_tmp_path(name: &str) -> String { let out_dir = std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string()); @@ -2855,7 +2849,7 @@ mod tests { command: CliCommand::Pay(PayCommand { lamports: 50_000_000_000, to: pubkey, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), sign_only: true, ..PayCommand::default() }), @@ -2878,7 +2872,10 @@ mod tests { command: CliCommand::Pay(PayCommand { lamports: 50_000_000_000, to: pubkey, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::Cluster, + blockhash + ), ..PayCommand::default() }), signers: vec![read_keypair_file(&keypair_file).unwrap().into()], @@ -2904,7 +2901,10 @@ mod tests { command: CliCommand::Pay(PayCommand { lamports: 50_000_000_000, to: pubkey, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(pubkey), + blockhash + ), nonce_account: Some(pubkey), ..PayCommand::default() }), @@ -2934,7 +2934,10 @@ mod tests { command: CliCommand::Pay(PayCommand { lamports: 50_000_000_000, to: pubkey, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(pubkey), + blockhash + ), nonce_account: Some(pubkey), nonce_authority: 0, ..PayCommand::default() @@ -2969,7 +2972,10 @@ mod tests { command: CliCommand::Pay(PayCommand { lamports: 50_000_000_000, to: pubkey, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(pubkey), + blockhash + ), nonce_account: Some(pubkey), nonce_authority: 0, ..PayCommand::default() @@ -3151,7 +3157,7 @@ mod tests { }, lamports: 1234, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -3169,7 +3175,7 @@ mod tests { lamports: 100, withdraw_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -3269,64 +3275,6 @@ mod tests { SIGNATURE.to_string() ); - // Nonced pay - let blockhash = Hash::default(); - let data = - nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data { - authority: config.signers[0].pubkey(), - blockhash, - fee_calculator: FeeCalculator::default(), - })); - let nonce_response = json!(Response { - context: RpcResponseContext { slot: 1 }, - value: json!(RpcAccount::encode( - Account::new_data(1, &data, &system_program::ID,).unwrap() - )), - }); - let mut mocks = HashMap::new(); - mocks.insert(RpcRequest::GetAccountInfo, nonce_response); - config.rpc_client = Some(RpcClient::new_mock_with_mocks("".to_string(), mocks)); - config.command = CliCommand::Pay(PayCommand { - lamports: 10, - to: bob_pubkey, - nonce_account: Some(bob_pubkey), - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), - ..PayCommand::default() - }); - let signature = process_command(&config); - assert_eq!(signature.unwrap(), SIGNATURE.to_string()); - - // Nonced pay w/ non-payer authority - let bob_keypair = Keypair::new(); - let bob_pubkey = bob_keypair.pubkey(); - let blockhash = Hash::default(); - let data = - nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data { - authority: bob_pubkey, - blockhash, - fee_calculator: FeeCalculator::default(), - })); - let nonce_authority_response = json!(Response { - context: RpcResponseContext { slot: 1 }, - value: json!(RpcAccount::encode( - Account::new_data(1, &data, &system_program::ID,).unwrap() - )), - }); - let mut mocks = HashMap::new(); - mocks.insert(RpcRequest::GetAccountInfo, nonce_authority_response); - config.rpc_client = Some(RpcClient::new_mock_with_mocks("".to_string(), mocks)); - config.command = CliCommand::Pay(PayCommand { - lamports: 10, - to: bob_pubkey, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), - nonce_account: Some(bob_pubkey), - nonce_authority: 1, - ..PayCommand::default() - }); - config.signers = vec![&keypair, &bob_keypair]; - let signature = process_command(&config); - assert_eq!(signature.unwrap(), SIGNATURE.to_string()); - let process_id = Pubkey::new_rand(); config.command = CliCommand::TimeElapsed(bob_pubkey, process_id, dt); config.signers = vec![&keypair]; @@ -3528,7 +3476,7 @@ mod tests { to: to_pubkey, from: 0, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -3557,7 +3505,7 @@ mod tests { to: to_pubkey, from: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -3591,7 +3539,10 @@ mod tests { to: to_pubkey, from: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::Cluster, + blockhash + ), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -3626,7 +3577,10 @@ mod tests { to: to_pubkey, from: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_address), + blockhash + ), nonce_account: Some(nonce_address.into()), nonce_authority: 1, fee_payer: 0, diff --git a/cli/src/offline.rs b/cli/src/offline.rs deleted file mode 100644 index 354dfe7847..0000000000 --- a/cli/src/offline.rs +++ /dev/null @@ -1,253 +0,0 @@ -use clap::{App, Arg, ArgMatches}; -use serde_json::Value; -use solana_clap_utils::{ - input_parsers::value_of, - input_validators::{is_hash, is_pubkey_sig}, - offline::{BLOCKHASH_ARG, SIGNER_ARG, SIGN_ONLY_ARG}, -}; -use solana_client::rpc_client::RpcClient; -use solana_sdk::{fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey, signature::Signature}; -use std::str::FromStr; - -#[derive(Clone, Debug, PartialEq)] -pub enum BlockhashQuery { - None(Hash, FeeCalculator), - FeeCalculator(Hash), - All, -} - -impl BlockhashQuery { - pub fn new(blockhash: Option, sign_only: bool) -> Self { - match blockhash { - Some(hash) if sign_only => Self::None(hash, FeeCalculator::default()), - Some(hash) if !sign_only => Self::FeeCalculator(hash), - None if !sign_only => Self::All, - _ => panic!("Cannot resolve blockhash"), - } - } - - pub fn new_from_matches(matches: &ArgMatches<'_>) -> Self { - let blockhash = value_of(matches, BLOCKHASH_ARG.name); - let sign_only = matches.is_present(SIGN_ONLY_ARG.name); - BlockhashQuery::new(blockhash, sign_only) - } - - pub fn get_blockhash_fee_calculator( - &self, - rpc_client: &RpcClient, - ) -> Result<(Hash, FeeCalculator), Box> { - let (hash, fee_calc) = match self { - BlockhashQuery::None(hash, fee_calc) => (Some(hash), Some(fee_calc)), - BlockhashQuery::FeeCalculator(hash) => (Some(hash), None), - BlockhashQuery::All => (None, None), - }; - if None == fee_calc { - let (cluster_hash, fee_calc) = rpc_client.get_recent_blockhash()?; - Ok((*hash.unwrap_or(&cluster_hash), fee_calc)) - } else { - Ok((*hash.unwrap(), fee_calc.unwrap().clone())) - } - } -} - -impl Default for BlockhashQuery { - fn default() -> Self { - BlockhashQuery::All - } -} - -fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name(BLOCKHASH_ARG.name) - .long(BLOCKHASH_ARG.long) - .takes_value(true) - .value_name("BLOCKHASH") - .validator(is_hash) - .help(BLOCKHASH_ARG.help) -} - -fn sign_only_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name(SIGN_ONLY_ARG.name) - .long(SIGN_ONLY_ARG.long) - .takes_value(false) - .requires(BLOCKHASH_ARG.name) - .help(SIGN_ONLY_ARG.help) -} - -fn signer_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name(SIGNER_ARG.name) - .long(SIGNER_ARG.long) - .takes_value(true) - .value_name("BASE58_PUBKEY=BASE58_SIG") - .validator(is_pubkey_sig) - .requires(BLOCKHASH_ARG.name) - .multiple(true) - .help(SIGNER_ARG.help) -} - -pub trait OfflineArgs { - fn offline_args(self) -> Self; -} - -impl OfflineArgs for App<'_, '_> { - fn offline_args(self) -> Self { - self.arg(blockhash_arg()) - .arg(sign_only_arg()) - .arg(signer_arg()) - } -} - -pub fn parse_sign_only_reply_string(reply: &str) -> (Hash, Vec<(Pubkey, Signature)>) { - let object: Value = serde_json::from_str(&reply).unwrap(); - let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap(); - let blockhash = blockhash_str.parse::().unwrap(); - let signer_strings = object.get("signers").unwrap().as_array().unwrap(); - let signers = signer_strings - .iter() - .map(|signer_string| { - let mut signer = signer_string.as_str().unwrap().split('='); - let key = Pubkey::from_str(signer.next().unwrap()).unwrap(); - let sig = Signature::from_str(signer.next().unwrap()).unwrap(); - (key, sig) - }) - .collect(); - (blockhash, signers) -} - -#[cfg(test)] -mod tests { - use super::*; - use clap::App; - use serde_json::{self, json, Value}; - use solana_client::{ - rpc_request::RpcRequest, - rpc_response::{Response, RpcResponseContext}, - }; - use solana_sdk::{fee_calculator::FeeCalculator, hash::hash}; - use std::collections::HashMap; - - #[test] - fn test_blockhashspec_new_ok() { - let blockhash = hash(&[1u8]); - - assert_eq!( - BlockhashQuery::new(Some(blockhash), true), - BlockhashQuery::None(blockhash, FeeCalculator::default()), - ); - assert_eq!( - BlockhashQuery::new(Some(blockhash), false), - BlockhashQuery::FeeCalculator(blockhash), - ); - assert_eq!(BlockhashQuery::new(None, false), BlockhashQuery::All,); - } - - #[test] - #[should_panic] - fn test_blockhashspec_new_fail() { - BlockhashQuery::new(None, true); - } - - #[test] - fn test_blockhashspec_new_from_matches_ok() { - let test_commands = App::new("blockhashspec_test").offline_args(); - let blockhash = hash(&[1u8]); - let blockhash_string = blockhash.to_string(); - - let matches = test_commands.clone().get_matches_from(vec![ - "blockhashspec_test", - "--blockhash", - &blockhash_string, - "--sign-only", - ]); - assert_eq!( - BlockhashQuery::new_from_matches(&matches), - BlockhashQuery::None(blockhash, FeeCalculator::default()), - ); - - let matches = test_commands.clone().get_matches_from(vec![ - "blockhashspec_test", - "--blockhash", - &blockhash_string, - ]); - assert_eq!( - BlockhashQuery::new_from_matches(&matches), - BlockhashQuery::FeeCalculator(blockhash), - ); - - let matches = test_commands - .clone() - .get_matches_from(vec!["blockhashspec_test"]); - assert_eq!( - BlockhashQuery::new_from_matches(&matches), - BlockhashQuery::All, - ); - } - - #[test] - #[should_panic] - fn test_blockhashspec_new_from_matches_fail() { - let test_commands = App::new("blockhashspec_test") - .arg(blockhash_arg()) - // We can really only hit this case unless the arg requirements - // are broken, so unset the requires() to recreate that condition - .arg(sign_only_arg().requires("")); - - let matches = test_commands - .clone() - .get_matches_from(vec!["blockhashspec_test", "--sign-only"]); - BlockhashQuery::new_from_matches(&matches); - } - - #[test] - fn test_blockhashspec_get_blockhash_fee_calc() { - let test_blockhash = hash(&[0u8]); - let rpc_blockhash = hash(&[1u8]); - let rpc_fee_calc = FeeCalculator::new(42); - let get_recent_blockhash_response = json!(Response { - context: RpcResponseContext { slot: 1 }, - value: json!(( - Value::String(rpc_blockhash.to_string()), - serde_json::to_value(rpc_fee_calc.clone()).unwrap() - )), - }); - let mut mocks = HashMap::new(); - mocks.insert( - RpcRequest::GetRecentBlockhash, - get_recent_blockhash_response.clone(), - ); - let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); - assert_eq!( - BlockhashQuery::All - .get_blockhash_fee_calculator(&rpc_client) - .unwrap(), - (rpc_blockhash, rpc_fee_calc.clone()), - ); - let mut mocks = HashMap::new(); - mocks.insert( - RpcRequest::GetRecentBlockhash, - get_recent_blockhash_response.clone(), - ); - let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); - assert_eq!( - BlockhashQuery::FeeCalculator(test_blockhash) - .get_blockhash_fee_calculator(&rpc_client) - .unwrap(), - (test_blockhash, rpc_fee_calc.clone()), - ); - let mut mocks = HashMap::new(); - mocks.insert( - RpcRequest::GetRecentBlockhash, - get_recent_blockhash_response.clone(), - ); - let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); - assert_eq!( - BlockhashQuery::None(test_blockhash, FeeCalculator::default()) - .get_blockhash_fee_calculator(&rpc_client) - .unwrap(), - (test_blockhash, FeeCalculator::default()), - ); - let rpc_client = RpcClient::new_mock("fails".to_string()); - assert!(BlockhashQuery::All - .get_blockhash_fee_calculator(&rpc_client) - .is_err()); - } -} diff --git a/cli/src/offline/blockhash_query.rs b/cli/src/offline/blockhash_query.rs new file mode 100644 index 0000000000..98ffbb71f0 --- /dev/null +++ b/cli/src/offline/blockhash_query.rs @@ -0,0 +1,394 @@ +use super::*; + +#[derive(Debug, PartialEq)] +pub enum Source { + Cluster, + NonceAccount(Pubkey), +} + +impl Source { + pub fn get_blockhash_and_fee_calculator( + &self, + rpc_client: &RpcClient, + ) -> Result<(Hash, FeeCalculator), Box> { + match self { + Self::Cluster => { + let res = rpc_client.get_recent_blockhash()?; + Ok(res) + } + Self::NonceAccount(ref pubkey) => { + let data = nonce::get_account(rpc_client, pubkey) + .and_then(|ref a| nonce::data_from_account(a))?; + Ok((data.blockhash, data.fee_calculator)) + } + } + } + + pub fn get_fee_calculator( + &self, + rpc_client: &RpcClient, + blockhash: &Hash, + ) -> Result, Box> { + match self { + Self::Cluster => { + let res = rpc_client.get_fee_calculator_for_blockhash(blockhash)?; + Ok(res) + } + Self::NonceAccount(ref pubkey) => { + let res = nonce::get_account(rpc_client, pubkey) + .and_then(|ref a| nonce::data_from_account(a)) + .and_then(|d| { + if d.blockhash == *blockhash { + Ok(Some(d.fee_calculator)) + } else { + Ok(None) + } + })?; + Ok(res) + } + } + } +} + +#[derive(Debug, PartialEq)] +pub enum BlockhashQuery { + None(Hash), + FeeCalculator(Source, Hash), + All(Source), +} + +impl BlockhashQuery { + pub fn new(blockhash: Option, sign_only: bool, nonce_account: Option) -> Self { + let source = nonce_account + .map(Source::NonceAccount) + .unwrap_or(Source::Cluster); + match blockhash { + Some(hash) if sign_only => Self::None(hash), + Some(hash) if !sign_only => Self::FeeCalculator(source, hash), + None if !sign_only => Self::All(source), + _ => panic!("Cannot resolve blockhash"), + } + } + + pub fn new_from_matches(matches: &ArgMatches<'_>) -> Self { + let blockhash = value_of(matches, BLOCKHASH_ARG.name); + let sign_only = matches.is_present(SIGN_ONLY_ARG.name); + let nonce_account = pubkey_of(matches, nonce::NONCE_ARG.name); + BlockhashQuery::new(blockhash, sign_only, nonce_account) + } + + pub fn get_blockhash_and_fee_calculator( + &self, + rpc_client: &RpcClient, + ) -> Result<(Hash, FeeCalculator), Box> { + match self { + BlockhashQuery::None(hash) => Ok((*hash, FeeCalculator::default())), + BlockhashQuery::FeeCalculator(source, hash) => { + let fee_calculator = source + .get_fee_calculator(rpc_client, hash)? + .ok_or(format!("Hash has expired {:?}", hash))?; + Ok((*hash, fee_calculator)) + } + BlockhashQuery::All(source) => source.get_blockhash_and_fee_calculator(rpc_client), + } + } +} + +impl Default for BlockhashQuery { + fn default() -> Self { + BlockhashQuery::All(Source::Cluster) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{nonce::nonce_arg, offline::blockhash_query::BlockhashQuery}; + use clap::App; + use serde_json::{self, json, Value}; + use solana_client::{ + rpc_request::RpcRequest, + rpc_response::{Response, RpcAccount, RpcFeeCalculator, RpcResponseContext}, + }; + use solana_sdk::{ + account::Account, fee_calculator::FeeCalculator, hash::hash, nonce, system_program, + }; + use std::collections::HashMap; + + #[test] + fn test_blockhash_query_new_ok() { + let blockhash = hash(&[1u8]); + let nonce_pubkey = Pubkey::new(&[1u8; 32]); + + assert_eq!( + BlockhashQuery::new(Some(blockhash), true, None), + BlockhashQuery::None(blockhash), + ); + assert_eq!( + BlockhashQuery::new(Some(blockhash), false, None), + BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), + ); + assert_eq!( + BlockhashQuery::new(None, false, None), + BlockhashQuery::All(blockhash_query::Source::Cluster) + ); + + assert_eq!( + BlockhashQuery::new(Some(blockhash), true, Some(nonce_pubkey)), + BlockhashQuery::None(blockhash), + ); + assert_eq!( + BlockhashQuery::new(Some(blockhash), false, Some(nonce_pubkey)), + BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_pubkey), + blockhash + ), + ); + assert_eq!( + BlockhashQuery::new(None, false, Some(nonce_pubkey)), + BlockhashQuery::All(blockhash_query::Source::NonceAccount(nonce_pubkey)), + ); + } + + #[test] + #[should_panic] + fn test_blockhash_query_new_no_nonce_fail() { + BlockhashQuery::new(None, true, None); + } + + #[test] + #[should_panic] + fn test_blockhash_query_new_nonce_fail() { + let nonce_pubkey = Pubkey::new(&[1u8; 32]); + BlockhashQuery::new(None, true, Some(nonce_pubkey)); + } + + #[test] + fn test_blockhash_query_new_from_matches_ok() { + let test_commands = App::new("blockhash_query_test") + .arg(nonce_arg()) + .offline_args(); + let blockhash = hash(&[1u8]); + let blockhash_string = blockhash.to_string(); + + let matches = test_commands.clone().get_matches_from(vec![ + "blockhash_query_test", + "--blockhash", + &blockhash_string, + "--sign-only", + ]); + assert_eq!( + BlockhashQuery::new_from_matches(&matches), + BlockhashQuery::None(blockhash), + ); + + let matches = test_commands.clone().get_matches_from(vec![ + "blockhash_query_test", + "--blockhash", + &blockhash_string, + ]); + assert_eq!( + BlockhashQuery::new_from_matches(&matches), + BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), + ); + + let matches = test_commands + .clone() + .get_matches_from(vec!["blockhash_query_test"]); + assert_eq!( + BlockhashQuery::new_from_matches(&matches), + BlockhashQuery::All(blockhash_query::Source::Cluster), + ); + + let nonce_pubkey = Pubkey::new(&[1u8; 32]); + let nonce_string = nonce_pubkey.to_string(); + let matches = test_commands.clone().get_matches_from(vec![ + "blockhash_query_test", + "--blockhash", + &blockhash_string, + "--sign-only", + "--nonce", + &nonce_string, + ]); + assert_eq!( + BlockhashQuery::new_from_matches(&matches), + BlockhashQuery::None(blockhash), + ); + + let matches = test_commands.clone().get_matches_from(vec![ + "blockhash_query_test", + "--blockhash", + &blockhash_string, + "--nonce", + &nonce_string, + ]); + assert_eq!( + BlockhashQuery::new_from_matches(&matches), + BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_pubkey), + blockhash + ), + ); + } + + #[test] + #[should_panic] + fn test_blockhash_query_new_from_matches_without_nonce_fail() { + let test_commands = App::new("blockhash_query_test") + .arg(blockhash_arg()) + // We can really only hit this case if the arg requirements + // are broken, so unset the requires() to recreate that condition + .arg(sign_only_arg().requires("")); + + let matches = test_commands + .clone() + .get_matches_from(vec!["blockhash_query_test", "--sign-only"]); + BlockhashQuery::new_from_matches(&matches); + } + + #[test] + #[should_panic] + fn test_blockhash_query_new_from_matches_with_nonce_fail() { + let test_commands = App::new("blockhash_query_test") + .arg(blockhash_arg()) + // We can really only hit this case if the arg requirements + // are broken, so unset the requires() to recreate that condition + .arg(sign_only_arg().requires("")); + let nonce_pubkey = Pubkey::new(&[1u8; 32]); + let nonce_string = nonce_pubkey.to_string(); + + let matches = test_commands.clone().get_matches_from(vec![ + "blockhash_query_test", + "--sign-only", + "--nonce", + &nonce_string, + ]); + BlockhashQuery::new_from_matches(&matches); + } + + #[test] + fn test_blockhash_query_get_blockhash_fee_calc() { + let test_blockhash = hash(&[0u8]); + let rpc_blockhash = hash(&[1u8]); + let rpc_fee_calc = FeeCalculator::new(42); + let get_recent_blockhash_response = json!(Response { + context: RpcResponseContext { slot: 1 }, + value: json!(( + Value::String(rpc_blockhash.to_string()), + serde_json::to_value(rpc_fee_calc.clone()).unwrap() + )), + }); + let get_fee_calculator_for_blockhash_response = json!(Response { + context: RpcResponseContext { slot: 1 }, + value: json!(RpcFeeCalculator { + fee_calculator: rpc_fee_calc.clone() + }), + }); + let mut mocks = HashMap::new(); + mocks.insert( + RpcRequest::GetRecentBlockhash, + get_recent_blockhash_response.clone(), + ); + let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); + assert_eq!( + BlockhashQuery::default() + .get_blockhash_and_fee_calculator(&rpc_client) + .unwrap(), + (rpc_blockhash, rpc_fee_calc.clone()), + ); + let mut mocks = HashMap::new(); + mocks.insert( + RpcRequest::GetRecentBlockhash, + get_recent_blockhash_response.clone(), + ); + mocks.insert( + RpcRequest::GetFeeCalculatorForBlockhash, + get_fee_calculator_for_blockhash_response.clone(), + ); + let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); + assert_eq!( + BlockhashQuery::FeeCalculator(Source::Cluster, test_blockhash) + .get_blockhash_and_fee_calculator(&rpc_client) + .unwrap(), + (test_blockhash, rpc_fee_calc.clone()), + ); + let mut mocks = HashMap::new(); + mocks.insert( + RpcRequest::GetRecentBlockhash, + get_recent_blockhash_response.clone(), + ); + let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); + assert_eq!( + BlockhashQuery::None(test_blockhash) + .get_blockhash_and_fee_calculator(&rpc_client) + .unwrap(), + (test_blockhash, FeeCalculator::default()), + ); + let rpc_client = RpcClient::new_mock("fails".to_string()); + assert!(BlockhashQuery::default() + .get_blockhash_and_fee_calculator(&rpc_client) + .is_err()); + + let nonce_blockhash = Hash::new(&[2u8; 32]); + let nonce_fee_calc = FeeCalculator::new(4242); + let data = nonce::state::Data { + authority: Pubkey::new(&[3u8; 32]), + blockhash: nonce_blockhash, + fee_calculator: nonce_fee_calc.clone(), + }; + let nonce_account = Account::new_data_with_space( + 42, + &nonce::state::Versions::new_current(nonce::State::Initialized(data)), + nonce::State::size(), + &system_program::id(), + ) + .unwrap(); + let nonce_pubkey = Pubkey::new(&[4u8; 32]); + let rpc_nonce_account = RpcAccount::encode(nonce_account); + let get_account_response = json!(Response { + context: RpcResponseContext { slot: 1 }, + value: json!(Some(rpc_nonce_account.clone())), + }); + + let mut mocks = HashMap::new(); + mocks.insert(RpcRequest::GetAccountInfo, get_account_response.clone()); + let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); + assert_eq!( + BlockhashQuery::All(Source::NonceAccount(nonce_pubkey)) + .get_blockhash_and_fee_calculator(&rpc_client) + .unwrap(), + (nonce_blockhash, nonce_fee_calc.clone()), + ); + let mut mocks = HashMap::new(); + mocks.insert(RpcRequest::GetAccountInfo, get_account_response.clone()); + let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); + assert_eq!( + BlockhashQuery::FeeCalculator(Source::NonceAccount(nonce_pubkey), nonce_blockhash) + .get_blockhash_and_fee_calculator(&rpc_client) + .unwrap(), + (nonce_blockhash, nonce_fee_calc.clone()), + ); + let mut mocks = HashMap::new(); + mocks.insert(RpcRequest::GetAccountInfo, get_account_response.clone()); + let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); + assert!( + BlockhashQuery::FeeCalculator(Source::NonceAccount(nonce_pubkey), test_blockhash) + .get_blockhash_and_fee_calculator(&rpc_client) + .is_err() + ); + let mut mocks = HashMap::new(); + mocks.insert(RpcRequest::GetAccountInfo, get_account_response.clone()); + let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks); + assert_eq!( + BlockhashQuery::None(nonce_blockhash) + .get_blockhash_and_fee_calculator(&rpc_client) + .unwrap(), + (nonce_blockhash, FeeCalculator::default()), + ); + + let rpc_client = RpcClient::new_mock("fails".to_string()); + assert!(BlockhashQuery::All(Source::NonceAccount(nonce_pubkey)) + .get_blockhash_and_fee_calculator(&rpc_client) + .is_err()); + } +} diff --git a/cli/src/offline/mod.rs b/cli/src/offline/mod.rs new file mode 100644 index 0000000000..46d03e2880 --- /dev/null +++ b/cli/src/offline/mod.rs @@ -0,0 +1,70 @@ +pub mod blockhash_query; + +use crate::nonce; +use clap::{App, Arg, ArgMatches}; +use serde_json::Value; +use solana_clap_utils::{ + input_parsers::{pubkey_of, value_of}, + input_validators::{is_hash, is_pubkey_sig}, + offline::{BLOCKHASH_ARG, SIGNER_ARG, SIGN_ONLY_ARG}, +}; +use solana_client::rpc_client::RpcClient; +use solana_sdk::{fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey, signature::Signature}; +use std::str::FromStr; + +fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name(BLOCKHASH_ARG.name) + .long(BLOCKHASH_ARG.long) + .takes_value(true) + .value_name("BLOCKHASH") + .validator(is_hash) + .help(BLOCKHASH_ARG.help) +} + +fn sign_only_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name(SIGN_ONLY_ARG.name) + .long(SIGN_ONLY_ARG.long) + .takes_value(false) + .requires(BLOCKHASH_ARG.name) + .help(SIGN_ONLY_ARG.help) +} + +fn signer_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name(SIGNER_ARG.name) + .long(SIGNER_ARG.long) + .takes_value(true) + .value_name("BASE58_PUBKEY=BASE58_SIG") + .validator(is_pubkey_sig) + .requires(BLOCKHASH_ARG.name) + .multiple(true) + .help(SIGNER_ARG.help) +} + +pub trait OfflineArgs { + fn offline_args(self) -> Self; +} + +impl OfflineArgs for App<'_, '_> { + fn offline_args(self) -> Self { + self.arg(blockhash_arg()) + .arg(sign_only_arg()) + .arg(signer_arg()) + } +} + +pub fn parse_sign_only_reply_string(reply: &str) -> (Hash, Vec<(Pubkey, Signature)>) { + let object: Value = serde_json::from_str(&reply).unwrap(); + let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap(); + let blockhash = blockhash_str.parse::().unwrap(); + let signer_strings = object.get("signers").unwrap().as_array().unwrap(); + let signers = signer_strings + .iter() + .map(|signer_string| { + let mut signer = signer_string.as_str().unwrap().split('='); + let key = Pubkey::from_str(signer.next().unwrap()).unwrap(); + let sig = Signature::from_str(signer.next().unwrap()).unwrap(); + (key, sig) + }) + .collect(); + (blockhash, signers) +} diff --git a/cli/src/stake.rs b/cli/src/stake.rs index d3d507ffcd..1fa75d524d 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -5,7 +5,7 @@ use crate::{ CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult, SignerIndex, FEE_PAYER_ARG, }, nonce::{check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG}, - offline::*, + offline::{blockhash_query::BlockhashQuery, *}, }; use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc}; use clap::{App, Arg, ArgGroup, ArgMatches, SubCommand}; @@ -814,7 +814,7 @@ pub fn process_create_stake_account( ) }; let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_fee_calculator(rpc_client)?; + blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?; let fee_payer = config.signers[fee_payer]; let nonce_authority = config.signers[nonce_authority]; @@ -870,7 +870,7 @@ pub fn process_stake_authorize( )?; let authority = config.signers[authority]; let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_fee_calculator(rpc_client)?; + blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?; let ixs = vec![stake_instruction::authorize( stake_account_pubkey, // stake account to update &authority.pubkey(), // currently authorized @@ -925,7 +925,7 @@ pub fn process_deactivate_stake_account( fee_payer: SignerIndex, ) -> ProcessResult { let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_fee_calculator(rpc_client)?; + blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?; let stake_authority = config.signers[stake_authority]; let ixs = vec![stake_instruction::deactivate_stake( stake_account_pubkey, @@ -980,7 +980,7 @@ pub fn process_withdraw_stake( fee_payer: SignerIndex, ) -> ProcessResult { let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_fee_calculator(rpc_client)?; + blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?; let withdraw_authority = config.signers[withdraw_authority]; let ixs = vec![stake_instruction::withdraw( @@ -1104,7 +1104,7 @@ pub fn process_split_stake( } let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_fee_calculator(rpc_client)?; + blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?; let ixs = if let Some(seed) = split_stake_account_seed { stake_instruction::split_with_seed( @@ -1171,7 +1171,7 @@ pub fn process_stake_set_lockup( fee_payer: SignerIndex, ) -> ProcessResult { let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_fee_calculator(rpc_client)?; + blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?; let custodian = config.signers[custodian]; let ixs = vec![stake_instruction::set_lockup( @@ -1406,7 +1406,7 @@ pub fn process_delegate_stake( } let (recent_blockhash, fee_calculator) = - blockhash_query.get_blockhash_fee_calculator(rpc_client)?; + blockhash_query.get_blockhash_and_fee_calculator(rpc_client)?; let ixs = vec![stake_instruction::delegate_stake( stake_account_pubkey, @@ -1452,7 +1452,6 @@ mod tests { use super::*; use crate::cli::{app, parse_command}; use solana_sdk::{ - fee_calculator::FeeCalculator, hash::Hash, signature::{ keypair_from_seed, read_keypair_file, write_keypair, Keypair, Presigner, Signer, @@ -1556,7 +1555,7 @@ mod tests { stake_authorize, authority: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -1590,7 +1589,10 @@ mod tests { stake_authorize, authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::Cluster, + blockhash + ), nonce_account: None, nonce_authority: 0, fee_payer: 1, @@ -1634,7 +1636,10 @@ mod tests { stake_authorize, authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account), + blockhash + ), nonce_account: Some(nonce_account), nonce_authority: 2, fee_payer: 1, @@ -1664,7 +1669,10 @@ mod tests { stake_authorize, authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::Cluster, + blockhash + ), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -1699,7 +1707,10 @@ mod tests { stake_authorize, authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account_pubkey), + blockhash + ), nonce_account: Some(nonce_account_pubkey), nonce_authority: 1, fee_payer: 0, @@ -1733,7 +1744,7 @@ mod tests { stake_authorize, authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 1, @@ -1768,7 +1779,10 @@ mod tests { stake_authorize, authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::Cluster, + blockhash + ), nonce_account: None, nonce_authority: 0, fee_payer: 1, @@ -1842,7 +1856,7 @@ mod tests { }, lamports: 50_000_000_000, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -1879,7 +1893,7 @@ mod tests { lockup: Lockup::default(), lamports: 50_000_000_000, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -1932,7 +1946,10 @@ mod tests { lockup: Lockup::default(), lamports: 50_000_000_000, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account), + nonce_hash + ), nonce_account: Some(nonce_account), nonce_authority: 0, fee_payer: 0, @@ -2052,7 +2069,10 @@ mod tests { stake_authority: 0, force: false, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::Cluster, + blockhash + ), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -2079,7 +2099,7 @@ mod tests { stake_authority: 0, force: false, sign_only: true, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -2113,7 +2133,10 @@ mod tests { stake_authority: 0, force: false, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::Cluster, + blockhash + ), nonce_account: None, nonce_authority: 0, fee_payer: 1, @@ -2156,7 +2179,10 @@ mod tests { stake_authority: 0, force: false, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account), + blockhash + ), nonce_account: Some(nonce_account), nonce_authority: 2, fee_payer: 1, @@ -2190,7 +2216,7 @@ mod tests { stake_authority: 0, force: false, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 1, @@ -2220,7 +2246,7 @@ mod tests { lamports: 42_000_000_000, withdraw_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -2249,7 +2275,7 @@ mod tests { lamports: 42_000_000_000, withdraw_authority: 1, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -2293,7 +2319,10 @@ mod tests { lamports: 42_000_000_000, withdraw_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account), + nonce_hash + ), nonce_account: Some(nonce_account), nonce_authority: 1, fee_payer: 1, @@ -2375,7 +2404,10 @@ mod tests { stake_account_pubkey, stake_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::Cluster, + blockhash + ), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -2399,7 +2431,7 @@ mod tests { stake_account_pubkey, stake_authority: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -2430,7 +2462,10 @@ mod tests { stake_account_pubkey, stake_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::Cluster, + blockhash + ), nonce_account: None, nonce_authority: 0, fee_payer: 1, @@ -2470,7 +2505,10 @@ mod tests { stake_account_pubkey, stake_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account), + blockhash + ), nonce_account: Some(nonce_account), nonce_authority: 2, fee_payer: 1, @@ -2498,7 +2536,7 @@ mod tests { stake_account_pubkey, stake_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 1, @@ -2593,7 +2631,10 @@ mod tests { stake_account_pubkey: stake_account_keypair.pubkey(), stake_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account), + nonce_hash + ), nonce_account: Some(nonce_account.into()), nonce_authority: 1, split_stake_account: 2, diff --git a/cli/tests/pay.rs b/cli/tests/pay.rs index 16536ba406..542586a3a0 100644 --- a/cli/tests/pay.rs +++ b/cli/tests/pay.rs @@ -4,13 +4,15 @@ use solana_clap_utils::keypair::presigner_from_pubkey_sigs; use solana_cli::{ cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand}, nonce, - offline::{parse_sign_only_reply_string, BlockhashQuery}, + offline::{ + blockhash_query::{self, BlockhashQuery}, + parse_sign_only_reply_string, + }, }; use solana_client::rpc_client::RpcClient; use solana_core::validator::TestValidator; use solana_faucet::faucet::run_local_faucet; use solana_sdk::{ - fee_calculator::FeeCalculator, nonce::State as NonceState, pubkey::Pubkey, signature::{Keypair, Signer}, @@ -323,7 +325,7 @@ fn test_offline_pay_tx() { config_offline.command = CliCommand::Pay(PayCommand { lamports: 10, to: bob_pubkey, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), sign_only: true, ..PayCommand::default() }); @@ -341,7 +343,7 @@ fn test_offline_pay_tx() { config_online.command = CliCommand::Pay(PayCommand { lamports: 10, to: bob_pubkey, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), ..PayCommand::default() }); process_command(&config_online).unwrap(); @@ -418,7 +420,10 @@ fn test_nonced_pay_tx() { config.command = CliCommand::Pay(PayCommand { lamports: 10, to: bob_pubkey, - blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account.pubkey()), + nonce_hash, + ), nonce_account: Some(nonce_account.pubkey()), ..PayCommand::default() }); diff --git a/cli/tests/stake.rs b/cli/tests/stake.rs index 79f8c1d4d3..57ba7a5c8f 100644 --- a/cli/tests/stake.rs +++ b/cli/tests/stake.rs @@ -2,14 +2,16 @@ use solana_clap_utils::keypair::presigner_from_pubkey_sigs; use solana_cli::{ cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig}, nonce, - offline::{parse_sign_only_reply_string, BlockhashQuery}, + offline::{ + blockhash_query::{self, BlockhashQuery}, + parse_sign_only_reply_string, + }, }; use solana_client::rpc_client::RpcClient; use solana_core::validator::{TestValidator, TestValidatorOptions}; use solana_faucet::faucet::run_local_faucet; use solana_sdk::{ account_utils::StateMut, - fee_calculator::FeeCalculator, nonce::State as NonceState, pubkey::Pubkey, signature::{keypair_from_seed, Keypair, Signer}, @@ -85,7 +87,7 @@ fn test_stake_delegation_force() { lockup: Lockup::default(), lamports: 50_000, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -176,7 +178,7 @@ fn test_seed_stake_delegation_and_deactivation() { lockup: Lockup::default(), lamports: 50_000, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -259,7 +261,7 @@ fn test_stake_delegation_and_deactivation() { lockup: Lockup::default(), lamports: 50_000, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -364,7 +366,7 @@ fn test_offline_stake_delegation_and_deactivation() { lockup: Lockup::default(), lamports: 50_000, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -380,7 +382,7 @@ fn test_offline_stake_delegation_and_deactivation() { stake_authority: 0, force: false, sign_only: true, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -396,7 +398,7 @@ fn test_offline_stake_delegation_and_deactivation() { stake_authority: 0, force: false, sign_only: false, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -409,7 +411,7 @@ fn test_offline_stake_delegation_and_deactivation() { stake_account_pubkey: stake_keypair.pubkey(), stake_authority: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -423,7 +425,7 @@ fn test_offline_stake_delegation_and_deactivation() { stake_account_pubkey: stake_keypair.pubkey(), stake_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -480,7 +482,7 @@ fn test_nonced_stake_delegation_and_deactivation() { lockup: Lockup::default(), lamports: 50_000, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -513,7 +515,10 @@ fn test_nonced_stake_delegation_and_deactivation() { stake_authority: 0, force: false, sign_only: false, - blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account.pubkey()), + nonce_hash, + ), nonce_account: Some(nonce_account.pubkey()), nonce_authority: 0, fee_payer: 0, @@ -531,7 +536,10 @@ fn test_nonced_stake_delegation_and_deactivation() { stake_account_pubkey: stake_keypair.pubkey(), stake_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account.pubkey()), + nonce_hash, + ), nonce_account: Some(nonce_account.pubkey()), nonce_authority: 0, fee_payer: 0, @@ -601,7 +609,7 @@ fn test_stake_authorize() { lockup: Lockup::default(), lamports: 50_000, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -665,7 +673,7 @@ fn test_stake_authorize() { stake_authorize: StakeAuthorize::Staker, authority: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -681,7 +689,7 @@ fn test_stake_authorize() { stake_authorize: StakeAuthorize::Staker, authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -725,7 +733,7 @@ fn test_stake_authorize() { stake_authorize: StakeAuthorize::Staker, authority: 1, sign_only: true, - blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(nonce_hash), nonce_account: Some(nonce_account.pubkey()), nonce_authority: 0, fee_payer: 0, @@ -744,7 +752,10 @@ fn test_stake_authorize() { stake_authorize: StakeAuthorize::Staker, authority: 1, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account.pubkey()), + blockhash, + ), nonce_account: Some(nonce_account.pubkey()), nonce_authority: 0, fee_payer: 0, @@ -831,7 +842,7 @@ fn test_stake_authorize_with_fee_payer() { lockup: Lockup::default(), lamports: 50_000, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -849,7 +860,7 @@ fn test_stake_authorize_with_fee_payer() { stake_authorize: StakeAuthorize::Staker, authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 1, @@ -869,7 +880,7 @@ fn test_stake_authorize_with_fee_payer() { stake_authorize: StakeAuthorize::Staker, authority: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -884,7 +895,7 @@ fn test_stake_authorize_with_fee_payer() { stake_authorize: StakeAuthorize::Staker, authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -961,7 +972,7 @@ fn test_stake_split() { lockup: Lockup::default(), lamports: 10 * minimum_stake_balance, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -1003,7 +1014,7 @@ fn test_stake_split() { stake_account_pubkey: stake_account_pubkey, stake_authority: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(nonce_hash), nonce_account: Some(nonce_account.pubkey()), nonce_authority: 0, split_stake_account: 1, @@ -1019,7 +1030,10 @@ fn test_stake_split() { stake_account_pubkey: stake_account_pubkey, stake_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account.pubkey()), + blockhash, + ), nonce_account: Some(nonce_account.pubkey()), nonce_authority: 0, split_stake_account: 1, @@ -1109,7 +1123,7 @@ fn test_stake_set_lockup() { lockup, lamports: 10 * minimum_stake_balance, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -1255,7 +1269,7 @@ fn test_stake_set_lockup() { lockup, custodian: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(nonce_hash), nonce_account: Some(nonce_account_pubkey), nonce_authority: 0, fee_payer: 0, @@ -1269,7 +1283,10 @@ fn test_stake_set_lockup() { lockup, custodian: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account_pubkey), + blockhash, + ), nonce_account: Some(nonce_account_pubkey), nonce_authority: 0, fee_payer: 0, @@ -1368,7 +1385,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { lockup: Lockup::default(), lamports: 50_000, sign_only: true, - blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(nonce_hash), nonce_account: Some(nonce_pubkey), nonce_authority: 0, fee_payer: 0, @@ -1387,7 +1404,10 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { lockup: Lockup::default(), lamports: 50_000, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_pubkey), + blockhash, + ), nonce_account: Some(nonce_pubkey), nonce_authority: 0, fee_payer: 0, @@ -1412,7 +1432,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { lamports: 42, withdraw_authority: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(nonce_hash), nonce_account: Some(nonce_pubkey), nonce_authority: 0, fee_payer: 0, @@ -1427,7 +1447,10 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { lamports: 42, withdraw_authority: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_pubkey), + blockhash, + ), nonce_account: Some(nonce_pubkey), nonce_authority: 0, fee_payer: 0, @@ -1452,7 +1475,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { lockup: Lockup::default(), lamports: 50_000, sign_only: true, - blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(nonce_hash), nonce_account: Some(nonce_pubkey), nonce_authority: 0, fee_payer: 0, @@ -1471,7 +1494,10 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { lockup: Lockup::default(), lamports: 50_000, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_pubkey), + blockhash, + ), nonce_account: Some(nonce_pubkey), nonce_authority: 0, fee_payer: 0, diff --git a/cli/tests/transfer.rs b/cli/tests/transfer.rs index e87680c658..0b31ea5c31 100644 --- a/cli/tests/transfer.rs +++ b/cli/tests/transfer.rs @@ -2,13 +2,15 @@ use solana_clap_utils::keypair::presigner_from_pubkey_sigs; use solana_cli::{ cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig}, nonce, - offline::{parse_sign_only_reply_string, BlockhashQuery}, + offline::{ + blockhash_query::{self, BlockhashQuery}, + parse_sign_only_reply_string, + }, }; use solana_client::rpc_client::RpcClient; use solana_core::validator::{TestValidator, TestValidatorOptions}; use solana_faucet::faucet::run_local_faucet; use solana_sdk::{ - fee_calculator::FeeCalculator, nonce::State as NonceState, pubkey::Pubkey, signature::{keypair_from_seed, Keypair, Signer}, @@ -67,7 +69,7 @@ fn test_transfer() { to: recipient_pubkey, from: 0, sign_only: false, - blockhash_query: BlockhashQuery::All, + blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -94,7 +96,7 @@ fn test_transfer() { to: recipient_pubkey, from: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -108,7 +110,7 @@ fn test_transfer() { to: recipient_pubkey, from: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash), nonce_account: None, nonce_authority: 0, fee_payer: 0, @@ -145,7 +147,10 @@ fn test_transfer() { to: recipient_pubkey, from: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account.pubkey()), + nonce_hash, + ), nonce_account: Some(nonce_account.pubkey()), nonce_authority: 0, fee_payer: 0, @@ -182,7 +187,7 @@ fn test_transfer() { to: recipient_pubkey, from: 0, sign_only: true, - blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()), + blockhash_query: BlockhashQuery::None(nonce_hash), nonce_account: Some(nonce_account.pubkey()), nonce_authority: 0, fee_payer: 0, @@ -196,7 +201,10 @@ fn test_transfer() { to: recipient_pubkey, from: 0, sign_only: false, - blockhash_query: BlockhashQuery::FeeCalculator(blockhash), + blockhash_query: BlockhashQuery::FeeCalculator( + blockhash_query::Source::NonceAccount(nonce_account.pubkey()), + blockhash, + ), nonce_account: Some(nonce_account.pubkey()), nonce_authority: 0, fee_payer: 0,