@@ -20,6 +20,7 @@ pub enum MyOperator {
2020 Equal ,
2121 Hash160 ,
2222 CheckMultiSig ,
23+ CheckTimeLock ,
2324 /// Stop script execution if top-most element of stack is not "true"
2425 Verify ,
2526 // Control flow
@@ -143,11 +144,26 @@ fn check_multi_sig(bytes_pkhs: Vec<MyValue>, bytes_keyed_signatures: Vec<MyValue
143144 true
144145}
145146
147+ fn check_timelock_operator ( stack : & mut Stack < MyValue > , block_timestamp : i64 ) {
148+ let timelock = stack. pop ( ) ;
149+ match timelock {
150+ MyValue :: Integer ( timelock) => {
151+ let timelock_ok = i128:: from ( block_timestamp) >= timelock;
152+ stack. push ( MyValue :: Boolean ( timelock_ok) ) ;
153+ }
154+ _ => {
155+ // TODO change panic by error
156+ unreachable ! ( "CheckTimelock should pick an integer as a first value" ) ;
157+ }
158+ }
159+ }
160+
146161// An operator system decides what to do with the stack when each operator is applied on it.
147162fn my_operator_system (
148163 stack : & mut Stack < MyValue > ,
149164 operator : & MyOperator ,
150165 if_stack : & mut ConditionStack ,
166+ context : & ScriptContext ,
151167) -> MyControlFlow {
152168 if !if_stack. all_true ( ) {
153169 match operator {
@@ -176,6 +192,7 @@ fn my_operator_system(
176192 MyOperator :: Equal => equal_operator ( stack) ,
177193 MyOperator :: Hash160 => hash_160_operator ( stack) ,
178194 MyOperator :: CheckMultiSig => check_multisig_operator ( stack) ,
195+ MyOperator :: CheckTimeLock => check_timelock_operator ( stack, context. block_timestamp ) ,
179196 MyOperator :: Verify => {
180197 let top = stack. pop ( ) ;
181198 if top != MyValue :: Boolean ( true ) {
@@ -346,15 +363,24 @@ pub fn encode(a: Script<MyOperator, MyValue>) -> Vec<u8> {
346363 serde_json:: to_vec ( & x) . unwrap ( )
347364}
348365
349- fn execute_script ( script : Script < MyOperator , MyValue > ) -> bool {
366+ #[ derive( Default ) ]
367+ pub struct ScriptContext {
368+ pub block_timestamp : i64 ,
369+ }
370+
371+ fn execute_script ( script : Script < MyOperator , MyValue > , context : & ScriptContext ) -> bool {
350372 // Instantiate the machine with a reference to your operator system.
351- let mut machine = Machine2 :: new ( my_operator_system) ;
373+ let mut machine = Machine2 :: new ( |a , b , c| my_operator_system ( a , b , c , context ) ) ;
352374 let result = machine. run_script ( & script) ;
353375
354376 result == None || result == Some ( & MyValue :: Boolean ( true ) )
355377}
356378
357- fn execute_locking_script ( redeem_bytes : & [ u8 ] , locking_bytes : & [ u8 ; 20 ] ) -> bool {
379+ fn execute_locking_script (
380+ redeem_bytes : & [ u8 ] ,
381+ locking_bytes : & [ u8 ; 20 ] ,
382+ context : & ScriptContext ,
383+ ) -> bool {
358384 // Check locking script
359385 let mut locking_script = vec ! [
360386 Item :: Operator ( MyOperator :: Hash160 ) ,
@@ -366,32 +392,37 @@ fn execute_locking_script(redeem_bytes: &[u8], locking_bytes: &[u8; 20]) -> bool
366392 locking_script. insert ( 0 , Item :: Value ( MyValue :: Bytes ( redeem_bytes. to_vec ( ) ) ) ) ;
367393
368394 // Execute the script
369- execute_script ( locking_script)
395+ execute_script ( locking_script, context )
370396}
371397
372- fn execute_redeem_script ( witness_bytes : & [ u8 ] , redeem_bytes : & [ u8 ] ) -> bool {
398+ fn execute_redeem_script (
399+ witness_bytes : & [ u8 ] ,
400+ redeem_bytes : & [ u8 ] ,
401+ context : & ScriptContext ,
402+ ) -> bool {
373403 // Execute witness script concatenated with redeem script
374404 let mut witness_script = decode ( witness_bytes) ;
375405 let redeem_script = decode ( redeem_bytes) ;
376406 witness_script. extend ( redeem_script) ;
377407
378408 // Execute the script
379- execute_script ( witness_script)
409+ execute_script ( witness_script, context )
380410}
381411
382412pub fn execute_complete_script (
383413 witness_bytes : & [ u8 ] ,
384414 redeem_bytes : & [ u8 ] ,
385415 locking_bytes : & [ u8 ; 20 ] ,
416+ context : & ScriptContext ,
386417) -> bool {
387418 // Execute locking script
388- let result = execute_locking_script ( redeem_bytes, locking_bytes) ;
419+ let result = execute_locking_script ( redeem_bytes, locking_bytes, context ) ;
389420 if !result {
390421 return false ;
391422 }
392423
393424 // Execute witness script concatenated with redeem script
394- execute_redeem_script ( witness_bytes, redeem_bytes)
425+ execute_redeem_script ( witness_bytes, redeem_bytes, context )
395426}
396427
397428// TODO: use control flow enum from scriptful library when ready
@@ -473,14 +504,14 @@ mod tests {
473504 Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
474505 Item :: Operator ( MyOperator :: Equal ) ,
475506 ] ;
476- assert ! ( execute_script( s) ) ;
507+ assert ! ( execute_script( s, & ScriptContext :: default ( ) ) ) ;
477508
478509 let s = vec ! [
479510 Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
480511 Item :: Value ( MyValue :: String ( "potato" . to_string( ) ) ) ,
481512 Item :: Operator ( MyOperator :: Equal ) ,
482513 ] ;
483- assert ! ( !execute_script( s) ) ;
514+ assert ! ( !execute_script( s, & ScriptContext :: default ( ) ) ) ;
484515 }
485516
486517 #[ test]
@@ -489,14 +520,16 @@ mod tests {
489520 let locking_script = EQUAL_OPERATOR_HASH ;
490521 assert ! ( execute_locking_script(
491522 & encode( redeem_script) ,
492- & locking_script
523+ & locking_script,
524+ & ScriptContext :: default ( ) ,
493525 ) ) ;
494526
495527 let redeem_script = vec ! [ Item :: Operator ( MyOperator :: Equal ) ] ;
496528 let locking_script = [ 1 ; 20 ] ;
497529 assert ! ( !execute_locking_script(
498530 & encode( redeem_script) ,
499- & locking_script
531+ & locking_script,
532+ & ScriptContext :: default ( ) ,
500533 ) ) ;
501534 }
502535
@@ -509,7 +542,8 @@ mod tests {
509542 let redeem_script = vec ! [ Item :: Operator ( MyOperator :: Equal ) ] ;
510543 assert ! ( execute_redeem_script(
511544 & encode( witness) ,
512- & encode( redeem_script)
545+ & encode( redeem_script) ,
546+ & ScriptContext :: default ( ) ,
513547 ) ) ;
514548
515549 let witness = vec ! [
@@ -519,7 +553,8 @@ mod tests {
519553 let redeem_script = vec ! [ Item :: Operator ( MyOperator :: Equal ) ] ;
520554 assert ! ( !execute_redeem_script(
521555 & encode( witness) ,
522- & encode( redeem_script)
556+ & encode( redeem_script) ,
557+ & ScriptContext :: default ( ) ,
523558 ) ) ;
524559 }
525560
@@ -535,6 +570,7 @@ mod tests {
535570 & encode( witness) ,
536571 & encode( redeem_script) ,
537572 & locking_script,
573+ & ScriptContext :: default ( ) ,
538574 ) ) ;
539575
540576 let witness = vec ! [
@@ -547,6 +583,7 @@ mod tests {
547583 & encode( witness) ,
548584 & encode( redeem_script) ,
549585 & locking_script,
586+ & ScriptContext :: default ( ) ,
550587 ) ) ;
551588
552589 let witness = vec ! [
@@ -559,6 +596,7 @@ mod tests {
559596 & encode( witness) ,
560597 & encode( redeem_script) ,
561598 & locking_script,
599+ & ScriptContext :: default ( ) ,
562600 ) ) ;
563601 }
564602
@@ -592,7 +630,8 @@ mod tests {
592630 ] ;
593631 assert ! ( execute_redeem_script(
594632 & encode( witness) ,
595- & encode( redeem_script)
633+ & encode( redeem_script) ,
634+ & ScriptContext :: default ( ) ,
596635 ) ) ;
597636
598637 let other_valid_witness = vec ! [
@@ -609,7 +648,8 @@ mod tests {
609648 ] ;
610649 assert ! ( execute_redeem_script(
611650 & encode( other_valid_witness) ,
612- & encode( redeem_script)
651+ & encode( redeem_script) ,
652+ & ScriptContext :: default ( ) ,
613653 ) ) ;
614654
615655 let pk_4 = PublicKey :: from_bytes ( [ 4 ; 33 ] ) ;
@@ -628,7 +668,8 @@ mod tests {
628668 ] ;
629669 assert ! ( !execute_redeem_script(
630670 & encode( invalid_witness) ,
631- & encode( redeem_script)
671+ & encode( redeem_script) ,
672+ & ScriptContext :: default ( ) ,
632673 ) ) ;
633674 }
634675
@@ -640,15 +681,15 @@ mod tests {
640681 Item :: Operator ( MyOperator :: Equal ) ,
641682 Item :: Operator ( MyOperator :: Verify ) ,
642683 ] ;
643- assert ! ( execute_script( s) ) ;
684+ assert ! ( execute_script( s, & ScriptContext :: default ( ) ) ) ;
644685
645686 let s = vec ! [
646687 Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
647688 Item :: Value ( MyValue :: String ( "potato" . to_string( ) ) ) ,
648689 Item :: Operator ( MyOperator :: Equal ) ,
649690 Item :: Operator ( MyOperator :: Verify ) ,
650691 ] ;
651- assert ! ( !execute_script( s) ) ;
692+ assert ! ( !execute_script( s, & ScriptContext :: default ( ) ) ) ;
652693 }
653694
654695 #[ test]
@@ -664,7 +705,7 @@ mod tests {
664705 Item :: Operator ( MyOperator :: Equal ) ,
665706 Item :: Operator ( MyOperator :: Verify ) ,
666707 ] ;
667- assert ! ( execute_script( s) ) ;
708+ assert ! ( execute_script( s, & ScriptContext :: default ( ) ) ) ;
668709
669710 let s = vec ! [
670711 Item :: Value ( MyValue :: String ( "patata" . to_string( ) ) ) ,
@@ -677,7 +718,7 @@ mod tests {
677718 Item :: Operator ( MyOperator :: Equal ) ,
678719 Item :: Operator ( MyOperator :: Verify ) ,
679720 ] ;
680- assert ! ( !execute_script( s) ) ;
721+ assert ! ( !execute_script( s, & ScriptContext :: default ( ) ) ) ;
681722 }
682723
683724 #[ test]
@@ -698,7 +739,7 @@ mod tests {
698739 Item :: Operator ( MyOperator :: Equal ) ,
699740 Item :: Operator ( MyOperator :: Verify ) ,
700741 ] ;
701- assert ! ( execute_script( s) ) ;
742+ assert ! ( execute_script( s, & ScriptContext :: default ( ) ) ) ;
702743
703744 let s = vec ! [
704745 Item :: Value ( MyValue :: String ( "potato" . to_string( ) ) ) ,
@@ -716,7 +757,7 @@ mod tests {
716757 Item :: Operator ( MyOperator :: Equal ) ,
717758 Item :: Operator ( MyOperator :: Verify ) ,
718759 ] ;
719- assert ! ( execute_script( s) ) ;
760+ assert ! ( execute_script( s, & ScriptContext :: default ( ) ) ) ;
720761 }
721762
722763 #[ test]
@@ -731,4 +772,26 @@ mod tests {
731772
732773 assert_eq ! ( v, vec![ 0 , 1 , 3 , 2 ] ) ;
733774 }
775+
776+ #[ test]
777+ fn test_execute_script_op_check_timelock ( ) {
778+ let s = vec ! [
779+ Item :: Value ( MyValue :: Integer ( 10_000 ) ) ,
780+ Item :: Operator ( MyOperator :: CheckTimeLock ) ,
781+ Item :: Operator ( MyOperator :: Verify ) ,
782+ ] ;
783+ assert ! ( !execute_script( s, & ScriptContext { block_timestamp: 0 } ) ) ;
784+
785+ let s = vec ! [
786+ Item :: Value ( MyValue :: Integer ( 10_000 ) ) ,
787+ Item :: Operator ( MyOperator :: CheckTimeLock ) ,
788+ Item :: Operator ( MyOperator :: Verify ) ,
789+ ] ;
790+ assert ! ( execute_script(
791+ s,
792+ & ScriptContext {
793+ block_timestamp: 20_000 ,
794+ }
795+ ) ) ;
796+ }
734797}
0 commit comments