From 616fb1566eae5cfabc7db695cfd49f97abb775b5 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 20 Apr 2020 13:25:12 -0700 Subject: [PATCH 1/4] Add more columns to analyze-storage subcommand --- ledger-tool/src/main.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ledger-tool/src/main.rs b/ledger-tool/src/main.rs index 0220fda8e05065..40b87e8915ebac 100644 --- a/ledger-tool/src/main.rs +++ b/ledger-tool/src/main.rs @@ -499,6 +499,17 @@ fn analyze_storage(database: &Database) -> Result<(), String> { "TransactionStatus", TransactionStatus::key_size(), )?; + analyze_column::( + database, + "TransactionStatusIndex", + TransactionStatusIndex::key_size(), + )?; + analyze_column::( + database, + "AddressSignatures", + AddressSignatures::key_size(), + )?; + analyze_column::(database, "Rewards", Rewards::key_size())?; Ok(()) } From c3635f3c8147826ddf8387e45cca4d8d585f8153 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 20 Apr 2020 14:25:34 -0700 Subject: [PATCH 2/4] Add transaction-history --- cli/src/cli.rs | 13 +++++++ cli/src/cluster_query.rs | 80 ++++++++++++++++++++++++++++++++++++++++ client/src/rpc_client.rs | 19 ++++++++-- 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index c71f5549108114..ec5ff6f8abbec1 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -227,6 +227,11 @@ pub enum CliCommand { use_lamports_unit: bool, commitment_config: CommitmentConfig, }, + TransactionHistory { + address: Pubkey, + start_slot: Option, + end_slot: Option, + }, // Nonce commands AuthorizeNonceAccount { nonce_account: Pubkey, @@ -618,6 +623,9 @@ pub fn parse_command( }), ("stakes", Some(matches)) => parse_show_stakes(matches, wallet_manager), ("validators", Some(matches)) => parse_show_validators(matches), + ("transaction-history", Some(matches)) => { + parse_transaction_history(matches, wallet_manager) + } // Nonce Commands ("authorize-nonce-account", Some(matches)) => { parse_authorize_nonce_account(matches, default_signer_path, wallet_manager) @@ -1729,6 +1737,11 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { use_lamports_unit, commitment_config, } => process_show_validators(&rpc_client, config, *use_lamports_unit, *commitment_config), + CliCommand::TransactionHistory { + address, + start_slot, + end_slot, + } => process_transaction_history(&rpc_client, address, *start_slot, *end_slot), // Nonce Commands diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index 4ae570d2ca06af..e03e0f9cf23ac4 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -273,6 +273,37 @@ impl ClusterQuerySubCommands for App<'_, '_> { .help("Display balance in lamports instead of SOL"), ), ) + .subcommand( + SubCommand::with_name("transaction-history") + .about("Show historical transactions affecting the given address, \ + ordered based on the slot in which they were confirmed in \ + from lowest to highest slot") + .arg( + pubkey!(Arg::with_name("address") + .index(1) + .value_name("ADDRESS") + .required(true), + "Account address"), + ) + .arg( + Arg::with_name("start_slot") + .takes_value(false) + .index(2) + .validator(is_slot) + .help( + "Optional slot to start from" + ), + ) + .arg( + Arg::with_name("end_slot") + .takes_value(false) + .index(3) + .validator(is_slot) + .help( + "Optional slot to end at" + ), + ), + ) } } @@ -436,6 +467,24 @@ pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result, + wallet_manager: &mut Option>, +) -> Result { + let address = pubkey_of_signer(matches, "address", wallet_manager)?.unwrap(); + let start_slot = value_t!(matches, "start_slot", Slot).ok(); + let end_slot = value_t!(matches, "end_slot", Slot).ok(); + + Ok(CliCommandInfo { + command: CliCommand::TransactionHistory { + address, + start_slot, + end_slot, + }, + signers: vec![], + }) +} + /// Creates a new process bar for processing that will take an unknown amount of time fn new_spinner_progress_bar() -> ProgressBar { let progress_bar = ProgressBar::new(42); @@ -1170,6 +1219,37 @@ pub fn process_show_validators( Ok("".to_string()) } +pub fn process_transaction_history( + rpc_client: &RpcClient, + address: &Pubkey, + start_slot: Option, + end_slot: Option, +) -> ProcessResult { + let (start_slot, end_slot) = { + if let Some(start_slot) = start_slot { + if let Some(end_slot) = end_slot { + (start_slot, end_slot) + } else { + (start_slot, start_slot + 1000) + } + } else { + let current_slot = rpc_client.get_slot_with_commitment(CommitmentConfig::max())?; + (current_slot.saturating_sub(1000), current_slot) + } + }; + + println!( + "Transactions affecting {} within slots [{},{}]", + address, start_slot, end_slot + ); + let signatures = + rpc_client.get_confirmed_signatures_for_address(address, start_slot, end_slot)?; + for signature in &signatures { + println!("{}", signature); + } + Ok(format!("{} transactions found", signatures.len(),)) +} + #[cfg(test)] mod tests { use super::*; diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index 2f3feef2ab873a..f94958491acf68 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -289,14 +289,25 @@ impl RpcClient { .client .send( &RpcRequest::GetConfirmedSignaturesForAddress, - json!([address, start_slot, end_slot]), + json!([address.to_string(), start_slot, end_slot]), 0, ) .map_err(|err| err.into_with_command("GetConfirmedSignaturesForAddress"))?; - serde_json::from_value(response).map_err(|err| { - ClientError::new_with_command(err.into(), "GetConfirmedSignaturesForAddress") - }) + let signatures_base58_str: Vec = + serde_json::from_value(response).map_err(|err| { + ClientError::new_with_command(err.into(), "GetConfirmedSignaturesForAddress") + })?; + + let mut signatures = vec![]; + for signature_base58_str in signatures_base58_str { + signatures.push( + signature_base58_str.parse::().map_err(|err| { + Into::::into(RpcError::ParseError(err.to_string())) + })?, + ); + } + Ok(signatures) } pub fn get_confirmed_transaction( From 84d5c450b236047daa600a9f42f53ce7e3d9f8ad Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 20 Apr 2020 17:58:39 -0700 Subject: [PATCH 3/4] Use MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE by default --- cli/src/cluster_query.rs | 11 +++++++++-- client/src/rpc_request.rs | 3 +++ core/src/rpc.rs | 18 ++++++++++-------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index e03e0f9cf23ac4..79e063f1055ed9 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -14,6 +14,7 @@ use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::signer_f use solana_client::{ pubsub_client::{PubsubClient, SlotInfoMessage}, rpc_client::RpcClient, + rpc_request::MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE, }; use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_sdk::{ @@ -1230,11 +1231,17 @@ pub fn process_transaction_history( if let Some(end_slot) = end_slot { (start_slot, end_slot) } else { - (start_slot, start_slot + 1000) + ( + start_slot, + start_slot + MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE, + ) } } else { let current_slot = rpc_client.get_slot_with_commitment(CommitmentConfig::max())?; - (current_slot.saturating_sub(1000), current_slot) + ( + current_slot.saturating_sub(MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE), + current_slot, + ) } }; diff --git a/client/src/rpc_request.rs b/client/src/rpc_request.rs index c9e7e9b3545298..bdac2335ae0333 100644 --- a/client/src/rpc_request.rs +++ b/client/src/rpc_request.rs @@ -42,6 +42,9 @@ pub enum RpcRequest { MinimumLedgerSlot, } +pub const MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS: usize = 256; +pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE: u64 = 10_000; + impl RpcRequest { pub(crate) fn build_request_json(&self, id: u64, params: Value) -> Value { let jsonrpc = "2.0"; diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 12907cae05afc1..a64f74becaa51b 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -7,7 +7,12 @@ use crate::{ use bincode::serialize; use jsonrpc_core::{Error, Metadata, Result}; use jsonrpc_derive::rpc; -use solana_client::rpc_response::*; +use solana_client::{ + rpc_request::{ + MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE, MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS, + }, + rpc_response::*, +}; use solana_faucet::faucet::request_airdrop_transaction; use solana_ledger::{ bank_forks::BankForks, blockstore::Blockstore, rooted_slot_iterator::RootedSlotIterator, @@ -38,9 +43,6 @@ use std::{ time::{Duration, Instant}, }; -const MAX_QUERY_ITEMS: usize = 256; -const MAX_SLOT_RANGE: u64 = 10_000; - type RpcResponse = Result>; fn new_response(bank: &Bank, value: T) -> RpcResponse { @@ -1058,10 +1060,10 @@ impl RpcSol for RpcSolImpl { signature_strs: Vec, config: Option, ) -> RpcResponse>> { - if signature_strs.len() > MAX_QUERY_ITEMS { + if signature_strs.len() > MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS { return Err(Error::invalid_params(format!( "Too many inputs provided; max {}", - MAX_QUERY_ITEMS + MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS ))); } let mut signatures: Vec = vec![]; @@ -1360,10 +1362,10 @@ impl RpcSol for RpcSolImpl { start_slot, end_slot ))); } - if end_slot - start_slot > MAX_SLOT_RANGE { + if end_slot - start_slot > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE { return Err(Error::invalid_params(format!( "Slot range too large; max {}", - MAX_SLOT_RANGE + MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE ))); } meta.request_processor From 5dc4aa55f92c0d1b2a54def2ef6f6424b5045a08 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 20 Apr 2020 20:34:03 -0700 Subject: [PATCH 4/4] Rework arguments --- cli/src/cli.rs | 8 ++++---- cli/src/cluster_query.rs | 43 +++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index ec5ff6f8abbec1..3305b21b01c5cc 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -229,8 +229,8 @@ pub enum CliCommand { }, TransactionHistory { address: Pubkey, - start_slot: Option, - end_slot: Option, + end_slot: Option, // None == latest slot + slot_limit: u64, }, // Nonce commands AuthorizeNonceAccount { @@ -1739,9 +1739,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { } => process_show_validators(&rpc_client, config, *use_lamports_unit, *commitment_config), CliCommand::TransactionHistory { address, - start_slot, end_slot, - } => process_transaction_history(&rpc_client, address, *start_slot, *end_slot), + slot_limit, + } => process_transaction_history(&rpc_client, address, *end_slot, *slot_limit), // Nonce Commands diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index 79e063f1055ed9..44f1390587874b 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -287,21 +287,23 @@ impl ClusterQuerySubCommands for App<'_, '_> { "Account address"), ) .arg( - Arg::with_name("start_slot") + Arg::with_name("end_slot") .takes_value(false) + .value_name("SLOT") .index(2) .validator(is_slot) .help( - "Optional slot to start from" + "Slot to start from [default: latest slot at maximum commitment]" ), ) .arg( - Arg::with_name("end_slot") - .takes_value(false) - .index(3) + Arg::with_name("limit") + .long("limit") + .takes_value(true) + .value_name("NUMBER OF SLOTS") .validator(is_slot) .help( - "Optional slot to end at" + "Limit the search to this many slots" ), ), ) @@ -473,14 +475,15 @@ pub fn parse_transaction_history( wallet_manager: &mut Option>, ) -> Result { let address = pubkey_of_signer(matches, "address", wallet_manager)?.unwrap(); - let start_slot = value_t!(matches, "start_slot", Slot).ok(); let end_slot = value_t!(matches, "end_slot", Slot).ok(); + let slot_limit = value_t!(matches, "limit", u64) + .unwrap_or(MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE); Ok(CliCommandInfo { command: CliCommand::TransactionHistory { address, - start_slot, end_slot, + slot_limit, }, signers: vec![], }) @@ -1223,27 +1226,17 @@ pub fn process_show_validators( pub fn process_transaction_history( rpc_client: &RpcClient, address: &Pubkey, - start_slot: Option, - end_slot: Option, + end_slot: Option, // None == use latest slot + slot_limit: u64, ) -> ProcessResult { - let (start_slot, end_slot) = { - if let Some(start_slot) = start_slot { - if let Some(end_slot) = end_slot { - (start_slot, end_slot) - } else { - ( - start_slot, - start_slot + MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE, - ) - } + let end_slot = { + if let Some(end_slot) = end_slot { + end_slot } else { - let current_slot = rpc_client.get_slot_with_commitment(CommitmentConfig::max())?; - ( - current_slot.saturating_sub(MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE), - current_slot, - ) + rpc_client.get_slot_with_commitment(CommitmentConfig::max())? } }; + let start_slot = end_slot.saturating_sub(slot_limit); println!( "Transactions affecting {} within slots [{},{}]",