Skip to main content

simplicity/node/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Simplicity Program Nodes
4//!
5//! The types in this module are used to represent Simplicity expressions as
6//! DAGs. The nodes of this DAG are individual combinators along with some
7//! cached data about the node, which depends on the specific node type.
8//!
9//! All nodes represent the root of an expression. Expressions whose source
10//! and target types are both unit are called "programs". Generally speaking,
11//! any nodes that users hold directly will be programs.
12//!
13//! There are three main node types:
14//!
15//! 1. [`crate::RedeemNode`] represents a Simplicity node as it exists on the blockchain.
16//!    Every witness node is populated with a correctly-typed [`Value`], every
17//!    disconnect node has a child, every non-executed branch of a `case` combinator
18//!    is pruned, and there is nothing you can do to modify the expression.
19//!
20//!    `RedeemNode`s can be executed on the bit machine and have complete types
21//!    and resource bounds, and can be serialized in the consensus bit-encoding.
22//!
23//! 2. [`CommitNode`] represents a Simplicity node as it is *committed to* on
24//!    the blockchain. This means that witness and (TODO) disconnect nodes are not
25//!    populated, but type inference is complete and resource bounds are
26//!    available. `case` combinators may have pruned children (in which case they
27//!    are instead considered `assertl` or `assertr` combinators), or not.
28//!
29//!    There is a bit-encoding for `CommitNode`s which is essentially only used
30//!    by this library. It consists of the bit-encoding.of the combinators, fully
31//!    shared *except* that witness and disconnect nodes (and their ancestors)
32//!    are unshared. No witness data is included.
33//!
34//!    TODO there is also a human-readable encoding.
35//!
36//! 3. [`ConstructNode`] represents an "under-construction" Simplicity expression.
37//!    These nodes' types are not necessarily complete, and are inferred as the
38//!    program is constructed. This is the only node that you can programmatically
39//!    construct. It has no encoding, human-readable or bitwise, and is intended
40//!    to exist only ephemerally.
41//!
42//! The following conversions are possible between the node types:
43//!
44//! 1. [`ConstructNode::finalize_types`] converts a [`ConstructNode`] to a
45//!    [`CommitNode`] by setting any free variables, as well as the source and
46//!    target of the root node, to unit.
47//!
48//!    This conversion requires no input from the user but may fail with a type
49//!    error, in case of infinitely-sized types or in the case that the unit
50//!    bounds cannot be applied.
51//!
52//! 2. [`CommitNode::finalize`] converts a [`CommitNode`] to a [`RedeemNode`]
53//!    by attaching witnesses to each witness node, and deciding whether to hide
54//!    branches for each `case` node.
55//!
56//! 3. [`CommitNode::unfinalize_types`] converts a [`CommitNode`] to a
57//!    [`ConstructNode`] by throwing away all types and re-inferring them. It
58//!    cannot fail.
59//!
60//! 4. [`RedeemNode::unfinalize`] converts a [`RedeemNode`] to a [`CommitNode`]
61//!    by throwing away witness and (TODO) disconnect data. It cannot recover
62//!    pruned branches so is of limited usefulness, but it is included for
63//!    completeness.
64//!
65
66use crate::dag::{DagLike, MaxSharing, SharingTracker};
67use crate::encode;
68use crate::jet::Jet;
69use crate::{types, BitWriter, Cmr, FailEntropy, HasCmr, Value};
70
71use std::sync::Arc;
72use std::{fmt, hash, io};
73
74mod commit;
75mod construct;
76mod convert;
77mod disconnect;
78mod display;
79mod hiding;
80mod inner;
81mod redeem;
82
83use crate::value::Word;
84pub use commit::{Commit, CommitData, CommitNode};
85pub use construct::{Construct, ConstructData, ConstructNode};
86pub use convert::{Converter, Hide, SimpleFinalizer};
87pub use disconnect::{Disconnectable, NoDisconnect};
88pub use display::{Display, DisplayAsGraph, DisplayExpr, GraphFormat, SharingLevel};
89pub use hiding::Hiding;
90pub use inner::Inner;
91pub use redeem::{Redeem, RedeemData, RedeemNode};
92
93/// Lots of existing code imports [`JetConstructible`] just to get the `jet` method.
94/// Almost all such code also imports [`CoreConstructible`], which now gives them
95/// this method, so this code will continue to work as long as there is something
96/// called [`JetConstructible`] to import.
97#[doc(hidden)]
98#[deprecated(note = "subsumed by CoreConstructible")]
99pub enum JetConstructible {}
100
101// This trait should only be implemented on empty types, so we can demand
102// every trait bound under the sun. Doing so will make #[derive]s easier
103// for downstream users.
104pub trait Marker:
105    Copy + Clone + PartialEq + Eq + PartialOrd + Ord + fmt::Debug + hash::Hash
106{
107    /// Precomputed data about the node, such as its type arrow or various Merkle roots.
108    type CachedData: Clone;
109
110    /// Type of witness data attached to DAGs of this node type. Typically either [`Value`]
111    /// or [`NoWitness`].
112    type Witness: Clone;
113
114    /// Type of disconnect data attached to DAGs of this node type.
115    type Disconnect: Disconnectable<Node<Self>> + Clone;
116
117    /// A type which uniquely identifies a node, for purposes of sharing
118    /// during iteration over the DAG.
119    type SharingId: hash::Hash + Clone + Eq;
120
121    /// Yields the sharing ID for a given type, starting from its CMR and its cached data.
122    ///
123    /// If the type cannot be uniquely identified (e.g. because it is missing data), then
124    /// this method returns `None`. In this case, the node will not be shared with any
125    /// other node.
126    fn compute_sharing_id(cmr: Cmr, cached_data: &Self::CachedData) -> Option<Self::SharingId>;
127}
128
129/// Null data type used as dummy for [`Marker::Witness`]
130#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
131pub struct NoWitness;
132
133impl From<NoWitness> for Option<Value> {
134    fn from(_: NoWitness) -> Self {
135        None
136    }
137}
138
139pub trait Constructible<'brand, X, W>:
140    DisconnectConstructible<'brand, X>
141    + WitnessConstructible<'brand, W>
142    + CoreConstructible<'brand>
143    + Sized
144{
145    fn from_inner(
146        inference_context: &types::Context<'brand>,
147        inner: Inner<&Self, &X, W>,
148    ) -> Result<Self, types::Error> {
149        match inner {
150            Inner::Iden => Ok(Self::iden(inference_context)),
151            Inner::Unit => Ok(Self::unit(inference_context)),
152            Inner::InjL(child) => Ok(Self::injl(child)),
153            Inner::InjR(child) => Ok(Self::injr(child)),
154            Inner::Take(child) => Ok(Self::take(child)),
155            Inner::Drop(child) => Ok(Self::drop_(child)),
156            Inner::Comp(left, right) => Self::comp(left, right),
157            Inner::Case(left, right) => Self::case(left, right),
158            Inner::AssertL(left, r_cmr) => Self::assertl(left, r_cmr),
159            Inner::AssertR(l_cmr, right) => Self::assertr(l_cmr, right),
160            Inner::Pair(left, right) => Self::pair(left, right),
161            Inner::Disconnect(left, right) => Self::disconnect(left, right),
162            Inner::Fail(entropy) => Ok(Self::fail(inference_context, entropy)),
163            Inner::Word(ref w) => Ok(Self::const_word(inference_context, w.shallow_clone())),
164            Inner::Jet(j) => Ok(Self::jet(inference_context, j.as_ref())),
165            Inner::Witness(w) => Ok(Self::witness(inference_context, w)),
166        }
167    }
168}
169
170impl<'brand, X, W, T> Constructible<'brand, X, W> for T where
171    T: DisconnectConstructible<'brand, X>
172        + WitnessConstructible<'brand, W>
173        + CoreConstructible<'brand>
174        + Sized
175{
176}
177
178pub trait CoreConstructible<'brand>: Sized {
179    fn iden(inference_context: &types::Context<'brand>) -> Self;
180    fn unit(inference_context: &types::Context<'brand>) -> Self;
181    fn injl(child: &Self) -> Self;
182    fn injr(child: &Self) -> Self;
183    fn take(child: &Self) -> Self;
184    fn drop_(child: &Self) -> Self;
185    fn comp(left: &Self, right: &Self) -> Result<Self, types::Error>;
186    fn case(left: &Self, right: &Self) -> Result<Self, types::Error>;
187    fn assertl(left: &Self, right: Cmr) -> Result<Self, types::Error>;
188    fn assertr(left: Cmr, right: &Self) -> Result<Self, types::Error>;
189    fn pair(left: &Self, right: &Self) -> Result<Self, types::Error>;
190    fn fail(inference_context: &types::Context<'brand>, entropy: FailEntropy) -> Self;
191    fn const_word(inference_context: &types::Context<'brand>, word: Word) -> Self;
192    fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self;
193
194    /// Accessor for the type inference context used to create the object.
195    #[inline]
196    fn inference_context(&self) -> &types::Context<'brand> {
197        &self.arrow().inference_context
198    }
199    fn arrow(&self) -> &types::Arrow<'brand>;
200
201    /// Create an expression that produces the given `value`.
202    ///
203    /// The expression is minimized by using as many word jets as possible.
204    fn scribe(ctx: &types::Context<'brand>, value: &Value) -> Self {
205        use crate::value::ValueRef;
206
207        #[derive(Debug, Clone)]
208        enum Task<'v> {
209            Process(ValueRef<'v>),
210            MakeLeft,
211            MakeRight,
212            MakeProduct,
213        }
214
215        let mut input = vec![Task::Process(value.as_ref())];
216        let mut output = vec![];
217        while let Some(top) = input.pop() {
218            match top {
219                Task::Process(value) => {
220                    if value.is_unit() {
221                        output.push(Self::unit(ctx));
222                    } else if let Some(word) = value.to_word() {
223                        output.push(Self::const_word(ctx, word));
224                    } else if let Some(left) = value.as_left() {
225                        input.push(Task::MakeLeft);
226                        input.push(Task::Process(left));
227                    } else if let Some(right) = value.as_right() {
228                        input.push(Task::MakeRight);
229                        input.push(Task::Process(right));
230                    } else if let Some((left, right)) = value.as_product() {
231                        input.push(Task::MakeProduct);
232                        input.push(Task::Process(right));
233                        input.push(Task::Process(left));
234                    }
235                }
236                Task::MakeLeft => {
237                    let inner = output.pop().unwrap();
238                    output.push(Self::injl(&inner));
239                }
240                Task::MakeRight => {
241                    let inner = output.pop().unwrap();
242                    output.push(Self::injr(&inner));
243                }
244                Task::MakeProduct => {
245                    let right = output.pop().unwrap();
246                    let left = output.pop().unwrap();
247                    // simfony::PairBuilder would remove this `.expect()` call
248                    output.push(
249                        Self::pair(&left, &right).expect(
250                            "`pair` should always succeed because input type is unrestricted",
251                        ),
252                    );
253                }
254            }
255        }
256        debug_assert_eq!(output.len(), 1);
257        output.pop().unwrap()
258    }
259
260    /// Create a DAG that takes any input and returns bit `0` as constant output.
261    ///
262    /// _Overall type: A → 2_
263    fn bit_false(inference_context: &types::Context<'brand>) -> Self {
264        let unit = Self::unit(inference_context);
265        Self::injl(&unit)
266    }
267
268    /// Create a DAG that takes any input and returns bit `1` as constant output.
269    ///
270    /// _Overall type: A → 2_
271    fn bit_true(inference_context: &types::Context<'brand>) -> Self {
272        let unit = Self::unit(inference_context);
273        Self::injr(&unit)
274    }
275
276    /// Create a DAG that takes a bit and an input,
277    /// such that the `left` child is evaluated on the input if the bit is `1` _(if branch)_
278    /// and the `right` child is evaluated on the input otherwise _(else branch)_.
279    ///
280    /// _Overall type: 2 × A → B where `left`: A → B and `right`: A → B_
281    ///
282    /// _Type inference will fail if children are not of the correct type._
283    fn cond(left: &Self, right: &Self) -> Result<Self, types::Error> {
284        let drop_left = Self::drop_(left);
285        let drop_right = Self::drop_(right);
286        Self::case(&drop_right, &drop_left)
287    }
288
289    /// Create a DAG that asserts that its child returns `true`, and fails otherwise.
290    /// The `hash` identifies the assertion and is returned upon failure.
291    ///
292    /// _Overall type: A → 1 where `child`: A → 2_
293    ///
294    /// _Type inference will fail if children are not of the correct type._
295    fn assert(child: &Self, hash: Cmr) -> Result<Self, types::Error> {
296        let unit = Self::unit(child.inference_context());
297        let pair_child_unit = Self::pair(child, &unit)?;
298        let assertr_hidden_unit = Self::assertr(hash, &unit)?;
299
300        Self::comp(&pair_child_unit, &assertr_hidden_unit)
301    }
302
303    /// Create a DAG that computes Boolean _NOT_ of the `child`.
304    ///
305    /// _Overall type: A → 2 where `child`: A → 2_
306    ///
307    /// _Type inference will fail if children are not of the correct type._
308    #[allow(clippy::should_implement_trait)]
309    fn not(child: &Self) -> Result<Self, types::Error> {
310        let unit = Self::unit(child.inference_context());
311        let pair_child_unit = Self::pair(child, &unit)?;
312        let bit_true = Self::bit_true(child.inference_context());
313        let bit_false = Self::bit_false(child.inference_context());
314        let case_true_false = Self::case(&bit_true, &bit_false)?;
315
316        Self::comp(&pair_child_unit, &case_true_false)
317    }
318
319    /// Create a DAG that computes Boolean _AND_ of the `left` and `right` child.
320    ///
321    /// _Overall type: A → 2 where `left`: A → 2 and `right`: A → 2_
322    ///
323    /// _Type inference will fail if children are not of the correct type._
324    fn and(left: &Self, right: &Self) -> Result<Self, types::Error> {
325        left.inference_context()
326            .check_eq(right.inference_context())?;
327        let iden = Self::iden(left.inference_context());
328        let pair_left_iden = Self::pair(left, &iden)?;
329        let bit_false = Self::bit_false(left.inference_context());
330        let drop_right = Self::drop_(right);
331        let case_false_right = Self::case(&bit_false, &drop_right)?;
332
333        Self::comp(&pair_left_iden, &case_false_right)
334    }
335
336    /// Create a DAG that computes Boolean _OR_ of the `left` and `right`.
337    ///
338    /// _Overall type: A → 2 where `left`: A → 2 and `right`: A → 2_
339    ///
340    /// _Type inference will fail if children are not of the correct type._
341    fn or(left: &Self, right: &Self) -> Result<Self, types::Error> {
342        left.inference_context()
343            .check_eq(right.inference_context())?;
344        let iden = Self::iden(left.inference_context());
345        let pair_left_iden = Self::pair(left, &iden)?;
346        let drop_right = Self::drop_(right);
347        let bit_true = Self::bit_true(left.inference_context());
348        let case_right_true = Self::case(&drop_right, &bit_true)?;
349
350        Self::comp(&pair_left_iden, &case_right_true)
351    }
352}
353
354pub trait DisconnectConstructible<'brand, X>: Sized {
355    fn disconnect(left: &Self, right: &X) -> Result<Self, types::Error>;
356}
357
358pub trait WitnessConstructible<'brand, W>: Sized {
359    fn witness(inference_context: &types::Context<'brand>, witness: W) -> Self;
360}
361
362/// A node in a Simplicity expression.
363///
364/// There are three node types provided by this library: `ConstructNode`, `CommitNode`,
365/// and `RedeemNode`, which represent Simplicty programs during construction, at
366/// commitment time, and at redemption time, respectively.
367///
368/// This generic structure is used to define conversions and mapping functions over
369/// nodes and DAGs, and allows users to define their own custom node types.
370///
371/// For equality and hashing purposes, nodes are characterized entirely by their
372/// CMR and cached data. Users who create custom nodes should define a custom type
373/// for [`Marker::CachedData`] and think carefully about whether and how to
374/// implement the [`std::hash::Hash`] or equality traits.
375pub struct Node<N: Marker> {
376    inner: Inner<Arc<Node<N>>, N::Disconnect, N::Witness>,
377    cmr: Cmr,
378    data: N::CachedData,
379}
380
381impl<N: Marker> PartialEq for Node<N>
382where
383    N::CachedData: PartialEq,
384{
385    fn eq(&self, other: &Self) -> bool {
386        self.cmr == other.cmr && self.data == other.data
387    }
388}
389impl<N: Marker> Eq for Node<N> where N::CachedData: Eq {}
390
391impl<N: Marker> hash::Hash for Node<N>
392where
393    N::CachedData: hash::Hash,
394{
395    fn hash<H: hash::Hasher>(&self, h: &mut H) {
396        self.cmr.hash(h);
397        self.data.hash(h);
398    }
399}
400
401impl<N: Marker> fmt::Debug for Node<N>
402where
403    for<'a> &'a Node<N>: DagLike,
404{
405    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406        self.post_order_iter::<MaxSharing<N>>().into_display(
407            f,
408            |node, f| fmt::Display::fmt(&node.inner, f),
409            |_, _| Ok(()),
410        )
411    }
412}
413
414#[cfg(feature = "base64")]
415impl<N: Marker> fmt::Display for Node<N> {
416    /// Displays the program data in base64.
417    ///
418    /// If you need witness data as well, then use [`Node::display`].
419    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
420        use crate::base64::display::Base64Display;
421        use crate::base64::engine::general_purpose;
422
423        let v = self.to_vec_without_witness();
424        Base64Display::new(&v, &general_purpose::STANDARD).fmt(f)
425    }
426}
427
428impl<N: Marker> HasCmr for Node<N> {
429    fn cmr(&self) -> Cmr {
430        self.cmr
431    }
432}
433
434impl<N: Marker> HasCmr for Arc<Node<N>> {
435    fn cmr(&self) -> Cmr {
436        self.cmr
437    }
438}
439
440impl<'brand, N> CoreConstructible<'brand> for Arc<Node<N>>
441where
442    N: Marker,
443    N::CachedData: CoreConstructible<'brand>,
444{
445    fn iden(inference_context: &types::Context<'brand>) -> Self {
446        Arc::new(Node {
447            cmr: Cmr::iden(),
448            data: N::CachedData::iden(inference_context),
449            inner: Inner::Iden,
450        })
451    }
452
453    fn unit(inference_context: &types::Context<'brand>) -> Self {
454        Arc::new(Node {
455            cmr: Cmr::unit(),
456            data: N::CachedData::unit(inference_context),
457            inner: Inner::Unit,
458        })
459    }
460
461    fn injl(child: &Self) -> Self {
462        Arc::new(Node {
463            cmr: Cmr::injl(child.cmr()),
464            data: N::CachedData::injl(&child.data),
465            inner: Inner::InjL(Arc::clone(child)),
466        })
467    }
468
469    fn injr(child: &Self) -> Self {
470        Arc::new(Node {
471            cmr: Cmr::injr(child.cmr()),
472            data: N::CachedData::injr(&child.data),
473            inner: Inner::InjR(Arc::clone(child)),
474        })
475    }
476
477    fn take(child: &Self) -> Self {
478        Arc::new(Node {
479            cmr: Cmr::take(child.cmr()),
480            data: N::CachedData::take(&child.data),
481            inner: Inner::Take(Arc::clone(child)),
482        })
483    }
484
485    fn drop_(child: &Self) -> Self {
486        Arc::new(Node {
487            cmr: Cmr::drop(child.cmr()),
488            data: N::CachedData::drop_(&child.data),
489            inner: Inner::Drop(Arc::clone(child)),
490        })
491    }
492
493    fn comp(left: &Self, right: &Self) -> Result<Self, types::Error> {
494        Ok(Arc::new(Node {
495            cmr: Cmr::comp(left.cmr(), right.cmr()),
496            data: N::CachedData::comp(&left.data, &right.data)?,
497            inner: Inner::Comp(Arc::clone(left), Arc::clone(right)),
498        }))
499    }
500
501    fn case(left: &Self, right: &Self) -> Result<Self, types::Error> {
502        Ok(Arc::new(Node {
503            cmr: Cmr::case(left.cmr(), right.cmr()),
504            data: N::CachedData::case(&left.data, &right.data)?,
505            inner: Inner::Case(Arc::clone(left), Arc::clone(right)),
506        }))
507    }
508
509    fn assertl(left: &Self, r_cmr: Cmr) -> Result<Self, types::Error> {
510        Ok(Arc::new(Node {
511            cmr: Cmr::case(left.cmr(), r_cmr),
512            data: N::CachedData::assertl(&left.data, r_cmr)?,
513            inner: Inner::AssertL(Arc::clone(left), r_cmr),
514        }))
515    }
516
517    fn assertr(l_cmr: Cmr, right: &Self) -> Result<Self, types::Error> {
518        Ok(Arc::new(Node {
519            cmr: Cmr::case(l_cmr, right.cmr()),
520            data: N::CachedData::assertr(l_cmr, &right.data)?,
521            inner: Inner::AssertR(l_cmr, Arc::clone(right)),
522        }))
523    }
524
525    fn pair(left: &Self, right: &Self) -> Result<Self, types::Error> {
526        Ok(Arc::new(Node {
527            cmr: Cmr::pair(left.cmr(), right.cmr()),
528            data: N::CachedData::pair(&left.data, &right.data)?,
529            inner: Inner::Pair(Arc::clone(left), Arc::clone(right)),
530        }))
531    }
532
533    fn fail(inference_context: &types::Context<'brand>, entropy: FailEntropy) -> Self {
534        Arc::new(Node {
535            cmr: Cmr::fail(entropy),
536            data: N::CachedData::fail(inference_context, entropy),
537            inner: Inner::Fail(entropy),
538        })
539    }
540
541    fn const_word(inference_context: &types::Context<'brand>, word: Word) -> Self {
542        Arc::new(Node {
543            cmr: Cmr::const_word(&word),
544            data: N::CachedData::const_word(inference_context, word.shallow_clone()),
545            inner: Inner::Word(word),
546        })
547    }
548
549    fn jet(inference_context: &types::Context<'brand>, jet: &dyn Jet) -> Self {
550        Arc::new(Node {
551            cmr: Cmr::jet(jet),
552            data: N::CachedData::jet(inference_context, jet),
553            inner: Inner::Jet(jet.dyn_clone()),
554        })
555    }
556
557    fn arrow(&self) -> &types::Arrow<'brand> {
558        self.data.arrow()
559    }
560}
561
562impl<'brand, N> DisconnectConstructible<'brand, N::Disconnect> for Arc<Node<N>>
563where
564    N: Marker,
565    N::CachedData: DisconnectConstructible<'brand, N::Disconnect>,
566{
567    fn disconnect(left: &Self, right: &N::Disconnect) -> Result<Self, types::Error> {
568        Ok(Arc::new(Node {
569            cmr: Cmr::disconnect(left.cmr()),
570            data: N::CachedData::disconnect(&left.data, right)?,
571            inner: Inner::Disconnect(Arc::clone(left), right.clone()),
572        }))
573    }
574}
575
576impl<'brand, N> WitnessConstructible<'brand, N::Witness> for Arc<Node<N>>
577where
578    N: Marker,
579    N::CachedData: WitnessConstructible<'brand, N::Witness>,
580{
581    fn witness(inference_context: &types::Context<'brand>, value: N::Witness) -> Self {
582        Arc::new(Node {
583            cmr: Cmr::witness(),
584            data: N::CachedData::witness(inference_context, value.clone()),
585            inner: Inner::Witness(value),
586        })
587    }
588}
589
590impl<N: Marker> Node<N> {
591    /// Accessor for the node's "inner value", i.e. its combinator
592    pub fn inner(&self) -> &Inner<Arc<Node<N>>, N::Disconnect, N::Witness> {
593        &self.inner
594    }
595
596    /// Accessor for the node's CMR
597    pub fn cmr(&self) -> Cmr {
598        self.cmr
599    }
600
601    /// Accessor for the node's cached data
602    pub fn sharing_id(&self) -> Option<N::SharingId> {
603        N::compute_sharing_id(self.cmr, &self.data)
604    }
605
606    /// Accessor for the node's cached data
607    pub fn cached_data(&self) -> &N::CachedData {
608        &self.data
609    }
610
611    /// Contruct a node from its constituent parts.
612    ///
613    /// This method can be used to directly costruct a node. It will compute the CMR
614    /// automatically based on the value of `inner` but requires that `cached_data`
615    /// be provided.
616    ///
617    /// If available, [`Constructible`] and its dependent traits will be easier to
618    /// use.
619    pub fn from_parts(
620        inner: Inner<Arc<Self>, N::Disconnect, N::Witness>,
621        data: N::CachedData,
622    ) -> Self {
623        let cmr = match &inner {
624            Inner::Unit => Cmr::unit(),
625            Inner::Iden => Cmr::iden(),
626            Inner::InjL(ref c) => Cmr::injl(c.cmr()),
627            Inner::InjR(ref c) => Cmr::injr(c.cmr()),
628            Inner::Take(ref c) => Cmr::take(c.cmr()),
629            Inner::Drop(ref c) => Cmr::drop(c.cmr()),
630            Inner::Comp(ref cl, ref cr) => Cmr::comp(cl.cmr(), cr.cmr()),
631            Inner::Case(ref cl, ref cr) => Cmr::case(cl.cmr(), cr.cmr()),
632            Inner::AssertL(ref c, cmr) => Cmr::case(c.cmr(), *cmr),
633            Inner::AssertR(cmr, ref c) => Cmr::case(*cmr, c.cmr()),
634            Inner::Pair(ref cl, ref cr) => Cmr::pair(cl.cmr(), cr.cmr()),
635            Inner::Disconnect(ref cl, _) => Cmr::disconnect(cl.cmr()),
636            Inner::Witness(_) => Cmr::witness(),
637            Inner::Fail(entropy) => Cmr::fail(*entropy),
638            Inner::Jet(j) => Cmr::jet(j.as_ref()),
639            Inner::Word(ref w) => Cmr::const_word(w),
640        };
641
642        Node { cmr, inner, data }
643    }
644
645    /// Generic conversion function from one type of node to another, with the
646    /// ability to prune during the conversion.
647    ///
648    /// Parameterized over what kind of sharing to use when iterating over the
649    /// DAG, and what conversion logic to use.
650    ///
651    /// See the documentation for [`Converter`] for details.
652    pub fn convert<S, M, C>(&self, converter: &mut C) -> Result<Arc<Node<M>>, C::Error>
653    where
654        S: for<'a> SharingTracker<&'a Self> + Default,
655        M: Marker,
656        C: Converter<N, M>,
657    {
658        let mut converted: Vec<Arc<Node<M>>> = vec![];
659        for data in self.post_order_iter::<S>() {
660            // First, tell the converter about the iterator state..
661            converter.visit_node(&data);
662
663            // Construct an Inner<usize> where pointers are replaced by indices.
664            // Note that `map_left_right`'s internal logic will ensure that these
665            // `unwrap`s are only called when they will succeed.
666            let indexed_inner: Inner<usize, &N::Disconnect, &N::Witness> = data
667                .node
668                .inner
669                .as_ref()
670                .map_left_right(|_| data.left_index.unwrap(), |_| data.right_index.unwrap());
671
672            // Then, convert witness data, if this is a witness node.
673            let witness_inner: Inner<&usize, &&N::Disconnect, M::Witness> = indexed_inner
674                .as_ref()
675                .map_witness_result(|wit| converter.convert_witness(&data, wit))?;
676
677            // Then convert disconnect nodes data.
678            let maybe_converted = data.right_index.map(|idx| &converted[idx]);
679            let witness_inner: Inner<&usize, M::Disconnect, M::Witness> = witness_inner
680                .map_disconnect_result(|disc| {
681                    converter.convert_disconnect(&data, maybe_converted, disc)
682                })?;
683
684            // Then put the converted nodes in place (it's easier to do this in this
685            // order because of the way the reference types work out).
686            let converted_inner: Inner<Arc<Node<M>>, M::Disconnect, M::Witness> =
687                witness_inner.map(|idx| Arc::clone(&converted[*idx]));
688
689            // Next, prune case nodes into asserts, if applicable
690            let pruned_inner = if let Inner::Case(left, right) = converted_inner {
691                let hide = converter.prune_case(&data, &left, &right)?;
692
693                match hide {
694                    Hide::Neither => Inner::Case(left, right),
695                    Hide::Left => Inner::AssertR(left.cmr(), right),
696                    Hide::Right => Inner::AssertL(left, right.cmr()),
697                }
698            } else {
699                converted_inner
700            };
701
702            // Finally, construct the node
703            converted.push(Arc::new(Node {
704                data: converter.convert_data(&data, pruned_inner.as_ref())?,
705                cmr: data.node.cmr,
706                inner: pruned_inner,
707            }));
708        }
709        Ok(converted.pop().unwrap())
710    }
711
712    pub fn display(&self) -> Display<'_, N> {
713        Display::from(self)
714    }
715
716    /// Display the Simplicity expression as a linear string.
717    ///
718    /// The linear string has no sharing and may be **exponentially larger**
719    /// than the originally shared expression!
720    pub fn display_expr(&self) -> DisplayExpr<'_, N> {
721        DisplayExpr::from(self)
722    }
723
724    /// Display the Simplicity expression as a graph in the given format and sharing level.
725    ///
726    /// This is the general form of [`display_as_dot`](Node::display_as_dot) and
727    /// [`display_as_mermaid`](Node::display_as_mermaid). Use those convenience methods for
728    /// the common case of DOT or Mermaid output with no sharing.
729    ///
730    /// The `format` field of the returned [`DisplayAsGraph`] can be changed after construction,
731    /// and the [`fmt::Display`] impl will use whatever `format` and `sharing` are set at that
732    /// point. See also [`DisplayAsGraph::to_dot_string`] and [`DisplayAsGraph::to_mermaid_string`]
733    /// to render to a specific format regardless of the stored `format` field.
734    pub fn display_as_graph(
735        &self,
736        format: GraphFormat,
737        sharing_level: SharingLevel,
738    ) -> DisplayAsGraph<'_, N> {
739        DisplayAsGraph::new(self, format, sharing_level)
740    }
741
742    /// Display the Simplicity expression as a Graphviz DOT graph.
743    ///
744    /// The DOT output can be rendered with `dot -Tsvg` or similar tools.
745    /// Shared nodes appear once in the graph with multiple incoming edges.
746    pub fn display_as_dot(&self) -> DisplayAsGraph<'_, N> {
747        DisplayAsGraph::new(self, GraphFormat::Dot, SharingLevel::None)
748    }
749
750    /// Display the Simplicity expression as a Mermaid diagram.
751    ///
752    /// The Mermaid output can be rendered in Markdown or the Mermaid live editor.
753    /// Shared nodes appear once in the diagram with multiple incoming edges.
754    pub fn display_as_mermaid(&self) -> DisplayAsGraph<'_, N> {
755        DisplayAsGraph::new(self, GraphFormat::Mermaid, SharingLevel::None)
756    }
757
758    /// Encode a Simplicity expression to bits without any witness data.
759    pub fn encode_without_witness(&self, prog: &mut dyn io::Write) -> io::Result<usize> {
760        let mut w = BitWriter::new(prog);
761        let program_bits = encode::encode_program(self, &mut w)?;
762        w.flush_all()?;
763        Ok(program_bits)
764    }
765
766    /// Encode a Simplicity expression to a vector of bytes, without any witness data.
767    pub fn to_vec_without_witness(&self) -> Vec<u8> {
768        let mut program = Vec::<u8>::new();
769        self.encode_without_witness(&mut program)
770            .expect("Vec::write is infallible");
771        debug_assert!(!program.is_empty());
772        program
773    }
774}
775
776impl<N: Marker<Witness = Value>> Node<N> {
777    /// Encode the program and witness data to bits.
778    ///
779    /// Returns the number of written bits for the program and witness, respectively.
780    pub fn encode_with_witness(
781        &self,
782        prog: &mut dyn io::Write,
783        witness: &mut dyn io::Write,
784    ) -> io::Result<(usize, usize)> {
785        let mut prog = BitWriter::new(prog);
786        let mut witness = BitWriter::new(witness);
787
788        let sharing_iter = self.post_order_iter::<MaxSharing<N>>();
789        let program_bits = encode::encode_program(self, &mut prog)?;
790        prog.flush_all()?;
791        let witness_bits = encode::encode_witness(sharing_iter.into_witnesses(), &mut witness)?;
792        witness.flush_all()?;
793        Ok((program_bits, witness_bits))
794    }
795
796    /// Encode the program and witness data to byte vectors.
797    pub fn to_vec_with_witness(&self) -> (Vec<u8>, Vec<u8>) {
798        let mut ret_1 = vec![];
799        let mut ret_2 = vec![];
800        self.encode_with_witness(&mut ret_1, &mut ret_2)
801            .expect("Vec::write is infallible");
802        (ret_1, ret_2)
803    }
804}
805
806impl<N: Marker> Drop for Node<N> {
807    fn drop(&mut self) {
808        // Note: this is basically identical to the drop impl for types::Incomplete.
809        fn push_children<N: Marker>(
810            stack: &mut Vec<Arc<Node<N>>>,
811            inner: Inner<Arc<Node<N>>, N::Disconnect, N::Witness>,
812        ) {
813            use crate::dag::Dag;
814            match inner.into_dag() {
815                Dag::Nullary => {}
816                Dag::Unary(child) => stack.push(child),
817                Dag::Binary(left, right) => {
818                    stack.push(left);
819                    stack.push(right);
820                }
821            }
822        }
823
824        let mut stack = Vec::new();
825        push_children(&mut stack, std::mem::replace(&mut self.inner, Inner::Unit));
826        while let Some(child) = stack.pop() {
827            if let Some(mut child) = Arc::into_inner(child) {
828                push_children(&mut stack, std::mem::replace(&mut child.inner, Inner::Unit));
829            }
830        }
831    }
832}
833
834#[cfg(test)]
835#[cfg(all(feature = "test-utils", feature = "elements"))]
836mod tests {
837    use ffi::tests::TestData;
838
839    use crate::analysis::Cost;
840    use crate::ffi;
841    use crate::jet::Elements;
842    use crate::BitIter;
843    use crate::RedeemNode;
844
845    fn check_merkle_roots(test: &TestData) {
846        let prog = BitIter::from(test.prog.as_slice());
847        let witness = BitIter::from(test.witness.as_slice());
848        ffi::tests::run_program(
849            &test.prog,
850            &test.witness,
851            ffi::tests::TestUpTo::CheckOneOne,
852            None,
853            None,
854        )
855        .unwrap();
856        let prog = RedeemNode::decode::<_, _, Elements>(prog, witness).unwrap();
857        assert_eq!(prog.cmr().to_byte_array(), test.cmr);
858        assert_eq!(prog.amr().to_byte_array(), test.amr);
859        assert_eq!(prog.ihr().to_byte_array(), test.ihr);
860        assert_eq!(prog.bounds().cost, Cost::from_milliweight(test.cost))
861    }
862
863    #[test]
864    fn progs_cmr() {
865        let schnorr0 = ffi::tests::schnorr0_test_data();
866        let schnorr6 = ffi::tests::schnorr6_test_data();
867        let ctx8_unpruned = ffi::tests::ctx8_unpruned_test_data();
868        let ctx8_pruned = ffi::tests::ctx8_pruned_test_data();
869        // check_merkle_roots(&hash_block); Need 1 -> 1 for now.
870        check_merkle_roots(&schnorr0);
871        check_merkle_roots(&schnorr6);
872        check_merkle_roots(&ctx8_unpruned);
873        check_merkle_roots(&ctx8_pruned);
874    }
875}