parent
6e908a1be8
commit
914b022663
|
@ -227,6 +227,11 @@ pub enum CliCommand {
|
|||
use_lamports_unit: bool,
|
||||
commitment_config: CommitmentConfig,
|
||||
},
|
||||
TransactionHistory {
|
||||
address: Pubkey,
|
||||
end_slot: Option<Slot>, // None == latest slot
|
||||
slot_limit: u64,
|
||||
},
|
||||
// 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,
|
||||
end_slot,
|
||||
slot_limit,
|
||||
} => process_transaction_history(&rpc_client, address, *end_slot, *slot_limit),
|
||||
|
||||
// Nonce Commands
|
||||
|
||||
|
|
|
@ -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::{
|
||||
|
@ -273,6 +274,39 @@ 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("end_slot")
|
||||
.takes_value(false)
|
||||
.value_name("SLOT")
|
||||
.index(2)
|
||||
.validator(is_slot)
|
||||
.help(
|
||||
"Slot to start from [default: latest slot at maximum commitment]"
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("limit")
|
||||
.long("limit")
|
||||
.takes_value(true)
|
||||
.value_name("NUMBER OF SLOTS")
|
||||
.validator(is_slot)
|
||||
.help(
|
||||
"Limit the search to this many slots"
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -436,6 +470,25 @@ pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result<CliCommandInfo,
|
|||
})
|
||||
}
|
||||
|
||||
pub fn parse_transaction_history(
|
||||
matches: &ArgMatches<'_>,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let address = pubkey_of_signer(matches, "address", wallet_manager)?.unwrap();
|
||||
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,
|
||||
end_slot,
|
||||
slot_limit,
|
||||
},
|
||||
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 +1223,33 @@ pub fn process_show_validators(
|
|||
Ok("".to_string())
|
||||
}
|
||||
|
||||
pub fn process_transaction_history(
|
||||
rpc_client: &RpcClient,
|
||||
address: &Pubkey,
|
||||
end_slot: Option<Slot>, // None == use latest slot
|
||||
slot_limit: u64,
|
||||
) -> ProcessResult {
|
||||
let end_slot = {
|
||||
if let Some(end_slot) = end_slot {
|
||||
end_slot
|
||||
} else {
|
||||
rpc_client.get_slot_with_commitment(CommitmentConfig::max())?
|
||||
}
|
||||
};
|
||||
let start_slot = end_slot.saturating_sub(slot_limit);
|
||||
|
||||
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::*;
|
||||
|
|
|
@ -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<String> =
|
||||
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::<Signature>().map_err(|err| {
|
||||
Into::<ClientError>::into(RpcError::ParseError(err.to_string()))
|
||||
})?,
|
||||
);
|
||||
}
|
||||
Ok(signatures)
|
||||
}
|
||||
|
||||
pub fn get_confirmed_transaction(
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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<T> = Result<Response<T>>;
|
||||
|
||||
fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
|
||||
|
@ -1058,10 +1060,10 @@ impl RpcSol for RpcSolImpl {
|
|||
signature_strs: Vec<String>,
|
||||
config: Option<RpcSignatureStatusConfig>,
|
||||
) -> RpcResponse<Vec<Option<TransactionStatus>>> {
|
||||
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<Signature> = 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
|
||||
|
|
|
@ -499,6 +499,17 @@ fn analyze_storage(database: &Database) -> Result<(), String> {
|
|||
"TransactionStatus",
|
||||
TransactionStatus::key_size(),
|
||||
)?;
|
||||
analyze_column::<TransactionStatus>(
|
||||
database,
|
||||
"TransactionStatusIndex",
|
||||
TransactionStatusIndex::key_size(),
|
||||
)?;
|
||||
analyze_column::<AddressSignatures>(
|
||||
database,
|
||||
"AddressSignatures",
|
||||
AddressSignatures::key_size(),
|
||||
)?;
|
||||
analyze_column::<Rewards>(database, "Rewards", Rewards::key_size())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue