Implement OutputFormat for confirm in Cli and ledger-tool bigtable (#15528)
* Add CliTransaction struct * Impl DisplayFormat for decode-transaction * Add block-time to transaction println, writeln * Impl DisplayFormat for confirm * Use DisplayFormat in ledger-tool bigtable confirm
This commit is contained in:
@ -26,10 +26,13 @@ use {
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
stake_history::StakeHistoryEntry,
|
stake_history::StakeHistoryEntry,
|
||||||
transaction::Transaction,
|
transaction::{Transaction, TransactionError},
|
||||||
},
|
},
|
||||||
solana_stake_program::stake_state::{Authorized, Lockup},
|
solana_stake_program::stake_state::{Authorized, Lockup},
|
||||||
solana_transaction_status::EncodedConfirmedBlock,
|
solana_transaction_status::{
|
||||||
|
EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus,
|
||||||
|
UiTransactionStatusMeta,
|
||||||
|
},
|
||||||
solana_vote_program::{
|
solana_vote_program::{
|
||||||
authorized_voters::AuthorizedVoters,
|
authorized_voters::AuthorizedVoters,
|
||||||
vote_state::{BlockTimestamp, Lockout, MAX_EPOCH_CREDITS_HISTORY, MAX_LOCKOUT_HISTORY},
|
vote_state::{BlockTimestamp, Lockout, MAX_EPOCH_CREDITS_HISTORY, MAX_LOCKOUT_HISTORY},
|
||||||
@ -1711,7 +1714,8 @@ pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum CliSignatureVerificationStatus {
|
pub enum CliSignatureVerificationStatus {
|
||||||
None,
|
None,
|
||||||
Pass,
|
Pass,
|
||||||
@ -1743,6 +1747,7 @@ impl fmt::Display for CliSignatureVerificationStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CliBlock {
|
pub struct CliBlock {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub encoded_confirmed_block: EncodedConfirmedBlock,
|
pub encoded_confirmed_block: EncodedConfirmedBlock,
|
||||||
@ -1830,12 +1835,103 @@ impl fmt::Display for CliBlock {
|
|||||||
&transaction_with_meta.meta,
|
&transaction_with_meta.meta,
|
||||||
" ",
|
" ",
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CliTransaction {
|
||||||
|
pub transaction: EncodedTransaction,
|
||||||
|
pub meta: Option<UiTransactionStatusMeta>,
|
||||||
|
pub block_time: Option<UnixTimestamp>,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub slot: Option<Slot>,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub decoded_transaction: Transaction,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub prefix: String,
|
||||||
|
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub sigverify_status: Vec<CliSignatureVerificationStatus>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QuietDisplay for CliTransaction {}
|
||||||
|
impl VerboseDisplay for CliTransaction {}
|
||||||
|
|
||||||
|
impl fmt::Display for CliTransaction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
writeln_transaction(
|
||||||
|
f,
|
||||||
|
&self.decoded_transaction,
|
||||||
|
&self.meta,
|
||||||
|
&self.prefix,
|
||||||
|
if !self.sigverify_status.is_empty() {
|
||||||
|
Some(&self.sigverify_status)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
self.block_time,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CliTransactionConfirmation {
|
||||||
|
pub confirmation_status: Option<TransactionConfirmationStatus>,
|
||||||
|
#[serde(flatten, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub transaction: Option<CliTransaction>,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub get_transaction_error: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub err: Option<TransactionError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QuietDisplay for CliTransactionConfirmation {}
|
||||||
|
impl VerboseDisplay for CliTransactionConfirmation {
|
||||||
|
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
|
||||||
|
if let Some(transaction) = &self.transaction {
|
||||||
|
writeln!(
|
||||||
|
w,
|
||||||
|
"\nTransaction executed in slot {}:",
|
||||||
|
transaction.slot.expect("slot should exist")
|
||||||
|
)?;
|
||||||
|
write!(w, "{}", transaction)?;
|
||||||
|
} else if let Some(confirmation_status) = &self.confirmation_status {
|
||||||
|
if confirmation_status != &TransactionConfirmationStatus::Finalized {
|
||||||
|
writeln!(w)?;
|
||||||
|
writeln!(
|
||||||
|
w,
|
||||||
|
"Unable to get finalized transaction details: not yet finalized"
|
||||||
|
)?;
|
||||||
|
} else if let Some(err) = &self.get_transaction_error {
|
||||||
|
writeln!(w)?;
|
||||||
|
writeln!(w, "Unable to get finalized transaction details: {}", err)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(w)?;
|
||||||
|
write!(w, "{}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CliTransactionConfirmation {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match &self.confirmation_status {
|
||||||
|
None => write!(f, "Not found"),
|
||||||
|
Some(confirmation_status) => {
|
||||||
|
if let Some(err) = &self.err {
|
||||||
|
write!(f, "Transaction failed: {}", err)
|
||||||
|
} else {
|
||||||
|
write!(f, "{:?}", confirmation_status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use {
|
use {
|
||||||
crate::cli_output::CliSignatureVerificationStatus,
|
crate::cli_output::CliSignatureVerificationStatus,
|
||||||
chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc},
|
chrono::{DateTime, Local, NaiveDateTime, SecondsFormat, TimeZone, Utc},
|
||||||
console::style,
|
console::style,
|
||||||
indicatif::{ProgressBar, ProgressStyle},
|
indicatif::{ProgressBar, ProgressStyle},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
@ -131,8 +131,17 @@ pub fn write_transaction<W: io::Write>(
|
|||||||
transaction_status: &Option<UiTransactionStatusMeta>,
|
transaction_status: &Option<UiTransactionStatusMeta>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
|
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
|
||||||
|
block_time: Option<UnixTimestamp>,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let message = &transaction.message;
|
let message = &transaction.message;
|
||||||
|
if let Some(block_time) = block_time {
|
||||||
|
writeln!(
|
||||||
|
w,
|
||||||
|
"{}Block Time: {:?}",
|
||||||
|
prefix,
|
||||||
|
Local.timestamp(block_time, 0)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
writeln!(
|
writeln!(
|
||||||
w,
|
w,
|
||||||
"{}Recent Blockhash: {:?}",
|
"{}Recent Blockhash: {:?}",
|
||||||
@ -277,6 +286,7 @@ pub fn println_transaction(
|
|||||||
transaction_status: &Option<UiTransactionStatusMeta>,
|
transaction_status: &Option<UiTransactionStatusMeta>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
|
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
|
||||||
|
block_time: Option<UnixTimestamp>,
|
||||||
) {
|
) {
|
||||||
let mut w = Vec::new();
|
let mut w = Vec::new();
|
||||||
if write_transaction(
|
if write_transaction(
|
||||||
@ -285,6 +295,7 @@ pub fn println_transaction(
|
|||||||
transaction_status,
|
transaction_status,
|
||||||
prefix,
|
prefix,
|
||||||
sigverify_status,
|
sigverify_status,
|
||||||
|
block_time,
|
||||||
)
|
)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
@ -300,6 +311,7 @@ pub fn writeln_transaction(
|
|||||||
transaction_status: &Option<UiTransactionStatusMeta>,
|
transaction_status: &Option<UiTransactionStatusMeta>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
|
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
|
||||||
|
block_time: Option<UnixTimestamp>,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
let mut w = Vec::new();
|
let mut w = Vec::new();
|
||||||
if write_transaction(
|
if write_transaction(
|
||||||
@ -308,6 +320,7 @@ pub fn writeln_transaction(
|
|||||||
transaction_status,
|
transaction_status,
|
||||||
prefix,
|
prefix,
|
||||||
sigverify_status,
|
sigverify_status,
|
||||||
|
block_time,
|
||||||
)
|
)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
|
@ -17,8 +17,9 @@ use solana_clap_utils::{
|
|||||||
offline::*,
|
offline::*,
|
||||||
};
|
};
|
||||||
use solana_cli_output::{
|
use solana_cli_output::{
|
||||||
display::{build_balance_message, println_name_value, println_transaction},
|
display::{build_balance_message, println_name_value},
|
||||||
return_signers, CliAccount, CliSignature, CliSignatureVerificationStatus, OutputFormat,
|
return_signers, CliAccount, CliSignature, CliSignatureVerificationStatus, CliTransaction,
|
||||||
|
CliTransactionConfirmation, OutputFormat,
|
||||||
};
|
};
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
blockhash_query::BlockhashQuery,
|
blockhash_query::BlockhashQuery,
|
||||||
@ -50,9 +51,7 @@ use solana_stake_program::{
|
|||||||
stake_instruction::LockupArgs,
|
stake_instruction::LockupArgs,
|
||||||
stake_state::{Lockup, StakeAuthorize},
|
stake_state::{Lockup, StakeAuthorize},
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding};
|
||||||
EncodedTransaction, TransactionConfirmationStatus, UiTransactionEncoding,
|
|
||||||
};
|
|
||||||
use solana_vote_program::vote_state::VoteAuthorize;
|
use solana_vote_program::vote_state::VoteAuthorize;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -1005,60 +1004,72 @@ fn process_confirm(
|
|||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
match rpc_client.get_signature_statuses_with_history(&[*signature]) {
|
match rpc_client.get_signature_statuses_with_history(&[*signature]) {
|
||||||
Ok(status) => {
|
Ok(status) => {
|
||||||
if let Some(transaction_status) = &status.value[0] {
|
let cli_transaction = if let Some(transaction_status) = &status.value[0] {
|
||||||
|
let mut transaction = None;
|
||||||
|
let mut get_transaction_error = None;
|
||||||
if config.verbose {
|
if config.verbose {
|
||||||
match rpc_client
|
match rpc_client
|
||||||
.get_confirmed_transaction(signature, UiTransactionEncoding::Base64)
|
.get_confirmed_transaction(signature, UiTransactionEncoding::Base64)
|
||||||
{
|
{
|
||||||
Ok(confirmed_transaction) => {
|
Ok(confirmed_transaction) => {
|
||||||
println!(
|
let decoded_transaction = confirmed_transaction
|
||||||
"\nTransaction executed in slot {}:",
|
|
||||||
confirmed_transaction.slot
|
|
||||||
);
|
|
||||||
println_transaction(
|
|
||||||
&confirmed_transaction
|
|
||||||
.transaction
|
.transaction
|
||||||
.transaction
|
.transaction
|
||||||
.decode()
|
.decode()
|
||||||
.expect("Successful decode"),
|
.expect("Successful decode");
|
||||||
&confirmed_transaction.transaction.meta,
|
let json_transaction = EncodedTransaction::encode(
|
||||||
" ",
|
decoded_transaction.clone(),
|
||||||
None,
|
UiTransactionEncoding::Json,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
transaction = Some(CliTransaction {
|
||||||
|
transaction: json_transaction,
|
||||||
|
meta: confirmed_transaction.transaction.meta,
|
||||||
|
block_time: confirmed_transaction.block_time,
|
||||||
|
slot: Some(confirmed_transaction.slot),
|
||||||
|
decoded_transaction,
|
||||||
|
prefix: " ".to_string(),
|
||||||
|
sigverify_status: vec![],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if transaction_status.confirmation_status()
|
get_transaction_error = Some(format!("{:?}", err));
|
||||||
!= TransactionConfirmationStatus::Finalized
|
|
||||||
{
|
|
||||||
println!();
|
|
||||||
println!("Unable to get finalized transaction details: not yet finalized")
|
|
||||||
} else {
|
|
||||||
println!();
|
|
||||||
println!("Unable to get finalized transaction details: {}", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!();
|
CliTransactionConfirmation {
|
||||||
}
|
confirmation_status: Some(transaction_status.confirmation_status()),
|
||||||
|
transaction,
|
||||||
if let Some(err) = &transaction_status.err {
|
get_transaction_error,
|
||||||
Ok(format!("Transaction failed: {}", err))
|
err: transaction_status.err.clone(),
|
||||||
} else {
|
|
||||||
Ok(format!("{:?}", transaction_status.confirmation_status()))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok("Not found".to_string())
|
CliTransactionConfirmation {
|
||||||
|
confirmation_status: None,
|
||||||
|
transaction: None,
|
||||||
|
get_transaction_error: None,
|
||||||
|
err: None,
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
Ok(config.output_format.formatted_string(&cli_transaction))
|
||||||
}
|
}
|
||||||
Err(err) => Err(CliError::RpcRequestError(format!("Unable to confirm: {}", err)).into()),
|
Err(err) => Err(CliError::RpcRequestError(format!("Unable to confirm: {}", err)).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn process_decode_transaction(transaction: &Transaction) -> ProcessResult {
|
fn process_decode_transaction(config: &CliConfig, transaction: &Transaction) -> ProcessResult {
|
||||||
let sig_stats = CliSignatureVerificationStatus::verify_transaction(&transaction);
|
let sigverify_status = CliSignatureVerificationStatus::verify_transaction(&transaction);
|
||||||
println_transaction(transaction, &None, "", Some(&sig_stats));
|
let decode_transaction = CliTransaction {
|
||||||
Ok("".to_string())
|
decoded_transaction: transaction.clone(),
|
||||||
|
transaction: EncodedTransaction::encode(transaction.clone(), UiTransactionEncoding::Json),
|
||||||
|
meta: None,
|
||||||
|
block_time: None,
|
||||||
|
slot: None,
|
||||||
|
prefix: "".to_string(),
|
||||||
|
sigverify_status,
|
||||||
|
};
|
||||||
|
Ok(config.output_format.formatted_string(&decode_transaction))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_show_account(
|
fn process_show_account(
|
||||||
@ -1745,7 +1756,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
} => process_balance(&rpc_client, config, &pubkey, *use_lamports_unit),
|
} => process_balance(&rpc_client, config, &pubkey, *use_lamports_unit),
|
||||||
// Confirm the last client transaction by signature
|
// Confirm the last client transaction by signature
|
||||||
CliCommand::Confirm(signature) => process_confirm(&rpc_client, config, signature),
|
CliCommand::Confirm(signature) => process_confirm(&rpc_client, config, signature),
|
||||||
CliCommand::DecodeTransaction(transaction) => process_decode_transaction(transaction),
|
CliCommand::DecodeTransaction(transaction) => {
|
||||||
|
process_decode_transaction(config, transaction)
|
||||||
|
}
|
||||||
CliCommand::ResolveSigner(path) => {
|
CliCommand::ResolveSigner(path) => {
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
Ok(path.to_string())
|
Ok(path.to_string())
|
||||||
@ -2189,6 +2202,7 @@ mod tests {
|
|||||||
signature::{keypair_from_seed, read_keypair_file, write_keypair_file, Keypair, Presigner},
|
signature::{keypair_from_seed, read_keypair_file, write_keypair_file, Keypair, Presigner},
|
||||||
transaction::TransactionError,
|
transaction::TransactionError,
|
||||||
};
|
};
|
||||||
|
use solana_transaction_status::TransactionConfirmationStatus;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn make_tmp_path(name: &str) -> String {
|
fn make_tmp_path(name: &str) -> String {
|
||||||
|
@ -1785,6 +1785,7 @@ pub fn process_transaction_history(
|
|||||||
&confirmed_transaction.transaction.meta,
|
&confirmed_transaction.transaction.meta,
|
||||||
" ",
|
" ",
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(err) => println!(" Unable to get confirmed transaction details: {}", err),
|
Err(err) => println!(" Unable to get confirmed transaction details: {}", err),
|
||||||
|
@ -4,10 +4,13 @@ use solana_clap_utils::{
|
|||||||
input_parsers::pubkey_of,
|
input_parsers::pubkey_of,
|
||||||
input_validators::{is_slot, is_valid_pubkey},
|
input_validators::{is_slot, is_valid_pubkey},
|
||||||
};
|
};
|
||||||
use solana_cli_output::{display::println_transaction, CliBlock, OutputFormat};
|
use solana_cli_output::{
|
||||||
|
display::println_transaction, CliBlock, CliTransaction, CliTransactionConfirmation,
|
||||||
|
OutputFormat,
|
||||||
|
};
|
||||||
use solana_ledger::{blockstore::Blockstore, blockstore_db::AccessType};
|
use solana_ledger::{blockstore::Blockstore, blockstore_db::AccessType};
|
||||||
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
|
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
|
||||||
use solana_transaction_status::{ConfirmedBlock, UiTransactionEncoding};
|
use solana_transaction_status::{ConfirmedBlock, EncodedTransaction, UiTransactionEncoding};
|
||||||
use std::{
|
use std::{
|
||||||
path::Path,
|
path::Path,
|
||||||
process::exit,
|
process::exit,
|
||||||
@ -75,37 +78,48 @@ async fn blocks(starting_slot: Slot, limit: usize) -> Result<(), Box<dyn std::er
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn confirm(signature: &Signature, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
|
async fn confirm(
|
||||||
|
signature: &Signature,
|
||||||
|
verbose: bool,
|
||||||
|
output_format: OutputFormat,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let bigtable = solana_storage_bigtable::LedgerStorage::new(false, None)
|
let bigtable = solana_storage_bigtable::LedgerStorage::new(false, None)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| format!("Failed to connect to storage: {:?}", err))?;
|
.map_err(|err| format!("Failed to connect to storage: {:?}", err))?;
|
||||||
|
|
||||||
let transaction_status = bigtable.get_signature_status(signature).await?;
|
let transaction_status = bigtable.get_signature_status(signature).await?;
|
||||||
|
|
||||||
|
let mut transaction = None;
|
||||||
|
let mut get_transaction_error = None;
|
||||||
if verbose {
|
if verbose {
|
||||||
match bigtable.get_confirmed_transaction(signature).await {
|
match bigtable.get_confirmed_transaction(signature).await {
|
||||||
Ok(Some(confirmed_transaction)) => {
|
Ok(Some(confirmed_transaction)) => {
|
||||||
println!(
|
transaction = Some(CliTransaction {
|
||||||
"\nTransaction executed in slot {}:",
|
transaction: EncodedTransaction::encode(
|
||||||
confirmed_transaction.slot
|
confirmed_transaction.transaction.transaction.clone(),
|
||||||
);
|
UiTransactionEncoding::Json,
|
||||||
println_transaction(
|
),
|
||||||
&confirmed_transaction.transaction.transaction,
|
meta: confirmed_transaction.transaction.meta.map(|m| m.into()),
|
||||||
&confirmed_transaction.transaction.meta.map(|m| m.into()),
|
block_time: confirmed_transaction.block_time,
|
||||||
" ",
|
slot: Some(confirmed_transaction.slot),
|
||||||
None,
|
decoded_transaction: confirmed_transaction.transaction.transaction,
|
||||||
);
|
prefix: " ".to_string(),
|
||||||
|
sigverify_status: vec![],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Ok(None) => println!("Finalized transaction details not available"),
|
Ok(None) => {}
|
||||||
Err(err) => println!("Unable to get finalized transaction details: {}", err),
|
Err(err) => {
|
||||||
|
get_transaction_error = Some(format!("{:?}", err));
|
||||||
}
|
}
|
||||||
println!();
|
|
||||||
}
|
}
|
||||||
if let Some(err) = &transaction_status.err {
|
|
||||||
println!("Transaction failed: {}", err);
|
|
||||||
} else {
|
|
||||||
println!("{:?}", transaction_status.confirmation_status());
|
|
||||||
}
|
}
|
||||||
|
let cli_transaction = CliTransactionConfirmation {
|
||||||
|
confirmation_status: Some(transaction_status.confirmation_status()),
|
||||||
|
transaction,
|
||||||
|
get_transaction_error,
|
||||||
|
err: transaction_status.err.clone(),
|
||||||
|
};
|
||||||
|
println!("{}", output_format.formatted_string(&cli_transaction));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +188,7 @@ pub async fn transaction_history(
|
|||||||
&transaction_with_meta.meta.clone().map(|m| m.into()),
|
&transaction_with_meta.meta.clone().map(|m| m.into()),
|
||||||
" ",
|
" ",
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,13 +316,6 @@ impl BigTableSubCommand for App<'_, '_> {
|
|||||||
.required(true)
|
.required(true)
|
||||||
.index(1)
|
.index(1)
|
||||||
.help("The transaction signature to confirm"),
|
.help("The transaction signature to confirm"),
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("verbose")
|
|
||||||
.short("v")
|
|
||||||
.long("verbose")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Show additional information"),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@ -366,13 +374,6 @@ impl BigTableSubCommand for App<'_, '_> {
|
|||||||
.long("show-transactions")
|
.long("show-transactions")
|
||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
.help("Display the full transactions"),
|
.help("Display the full transactions"),
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("verbose")
|
|
||||||
.short("v")
|
|
||||||
.long("verbose")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Show additional information"),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -382,6 +383,7 @@ impl BigTableSubCommand for App<'_, '_> {
|
|||||||
pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
||||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
|
||||||
|
let verbose = matches.is_present("verbose");
|
||||||
let output_format = matches
|
let output_format = matches
|
||||||
.value_of("output_format")
|
.value_of("output_format")
|
||||||
.map(|value| match value {
|
.map(|value| match value {
|
||||||
@ -389,7 +391,11 @@ pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
|||||||
"json-compact" => OutputFormat::JsonCompact,
|
"json-compact" => OutputFormat::JsonCompact,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
.unwrap_or(OutputFormat::Display);
|
.unwrap_or(if verbose {
|
||||||
|
OutputFormat::DisplayVerbose
|
||||||
|
} else {
|
||||||
|
OutputFormat::Display
|
||||||
|
});
|
||||||
|
|
||||||
let future = match matches.subcommand() {
|
let future = match matches.subcommand() {
|
||||||
("upload", Some(arg_matches)) => {
|
("upload", Some(arg_matches)) => {
|
||||||
@ -425,9 +431,8 @@ pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("Invalid signature");
|
.expect("Invalid signature");
|
||||||
let verbose = arg_matches.is_present("verbose");
|
|
||||||
|
|
||||||
runtime.block_on(confirm(&signature, verbose))
|
runtime.block_on(confirm(&signature, verbose, output_format))
|
||||||
}
|
}
|
||||||
("transaction-history", Some(arg_matches)) => {
|
("transaction-history", Some(arg_matches)) => {
|
||||||
let address = pubkey_of(arg_matches, "address").unwrap();
|
let address = pubkey_of(arg_matches, "address").unwrap();
|
||||||
@ -439,7 +444,6 @@ pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
|||||||
let until = arg_matches
|
let until = arg_matches
|
||||||
.value_of("until")
|
.value_of("until")
|
||||||
.map(|signature| signature.parse().expect("Invalid signature"));
|
.map(|signature| signature.parse().expect("Invalid signature"));
|
||||||
let verbose = arg_matches.is_present("verbose");
|
|
||||||
let show_transactions = arg_matches.is_present("show_transactions");
|
let show_transactions = arg_matches.is_present("show_transactions");
|
||||||
|
|
||||||
runtime.block_on(transaction_history(
|
runtime.block_on(transaction_history(
|
||||||
|
@ -123,6 +123,7 @@ fn output_entry(
|
|||||||
&transaction_status,
|
&transaction_status,
|
||||||
" ",
|
" ",
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -852,6 +853,15 @@ fn main() {
|
|||||||
.possible_values(&["json", "json-compact"])
|
.possible_values(&["json", "json-compact"])
|
||||||
.help("Return information in specified output format, currently only available for bigtable subcommands"),
|
.help("Return information in specified output format, currently only available for bigtable subcommands"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("verbose")
|
||||||
|
.short("v")
|
||||||
|
.long("verbose")
|
||||||
|
.global(true)
|
||||||
|
.multiple(true)
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Show additional information where supported"),
|
||||||
|
)
|
||||||
.bigtable_subcommand()
|
.bigtable_subcommand()
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("print")
|
SubCommand::with_name("print")
|
||||||
@ -873,14 +883,6 @@ fn main() {
|
|||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
.help("Only print root slots"),
|
.help("Only print root slots"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("verbose")
|
|
||||||
.long("verbose")
|
|
||||||
.short("v")
|
|
||||||
.multiple(true)
|
|
||||||
.takes_value(false)
|
|
||||||
.help("How verbose to print the ledger contents."),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("copy")
|
SubCommand::with_name("copy")
|
||||||
@ -1349,7 +1351,7 @@ fn main() {
|
|||||||
let num_slots = value_t!(arg_matches, "num_slots", Slot).ok();
|
let num_slots = value_t!(arg_matches, "num_slots", Slot).ok();
|
||||||
let allow_dead_slots = arg_matches.is_present("allow_dead_slots");
|
let allow_dead_slots = arg_matches.is_present("allow_dead_slots");
|
||||||
let only_rooted = arg_matches.is_present("only_rooted");
|
let only_rooted = arg_matches.is_present("only_rooted");
|
||||||
let verbose = arg_matches.occurrences_of("verbose");
|
let verbose = matches.occurrences_of("verbose");
|
||||||
output_ledger(
|
output_ledger(
|
||||||
open_blockstore(
|
open_blockstore(
|
||||||
&ledger_path,
|
&ledger_path,
|
||||||
|
@ -384,10 +384,11 @@ fn execute_transactions(bank: &Bank, txs: &[Transaction]) -> Vec<ConfirmedTransa
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_confirmed_tx(name: &str, confirmed_tx: ConfirmedTransaction) {
|
fn print_confirmed_tx(name: &str, confirmed_tx: ConfirmedTransaction) {
|
||||||
|
let block_time = confirmed_tx.block_time;
|
||||||
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, " ", None);
|
println_transaction(&tx, &encoded.transaction.meta, " ", None, block_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Reference in New Issue
Block a user