radix_transactions/manifest/
decompiler.rs1use 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 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
119pub 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 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}