Cli: support json output for transaction-history (#30376)

* Add cli-output structs for transaction-history

* Support json output for transaction history

* Use pre-existing CliTransactionConfirmation
This commit is contained in:
Tyera 2023-02-21 22:47:22 -07:00 committed by GitHub
parent d984fbb735
commit a095f5f229
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 169 additions and 45 deletions

View File

@ -758,6 +758,111 @@ impl CliValidator {
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliHistorySignatureVec(Vec<CliHistorySignature>);
impl CliHistorySignatureVec {
pub fn new(list: Vec<CliHistorySignature>) -> Self {
Self(list)
}
}
impl QuietDisplay for CliHistorySignatureVec {}
impl VerboseDisplay for CliHistorySignatureVec {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
for signature in &self.0 {
VerboseDisplay::write_str(signature, w)?;
}
writeln!(w, "{} transactions found", self.0.len())
}
}
impl fmt::Display for CliHistorySignatureVec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for signature in &self.0 {
write!(f, "{signature}")?;
}
writeln!(f, "{} transactions found", self.0.len())
}
}
#[derive(Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct CliHistorySignature {
pub signature: String,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub verbose: Option<CliHistoryVerbose>,
}
impl QuietDisplay for CliHistorySignature {}
impl VerboseDisplay for CliHistorySignature {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
let verbose = self
.verbose
.as_ref()
.expect("should have verbose.is_some()");
writeln!(
w,
"{} [slot={} {}status={}] {}",
self.signature,
verbose.slot,
match verbose.block_time {
None => "".to_string(),
Some(block_time) => format!("timestamp={} ", unix_timestamp_to_string(block_time)),
},
if let Some(err) = &verbose.err {
format!("Failed: {err:?}")
} else {
match &verbose.confirmation_status {
None => "Finalized".to_string(),
Some(status) => format!("{status:?}"),
}
},
verbose.memo.clone().unwrap_or_default(),
)
}
}
impl fmt::Display for CliHistorySignature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{}", self.signature)
}
}
#[derive(Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct CliHistoryVerbose {
pub slot: Slot,
pub block_time: Option<UnixTimestamp>,
pub err: Option<TransactionError>,
pub confirmation_status: Option<TransactionConfirmationStatus>,
pub memo: Option<String>,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliHistoryTransactionVec(Vec<CliTransactionConfirmation>);
impl CliHistoryTransactionVec {
pub fn new(list: Vec<CliTransactionConfirmation>) -> Self {
Self(list)
}
}
impl QuietDisplay for CliHistoryTransactionVec {}
impl VerboseDisplay for CliHistoryTransactionVec {}
impl fmt::Display for CliHistoryTransactionVec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for transaction in &self.0 {
VerboseDisplay::write_str(transaction, f)?;
writeln!(f)?;
}
writeln!(f, "{} transactions found", self.0.len())
}
}
#[derive(Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliNonceAccount {

View File

@ -19,7 +19,7 @@ use {
cli_version::CliVersion,
display::{
build_balance_message, format_labeled_address, new_spinner_progress_bar,
println_transaction, unix_timestamp_to_string, writeln_name_value,
writeln_name_value,
},
*,
},
@ -61,7 +61,9 @@ use {
},
transaction::Transaction,
},
solana_transaction_status::UiTransactionEncoding,
solana_transaction_status::{
EncodableWithMeta, EncodedConfirmedTransactionWithStatusMeta, UiTransactionEncoding,
},
solana_vote_program::vote_state::VoteState,
std::{
collections::{BTreeMap, HashMap, VecDeque},
@ -2032,35 +2034,35 @@ pub fn process_transaction_history(
},
)?;
let transactions_found = format!("{} transactions found", results.len());
for result in results {
if config.verbose {
println!(
"{} [slot={} {}status={}] {}",
result.signature,
result.slot,
match result.block_time {
None => "".to_string(),
Some(block_time) =>
format!("timestamp={} ", unix_timestamp_to_string(block_time)),
},
if let Some(err) = result.err {
format!("Failed: {err:?}")
} else {
match result.confirmation_status {
None => "Finalized".to_string(),
Some(status) => format!("{status:?}"),
}
},
result.memo.unwrap_or_default(),
);
} else {
println!("{}", result.signature);
}
if show_transactions {
if !show_transactions {
let cli_signatures: Vec<_> = results
.into_iter()
.map(|result| {
let mut signature = CliHistorySignature {
signature: result.signature,
..CliHistorySignature::default()
};
if config.verbose {
signature.verbose = Some(CliHistoryVerbose {
slot: result.slot,
block_time: result.block_time,
err: result.err,
confirmation_status: result.confirmation_status,
memo: result.memo,
});
}
signature
})
.collect();
Ok(config
.output_format
.formatted_string(&CliHistorySignatureVec::new(cli_signatures)))
} else {
let mut cli_transactions = vec![];
for result in results {
if let Ok(signature) = result.signature.parse::<Signature>() {
let mut transaction = None;
let mut get_transaction_error = None;
match rpc_client.get_transaction_with_config(
&signature,
RpcTransactionConfig {
@ -2070,25 +2072,42 @@ pub fn process_transaction_history(
},
) {
Ok(confirmed_transaction) => {
println_transaction(
&confirmed_transaction
.transaction
.transaction
.decode()
.expect("Successful decode"),
confirmed_transaction.transaction.meta.as_ref(),
" ",
None,
None,
);
let EncodedConfirmedTransactionWithStatusMeta {
block_time,
slot,
transaction: transaction_with_meta,
} = confirmed_transaction;
let decoded_transaction =
transaction_with_meta.transaction.decode().unwrap();
let json_transaction = decoded_transaction.json_encode();
transaction = Some(CliTransaction {
transaction: json_transaction,
meta: transaction_with_meta.meta,
block_time,
slot: Some(slot),
decoded_transaction,
prefix: " ".to_string(),
sigverify_status: vec![],
});
}
Err(err) => println!(" Unable to get confirmed transaction details: {err}"),
}
Err(err) => {
get_transaction_error = Some(format!("{err:?}"));
}
};
cli_transactions.push(CliTransactionConfirmation {
confirmation_status: result.confirmation_status,
transaction,
get_transaction_error,
err: result.err,
});
}
println!();
}
Ok(config
.output_format
.formatted_string(&CliHistoryTransactionVec::new(cli_transactions)))
}
Ok(transactions_found)
}
#[derive(Serialize, Deserialize)]