cs_mwc_bch/script/
mod.rs

1//! Script opcodes and interpreter
2//!
3//! # Examples
4//!
5//! Evaluate a script that divides two numbers:
6//!
7//! ```rust
8//! use bch::script::op_codes::*;
9//! use bch::script::{Script, TransactionlessChecker};
10//!
11//! let mut script = Script::new();
12//! script.append(OP_10);
13//! script.append(OP_5);
14//! script.append(OP_DIV);
15//!
16//! script.eval(&mut TransactionlessChecker {}).unwrap();
17//! ```
18
19use hex;
20use script::op_codes::*;
21use std::fmt;
22use util::Result;
23
24mod checker;
25mod interpreter;
26#[allow(dead_code)]
27pub mod op_codes;
28mod stack;
29
30pub use self::checker::{Checker, TransactionChecker, TransactionlessChecker};
31pub(crate) use self::interpreter::next_op;
32
33/// Maximum number of bytes pushable to the stack
34pub const MAX_SCRIPT_ELEMENT_SIZE: usize = 520;
35
36/// Maximum number of multisig keys
37pub const MAX_PUBKEYS_PER_MULTISIG: usize = 20;
38
39/// Maximum number of non-push operations per script
40pub const MAX_OPS_PER_SCRIPT: usize = 500;
41
42/// Maximum script length in bytes
43pub const MAX_SCRIPT_SIZE: usize = 10000;
44
45/// Transaction script
46#[derive(Default, Clone, PartialEq, Eq, Hash)]
47pub struct Script(pub Vec<u8>);
48
49impl Script {
50    /// Creates a new empty script
51    pub fn new() -> Script {
52        Script(vec![])
53    }
54
55    /// Appends a single opcode or data byte
56    pub fn append(&mut self, byte: u8) {
57        self.0.push(byte);
58    }
59
60    /// Appends a slice of data
61    pub fn append_slice(&mut self, slice: &[u8]) {
62        self.0.extend_from_slice(slice);
63    }
64
65    /// Appends the opcodes and provided data that push it onto the stack
66    pub fn append_data(&mut self, data: &[u8]) {
67        let len = data.len();
68        match len {
69            0 => self.0.push(op_codes::OP_0),
70            1..=75 => {
71                self.0.push(op_codes::OP_PUSH + len as u8);
72                self.0.extend_from_slice(data);
73            }
74            76..=255 => {
75                self.0.push(op_codes::OP_PUSHDATA1);
76                self.0.push(len as u8);
77                self.0.extend_from_slice(data);
78            }
79            256..=65535 => {
80                self.0.push(op_codes::OP_PUSHDATA2);
81                self.0.push((len >> 0) as u8);
82                self.0.push((len >> 8) as u8);
83                self.0.extend_from_slice(data);
84            }
85            _ => {
86                self.0.push(op_codes::OP_PUSHDATA4);
87                self.0.push((len >> 0) as u8);
88                self.0.push((len >> 8) as u8);
89                self.0.push((len >> 16) as u8);
90                self.0.push((len >> 24) as u8);
91                self.0.extend_from_slice(data);
92            }
93        }
94    }
95
96    /// Appends the opcodes to push a number to the stack
97    ///
98    /// The number must be in the range [2^-31+1,2^31-1].
99    pub fn append_num(&mut self, n: i32) -> Result<()> {
100        self.append_data(&stack::encode_num(n as i64)?);
101        Ok(())
102    }
103
104    /// Evaluates a script using the provided checker
105    pub fn eval<T: Checker>(&self, checker: &mut T) -> Result<()> {
106        self::interpreter::eval(&self.0, checker)
107    }
108}
109
110impl fmt::Debug for Script {
111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112        let script = &self.0;
113        let mut ret = String::new();
114        let mut i = 0;
115        ret.push_str("[");
116        while i < script.len() {
117            if i != 0 {
118                ret.push_str(" ")
119            }
120            match script[i] {
121                OP_0 => ret.push_str("OP_0"),
122                OP_1NEGATE => ret.push_str("OP_1NEGATE"),
123                OP_1 => ret.push_str("OP_1"),
124                OP_2 => ret.push_str("OP_2"),
125                OP_3 => ret.push_str("OP_3"),
126                OP_4 => ret.push_str("OP_4"),
127                OP_5 => ret.push_str("OP_5"),
128                OP_6 => ret.push_str("OP_6"),
129                OP_7 => ret.push_str("OP_7"),
130                OP_8 => ret.push_str("OP_8"),
131                OP_9 => ret.push_str("OP_9"),
132                OP_10 => ret.push_str("OP_10"),
133                OP_11 => ret.push_str("OP_11"),
134                OP_12 => ret.push_str("OP_12"),
135                OP_13 => ret.push_str("OP_13"),
136                OP_14 => ret.push_str("OP_14"),
137                OP_15 => ret.push_str("OP_15"),
138                OP_16 => ret.push_str("OP_16"),
139                len @ 1..=75 => {
140                    ret.push_str(&format!("OP_PUSH+{} ", len));
141                    if i + 1 + len as usize <= script.len() {
142                        ret.push_str(&hex::encode(&script[i + 1..i + 1 + len as usize]));
143                    } else {
144                        break;
145                    }
146                }
147                OP_PUSHDATA1 => {
148                    ret.push_str("OP_PUSHDATA1 ");
149                    if i + 2 <= script.len() {
150                        let len = script[i + 1] as usize;
151                        ret.push_str(&format!("{} ", len));
152                        if i + 2 + len <= script.len() {
153                            ret.push_str(&hex::encode(&script[i + 2..i + 2 + len]));
154                        } else {
155                            break;
156                        }
157                    } else {
158                        break;
159                    }
160                }
161                OP_PUSHDATA2 => {
162                    ret.push_str("OP_PUSHDATA2 ");
163                    if i + 3 <= script.len() {
164                        let len = ((script[i + 1] as usize) << 0) + ((script[i + 2] as usize) << 8);
165                        ret.push_str(&format!("{} ", len));
166                        if i + 3 + len <= script.len() {
167                            ret.push_str(&hex::encode(&script[i + 3..i + 3 + len]));
168                        } else {
169                            break;
170                        }
171                    } else {
172                        break;
173                    }
174                }
175                OP_PUSHDATA4 => {
176                    ret.push_str("OP_PUSHDATA4 ");
177                    if i + 5 <= script.len() {
178                        let len = ((script[i + 1] as usize) << 0)
179                            + ((script[i + 2] as usize) << 8)
180                            + ((script[i + 3] as usize) << 16)
181                            + ((script[i + 4] as usize) << 24);
182                        ret.push_str(&format!("{} ", len));
183                        if i + 5 + len <= script.len() {
184                            ret.push_str(&hex::encode(&script[i..i + len]));
185                        } else {
186                            break;
187                        }
188                    } else {
189                        break;
190                    }
191                }
192                OP_NOP => ret.push_str("OP_NOP"),
193                OP_IF => ret.push_str("OP_IF"),
194                OP_NOTIF => ret.push_str("OP_NOTIF"),
195                OP_ELSE => ret.push_str("OP_ELSE"),
196                OP_ENDIF => ret.push_str("OP_ENDIF"),
197                OP_VERIFY => ret.push_str("OP_VERIFY"),
198                OP_RETURN => ret.push_str("OP_RETURN"),
199                OP_TOALTSTACK => ret.push_str("OP_TOALTSTACK"),
200                OP_FROMALTSTACK => ret.push_str("OP_FROMALTSTACK"),
201                OP_IFDUP => ret.push_str("OP_IFDUP"),
202                OP_DEPTH => ret.push_str("OP_DEPTH"),
203                OP_DROP => ret.push_str("OP_DROP"),
204                OP_DUP => ret.push_str("OP_DUP"),
205                OP_NIP => ret.push_str("OP_NIP"),
206                OP_OVER => ret.push_str("OP_OVER"),
207                OP_PICK => ret.push_str("OP_PICK"),
208                OP_ROLL => ret.push_str("OP_ROLL"),
209                OP_ROT => ret.push_str("OP_ROT"),
210                OP_SWAP => ret.push_str("OP_SWAP"),
211                OP_TUCK => ret.push_str("OP_TUCK"),
212                OP_2DROP => ret.push_str("OP_2DROP"),
213                OP_2DUP => ret.push_str("OP_2DUP"),
214                OP_3DUP => ret.push_str("OP_3DUP"),
215                OP_2OVER => ret.push_str("OP_2OVER"),
216                OP_2ROT => ret.push_str("OP_2ROT"),
217                OP_2SWAP => ret.push_str("OP_2SWAP"),
218                OP_CAT => ret.push_str("OP_CAT"),
219                OP_SPLIT => ret.push_str("OP_SPLIT"),
220                OP_SIZE => ret.push_str("OP_SIZE"),
221                OP_AND => ret.push_str("OP_AND"),
222                OP_OR => ret.push_str("OP_OR"),
223                OP_XOR => ret.push_str("OP_XOR"),
224                OP_EQUAL => ret.push_str("OP_EQUAL"),
225                OP_EQUALVERIFY => ret.push_str("OP_EQUALVERIFY"),
226                OP_1ADD => ret.push_str("OP_1ADD"),
227                OP_1SUB => ret.push_str("OP_1SUB"),
228                OP_NEGATE => ret.push_str("OP_NEGATE"),
229                OP_ABS => ret.push_str("OP_ABS"),
230                OP_NOT => ret.push_str("OP_NOT"),
231                OP_0NOTEQUAL => ret.push_str("OP_0NOTEQUAL"),
232                OP_ADD => ret.push_str("OP_ADD"),
233                OP_SUB => ret.push_str("OP_SUB"),
234                OP_DIV => ret.push_str("OP_DIV"),
235                OP_MOD => ret.push_str("OP_MOD"),
236                OP_BOOLAND => ret.push_str("OP_BOOLAND"),
237                OP_BOOLOR => ret.push_str("OP_BOOLOR"),
238                OP_NUMEQUAL => ret.push_str("OP_NUMEQUAL"),
239                OP_NUMEQUALVERIFY => ret.push_str("OP_NUMEQUALVERIFY"),
240                OP_NUMNOTEQUAL => ret.push_str("OP_NUMNOTEQUAL"),
241                OP_LESSTHAN => ret.push_str("OP_LESSTHAN"),
242                OP_GREATERTHAN => ret.push_str("OP_GREATERTHAN"),
243                OP_LESSTHANOREQUAL => ret.push_str("OP_LESSTHANOREQUAL"),
244                OP_GREATERTHANOREQUAL => ret.push_str("OP_GREATERTHANOREQUAL"),
245                OP_MIN => ret.push_str("OP_MIN"),
246                OP_MAX => ret.push_str("OP_MAX"),
247                OP_WITHIN => ret.push_str("OP_WITHIN"),
248                OP_NUM2BIN => ret.push_str("OP_NUM2BIN"),
249                OP_BIN2NUM => ret.push_str("OP_BIN2NUM"),
250                OP_RIPEMD160 => ret.push_str("OP_RIPEMD160"),
251                OP_SHA1 => ret.push_str("OP_SHA1"),
252                OP_SHA256 => ret.push_str("OP_SHA256"),
253                OP_HASH160 => ret.push_str("OP_HASH160"),
254                OP_HASH256 => ret.push_str("OP_HASH256"),
255                OP_CODESEPARATOR => ret.push_str("OP_CODESEPARATOR"),
256                OP_CHECKSIG => ret.push_str("OP_CHECKSIG"),
257                OP_CHECKSIGVERIFY => ret.push_str("OP_CHECKSIGVERIFY"),
258                OP_CHECKMULTISIG => ret.push_str("OP_CHECKMULTISIG"),
259                OP_CHECKMULTISIGVERIFY => ret.push_str("OP_CHECKMULTISIGVERIFY"),
260                OP_CHECKLOCKTIMEVERIFY => ret.push_str("OP_CHECKLOCKTIMEVERIFY"),
261                OP_CHECKSEQUENCEVERIFY => ret.push_str("OP_CHECKSEQUENCEVERIFY"),
262                _ => ret.push_str(&format!("{}", script[i])),
263            }
264            i = next_op(i, script);
265        }
266
267        // Add whatever is remaining if we exited early
268        if i < script.len() {
269            for j in i..script.len() {
270                ret.push_str(&format!(" {}", script[j]));
271            }
272        }
273        ret.push_str("]");
274        f.write_str(&ret)
275    }
276}
277
278#[cfg(test)]
279mod tests {
280    use super::op_codes::*;
281    use super::*;
282
283    #[test]
284    fn append_data() {
285        let mut s = Script::new();
286        s.append_data(&vec![]);
287        assert!(s.0.len() == 1);
288
289        let mut s = Script::new();
290        s.append_data(&vec![0; 1]);
291        assert!(s.0[0] == OP_PUSH + 1 && s.0.len() == 2);
292
293        let mut s = Script::new();
294        s.append_data(&vec![0; 75]);
295        assert!(s.0[0] == OP_PUSH + 75 && s.0.len() == 76);
296
297        let mut s = Script::new();
298        s.append_data(&vec![0; 76]);
299        assert!(s.0[0] == OP_PUSHDATA1 && s.0[1] == 76 && s.0.len() == 78);
300
301        let mut s = Script::new();
302        s.append_data(&vec![0; 255]);
303        assert!(s.0[0] == OP_PUSHDATA1 && s.0[1] == 255 && s.0.len() == 257);
304
305        let mut s = Script::new();
306        s.append_data(&vec![0; 256]);
307        assert!(s.0[0] == OP_PUSHDATA2 && s.0[1] == 0 && s.0[2] == 1 && s.0.len() == 259);
308
309        let mut s = Script::new();
310        s.append_data(&vec![0; 65535]);
311        assert!(s.0[0] == OP_PUSHDATA2 && s.0[1] == 255 && s.0[2] == 255 && s.0.len() == 65538);
312
313        let mut s = Script::new();
314        s.append_data(&vec![0; 65536]);
315        assert!(s.0[0] == OP_PUSHDATA4 && s.0[1] == 0 && s.0[2] == 0 && s.0[3] == 1);
316        assert!(s.0.len() == 65541);
317    }
318}