radix_transactions/manifest/
decompiler.rs

1use crate::data::*;
2use crate::internal_prelude::*;
3use crate::validation::*;
4use radix_common::address::AddressBech32Encoder;
5use radix_common::data::manifest::model::*;
6use radix_common::data::manifest::*;
7use radix_common::network::NetworkDefinition;
8use sbor::rust::prelude::*;
9use sbor::*;
10
11#[derive(Debug, Clone)]
12pub enum DecompileError {
13    InvalidArguments,
14    EncodeError(EncodeError),
15    DecodeError(DecodeError),
16    FormattingError(fmt::Error),
17    ValueConversionError(RustToManifestValueError),
18}
19
20impl From<EncodeError> for DecompileError {
21    fn from(error: EncodeError) -> Self {
22        Self::EncodeError(error)
23    }
24}
25
26impl From<DecodeError> for DecompileError {
27    fn from(error: DecodeError) -> Self {
28        Self::DecodeError(error)
29    }
30}
31
32impl From<fmt::Error> for DecompileError {
33    fn from(error: fmt::Error) -> Self {
34        Self::FormattingError(error)
35    }
36}
37
38impl From<RustToManifestValueError> for DecompileError {
39    fn from(error: RustToManifestValueError) -> Self {
40        Self::ValueConversionError(error)
41    }
42}
43
44#[derive(Default)]
45pub struct DecompilationContext<'a> {
46    pub address_bech32_encoder: Option<&'a AddressBech32Encoder>,
47    pub transaction_hash_bech32_encoder: Option<&'a TransactionHashBech32Encoder>,
48    pub id_allocator: ManifestIdAllocator,
49    pub object_names: ManifestObjectNamesRef<'a>,
50}
51
52impl<'a> DecompilationContext<'a> {
53    pub fn new(
54        address_bech32_encoder: &'a AddressBech32Encoder,
55        transaction_hash_bech32_encoder: &'a TransactionHashBech32Encoder,
56        object_names: ManifestObjectNamesRef<'a>,
57    ) -> Self {
58        Self {
59            address_bech32_encoder: Some(address_bech32_encoder),
60            transaction_hash_bech32_encoder: Some(transaction_hash_bech32_encoder),
61            object_names,
62            ..Default::default()
63        }
64    }
65
66    pub fn for_value_display(&'a self) -> ManifestDecompilationDisplayContext<'a> {
67        ManifestDecompilationDisplayContext::with_bech32_and_names(
68            self.address_bech32_encoder,
69            self.object_names,
70        )
71        .with_multi_line(4, 4)
72    }
73
74    pub fn transaction_hash_encoder(&'a self) -> Option<&'a TransactionHashBech32Encoder> {
75        self.transaction_hash_bech32_encoder
76    }
77
78    pub fn new_bucket(&mut self) -> ManifestBucket {
79        self.id_allocator.new_bucket_id()
80    }
81
82    pub fn new_proof(&mut self) -> ManifestProof {
83        self.id_allocator.new_proof_id()
84    }
85
86    pub fn new_address_reservation(&mut self) -> ManifestAddressReservation {
87        self.id_allocator.new_address_reservation_id()
88    }
89
90    pub fn new_address(&mut self) -> ManifestAddress {
91        let id = self.id_allocator.new_address_id();
92        ManifestAddress::Named(id)
93    }
94
95    pub fn new_named_intent(&mut self) -> ManifestNamedIntent {
96        self.id_allocator.new_named_intent_id()
97    }
98
99    /// Allocate addresses before transaction, for system transactions only.
100    pub fn preallocate_addresses(&mut self, n: u32) {
101        for _ in 0..n {
102            let _ = self.new_address();
103        }
104    }
105}
106
107pub fn decompile_any(
108    manifest: &AnyManifest,
109    network: &NetworkDefinition,
110) -> Result<String, DecompileError> {
111    match manifest {
112        AnyManifest::V1(m) => decompile(m, network),
113        AnyManifest::SystemV1(m) => decompile(m, network),
114        AnyManifest::V2(m) => decompile(m, network),
115        AnyManifest::SubintentV2(m) => decompile(m, network),
116    }
117}
118
119/// Contract: if the instructions are from a validated notarized transaction, no error
120/// should be returned.
121pub fn decompile(
122    manifest: &impl TypedReadableManifest,
123    network: &NetworkDefinition,
124) -> Result<String, DecompileError> {
125    let address_bech32_encoder = AddressBech32Encoder::new(network);
126    let transaction_hash_encoder = TransactionHashBech32Encoder::new(network);
127    let mut buf = String::new();
128    let mut context = DecompilationContext::new(
129        &address_bech32_encoder,
130        &transaction_hash_encoder,
131        manifest.get_known_object_names_ref(),
132    );
133    for preallocated_address in manifest.get_preallocated_addresses() {
134        let psuedo_instruction =
135            preallocated_address.decompile_as_pseudo_instruction(&mut context)?;
136        output_instruction(&mut buf, &context, psuedo_instruction)?;
137    }
138    for child_subintent in manifest.get_child_subintent_hashes() {
139        let psuedo_instruction = child_subintent.decompile_as_pseudo_instruction(&mut context)?;
140        output_instruction(&mut buf, &context, psuedo_instruction)?;
141    }
142    for inst in manifest.get_typed_instructions() {
143        let decompiled = inst.decompile(&mut context)?;
144        output_instruction(&mut buf, &context, decompiled)?;
145    }
146
147    Ok(buf)
148}
149
150pub struct DecompiledInstruction {
151    command: &'static str,
152    fields: Vec<DecompiledInstructionField>,
153}
154
155enum DecompiledInstructionField {
156    Value(ManifestValue),
157    Raw(String),
158}
159
160impl DecompiledInstruction {
161    pub fn new(instruction: &'static str) -> Self {
162        Self {
163            command: instruction,
164            fields: vec![],
165        }
166    }
167
168    pub fn add_value_argument(mut self, value: ManifestValue) -> Self {
169        self.fields.push(DecompiledInstructionField::Value(value));
170        self
171    }
172
173    pub fn add_separated_tuple_value_arguments(
174        mut self,
175        tuple_args: &ManifestValue,
176    ) -> Result<Self, DecompileError> {
177        if let Value::Tuple { fields } = tuple_args {
178            for argument in fields.iter() {
179                self = self.add_value_argument(argument.clone());
180            }
181        } else {
182            return Err(DecompileError::InvalidArguments);
183        }
184        Ok(self)
185    }
186
187    pub fn add_argument(self, value: impl ManifestEncode) -> Self {
188        let encoded = manifest_encode(&value).unwrap();
189        let value = manifest_decode(&encoded).unwrap();
190        self.add_value_argument(value)
191    }
192
193    /// Only for use in pseudo-instructions.
194    /// When we update the manifest value model, we should be able to discard these.
195    pub fn add_raw_argument(mut self, value: String) -> Self {
196        self.fields.push(DecompiledInstructionField::Raw(value));
197        self
198    }
199}
200
201pub fn output_instruction<F: fmt::Write>(
202    f: &mut F,
203    context: &DecompilationContext,
204    DecompiledInstruction {
205        command,
206        fields: arguments,
207    }: DecompiledInstruction,
208) -> Result<(), DecompileError> {
209    let value_display_context = context.for_value_display();
210    write!(f, "{}", command)?;
211    for argument in arguments.iter() {
212        writeln!(f)?;
213        match argument {
214            DecompiledInstructionField::Value(value) => {
215                format_manifest_value(f, value, &value_display_context, true, 0)?;
216            }
217            DecompiledInstructionField::Raw(raw_argument) => {
218                let initial_indent = value_display_context.get_indent(0);
219                write!(f, "{initial_indent}{raw_argument}")?;
220            }
221        }
222    }
223    if !arguments.is_empty() {
224        write!(f, "\n;\n")?;
225    } else {
226        writeln!(f, ";")?;
227    }
228
229    Ok(())
230}