1
1
// SPDX-License-Identifier: CC0-1.0
2
2
3
- //! # Simplicity Execution
3
+ //! Simplicity Execution
4
4
//!
5
5
//! Implementation of the Bit Machine, without TCO, as TCO precludes some
6
6
//! frame management optimizations which can be used to great benefit.
7
7
//!
8
8
9
9
mod frame;
10
+ mod limits;
10
11
11
12
use std:: collections:: HashSet ;
12
13
use std:: error;
@@ -20,6 +21,8 @@ use crate::{analysis, Imr};
20
21
use crate :: { Cmr , FailEntropy , Value } ;
21
22
use frame:: Frame ;
22
23
24
+ pub use self :: limits:: LimitError ;
25
+
23
26
/// An execution context for a Simplicity program
24
27
pub struct BitMachine {
25
28
/// Space for bytes that read and write frames point to.
@@ -37,16 +40,17 @@ pub struct BitMachine {
37
40
38
41
impl BitMachine {
39
42
/// Construct a Bit Machine with enough space to execute the given program.
40
- pub fn for_program < J : Jet > ( program : & RedeemNode < J > ) -> Self {
43
+ pub fn for_program < J : Jet > ( program : & RedeemNode < J > ) -> Result < Self , LimitError > {
44
+ LimitError :: check_program ( program) ?;
41
45
let io_width = program. arrow ( ) . source . bit_width ( ) + program. arrow ( ) . target . bit_width ( ) ;
42
46
43
- Self {
47
+ Ok ( Self {
44
48
data : vec ! [ 0 ; ( io_width + program. bounds( ) . extra_cells + 7 ) / 8 ] ,
45
49
next_frame_start : 0 ,
46
50
read : Vec :: with_capacity ( program. bounds ( ) . extra_frames + analysis:: IO_EXTRA_FRAMES ) ,
47
51
write : Vec :: with_capacity ( program. bounds ( ) . extra_frames + analysis:: IO_EXTRA_FRAMES ) ,
48
52
source_ty : program. arrow ( ) . source . clone ( ) ,
49
- }
53
+ } )
50
54
}
51
55
52
56
#[ cfg( test) ]
@@ -61,7 +65,7 @@ impl BitMachine {
61
65
. expect ( "finalizing types" )
62
66
. finalize ( & mut SimpleFinalizer :: new ( None . into_iter ( ) ) )
63
67
. expect ( "finalizing" ) ;
64
- let mut mac = BitMachine :: for_program ( & prog) ;
68
+ let mut mac = BitMachine :: for_program ( & prog) . expect ( "program has reasonable bounds" ) ;
65
69
mac. exec ( & prog, env)
66
70
}
67
71
@@ -569,6 +573,8 @@ pub enum ExecutionError {
569
573
ReachedFailNode ( FailEntropy ) ,
570
574
/// Reached a pruned branch
571
575
ReachedPrunedBranch ( Cmr ) ,
576
+ /// Exceeded some program limit
577
+ LimitExceeded ( LimitError ) ,
572
578
/// Jet failed during execution
573
579
JetFailed ( JetFailed ) ,
574
580
}
@@ -585,12 +591,29 @@ impl fmt::Display for ExecutionError {
585
591
ExecutionError :: ReachedPrunedBranch ( hash) => {
586
592
write ! ( f, "Execution reached a pruned branch: {}" , hash)
587
593
}
588
- ExecutionError :: JetFailed ( jet_failed) => fmt:: Display :: fmt ( jet_failed, f) ,
594
+ ExecutionError :: LimitExceeded ( e) => e. fmt ( f) ,
595
+ ExecutionError :: JetFailed ( jet_failed) => jet_failed. fmt ( f) ,
589
596
}
590
597
}
591
598
}
592
599
593
- impl error:: Error for ExecutionError { }
600
+ impl error:: Error for ExecutionError {
601
+ fn source ( & self ) -> Option < & ( dyn error:: Error + ' static ) > {
602
+ match self {
603
+ Self :: InputWrongType ( ..)
604
+ | Self :: ReachedFailNode ( ..)
605
+ | Self :: ReachedPrunedBranch ( ..) => None ,
606
+ Self :: LimitExceeded ( ref e) => Some ( e) ,
607
+ Self :: JetFailed ( ref e) => Some ( e) ,
608
+ }
609
+ }
610
+ }
611
+
612
+ impl From < LimitError > for ExecutionError {
613
+ fn from ( e : LimitError ) -> Self {
614
+ ExecutionError :: LimitExceeded ( e)
615
+ }
616
+ }
594
617
595
618
impl From < JetFailed > for ExecutionError {
596
619
fn from ( jet_failed : JetFailed ) -> Self {
@@ -600,7 +623,6 @@ impl From<JetFailed> for ExecutionError {
600
623
601
624
#[ cfg( test) ]
602
625
mod tests {
603
- #[ cfg( feature = "elements" ) ]
604
626
use super :: * ;
605
627
606
628
#[ cfg( feature = "elements" ) ]
@@ -656,7 +678,9 @@ mod tests {
656
678
657
679
// Try to run it on the bit machine and return the result
658
680
let env = ElementsEnv :: dummy ( ) ;
659
- BitMachine :: for_program ( & prog) . exec ( & prog, & env)
681
+ BitMachine :: for_program ( & prog)
682
+ . expect ( "program has reasonable bounds" )
683
+ . exec ( & prog, & env)
660
684
}
661
685
662
686
#[ test]
@@ -685,4 +709,20 @@ mod tests {
685
709
) ;
686
710
assert_eq ! ( res. unwrap( ) , Value :: unit( ) ) ;
687
711
}
712
+
713
+ #[ test]
714
+ fn crash_regression2 ( ) {
715
+ use crate :: node:: { CoreConstructible as _, JetConstructible as _} ;
716
+
717
+ type Node = Arc < crate :: ConstructNode < crate :: jet:: Core > > ;
718
+
719
+ let mut bomb = Node :: jet (
720
+ & crate :: types:: Context :: new ( ) ,
721
+ crate :: jet:: Core :: Ch8 , // arbitrary jet with nonzero output size
722
+ ) ;
723
+ for _ in 0 ..100 {
724
+ bomb = Node :: pair ( & bomb, & bomb) . unwrap ( ) ;
725
+ }
726
+ let _ = bomb. finalize_pruned ( & ( ) ) ;
727
+ }
688
728
}
0 commit comments