Skip to main content

bitcoin_cash/
serialize_json.rs

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}