From ca16bd86b9de807404bde882ef85801828d5b135 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 15 Jun 2022 12:45:33 -0700 Subject: [PATCH 1/5] Fix formatter configuration errors with latest nightly --- rustfmt.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index f3bff64fa..37abad596 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -16,7 +16,6 @@ format_code_in_doc_comments = false comment_width = 80 normalize_comments = false normalize_doc_attributes = false -license_template_path = "" format_strings = false format_macro_matchers = false format_macro_bodies = true @@ -53,7 +52,7 @@ trailing_comma = "Vertical" match_block_trailing_comma = false blank_lines_upper_bound = 1 blank_lines_lower_bound = 0 -edition = "2015" +edition = "2018" version = "One" inline_attribute_width = 0 format_generated_files = true @@ -63,15 +62,12 @@ use_field_init_shorthand = false force_explicit_abi = true condense_wildcard_suffixes = false color = "Auto" -required_version = "1.4.38" unstable_features = false disable_all_formatting = false skip_children = false hide_parse_errors = false error_on_line_overflow = false error_on_unformatted = false -report_todo = "Never" -report_fixme = "Never" ignore = [] emit_mode = "Files" make_backup = false From 701c9ccd2c30d0c91e7b7130312caa5daaaba2da Mon Sep 17 00:00:00 2001 From: Aman Rojjha Date: Thu, 16 Jun 2022 01:37:30 +0530 Subject: [PATCH 2/5] Remove un-necessary lifetimes Remove lifetime parameter concerning `PkH(Pk::Hash)` to `PkH(Pk)` refactor. --- src/interpreter/mod.rs | 6 +++--- src/interpreter/stack.rs | 12 +++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index a987b7463..0cfc48b64 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -590,7 +590,7 @@ where Terminal::PkK(ref pk) => { debug_assert_eq!(node_state.n_evaluated, 0); debug_assert_eq!(node_state.n_satisfied, 0); - let res = self.stack.evaluate_pk(&mut self.verify_sig, pk); + let res = self.stack.evaluate_pk(&mut self.verify_sig, *pk); if res.is_some() { return res; } @@ -598,7 +598,7 @@ where Terminal::PkH(ref pkh) => { debug_assert_eq!(node_state.n_evaluated, 0); debug_assert_eq!(node_state.n_satisfied, 0); - let res = self.stack.evaluate_pkh(&mut self.verify_sig, pkh); + let res = self.stack.evaluate_pkh(&mut self.verify_sig, *pkh); if res.is_some() { return res; } @@ -857,7 +857,7 @@ where // push 1 on satisfied sigs and push 0 on empty sigs match self .stack - .evaluate_pk(&mut self.verify_sig, &subs[node_state.n_evaluated]) + .evaluate_pk(&mut self.verify_sig, subs[node_state.n_evaluated]) { Some(Ok(x)) => { self.push_evaluation_state( diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index 75adbe9a1..1b793b979 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -134,7 +134,7 @@ impl<'txin> Stack<'txin> { pub(super) fn evaluate_pk<'intp>( &mut self, verify_sig: &mut Box bool + 'intp>, - pk: &'intp BitcoinKey, + pk: BitcoinKey, ) -> Option> { if let Some(sigser) = self.pop() { match sigser { @@ -143,7 +143,7 @@ impl<'txin> Stack<'txin> { None } Element::Push(sigser) => { - let key_sig = verify_sersig(verify_sig, pk, sigser); + let key_sig = verify_sersig(verify_sig, &pk, sigser); match key_sig { Ok(key_sig) => { self.push(Element::Satisfied); @@ -152,9 +152,7 @@ impl<'txin> Stack<'txin> { Err(e) => Some(Err(e)), } } - Element::Satisfied => { - Some(Err(Error::PkEvaluationError(PkEvalErrInner::from(*pk)))) - } + Element::Satisfied => Some(Err(Error::PkEvaluationError(PkEvalErrInner::from(pk)))), } } else { Some(Err(Error::UnexpectedStackEnd)) @@ -170,7 +168,7 @@ impl<'txin> Stack<'txin> { pub(super) fn evaluate_pkh<'intp>( &mut self, verify_sig: &mut Box bool + 'intp>, - pkh: &'intp TypedHash160, + pkh: TypedHash160, ) -> Option> { // Parse a bitcoin key from witness data slice depending on hash context // when we encounter a pkh(hash) @@ -189,7 +187,7 @@ impl<'txin> Stack<'txin> { if pk_hash != pkh.hash160() { return Some(Err(Error::PkHashVerifyFail(pkh.hash160()))); } - match bitcoin_key_from_slice(pk, *pkh) { + match bitcoin_key_from_slice(pk, pkh) { Some(pk) => { if let Some(sigser) = self.pop() { match sigser { From 09299b072e8bbb703406192239f67ada37d53798 Mon Sep 17 00:00:00 2001 From: Aman Rojjha Date: Mon, 13 Jun 2022 13:10:24 +0530 Subject: [PATCH 3/5] Refactor ForEach to contain only Pk. This change allows us to allow to refactor `Terminal::PkH(Pk::Hash)` to `Terminal::PkH(Pk)`. --- src/descriptor/bare.rs | 2 +- src/descriptor/segwitv0.rs | 2 +- src/descriptor/sortedmulti.rs | 2 +- src/descriptor/tr.rs | 7 ++----- src/lib.rs | 14 +++----------- src/miniscript/astelem.rs | 6 +++--- src/policy/concrete.rs | 2 +- src/policy/semantic.rs | 2 +- 8 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 0b3159ab6..83ec15a53 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -331,7 +331,7 @@ impl ForEachKey for Pkh { Pk: 'a, Pk::Hash: 'a, { - pred(ForEach::Key(&self.pk)) + pred(ForEach(&self.pk)) } } diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 070d23934..f88e06602 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -444,7 +444,7 @@ impl ForEachKey for Wpkh { Pk: 'a, Pk::Hash: 'a, { - pred(ForEach::Key(&self.pk)) + pred(ForEach(&self.pk)) } } diff --git a/src/descriptor/sortedmulti.rs b/src/descriptor/sortedmulti.rs index d3c21a239..b86875a36 100644 --- a/src/descriptor/sortedmulti.rs +++ b/src/descriptor/sortedmulti.rs @@ -117,7 +117,7 @@ impl ForEachKey for SortedMultiVec ForEachKey for Tr { let script_keys_res = self .iter_scripts() .all(|(_d, ms)| ms.for_each_key(&mut pred)); - script_keys_res && pred(ForEach::Key(&self.internal_key)) + script_keys_res && pred(ForEach(&self.internal_key)) } } @@ -702,9 +702,6 @@ mod tests { let desc = desc.replace(&[' ', '\n'][..], ""); let tr = Tr::::from_str(&desc).unwrap(); // Note the last ac12 only has ac and fails the predicate - assert!(!tr.for_each_key(|k| match k { - ForEach::Key(k) => k.starts_with("acc"), - ForEach::Hash(_h) => unreachable!(), - })); + assert!(!tr.for_each_key(|k| k.0.starts_with("acc"))); } } diff --git a/src/lib.rs b/src/lib.rs index 5bac1c908..2b25dd3f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -458,21 +458,13 @@ where T: Translator; } -/// Either a key or a keyhash -pub enum ForEach<'a, Pk: MiniscriptKey> { - /// A key - Key(&'a Pk), - /// A keyhash - Hash(&'a Pk::Hash), -} +/// Either a key or keyhash, but both contain Pk +pub struct ForEach<'a, Pk: MiniscriptKey>(&'a Pk); impl<'a, Pk: MiniscriptKey> ForEach<'a, Pk> { /// Convenience method to avoid distinguishing between keys and hashes when these are the same type pub fn as_key(&self) -> &'a Pk { - match *self { - ForEach::Key(ref_key) => ref_key, - ForEach::Hash(ref_key) => ref_key, - } + self.0 } } diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index 932d5135e..aa5157916 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -85,8 +85,8 @@ impl Terminal { Pk::Hash: 'a, { match *self { - Terminal::PkK(ref p) => pred(ForEach::Key(p)), - Terminal::PkH(ref p) => pred(ForEach::Hash(p)), + Terminal::PkK(ref p) => pred(ForEach(p)), + Terminal::PkH(ref _p) => todo!("KeyHash should contain Pk"), Terminal::After(..) | Terminal::Older(..) | Terminal::Sha256(..) @@ -117,7 +117,7 @@ impl Terminal { } Terminal::Thresh(_, ref subs) => subs.iter().all(|sub| sub.real_for_each_key(pred)), Terminal::Multi(_, ref keys) | Terminal::MultiA(_, ref keys) => { - keys.iter().all(|key| pred(ForEach::Key(key))) + keys.iter().all(|key| pred(ForEach(key))) } } } diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index a007ea881..f62fce1c9 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -304,7 +304,7 @@ impl ForEachKey for Policy { { match *self { Policy::Unsatisfiable | Policy::Trivial => true, - Policy::Key(ref pk) => pred(ForEach::Key(pk)), + Policy::Key(ref pk) => pred(ForEach(pk)), Policy::Sha256(..) | Policy::Hash256(..) | Policy::Ripemd160(..) diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index 8818bfe92..fb436c454 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -63,7 +63,7 @@ impl ForEachKey for Policy { { match *self { Policy::Unsatisfiable | Policy::Trivial => true, - Policy::KeyHash(ref pkh) => pred(ForEach::Hash(pkh)), + Policy::KeyHash(ref _pkh) => todo!("Semantic Policy KeyHash must store Pk"), Policy::Sha256(..) | Policy::Hash256(..) | Policy::Ripemd160(..) From 5cb2bcffae4f5720868138eadae7b98de0d0a9bc Mon Sep 17 00:00:00 2001 From: Aman Rojjha Date: Fri, 10 Jun 2022 17:23:20 +0530 Subject: [PATCH 4/5] Refactor PkH to include key. The test-cases previously containing 40-byte hash for `pk_h` fragment have been replaced with 66-byte pubkey. --- src/descriptor/mod.rs | 7 ++- src/interpreter/mod.rs | 24 ++++---- src/miniscript/astelem.rs | 37 ++++++++---- src/miniscript/context.rs | 5 +- src/miniscript/decode.rs | 6 +- src/miniscript/iter.rs | 56 ++++++++++-------- src/miniscript/mod.rs | 89 +++++++++++++++++++---------- src/miniscript/satisfy.rs | 15 ++++- src/miniscript/types/extra_props.rs | 2 +- src/miniscript/types/mod.rs | 4 +- src/policy/compiler.rs | 8 +-- src/policy/mod.rs | 4 +- src/psbt/mod.rs | 7 +-- src/util.rs | 23 +++++++- 14 files changed, 186 insertions(+), 101 deletions(-) diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 46d1adfa9..e614e4a84 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -1253,7 +1253,7 @@ mod tests { let p2 = "020000000000000000000000000000000000000000000000000000000000000002"; let p3 = "020000000000000000000000000000000000000000000000000000000000000003"; let p4 = "020000000000000000000000000000000000000000000000000000000000000004"; - let p5 = "f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"; + let p5 = "03f8551772d66557da28c1de858124f365a8eb30ce6ad79c10e0f4c546d0ab0f82"; let descriptor = Tr::::from_str(&format!( "tr({},{{pk({}),{{pk({}),or_d(pk({}),pkh({}))}}}})", p1, p2, p3, p4, p5 @@ -1261,11 +1261,12 @@ mod tests { .unwrap() .to_string(); + // p5.to_pubkeyhash() = 516ca378e588a7ed71336147e2a72848b20aca1a assert_eq!( descriptor, format!( - "tr({},{{pk({}),{{pk({}),or_d(pk({}),pkh({}))}}}})#fdhmu4fj", - p1, p2, p3, p4, p5 + "tr({},{{pk({}),{{pk({}),or_d(pk({}),pkh(516ca378e588a7ed71336147e2a72848b20aca1a))}}}})#xz8ny8ae", + p1, p2, p3, p4, ) ) } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 0cfc48b64..661270ae0 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -595,7 +595,17 @@ where return res; } } - Terminal::PkH(ref pkh) => { + Terminal::PkH(ref pk) => { + debug_assert_eq!(node_state.n_evaluated, 0); + debug_assert_eq!(node_state.n_satisfied, 0); + let res = self + .stack + .evaluate_pkh(&mut self.verify_sig, pk.to_pubkeyhash()); + if res.is_some() { + return res; + } + } + Terminal::RawPkH(ref pkh) => { debug_assert_eq!(node_state.n_evaluated, 0); debug_assert_eq!(node_state.n_satisfied, 0); let res = self.stack.evaluate_pkh(&mut self.verify_sig, *pkh); @@ -1138,7 +1148,7 @@ mod tests { } let pk = no_checks_ms(&format!("c:pk_k({})", pks[0])); - let pkh = no_checks_ms(&format!("c:pk_h({})", pks[1].to_pubkeyhash())); + let pkh = no_checks_ms(&format!("c:pk_h({})", pks[1])); //Time let after = no_checks_ms(&format!("after({})", 1000)); let older = no_checks_ms(&format!("older({})", 1000)); @@ -1270,11 +1280,7 @@ mod tests { stack::Element::Push(&pk_bytes), stack::Element::Push(&der_sigs[0]), ]); - let elem = no_checks_ms(&format!( - "and_v(vc:pk_k({}),c:pk_h({}))", - pks[0], - pks[1].to_pubkeyhash() - )); + let elem = no_checks_ms(&format!("and_v(vc:pk_k({}),c:pk_h({}))", pks[0], pks[1])); let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); @@ -1325,9 +1331,7 @@ mod tests { ]); let elem = no_checks_ms(&format!( "andor(c:pk_k({}),jtv:sha256({}),c:pk_h({}))", - pks[0], - sha256_hash, - pks[1].to_pubkeyhash(), + pks[0], sha256_hash, pks[1], )); let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index aa5157916..cbc546f92 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -86,8 +86,9 @@ impl Terminal { { match *self { Terminal::PkK(ref p) => pred(ForEach(p)), - Terminal::PkH(ref _p) => todo!("KeyHash should contain Pk"), - Terminal::After(..) + Terminal::PkH(ref p) => pred(ForEach(p)), + Terminal::RawPkH(..) + | Terminal::After(..) | Terminal::Older(..) | Terminal::Sha256(..) | Terminal::Hash256(..) @@ -130,7 +131,8 @@ impl Terminal { { let frag: Terminal = match *self { Terminal::PkK(ref p) => Terminal::PkK(t.pk(p)?), - Terminal::PkH(ref p) => Terminal::PkH(t.pkh(p)?), + Terminal::PkH(ref p) => Terminal::PkH(t.pk(p)?), + Terminal::RawPkH(ref p) => Terminal::RawPkH(t.pkh(p)?), Terminal::After(n) => Terminal::After(n), Terminal::Older(n) => Terminal::Older(n), Terminal::Sha256(ref x) => Terminal::Sha256(t.sha256(&x)?), @@ -255,7 +257,8 @@ impl fmt::Debug for Terminal { } else { match *self { Terminal::PkK(ref pk) => write!(f, "pk_k({:?})", pk), - Terminal::PkH(ref pkh) => write!(f, "pk_h({:?})", pkh), + Terminal::PkH(ref pk) => write!(f, "pk_h({:?})", pk), + Terminal::RawPkH(ref pkh) => write!(f, "pk_h({:?})", pkh), Terminal::After(t) => write!(f, "after({})", t), Terminal::Older(t) => write!(f, "older({})", t), Terminal::Sha256(ref h) => write!(f, "sha256({})", h), @@ -312,7 +315,8 @@ impl fmt::Display for Terminal { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Terminal::PkK(ref pk) => write!(f, "pk_k({})", pk), - Terminal::PkH(ref pkh) => write!(f, "pk_h({})", pkh), + Terminal::PkH(ref pk) => write!(f, "pk_h({})", pk), + Terminal::RawPkH(ref pkh) => write!(f, "pk_h({})", pkh), Terminal::After(t) => write!(f, "after({})", t), Terminal::Older(t) => write!(f, "older({})", t), Terminal::Sha256(ref h) => write!(f, "sha256({})", h), @@ -372,9 +376,13 @@ impl fmt::Display for Terminal { if let Terminal::PkK(ref pk) = sub.node { // alias: pk(K) = c:pk_k(K) return write!(f, "pk({})", pk); - } else if let Terminal::PkH(ref pkh) = sub.node { + } else if let Terminal::RawPkH(ref pkh) = sub.node { + // `RawPkH` is currently unsupported in the descriptor spec // alias: pkh(K) = c:pk_h(K) return write!(f, "pkh({})", pkh); + } else if let Terminal::PkH(ref pk) = sub.node { + // alias: pkh(K) = c:pk_h(K) + return write!(f, "pkh({})", &pk.to_pubkeyhash()); } } @@ -386,7 +394,9 @@ impl fmt::Display for Terminal { // Add a ':' wrapper if there are other wrappers apart from c:pk_k() // tvc:pk_k() -> tv:pk() Some(('c', ms)) => match ms.node { - Terminal::PkK(_) | Terminal::PkH(_) => fmt::Write::write_char(f, ':')?, + Terminal::PkK(_) | Terminal::PkH(_) | Terminal::RawPkH(_) => { + fmt::Write::write_char(f, ':')? + } _ => {} }, _ => {} @@ -460,9 +470,7 @@ impl_from_tree!( ("pk_k", 1) => { expression::terminal(&top.args[0], |x| Pk::from_str(x).map(Terminal::PkK)) } - ("pk_h", 1) => { - expression::terminal(&top.args[0], |x| Pk::Hash::from_str(x).map(Terminal::PkH)) - } + ("pk_h", 1) => expression::terminal(&top.args[0], |x| Pk::from_str(x).map(Terminal::PkH)), ("after", 1) => expression::terminal(&top.args[0], |x| { expression::parse_num(x).map(Terminal::After) }), @@ -620,7 +628,12 @@ impl Terminal { { match *self { Terminal::PkK(ref pk) => builder.push_ms_key::<_, Ctx>(pk), - Terminal::PkH(ref hash) => builder + Terminal::PkH(ref pk) => builder + .push_opcode(opcodes::all::OP_DUP) + .push_opcode(opcodes::all::OP_HASH160) + .push_ms_key_hash::<_, Ctx>(pk) + .push_opcode(opcodes::all::OP_EQUALVERIFY), + Terminal::RawPkH(ref hash) => builder .push_opcode(opcodes::all::OP_DUP) .push_opcode(opcodes::all::OP_HASH160) .push_slice(&Pk::hash_to_hash160(hash)[..]) @@ -760,7 +773,7 @@ impl Terminal { pub fn script_size(&self) -> usize { match *self { Terminal::PkK(ref pk) => Ctx::pk_len(pk), - Terminal::PkH(..) => 24, + Terminal::PkH(..) | Terminal::RawPkH(..) => 24, Terminal::After(n) => script_num_size(n as usize) + 1, Terminal::Older(n) => script_num_size(n as usize) + 1, Terminal::Sha256(..) => 33 + 6, diff --git a/src/miniscript/context.rs b/src/miniscript/context.rs index 9aeb2563c..645eef235 100644 --- a/src/miniscript/context.rs +++ b/src/miniscript/context.rs @@ -356,6 +356,7 @@ impl ScriptContext for Legacy { ) -> Result<(), ScriptContextError> { match *frag { Terminal::PkH(ref _pkh) => Err(ScriptContextError::MalleablePkH), + Terminal::RawPkH(ref _pk) => Err(ScriptContextError::MalleablePkH), Terminal::OrI(ref _a, ref _b) => Err(ScriptContextError::MalleableOrI), Terminal::DupIf(ref _ms) => Err(ScriptContextError::MalleableDupIf), _ => Ok(()), @@ -747,8 +748,8 @@ impl ScriptContext for BareCtx { fn other_top_level_checks(ms: &Miniscript) -> Result<(), Error> { match &ms.node { Terminal::Check(ref ms) => match &ms.node { - Terminal::PkH(_pkh) => Ok(()), - Terminal::PkK(_pk) => Ok(()), + Terminal::RawPkH(_pkh) => Ok(()), + Terminal::PkK(_pk) | Terminal::PkH(_pk) => Ok(()), _ => Err(Error::NonStandardBareScript), }, Terminal::Multi(_k, subs) if subs.len() <= 3 => Ok(()), diff --git a/src/miniscript/decode.rs b/src/miniscript/decode.rs index f7a94d42b..e6a0f9fa8 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -134,7 +134,9 @@ pub enum Terminal { /// `` PkK(Pk), /// `DUP HASH160 EQUALVERIFY` - PkH(Pk::Hash), + PkH(Pk), + /// Only for parsing PkH for Script + RawPkH(Pk::Hash), // timelocks /// `n CHECKLOCKTIMEVERIFY` After(u32), @@ -336,7 +338,7 @@ pub fn parse( Tk::Hash160 => match_token!( tokens, Tk::Dup => { - term.reduce0(Terminal::PkH( + term.reduce0(Terminal::RawPkH( hash160::Hash::from_slice(hash).expect("valid size") ))? }, diff --git a/src/miniscript/iter.rs b/src/miniscript/iter.rs index fc9e28044..a3dff1b8b 100644 --- a/src/miniscript/iter.rs +++ b/src/miniscript/iter.rs @@ -58,7 +58,9 @@ impl Miniscript { /// them. pub fn branches(&self) -> Vec<&Miniscript> { match self.node { - Terminal::PkK(_) | Terminal::PkH(_) | Terminal::Multi(_, _) => vec![], + Terminal::PkK(_) | Terminal::PkH(_) | Terminal::RawPkH(_) | Terminal::Multi(_, _) => { + vec![] + } Terminal::Alt(ref node) | Terminal::Swap(ref node) @@ -123,7 +125,7 @@ impl Miniscript { /// `miniscript.iter_pubkeys().collect()`. pub fn get_leapk(&self) -> Vec { match self.node { - Terminal::PkK(ref key) => vec![key.clone()], + Terminal::PkK(ref key) | Terminal::PkH(ref key) => vec![key.clone()], Terminal::Multi(_, ref keys) | Terminal::MultiA(_, ref keys) => keys.clone(), _ => vec![], } @@ -140,8 +142,8 @@ impl Miniscript { /// for example `miniscript.iter_pubkey_hashes().collect()`. pub fn get_leapkh(&self) -> Vec { match self.node { - Terminal::PkH(ref hash) => vec![hash.clone()], - Terminal::PkK(ref key) => vec![key.to_pubkeyhash()], + Terminal::RawPkH(ref hash) => vec![hash.clone()], + Terminal::PkK(ref key) | Terminal::PkH(ref key) => vec![key.to_pubkeyhash()], Terminal::Multi(_, ref keys) | Terminal::MultiA(_, ref keys) => { keys.iter().map(Pk::to_pubkeyhash).collect() } @@ -158,8 +160,10 @@ impl Miniscript { /// function, for example `miniscript.iter_pubkeys_and_hashes().collect()`. pub fn get_leapk_pkh(&self) -> Vec> { match self.node { - Terminal::PkH(ref hash) => vec![PkPkh::HashedPubkey(hash.clone())], - Terminal::PkK(ref key) => vec![PkPkh::PlainPubkey(key.clone())], + Terminal::RawPkH(ref hash) => vec![PkPkh::HashedPubkey(hash.clone())], + Terminal::PkH(ref key) | Terminal::PkK(ref key) => { + vec![PkPkh::PlainPubkey(key.clone())] + } Terminal::Multi(_, ref keys) | Terminal::MultiA(_, ref keys) => keys .iter() .map(|key| PkPkh::PlainPubkey(key.clone())) @@ -174,7 +178,7 @@ impl Miniscript { /// NB: The function analyzes only single miniscript item and not any of its descendants in AST. pub fn get_nth_pk(&self, n: usize) -> Option { match (&self.node, n) { - (&Terminal::PkK(ref key), 0) => Some(key.clone()), + (&Terminal::PkK(ref key), 0) | (&Terminal::PkH(ref key), 0) => Some(key.clone()), (&Terminal::Multi(_, ref keys), _) | (&Terminal::MultiA(_, ref keys), _) => { keys.get(n).cloned() } @@ -191,8 +195,10 @@ impl Miniscript { /// NB: The function analyzes only single miniscript item and not any of its descendants in AST. pub fn get_nth_pkh(&self, n: usize) -> Option { match (&self.node, n) { - (&Terminal::PkH(ref hash), 0) => Some(hash.clone()), - (&Terminal::PkK(ref key), 0) => Some(key.to_pubkeyhash()), + (&Terminal::RawPkH(ref hash), 0) => Some(hash.clone()), + (&Terminal::PkK(ref key), 0) | (&Terminal::PkH(ref key), 0) => { + Some(key.to_pubkeyhash()) + } (&Terminal::Multi(_, ref keys), _) | (&Terminal::MultiA(_, ref keys), _) => { keys.get(n).map(Pk::to_pubkeyhash) } @@ -206,8 +212,10 @@ impl Miniscript { /// NB: The function analyzes only single miniscript item and not any of its descendants in AST. pub fn get_nth_pk_pkh(&self, n: usize) -> Option> { match (&self.node, n) { - (&Terminal::PkH(ref hash), 0) => Some(PkPkh::HashedPubkey(hash.clone())), - (&Terminal::PkK(ref key), 0) => Some(PkPkh::PlainPubkey(key.clone())), + (&Terminal::RawPkH(ref hash), 0) => Some(PkPkh::HashedPubkey(hash.clone())), + (&Terminal::PkH(ref key), 0) | (&Terminal::PkK(ref key), 0) => { + Some(PkPkh::PlainPubkey(key.clone())) + } (&Terminal::Multi(_, ref keys), _) | (&Terminal::MultiA(_, ref keys), _) => { keys.get(n).map(|key| PkPkh::PlainPubkey(key.clone())) } @@ -493,7 +501,7 @@ pub mod test { pub fn gen_testcases() -> Vec { let k = gen_bitcoin_pubkeys(10, true); - let h: Vec = k + let _h: Vec = k .iter() .map(|pk| hash160::Hash::hash(&pk.to_bytes())) .collect(); @@ -520,11 +528,11 @@ pub mod test { false, ), (ms_str!("c:pk_k({})", k[0]), vec![k[0]], vec![], true), - (ms_str!("c:pk_h({})", h[6]), vec![], vec![h[6]], true), + (ms_str!("c:pk_h({})", k[0]), vec![k[0]], vec![], true), ( - ms_str!("and_v(vc:pk_k({}),c:pk_h({}))", k[0], h[1]), - vec![k[0]], - vec![h[1]], + ms_str!("and_v(vc:pk_k({}),c:pk_h({}))", k[0], k[1]), + vec![k[0], k[1]], + vec![], false, ), ( @@ -538,10 +546,10 @@ pub mod test { "andor(c:pk_k({}),jtv:sha256({}),c:pk_h({}))", k[1], sha256_hash, - h[2] + k[2] ), - vec![k[1]], - vec![h[2]], + vec![k[1], k[2]], + vec![], false, ), ( @@ -585,12 +593,12 @@ pub mod test { k[4], k[6], k[9], - h[8], - h[7], - h[0] + k[1], + k[3], + k[5] ), - vec![k[0], k[2], k[4], k[6], k[9]], - vec![h[8], h[7], h[0]], + vec![k[0], k[2], k[4], k[6], k[9], k[1], k[3], k[5]], + vec![], false, ), ] diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 08c7f75d6..576c13bdd 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -507,6 +507,22 @@ mod tests { assert_eq!(roundtrip, script); } + fn string_display_debug_test( + script: Miniscript, + expected_debug: &str, + expected_display: &str, + ) { + assert_eq!(script.ty.corr.base, types::Base::B); + let debug = format!("{:?}", script); + let display = format!("{}", script); + if let Some(expected) = expected_debug.into() { + assert_eq!(debug, expected); + } + if let Some(expected) = expected_display.into() { + assert_eq!(display, expected); + } + } + fn dummy_string_rtt( script: Miniscript, expected_debug: &str, @@ -607,14 +623,14 @@ mod tests { ms_attributes_test("and_v(andor(hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),v:hash256(939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735),v:older(50000)),after(499999999))", "82012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b2587640350c300b2696782012088aa20939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735886804ff64cd1db1", true, false, false, 14, 2); ms_attributes_test("andor(hash256(5f8d30e655a7ba0d7596bb3ddfb1d2d20390d23b1845000e1e118b3be1b3f040),j:and_v(v:hash160(3a2bff0da9d96868e66abc4427bea4691cf61ccd),older(4194305)),ripemd160(44d90e2d3714c8663b632fcf0f9d5f22192cc4c8))", "82012088aa205f8d30e655a7ba0d7596bb3ddfb1d2d20390d23b1845000e1e118b3be1b3f040876482012088a61444d90e2d3714c8663b632fcf0f9d5f22192cc4c8876782926382012088a9143a2bff0da9d96868e66abc4427bea4691cf61ccd8803010040b26868", true, false, false, 20, 2); ms_attributes_test("or_i(c:and_v(v:after(500000),pk_k(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)),sha256(d9147961436944f43cd99d28b2bbddbf452ef872b30c8279e255e7daafc7f946))", "630320a107b1692102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ac6782012088a820d9147961436944f43cd99d28b2bbddbf452ef872b30c8279e255e7daafc7f9468768", true, true, false, 10, 2); - ms_attributes_test("thresh(2,c:pk_h(5dedfbf9ea599dd4e3ca6a80b333c472fd0b3f69),s:sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),a:hash160(dd69735817e0e3f6f826a9238dc2e291184f0131))", "76a9145dedfbf9ea599dd4e3ca6a80b333c472fd0b3f6988ac7c82012088a820e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f87936b82012088a914dd69735817e0e3f6f826a9238dc2e291184f0131876c935287", true, false, false, 18, 4); + ms_attributes_test("thresh(2,c:pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),s:sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),a:hash160(dd69735817e0e3f6f826a9238dc2e291184f0131))", "76a91420d637c1a6404d2227f3561fdbaff5a680dba64888ac7c82012088a820e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f87936b82012088a914dd69735817e0e3f6f826a9238dc2e291184f0131876c935287", true, false, false, 18, 4); ms_attributes_test("and_n(sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2),uc:and_v(v:older(144),pk_k(03fe72c435413d33d48ac09c9161ba8b09683215439d62b7940502bda8b202e6ce)))", "82012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed28764006763029000b2692103fe72c435413d33d48ac09c9161ba8b09683215439d62b7940502bda8b202e6ceac67006868", true, false, true, 13, 3); ms_attributes_test("and_n(c:pk_k(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),and_b(l:older(4252898),a:older(16)))", "2103daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729ac64006763006703e2e440b2686b60b26c9a68", true, true, true, 12, 2); - ms_attributes_test("c:or_i(and_v(v:older(16),pk_h(9fc5dbe5efdce10374a4dd4053c93af540211718)),pk_h(2fbd32c8dd59ee7c17e66cb6ebea7e9846c3040f))", "6360b26976a9149fc5dbe5efdce10374a4dd4053c93af540211718886776a9142fbd32c8dd59ee7c17e66cb6ebea7e9846c3040f8868ac", true, true, true, 12, 3); - ms_attributes_test("or_d(c:pk_h(c42e7ef92fdb603af844d064faad95db9bcdfd3d),andor(c:pk_k(024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),older(2016),after(1567547623)))", "76a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac736421024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97ac6404e7e06e5db16702e007b26868", true, true, false, 13, 3); - ms_attributes_test("c:andor(ripemd160(6ad07d21fd5dfc646f0b30577045ce201616b9ba),pk_h(9fc5dbe5efdce10374a4dd4053c93af540211718),and_v(v:hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),pk_h(dd100be7d9aea5721158ebde6d6a1fd8fff93bb1)))", "82012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba876482012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b258876a914dd100be7d9aea5721158ebde6d6a1fd8fff93bb1886776a9149fc5dbe5efdce10374a4dd4053c93af5402117188868ac", true, false, true, 18, 3); - ms_attributes_test("c:andor(u:ripemd160(6ad07d21fd5dfc646f0b30577045ce201616b9ba),pk_h(20d637c1a6404d2227f3561fdbaff5a680dba648),or_i(pk_h(9652d86bedf43ad264362e6e6eba6eb764508127),pk_h(751e76e8199196d454941c45d1b3a323f1433bd6)))", "6382012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba87670068646376a9149652d86bedf43ad264362e6e6eba6eb764508127886776a914751e76e8199196d454941c45d1b3a323f1433bd688686776a91420d637c1a6404d2227f3561fdbaff5a680dba6488868ac", true, false, true, 23, 4); - ms_attributes_test("c:or_i(andor(c:pk_h(fcd35ddacad9f2d5be5e464639441c6065e6955d),pk_h(9652d86bedf43ad264362e6e6eba6eb764508127),pk_h(06afd46bcdfd22ef94ac122aa11f241244a37ecc)),pk_k(02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e))", "6376a914fcd35ddacad9f2d5be5e464639441c6065e6955d88ac6476a91406afd46bcdfd22ef94ac122aa11f241244a37ecc886776a9149652d86bedf43ad264362e6e6eba6eb7645081278868672102d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e68ac", true, true, true, 17, 5); + ms_attributes_test("c:or_i(and_v(v:older(16),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729)),pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5))", "6360b26976a91420d637c1a6404d2227f3561fdbaff5a680dba648886776a9148f9dff39a81ee4abcbad2ad8bafff090415a2be88868ac", true, true, true, 12, 3); + ms_attributes_test("or_d(c:pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),andor(c:pk_k(024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),older(2016),after(1567547623)))", "76a9148f9dff39a81ee4abcbad2ad8bafff090415a2be888ac736421024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97ac6404e7e06e5db16702e007b26868", true, true, false, 13, 3); + ms_attributes_test("c:andor(ripemd160(6ad07d21fd5dfc646f0b30577045ce201616b9ba),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),and_v(v:hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5)))", "82012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba876482012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b258876a9148f9dff39a81ee4abcbad2ad8bafff090415a2be8886776a91420d637c1a6404d2227f3561fdbaff5a680dba6488868ac", true, false, true, 18, 3); + ms_attributes_test("c:andor(u:ripemd160(6ad07d21fd5dfc646f0b30577045ce201616b9ba),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),or_i(pk_h(024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5)))", "6382012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba87670068646376a914385defb0ed10fe95817943ed37b4984f8f4255d6886776a9148f9dff39a81ee4abcbad2ad8bafff090415a2be888686776a91420d637c1a6404d2227f3561fdbaff5a680dba6488868ac", true, false, true, 23, 4); + ms_attributes_test("c:or_i(andor(c:pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),pk_h(024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729)),pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "6376a9148f9dff39a81ee4abcbad2ad8bafff090415a2be888ac6476a91420d637c1a6404d2227f3561fdbaff5a680dba648886776a914385defb0ed10fe95817943ed37b4984f8f4255d68868672103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a146029755668ac", true, true, true, 17, 5); } #[test] @@ -642,7 +658,7 @@ mod tests { let pkh_ms: Miniscript = Miniscript { node: Terminal::Check(Arc::new(Miniscript { - node: Terminal::PkH(DummyKeyHash), + node: Terminal::RawPkH(DummyKeyHash), ty: Type::from_pk_h::(), ext: types::extra_props::ExtData::from_pk_h::(), phantom: PhantomData, @@ -651,7 +667,19 @@ mod tests { ext: ExtData::cast_check(ExtData::from_pk_h::()).unwrap(), phantom: PhantomData, }; - dummy_string_rtt(pkh_ms, "[B/nduesm]c:[K/nduesm]pk_h(DummyKeyHash)", "pkh()"); + + let expected_debug = "[B/nduesm]c:[K/nduesm]pk_h(DummyKeyHash)"; + let expected_display = "pkh()"; + + assert_eq!(pkh_ms.ty.corr.base, types::Base::B); + let debug = format!("{:?}", pkh_ms); + let display = format!("{}", pkh_ms); + if let Some(expected) = expected_debug.into() { + assert_eq!(debug, expected); + } + if let Some(expected) = expected_display.into() { + assert_eq!(display, expected); + } let pkk_ms: Segwitv0Script = Miniscript { node: Terminal::Check(Arc::new(Miniscript { @@ -673,7 +701,7 @@ mod tests { let pkh_ms: Segwitv0Script = Miniscript { node: Terminal::Check(Arc::new(Miniscript { - node: Terminal::PkH(hash), + node: Terminal::RawPkH(hash), ty: Type::from_pk_h::(), ext: types::extra_props::ExtData::from_pk_h::(), phantom: PhantomData, @@ -750,46 +778,45 @@ mod tests { "tv:pk(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)" ); - let pubkey_hash = - hash160::Hash::from_str("f54a5851e9372b87810a8e60cdd2e7cfd80b6e31").unwrap(); - let script: Segwitv0Script = ms_str!("c:pk_h({})", pubkey_hash.to_string()); + let script: Segwitv0Script = ms_str!("c:pk_h({})", pubkey.to_string()); - string_rtt( + string_display_debug_test( script, - "[B/nduesm]c:[K/nduesm]pk_h(f54a5851e9372b87810a8e60cdd2e7cfd80b6e31)", - "pkh(f54a5851e9372b87810a8e60cdd2e7cfd80b6e31)", + "[B/nduesm]c:[K/nduesm]pk_h(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "pkh(60afcdec519698a263417ddfe7cea936737a0ee7)", ); - let script: Segwitv0Script = ms_str!("pkh({})", pubkey_hash.to_string()); + let script: Segwitv0Script = ms_str!("pkh({})", pubkey.to_string()); - string_rtt( + string_display_debug_test( script, - "[B/nduesm]c:[K/nduesm]pk_h(f54a5851e9372b87810a8e60cdd2e7cfd80b6e31)", - "pkh(f54a5851e9372b87810a8e60cdd2e7cfd80b6e31)", + "[B/nduesm]c:[K/nduesm]pk_h(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "pkh(60afcdec519698a263417ddfe7cea936737a0ee7)", ); - let script: Segwitv0Script = ms_str!("tv:pkh({})", pubkey_hash.to_string()); + let script: Segwitv0Script = ms_str!("tv:pkh({})", pubkey.to_string()); - string_rtt( + string_display_debug_test( script, - "[B/nufsm]t[V/nfsm]v[B/nduesm]c:[K/nduesm]pk_h(f54a5851e9372b87810a8e60cdd2e7cfd80b6e31)", - "tv:pkh(f54a5851e9372b87810a8e60cdd2e7cfd80b6e31)", + "[B/nufsm]t[V/nfsm]v[B/nduesm]c:[K/nduesm]pk_h(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "tv:pkh(60afcdec519698a263417ddfe7cea936737a0ee7)", ); } #[test] fn serialize() { - let keys = pubkeys(5); - let dummy_hash = hash160::Hash::from_inner([0; 20]); + let keys = pubkeys(6); - roundtrip( - &ms_str!("c:pk_h({})", dummy_hash), - "\ + let tree: &Segwitv0Script = &ms_str!("c:pk_h({})", keys[5]); + assert_eq!(tree.ty.corr.base, types::Base::B); + let ser = tree.encode(); + let s = "\ Script(OP_DUP OP_HASH160 OP_PUSHBYTES_20 \ - 0000000000000000000000000000000000000000 \ + 7e5a2a6a7610ca4ea78bd65a087bd75b1870e319 \ OP_EQUALVERIFY OP_CHECKSIG)\ - ", - ); + "; + assert_eq!(ser.len(), tree.script_size()); + assert_eq!(ser.to_string(), s); roundtrip( &ms_str!("pk({})", keys[0]), diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index be1b477da..6f3be9bbd 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -938,7 +938,11 @@ impl Satisfaction { stack: Witness::signature::<_, _, Ctx>(stfr, pk, leaf_hash), has_sig: true, }, - Terminal::PkH(ref pkh) => Satisfaction { + Terminal::PkH(ref pk) => Satisfaction { + stack: Witness::pkh_signature(stfr, &pk.to_pubkeyhash()), + has_sig: true, + }, + Terminal::RawPkH(ref pkh) => Satisfaction { stack: Witness::pkh_signature(stfr, pkh), has_sig: true, }, @@ -1246,7 +1250,14 @@ impl Satisfaction { stack: Witness::push_0(), has_sig: false, }, - Terminal::PkH(ref pkh) => Satisfaction { + Terminal::PkH(ref pk) => Satisfaction { + stack: Witness::combine( + Witness::push_0(), + Witness::pkh_public_key(stfr, &pk.to_pubkeyhash()), + ), + has_sig: false, + }, + Terminal::RawPkH(ref pkh) => Satisfaction { stack: Witness::combine(Witness::push_0(), Witness::pkh_public_key(stfr, pkh)), has_sig: false, }, diff --git a/src/miniscript/types/extra_props.rs b/src/miniscript/types/extra_props.rs index 3ef667e89..0cd97f78b 100644 --- a/src/miniscript/types/extra_props.rs +++ b/src/miniscript/types/extra_props.rs @@ -910,7 +910,7 @@ impl Property for ExtData { Terminal::True => Ok(Self::from_true()), Terminal::False => Ok(Self::from_false()), Terminal::PkK(..) => Ok(Self::from_pk_k::()), - Terminal::PkH(..) => Ok(Self::from_pk_h::()), + Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::from_pk_h::()), Terminal::Multi(k, ref pks) | Terminal::MultiA(k, ref pks) => { if k == 0 { return Err(Error { diff --git a/src/miniscript/types/mod.rs b/src/miniscript/types/mod.rs index 90fb5fca5..161185c4f 100644 --- a/src/miniscript/types/mod.rs +++ b/src/miniscript/types/mod.rs @@ -413,7 +413,7 @@ pub trait Property: Sized { Terminal::True => Ok(Self::from_true()), Terminal::False => Ok(Self::from_false()), Terminal::PkK(..) => Ok(Self::from_pk_k::()), - Terminal::PkH(..) => Ok(Self::from_pk_h::()), + Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::from_pk_h::()), Terminal::Multi(k, ref pks) | Terminal::MultiA(k, ref pks) => { if k == 0 { return Err(Error { @@ -796,7 +796,7 @@ impl Property for Type { Terminal::True => Ok(Self::from_true()), Terminal::False => Ok(Self::from_false()), Terminal::PkK(..) => Ok(Self::from_pk_k::()), - Terminal::PkH(..) => Ok(Self::from_pk_h::()), + Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::from_pk_h::()), Terminal::Multi(k, ref pks) | Terminal::MultiA(k, ref pks) => { if k == 0 { return Err(Error { diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 79e76d0d9..ec562acd3 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -840,7 +840,7 @@ where insert_wrap!(AstElemExt::terminal(Terminal::True)); } Concrete::Key(ref pk) => { - insert_wrap!(AstElemExt::terminal(Terminal::PkH(pk.to_pubkeyhash()))); + insert_wrap!(AstElemExt::terminal(Terminal::PkH(pk.clone()))); insert_wrap!(AstElemExt::terminal(Terminal::PkK(pk.clone()))); } Concrete::After(n) => insert_wrap!(AstElemExt::terminal(Terminal::After(n))), @@ -1378,9 +1378,9 @@ mod tests { keys[2], keys[3], keys[4], - keys[5].to_pubkeyhash(), - keys[6].to_pubkeyhash(), - keys[7].to_pubkeyhash() + keys[5], + keys[6], + keys[7] ); assert_eq!(ms, ms_comp_res); diff --git a/src/policy/mod.rs b/src/policy/mod.rs index 29552da7b..3582b9cd4 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -124,8 +124,8 @@ impl Liftable for Miniscript impl Liftable for Terminal { fn lift(&self) -> Result, Error> { let ret = match *self { - Terminal::PkK(ref pk) => Semantic::KeyHash(pk.to_pubkeyhash()), - Terminal::PkH(ref pkh) => Semantic::KeyHash(pkh.clone()), + Terminal::PkK(ref pk) | Terminal::PkH(ref pk) => Semantic::KeyHash(pk.to_pubkeyhash()), + Terminal::RawPkH(ref pkh) => Semantic::KeyHash(pkh.clone()), Terminal::After(t) => Semantic::After(t), Terminal::Older(t) => Semantic::Older(t), Terminal::Sha256(ref h) => Semantic::Sha256(h.clone()), diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index cc8a9f7c1..c77717f87 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -1338,11 +1338,8 @@ mod tests { ) .unwrap(); let first_leaf_hash = { - let ms = Miniscript::::from_str(&format!( - "pkh({})", - &key_0_1.to_pubkeyhash() - )) - .unwrap(); + let ms = + Miniscript::::from_str(&format!("pkh({})", &key_0_1)).unwrap(); let first_script = ms.encode(); assert!(psbt_input .tap_scripts diff --git a/src/util.rs b/src/util.rs index 3189455fc..b59c2fde4 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,7 +3,7 @@ use bitcoin::Script; use crate::miniscript::context; use crate::prelude::*; -use crate::{ScriptContext, ToPublicKey}; +use crate::{MiniscriptKey, ScriptContext, ToPublicKey}; pub(crate) fn varint_len(n: usize) -> usize { bitcoin::VarInt(n as u64).len() } @@ -32,6 +32,12 @@ pub(crate) trait MsKeyBuilder { where Pk: ToPublicKey, Ctx: ScriptContext; + + /// Serialize the key hash as bytes based on script context. Used when encoding miniscript into bitcoin script + fn push_ms_key_hash(self, key: &Pk) -> Self + where + Pk: ToPublicKey, + Ctx: ScriptContext; } impl MsKeyBuilder for script::Builder { @@ -45,4 +51,19 @@ impl MsKeyBuilder for script::Builder { context::SigType::Schnorr => self.push_slice(&key.to_x_only_pubkey().serialize()), } } + + fn push_ms_key_hash(self, key: &Pk) -> Self + where + Pk: ToPublicKey, + Ctx: ScriptContext, + { + match Ctx::sig_type() { + context::SigType::Ecdsa => { + self.push_slice(&Pk::hash_to_hash160(&key.to_pubkeyhash())[..]) + } + context::SigType::Schnorr => { + self.push_slice(&key.to_x_only_pubkey().to_pubkeyhash()[..]) + } + } + } } From 8d0cf061e4fcc3f7784116e43b2d2afb712cd066 Mon Sep 17 00:00:00 2001 From: Aman Rojjha Date: Fri, 17 Jun 2022 22:28:16 +0530 Subject: [PATCH 5/5] Remove `ForEach` Trait Since we disregard any `Pk::Hash` as a valid iterable key, only `Pk` is considered as such. The refactor reflects directly iterating over `Pk` (a valid Miniscript Key). --- src/descriptor/bare.rs | 10 +++++----- src/descriptor/mod.rs | 8 ++++---- src/descriptor/segwitv0.rs | 10 +++++----- src/descriptor/sh.rs | 6 +++--- src/descriptor/sortedmulti.rs | 8 ++++---- src/descriptor/tr.rs | 9 ++++----- src/lib.rs | 18 +++++++++--------- src/miniscript/astelem.rs | 17 +++++++---------- src/miniscript/mod.rs | 8 +++----- src/policy/concrete.rs | 6 +++--- src/policy/semantic.rs | 4 ++-- 11 files changed, 49 insertions(+), 55 deletions(-) diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 83ec15a53..49abef16e 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -30,8 +30,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ - BareCtx, Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, - TranslatePk, Translator, + BareCtx, Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, TranslatePk, + Translator, }; /// Create a Bare Descriptor. That is descriptor that is @@ -164,7 +164,7 @@ impl_from_str!( ); impl ForEachKey for Bare { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, @@ -326,12 +326,12 @@ impl_from_str!( ); impl ForEachKey for Pkh { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, { - pred(ForEach(&self.pk)) + pred(&self.pk) } } diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index e614e4a84..27487ff85 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -37,8 +37,8 @@ use self::checksum::verify_checksum; use crate::miniscript::{Legacy, Miniscript, Segwitv0}; use crate::prelude::*; use crate::{ - expression, miniscript, BareCtx, Error, ForEach, ForEachKey, MiniscriptKey, PkTranslator, - Satisfier, ToPublicKey, TranslatePk, Translator, + expression, miniscript, BareCtx, Error, ForEachKey, MiniscriptKey, PkTranslator, Satisfier, + ToPublicKey, TranslatePk, Translator, }; mod bare; @@ -495,7 +495,7 @@ where } impl ForEachKey for Descriptor { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, @@ -514,7 +514,7 @@ impl ForEachKey for Descriptor { impl Descriptor { /// Whether or not the descriptor has any wildcards pub fn is_deriveable(&self) -> bool { - self.for_any_key(|key| key.as_key().is_deriveable()) + self.for_any_key(|key| key.is_deriveable()) } /// Derives all wildcard keys in the descriptor using the supplied index diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index f88e06602..f1c0202dc 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -28,8 +28,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::varint_len; use crate::{ - Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, - TranslatePk, Translator, + Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, TranslatePk, + Translator, }; /// A Segwitv0 wsh descriptor #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -246,7 +246,7 @@ impl_from_str!( ); impl ForEachKey for Wsh { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, @@ -439,12 +439,12 @@ impl_from_str!( ); impl ForEachKey for Wpkh { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, { - pred(ForEach(&self.pk)) + pred(&self.pk) } } diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index d9202e67e..6d8aa0923 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -31,8 +31,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ - push_opcode_size, Error, ForEach, ForEachKey, Legacy, Miniscript, MiniscriptKey, Satisfier, - Segwitv0, ToPublicKey, TranslatePk, Translator, + push_opcode_size, Error, ForEachKey, Legacy, Miniscript, MiniscriptKey, Satisfier, Segwitv0, + ToPublicKey, TranslatePk, Translator, }; /// A Legacy p2sh Descriptor @@ -377,7 +377,7 @@ impl Sh { } impl ForEachKey for Sh { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, diff --git a/src/descriptor/sortedmulti.rs b/src/descriptor/sortedmulti.rs index b86875a36..47f1ac627 100644 --- a/src/descriptor/sortedmulti.rs +++ b/src/descriptor/sortedmulti.rs @@ -27,8 +27,8 @@ use crate::miniscript::decode::Terminal; use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG; use crate::prelude::*; use crate::{ - errstr, expression, miniscript, policy, script_num_size, Error, ForEach, ForEachKey, - Miniscript, MiniscriptKey, Satisfier, ToPublicKey, Translator, + errstr, expression, miniscript, policy, script_num_size, Error, ForEachKey, Miniscript, + MiniscriptKey, Satisfier, ToPublicKey, Translator, }; /// Contents of a "sortedmulti" descriptor @@ -112,12 +112,12 @@ impl SortedMultiVec { } impl ForEachKey for SortedMultiVec { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, { - self.pks.iter().all(|key| pred(ForEach(key))) + self.pks.iter().all(|key| pred(key)) } } diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 2f8db2837..b2dc1ee20 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -19,8 +19,7 @@ use crate::policy::Liftable; use crate::prelude::*; use crate::util::{varint_len, witness_size}; use crate::{ - errstr, Error, ForEach, ForEachKey, MiniscriptKey, Satisfier, Tap, ToPublicKey, TranslatePk, - Translator, + errstr, Error, ForEachKey, MiniscriptKey, Satisfier, Tap, ToPublicKey, TranslatePk, Translator, }; /// A Taproot Tree representation. @@ -579,7 +578,7 @@ impl Liftable for Tr { } impl ForEachKey for Tr { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, @@ -587,7 +586,7 @@ impl ForEachKey for Tr { let script_keys_res = self .iter_scripts() .all(|(_d, ms)| ms.for_each_key(&mut pred)); - script_keys_res && pred(ForEach(&self.internal_key)) + script_keys_res && pred(&self.internal_key) } } @@ -702,6 +701,6 @@ mod tests { let desc = desc.replace(&[' ', '\n'][..], ""); let tr = Tr::::from_str(&desc).unwrap(); // Note the last ac12 only has ac and fails the predicate - assert!(!tr.for_each_key(|k| k.0.starts_with("acc"))); + assert!(!tr.for_each_key(|k| k.starts_with("acc"))); } } diff --git a/src/lib.rs b/src/lib.rs index 2b25dd3f6..338488e1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -459,27 +459,27 @@ where } /// Either a key or keyhash, but both contain Pk -pub struct ForEach<'a, Pk: MiniscriptKey>(&'a Pk); +// pub struct ForEach<'a, Pk: MiniscriptKey>(&'a Pk); -impl<'a, Pk: MiniscriptKey> ForEach<'a, Pk> { - /// Convenience method to avoid distinguishing between keys and hashes when these are the same type - pub fn as_key(&self) -> &'a Pk { - self.0 - } -} +// impl<'a, Pk: MiniscriptKey> ForEach<'a, Pk> { +// /// Convenience method to avoid distinguishing between keys and hashes when these are the same type +// pub fn as_key(&self) -> &'a Pk { +// self.0 +// } +// } /// Trait describing the ability to iterate over every key pub trait ForEachKey { /// Run a predicate on every key in the descriptor, returning whether /// the predicate returned true for every key - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, Pk::Hash: 'a; /// Run a predicate on every key in the descriptor, returning whether /// the predicate returned true for any key - fn for_any_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool + fn for_any_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index cbc546f92..4a4c34459 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -33,8 +33,8 @@ use crate::miniscript::ScriptContext; use crate::prelude::*; use crate::util::MsKeyBuilder; use crate::{ - errstr, expression, script_num_size, Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, - Terminal, ToPublicKey, TranslatePk, Translator, + errstr, expression, script_num_size, Error, ForEachKey, Miniscript, MiniscriptKey, Terminal, + ToPublicKey, TranslatePk, Translator, }; impl Terminal { @@ -76,17 +76,14 @@ where } impl Terminal { - pub(super) fn real_for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>( - &'a self, - pred: &mut F, - ) -> bool + pub(super) fn real_for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: &mut F) -> bool where Pk: 'a, Pk::Hash: 'a, { match *self { - Terminal::PkK(ref p) => pred(ForEach(p)), - Terminal::PkH(ref p) => pred(ForEach(p)), + Terminal::PkK(ref p) => pred(p), + Terminal::PkH(ref p) => pred(p), Terminal::RawPkH(..) | Terminal::After(..) | Terminal::Older(..) @@ -118,7 +115,7 @@ impl Terminal { } Terminal::Thresh(_, ref subs) => subs.iter().all(|sub| sub.real_for_each_key(pred)), Terminal::Multi(_, ref keys) | Terminal::MultiA(_, ref keys) => { - keys.iter().all(|key| pred(ForEach(key))) + keys.iter().all(|key| pred(key)) } } } @@ -200,7 +197,7 @@ impl Terminal { } impl ForEachKey for Terminal { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 576c13bdd..fd81d9d78 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -53,9 +53,7 @@ pub use crate::miniscript::context::ScriptContext; use crate::miniscript::decode::Terminal; use crate::miniscript::types::extra_props::ExtData; use crate::miniscript::types::Type; -use crate::{ - expression, Error, ForEach, ForEachKey, MiniscriptKey, ToPublicKey, TranslatePk, Translator, -}; +use crate::{expression, Error, ForEachKey, MiniscriptKey, ToPublicKey, TranslatePk, Translator}; #[cfg(test)] mod ms_tests; @@ -271,7 +269,7 @@ impl Miniscript { } impl ForEachKey for Miniscript { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, @@ -299,7 +297,7 @@ where } impl Miniscript { - fn real_for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: &mut F) -> bool + fn real_for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: &mut F) -> bool where Pk: 'a, Pk::Hash: 'a, diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index f62fce1c9..ad30a7311 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -40,7 +40,7 @@ use crate::expression::{self, FromTree}; use crate::miniscript::limits::{LOCKTIME_THRESHOLD, SEQUENCE_LOCKTIME_TYPE_FLAG}; use crate::miniscript::types::extra_props::TimelockInfo; use crate::prelude::*; -use crate::{errstr, Error, ForEach, ForEachKey, MiniscriptKey, Translator}; +use crate::{errstr, Error, ForEachKey, MiniscriptKey, Translator}; /// Concrete policy which corresponds directly to a Miniscript structure, /// and whose disjunctions are annotated with satisfaction probabilities @@ -297,14 +297,14 @@ impl Policy { } impl ForEachKey for Policy { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, Pk::Hash: 'a, { match *self { Policy::Unsatisfiable | Policy::Trivial => true, - Policy::Key(ref pk) => pred(ForEach(pk)), + Policy::Key(ref pk) => pred(pk), Policy::Sha256(..) | Policy::Hash256(..) | Policy::Ripemd160(..) diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index fb436c454..2d463573e 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -23,7 +23,7 @@ use bitcoin::hashes::{hash160, ripemd160, sha256d}; use super::concrete::PolicyError; use super::ENTAILMENT_MAX_TERMINALS; use crate::prelude::*; -use crate::{errstr, expression, timelock, Error, ForEach, ForEachKey, MiniscriptKey, Translator}; +use crate::{errstr, expression, timelock, Error, ForEachKey, MiniscriptKey, Translator}; /// Abstract policy which corresponds to the semantics of a Miniscript /// and which allows complex forms of analysis, e.g. filtering and @@ -56,7 +56,7 @@ pub enum Policy { } impl ForEachKey for Policy { - fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, Pk::Hash: 'a,