Skip to content

Commit

Permalink
cli: add --dump-tx option to dump transactions
Browse files Browse the repository at this point in the history
This option dumps transactions before and after signing, and dumps the
wrapper transaction as well. (We currently wrap and sign the wrapper
simultaneously.)
  • Loading branch information
juped committed Jan 19, 2023
1 parent 1829357 commit 1b81c11
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
9 changes: 9 additions & 0 deletions apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1568,6 +1568,7 @@ pub mod args {
const DECRYPT: ArgFlag = flag("decrypt");
const DONT_ARCHIVE: ArgFlag = flag("dont-archive");
const DRY_RUN_TX: ArgFlag = flag("dry-run");
const DUMP_TX: ArgFlag = flag("dump-tx");
const EPOCH: ArgOpt<Epoch> = arg_opt("epoch");
const FORCE: ArgFlag = flag("force");
const DONT_PREFETCH_WASM: ArgFlag = flag("dont-prefetch-wasm");
Expand Down Expand Up @@ -2734,6 +2735,8 @@ pub mod args {
pub struct Tx {
/// Simulate applying the transaction
pub dry_run: bool,
/// Dump the transaction bytes
pub dump_tx: bool,
/// Submit the transaction even if it doesn't pass client checks
pub force: bool,
/// Do not wait for the transaction to be added to the blockchain
Expand All @@ -2759,6 +2762,7 @@ pub mod args {
pub fn parse_from_context(&self, ctx: &mut Context) -> ParsedTxArgs {
ParsedTxArgs {
dry_run: self.dry_run,
dump_tx: self.dump_tx,
force: self.force,
broadcast_only: self.broadcast_only,
ledger_address: self.ledger_address.clone(),
Expand All @@ -2784,6 +2788,9 @@ pub mod args {
.def()
.about("Simulate the transaction application."),
)
.arg(DUMP_TX.def().about(
"Dump transaction bytes to a file."
))
.arg(FORCE.def().about(
"Submit the transaction even if it doesn't pass client checks.",
))
Expand Down Expand Up @@ -2830,6 +2837,7 @@ pub mod args {

fn parse(matches: &ArgMatches) -> Self {
let dry_run = DRY_RUN_TX.parse(matches);
let dump_tx = DUMP_TX.parse(matches);
let force = FORCE.parse(matches);
let broadcast_only = BROADCAST_ONLY.parse(matches);
let ledger_address = LEDGER_ADDRESS_DEFAULT.parse(matches);
Expand All @@ -2842,6 +2850,7 @@ pub mod args {
let signer = SIGNER.parse(matches);
Self {
dry_run,
dump_tx,
force,
broadcast_only,
ledger_address,
Expand Down
49 changes: 49 additions & 0 deletions apps/src/lib/client/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use borsh::BorshSerialize;
use namada::ledger::parameters::storage as parameter_storage;
use namada::proto::Tx;
use namada::types::address::{Address, ImplicitAddress};
use namada::types::hash::Hash;
use namada::types::key::*;
use namada::types::storage::Epoch;
use namada::types::token;
Expand Down Expand Up @@ -151,8 +152,15 @@ pub async fn sign_tx(
default: TxSigningKey,
#[cfg(not(feature = "mainnet"))] requires_pow: bool,
) -> (Context, TxBroadcastData) {
if args.dump_tx {
dump_tx_helper(&ctx, &tx, "unsigned", None);
}

let keypair = tx_signer(&mut ctx, args, default).await;
let tx = tx.sign(&keypair);
if args.dump_tx {
dump_tx_helper(&ctx, &tx, "signed", None);
}

let epoch = rpc::query_epoch(args::Query {
ledger_address: args.ledger_address.clone(),
Expand All @@ -172,9 +180,50 @@ pub async fn sign_tx(
)
.await
};

if args.dump_tx && !args.dry_run {
let (wrapper_tx, wrapper_hash) = match broadcast_data {
TxBroadcastData::DryRun(_) => panic!(
"somehow created a dry run transaction without --dry-run"
),
TxBroadcastData::Wrapper {
ref tx,
ref wrapper_hash,
decrypted_hash: _,
} => (tx, wrapper_hash),
};

dump_tx_helper(&ctx, wrapper_tx, "wrapper", Some(wrapper_hash));
}

(ctx, broadcast_data)
}

pub fn dump_tx_helper(
ctx: &Context,
tx: &Tx,
extension: &str,
precomputed_hash: Option<&String>,
) -> () {
let chain_dir = ctx.config.ledger.chain_dir();
let hash = match precomputed_hash {
Some(hash) => hash.to_owned(),
None => {
let hash: Hash = tx
.hash()
.as_ref()
.try_into()
.expect("expected hash of dumped tx to be a hash");
format!("{}", hash)
}
};
let filename = chain_dir.join(hash).with_extension(extension);
let tx_bytes = tx.to_bytes();

std::fs::write(filename, tx_bytes)
.expect("expected to be able to write tx dump file");
}

/// Create a wrapper tx from a normal tx. Get the hash of the
/// wrapper and its payload which is needed for monitoring its
/// progress on chain.
Expand Down
2 changes: 2 additions & 0 deletions apps/src/lib/client/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use crate::facade::tendermint_config::net::Address as TendermintAddress;
pub struct ParsedTxArgs {
/// Simulate applying the transaction
pub dry_run: bool,
/// Dump the transaction bytes
pub dump_tx: bool,
/// Submit the transaction even if it doesn't pass client checks
pub force: bool,
/// Do not wait for the transaction to be added to the blockchain
Expand Down

0 comments on commit 1b81c11

Please sign in to comment.