bitcoin_cash/
script.rs

1use crate::error::{Result, ScriptSerializeError};
2use crate::{encoding_utils::encode_int, ByteArray, Op, Opcode, Ops, TaggedOp};
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
5use std::borrow::Cow;
6use std::io::Read;
7use std::sync::Arc;
8
9#[derive(Clone, Debug, Eq, PartialEq)]
10pub struct Script {
11    ops: Arc<[TaggedOp]>,
12}
13
14impl Ops for Script {
15    fn ops(&self) -> Cow<[TaggedOp]> {
16        self.ops.as_ref().into()
17    }
18}
19
20impl Script {
21    pub fn new(ops: impl Into<Arc<[TaggedOp]>>) -> Self {
22        Script { ops: ops.into() }
23    }
24
25    pub fn serialize(&self) -> Result<ByteArray> {
26        serialize_ops(self.ops.iter().map(|op| &op.op))
27    }
28}
29
30impl Script {
31    pub fn ops_arc(&self) -> &Arc<[TaggedOp]> {
32        &self.ops
33    }
34
35    pub fn to_script_code(&self, n_codesep: Option<usize>) -> Script {
36        let idx = if let Some(n_codesep) = n_codesep {
37            let mut n_codeseps_found = 0;
38            let mut codesep_idx = None;
39            for (idx, op) in self.ops.iter().enumerate() {
40                match op.op {
41                    Op::Code(Opcode::OP_CODESEPARATOR) => {
42                        if n_codesep == n_codeseps_found {
43                            codesep_idx = Some(idx);
44                            break;
45                        }
46                        n_codeseps_found += 1;
47                    }
48                    _ => continue,
49                }
50            }
51            codesep_idx.expect("Couldn't find OP_CODESEPARATOR")
52        } else {
53            0
54        };
55        Script::new(self.ops[idx..].to_vec())
56    }
57
58    pub fn to_script_code_first(&self) -> Script {
59        if let Some(code_separator_idx) = self
60            .ops
61            .iter()
62            .position(|op| op.op == Op::Code(Opcode::OP_CODESEPARATOR))
63        {
64            Script::new(self.ops[code_separator_idx + 1..].to_vec())
65        } else {
66            self.clone()
67        }
68    }
69}
70
71impl Default for Script {
72    fn default() -> Self {
73        Script { ops: Arc::new([]) }
74    }
75}
76
77#[derive(Clone, Copy)]
78enum PushPrefixTail {
79    NoTail,
80    PushedData,
81}
82
83fn serialize_push_prefix(
84    vec: &mut Vec<u8>,
85    bytes: &[u8],
86    is_minimal_push: bool,
87) -> Result<PushPrefixTail> {
88    use Opcode::*;
89    match bytes.len() {
90        0 if is_minimal_push => {
91            vec.push(OP_0 as u8);
92            return Ok(PushPrefixTail::NoTail);
93        }
94        0 if !is_minimal_push => {
95            vec.push(OP_PUSHDATA1 as u8);
96            vec.push(0);
97        }
98        1 if is_minimal_push => {
99            let value = bytes[0];
100            if value <= 16 {
101                vec.push(OP_1 as u8 - 1 + value);
102                return Ok(PushPrefixTail::NoTail);
103            } else if value == 0x81 {
104                vec.push(OP_1NEGATE as u8);
105                return Ok(PushPrefixTail::NoTail);
106            } else {
107                vec.push(1);
108            }
109        }
110        len @ 0x00..=0x4b => vec.push(len as u8),
111        len @ 0x4c..=0xff => {
112            vec.push(OP_PUSHDATA1 as u8);
113            vec.push(len as u8);
114        }
115        len @ 0x100..=0xffff => {
116            vec.push(OP_PUSHDATA2 as u8);
117            vec.write_u16::<LittleEndian>(len as u16).unwrap();
118        }
119        len @ 0x10000..=0xffff_ffff => {
120            vec.push(OP_PUSHDATA4 as u8);
121            vec.write_u32::<LittleEndian>(len as u32).unwrap();
122        }
123        _ => return ScriptSerializeError::PushTooLarge.into_err(),
124    }
125    Ok(PushPrefixTail::PushedData)
126}
127
128fn serialize_push_bytes(bytes: ByteArray, is_minimal_push: bool) -> Result<ByteArray> {
129    use PushPrefixTail::*;
130    let mut vec = Vec::new();
131    match serialize_push_prefix(&mut vec, &bytes, is_minimal_push)? {
132        NoTail => Ok(vec.into()),
133        PushedData => Ok(ByteArray::new_unnamed(vec).concat(bytes)),
134    }
135}
136
137pub fn serialize_op(op: &Op) -> Result<ByteArray> {
138    use Opcode::*;
139    match *op {
140        Op::Code(opcode) => Ok([opcode as u8].into()),
141        Op::Invalid(opcode) => Ok([opcode as u8].into()),
142        Op::PushBoolean(boolean) => Ok([if boolean { OP_1 as u8 } else { OP_0 as u8 }].into()),
143        Op::PushInteger(int) => Ok([match int {
144            -1 => OP_1NEGATE as u8,
145            0 => OP_0 as u8,
146            1..=16 => OP_1 as u8 + int as u8 - 1,
147            -0x8000_0000 => return ScriptSerializeError::InvalidInteger.into_err(),
148            _ => {
149                return serialize_push_bytes(encode_int(int).into(), false);
150            }
151        }]
152        .into()),
153        Op::PushByteArray {
154            ref array,
155            is_minimal,
156        } => serialize_push_bytes(array.clone(), is_minimal),
157    }
158}
159
160pub fn serialize_ops<'a>(ops: impl IntoIterator<Item = &'a Op>) -> Result<ByteArray> {
161    let mut byte_array: ByteArray = [].into();
162    for op in ops {
163        byte_array = byte_array.concat(serialize_op(op)?);
164    }
165    Ok(byte_array)
166}
167
168pub fn deserialize_ops(bytes: &[u8]) -> Result<Vec<Op>> {
169    use Opcode::*;
170    let mut i = 0;
171    let mut ops = Vec::new();
172    let mut cur = std::io::Cursor::new(bytes);
173    while i < bytes.len() {
174        let byte = cur.read_u8()?;
175        i += 1;
176        let push_len = match byte {
177            0 => {
178                ops.push(Op::Code(OP_0));
179                continue;
180            }
181            push_len @ 0x01..=0x4b => push_len as usize,
182            byte if byte == OP_PUSHDATA1 as u8 => {
183                i += 1;
184                cur.read_u8()? as usize
185            }
186            byte if byte == OP_PUSHDATA2 as u8 => {
187                i += 2;
188                cur.read_u16::<LittleEndian>()? as usize
189            }
190            byte if byte == OP_PUSHDATA4 as u8 => {
191                i += 4;
192                cur.read_u32::<LittleEndian>()? as usize
193            }
194            opcode => {
195                let opcode = num::FromPrimitive::from_u8(opcode)
196                    .ok_or(())
197                    .or_else(|()| ScriptSerializeError::UnknownOpcode.into_err())?;
198                ops.push(Op::Code(opcode));
199                continue;
200            }
201        };
202        let mut vec = vec![0; push_len];
203        cur.read_exact(&mut vec)?;
204        i += push_len;
205        let mut prefix = Vec::new();
206        serialize_push_prefix(&mut prefix, &vec, true)?;
207        let mut op: Op = ByteArray::new_unnamed(vec).into();
208        if prefix[0] == byte {
209            if let Op::PushByteArray { is_minimal, .. } = &mut op {
210                *is_minimal = false;
211            }
212        }
213        ops.push(op);
214    }
215    Ok(ops)
216}
217
218pub fn deserialize_ops_byte_array(byte_array: ByteArray) -> Result<Vec<Op>> {
219    use std::convert::TryInto;
220    use Opcode::*;
221    let mut ops = Vec::new();
222    let mut byte_array = Some(byte_array);
223    while byte_array.as_ref().map_or(false, |array| array.len() > 0) {
224        let (head, remainder) = byte_array.take().unwrap().split(1)?;
225        let byte = head[0];
226        let (push_len, remainder) = match byte {
227            0 => {
228                ops.push(Op::Code(OP_0));
229                byte_array = Some(remainder);
230                continue;
231            }
232            push_len @ 0x01..=0x4b => (push_len as usize, remainder),
233            byte if byte == OP_PUSHDATA1 as u8 => {
234                let (push_len, remainder) = remainder.split(1)?;
235                (push_len[0] as usize, remainder)
236            }
237            byte if byte == OP_PUSHDATA2 as u8 => {
238                let (push_len, remainder) = remainder.split(2)?;
239                (
240                    u16::from_le_bytes(push_len.as_ref().try_into().unwrap()) as usize,
241                    remainder,
242                )
243            }
244            byte if byte == OP_PUSHDATA4 as u8 => {
245                let (push_len, remainder) = remainder.split(4)?;
246                (
247                    u32::from_le_bytes(push_len.as_ref().try_into().unwrap()) as usize,
248                    remainder,
249                )
250            }
251            opcode => {
252                ops.push(
253                    num::FromPrimitive::from_u8(opcode)
254                        .map(Op::Code)
255                        .unwrap_or(Op::Invalid(opcode)),
256                );
257                byte_array = Some(remainder);
258                continue;
259            }
260        };
261        let (pushed, remainder) = remainder.split(push_len)?;
262        let mut prefix = Vec::new();
263        serialize_push_prefix(&mut prefix, &pushed, true)?;
264        let mut op: Op = pushed.into();
265        if prefix[0] == byte {
266            if let Op::PushByteArray { is_minimal, .. } = &mut op {
267                *is_minimal = false;
268            }
269        }
270        ops.push(op);
271        byte_array = Some(remainder);
272    }
273    Ok(ops)
274}
275
276impl Serialize for Script {
277    fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
278        use ser::Error;
279        serializer.serialize_bytes(
280            &serialize_ops(self.ops.iter().map(|op| &op.op))
281                .map_err(|err| S::Error::custom(err.to_string()))?,
282        )
283    }
284}
285
286struct ScriptVisitor;
287
288impl<'de> de::Visitor<'de> for ScriptVisitor {
289    type Value = Vec<TaggedOp>;
290    fn expecting(
291        &self,
292        fmt: &mut std::fmt::Formatter<'_>,
293    ) -> std::result::Result<(), std::fmt::Error> {
294        write!(fmt, "a byte array")
295    }
296
297    fn visit_bytes<E: de::Error>(self, v: &[u8]) -> std::result::Result<Self::Value, E> {
298        let ops = deserialize_ops(v).map_err(|err| E::custom(err.to_string()))?;
299        Ok(ops.into_iter().map(TaggedOp::from_op).collect())
300    }
301}
302
303impl<'de, 'a> Deserialize<'de> for Script {
304    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
305    where
306        D: Deserializer<'de>,
307    {
308        Ok(Script::new(deserializer.deserialize_bytes(ScriptVisitor)?))
309    }
310}
311
312#[cfg(test)]
313mod tests {}