1
1
// SPDX-License-Identifier: CC0-1.0
2
2
3
3
use crate :: dag:: { InternalSharing , PostOrderIterItem } ;
4
- use crate :: encode;
5
4
use crate :: jet:: Jet ;
6
5
use crate :: types:: { self , arrow:: Arrow } ;
7
- use crate :: { BitIter , BitWriter , Cmr , FailEntropy } ;
6
+ use crate :: { encode , BitIter , BitWriter , Cmr , FailEntropy , RedeemNode , Value , Word } ;
8
7
9
- use crate :: value:: Word ;
10
8
use std:: io;
11
9
use std:: marker:: PhantomData ;
12
10
use std:: sync:: Arc ;
13
11
14
12
use super :: {
15
13
Commit , CommitData , CommitNode , Converter , Inner , Marker , NoDisconnect , NoWitness , Node ,
14
+ Redeem , RedeemData ,
16
15
} ;
17
16
use super :: { CoreConstructible , DisconnectConstructible , JetConstructible , WitnessConstructible } ;
18
17
@@ -33,7 +32,7 @@ pub struct Construct<J> {
33
32
34
33
impl < J : Jet > Marker for Construct < J > {
35
34
type CachedData = ConstructData < J > ;
36
- type Witness = NoWitness ;
35
+ type Witness = Option < Value > ;
37
36
type Disconnect = Option < Arc < ConstructNode < J > > > ;
38
37
type SharingId = ConstructId ;
39
38
type Jet = J ;
@@ -90,7 +89,7 @@ impl<J: Jet> ConstructNode<J> {
90
89
fn convert_witness (
91
90
& mut self ,
92
91
_: & PostOrderIterItem < & ConstructNode < J > > ,
93
- _: & NoWitness ,
92
+ _: & Option < Value > ,
94
93
) -> Result < NoWitness , Self :: Error > {
95
94
Ok ( NoWitness )
96
95
}
@@ -119,6 +118,104 @@ impl<J: Jet> ConstructNode<J> {
119
118
self . convert :: < InternalSharing , _ , _ > ( & mut FinalizeTypes ( PhantomData ) )
120
119
}
121
120
121
+ /// Finalize the witness program as an unpruned redeem program.
122
+ ///
123
+ /// Witness nodes must be populated with sufficient data,
124
+ /// to ensure that the resulting redeem program successfully runs on the Bit Machine.
125
+ /// Furthermore, **all** disconnected branches must be populated,
126
+ /// even those that are not executed.
127
+ ///
128
+ /// The resulting redeem program is **not pruned**.
129
+ ///
130
+ /// ## See
131
+ ///
132
+ /// [`RedeemNode::prune`]
133
+ pub fn finalize_unpruned ( & self ) -> Result < Arc < RedeemNode < J > > , crate :: Error > {
134
+ struct Finalizer < J > ( PhantomData < J > ) ;
135
+
136
+ impl < J : Jet > Converter < Construct < J > , Redeem < J > > for Finalizer < J > {
137
+ type Error = crate :: Error ;
138
+
139
+ fn convert_witness (
140
+ & mut self ,
141
+ data : & PostOrderIterItem < & ConstructNode < J > > ,
142
+ wit : & Option < Value > ,
143
+ ) -> Result < Value , Self :: Error > {
144
+ if let Some ( ref wit) = wit {
145
+ Ok ( wit. shallow_clone ( ) )
146
+ } else {
147
+ // We insert a zero value into unpopulated witness nodes,
148
+ // assuming that this node will later be pruned out of the program.
149
+ //
150
+ // Pruning requires running a program on the Bit Machine,
151
+ // which in turn requires a program with fully populated witness nodes.
152
+ // It would be horrible UX to force the caller to provide witness data
153
+ // even for unexecuted branches, so we insert zero values here.
154
+ //
155
+ // If this node is executed after all, then the caller can fix the witness
156
+ // data based on the returned execution error.
157
+ //
158
+ // Zero values may "accidentally" satisfy a program even if the caller
159
+ // didn't provide any witness data. However, this is only the case for the
160
+ // most trivial programs. The only place where we must be careful is our
161
+ // unit tests, which tend to include these kinds of trivial programs.
162
+ let ty = data. node . arrow ( ) . target . finalize ( ) ?;
163
+ Ok ( Value :: zero ( & ty) )
164
+ }
165
+ }
166
+
167
+ fn convert_disconnect (
168
+ & mut self ,
169
+ _: & PostOrderIterItem < & ConstructNode < J > > ,
170
+ maybe_converted : Option < & Arc < RedeemNode < J > > > ,
171
+ _: & Option < Arc < ConstructNode < J > > > ,
172
+ ) -> Result < Arc < RedeemNode < J > > , Self :: Error > {
173
+ if let Some ( child) = maybe_converted {
174
+ Ok ( Arc :: clone ( child) )
175
+ } else {
176
+ Err ( crate :: Error :: DisconnectRedeemTime )
177
+ }
178
+ }
179
+
180
+ fn convert_data (
181
+ & mut self ,
182
+ data : & PostOrderIterItem < & ConstructNode < J > > ,
183
+ inner : Inner < & Arc < RedeemNode < J > > , J , & Arc < RedeemNode < J > > , & Value > ,
184
+ ) -> Result < Arc < RedeemData < J > > , Self :: Error > {
185
+ let converted_data = inner
186
+ . map ( |node| node. cached_data ( ) )
187
+ . map_disconnect ( |node| node. cached_data ( ) )
188
+ . map_witness ( Value :: shallow_clone) ;
189
+ Ok ( Arc :: new ( RedeemData :: new (
190
+ data. node . arrow ( ) . finalize ( ) ?,
191
+ converted_data,
192
+ ) ) )
193
+ }
194
+ }
195
+
196
+ self . convert :: < InternalSharing , _ , _ > ( & mut Finalizer ( PhantomData ) )
197
+ }
198
+
199
+ /// Finalize the witness program as a pruned redeem program.
200
+ ///
201
+ /// Witness nodes must be populated with sufficient data,
202
+ /// to ensure that the resulting redeem program successfully runs on the Bit Machine.
203
+ /// Furthermore, **all** disconnected branches must be populated,
204
+ /// even those that are not executed.
205
+ ///
206
+ /// The resulting redeem program is **pruned** based on the given transaction environment.
207
+ ///
208
+ /// ## See
209
+ ///
210
+ /// [`RedeemNode::prune`]
211
+ pub fn finalize_pruned (
212
+ & self ,
213
+ env : & J :: Environment ,
214
+ ) -> Result < Arc < RedeemNode < J > > , crate :: Error > {
215
+ let unpruned = self . finalize_unpruned ( ) ?;
216
+ unpruned. prune ( env) . map_err ( crate :: Error :: Execution )
217
+ }
218
+
122
219
/// Decode a Simplicity expression from bits, without witness data.
123
220
///
124
221
/// # Usage
@@ -278,10 +375,10 @@ impl<J: Jet> DisconnectConstructible<Option<Arc<ConstructNode<J>>>> for Construc
278
375
}
279
376
}
280
377
281
- impl < J > WitnessConstructible < NoWitness > for ConstructData < J > {
282
- fn witness ( inference_context : & types:: Context , witness : NoWitness ) -> Self {
378
+ impl < J > WitnessConstructible < Option < Value > > for ConstructData < J > {
379
+ fn witness ( inference_context : & types:: Context , _witness : Option < Value > ) -> Self {
283
380
ConstructData {
284
- arrow : Arrow :: witness ( inference_context, witness ) ,
381
+ arrow : Arrow :: witness ( inference_context, NoWitness ) ,
285
382
phantom : PhantomData ,
286
383
}
287
384
}
@@ -340,7 +437,7 @@ mod tests {
340
437
fn occurs_check_3 ( ) {
341
438
let ctx = types:: Context :: new ( ) ;
342
439
// A similar example that caused a slightly different deadlock in the past.
343
- let wit = Arc :: < ConstructNode < Core > > :: witness ( & ctx, NoWitness ) ;
440
+ let wit = Arc :: < ConstructNode < Core > > :: witness ( & ctx, None ) ;
344
441
let drop = Arc :: < ConstructNode < Core > > :: drop_ ( & wit) ;
345
442
346
443
let comp1 = Arc :: < ConstructNode < Core > > :: comp ( & drop, & drop) . unwrap ( ) ;
0 commit comments