1mod frame;
10mod limits;
11mod tracker;
12
13use std::error;
14use std::fmt;
15use std::sync::Arc;
16
17use crate::analysis;
18use crate::jet::JetEnvironment;
19use crate::jet::{Jet, JetFailed};
20use crate::node::{self, RedeemNode};
21use crate::types::Final;
22use crate::{Cmr, FailEntropy, Value};
23use frame::Frame;
24
25pub use self::limits::LimitError;
26pub use self::tracker::{
27 ExecTracker, NoTracker, NodeOutput, PruneTracker, SetTracker, StderrTracker,
28};
29
30pub type FrameIter<'a> = crate::BitIter<core::iter::Copied<core::slice::Iter<'a, u8>>>;
32
33pub struct BitMachine {
35 data: Vec<u8>,
38 next_frame_start: usize,
40 read: Vec<Frame>,
42 write: Vec<Frame>,
44 source_ty: Arc<Final>,
46}
47
48impl BitMachine {
49 pub fn for_program(program: &RedeemNode) -> Result<Self, LimitError> {
51 LimitError::check_program(program)?;
52 let io_width = program.arrow().source.bit_width() + program.arrow().target.bit_width();
53
54 Ok(Self {
55 data: vec![0; (io_width + program.bounds().extra_cells).div_ceil(8)],
56 next_frame_start: 0,
57 read: Vec::with_capacity(program.bounds().extra_frames + analysis::IO_EXTRA_FRAMES),
58 write: Vec::with_capacity(program.bounds().extra_frames + analysis::IO_EXTRA_FRAMES),
59 source_ty: program.arrow().source.clone(),
60 })
61 }
62
63 #[cfg(test)]
64 pub fn test_exec<JE: JetEnvironment>(
65 program: Arc<crate::node::ConstructNode>,
66 env: &JE,
67 ) -> Result<Value, ExecutionError> {
68 use crate::node::SimpleFinalizer;
69
70 let prog = program
71 .finalize_types_non_program()
72 .expect("finalizing types")
73 .finalize(&mut SimpleFinalizer::new(None.into_iter()))
74 .expect("finalizing");
75 let mut mac = BitMachine::for_program(&prog).expect("program has reasonable bounds");
76 mac.exec(&prog, env)
77 }
78
79 fn new_write_frame(&mut self, len: usize) {
81 debug_assert!(
82 self.next_frame_start + len <= self.data.len() * 8,
83 "Data out of bounds: number of cells"
84 );
85 debug_assert!(
86 self.write.len() + self.read.len() < self.read.capacity(),
87 "Stacks out of bounds: number of frames"
88 );
89
90 self.write.push(Frame::new(self.next_frame_start, len));
91 self.next_frame_start += len;
92 }
93
94 fn move_write_frame_to_read(&mut self) {
96 let mut _active_write_frame = self.write.pop().unwrap();
97 _active_write_frame.reset_cursor();
98 self.read.push(_active_write_frame);
99 }
100
101 fn drop_read_frame(&mut self) {
103 let active_read_frame = self.read.pop().unwrap();
104 self.next_frame_start -= active_read_frame.bit_width();
105 assert_eq!(self.next_frame_start, active_read_frame.start());
106 }
107
108 fn write_bit(&mut self, bit: bool) {
110 self.write
111 .last_mut()
112 .expect("Empty write frame stack")
113 .write_bit(bit, &mut self.data);
114 }
115
116 fn skip(&mut self, n: usize) {
119 if n == 0 {
121 return;
122 }
123 let idx = self.write.len() - 1;
124 self.write[idx].move_cursor_forward(n);
125 }
126
127 fn copy(&mut self, n: usize) {
130 if n == 0 {
132 return;
133 }
134 let widx = self.write.len() - 1;
135 let ridx = self.read.len() - 1;
136 self.write[widx].copy_from(&self.read[ridx], n, &mut self.data);
137 }
138
139 fn fwd(&mut self, n: usize) {
142 if n == 0 {
144 return;
145 }
146 let idx = self.read.len() - 1;
147 self.read[idx].move_cursor_forward(n);
148 }
149
150 fn back(&mut self, n: usize) {
153 if n == 0 {
155 return;
156 }
157 let idx = self.read.len() - 1;
158 self.read[idx].move_cursor_backward(n);
159 }
160
161 fn write_u8(&mut self, value: u8) {
163 self.write
164 .last_mut()
165 .expect("Empty write frame stack")
166 .write_u8(value, &mut self.data);
167 }
168
169 fn read_bit(&mut self) -> bool {
171 self.read
172 .last_mut()
173 .expect("Empty read frame stack")
174 .read_bit(&self.data)
175 }
176
177 fn write_bytes(&mut self, bytes: &[u8]) {
179 for bit in bytes {
180 self.write_u8(*bit);
181 }
182 }
183
184 fn write_value(&mut self, val: &Value) {
186 for bit in val.iter_padded() {
187 self.write_bit(bit);
188 }
189 }
190
191 fn active_read_bit_width(&self) -> usize {
193 self.read.last().map(|frame| frame.bit_width()).unwrap_or(0)
194 }
195
196 fn active_write_bit_width(&self) -> usize {
198 self.write
199 .last()
200 .map(|frame| frame.bit_width())
201 .unwrap_or(0)
202 }
203
204 pub fn input(&mut self, input: &Value) -> Result<(), ExecutionError> {
207 if !input.is_of_type(&self.source_ty) {
208 return Err(ExecutionError::InputWrongType(self.source_ty.clone()));
209 }
210 if !input.is_empty() {
212 self.new_write_frame(input.padded_len());
213 self.write_value(input);
214 self.move_write_frame_to_read();
215 }
216 Ok(())
217 }
218
219 pub fn exec<JE: JetEnvironment>(
225 &mut self,
226 program: &RedeemNode,
227 env: &JE,
228 ) -> Result<Value, ExecutionError> {
229 self.exec_with_tracker(program, env, &mut NoTracker)
230 }
231
232 pub fn exec_with_tracker<JE: JetEnvironment, T: ExecTracker>(
241 &mut self,
242 program: &RedeemNode,
243 env: &JE,
244 tracker: &mut T,
245 ) -> Result<Value, ExecutionError> {
246 enum CallStack<'a> {
247 Goto(&'a RedeemNode),
248 MoveWriteFrameToRead,
249 DropReadFrame,
250 CopyFwd(usize),
251 Back(usize),
252 }
253
254 impl fmt::Debug for CallStack<'_> {
256 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257 match self {
258 CallStack::Goto(ins) => write!(f, "goto {}", ins.inner()),
259 CallStack::MoveWriteFrameToRead => f.write_str("move frame"),
260 CallStack::DropReadFrame => f.write_str("drop frame"),
261 CallStack::CopyFwd(n) => write!(f, "copy/fwd {}", n),
262 CallStack::Back(n) => write!(f, "back {}", n),
263 }
264 }
265 }
266
267 if self.read.is_empty() != self.source_ty.is_empty() {
268 return Err(ExecutionError::InputWrongType(self.source_ty.clone()));
269 }
270
271 let mut ip = program;
272 let mut call_stack: Vec<CallStack<'_>> = vec![];
273
274 let output_width = ip.arrow().target.bit_width();
275 if output_width > 0 {
276 self.new_write_frame(output_width);
277 }
278
279 'main_loop: loop {
280 let input_frame = self.read.last().map(Frame::shallow_copy);
284 let output_frame = self.write.last().map(Frame::shallow_copy);
285 let mut jet_result = Ok(());
286
287 match ip.inner() {
288 node::Inner::Unit => {}
289 node::Inner::Iden => {
290 let size_a = ip.arrow().source.bit_width();
291 self.copy(size_a);
292 }
293 node::Inner::InjL(left) => {
294 let (b, c) = ip.arrow().target.as_sum().unwrap();
295 self.write_bit(false);
296 self.skip(b.pad_left(c));
297 call_stack.push(CallStack::Goto(left));
298 }
299 node::Inner::InjR(left) => {
300 let (b, c) = ip.arrow().target.as_sum().unwrap();
301 self.write_bit(true);
302 self.skip(b.pad_right(c));
303 call_stack.push(CallStack::Goto(left));
304 }
305 node::Inner::Pair(left, right) => {
306 call_stack.push(CallStack::Goto(right));
307 call_stack.push(CallStack::Goto(left));
308 }
309 node::Inner::Comp(left, right) => {
310 let size_b = left.arrow().target.bit_width();
311
312 self.new_write_frame(size_b);
313 call_stack.push(CallStack::DropReadFrame);
314 call_stack.push(CallStack::Goto(right));
315 call_stack.push(CallStack::MoveWriteFrameToRead);
316 call_stack.push(CallStack::Goto(left));
317 }
318 node::Inner::Disconnect(left, right) => {
319 let size_prod_256_a = left.arrow().source.bit_width();
320 let size_a = size_prod_256_a - 256;
321 let size_prod_b_c = left.arrow().target.bit_width();
322 let size_b = size_prod_b_c - right.arrow().source.bit_width();
323
324 self.new_write_frame(size_prod_256_a);
325 self.write_bytes(right.cmr().as_ref());
326 self.copy(size_a);
327 self.move_write_frame_to_read();
328 self.new_write_frame(size_prod_b_c);
329
330 call_stack.push(CallStack::DropReadFrame);
332 call_stack.push(CallStack::DropReadFrame);
333 call_stack.push(CallStack::Goto(right));
334 call_stack.push(CallStack::CopyFwd(size_b));
335 call_stack.push(CallStack::MoveWriteFrameToRead);
336 call_stack.push(CallStack::Goto(left));
337 }
338 node::Inner::Take(left) => call_stack.push(CallStack::Goto(left)),
339 node::Inner::Drop(left) => {
340 let size_a = ip.arrow().source.as_product().unwrap().0.bit_width();
341 self.fwd(size_a);
342 call_stack.push(CallStack::Back(size_a));
343 call_stack.push(CallStack::Goto(left));
344 }
345 node::Inner::Case(..) | node::Inner::AssertL(..) | node::Inner::AssertR(..) => {
346 let in_frame = &self.read[self.read.len() - 1];
347 let choice_bit: bool = in_frame.peek_bit(&self.data);
348
349 let (sum_a_b, _c) = ip.arrow().source.as_product().unwrap();
350 let (a, b) = sum_a_b.as_sum().unwrap();
351
352 match (ip.inner(), choice_bit) {
353 (node::Inner::Case(_, right), true)
354 | (node::Inner::AssertR(_, right), true) => {
355 self.fwd(1 + a.pad_right(b));
356 call_stack.push(CallStack::Back(1 + a.pad_right(b)));
357 call_stack.push(CallStack::Goto(right));
358 }
359 (node::Inner::Case(left, _), false)
360 | (node::Inner::AssertL(left, _), false) => {
361 self.fwd(1 + a.pad_left(b));
362 call_stack.push(CallStack::Back(1 + a.pad_left(b)));
363 call_stack.push(CallStack::Goto(left));
364 }
365 (node::Inner::AssertL(_, r_cmr), true) => {
366 return Err(ExecutionError::ReachedPrunedBranch(*r_cmr))
367 }
368 (node::Inner::AssertR(l_cmr, _), false) => {
369 return Err(ExecutionError::ReachedPrunedBranch(*l_cmr))
370 }
371 _ => unreachable!(),
372 }
373 }
374 node::Inner::Witness(value) => self.write_value(value),
375 node::Inner::Jet(jet) => {
376 let typed_jet = jet
377 .as_ref()
378 .as_any()
379 .downcast_ref::<JE::Jet>()
380 .ok_or(ExecutionError::JetTypeMismatch)?;
381 jet_result = self.exec_jet(typed_jet, env);
382 }
383 node::Inner::Word(value) => self.write_value(value.as_value()),
384 node::Inner::Fail(entropy) => {
385 return Err(ExecutionError::ReachedFailNode(*entropy))
386 }
387 }
388
389 {
391 let read_iter = input_frame
397 .map(|frame| frame.as_bit_iter_from_cursor(&self.data))
398 .unwrap_or(crate::BitIter::from([].iter().copied()));
399 let output = match (ip.inner(), &jet_result) {
402 (node::Inner::Unit | node::Inner::Iden | node::Inner::Witness(_), _)
403 | (node::Inner::Jet(_), Ok(_)) => NodeOutput::Success(
404 output_frame
405 .map(|frame| frame.as_bit_iter_from_cursor(&self.data))
406 .unwrap_or(crate::BitIter::from([].iter().copied())),
407 ),
408 (node::Inner::Jet(_), Err(_)) => NodeOutput::JetFailed,
409 _ => NodeOutput::NonTerminal,
410 };
411 tracker.visit_node(ip, read_iter, output);
412 }
413 jet_result?;
415
416 ip = loop {
417 match call_stack.pop() {
418 Some(CallStack::Goto(next)) => break next,
419 Some(CallStack::MoveWriteFrameToRead) => self.move_write_frame_to_read(),
420 Some(CallStack::DropReadFrame) => self.drop_read_frame(),
421 Some(CallStack::CopyFwd(n)) => {
422 self.copy(n);
423 self.fwd(n);
424 }
425 Some(CallStack::Back(n)) => self.back(n),
426 None => break 'main_loop,
427 };
428 };
429 }
430
431 if output_width > 0 {
432 let out_frame = self.write.last_mut().unwrap();
433 out_frame.reset_cursor();
434 let value = Value::from_padded_bits(
435 &mut out_frame.as_bit_iter_from_cursor(&self.data),
436 &program.arrow().target,
437 )
438 .expect("Decode value of output frame");
439
440 Ok(value)
441 } else {
442 Ok(Value::unit())
443 }
444 }
445
446 fn exec_jet<JE: JetEnvironment>(&mut self, jet: &JE::Jet, env: &JE) -> Result<(), JetFailed> {
447 use crate::ffi::c_jets::frame_ffi::{c_readBit, c_writeBit, CFrameItem};
448 use crate::ffi::c_jets::uword_width;
449 use crate::ffi::ffi::UWORD;
450
451 unsafe fn get_input_frame(
463 mac: &mut BitMachine,
464 bit_width: usize,
465 ) -> (CFrameItem, Vec<UWORD>) {
466 assert!(bit_width <= mac.active_read_bit_width());
467 let uword_width = uword_width(bit_width);
468 let mut buffer = vec![0; uword_width];
469
470 let buffer_end = buffer.as_mut_ptr().add(uword_width);
472 let mut write_frame = CFrameItem::new_write(bit_width, buffer_end);
473 for _ in 0..bit_width {
474 let bit = mac.read_bit();
475 c_writeBit(&mut write_frame, bit);
476 }
477 mac.back(bit_width);
478
479 let buffer_ptr = buffer.as_mut_ptr();
481 let read_frame = CFrameItem::new_read(bit_width, buffer_ptr);
482
483 (read_frame, buffer)
484 }
485
486 unsafe fn get_output_frame(bit_width: usize) -> (CFrameItem, Vec<UWORD>) {
494 let uword_width = uword_width(bit_width);
495 let mut buffer = vec![0; uword_width];
496
497 let buffer_end = buffer.as_mut_ptr().add(uword_width);
499 let write_frame = CFrameItem::new_write(bit_width, buffer_end);
500
501 (write_frame, buffer)
502 }
503
504 fn update_active_write_frame(mac: &mut BitMachine, bit_width: usize, buffer: &[UWORD]) {
512 assert!(bit_width <= mac.active_write_bit_width());
513 assert!(uword_width(bit_width) <= buffer.len());
514 let buffer_ptr = buffer.as_ptr();
515 let mut read_frame = unsafe { CFrameItem::new_read(bit_width, buffer_ptr) };
516
517 for _ in 0..bit_width {
518 let bit = unsafe { c_readBit(&mut read_frame) };
519 mac.write_bit(bit);
520 }
521 }
522
523 if !simplicity_sys::c_jets::sanity_checks() {
525 return Err(JetFailed);
526 }
527
528 let input_width = jet.source_ty().to_bit_width();
529 let output_width = jet.target_ty().to_bit_width();
530 let (input_read_frame, _input_buffer) = unsafe { get_input_frame(self, input_width) };
533 let (mut output_write_frame, output_buffer) = unsafe { get_output_frame(output_width) };
534
535 let jet_fn = JE::c_jet_ptr(jet);
536 let c_env = env.c_jet_env();
537 let success = jet_fn(&mut output_write_frame, input_read_frame, c_env);
538
539 if !success {
540 Err(JetFailed)
541 } else {
542 update_active_write_frame(self, output_width, &output_buffer);
543 Ok(())
544 }
545 }
546}
547
548#[derive(Debug)]
550pub enum ExecutionError {
551 InputWrongType(Arc<Final>),
553 ReachedFailNode(FailEntropy),
555 ReachedPrunedBranch(Cmr),
557 LimitExceeded(LimitError),
559 JetFailed(JetFailed),
561 JetTypeMismatch,
563}
564
565impl fmt::Display for ExecutionError {
566 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
567 match self {
568 ExecutionError::InputWrongType(expected_ty) => {
569 write!(f, "Expected input of type: {expected_ty}")
570 }
571 ExecutionError::ReachedFailNode(entropy) => {
572 write!(f, "Execution reached a fail node: {}", entropy)
573 }
574 ExecutionError::ReachedPrunedBranch(hash) => {
575 write!(f, "Execution reached a pruned branch: {}", hash)
576 }
577 ExecutionError::LimitExceeded(e) => e.fmt(f),
578 ExecutionError::JetFailed(jet_failed) => jet_failed.fmt(f),
579 ExecutionError::JetTypeMismatch => {
580 f.write_str("Jet type mismatch between program and execution environment")
581 }
582 }
583 }
584}
585
586impl error::Error for ExecutionError {
587 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
588 match self {
589 Self::InputWrongType(..)
590 | Self::ReachedFailNode(..)
591 | Self::ReachedPrunedBranch(..)
592 | Self::JetTypeMismatch => None,
593 Self::LimitExceeded(ref e) => Some(e),
594 Self::JetFailed(ref e) => Some(e),
595 }
596 }
597}
598
599impl From<LimitError> for ExecutionError {
600 fn from(e: LimitError) -> Self {
601 ExecutionError::LimitExceeded(e)
602 }
603}
604
605impl From<JetFailed> for ExecutionError {
606 fn from(jet_failed: JetFailed) -> Self {
607 ExecutionError::JetFailed(jet_failed)
608 }
609}
610
611#[cfg(test)]
612mod tests {
613 use super::*;
614
615 #[cfg(feature = "elements")]
616 use crate::jet::elements::ElementsEnv;
617 use crate::jet::CoreEnv;
618 #[cfg(feature = "elements")]
619 use crate::{node::RedeemNode, BitIter};
620 #[cfg(feature = "elements")]
621 use hex::DisplayHex;
622
623 #[cfg(feature = "elements")]
624 fn run_program_elements(
625 prog_bytes: &[u8],
626 witness_bytes: &[u8],
627 cmr_str: &str,
628 amr_str: &str,
629 ihr_str: &str,
630 ) -> Result<Value, ExecutionError> {
631 let prog_hex = prog_bytes.as_hex();
632
633 let prog = BitIter::from(prog_bytes);
634 let witness = BitIter::from(witness_bytes);
635 let prog = match RedeemNode::decode::<_, _, crate::jet::Elements>(prog, witness) {
636 Ok(prog) => prog,
637 Err(e) => panic!("program {} failed: {}", prog_hex, e),
638 };
639
640 assert_eq!(
643 prog.cmr().to_string(),
644 cmr_str,
645 "CMR mismatch (got {} expected {}) for program {}",
646 prog.cmr(),
647 cmr_str,
648 prog_hex,
649 );
650 assert_eq!(
651 prog.amr().to_string(),
652 amr_str,
653 "AMR mismatch (got {} expected {}) for program {}",
654 prog.amr(),
655 amr_str,
656 prog_hex,
657 );
658 assert_eq!(
659 prog.ihr().to_string(),
660 ihr_str,
661 "IHR mismatch (got {} expected {}) for program {}",
662 prog.ihr(),
663 ihr_str,
664 prog_hex,
665 );
666
667 let env = ElementsEnv::dummy();
669 BitMachine::for_program(&prog)
670 .expect("program has reasonable bounds")
671 .exec(&prog, &env)
672 }
673
674 #[test]
675 #[cfg(feature = "human_encoding")]
676 fn set_tracker_cursor_regression() {
677 use crate::human_encoding::Forest;
688 use crate::types;
689 use std::collections::HashMap;
690
691 types::Context::with_context(|ctx| {
692 let s = "main := comp (pair (injl (injr unit)) unit) (case (case unit unit) unit)";
693 let program = Forest::parse::<crate::jet::Core>(s)
694 .expect("parse")
695 .to_witness_node(&ctx, &HashMap::new())
696 .expect("main root")
697 .finalize_pruned(&CoreEnv::new())
698 .expect("finalize and prune");
699 let mut mac = BitMachine::for_program(&program).expect("for_program");
700 mac.exec(&program, &CoreEnv::new())
701 .expect("pruned execution should succeed");
702 });
703 }
704
705 #[test]
706 #[cfg(feature = "elements")]
707 fn crash_regression1() {
708 let res = run_program_elements(
723 &[0xcf, 0xe1, 0x8f, 0xb4, 0x40, 0x28, 0x87, 0x04, 0x00],
724 &[],
725 "0075f5368af7b453c2f7318493df12567bc6d733cf1ebb69a08ce93e1e529956",
726 "0ac9baaee94e416c6598a271dfc18d6014f751ac300cfe69eb758c20f26c624b",
727 "61f2cf59bfec55bb6e44cbae71c3ba225f1059f9a5679c0b42a7177daff52b5a",
728 );
729 assert_eq!(res.unwrap(), Value::unit());
730 }
731
732 #[test]
733 fn crash_regression2() {
734 use crate::node::{CoreConstructible as _, JetConstructible as _};
735
736 type Node<'brand> = Arc<crate::ConstructNode<'brand>>;
737
738 crate::types::Context::with_context(|ctx| {
739 let mut bomb = Node::jet(
740 &ctx,
741 &crate::jet::Core::Ch8, );
743 for _ in 0..100 {
744 bomb = Node::pair(&bomb, &bomb).unwrap();
745 }
746 let _ = bomb.finalize_pruned(&CoreEnv::new());
747 });
748 }
749}