diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index 921320e12c..836f4d10c9 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -256,9 +256,8 @@ impl ClusterQuerySubCommands for App<'_, '_> { ) .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") + .about("Show historical transactions affecting the given address \ + from newest to oldest") .arg( pubkey!(Arg::with_name("address") .index(1) diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 23bd2fbf57..65ef429250 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -808,8 +808,8 @@ impl JsonRpcRequestProcessor { pub fn get_confirmed_signatures_for_address2( &self, address: Pubkey, - before: Option, - limit: usize, + mut before: Option, + mut limit: usize, ) -> Result> { if self.config.enable_rpc_transaction_history { let highest_confirmed_root = self @@ -818,7 +818,7 @@ impl JsonRpcRequestProcessor { .unwrap() .highest_confirmed_slot(); - let results = self + let mut results = self .blockstore .get_confirmed_signatures_for_address2( address, @@ -828,6 +828,27 @@ impl JsonRpcRequestProcessor { ) .map_err(|err| Error::invalid_params(format!("{}", err)))?; + if results.len() < limit { + if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage { + if !results.is_empty() { + limit -= results.len(); + before = results.last().map(|x| x.signature); + } + + let mut bigtable_results = self + .runtime_handle + .block_on( + bigtable_ledger_storage.get_confirmed_signatures_for_address( + &address, + before.as_ref(), + limit, + ), + ) + .map_err(|err| Error::invalid_params(format!("{}", err)))?; + results.append(&mut bigtable_results) + } + } + Ok(results.into_iter().map(|x| x.into()).collect()) } else { Ok(vec![]) diff --git a/ledger-tool/src/bigtable.rs b/ledger-tool/src/bigtable.rs index 61520ca675..93ef4f8317 100644 --- a/ledger-tool/src/bigtable.rs +++ b/ledger-tool/src/bigtable.rs @@ -308,30 +308,39 @@ async fn confirm(signature: &Signature, verbose: bool) -> Result<(), Box, + mut limit: usize, + mut before: Option, verbose: bool, ) -> Result<(), Box> { let bigtable = solana_storage_bigtable::LedgerStorage::new(true).await?; - let results = bigtable - .get_confirmed_signatures_for_address(address, before, limit) - .await?; + while limit > 0 { + let results = bigtable + .get_confirmed_signatures_for_address(address, before.as_ref(), limit.min(1000)) + .await?; - for (signature, slot, memo, err) in results { - if verbose { - println!( - "{}, slot={}, memo=\"{}\", status={}", - signature, - slot, - memo.unwrap_or_else(|| "".to_string()), - match err { - None => "Confirmed".to_string(), - Some(err) => format!("Failed: {:?}", err), - } - ); - } else { - println!("{}", signature); + if results.is_empty() { + break; + } + before = Some(results.last().unwrap().signature); + assert!(limit >= results.len()); + limit = limit.saturating_sub(results.len()); + + for result in results { + if verbose { + println!( + "{}, slot={}, memo=\"{}\", status={}", + result.signature, + result.slot, + result.memo.unwrap_or_else(|| "".to_string()), + match result.err { + None => "Confirmed".to_string(), + Some(err) => format!("Failed: {:?}", err), + } + ); + } else { + println!("{}", result.signature); + } } } Ok(()) @@ -443,9 +452,8 @@ impl BigTableSubCommand for App<'_, '_> { .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", + "Show historical transactions affecting the given address \ + from newest to oldest", ) .arg( Arg::with_name("address") @@ -462,7 +470,7 @@ impl BigTableSubCommand for App<'_, '_> { .value_name("LIMIT") .validator(is_slot) .index(2) - .default_value("1000") + .default_value("18446744073709551615") .help("Maximum number of transaction signatures to return"), ) .arg( @@ -531,12 +539,7 @@ pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) { .map(|signature| signature.parse().expect("Invalid signature")); let verbose = arg_matches.is_present("verbose"); - runtime.block_on(transaction_history( - &address, - limit, - before.as_ref(), - verbose, - )) + runtime.block_on(transaction_history(&address, limit, before, verbose)) } _ => unreachable!(), }; diff --git a/storage-bigtable/src/lib.rs b/storage-bigtable/src/lib.rs index dcee9b117d..65bcd70c45 100644 --- a/storage-bigtable/src/lib.rs +++ b/storage-bigtable/src/lib.rs @@ -8,8 +8,9 @@ use solana_sdk::{ transaction::{Transaction, TransactionError}, }; use solana_transaction_status::{ - ConfirmedBlock, ConfirmedTransaction, EncodedTransaction, Rewards, TransactionStatus, - TransactionWithStatusMeta, UiTransactionEncoding, UiTransactionStatusMeta, + ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, + EncodedTransaction, Rewards, TransactionStatus, TransactionWithStatusMeta, + UiTransactionEncoding, UiTransactionStatusMeta, }; use std::{ collections::HashMap, @@ -365,7 +366,7 @@ impl LedgerStorage { address: &Pubkey, before_signature: Option<&Signature>, limit: usize, - ) -> Result, Option)>> { + ) -> Result> { let mut bigtable = self.connection.client(); let address_prefix = format!("{}/", address); @@ -414,12 +415,12 @@ impl LedgerStorage { .into_iter() .skip(first_transaction_index as usize) { - infos.push(( - tx_by_addr_info.signature, + infos.push(ConfirmedTransactionStatusWithSignature { + signature: tx_by_addr_info.signature, slot, - tx_by_addr_info.memo, - tx_by_addr_info.err, - )); + err: tx_by_addr_info.err, + memo: tx_by_addr_info.memo, + }); if infos.len() >= limit { break 'outer; }