11use scriptful:: {
2- core:: Script ,
3- prelude:: { Machine , Stack } ,
2+ core:: { Script , ScriptRef } ,
3+ prelude:: Stack ,
44} ;
55use serde:: { Deserialize , Serialize } ;
66
@@ -19,6 +19,12 @@ pub enum MyOperator {
1919 Equal ,
2020 Hash160 ,
2121 CheckMultiSig ,
22+ /// Stop script execution if top-most element of stack is not "true"
23+ Verify ,
24+ // Control flow
25+ If ,
26+ Else ,
27+ EndIf ,
2228}
2329
2430#[ derive( Clone , Debug , PartialEq , Deserialize , Serialize ) ]
@@ -137,11 +143,158 @@ fn check_multi_sig(bytes_pkhs: Vec<MyValue>, bytes_keyed_signatures: Vec<MyValue
137143}
138144
139145// An operator system decides what to do with the stack when each operator is applied on it.
140- fn my_operator_system ( stack : & mut Stack < MyValue > , operator : & MyOperator ) {
146+ fn my_operator_system (
147+ stack : & mut Stack < MyValue > ,
148+ operator : & MyOperator ,
149+ if_stack : & mut ConditionStack ,
150+ ) -> MyControlFlow {
151+ if !if_stack. all_true ( ) {
152+ match operator {
153+ MyOperator :: If => {
154+ if_stack. push_back ( false ) ;
155+ }
156+ MyOperator :: Else => {
157+ if let Err ( ( ) ) = if_stack. toggle_top ( ) {
158+ stack. push ( MyValue :: Boolean ( false ) ) ;
159+ return MyControlFlow :: Break ;
160+ }
161+ }
162+ MyOperator :: EndIf => {
163+ if if_stack. pop_back ( ) . is_err ( ) {
164+ stack. push ( MyValue :: Boolean ( false ) ) ;
165+ return MyControlFlow :: Break ;
166+ }
167+ }
168+ _ => { }
169+ }
170+
171+ return MyControlFlow :: Continue ;
172+ }
173+
141174 match operator {
142175 MyOperator :: Equal => equal_operator ( stack) ,
143176 MyOperator :: Hash160 => hash_160_operator ( stack) ,
144177 MyOperator :: CheckMultiSig => check_multisig_operator ( stack) ,
178+ MyOperator :: Verify => {
179+ let top = stack. pop ( ) ;
180+ if top != MyValue :: Boolean ( true ) {
181+ // Push the element back because there is a check in execute_script that needs a
182+ // false value to mark the script execution as failed, otherwise it may be marked as
183+ // success
184+ stack. push ( top) ;
185+ return MyControlFlow :: Break ;
186+ }
187+ }
188+ MyOperator :: If => {
189+ let top = stack. pop ( ) ;
190+ if let MyValue :: Boolean ( bool) = top {
191+ if_stack. push_back ( bool) ;
192+ } else {
193+ stack. push ( MyValue :: Boolean ( false ) ) ;
194+ return MyControlFlow :: Break ;
195+ }
196+ }
197+ MyOperator :: Else => {
198+ if let Err ( ( ) ) = if_stack. toggle_top ( ) {
199+ stack. push ( MyValue :: Boolean ( false ) ) ;
200+ return MyControlFlow :: Break ;
201+ }
202+ }
203+ MyOperator :: EndIf => {
204+ if if_stack. pop_back ( ) . is_err ( ) {
205+ stack. push ( MyValue :: Boolean ( false ) ) ;
206+ return MyControlFlow :: Break ;
207+ }
208+ }
209+ }
210+
211+ MyControlFlow :: Continue
212+ }
213+
214+ // ConditionStack implementation from bitcoin-core
215+ // https://github.com/bitcoin/bitcoin/blob/505ba3966562b10d6dd4162f3216a120c73a4edb/src/script/interpreter.cpp#L272
216+ // https://bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts/
217+ /** A data type to abstract out the condition stack during script execution.
218+ *
219+ * Conceptually it acts like a vector of booleans, one for each level of nested
220+ * IF/THEN/ELSE, indicating whether we're in the active or inactive branch of
221+ * each.
222+ *
223+ * The elements on the stack cannot be observed individually; we only need to
224+ * expose whether the stack is empty and whether or not any false values are
225+ * present at all. To implement OP_ELSE, a toggle_top modifier is added, which
226+ * flips the last value without returning it.
227+ *
228+ * This uses an optimized implementation that does not materialize the
229+ * actual stack. Instead, it just stores the size of the would-be stack,
230+ * and the position of the first false value in it.
231+ */
232+ pub struct ConditionStack {
233+ stack_size : u32 ,
234+ first_false_pos : u32 ,
235+ }
236+
237+ impl Default for ConditionStack {
238+ fn default ( ) -> Self {
239+ Self {
240+ stack_size : 0 ,
241+ first_false_pos : Self :: NO_FALSE ,
242+ }
243+ }
244+ }
245+
246+ impl ConditionStack {
247+ const NO_FALSE : u32 = u32:: MAX ;
248+
249+ pub fn is_empty ( & self ) -> bool {
250+ self . stack_size == 0
251+ }
252+
253+ pub fn all_true ( & self ) -> bool {
254+ self . first_false_pos == Self :: NO_FALSE
255+ }
256+
257+ pub fn push_back ( & mut self , b : bool ) {
258+ if ( self . first_false_pos == Self :: NO_FALSE ) && !b {
259+ // The stack consists of all true values, and a false is added.
260+ // The first false value will appear at the current size.
261+ self . first_false_pos = self . stack_size ;
262+ }
263+
264+ self . stack_size += 1 ;
265+ }
266+
267+ pub fn pop_back ( & mut self ) -> Result < ( ) , ( ) > {
268+ if self . stack_size == 0 {
269+ return Err ( ( ) ) ;
270+ }
271+
272+ self . stack_size -= 1 ;
273+ if self . first_false_pos == self . stack_size {
274+ // When popping off the first false value, everything becomes true.
275+ self . first_false_pos = Self :: NO_FALSE ;
276+ }
277+
278+ Ok ( ( ) )
279+ }
280+
281+ pub fn toggle_top ( & mut self ) -> Result < ( ) , ( ) > {
282+ if self . stack_size == 0 {
283+ return Err ( ( ) ) ;
284+ }
285+
286+ if self . first_false_pos == Self :: NO_FALSE {
287+ // The current stack is all true values; the first false will be the top.
288+ self . first_false_pos = self . stack_size - 1 ;
289+ } else if self . first_false_pos == self . stack_size - 1 {
290+ // The top is the first false value; toggling it will make everything true.
291+ self . first_false_pos = Self :: NO_FALSE ;
292+ } else {
293+ // There is a false value, but not on top. No action is needed as toggling
294+ // anything but the first false value is unobservable.
295+ }
296+
297+ Ok ( ( ) )
145298 }
146299}
147300
@@ -194,10 +347,10 @@ pub fn encode(a: Script<MyOperator, MyValue>) -> Vec<u8> {
194347
195348fn execute_script ( script : Script < MyOperator , MyValue > ) -> bool {
196349 // Instantiate the machine with a reference to your operator system.
197- let mut machine = Machine :: new ( & my_operator_system) ;
350+ let mut machine = Machine2 :: new ( & my_operator_system) ;
198351 let result = machine. run_script ( & script) ;
199352
200- result == Some ( & MyValue :: Boolean ( true ) )
353+ result == None || result == Some ( & MyValue :: Boolean ( true ) )
201354}
202355
203356fn execute_locking_script ( redeem_bytes : & [ u8 ] , locking_bytes : & [ u8 ; 20 ] ) -> bool {
@@ -240,6 +393,67 @@ pub fn execute_complete_script(
240393 execute_redeem_script ( witness_bytes, redeem_bytes)
241394}
242395
396+ // TODO: use control flow enum from scriptful library when ready
397+ pub enum MyControlFlow {
398+ Continue ,
399+ Break ,
400+ }
401+
402+ pub struct Machine2 < ' a , Op , Val >
403+ where
404+ Val : core:: fmt:: Debug + core:: cmp:: PartialEq ,
405+ {
406+ op_sys : & ' a dyn Fn ( & mut Stack < Val > , & Op , & mut ConditionStack ) -> MyControlFlow ,
407+ stack : Stack < Val > ,
408+ if_stack : ConditionStack ,
409+ }
410+
411+ impl < ' a , Op , Val > Machine2 < ' a , Op , Val >
412+ where
413+ Op : core:: fmt:: Debug + core:: cmp:: Eq ,
414+ Val : core:: fmt:: Debug + core:: cmp:: PartialEq + core:: clone:: Clone ,
415+ {
416+ pub fn new (
417+ op_sys : & ' a dyn Fn ( & mut Stack < Val > , & Op , & mut ConditionStack ) -> MyControlFlow ,
418+ ) -> Self {
419+ Self {
420+ op_sys,
421+ stack : Stack :: < Val > :: default ( ) ,
422+ if_stack : ConditionStack :: default ( ) ,
423+ }
424+ }
425+
426+ pub fn operate ( & mut self , item : & Item < Op , Val > ) -> MyControlFlow {
427+ match item {
428+ Item :: Operator ( operator) => {
429+ ( self . op_sys ) ( & mut self . stack , operator, & mut self . if_stack )
430+ }
431+ Item :: Value ( value) => {
432+ if self . if_stack . all_true ( ) {
433+ self . stack . push ( ( * value) . clone ( ) ) ;
434+ }
435+
436+ MyControlFlow :: Continue
437+ }
438+ }
439+ }
440+
441+ pub fn run_script ( & mut self , script : ScriptRef < Op , Val > ) -> Option < & Val > {
442+ for item in script {
443+ match self . operate ( item) {
444+ MyControlFlow :: Continue => {
445+ continue ;
446+ }
447+ MyControlFlow :: Break => {
448+ break ;
449+ }
450+ }
451+ }
452+
453+ self . stack . topmost ( )
454+ }
455+ }
456+
243457#[ cfg( test) ]
244458mod tests {
245459 use super :: * ;
@@ -414,4 +628,91 @@ mod tests {
414628 & encode( redeem_script)
415629 ) ) ;
416630 }
631+
632+ #[ test]
633+ fn test_execute_script_op_verify ( ) {
634+ let s = vec ! [
635+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
636+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
637+ Item :: Operator ( MyOperator :: Equal ) ,
638+ Item :: Operator ( MyOperator :: Verify ) ,
639+ ] ;
640+ assert ! ( execute_script( s) ) ;
641+
642+ let s = vec ! [
643+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
644+ Item :: Value ( MyValue :: String ( "potato" . to_string( ) ) ) ,
645+ Item :: Operator ( MyOperator :: Equal ) ,
646+ Item :: Operator ( MyOperator :: Verify ) ,
647+ ] ;
648+ assert ! ( !execute_script( s) ) ;
649+ }
650+
651+ #[ test]
652+ fn test_execute_script_op_if ( ) {
653+ let s = vec ! [
654+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
655+ Item :: Value ( MyValue :: Boolean ( true ) ) ,
656+ Item :: Operator ( MyOperator :: If ) ,
657+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
658+ Item :: Operator ( MyOperator :: Else ) ,
659+ Item :: Value ( MyValue :: String ( "potato" . to_string( ) ) ) ,
660+ Item :: Operator ( MyOperator :: EndIf ) ,
661+ Item :: Operator ( MyOperator :: Equal ) ,
662+ Item :: Operator ( MyOperator :: Verify ) ,
663+ ] ;
664+ assert ! ( execute_script( s) ) ;
665+
666+ let s = vec ! [
667+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
668+ Item :: Value ( MyValue :: Boolean ( false ) ) ,
669+ Item :: Operator ( MyOperator :: If ) ,
670+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
671+ Item :: Operator ( MyOperator :: Else ) ,
672+ Item :: Value ( MyValue :: String ( "potato" . to_string( ) ) ) ,
673+ Item :: Operator ( MyOperator :: EndIf ) ,
674+ Item :: Operator ( MyOperator :: Equal ) ,
675+ Item :: Operator ( MyOperator :: Verify ) ,
676+ ] ;
677+ assert ! ( !execute_script( s) ) ;
678+ }
679+
680+ #[ test]
681+ fn test_execute_script_op_if_nested ( ) {
682+ let s = vec ! [
683+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
684+ Item :: Value ( MyValue :: Boolean ( true ) ) ,
685+ Item :: Operator ( MyOperator :: If ) ,
686+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
687+ Item :: Operator ( MyOperator :: Else ) ,
688+ Item :: Value ( MyValue :: Boolean ( false ) ) ,
689+ Item :: Operator ( MyOperator :: If ) ,
690+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
691+ Item :: Operator ( MyOperator :: Else ) ,
692+ Item :: Value ( MyValue :: String ( "potato" . to_string( ) ) ) ,
693+ Item :: Operator ( MyOperator :: EndIf ) ,
694+ Item :: Operator ( MyOperator :: EndIf ) ,
695+ Item :: Operator ( MyOperator :: Equal ) ,
696+ Item :: Operator ( MyOperator :: Verify ) ,
697+ ] ;
698+ assert ! ( execute_script( s) ) ;
699+
700+ let s = vec ! [
701+ Item :: Value ( MyValue :: String ( "potato" . to_string( ) ) ) ,
702+ Item :: Value ( MyValue :: Boolean ( false ) ) ,
703+ Item :: Operator ( MyOperator :: If ) ,
704+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
705+ Item :: Operator ( MyOperator :: Else ) ,
706+ Item :: Value ( MyValue :: Boolean ( false ) ) ,
707+ Item :: Operator ( MyOperator :: If ) ,
708+ Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
709+ Item :: Operator ( MyOperator :: Else ) ,
710+ Item :: Value ( MyValue :: String ( "potato" . to_string( ) ) ) ,
711+ Item :: Operator ( MyOperator :: EndIf ) ,
712+ Item :: Operator ( MyOperator :: EndIf ) ,
713+ Item :: Operator ( MyOperator :: Equal ) ,
714+ Item :: Operator ( MyOperator :: Verify ) ,
715+ ] ;
716+ assert ! ( execute_script( s) ) ;
717+ }
417718}
0 commit comments