1use crate::{
2 ByteArray, Function, Hashed, Op, Opcode, Ops, Script, Sha256d, TaggedOp, TxInput, TxOutpoint,
3 TxOutput, UnhashedTx,
4};
5use bimap::BiMap;
6use serde_derive::{Deserialize, Serialize};
7use std::borrow::Cow;
8use std::collections::HashMap;
9use std::sync::Arc;
10
11#[derive(Serialize, Deserialize, Default)]
12struct JsonData {
13 data_b64: Vec<String>,
14 byte_arrays: Vec<JsonByteArray>,
15 strings: Vec<Cow<'static, str>>,
16
17 #[serde(skip)]
18 string_indices: HashMap<Arc<Cow<'static, str>>, usize>,
19
20 #[serde(skip)]
21 data_indices: BiMap<Arc<[u8]>, usize>,
22}
23
24struct JsonByteArray {
25 data_idx: usize,
26 function: Function,
27 name_idx: Option<usize>,
28 preimage_indices: Option<Vec<usize>>,
29}
30
31type JsonByteArrayTuple = (usize, Function, Option<usize>, Option<Vec<usize>>);
32type JsonByteArrayTupleRef<'a> = (
33 &'a usize,
34 &'a Function,
35 &'a Option<usize>,
36 &'a Option<Vec<usize>>,
37);
38
39#[derive(Serialize, Deserialize)]
40enum JsonOp {
41 Code(u8),
42 Invalid(u8),
43 PushByteArray { array_idx: usize, is_minimal: bool },
44 PushBoolean(bool),
45 PushInteger(i32),
46}
47
48#[derive(Serialize, Deserialize)]
49struct JsonTaggedOp {
50 op: JsonOp,
51 src_file: usize,
52 src_line: u32,
53 src_column: u32,
54 src_code: Vec<(u32, usize)>,
55 pushed_names: Option<Vec<Option<usize>>>,
56 alt_pushed_names: Option<Vec<Option<usize>>>,
57}
58
59#[derive(Serialize, Deserialize)]
60struct JsonInput {
61 prev_out_hash: usize,
62 prev_out_vout: u32,
63 script: Vec<JsonTaggedOp>,
64 sequence: u32,
65 lock_script: Option<Vec<JsonTaggedOp>>,
66 value: Option<u64>,
67 is_p2sh: Option<bool>,
68}
69
70#[derive(Deserialize, Serialize)]
71struct JsonOutput {
72 value: u64,
73 script: Vec<JsonTaggedOp>,
74}
75
76#[derive(Serialize, Deserialize)]
77struct JsonTx {
78 data: JsonData,
79 version: i32,
80 inputs: Vec<JsonInput>,
81 outputs: Vec<JsonOutput>,
82 lock_time: u32,
83}
84
85pub mod error {
86 use error_chain::error_chain;
87 error_chain! {
88 foreign_links {
89 DecodeError(base64::DecodeError);
90 }
91 errors {
92 InvalidDataIdx(idx: usize) {}
93 InvalidStringIdx(idx: usize) {}
94 InvalidHash {}
95 }
96 }
97}
98
99use error::ResultExt;
100
101pub fn tx_to_json(tx: &UnhashedTx) -> Result<String, serde_json::Error> {
102 let json_tx = JsonTx::from_tx(tx);
103 serde_json::to_string(&json_tx)
104}
105
106pub fn json_to_tx(s: &str) -> Result<UnhashedTx, crate::error::Error> {
107 let mut json_tx: JsonTx = serde_json::from_str(s)?;
108 Ok(json_tx.to_tx()?)
109}
110
111impl JsonTx {
112 fn from_tx(tx: &UnhashedTx) -> Self {
113 let mut json_tx = JsonTx {
114 data: JsonData::default(),
115 version: tx.version,
116 inputs: vec![],
117 outputs: vec![],
118 lock_time: tx.lock_time,
119 };
120 for input in tx.inputs.iter() {
121 let json_input = JsonInput {
122 prev_out_hash: json_tx
123 .data
124 .insert_byte_array(input.prev_out.tx_hash.as_byte_array()),
125 prev_out_vout: input.prev_out.vout,
126 script: json_tx.make_ops(input.script.ops().iter()),
127 sequence: input.sequence,
128 lock_script: input
129 .lock_script
130 .as_ref()
131 .map(|script| json_tx.make_ops(script.ops().iter())),
132 value: input.value,
133 is_p2sh: input.is_p2sh,
134 };
135 json_tx.inputs.push(json_input);
136 }
137 for output in tx.outputs.iter() {
138 let json_output = JsonOutput {
139 value: output.value,
140 script: json_tx.make_ops(output.script.ops().iter()),
141 };
142 json_tx.outputs.push(json_output);
143 }
144 json_tx
145 }
146
147 fn to_tx(&mut self) -> Result<UnhashedTx, error::Error> {
148 let mut tx = UnhashedTx {
149 version: self.version,
150 inputs: Vec::with_capacity(self.inputs.len()),
151 outputs: Vec::with_capacity(self.outputs.len()),
152 lock_time: self.lock_time,
153 };
154 let JsonTx {
155 data,
156 inputs,
157 outputs,
158 ..
159 } = self;
160 for input in inputs.iter() {
161 let input = TxInput {
162 prev_out: TxOutpoint {
163 tx_hash: Sha256d::from_byte_array(data.get_byte_array(input.prev_out_hash)?)
164 .chain_err(|| error::ErrorKind::InvalidHash)?,
165 vout: input.prev_out_vout,
166 },
167 sequence: input.sequence,
168 script: Script::new(
169 input
170 .script
171 .iter()
172 .map(|op| op.to_tagged_op(data))
173 .collect::<Result<Vec<_>, _>>()?,
174 ),
175 lock_script: input
176 .lock_script
177 .as_ref()
178 .map(|lock_script| {
179 lock_script
180 .iter()
181 .map(|op| op.to_tagged_op(data))
182 .collect::<Result<Vec<_>, _>>()
183 .map(Script::new)
184 })
185 .map_or(Ok(None), |name| name.map(Some))?,
186 value: input.value,
187 is_p2sh: input.is_p2sh,
188 };
189 tx.inputs.push(input);
190 }
191 for output in outputs.iter() {
192 let output = TxOutput {
193 script: Script::new(
194 output
195 .script
196 .iter()
197 .map(|op| op.to_tagged_op(data))
198 .collect::<Result<Vec<_>, _>>()?,
199 ),
200 value: output.value,
201 };
202 tx.outputs.push(output);
203 }
204 Ok(tx)
205 }
206
207 fn make_ops<'a>(&mut self, ops: impl Iterator<Item = &'a TaggedOp>) -> Vec<JsonTaggedOp> {
208 ops.map(|op| JsonTaggedOp::from_tagged_op(&mut self.data, op))
209 .collect()
210 }
211}
212
213impl JsonTaggedOp {
214 fn from_tagged_op(data: &mut JsonData, tagged_op: &TaggedOp) -> Self {
215 let op = match tagged_op.op {
216 Op::Code(code) => JsonOp::Code(code as u8),
217 Op::Invalid(code) => JsonOp::Invalid(code),
218 Op::PushBoolean(boolean) => JsonOp::PushBoolean(boolean),
219 Op::PushInteger(integer) => JsonOp::PushInteger(integer),
220 Op::PushByteArray {
221 ref array,
222 is_minimal,
223 } => JsonOp::PushByteArray {
224 array_idx: data.insert_byte_array(array),
225 is_minimal,
226 },
227 };
228 JsonTaggedOp {
229 op,
230 src_file: data.insert_string(&tagged_op.src_file),
231 src_line: tagged_op.src_line,
232 src_column: tagged_op.src_column,
233 src_code: tagged_op
234 .src_code
235 .iter()
236 .map(|&(width, ref code)| (width, data.insert_string(code)))
237 .collect(),
238 pushed_names: tagged_op.pushed_names.as_ref().map(|pushed_names| {
239 pushed_names
240 .iter()
241 .map(|name| name.as_ref().map(|n| data.insert_string(n)))
242 .collect()
243 }),
244 alt_pushed_names: tagged_op.alt_pushed_names.as_ref().map(|pushed_names| {
245 pushed_names
246 .iter()
247 .map(|name| name.as_ref().map(|n| data.insert_string(n)))
248 .collect()
249 }),
250 }
251 }
252
253 fn to_tagged_op(&self, data: &mut JsonData) -> Result<TaggedOp, error::Error> {
254 let op = match self.op {
255 JsonOp::Code(code) => {
256 let opcode: Option<Opcode> = num::FromPrimitive::from_u8(code);
257 opcode.map(Op::Code).unwrap_or(Op::Invalid(code))
258 }
259 JsonOp::Invalid(code) => Op::Invalid(code),
260 JsonOp::PushBoolean(boolean) => Op::PushBoolean(boolean),
261 JsonOp::PushInteger(int) => Op::PushInteger(int),
262 JsonOp::PushByteArray {
263 array_idx,
264 is_minimal,
265 } => Op::PushByteArray {
266 array: data.get_byte_array(array_idx)?,
267 is_minimal,
268 },
269 };
270 Ok(TaggedOp {
271 op,
272 src_file: data.get_string(self.src_file)?.clone(),
273 src_line: self.src_line,
274 src_column: self.src_column,
275 src_code: self
276 .src_code
277 .iter()
278 .map(|&(width, string_idx)| data.get_string(string_idx).map(|s| (width, s.clone())))
279 .collect::<Result<Vec<_>, _>>()?,
280 pushed_names: self
281 .pushed_names
282 .as_ref()
283 .map(|pushed_names| {
284 pushed_names
285 .iter()
286 .map(|name| {
287 name.map(|string_idx| data.get_string(string_idx).map(Clone::clone))
288 .map_or(Ok(None), |name| name.map(Some))
289 })
290 .collect::<Result<Vec<_>, _>>()
291 })
292 .map_or(Ok(None), |name| name.map(Some))?,
293 alt_pushed_names: self
294 .alt_pushed_names
295 .as_ref()
296 .map(|pushed_names| {
297 pushed_names
298 .iter()
299 .map(|name| {
300 name.map(|string_idx| data.get_string(string_idx).map(Clone::clone))
301 .map_or(Ok(None), |name| name.map(Some))
302 })
303 .collect::<Result<Vec<_>, _>>()
304 })
305 .map_or(Ok(None), |name| name.map(Some))?,
306 })
307 }
308}
309
310impl JsonData {
311 fn insert_byte_array(&mut self, byte_array: &ByteArray) -> usize {
312 let preimage_indices = byte_array.preimage().map(|preimage| {
313 preimage
314 .iter()
315 .map(|preimage| self.insert_byte_array(preimage))
316 .collect::<Vec<_>>()
317 });
318 let name_idx = byte_array
319 .name_arc()
320 .map(|name| self.insert_string_arc(name));
321 let data_idx = self.ensure_data(byte_array.data());
322 let byte_array_idx = self.byte_arrays.len();
323 self.byte_arrays.push(JsonByteArray {
324 data_idx,
325 function: byte_array.function(),
326 name_idx,
327 preimage_indices,
328 });
329 byte_array_idx
330 }
331
332 fn ensure_data(&mut self, data: &Arc<[u8]>) -> usize {
333 if let Some(&data_idx) = self.data_indices.get_by_left(data) {
334 data_idx
335 } else {
336 let new_idx = self.data_b64.len();
337 self.data_b64.push(base64::encode(data));
338 self.data_indices.insert(Arc::clone(data), new_idx);
339 new_idx
340 }
341 }
342
343 fn get_byte_array(&mut self, byte_array_idx: usize) -> Result<ByteArray, error::Error> {
344 use error::ErrorKind::*;
345 let preimage = self.byte_arrays[byte_array_idx]
346 .preimage_indices
347 .clone()
348 .map(|preimage_indices| {
349 preimage_indices
350 .iter()
351 .map(|&idx| self.get_byte_array(idx))
352 .collect::<Result<Vec<_>, _>>()
353 })
354 .map_or(Ok(None), |preimage| preimage.map(Some))?;
355 let json = &self.byte_arrays[byte_array_idx];
356 let data = if let Some(data) = self.data_indices.get_by_right(&json.data_idx) {
357 Arc::clone(data)
358 } else {
359 let data_b64 = self
360 .data_b64
361 .get(json.data_idx)
362 .ok_or(InvalidDataIdx(json.data_idx))?;
363 let data = base64::decode(data_b64)?.into();
364 self.data_indices.insert(Arc::clone(&data), json.data_idx);
365 data
366 };
367 let name = json
368 .name_idx
369 .map(|name_idx| self.get_string(name_idx).map(Clone::clone).map(Arc::new))
370 .map_or(Ok(None), |name| name.map(Some))?;
371 Ok(ByteArray::from_preimage(
372 data,
373 name,
374 json.function,
375 preimage.map(Into::into),
376 ))
377 }
378
379 fn insert_string(&mut self, cow: &Cow<'static, str>) -> usize {
380 if let Some(&string_idx) = self.string_indices.get(cow) {
381 string_idx
382 } else {
383 let string_idx = self.strings.len();
384 self.strings.push(cow.clone());
385 self.string_indices
386 .insert(Arc::new(cow.clone()), string_idx);
387 string_idx
388 }
389 }
390
391 fn insert_string_arc(&mut self, arc: &Arc<Cow<'static, str>>) -> usize {
392 if let Some(&string_idx) = self.string_indices.get(arc) {
393 string_idx
394 } else {
395 let string_idx = self.strings.len();
396 self.strings.push((**arc).clone());
397 self.string_indices.insert(Arc::clone(arc), string_idx);
398 string_idx
399 }
400 }
401
402 fn get_string(&self, string_idx: usize) -> Result<&Cow<'static, str>, error::Error> {
403 self.strings
404 .get(string_idx)
405 .ok_or_else(|| error::ErrorKind::InvalidStringIdx(string_idx).into())
406 }
407}
408
409impl JsonByteArray {
410 fn from_tuple(t: JsonByteArrayTuple) -> Self {
411 JsonByteArray {
412 data_idx: t.0,
413 function: t.1,
414 name_idx: t.2,
415 preimage_indices: t.3,
416 }
417 }
418
419 fn as_tuple(&self) -> JsonByteArrayTupleRef {
420 (
421 &self.data_idx,
422 &self.function,
423 &self.name_idx,
424 &self.preimage_indices,
425 )
426 }
427}
428
429impl<'de> serde::Deserialize<'de> for JsonByteArray {
430 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
431 where
432 D: serde::Deserializer<'de>,
433 {
434 Ok(JsonByteArray::from_tuple(
435 <JsonByteArrayTuple as serde::Deserialize<'de>>::deserialize(deserializer)?,
436 ))
437 }
438}
439
440impl serde::Serialize for JsonByteArray {
441 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
442 where
443 S: serde::Serializer,
444 {
445 self.as_tuple().serialize(serializer)
446 }
447}