@@ -23,7 +23,7 @@ use elements::{opcodes, script};
23
23
use std:: fmt;
24
24
25
25
use super :: Error ;
26
- use util:: slice_to_u32_le;
26
+ use util:: { build_scriptint , slice_to_u32_le} ;
27
27
/// Atom of a tokenized version of a script
28
28
#[ derive( Debug , Clone , PartialEq , Eq ) ]
29
29
#[ allow( missing_docs) ]
@@ -65,8 +65,10 @@ pub enum Token {
65
65
Hash20 ( [ u8 ; 20 ] ) ,
66
66
Hash32 ( [ u8 ; 32 ] ) ,
67
67
Pubkey ( PublicKey ) ,
68
- Push4 ( u32 ) ,
69
- Push ( Vec < u8 > ) , // <pref> <swap> <cat> /* prefix is catted */
68
+ Push ( Vec < u8 > ) , // Num or a
69
+ PickPush4 ( u32 ) , // Pick followed by a 4 byte push
70
+ PickPush32 ( [ u8 ; 32 ] ) , // Pick followed by a 32 byte push
71
+ PickPush ( Vec < u8 > ) , // Pick followed by a push
70
72
}
71
73
72
74
impl fmt:: Display for Token {
@@ -131,6 +133,23 @@ impl Iterator for TokenIter {
131
133
pub fn lex ( script : & script:: Script ) -> Result < Vec < Token > , Error > {
132
134
let mut ret = Vec :: with_capacity ( script. len ( ) ) ;
133
135
136
+ fn process_candidate_push ( ret : & mut Vec < Token > ) -> Result < ( ) , Error > {
137
+ let ret_len = ret. len ( ) ;
138
+
139
+ if ret_len < 2 || ret[ ret_len - 1 ] != Token :: Swap {
140
+ return Ok ( ( ) ) ;
141
+ }
142
+ let token = match & ret[ ret_len - 2 ] {
143
+ Token :: Hash20 ( x) => Token :: Push ( x. to_vec ( ) ) ,
144
+ Token :: Hash32 ( x) => Token :: Push ( x. to_vec ( ) ) ,
145
+ Token :: Pubkey ( pk) => Token :: Push ( pk. to_bytes ( ) ) ,
146
+ Token :: Num ( k) => Token :: Push ( build_scriptint ( * k as i64 ) ) ,
147
+ _x => return Ok ( ( ) ) , // no change required
148
+ } ;
149
+ ret[ ret_len - 2 ] = token;
150
+ Ok ( ( ) )
151
+ }
152
+
134
153
for ins in script. instructions_minimal ( ) {
135
154
match ins. map_err ( Error :: Script ) ? {
136
155
script:: Instruction :: Op ( opcodes:: all:: OP_BOOLAND ) => {
@@ -179,6 +198,7 @@ pub fn lex(script: &script::Script) -> Result<Vec<Token>, Error> {
179
198
ret. push ( Token :: Left ) ;
180
199
}
181
200
script:: Instruction :: Op ( opcodes:: all:: OP_CAT ) => {
201
+ process_candidate_push ( & mut ret) ?;
182
202
ret. push ( Token :: Cat ) ;
183
203
}
184
204
script:: Instruction :: Op ( opcodes:: all:: OP_CODESEPARATOR ) => {
@@ -253,36 +273,41 @@ pub fn lex(script: &script::Script) -> Result<Vec<Token>, Error> {
253
273
ret. push ( Token :: Hash256 ) ;
254
274
}
255
275
script:: Instruction :: PushBytes ( bytes) => {
256
- // Check for Push
257
- let ret_len = ret. len ( ) ;
258
- // See that last five elements are CAT
259
- // Checking only two here
260
- if ret_len >= 5
261
- && ret. last ( ) == Some ( & Token :: Cat )
262
- && ret. get ( ret_len - 2 ) == Some ( & Token :: Cat )
263
- {
264
- ret. push ( Token :: Push ( bytes. to_owned ( ) ) ) ;
265
- }
276
+ // Check for Pick Push
266
277
// Special handling of tokens for Covenants
267
278
// To determine whether some Token is actually
268
279
// 4 bytes push or a script int of 4 bytes,
269
280
// we need additional script context
270
- else if ret. last ( ) == Some ( & Token :: Pick ) {
281
+ if ret. last ( ) == Some ( & Token :: Pick ) {
282
+ ret. pop ( ) . unwrap ( ) ;
271
283
match bytes. len ( ) {
272
- 4 => ret. push ( Token :: Push4 ( slice_to_u32_le ( bytes) ) ) ,
284
+ // All other sighash elements are 32 bytes. And the script code
285
+ // is 24 bytes
286
+ 4 => ret. push ( Token :: PickPush4 ( slice_to_u32_le ( bytes) ) ) ,
287
+ 32 => {
288
+ let mut x = [ 0u8 ; 32 ] ;
289
+ x. copy_from_slice ( bytes) ;
290
+ ret. push ( Token :: PickPush32 ( x) ) ;
291
+ }
292
+ // Other pushes should be err. This will change
293
+ // once we add script introspection
273
294
_ => return Err ( Error :: InvalidPush ( bytes. to_owned ( ) ) ) ,
274
295
}
275
296
} else {
297
+ // Create the most specific type possible out of the
298
+ // Push. When we later encounter CAT, revisit and
299
+ // reconvert these to pushes.
300
+ // See [process_candidate_push]
276
301
match bytes. len ( ) {
277
302
20 => {
278
303
let mut x = [ 0 ; 20 ] ;
279
304
x. copy_from_slice ( bytes) ;
280
- ret. push ( Token :: Hash20 ( x) )
305
+ ret. push ( Token :: Hash20 ( x) ) ;
281
306
}
282
307
32 => {
283
308
let mut x = [ 0 ; 32 ] ;
284
309
x. copy_from_slice ( bytes) ;
285
- ret. push ( Token :: Hash32 ( x) )
310
+ ret. push ( Token :: Hash32 ( x) ) ;
286
311
}
287
312
33 | 65 => {
288
313
ret. push ( Token :: Pubkey (
@@ -300,8 +325,7 @@ pub fn lex(script: &script::Script) -> Result<Vec<Token>, Error> {
300
325
}
301
326
ret. push ( Token :: Num ( v as u32 ) ) ;
302
327
}
303
- Ok ( _) => return Err ( Error :: InvalidPush ( bytes. to_owned ( ) ) ) ,
304
- Err ( e) => return Err ( Error :: Script ( e) ) ,
328
+ _ => ret. push ( Token :: Push ( bytes. to_owned ( ) ) ) ,
305
329
}
306
330
}
307
331
}
0 commit comments