1use core::fmt;
12
13use elements::{self, script, secp256k1_zkp, Script};
14
15use super::checksum::verify_checksum;
16use super::{SortedMultiVec, Wpkh, Wsh, ELMTS_STR};
17use crate::descriptor::checksum;
18use crate::expression::{self, FromTree};
19use crate::miniscript::context::ScriptContext;
20use crate::policy::{semantic, Liftable};
21use crate::util::{varint_len, witness_to_scriptsig};
22use crate::{
23 push_opcode_size, Error, ForEachKey, Legacy, Miniscript, MiniscriptKey, Satisfier, Segwitv0,
24 ToPublicKey, TranslatePk, Translator,
25};
26
27#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
29pub struct Sh<Pk: MiniscriptKey> {
30 inner: ShInner<Pk>,
32}
33
34#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
36pub enum ShInner<Pk: MiniscriptKey> {
37 Wsh(Wsh<Pk>),
39 Wpkh(Wpkh<Pk>),
41 SortedMulti(SortedMultiVec<Pk, Legacy>),
43 Ms(Miniscript<Pk, Legacy>),
46}
47
48impl<Pk: MiniscriptKey> Liftable<Pk> for Sh<Pk> {
49 fn lift(&self) -> Result<semantic::Policy<Pk>, Error> {
50 match self.inner {
51 ShInner::Wsh(ref wsh) => wsh.lift(),
52 ShInner::Wpkh(ref pk) => Ok(semantic::Policy::Key(pk.as_inner().clone())),
53 ShInner::SortedMulti(ref smv) => smv.lift(),
54 ShInner::Ms(ref ms) => ms.lift(),
55 }
56 }
57}
58
59impl<Pk: MiniscriptKey> fmt::Debug for Sh<Pk> {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 match self.inner {
62 ShInner::Wsh(ref wsh_inner) => write!(f, "{}sh({:?})", ELMTS_STR, wsh_inner),
63 ShInner::Wpkh(ref pk) => write!(f, "{}sh({:?})", ELMTS_STR, pk),
64 ShInner::SortedMulti(ref smv) => write!(f, "{}sh({:?})", ELMTS_STR, smv),
65 ShInner::Ms(ref ms) => write!(f, "{}sh({:?})", ELMTS_STR, ms),
66 }
67 }
68}
69
70impl<Pk: MiniscriptKey> fmt::Display for Sh<Pk> {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 use fmt::Write;
73 let mut wrapped_f = checksum::Formatter::new(f);
74 match self.inner {
75 ShInner::Wsh(ref wsh) => {
76 write!(wrapped_f, "{}sh(", ELMTS_STR)?;
77 wsh.to_string_no_el_pref(&mut wrapped_f)?;
78 write!(wrapped_f, ")")?;
79 }
80 ShInner::Wpkh(ref pk) => {
81 write!(wrapped_f, "{}sh(", ELMTS_STR)?;
82 pk.to_string_no_el_pref(&mut wrapped_f)?;
83 write!(wrapped_f, ")")?;
84 }
85 ShInner::SortedMulti(ref smv) => write!(wrapped_f, "{}sh({})", ELMTS_STR, smv)?,
86 ShInner::Ms(ref ms) => write!(wrapped_f, "{}sh({})", ELMTS_STR, ms)?,
87 }
88 wrapped_f.write_checksum_if_not_alt()
89 }
90}
91
92impl_from_tree!(
93 Sh<Pk>,
94 fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
95 if top.name == "elsh" && top.args.len() == 1 {
96 let top = &top.args[0];
97 let inner = match top.name {
98 "wsh" => ShInner::Wsh(Wsh::from_inner_tree(top)?),
99 "wpkh" => ShInner::Wpkh(Wpkh::from_inner_tree(top)?),
100 "sortedmulti" => ShInner::SortedMulti(SortedMultiVec::from_tree(top)?),
101 _ => {
102 let sub = Miniscript::from_tree(top)?;
103 Legacy::top_level_checks(&sub)?;
104 ShInner::Ms(sub)
105 }
106 };
107 Ok(Sh { inner })
108 } else {
109 Err(Error::Unexpected(format!(
110 "{}({} args) while parsing sh descriptor",
111 top.name,
112 top.args.len(),
113 )))
114 }
115 }
116);
117
118impl_from_str!(
119 Sh<Pk>,
120 type Err = Error;,
121 fn from_str(s: &str) -> Result<Self, Self::Err> {
122 let desc_str = verify_checksum(s)?;
123 let top = expression::Tree::from_str(desc_str)?;
124 Self::from_tree(&top)
125 }
126);
127
128impl<Pk: MiniscriptKey> Sh<Pk> {
129 pub fn into_inner(self) -> ShInner<Pk> {
131 self.inner
132 }
133
134 pub fn as_inner(&self) -> &ShInner<Pk> {
136 &self.inner
137 }
138
139 pub fn new(ms: Miniscript<Pk, Legacy>) -> Result<Self, Error> {
141 Legacy::top_level_checks(&ms)?;
143 Ok(Self {
144 inner: ShInner::Ms(ms),
145 })
146 }
147
148 pub fn new_sortedmulti(k: usize, pks: Vec<Pk>) -> Result<Self, Error> {
151 Ok(Self {
154 inner: ShInner::SortedMulti(SortedMultiVec::new(k, pks)?),
155 })
156 }
157
158 pub fn new_wsh(ms: Miniscript<Pk, Segwitv0>) -> Result<Self, Error> {
160 Ok(Self {
161 inner: ShInner::Wsh(Wsh::new(ms)?),
162 })
163 }
164
165 pub fn new_with_wsh(wsh: Wsh<Pk>) -> Self {
167 Self {
168 inner: ShInner::Wsh(wsh),
169 }
170 }
171
172 pub fn sanity_check(&self) -> Result<(), Error> {
174 match self.inner {
175 ShInner::Wsh(ref wsh) => wsh.sanity_check()?,
176 ShInner::Wpkh(ref wpkh) => wpkh.sanity_check()?,
177 ShInner::SortedMulti(ref smv) => smv.sanity_check()?,
178 ShInner::Ms(ref ms) => ms.sanity_check()?,
179 }
180 Ok(())
181 }
182
183 pub fn new_wsh_sortedmulti(k: usize, pks: Vec<Pk>) -> Result<Self, Error> {
186 Ok(Self {
189 inner: ShInner::Wsh(Wsh::new_sortedmulti(k, pks)?),
190 })
191 }
192
193 pub fn new_wpkh(pk: Pk) -> Result<Self, Error> {
195 Ok(Self {
196 inner: ShInner::Wpkh(Wpkh::new(pk)?),
197 })
198 }
199
200 pub fn new_with_wpkh(wpkh: Wpkh<Pk>) -> Self {
202 Self {
203 inner: ShInner::Wpkh(wpkh),
204 }
205 }
206
207 pub fn max_weight_to_satisfy(&self) -> Result<usize, Error> {
221 let (scriptsig_size, witness_size) = match self.inner {
222 ShInner::Wsh(ref wsh) => {
224 let scriptsig_size = 1 + 1 + 1 + 32;
226 let witness_size = wsh.max_weight_to_satisfy()?;
227 (scriptsig_size, witness_size)
228 }
229 ShInner::SortedMulti(ref smv) => {
230 let ss = smv.script_size();
231 let ps = push_opcode_size(ss);
232 let scriptsig_size = ps + ss + smv.max_satisfaction_size();
233 (scriptsig_size, 0)
234 }
235 ShInner::Wpkh(ref wpkh) => {
237 let scriptsig_size = 1 + 1 + 1 + 20;
239 let witness_size = wpkh.max_weight_to_satisfy();
240 (scriptsig_size, witness_size)
241 }
242 ShInner::Ms(ref ms) => {
243 let ss = ms.script_size();
244 let ps = push_opcode_size(ss);
245 let scriptsig_size = ps + ss + ms.max_satisfaction_size()?;
246 (scriptsig_size, 0)
247 }
248 };
249
250 let scriptsig_varint_diff = varint_len(scriptsig_size) - varint_len(0);
252
253 Ok(4 * (scriptsig_varint_diff + scriptsig_size) + witness_size)
254 }
255
256 #[deprecated(note = "use max_weight_to_satisfy instead")]
266 #[allow(deprecated)]
267 pub fn max_satisfaction_weight(&self) -> Result<usize, Error> {
268 Ok(match self.inner {
269 ShInner::Wsh(ref wsh) => 4 * 35 + wsh.max_satisfaction_weight()?,
271 ShInner::SortedMulti(ref smv) => {
272 let ss = smv.script_size();
273 let ps = push_opcode_size(ss);
274 let scriptsig_len = ps + ss + smv.max_satisfaction_size();
275 4 * (varint_len(scriptsig_len) + scriptsig_len)
276 }
277 ShInner::Wpkh(ref wpkh) => 4 * 23 + wpkh.max_satisfaction_weight(),
279 ShInner::Ms(ref ms) => {
280 let ss = ms.script_size();
281 let ps = push_opcode_size(ss);
282 let scriptsig_len = ps + ss + ms.max_satisfaction_size()?;
283 4 * (varint_len(scriptsig_len) + scriptsig_len)
284 }
285 })
286 }
287}
288
289impl<Pk: MiniscriptKey + ToPublicKey> Sh<Pk> {
290 pub fn script_pubkey(&self) -> Script {
292 match self.inner {
293 ShInner::Wsh(ref wsh) => wsh.script_pubkey().to_p2sh(),
294 ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey().to_p2sh(),
295 ShInner::SortedMulti(ref smv) => smv.encode().to_p2sh(),
296 ShInner::Ms(ref ms) => ms.encode().to_p2sh(),
297 }
298 }
299
300 pub fn address(
302 &self,
303 blinder: Option<secp256k1_zkp::PublicKey>,
304 params: &'static elements::AddressParams,
305 ) -> elements::Address {
306 match self.inner {
307 ShInner::Wsh(ref wsh) => elements::Address::p2sh(&wsh.script_pubkey(), blinder, params),
308 ShInner::Wpkh(ref wpkh) => {
309 elements::Address::p2sh(&wpkh.script_pubkey(), blinder, params)
310 }
311 ShInner::SortedMulti(ref smv) => {
312 elements::Address::p2sh(&smv.encode(), blinder, params)
313 }
314 ShInner::Ms(ref ms) => elements::Address::p2sh(&ms.encode(), blinder, params),
315 }
316 }
317
318 pub fn inner_script(&self) -> Script {
320 match self.inner {
321 ShInner::Wsh(ref wsh) => wsh.inner_script(),
322 ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(),
323 ShInner::SortedMulti(ref smv) => smv.encode(),
324 ShInner::Ms(ref ms) => ms.encode(),
325 }
326 }
327
328 pub fn ecdsa_sighash_script_code(&self) -> Script {
330 match self.inner {
331 ShInner::Wsh(ref wsh) => wsh.ecdsa_sighash_script_code(),
334 ShInner::SortedMulti(ref smv) => smv.encode(),
335 ShInner::Wpkh(ref wpkh) => wpkh.ecdsa_sighash_script_code(),
336 ShInner::Ms(ref ms) => ms.encode(),
338 }
339 }
340
341 pub fn unsigned_script_sig(&self) -> Script {
349 match self.inner {
350 ShInner::Wsh(ref wsh) => {
351 let witness_script = wsh.inner_script();
353 script::Builder::new()
354 .push_slice(&witness_script.to_v0_p2wsh()[..])
355 .into_script()
356 }
357 ShInner::Wpkh(ref wpkh) => {
358 let redeem_script = wpkh.script_pubkey();
359 script::Builder::new()
360 .push_slice(&redeem_script[..])
361 .into_script()
362 }
363 ShInner::SortedMulti(..) | ShInner::Ms(..) => Script::new(),
364 }
365 }
366
367 pub fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
371 where
372 S: Satisfier<Pk>,
373 {
374 let script_sig = self.unsigned_script_sig();
375 match self.inner {
376 ShInner::Wsh(ref wsh) => {
377 let (witness, _) = wsh.get_satisfaction(satisfier)?;
378 Ok((witness, script_sig))
379 }
380 ShInner::Wpkh(ref wpkh) => {
381 let (witness, _) = wpkh.get_satisfaction(satisfier)?;
382 Ok((witness, script_sig))
383 }
384 ShInner::SortedMulti(ref smv) => {
385 let mut script_witness = smv.satisfy(satisfier)?;
386 script_witness.push(smv.encode().into_bytes());
387 let script_sig = witness_to_scriptsig(&script_witness);
388 let witness = vec![];
389 Ok((witness, script_sig))
390 }
391 ShInner::Ms(ref ms) => {
392 let mut script_witness = ms.satisfy(satisfier)?;
393 script_witness.push(ms.encode().into_bytes());
394 let script_sig = witness_to_scriptsig(&script_witness);
395 let witness = vec![];
396 Ok((witness, script_sig))
397 }
398 }
399 }
400
401 pub fn get_satisfaction_mall<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
405 where
406 S: Satisfier<Pk>,
407 {
408 let script_sig = self.unsigned_script_sig();
409 match self.inner {
410 ShInner::Wsh(ref wsh) => {
411 let (witness, _) = wsh.get_satisfaction_mall(satisfier)?;
412 Ok((witness, script_sig))
413 }
414 ShInner::Ms(ref ms) => {
415 let mut script_witness = ms.satisfy_malleable(satisfier)?;
416 script_witness.push(ms.encode().into_bytes());
417 let script_sig = witness_to_scriptsig(&script_witness);
418 let witness = vec![];
419 Ok((witness, script_sig))
420 }
421 _ => self.get_satisfaction(satisfier),
422 }
423 }
424}
425
426impl<Pk: MiniscriptKey> ForEachKey<Pk> for Sh<Pk> {
427 fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool
428 where
429 Pk: 'a,
430 {
431 match self.inner {
432 ShInner::Wsh(ref wsh) => wsh.for_each_key(pred),
433 ShInner::SortedMulti(ref smv) => smv.for_each_key(pred),
434 ShInner::Wpkh(ref wpkh) => wpkh.for_each_key(pred),
435 ShInner::Ms(ref ms) => ms.for_each_key(pred),
436 }
437 }
438}
439
440impl<P: MiniscriptKey, Q: MiniscriptKey> TranslatePk<P, Q> for Sh<P> {
441 type Output = Sh<Q>;
442
443 fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
444 where
445 T: Translator<P, Q, E>,
446 {
447 let inner = match self.inner {
448 ShInner::Wsh(ref wsh) => ShInner::Wsh(wsh.translate_pk(t)?),
449 ShInner::Wpkh(ref wpkh) => ShInner::Wpkh(wpkh.translate_pk(t)?),
450 ShInner::SortedMulti(ref smv) => ShInner::SortedMulti(smv.translate_pk(t)?),
451 ShInner::Ms(ref ms) => ShInner::Ms(ms.translate_pk(t)?),
452 };
453 Ok(Sh { inner })
454 }
455}