diff --git a/src/bit_encoding/decode.rs b/src/bit_encoding/decode.rs index df98fb2d..c586e3e3 100644 --- a/src/bit_encoding/decode.rs +++ b/src/bit_encoding/decode.rs @@ -9,7 +9,7 @@ use crate::dag::{Dag, DagLike, InternalSharing}; use crate::jet::Jet; use crate::merkle::cmr::Cmr; use crate::node::{ - ConstructNode, CoreConstructible, DisconnectConstructible, JetConstructible, NoWitness, + ConstructNode, CoreConstructible, DisconnectConstructible, JetConstructible, WitnessConstructible, }; use crate::types; @@ -235,7 +235,7 @@ pub fn decode_expression, J: Jet>( converted[i].get()?, &Some(Arc::clone(converted[j].get()?)), )?), - DecodeNode::Witness => Node(ArcNode::witness(&inference_context, NoWitness)), + DecodeNode::Witness => Node(ArcNode::witness(&inference_context, None)), DecodeNode::Fail(entropy) => Node(ArcNode::fail(&inference_context, entropy)), DecodeNode::Hidden(cmr) => { if !hidden_set.insert(cmr) { diff --git a/src/human_encoding/mod.rs b/src/human_encoding/mod.rs index 30efb63d..66f5f570 100644 --- a/src/human_encoding/mod.rs +++ b/src/human_encoding/mod.rs @@ -13,7 +13,7 @@ mod parse; use crate::dag::{DagLike, MaxSharing}; use crate::jet::Jet; use crate::node::{self, CommitNode, NoWitness}; -use crate::{Cmr, Imr, Value, WitnessNode}; +use crate::{Cmr, ConstructNode, Imr, Value}; use std::collections::HashMap; use std::str; @@ -213,9 +213,9 @@ impl Forest { pub fn to_witness_node( &self, witness: &HashMap, Value>, - ) -> Option>> { + ) -> Option>> { let main = self.roots.get("main")?; - Some(main.to_witness_node(witness, self.roots())) + Some(main.to_construct_node(witness, self.roots())) } } diff --git a/src/human_encoding/named_node.rs b/src/human_encoding/named_node.rs index e1bb9e7e..dddf4c8b 100644 --- a/src/human_encoding/named_node.rs +++ b/src/human_encoding/named_node.rs @@ -6,13 +6,12 @@ use crate::dag::{InternalSharing, MaxSharing, PostOrderIterItem}; use crate::human_encoding::{Error, ErrorSet, Position, WitnessOrHole}; use crate::jet::Jet; use crate::node::{ - self, Commit, CommitData, CommitNode, Converter, Inner, NoDisconnect, NoWitness, Node, Witness, - WitnessData, + self, Commit, CommitData, CommitNode, Construct, ConstructData, Constructible as _, Converter, + CoreConstructible as _, Inner, NoDisconnect, NoWitness, Node, }; -use crate::node::{Construct, ConstructData, Constructible as _, CoreConstructible as _}; use crate::types; use crate::types::arrow::{Arrow, FinalArrow}; -use crate::{encode, Value, WitnessNode}; +use crate::{encode, ConstructNode, Value}; use crate::{BitWriter, Cmr, Imr}; use std::collections::HashMap; @@ -108,11 +107,11 @@ impl NamedCommitNode { .unwrap() } - pub fn to_witness_node( + pub fn to_construct_node( &self, witness: &HashMap, Value>, disconnect: &HashMap, Arc>>, - ) -> Arc> { + ) -> Arc> { struct Populator<'a, J: Jet> { witness_map: &'a HashMap, Value>, disconnect_map: &'a HashMap, Arc>>, @@ -120,7 +119,7 @@ impl NamedCommitNode { phantom: PhantomData, } - impl Converter>, Witness> for Populator<'_, J> { + impl Converter>, Construct> for Populator<'_, J> { type Error = (); fn convert_witness( @@ -140,9 +139,9 @@ impl NamedCommitNode { fn convert_disconnect( &mut self, data: &PostOrderIterItem<&Node>>>, - maybe_converted: Option<&Arc>>>, + maybe_converted: Option<&Arc>>>, _: &Arc, - ) -> Result>>>, Self::Error> { + ) -> Result>>>, Self::Error> { if let Some(converted) = maybe_converted { Ok(Some(converted.clone())) } else { @@ -172,16 +171,16 @@ impl NamedCommitNode { &mut self, _: &PostOrderIterItem<&Node>>>, inner: Inner< - &Arc>>, + &Arc>>, J, - &Option>>, + &Option>>, &Option, >, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { let inner = inner .map(|node| node.cached_data()) .map_witness(|maybe_value| maybe_value.clone()); - Ok(WitnessData::from_inner(&self.inference_context, inner) + Ok(ConstructData::from_inner(&self.inference_context, inner) .expect("types are already finalized")) } } @@ -260,7 +259,7 @@ impl NamedConstructNode { .as_ref() .map(|data| &data.cached_data().internal) .map_disconnect(|_| &None) - .map_witness(|_| NoWitness), + .map_witness(|_| None), )?; let named_data = NamedConstructData { internal: construct_data, diff --git a/src/human_encoding/parse/mod.rs b/src/human_encoding/parse/mod.rs index 26db5f0c..36af63b2 100644 --- a/src/human_encoding/parse/mod.rs +++ b/src/human_encoding/parse/mod.rs @@ -591,7 +591,7 @@ mod tests { assert_eq!(main.cmr().to_string(), cmr); let program = main - .to_witness_node(witness, &forest) + .to_construct_node(witness, &forest) .finalize_unpruned() .expect("finalize"); diff --git a/src/lib.rs b/src/lib.rs index eb883cf7..785bce82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,7 @@ pub use crate::merkle::{ tmr::Tmr, FailEntropy, HasCmr, }; -pub use crate::node::{CommitNode, ConstructNode, Hiding, RedeemNode, WitnessNode}; +pub use crate::node::{CommitNode, ConstructNode, Hiding, RedeemNode}; pub use crate::value::{Value, Word}; pub use simplicity_sys as ffi; use std::fmt; @@ -88,8 +88,6 @@ pub enum Error { Type(types::Error), // Execution error Execution(bit_machine::ExecutionError), - /// Witness iterator ended early - NoMoreWitnesses, /// Tried to parse a jet but the name wasn't recognized InvalidJetName(String), /// Policy error @@ -107,7 +105,6 @@ impl fmt::Display for Error { Error::Type(ref e) => fmt::Display::fmt(e, f), Error::Execution(ref e) => fmt::Display::fmt(e, f), Error::InvalidJetName(s) => write!(f, "unknown jet `{}`", s), - Error::NoMoreWitnesses => f.write_str("no more witness data available"), #[cfg(feature = "elements")] Error::Policy(ref e) => fmt::Display::fmt(e, f), } @@ -121,7 +118,6 @@ impl std::error::Error for Error { Error::DisconnectRedeemTime => None, Error::Type(ref e) => Some(e), Error::Execution(ref e) => Some(e), - Error::NoMoreWitnesses => None, Error::InvalidJetName(..) => None, #[cfg(feature = "elements")] Error::Policy(ref e) => Some(e), diff --git a/src/node/commit.rs b/src/node/commit.rs index 952c6c04..561a7bba 100644 --- a/src/node/commit.rs +++ b/src/node/commit.rs @@ -3,7 +3,7 @@ use crate::dag::{DagLike, MaxSharing, NoSharing, PostOrderIterItem}; use crate::jet::Jet; use crate::types::arrow::{Arrow, FinalArrow}; -use crate::{encode, types}; +use crate::{encode, types, Value}; use crate::{Amr, BitIter, BitWriter, Cmr, Error, FirstPassImr, Imr}; use super::{ @@ -213,8 +213,8 @@ impl CommitNode { &mut self, _: &PostOrderIterItem<&CommitNode>, _: &NoWitness, - ) -> Result { - Ok(NoWitness) + ) -> Result, Self::Error> { + Ok(None) } fn convert_disconnect( @@ -229,7 +229,12 @@ impl CommitNode { fn convert_data( &mut self, _: &PostOrderIterItem<&CommitNode>, - inner: Inner<&Arc>, J, &Option>>, &NoWitness>, + inner: Inner< + &Arc>, + J, + &Option>>, + &Option, + >, ) -> Result, Self::Error> { let inner = inner .map(|node| node.arrow()) diff --git a/src/node/construct.rs b/src/node/construct.rs index a45b9780..ec7ef937 100644 --- a/src/node/construct.rs +++ b/src/node/construct.rs @@ -1,18 +1,17 @@ // SPDX-License-Identifier: CC0-1.0 use crate::dag::{InternalSharing, PostOrderIterItem}; -use crate::encode; use crate::jet::Jet; use crate::types::{self, arrow::Arrow}; -use crate::{BitIter, BitWriter, Cmr, FailEntropy}; +use crate::{encode, BitIter, BitWriter, Cmr, FailEntropy, RedeemNode, Value, Word}; -use crate::value::Word; use std::io; use std::marker::PhantomData; use std::sync::Arc; use super::{ Commit, CommitData, CommitNode, Converter, Inner, Marker, NoDisconnect, NoWitness, Node, + Redeem, RedeemData, }; use super::{CoreConstructible, DisconnectConstructible, JetConstructible, WitnessConstructible}; @@ -33,7 +32,7 @@ pub struct Construct { impl Marker for Construct { type CachedData = ConstructData; - type Witness = NoWitness; + type Witness = Option; type Disconnect = Option>>; type SharingId = ConstructId; type Jet = J; @@ -90,7 +89,7 @@ impl ConstructNode { fn convert_witness( &mut self, _: &PostOrderIterItem<&ConstructNode>, - _: &NoWitness, + _: &Option, ) -> Result { Ok(NoWitness) } @@ -119,6 +118,104 @@ impl ConstructNode { self.convert::(&mut FinalizeTypes(PhantomData)) } + /// Finalize the witness program as an unpruned redeem program. + /// + /// Witness nodes must be populated with sufficient data, + /// to ensure that the resulting redeem program successfully runs on the Bit Machine. + /// Furthermore, **all** disconnected branches must be populated, + /// even those that are not executed. + /// + /// The resulting redeem program is **not pruned**. + /// + /// ## See + /// + /// [`RedeemNode::prune`] + pub fn finalize_unpruned(&self) -> Result>, crate::Error> { + struct Finalizer(PhantomData); + + impl Converter, Redeem> for Finalizer { + type Error = crate::Error; + + fn convert_witness( + &mut self, + data: &PostOrderIterItem<&ConstructNode>, + wit: &Option, + ) -> Result { + if let Some(ref wit) = wit { + Ok(wit.shallow_clone()) + } else { + // We insert a zero value into unpopulated witness nodes, + // assuming that this node will later be pruned out of the program. + // + // Pruning requires running a program on the Bit Machine, + // which in turn requires a program with fully populated witness nodes. + // It would be horrible UX to force the caller to provide witness data + // even for unexecuted branches, so we insert zero values here. + // + // If this node is executed after all, then the caller can fix the witness + // data based on the returned execution error. + // + // Zero values may "accidentally" satisfy a program even if the caller + // didn't provide any witness data. However, this is only the case for the + // most trivial programs. The only place where we must be careful is our + // unit tests, which tend to include these kinds of trivial programs. + let ty = data.node.arrow().target.finalize()?; + Ok(Value::zero(&ty)) + } + } + + fn convert_disconnect( + &mut self, + _: &PostOrderIterItem<&ConstructNode>, + maybe_converted: Option<&Arc>>, + _: &Option>>, + ) -> Result>, Self::Error> { + if let Some(child) = maybe_converted { + Ok(Arc::clone(child)) + } else { + Err(crate::Error::DisconnectRedeemTime) + } + } + + fn convert_data( + &mut self, + data: &PostOrderIterItem<&ConstructNode>, + inner: Inner<&Arc>, J, &Arc>, &Value>, + ) -> Result>, Self::Error> { + let converted_data = inner + .map(|node| node.cached_data()) + .map_disconnect(|node| node.cached_data()) + .map_witness(Value::shallow_clone); + Ok(Arc::new(RedeemData::new( + data.node.arrow().finalize()?, + converted_data, + ))) + } + } + + self.convert::(&mut Finalizer(PhantomData)) + } + + /// Finalize the witness program as a pruned redeem program. + /// + /// Witness nodes must be populated with sufficient data, + /// to ensure that the resulting redeem program successfully runs on the Bit Machine. + /// Furthermore, **all** disconnected branches must be populated, + /// even those that are not executed. + /// + /// The resulting redeem program is **pruned** based on the given transaction environment. + /// + /// ## See + /// + /// [`RedeemNode::prune`] + pub fn finalize_pruned( + &self, + env: &J::Environment, + ) -> Result>, crate::Error> { + let unpruned = self.finalize_unpruned()?; + unpruned.prune(env).map_err(crate::Error::Execution) + } + /// Decode a Simplicity expression from bits, without witness data. /// /// # Usage @@ -278,10 +375,10 @@ impl DisconnectConstructible>>> for Construc } } -impl WitnessConstructible for ConstructData { - fn witness(inference_context: &types::Context, witness: NoWitness) -> Self { +impl WitnessConstructible> for ConstructData { + fn witness(inference_context: &types::Context, _witness: Option) -> Self { ConstructData { - arrow: Arrow::witness(inference_context, witness), + arrow: Arrow::witness(inference_context, NoWitness), phantom: PhantomData, } } @@ -340,7 +437,7 @@ mod tests { fn occurs_check_3() { let ctx = types::Context::new(); // A similar example that caused a slightly different deadlock in the past. - let wit = Arc::>::witness(&ctx, NoWitness); + let wit = Arc::>::witness(&ctx, None); let drop = Arc::>::drop_(&wit); let comp1 = Arc::>::comp(&drop, &drop).unwrap(); diff --git a/src/node/convert.rs b/src/node/convert.rs index 8180b4d5..f6a9b9bd 100644 --- a/src/node/convert.rs +++ b/src/node/convert.rs @@ -152,6 +152,10 @@ pub trait Converter { /// Does not do any type-checking and may attach an invalid witness to a combinator. /// /// If it encounters a disconnect node, it simply returns an error. +/// +/// **This finalizer should not be used in production. +/// It introduces default values ([`Value::zero`]) to handle missing witness data, +/// which might trigger unexpected spending paths.** // FIXME we should do type checking, but this would require a method to check // type compatibility between a Value and a type::Final. pub struct SimpleFinalizer> { @@ -169,10 +173,13 @@ impl, J: Jet> Converter, Redeem> for Simp fn convert_witness( &mut self, - _: &PostOrderIterItem<&CommitNode>, + data: &PostOrderIterItem<&CommitNode>, _: &NoWitness, ) -> Result { - self.iter.next().ok_or(crate::Error::NoMoreWitnesses) + Ok(self + .iter + .next() + .unwrap_or_else(|| Value::zero(&data.node.arrow().target))) } fn convert_disconnect( diff --git a/src/node/mod.rs b/src/node/mod.rs index 14e82fbf..02f584a8 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -78,7 +78,6 @@ mod display; mod hiding; mod inner; mod redeem; -mod witness; use crate::value::Word; pub use commit::{Commit, CommitData, CommitNode}; @@ -89,7 +88,6 @@ use display::DisplayExpr; pub use hiding::Hiding; pub use inner::Inner; pub use redeem::{Redeem, RedeemData, RedeemNode}; -pub use witness::{Witness, WitnessData, WitnessNode}; // This trait should only be implemented on empty types, so we can demand // every trait bound under the sun. Doing so will make #[derive]s easier diff --git a/src/node/redeem.rs b/src/node/redeem.rs index 570dcaa1..1f2a3d25 100644 --- a/src/node/redeem.rs +++ b/src/node/redeem.rs @@ -5,12 +5,12 @@ use crate::bit_machine::{ExecutionError, SetTracker}; use crate::dag::{DagLike, InternalSharing, MaxSharing, PostOrderIterItem}; use crate::jet::Jet; use crate::types::{self, arrow::FinalArrow}; -use crate::{encode, BitMachine, WitnessNode}; +use crate::{encode, BitMachine}; use crate::{Amr, BitIter, BitWriter, Cmr, Error, FirstPassImr, Imr, Value}; use super::{ - Commit, CommitData, CommitNode, Construct, ConstructNode, Constructible, Converter, Hide, - Inner, Marker, NoDisconnect, NoWitness, Node, Witness, WitnessData, + Commit, CommitData, CommitNode, Construct, ConstructData, ConstructNode, Constructible, + Converter, Hide, Inner, Marker, NoDisconnect, NoWitness, Node, }; use std::collections::HashSet; @@ -221,15 +221,15 @@ impl RedeemNode { self.convert::>, _, _>(&mut Unfinalizer(PhantomData)) } - /// Convert a [`RedeemNode`] back into a [`WitnessNode`] + /// Convert a [`RedeemNode`] back into a [`ConstructNode`] /// by loosening the finalized types, witness data and disconnected branches. - pub fn to_witness_node(&self) -> Arc> { - struct ToWitness { + pub fn to_construct_node(&self) -> Arc> { + struct ToConstruct { inference_context: types::Context, phantom: PhantomData, } - impl Converter, Witness> for ToWitness { + impl Converter, Construct> for ToConstruct { type Error = (); fn convert_witness( @@ -243,9 +243,9 @@ impl RedeemNode { fn convert_disconnect( &mut self, _: &PostOrderIterItem<&Node>>, - right: Option<&Arc>>>, + right: Option<&Arc>>>, _: &Arc>, - ) -> Result>>>, Self::Error> { + ) -> Result>>>, Self::Error> { Ok(right.cloned()) } @@ -253,21 +253,21 @@ impl RedeemNode { &mut self, _: &PostOrderIterItem<&Node>>, inner: Inner< - &Arc>>, + &Arc>>, J, - &Option>>, + &Option>>, &Option, >, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { let inner = inner .map(|node| node.cached_data()) .map_witness(|maybe_value| maybe_value.clone()); - Ok(WitnessData::from_inner(&self.inference_context, inner) + Ok(ConstructData::from_inner(&self.inference_context, inner) .expect("types were already finalized")) } } - self.convert::(&mut ToWitness { + self.convert::(&mut ToConstruct { inference_context: types::Context::new(), phantom: PhantomData, }) @@ -297,7 +297,7 @@ impl RedeemNode { phantom: PhantomData, } - impl Converter, Witness> for Pruner { + impl Converter, Construct> for Pruner { type Error = std::convert::Infallible; fn convert_witness( @@ -313,9 +313,9 @@ impl RedeemNode { fn convert_disconnect( &mut self, _: &PostOrderIterItem<&RedeemNode>, - right: Option<&Arc>>, + right: Option<&Arc>>, _: &Arc>, - ) -> Result>>, Self::Error> { + ) -> Result>>, Self::Error> { debug_assert!( right.is_some(), "disconnected branch should exist in unpruned redeem program" @@ -326,8 +326,8 @@ impl RedeemNode { fn prune_case( &mut self, data: &PostOrderIterItem<&RedeemNode>, - _left: &Arc>, - _right: &Arc>, + _left: &Arc>, + _right: &Arc>, ) -> Result { // The IMR of the pruned program may change, // but the Converter trait gives us access to the unpruned node (`data`). @@ -346,12 +346,17 @@ impl RedeemNode { fn convert_data( &mut self, _: &PostOrderIterItem<&RedeemNode>, - inner: Inner<&Arc>, J, &Option>>, &Option>, - ) -> Result, Self::Error> { + inner: Inner< + &Arc>, + J, + &Option>>, + &Option, + >, + ) -> Result, Self::Error> { let converted_inner = inner .map(|node| node.cached_data()) .map_witness(Option::::clone); - let retyped = WitnessData::from_inner(&self.inference_context, converted_inner) + let retyped = ConstructData::from_inner(&self.inference_context, converted_inner) .expect("pruned types should check out if unpruned types check out"); Ok(retyped) } @@ -359,12 +364,12 @@ impl RedeemNode { struct Finalizer(PhantomData); - impl Converter, Redeem> for Finalizer { + impl Converter, Redeem> for Finalizer { type Error = std::convert::Infallible; fn convert_witness( &mut self, - data: &PostOrderIterItem<&WitnessNode>, + data: &PostOrderIterItem<&ConstructNode>, witness: &Option, ) -> Result { let pruned_target_ty = data @@ -383,9 +388,9 @@ impl RedeemNode { fn convert_disconnect( &mut self, - _: &PostOrderIterItem<&WitnessNode>, + _: &PostOrderIterItem<&ConstructNode>, right: Option<&Arc>>, - _: &Option>>, + _: &Option>>, ) -> Result>, Self::Error> { Ok(right .map(Arc::clone) @@ -394,7 +399,7 @@ impl RedeemNode { fn convert_data( &mut self, - data: &PostOrderIterItem<&WitnessNode>, + data: &PostOrderIterItem<&ConstructNode>, inner: Inner<&Arc>, J, &Arc>, &Value>, ) -> Result>, Self::Error> { // Finalize target types of witness nodes in advance so we can prune their values. @@ -457,7 +462,7 @@ impl RedeemNode { fn convert_witness( &mut self, data: &PostOrderIterItem<&ConstructNode>, - _: &NoWitness, + _: &Option, ) -> Result { let arrow = data.node.data.arrow(); let target_ty = arrow.target.finalize()?; diff --git a/src/node/witness.rs b/src/node/witness.rs deleted file mode 100644 index ecbcfbc2..00000000 --- a/src/node/witness.rs +++ /dev/null @@ -1,284 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 - -use crate::dag::{InternalSharing, PostOrderIterItem}; -use crate::jet::Jet; -use crate::types::{self, arrow::Arrow}; -use crate::{Cmr, Error, FailEntropy, Value}; - -use crate::value::Word; -use std::marker::PhantomData; -use std::sync::Arc; - -use super::{ - Converter, CoreConstructible, DisconnectConstructible, Inner, JetConstructible, Marker, - NoWitness, Node, Redeem, RedeemData, RedeemNode, WitnessConstructible, -}; - -/// ID used to share [`WitnessNode`]s. -/// -/// This is impossible to construct, which is a promise that it is impossible -/// to share [`WitnessNode`]s. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub enum WitnessId {} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Witness { - /// Makes the type non-constructible. - never: std::convert::Infallible, - /// Required by Rust. - phantom: std::marker::PhantomData, -} - -impl Marker for Witness { - type CachedData = WitnessData; - type Witness = Option; - type Disconnect = Option>>; - type SharingId = WitnessId; - type Jet = J; - - fn compute_sharing_id(_: Cmr, _: &WitnessData) -> Option { - None - } -} - -pub type WitnessNode = Node>; - -impl WitnessNode { - /// Accessor for the node's arrow - pub fn arrow(&self) -> &Arrow { - &self.data.arrow - } - - /// Finalize the witness program as an unpruned redeem program. - /// - /// Witness nodes must be populated with sufficient data, - /// to ensure that the resulting redeem program successfully runs on the Bit Machine. - /// Furthermore, **all** disconnected branches must be populated, - /// even those that are not executed. - /// - /// The resulting redeem program is **not pruned**. - /// - /// ## See - /// - /// [`RedeemNode::prune`] - pub fn finalize_unpruned(&self) -> Result>, Error> { - struct Finalizer(PhantomData); - - impl Converter, Redeem> for Finalizer { - type Error = Error; - - fn convert_witness( - &mut self, - data: &PostOrderIterItem<&WitnessNode>, - wit: &Option, - ) -> Result { - if let Some(ref wit) = wit { - Ok(wit.shallow_clone()) - } else { - // We insert a zero value into unpopulated witness nodes, - // assuming that this node will later be pruned out of the program. - // - // Pruning requires running a program on the Bit Machine, - // which in turn requires a program with fully populated witness nodes. - // It would be horrible UX to force the caller to provide witness data - // even for unexecuted branches, so we insert zero values here. - // - // If this node is executed after all, then the caller can fix the witness - // data based on the returned execution error. - // - // Zero values may "accidentally" satisfy a program even if the caller - // didn't provide any witness data. However, this is only the case for the - // most trivial programs. The only place where we must be careful is our - // unit tests, which tend to include these kinds of trivial programs. - let ty = data.node.arrow().target.finalize()?; - Ok(Value::zero(&ty)) - } - } - - fn convert_disconnect( - &mut self, - _: &PostOrderIterItem<&WitnessNode>, - maybe_converted: Option<&Arc>>, - _: &Option>>, - ) -> Result>, Self::Error> { - if let Some(child) = maybe_converted { - Ok(Arc::clone(child)) - } else { - Err(Error::DisconnectRedeemTime) - } - } - - fn convert_data( - &mut self, - data: &PostOrderIterItem<&WitnessNode>, - inner: Inner<&Arc>, J, &Arc>, &Value>, - ) -> Result>, Self::Error> { - let converted_data = inner - .map(|node| node.cached_data()) - .map_disconnect(|node| node.cached_data()) - .map_witness(Value::shallow_clone); - Ok(Arc::new(RedeemData::new( - data.node.arrow().finalize()?, - converted_data, - ))) - } - } - - self.convert::(&mut Finalizer(PhantomData)) - } - - /// Finalize the witness program as a pruned redeem program. - /// - /// Witness nodes must be populated with sufficient data, - /// to ensure that the resulting redeem program successfully runs on the Bit Machine. - /// Furthermore, **all** disconnected branches must be populated, - /// even those that are not executed. - /// - /// The resulting redeem program is **pruned** based on the given transaction environment. - /// - /// ## See - /// - /// [`RedeemNode::prune`] - pub fn finalize_pruned(&self, env: &J::Environment) -> Result>, Error> { - let unpruned = self.finalize_unpruned()?; - unpruned.prune(env).map_err(Error::Execution) - } -} - -#[derive(Clone, Debug)] -pub struct WitnessData { - arrow: Arrow, - /// This isn't really necessary, but it helps type inference if every - /// struct has a \ parameter, since it forces the choice of jets to - /// be consistent without the user needing to specify it too many times. - phantom: PhantomData, -} - -impl CoreConstructible for WitnessData { - fn iden(inference_context: &types::Context) -> Self { - WitnessData { - arrow: Arrow::iden(inference_context), - phantom: PhantomData, - } - } - - fn unit(inference_context: &types::Context) -> Self { - WitnessData { - arrow: Arrow::unit(inference_context), - phantom: PhantomData, - } - } - - fn injl(child: &Self) -> Self { - WitnessData { - arrow: Arrow::injl(&child.arrow), - phantom: PhantomData, - } - } - - fn injr(child: &Self) -> Self { - WitnessData { - arrow: Arrow::injr(&child.arrow), - phantom: PhantomData, - } - } - - fn take(child: &Self) -> Self { - WitnessData { - arrow: Arrow::take(&child.arrow), - phantom: PhantomData, - } - } - - fn drop_(child: &Self) -> Self { - WitnessData { - arrow: Arrow::drop_(&child.arrow), - phantom: PhantomData, - } - } - - fn comp(left: &Self, right: &Self) -> Result { - Ok(WitnessData { - arrow: Arrow::comp(&left.arrow, &right.arrow)?, - phantom: PhantomData, - }) - } - - fn case(left: &Self, right: &Self) -> Result { - // Specifically for case, rules for propagating prunedness are weird, - // since we assume we can hide pruned nodes, so only if _both_ are - // pruned is the case node itself pruned. - Ok(WitnessData { - arrow: Arrow::case(&left.arrow, &right.arrow)?, - phantom: PhantomData, - }) - } - - fn assertl(left: &Self, right: Cmr) -> Result { - Ok(WitnessData { - arrow: Arrow::assertl(&left.arrow, right)?, - phantom: PhantomData, - }) - } - - fn assertr(left: Cmr, right: &Self) -> Result { - Ok(WitnessData { - arrow: Arrow::assertr(left, &right.arrow)?, - phantom: PhantomData, - }) - } - - fn pair(left: &Self, right: &Self) -> Result { - Ok(WitnessData { - arrow: Arrow::pair(&left.arrow, &right.arrow)?, - phantom: PhantomData, - }) - } - - fn fail(inference_context: &types::Context, entropy: FailEntropy) -> Self { - // Fail nodes always get pruned. - WitnessData { - arrow: Arrow::fail(inference_context, entropy), - phantom: PhantomData, - } - } - - fn const_word(inference_context: &types::Context, word: Word) -> Self { - WitnessData { - arrow: Arrow::const_word(inference_context, word), - phantom: PhantomData, - } - } - - fn inference_context(&self) -> &types::Context { - self.arrow.inference_context() - } -} - -impl DisconnectConstructible>>> for WitnessData { - fn disconnect(left: &Self, right: &Option>>) -> Result { - let right = right.as_ref(); - Ok(WitnessData { - arrow: Arrow::disconnect(&left.arrow, &right.map(|n| n.arrow()))?, - phantom: PhantomData, - }) - } -} - -impl WitnessConstructible> for WitnessData { - fn witness(inference_context: &types::Context, _witness: Option) -> Self { - WitnessData { - arrow: Arrow::witness(inference_context, NoWitness), - phantom: PhantomData, - } - } -} - -impl JetConstructible for WitnessData { - fn jet(inference_context: &types::Context, jet: J) -> Self { - WitnessData { - arrow: Arrow::jet(inference_context, jet), - phantom: PhantomData, - } - } -} diff --git a/src/policy/ast.rs b/src/policy/ast.rs index 94360646..53464940 100644 --- a/src/policy/ast.rs +++ b/src/policy/ast.rs @@ -13,11 +13,9 @@ use std::sync::Arc; use std::{fmt, iter, mem}; use crate::jet::Elements; -use crate::node::{ - ConstructNode, CoreConstructible, JetConstructible, NoWitness, WitnessConstructible, -}; +use crate::node::{ConstructNode, CoreConstructible, JetConstructible, WitnessConstructible}; use crate::policy::serialize::{self, AssemblyConstructible}; -use crate::types; +use crate::{types, Value}; use crate::{Cmr, CommitNode, FailEntropy}; use crate::{SimplicityKey, ToXOnlyPubkey, Translator}; @@ -63,7 +61,7 @@ impl Policy { where N: CoreConstructible + JetConstructible - + WitnessConstructible + + WitnessConstructible> + AssemblyConstructible, { match *self { @@ -73,12 +71,10 @@ impl Policy { Policy::Trivial => Some(serialize::trivial(inference_context)), Policy::After(n) => Some(serialize::after(inference_context, n)), Policy::Older(n) => Some(serialize::older(inference_context, n)), - Policy::Key(ref key) => Some(serialize::key(inference_context, key, NoWitness)), - Policy::Sha256(ref hash) => Some(serialize::sha256::( - inference_context, - hash, - NoWitness, - )), + Policy::Key(ref key) => Some(serialize::key(inference_context, key, None)), + Policy::Sha256(ref hash) => { + Some(serialize::sha256::(inference_context, hash, None)) + } Policy::And { ref left, ref right, @@ -93,7 +89,7 @@ impl Policy { } => { let left = left.serialize_no_witness(inference_context)?; let right = right.serialize_no_witness(inference_context)?; - Some(serialize::or(&left, &right, NoWitness)) + Some(serialize::or(&left, &right, None)) } Policy::Threshold(k, ref subs) => { let k = u32::try_from(k).expect("can have k at most 2^32 in a threshold"); @@ -101,9 +97,7 @@ impl Policy { .iter() .map(|sub| sub.serialize_no_witness(inference_context)) .collect::>>()?; - let wits = iter::repeat(NoWitness) - .take(subs.len()) - .collect::>(); + let wits = iter::repeat(None).take(subs.len()).collect::>(); Some(serialize::threshold(k, &subs, &wits)) } Policy::Assembly(cmr) => N::assembly(inference_context, cmr), diff --git a/src/policy/satisfy.rs b/src/policy/satisfy.rs index ac9c9225..bbb0a2cd 100644 --- a/src/policy/satisfy.rs +++ b/src/policy/satisfy.rs @@ -2,7 +2,7 @@ use crate::analysis::Cost; use crate::jet::Elements; -use crate::node::{Hiding, RedeemNode, WitnessNode}; +use crate::node::{ConstructNode, Hiding, RedeemNode}; use crate::policy::ToXOnlyPubkey; use crate::types; use crate::{Cmr, Policy, Value}; @@ -57,7 +57,7 @@ pub trait Satisfier { /// /// If the assembly program fails to run for the current transaction environment, /// then implementations should return `None`. - fn lookup_asm_program(&self, _: Cmr) -> Option>> { + fn lookup_asm_program(&self, _: Cmr) -> Option>> { None } } @@ -105,7 +105,7 @@ pub enum SatisfierError { AssemblyFailed(crate::bit_machine::ExecutionError), } -type SatResult = Hiding>>; +type SatResult = Hiding>>; fn ok_if(condition: bool, expr: SatResult) -> SatResult { match condition { @@ -278,7 +278,7 @@ mod tests { pub struct PolicySatisfier<'a, Pk: SimplicityKey> { pub preimages: HashMap, pub signatures: HashMap, - pub assembly: HashMap>>, + pub assembly: HashMap>>, pub tx: &'a elements::Transaction, pub index: usize, } @@ -305,7 +305,7 @@ mod tests { >::check_after(&self.tx.lock_time, locktime) } - fn lookup_asm_program(&self, cmr: Cmr) -> Option>> { + fn lookup_asm_program(&self, cmr: Cmr) -> Option>> { self.assembly.get(&cmr).cloned() } } @@ -681,12 +681,12 @@ mod tests { let mut assert_branch = |witness0: Value, witness1: Value| { let asm_program = serialize::verify_bexp( - &Arc::>::pair( - &Arc::>::witness(&ctx, Some(witness0.clone())), - &Arc::>::witness(&ctx, Some(witness1.clone())), + &Arc::>::pair( + &Arc::>::witness(&ctx, Some(witness0.clone())), + &Arc::>::witness(&ctx, Some(witness1.clone())), ) .expect("sound types"), - &Arc::>::jet(&ctx, Elements::Eq8), + &Arc::>::jet(&ctx, Elements::Eq8), ); let cmr = asm_program.cmr(); satisfier.assembly.insert(cmr, asm_program); diff --git a/src/types/mod.rs b/src/types/mod.rs index 95e831a4..75d93c36 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -440,7 +440,7 @@ mod tests { use super::*; use crate::jet::Core; - use crate::node::{ConstructNode, CoreConstructible, WitnessNode}; + use crate::node::{ConstructNode, CoreConstructible}; #[test] fn inference_failure() { @@ -464,9 +464,9 @@ mod tests { #[test] fn memory_leak() { let ctx = Context::new(); - let iden = Arc::>::iden(&ctx); - let drop = Arc::>::drop_(&iden); - let case = Arc::>::case(&iden, &drop).unwrap(); + let iden = Arc::>::iden(&ctx); + let drop = Arc::>::drop_(&iden); + let case = Arc::>::case(&iden, &drop).unwrap(); let _ = format!("{:?}", case.arrow().source); }