bsv_script/interpreter/
parsed_opcode.rs1use super::error::{InterpreterError, InterpreterErrorCode};
4use crate::opcodes::*;
5use crate::Script;
6
7#[derive(Debug, Clone)]
9pub struct ParsedOpcode {
10 pub opcode: u8,
12 pub data: Vec<u8>,
14}
15
16impl ParsedOpcode {
17 pub fn name(&self) -> &'static str {
19 crate::opcodes::opcode_to_string(self.opcode)
20 }
21
22 pub fn is_disabled(&self) -> bool {
24 matches!(self.opcode, OP_2MUL | OP_2DIV)
25 }
26
27 pub fn always_illegal(&self) -> bool {
29 matches!(self.opcode, OP_VERIF | OP_VERNOTIF)
30 }
31
32 pub fn is_conditional(&self) -> bool {
34 matches!(
35 self.opcode,
36 OP_IF | OP_NOTIF | OP_ELSE | OP_ENDIF | OP_VERIF | OP_VERNOTIF
37 )
38 }
39
40 pub fn requires_tx(&self) -> bool {
42 matches!(
43 self.opcode,
44 OP_CHECKSIG
45 | OP_CHECKSIGVERIFY
46 | OP_CHECKMULTISIG
47 | OP_CHECKMULTISIGVERIFY
48 | OP_CHECKSEQUENCEVERIFY
49 )
50 }
51
52 pub fn enforce_minimum_data_push(&self) -> Result<(), InterpreterError> {
54 let data_len = self.data.len();
55 if data_len == 0 && self.opcode != OP_0 {
56 return Err(InterpreterError::new(
57 InterpreterErrorCode::MinimalData,
58 format!(
59 "zero length data push is encoded with opcode {} instead of OP_0",
60 self.name()
61 ),
62 ));
63 }
64 if data_len == 1
65 && (1..=16).contains(&self.data[0])
66 && self.opcode != OP_1 + self.data[0] - 1
67 {
68 return Err(InterpreterError::new(
69 InterpreterErrorCode::MinimalData,
70 format!(
71 "data push of the value {} encoded with opcode {} instead of OP_{}",
72 self.data[0],
73 self.name(),
74 self.data[0]
75 ),
76 ));
77 }
78 if data_len == 1 && self.data[0] == 0x81 && self.opcode != OP_1NEGATE {
79 return Err(InterpreterError::new(
80 InterpreterErrorCode::MinimalData,
81 format!(
82 "data push of the value -1 encoded with opcode {} instead of OP_1NEGATE",
83 self.name()
84 ),
85 ));
86 }
87 if data_len <= 75 {
88 if self.opcode as usize != data_len {
89 return Err(InterpreterError::new(
90 InterpreterErrorCode::MinimalData,
91 format!(
92 "data push of {} bytes encoded with opcode {} instead of OP_DATA_{}",
93 data_len,
94 self.name(),
95 data_len
96 ),
97 ));
98 }
99 } else if data_len <= 255 {
100 if self.opcode != OP_PUSHDATA1 {
101 return Err(InterpreterError::new(
102 InterpreterErrorCode::MinimalData,
103 format!(
104 "data push of {} bytes encoded with opcode {} instead of OP_PUSHDATA1",
105 data_len,
106 self.name()
107 ),
108 ));
109 }
110 } else if data_len <= 65535 && self.opcode != OP_PUSHDATA2 {
111 return Err(InterpreterError::new(
112 InterpreterErrorCode::MinimalData,
113 format!(
114 "data push of {} bytes encoded with opcode {} instead of OP_PUSHDATA2",
115 data_len,
116 self.name()
117 ),
118 ));
119 }
120 Ok(())
121 }
122
123 pub fn canonical_push(&self) -> bool {
125 let opcode = self.opcode;
126 let data = &self.data;
127 let data_len = data.len();
128 if opcode > OP_16 {
129 return true;
130 }
131 if opcode < OP_PUSHDATA1 && opcode > OP_0 && data_len == 1 && data[0] <= 16 {
132 return false;
133 }
134 if opcode == OP_PUSHDATA1 && data_len < OP_PUSHDATA1 as usize {
135 return false;
136 }
137 if opcode == OP_PUSHDATA2 && data_len <= 0xff {
138 return false;
139 }
140 if opcode == OP_PUSHDATA4 && data_len <= 0xffff {
141 return false;
142 }
143 true
144 }
145
146 pub fn to_bytes(&self) -> Vec<u8> {
148 let mut out = vec![self.opcode];
149 if self.opcode == 0
150 || (self.opcode >= OP_1NEGATE && self.opcode <= OP_16)
151 || self.opcode > OP_PUSHDATA4
152 {
153 if self.opcode == OP_RETURN && !self.data.is_empty() {
155 out.extend_from_slice(&self.data);
156 }
157 return out;
158 }
159 match self.opcode {
161 OP_PUSHDATA1 => {
162 out.push(self.data.len() as u8);
163 out.extend_from_slice(&self.data);
164 }
165 OP_PUSHDATA2 => {
166 out.extend_from_slice(&(self.data.len() as u16).to_le_bytes());
167 out.extend_from_slice(&self.data);
168 }
169 OP_PUSHDATA4 => {
170 out.extend_from_slice(&(self.data.len() as u32).to_le_bytes());
171 out.extend_from_slice(&self.data);
172 }
173 _ => {
174 out.extend_from_slice(&self.data);
176 }
177 }
178 out
179 }
180}
181
182pub type ParsedScript = Vec<ParsedOpcode>;
184
185pub fn is_push_only(script: &ParsedScript) -> bool {
187 script.iter().all(|op| op.opcode <= OP_16)
188}
189
190pub fn remove_opcode_by_data(script: &ParsedScript, data: &[u8]) -> ParsedScript {
192 script
193 .iter()
194 .filter(|pop| !pop.canonical_push() || !pop.data.windows(data.len()).any(|w| w == data))
195 .cloned()
196 .collect()
197}
198
199pub fn remove_opcode(script: &ParsedScript, opcode: u8) -> ParsedScript {
201 script
202 .iter()
203 .filter(|pop| pop.opcode != opcode)
204 .cloned()
205 .collect()
206}
207
208pub fn unparse(pscript: &ParsedScript) -> Script {
210 let mut bytes = Vec::new();
211 for pop in pscript {
212 bytes.extend_from_slice(&pop.to_bytes());
213 }
214 Script::from_bytes(&bytes)
215}
216
217pub fn parse_script(
221 script: &Script,
222 error_on_checksig: bool,
223) -> Result<ParsedScript, InterpreterError> {
224 let scr = script.to_bytes();
225 let mut parsed_ops = Vec::new();
226 let mut conditional_depth = 0i32;
227 let mut i = 0;
228
229 while i < scr.len() {
230 let instruction = scr[i];
231 let mut parsed_op = ParsedOpcode {
232 opcode: instruction,
233 data: Vec::new(),
234 };
235
236 if error_on_checksig && parsed_op.requires_tx() {
237 return Err(InterpreterError::new(
238 InterpreterErrorCode::InvalidParams,
239 "tx and previous output must be supplied for checksig".to_string(),
240 ));
241 }
242
243 match instruction {
245 OP_IF | OP_NOTIF | OP_VERIF | OP_VERNOTIF => conditional_depth += 1,
246 OP_ENDIF => {
247 if conditional_depth > 0 {
248 conditional_depth -= 1;
249 }
250 }
251 OP_RETURN if conditional_depth == 0 => {
252 if i + 1 < scr.len() {
254 parsed_op.data = scr[i + 1..].to_vec();
255 }
256 parsed_ops.push(parsed_op);
257 return Ok(parsed_ops);
258 }
259 _ => {}
260 }
261
262 match instruction {
264 OP_PUSHDATA1 => {
265 if i + 1 >= scr.len() {
266 return Err(InterpreterError::new(
267 InterpreterErrorCode::MalformedPush,
268 "script truncated".to_string(),
269 ));
270 }
271 let data_len = scr[i + 1] as usize;
272 if i + 2 + data_len > scr.len() {
273 return Err(InterpreterError::new(
274 InterpreterErrorCode::MalformedPush,
275 "push data exceeds script length".to_string(),
276 ));
277 }
278 parsed_op.data = scr[i + 2..i + 2 + data_len].to_vec();
279 i += 2 + data_len;
280 }
281 OP_PUSHDATA2 => {
282 if i + 2 >= scr.len() {
283 return Err(InterpreterError::new(
284 InterpreterErrorCode::MalformedPush,
285 "script truncated".to_string(),
286 ));
287 }
288 let data_len = u16::from_le_bytes([scr[i + 1], scr[i + 2]]) as usize;
289 if i + 3 + data_len > scr.len() {
290 return Err(InterpreterError::new(
291 InterpreterErrorCode::MalformedPush,
292 "push data exceeds script length".to_string(),
293 ));
294 }
295 parsed_op.data = scr[i + 3..i + 3 + data_len].to_vec();
296 i += 3 + data_len;
297 }
298 OP_PUSHDATA4 => {
299 if i + 4 >= scr.len() {
300 return Err(InterpreterError::new(
301 InterpreterErrorCode::MalformedPush,
302 "script truncated".to_string(),
303 ));
304 }
305 let data_len =
306 u32::from_le_bytes([scr[i + 1], scr[i + 2], scr[i + 3], scr[i + 4]]) as usize;
307 if i + 5 + data_len > scr.len() {
308 return Err(InterpreterError::new(
309 InterpreterErrorCode::MalformedPush,
310 "push data exceeds script length".to_string(),
311 ));
312 }
313 parsed_op.data = scr[i + 5..i + 5 + data_len].to_vec();
314 i += 5 + data_len;
315 }
316 op if op >= OP_DATA_1 && op <= OP_DATA_75 => {
317 let data_len = op as usize;
318 if i + 1 + data_len > scr.len() {
319 return Err(InterpreterError::new(
320 InterpreterErrorCode::MalformedPush,
321 "script truncated".to_string(),
322 ));
323 }
324 parsed_op.data = scr[i + 1..i + 1 + data_len].to_vec();
325 i += 1 + data_len;
326 }
327 _ => {
328 i += 1;
330 }
331 }
332
333 parsed_ops.push(parsed_op);
334 }
335
336 Ok(parsed_ops)
337}