pcli/command/view/
tx.rs

1use anyhow::{Context, Result};
2use penumbra_sdk_proto::{util::tendermint_proxy::v1::GetTxRequest, DomainType};
3use penumbra_sdk_transaction::Transaction;
4use penumbra_sdk_view::{TransactionInfo, ViewClient};
5
6use crate::App;
7
8/// Queries the chain for a transaction by hash.
9#[derive(Debug, clap::Args)]
10pub struct TxCmd {
11    /// The hex-formatted transaction hash to query.
12    hash: String,
13    /// If set, print the raw transaction view rather than a formatted table.
14    #[clap(long)]
15    raw: bool,
16}
17
18impl TxCmd {
19    pub fn offline(&self) -> bool {
20        false
21    }
22    pub async fn exec(&self, app: &mut App) -> Result<()> {
23        let hash = self
24            .hash
25            // We have to convert to uppercase because `tendermint::Hash` only accepts uppercase :(
26            .to_uppercase()
27            .parse()
28            .context("invalid transaction hash")?;
29
30        // Retrieve Transaction from the view service first, or else the fullnode
31        let tx_info = if let Ok(tx_info) = app.view().transaction_info_by_hash(hash).await {
32            tx_info
33        } else {
34            if !self.raw {
35                println!("Transaction not found in view service, fetching from fullnode...");
36            } else {
37                tracing::info!("Transaction not found in view service, fetching from fullnode...");
38            }
39            // Fall back to fetching from fullnode
40            let mut client = app.tendermint_proxy_client().await?;
41            let rsp = client
42                .get_tx(GetTxRequest {
43                    hash: hex::decode(self.hash.clone())?,
44                    prove: false,
45                })
46                .await?;
47
48            let rsp = rsp.into_inner();
49            let tx = Transaction::decode(rsp.tx.as_slice())?;
50            let txp = Default::default();
51            let txv = tx.view_from_perspective(&txp);
52            let summary = txv.summary();
53
54            TransactionInfo {
55                height: rsp.height,
56                id: hash,
57                transaction: tx,
58                perspective: txp,
59                view: txv,
60                summary: summary,
61            }
62        };
63
64        if self.raw {
65            use colored_json::prelude::*;
66            println!(
67                "{}",
68                serde_json::to_string_pretty(&tx_info.view)?.to_colored_json_auto()?
69            );
70        } else {
71            use crate::transaction_view_ext::TransactionViewExt;
72            tx_info.view.render_terminal();
73        }
74
75        Ok(())
76    }
77}