sapio_miniscript/miniscript/
lex.rs1use bitcoin::blockdata::{opcodes, script};
21
22use std::fmt;
23
24use super::Error;
25
26#[derive(Debug, Copy, Clone, PartialEq, Eq)]
28#[allow(missing_docs)]
29pub enum Token<'s> {
30 BoolAnd,
31 BoolOr,
32 Add,
33 Equal,
34 NumEqual,
35 CheckSig,
36 CheckSigAdd,
37 CheckMultiSig,
38 CheckSequenceVerify,
39 CheckLockTimeVerify,
40 CheckTemplateVerify,
41 FromAltStack,
42 ToAltStack,
43 Drop,
44 Dup,
45 If,
46 IfDup,
47 NotIf,
48 Else,
49 EndIf,
50 ZeroNotEqual,
51 Size,
52 Swap,
53 Verify,
54 Ripemd160,
55 Hash160,
56 Sha256,
57 Hash256,
58 Num(u32),
59 Hash20(&'s [u8]),
60 Bytes32(&'s [u8]),
61 Bytes33(&'s [u8]),
62 Bytes65(&'s [u8]),
63}
64
65impl<'s> fmt::Display for Token<'s> {
66 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67 match *self {
68 Token::Num(n) => write!(f, "#{}", n),
69 Token::Hash20(b) | Token::Bytes33(b) | Token::Bytes32(b) | Token::Bytes65(b) => {
70 for ch in &b[..] {
71 write!(f, "{:02x}", *ch)?;
72 }
73 Ok(())
74 }
75 x => write!(f, "{:?}", x),
76 }
77 }
78}
79
80#[derive(Debug, Clone)]
81pub struct TokenIter<'s>(Vec<Token<'s>>);
84
85impl<'s> TokenIter<'s> {
86 pub fn new(v: Vec<Token<'s>>) -> TokenIter<'s> {
88 TokenIter(v)
89 }
90
91 pub fn peek(&self) -> Option<&'s Token> {
93 self.0.last()
94 }
95
96 pub fn un_next(&mut self, tok: Token<'s>) {
99 self.0.push(tok)
100 }
101
102 pub fn len(&self) -> usize {
104 self.0.len()
105 }
106}
107
108impl<'s> Iterator for TokenIter<'s> {
109 type Item = Token<'s>;
110
111 fn next(&mut self) -> Option<Token<'s>> {
112 self.0.pop()
113 }
114}
115
116pub fn lex<'s>(script: &'s script::Script) -> Result<Vec<Token<'s>>, Error> {
118 let mut ret = Vec::with_capacity(script.len());
119
120 for ins in script.instructions_minimal() {
121 match ins.map_err(Error::Script)? {
122 script::Instruction::Op(opcodes::all::OP_BOOLAND) => {
123 ret.push(Token::BoolAnd);
124 }
125 script::Instruction::Op(opcodes::all::OP_BOOLOR) => {
126 ret.push(Token::BoolOr);
127 }
128 script::Instruction::Op(opcodes::all::OP_EQUAL) => {
129 ret.push(Token::Equal);
130 }
131 script::Instruction::Op(opcodes::all::OP_EQUALVERIFY) => {
132 ret.push(Token::Equal);
133 ret.push(Token::Verify);
134 }
135 script::Instruction::Op(opcodes::all::OP_NUMEQUAL) => {
136 ret.push(Token::NumEqual);
137 }
138 script::Instruction::Op(opcodes::all::OP_NUMEQUALVERIFY) => {
139 ret.push(Token::NumEqual);
140 ret.push(Token::Verify);
141 }
142 script::Instruction::Op(opcodes::all::OP_CHECKSIG) => {
143 ret.push(Token::CheckSig);
144 }
145 script::Instruction::Op(opcodes::all::OP_CHECKSIGVERIFY) => {
146 ret.push(Token::CheckSig);
147 ret.push(Token::Verify);
148 }
149 script::Instruction::Op(opcodes::all::OP_CHECKSIGADD) => {
151 ret.push(Token::CheckSigAdd);
152 }
153 script::Instruction::Op(opcodes::all::OP_CHECKMULTISIG) => {
154 ret.push(Token::CheckMultiSig);
155 }
156 script::Instruction::Op(opcodes::all::OP_CHECKMULTISIGVERIFY) => {
157 ret.push(Token::CheckMultiSig);
158 ret.push(Token::Verify);
159 }
160 script::Instruction::Op(op) if op == opcodes::all::OP_CSV => {
161 ret.push(Token::CheckSequenceVerify);
162 }
163 script::Instruction::Op(op) if op == opcodes::all::OP_CLTV => {
164 ret.push(Token::CheckLockTimeVerify);
165 }
166 script::Instruction::Op(op) if op == opcodes::all::OP_NOP4 => {
167 ret.push(Token::CheckTemplateVerify);
168 }
169 script::Instruction::Op(opcodes::all::OP_FROMALTSTACK) => {
170 ret.push(Token::FromAltStack);
171 }
172 script::Instruction::Op(opcodes::all::OP_TOALTSTACK) => {
173 ret.push(Token::ToAltStack);
174 }
175 script::Instruction::Op(opcodes::all::OP_DROP) => {
176 ret.push(Token::Drop);
177 }
178 script::Instruction::Op(opcodes::all::OP_DUP) => {
179 ret.push(Token::Dup);
180 }
181 script::Instruction::Op(opcodes::all::OP_ADD) => {
182 ret.push(Token::Add);
183 }
184 script::Instruction::Op(opcodes::all::OP_IF) => {
185 ret.push(Token::If);
186 }
187 script::Instruction::Op(opcodes::all::OP_IFDUP) => {
188 ret.push(Token::IfDup);
189 }
190 script::Instruction::Op(opcodes::all::OP_NOTIF) => {
191 ret.push(Token::NotIf);
192 }
193 script::Instruction::Op(opcodes::all::OP_ELSE) => {
194 ret.push(Token::Else);
195 }
196 script::Instruction::Op(opcodes::all::OP_ENDIF) => {
197 ret.push(Token::EndIf);
198 }
199 script::Instruction::Op(opcodes::all::OP_0NOTEQUAL) => {
200 ret.push(Token::ZeroNotEqual);
201 }
202 script::Instruction::Op(opcodes::all::OP_SIZE) => {
203 ret.push(Token::Size);
204 }
205 script::Instruction::Op(opcodes::all::OP_SWAP) => {
206 ret.push(Token::Swap);
207 }
208 script::Instruction::Op(opcodes::all::OP_VERIFY) => {
209 match ret.last() {
210 Some(op @ &Token::Equal)
211 | Some(op @ &Token::CheckSig)
212 | Some(op @ &Token::CheckMultiSig) => {
213 return Err(Error::NonMinimalVerify(String::from(format!("{:?}", op))))
214 }
215 _ => {}
216 }
217 ret.push(Token::Verify);
218 }
219 script::Instruction::Op(opcodes::all::OP_RIPEMD160) => {
220 ret.push(Token::Ripemd160);
221 }
222 script::Instruction::Op(opcodes::all::OP_HASH160) => {
223 ret.push(Token::Hash160);
224 }
225 script::Instruction::Op(opcodes::all::OP_SHA256) => {
226 ret.push(Token::Sha256);
227 }
228 script::Instruction::Op(opcodes::all::OP_HASH256) => {
229 ret.push(Token::Hash256);
230 }
231 script::Instruction::PushBytes(bytes) => {
232 match bytes.len() {
233 20 => ret.push(Token::Hash20(&bytes)),
234 32 => ret.push(Token::Bytes32(&bytes)),
235 33 => ret.push(Token::Bytes33(&bytes)),
236 65 => ret.push(Token::Bytes65(&bytes)),
237 _ => {
238 match script::read_scriptint(bytes) {
239 Ok(v) if v >= 0 => {
240 if &script::Builder::new().push_int(v).into_script()[1..] != bytes {
242 return Err(Error::InvalidPush(bytes.to_owned()));
243 }
244 ret.push(Token::Num(v as u32));
245 }
246 Ok(_) => return Err(Error::InvalidPush(bytes.to_owned())),
247 Err(e) => return Err(Error::Script(e)),
248 }
249 }
250 }
251 }
252 script::Instruction::Op(opcodes::all::OP_PUSHBYTES_0) => {
253 ret.push(Token::Num(0));
254 }
255 script::Instruction::Op(opcodes::all::OP_PUSHNUM_1) => {
256 ret.push(Token::Num(1));
257 }
258 script::Instruction::Op(opcodes::all::OP_PUSHNUM_2) => {
259 ret.push(Token::Num(2));
260 }
261 script::Instruction::Op(opcodes::all::OP_PUSHNUM_3) => {
262 ret.push(Token::Num(3));
263 }
264 script::Instruction::Op(opcodes::all::OP_PUSHNUM_4) => {
265 ret.push(Token::Num(4));
266 }
267 script::Instruction::Op(opcodes::all::OP_PUSHNUM_5) => {
268 ret.push(Token::Num(5));
269 }
270 script::Instruction::Op(opcodes::all::OP_PUSHNUM_6) => {
271 ret.push(Token::Num(6));
272 }
273 script::Instruction::Op(opcodes::all::OP_PUSHNUM_7) => {
274 ret.push(Token::Num(7));
275 }
276 script::Instruction::Op(opcodes::all::OP_PUSHNUM_8) => {
277 ret.push(Token::Num(8));
278 }
279 script::Instruction::Op(opcodes::all::OP_PUSHNUM_9) => {
280 ret.push(Token::Num(9));
281 }
282 script::Instruction::Op(opcodes::all::OP_PUSHNUM_10) => {
283 ret.push(Token::Num(10));
284 }
285 script::Instruction::Op(opcodes::all::OP_PUSHNUM_11) => {
286 ret.push(Token::Num(11));
287 }
288 script::Instruction::Op(opcodes::all::OP_PUSHNUM_12) => {
289 ret.push(Token::Num(12));
290 }
291 script::Instruction::Op(opcodes::all::OP_PUSHNUM_13) => {
292 ret.push(Token::Num(13));
293 }
294 script::Instruction::Op(opcodes::all::OP_PUSHNUM_14) => {
295 ret.push(Token::Num(14));
296 }
297 script::Instruction::Op(opcodes::all::OP_PUSHNUM_15) => {
298 ret.push(Token::Num(15));
299 }
300 script::Instruction::Op(opcodes::all::OP_PUSHNUM_16) => {
301 ret.push(Token::Num(16));
302 }
303 script::Instruction::Op(op) => return Err(Error::InvalidOpcode(op)),
304 };
305 }
306 Ok(ret)
307}