@@ -19,62 +19,55 @@ use crate::plan::AssetProvider;
19
19
use crate :: prelude:: * ;
20
20
use crate :: sync:: Arc ;
21
21
use crate :: {
22
- errstr , expression, policy, script_num_size, Error , ForEachKey , Miniscript , MiniscriptKey ,
23
- Satisfier , ToPublicKey , TranslateErr , Translator ,
22
+ expression, policy, script_num_size, Error , ForEachKey , Miniscript , MiniscriptKey , Satisfier ,
23
+ Threshold , ToPublicKey , TranslateErr , Translator ,
24
24
} ;
25
25
26
26
/// Contents of a "sortedmulti" descriptor
27
27
#[ derive( Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
28
28
pub struct SortedMultiVec < Pk : MiniscriptKey , Ctx : ScriptContext > {
29
- /// signatures required
30
- pub k : usize ,
31
- /// public keys inside sorted Multi
32
- pub pks : Vec < Pk > ,
29
+ inner : Threshold < Pk , MAX_PUBKEYS_PER_MULTISIG > ,
33
30
/// The current ScriptContext for sortedmulti
34
- pub ( crate ) phantom : PhantomData < Ctx > ,
31
+ phantom : PhantomData < Ctx > ,
35
32
}
36
33
37
34
impl < Pk : MiniscriptKey , Ctx : ScriptContext > SortedMultiVec < Pk , Ctx > {
38
- /// Create a new instance of `SortedMultiVec` given a list of keys and the threshold
39
- ///
40
- /// Internally checks all the applicable size limits and pubkey types limitations according to the current `Ctx`.
41
- pub fn new ( k : usize , pks : Vec < Pk > ) -> Result < Self , Error > {
42
- // A sortedmulti() is only defined for <= 20 keys (it maps to CHECKMULTISIG)
43
- if pks. len ( ) > MAX_PUBKEYS_PER_MULTISIG {
44
- return Err ( Error :: BadDescriptor ( "Too many public keys" . to_string ( ) ) ) ;
45
- }
46
-
35
+ fn constructor_check ( & self ) -> Result < ( ) , Error > {
47
36
// Check the limits before creating a new SortedMultiVec
48
37
// For example, under p2sh context the scriptlen can only be
49
38
// upto 520 bytes.
50
- let term: Terminal < Pk , Ctx > = Terminal :: Multi ( k , pks . clone ( ) ) ;
39
+ let term: Terminal < Pk , Ctx > = Terminal :: Multi ( self . inner . k ( ) , self . inner . data ( ) . to_owned ( ) ) ;
51
40
let ms = Miniscript :: from_ast ( term) ?;
52
-
53
41
// This would check all the consensus rules for p2sh/p2wsh and
54
42
// even tapscript in future
55
- Ctx :: check_local_validity ( & ms) ?;
43
+ Ctx :: check_local_validity ( & ms) . map_err ( From :: from)
44
+ }
56
45
57
- Ok ( Self { k, pks, phantom : PhantomData } )
46
+ /// Create a new instance of `SortedMultiVec` given a list of keys and the threshold
47
+ ///
48
+ /// Internally checks all the applicable size limits and pubkey types limitations according to the current `Ctx`.
49
+ pub fn new ( k : usize , pks : Vec < Pk > ) -> Result < Self , Error > {
50
+ let ret =
51
+ Self { inner : Threshold :: new ( k, pks) . map_err ( Error :: Threshold ) ?, phantom : PhantomData } ;
52
+ ret. constructor_check ( ) ?;
53
+ Ok ( ret)
58
54
}
55
+
59
56
/// Parse an expression tree into a SortedMultiVec
60
57
pub fn from_tree ( tree : & expression:: Tree ) -> Result < Self , Error >
61
58
where
62
59
Pk : FromStr ,
63
60
<Pk as FromStr >:: Err : fmt:: Display ,
64
61
{
65
- if tree. args . is_empty ( ) {
66
- return Err ( errstr ( "no arguments given for sortedmulti" ) ) ;
67
- }
68
- let k = expression:: parse_num ( tree. args [ 0 ] . name ) ?;
69
- if k > ( tree. args . len ( ) - 1 ) as u32 {
70
- return Err ( errstr ( "higher threshold than there were keys in sortedmulti" ) ) ;
71
- }
72
- let pks: Result < Vec < Pk > , _ > = tree. args [ 1 ..]
73
- . iter ( )
74
- . map ( |sub| expression:: terminal ( sub, Pk :: from_str) )
75
- . collect ( ) ;
76
-
77
- pks. map ( |pks| SortedMultiVec :: new ( k as usize , pks) ) ?
62
+ let ret = Self {
63
+ inner : tree
64
+ . to_null_threshold ( )
65
+ . map_err ( Error :: ParseThreshold ) ?
66
+ . translate_by_index ( |i| expression:: terminal ( & tree. args [ i + 1 ] , Pk :: from_str) ) ?,
67
+ phantom : PhantomData ,
68
+ } ;
69
+ ret. constructor_check ( ) ?;
70
+ Ok ( ret)
78
71
}
79
72
80
73
/// This will panic if fpk returns an uncompressed key when
@@ -88,23 +81,39 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
88
81
T : Translator < Pk , Q , FuncError > ,
89
82
Q : MiniscriptKey ,
90
83
{
91
- let pks: Result < Vec < Q > , _ > = self . pks . iter ( ) . map ( |pk| t. pk ( pk) ) . collect ( ) ;
92
- let res = SortedMultiVec :: new ( self . k , pks?) . map_err ( TranslateErr :: OuterError ) ?;
93
- Ok ( res)
84
+ let ret = SortedMultiVec {
85
+ inner : self . inner . translate_ref ( |pk| t. pk ( pk) ) ?,
86
+ phantom : PhantomData ,
87
+ } ;
88
+ ret. constructor_check ( ) . map_err ( TranslateErr :: OuterError ) ?;
89
+ Ok ( ret)
94
90
}
91
+
92
+ /// The threshold value for the multisig.
93
+ pub fn k ( & self ) -> usize { self . inner . k ( ) }
94
+
95
+ /// The number of keys in the multisig.
96
+ pub fn n ( & self ) -> usize { self . inner . n ( ) }
97
+
98
+ /// Accessor for the public keys in the multisig.
99
+ ///
100
+ /// The keys in this structure might **not** be sorted. In general, they cannot be
101
+ /// sorted until they are converted to consensus-encoded public keys, which may not
102
+ /// be possible (for example for BIP32 paths with unfilled wildcards).
103
+ pub fn pks ( & self ) -> & [ Pk ] { self . inner . data ( ) }
95
104
}
96
105
97
106
impl < Pk : MiniscriptKey , Ctx : ScriptContext > ForEachKey < Pk > for SortedMultiVec < Pk , Ctx > {
98
107
fn for_each_key < ' a , F : FnMut ( & ' a Pk ) -> bool > ( & ' a self , pred : F ) -> bool {
99
- self . pks . iter ( ) . all ( pred)
108
+ self . pks ( ) . iter ( ) . all ( pred)
100
109
}
101
110
}
102
111
103
112
impl < Pk : MiniscriptKey , Ctx : ScriptContext > SortedMultiVec < Pk , Ctx > {
104
113
/// utility function to sanity a sorted multi vec
105
114
pub fn sanity_check ( & self ) -> Result < ( ) , Error > {
106
115
let ms: Miniscript < Pk , Ctx > =
107
- Miniscript :: from_ast ( Terminal :: Multi ( self . k , self . pks . clone ( ) ) )
116
+ Miniscript :: from_ast ( Terminal :: Multi ( self . k ( ) , self . pks ( ) . to_owned ( ) ) )
108
117
. expect ( "Must typecheck" ) ;
109
118
// '?' for doing From conversion
110
119
ms. sanity_check ( ) ?;
@@ -118,7 +127,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
118
127
where
119
128
Pk : ToPublicKey ,
120
129
{
121
- let mut pks = self . pks . clone ( ) ;
130
+ let mut pks = self . pks ( ) . to_owned ( ) ;
122
131
// Sort pubkeys lexicographically according to BIP 67
123
132
pks. sort_by ( |a, b| {
124
133
a. to_public_key ( )
@@ -127,7 +136,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
127
136
. partial_cmp ( & b. to_public_key ( ) . inner . serialize ( ) )
128
137
. unwrap ( )
129
138
} ) ;
130
- Terminal :: Multi ( self . k , pks)
139
+ Terminal :: Multi ( self . k ( ) , pks)
131
140
}
132
141
133
142
/// Encode as a Bitcoin script
@@ -169,10 +178,10 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
169
178
/// to instead call the corresponding function on a `Descriptor`, which
170
179
/// will handle the segwit/non-segwit technicalities for you.
171
180
pub fn script_size ( & self ) -> usize {
172
- script_num_size ( self . k )
181
+ script_num_size ( self . k ( ) )
173
182
+ 1
174
- + script_num_size ( self . pks . len ( ) )
175
- + self . pks . iter ( ) . map ( |pk| Ctx :: pk_len ( pk) ) . sum :: < usize > ( )
183
+ + script_num_size ( self . n ( ) )
184
+ + self . pks ( ) . iter ( ) . map ( |pk| Ctx :: pk_len ( pk) ) . sum :: < usize > ( )
176
185
}
177
186
178
187
/// Maximum number of witness elements used to satisfy the Miniscript
@@ -183,7 +192,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
183
192
/// This function may panic on malformed `Miniscript` objects which do
184
193
/// not correspond to semantically sane Scripts. (Such scripts should be
185
194
/// rejected at parse time. Any exceptions are bugs.)
186
- pub fn max_satisfaction_witness_elements ( & self ) -> usize { 2 + self . k }
195
+ pub fn max_satisfaction_witness_elements ( & self ) -> usize { 2 + self . k ( ) }
187
196
188
197
/// Maximum size, in bytes, of a satisfying witness.
189
198
/// In general, it is not recommended to use this function directly, but
@@ -193,19 +202,16 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
193
202
/// All signatures are assumed to be 73 bytes in size, including the
194
203
/// length prefix (segwit) or push opcode (pre-segwit) and sighash
195
204
/// postfix.
196
- pub fn max_satisfaction_size ( & self ) -> usize { 1 + 73 * self . k }
205
+ pub fn max_satisfaction_size ( & self ) -> usize { 1 + 73 * self . k ( ) }
197
206
}
198
207
199
208
impl < Pk : MiniscriptKey , Ctx : ScriptContext > policy:: Liftable < Pk > for SortedMultiVec < Pk , Ctx > {
200
209
fn lift ( & self ) -> Result < policy:: semantic:: Policy < Pk > , Error > {
201
- let ret = policy:: semantic:: Policy :: Thresh (
202
- self . k ,
203
- self . pks
204
- . iter ( )
205
- . map ( |k| Arc :: new ( policy:: semantic:: Policy :: Key ( k. clone ( ) ) ) )
206
- . collect ( ) ,
207
- ) ;
208
- Ok ( ret)
210
+ Ok ( policy:: semantic:: Policy :: Thresh (
211
+ self . inner
212
+ . map_ref ( |pk| Arc :: new ( policy:: semantic:: Policy :: Key ( pk. clone ( ) ) ) )
213
+ . forget_maximum ( ) ,
214
+ ) )
209
215
}
210
216
}
211
217
@@ -215,11 +221,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Debug for SortedMultiVec<Pk, Ct
215
221
216
222
impl < Pk : MiniscriptKey , Ctx : ScriptContext > fmt:: Display for SortedMultiVec < Pk , Ctx > {
217
223
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
218
- write ! ( f, "sortedmulti({}" , self . k) ?;
219
- for k in & self . pks {
220
- write ! ( f, ",{}" , k) ?;
221
- }
222
- f. write_str ( ")" )
224
+ fmt:: Display :: fmt ( & self . inner . display ( "sortedmulti" , true ) , f)
223
225
}
224
226
}
225
227
@@ -249,7 +251,7 @@ mod tests {
249
251
let error = res. expect_err ( "constructor should err" ) ;
250
252
251
253
match error {
252
- Error :: BadDescriptor ( _) => { } // ok
254
+ Error :: Threshold ( _) => { } // ok
253
255
other => panic ! ( "unexpected error: {:?}" , other) ,
254
256
}
255
257
}
0 commit comments