CLI: Add sigverify results to solana decode-transaction output (bp #14964) (#15008)

* cli-output: Add option sigverify status to `println_transaction()` output

(cherry picked from commit a2aea0ca33)

* cli: Add sigverify status to `decode-transaction` output

(cherry picked from commit d547585041)

* CLI: Modernize `decode-transaction` about message

(cherry picked from commit fddbfe1052)

Co-authored-by: Trent Nelson <trent@solana.com>
This commit is contained in:
mergify[bot]
2021-02-02 20:33:24 +00:00
committed by GitHub
parent fe1347b441
commit f534698618
7 changed files with 71 additions and 8 deletions

View File

@ -1563,6 +1563,37 @@ pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
} }
} }
#[derive(Debug)]
pub enum CliSignatureVerificationStatus {
None,
Pass,
Fail,
}
impl CliSignatureVerificationStatus {
pub fn verify_transaction(tx: &Transaction) -> Vec<Self> {
tx.verify_with_results()
.iter()
.zip(&tx.signatures)
.map(|(stat, sig)| match stat {
true => CliSignatureVerificationStatus::Pass,
false if sig == &Signature::default() => CliSignatureVerificationStatus::None,
false => CliSignatureVerificationStatus::Fail,
})
.collect()
}
}
impl fmt::Display for CliSignatureVerificationStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::None => write!(f, "none"),
Self::Pass => write!(f, "pass"),
Self::Fail => write!(f, "fail"),
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -1,3 +1,4 @@
use crate::cli_output::CliSignatureVerificationStatus;
use console::style; use console::style;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use solana_sdk::{ use solana_sdk::{
@ -126,6 +127,7 @@ pub fn write_transaction<W: io::Write>(
transaction: &Transaction, transaction: &Transaction,
transaction_status: &Option<UiTransactionStatusMeta>, transaction_status: &Option<UiTransactionStatusMeta>,
prefix: &str, prefix: &str,
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
) -> io::Result<()> { ) -> io::Result<()> {
let message = &transaction.message; let message = &transaction.message;
writeln!( writeln!(
@ -133,11 +135,24 @@ pub fn write_transaction<W: io::Write>(
"{}Recent Blockhash: {:?}", "{}Recent Blockhash: {:?}",
prefix, message.recent_blockhash prefix, message.recent_blockhash
)?; )?;
for (signature_index, signature) in transaction.signatures.iter().enumerate() { let sigverify_statuses = if let Some(sigverify_status) = sigverify_status {
sigverify_status
.iter()
.map(|s| format!(" ({})", s))
.collect()
} else {
vec!["".to_string(); transaction.signatures.len()]
};
for (signature_index, (signature, sigverify_status)) in transaction
.signatures
.iter()
.zip(&sigverify_statuses)
.enumerate()
{
writeln!( writeln!(
w, w,
"{}Signature {}: {:?}", "{}Signature {}: {:?}{}",
prefix, signature_index, signature prefix, signature_index, signature, sigverify_status,
)?; )?;
} }
writeln!(w, "{}{:?}", prefix, message.header)?; writeln!(w, "{}{:?}", prefix, message.header)?;
@ -258,9 +273,18 @@ pub fn println_transaction(
transaction: &Transaction, transaction: &Transaction,
transaction_status: &Option<UiTransactionStatusMeta>, transaction_status: &Option<UiTransactionStatusMeta>,
prefix: &str, prefix: &str,
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
) { ) {
let mut w = Vec::new(); let mut w = Vec::new();
if write_transaction(&mut w, transaction, transaction_status, prefix).is_ok() { if write_transaction(
&mut w,
transaction,
transaction_status,
prefix,
sigverify_status,
)
.is_ok()
{
if let Ok(s) = String::from_utf8(w) { if let Ok(s) = String::from_utf8(w) {
print!("{}", s); print!("{}", s);
} }

View File

@ -18,7 +18,7 @@ use solana_clap_utils::{
}; };
use solana_cli_output::{ use solana_cli_output::{
display::{build_balance_message, println_name_value, println_transaction}, display::{build_balance_message, println_name_value, println_transaction},
return_signers, CliAccount, CliSignature, OutputFormat, return_signers, CliAccount, CliSignature, CliSignatureVerificationStatus, OutputFormat,
}; };
use solana_client::{ use solana_client::{
blockhash_query::BlockhashQuery, blockhash_query::BlockhashQuery,
@ -1011,6 +1011,7 @@ fn process_confirm(
.expect("Successful decode"), .expect("Successful decode"),
&confirmed_transaction.transaction.meta, &confirmed_transaction.transaction.meta,
" ", " ",
None,
); );
} }
Err(err) => { Err(err) => {
@ -1043,7 +1044,8 @@ fn process_confirm(
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn process_decode_transaction(transaction: &Transaction) -> ProcessResult { fn process_decode_transaction(transaction: &Transaction) -> ProcessResult {
println_transaction(transaction, &None, ""); let sig_stats = CliSignatureVerificationStatus::verify_transaction(&transaction);
println_transaction(transaction, &None, "", Some(&sig_stats));
Ok("".to_string()) Ok("".to_string())
} }
@ -1932,7 +1934,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
) )
.subcommand( .subcommand(
SubCommand::with_name("decode-transaction") SubCommand::with_name("decode-transaction")
.about("Decode a base-58 binary transaction") .about("Decode a serialized transaction")
.arg( .arg(
Arg::with_name("transaction") Arg::with_name("transaction")
.index(1) .index(1)

View File

@ -967,6 +967,7 @@ pub fn process_get_block(
&transaction_with_meta.transaction.decode().unwrap(), &transaction_with_meta.transaction.decode().unwrap(),
&transaction_with_meta.meta, &transaction_with_meta.meta,
" ", " ",
None,
); );
} }
Ok("".to_string()) Ok("".to_string())
@ -1840,6 +1841,7 @@ pub fn process_transaction_history(
.expect("Successful decode"), .expect("Successful decode"),
&confirmed_transaction.transaction.meta, &confirmed_transaction.transaction.meta,
" ", " ",
None,
); );
} }
Err(err) => println!(" Unable to get confirmed transaction details: {}", err), Err(err) => println!(" Unable to get confirmed transaction details: {}", err),

View File

@ -69,6 +69,7 @@ async fn block(slot: Slot) -> Result<(), Box<dyn std::error::Error>> {
&transaction_with_meta.transaction, &transaction_with_meta.transaction,
&transaction_with_meta.meta.map(|meta| meta.into()), &transaction_with_meta.meta.map(|meta| meta.into()),
" ", " ",
None,
); );
} }
Ok(()) Ok(())
@ -104,6 +105,7 @@ async fn confirm(signature: &Signature, verbose: bool) -> Result<(), Box<dyn std
&confirmed_transaction.transaction.transaction, &confirmed_transaction.transaction.transaction,
&confirmed_transaction.transaction.meta.map(|m| m.into()), &confirmed_transaction.transaction.meta.map(|m| m.into()),
" ", " ",
None,
); );
} }
Ok(None) => println!("Finalized transaction details not available"), Ok(None) => println!("Finalized transaction details not available"),
@ -183,6 +185,7 @@ pub async fn transaction_history(
&transaction_with_meta.transaction, &transaction_with_meta.transaction,
&transaction_with_meta.meta.clone().map(|m| m.into()), &transaction_with_meta.meta.clone().map(|m| m.into()),
" ", " ",
None,
); );
} }
} }

View File

@ -122,6 +122,7 @@ fn output_entry(
&transaction, &transaction,
&transaction_status, &transaction_status,
" ", " ",
None,
); );
} }
} }

View File

@ -387,7 +387,7 @@ fn print_confirmed_tx(name: &str, confirmed_tx: ConfirmedTransaction) {
let tx = confirmed_tx.transaction.transaction.clone(); let tx = confirmed_tx.transaction.transaction.clone();
let encoded = confirmed_tx.encode(UiTransactionEncoding::JsonParsed); let encoded = confirmed_tx.encode(UiTransactionEncoding::JsonParsed);
println!("EXECUTE {} (slot {})", name, encoded.slot); println!("EXECUTE {} (slot {})", name, encoded.slot);
println_transaction(&tx, &encoded.transaction.meta, " "); println_transaction(&tx, &encoded.transaction.meta, " ", None);
} }
#[test] #[test]