radix_clis/rtmd/
mod.rs

1use crate::prelude::*;
2
3/// Radix transaction manifest decompiler
4#[derive(Parser, Debug)]
5#[clap(author, version, about, long_about = None, name = "rtmd")]
6pub struct Args {
7    /// Path to the output file
8    #[clap(short, long)]
9    output: PathBuf,
10
11    /// Network to Use [Simulator | Alphanet | Mainnet]
12    #[clap(short, long)]
13    network: Option<String>,
14
15    /// Whether to export blobs
16    #[clap(short, long, action)]
17    export_blobs: bool,
18
19    /// Input file
20    #[clap(required = true)]
21    input: PathBuf,
22}
23
24#[derive(Debug)]
25pub enum Error {
26    IoError(std::io::Error),
27    DecodeError(sbor::DecodeError),
28    DecompileError(DecompileError),
29    ParseNetworkError(ParseNetworkError),
30    ManifestValidationError(ManifestValidationError),
31    InstructionSchemaValidationError(radix_engine::utils::LocatedInstructionSchemaValidationError),
32}
33
34impl fmt::Display for Error {
35    // TODO Implement pretty error printing
36    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37        write!(f, "{:?}", self)
38    }
39}
40
41impl From<Error> for String {
42    fn from(err: Error) -> String {
43        err.to_string()
44    }
45}
46
47pub fn run() -> Result<(), String> {
48    let args = Args::parse();
49
50    let content = std::fs::read(&args.input).map_err(Error::IoError)?;
51    let network = match args.network {
52        Some(n) => NetworkDefinition::from_str(&n).map_err(Error::ParseNetworkError)?,
53        None => NetworkDefinition::simulator(),
54    };
55
56    let manifest = AnyManifest::attempt_decode_from_arbitrary_payload(&content)?;
57
58    manifest
59        .validate(ValidationRuleset::all())
60        .map_err(Error::ManifestValidationError)?;
61
62    validate_call_arguments_to_native_components(&manifest)
63        .map_err(Error::InstructionSchemaValidationError)?;
64
65    let decompiled = decompile_any(&manifest, &network).map_err(Error::DecompileError)?;
66
67    write_ensuring_folder_exists(&args.output, &decompiled).map_err(Error::IoError)?;
68
69    if args.export_blobs {
70        let directory = args.output.parent().unwrap();
71        for (blob_hash, content) in manifest.get_blobs() {
72            std::fs::write(directory.join(format!("{}.blob", blob_hash)), content)
73                .map_err(Error::IoError)?;
74        }
75    }
76
77    Ok(())
78}