Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Musig fragment parsing #433

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions examples/exp_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use miniscript::Descriptor;
use std::str::FromStr;

fn test_one_descriptor(descriptor: &str) -> bool {
let res = Descriptor::<String>::from_str(descriptor);
match res {
Ok(_) => true,
Err(err) => {
println!("{}", err);
false
}
}
}

fn main() {
dbg!("inside test");
assert!(test_one_descriptor("pk(musig(a))"));
// assert!(test_one_descriptor("pk(musig(a,b))"));
// assert!(test_one_descriptor("pk(musig(a,musig(b,c,d)))"));
// assert!(test_one_descriptor("sh(multi(2,musig(a,b),k1,k2))"));
// assert!(test_one_descriptor("pk(musig(musig(a,b),musig(c,d)))"));
// assert!(test_one_descriptor(
// "pk(musig(a,musig(b,c,musig(d,e,f,musig(g,h,i))),j))"
// ));
// assert!(test_one_descriptor(
// "sh(sortedmulti(3,k1,musig(a,b),musig(musig(c,d))))"
// ));
// Need to test, cases which can give errors
// assert!(!test_one_descriptor("pk(musig(a,b),musig(c))"));
// assert!(!test_one_descriptor("pk(k1,k2)"));
}
1 change: 1 addition & 0 deletions src/descriptor/bare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Bare<Pk> {
impl_from_tree!(
Bare<Pk>,
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
dbg!("from_tree in Bare");
let sub = Miniscript::<Pk, BareCtx>::from_tree(top)?;
BareCtx::top_level_checks(&sub)?;
Bare::new(sub)
Expand Down
31 changes: 31 additions & 0 deletions src/descriptor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,7 @@ impl_from_tree!(
Descriptor<Pk>,
/// Parse an expression tree into a descriptor.
fn from_tree(top: &expression::Tree) -> Result<Descriptor<Pk>, Error> {
dbg!("from_tree of Descriptor<Pk>");
Ok(match (top.name, top.args.len() as u32) {
("pkh", 1) => Descriptor::Pkh(Pkh::from_tree(top)?),
("wpkh", 1) => Descriptor::Wpkh(Wpkh::from_tree(top)?),
Expand All @@ -736,6 +737,7 @@ impl_from_str!(
// tr tree parsing has special code
// Tr::from_str will check the checksum
// match "tr(" to handle more extensibly
dbg!("from_str of Descriptor<Pk>");
if s.starts_with("tr(") {
Ok(Descriptor::Tr(Tr::from_str(s)?))
} else {
Expand Down Expand Up @@ -817,6 +819,35 @@ mod tests {
}
}

fn test_one_descriptor(descriptor: &str) -> bool {
let res = Descriptor::<String>::from_str(descriptor);
match res {
Ok(_) => true,
Err(err) => {
println!("{}", err);
false
}
}
}

#[test]
fn test_musig_descriptors() {
dbg!("inside test");
assert!(test_one_descriptor("pk(musig(a))"));
assert!(test_one_descriptor("pk(musig(a,b))"));
assert!(test_one_descriptor("pk(musig(a,musig(b,c,d)))"));
assert!(test_one_descriptor("sh(multi(2,musig(a,b),k1,k2))"));
assert!(test_one_descriptor("pk(musig(musig(a,b),musig(c,d)))"));
assert!(test_one_descriptor(
"pk(musig(a,musig(b,c,musig(d,e,f,musig(g,h,i))),j))"
));
assert!(test_one_descriptor(
"sh(sortedmulti(3,k1,musig(a,b),musig(musig(c,d))))"
));
// Need to test, cases which can give errors
assert!(!test_one_descriptor("pk(musig(a,b),musig(c))"));
assert!(!test_one_descriptor("pk(k1,k2)"));
}
fn roundtrip_descriptor(s: &str) {
let desc = Descriptor::<DummyKey>::from_str(&s).unwrap();
let output = desc.to_string();
Expand Down
1 change: 1 addition & 0 deletions src/descriptor/sh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl_from_tree!(
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
if top.name == "sh" && top.args.len() == 1 {
let top = &top.args[0];
dbg!("from_tree of sh");
let inner = match top.name {
"wsh" => ShInner::Wsh(Wsh::from_tree(top)?),
"wpkh" => ShInner::Wpkh(Wpkh::from_tree(top)?),
Expand Down
3 changes: 2 additions & 1 deletion src/descriptor/sortedmulti.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
Pk: FromStr,
<Pk as FromStr>::Err: ToString,
{
dbg!("from_tree of sorted multi vec");
if tree.args.is_empty() {
return Err(errstr("no arguments given for sortedmulti"));
}
Expand All @@ -87,7 +88,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
.iter()
.map(|sub| expression::terminal(sub, Pk::from_str))
.collect();

dbg!(&pks);
pks.map(|pks| SortedMultiVec::new(k as usize, pks))?
}

Expand Down
68 changes: 48 additions & 20 deletions src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,33 +143,61 @@ impl<'a> Tree<'a> {
)),
// Function call
Found::LBracket(n) => {
let mut ret = Tree {
name: &sl[..n],
args: vec![],
};

sl = &sl[n + 1..];
loop {
let (arg, new_sl) = Tree::from_slice_delim(sl, depth + 1, delim)?;
ret.args.push(arg);

if new_sl.is_empty() {
// Special case for musig
// We want the complex musig to be just one node in our tree.
if &sl[..n] == "musig" {
let mut open_brackets = 0;
let mut finish_index = 0;
for (i, ch) in sl[n..].char_indices() {
if ch == delim {
open_brackets = open_brackets + 1;
} else if ch == closing_delim(delim) {
open_brackets = open_brackets - 1;
}
if open_brackets == 0 {
finish_index = i;
break;
}
}
if open_brackets != 0 {
return Err(Error::ExpectedChar(closing_delim(delim)));
}
Ok((
Tree {
name: &sl[..n + finish_index + 1],
args: vec![],
},
&sl[n + finish_index + 1..],
))
} else {
let mut ret = Tree {
name: &sl[..n],
args: vec![],
};
// update the string to parse
sl = &sl[n + 1..];
loop {
let (arg, new_sl) = Tree::from_slice_delim(sl, depth + 1, delim)?;
ret.args.push(arg);
// There has to be a closing bracket for the open bracket we encounter in this case
if new_sl.is_empty() {
return Err(Error::ExpectedChar(closing_delim(delim)));
}

sl = &new_sl[1..];
match new_sl.as_bytes()[0] {
b',' => {}
last_byte => {
if last_byte == closing_delim(delim) as u8 {
break;
} else {
return Err(Error::ExpectedChar(closing_delim(delim)));
sl = &new_sl[1..];
match new_sl.as_bytes()[0] {
b',' => {}
last_byte => {
if last_byte == closing_delim(delim) as u8 {
break;
} else {
return Err(Error::ExpectedChar(closing_delim(delim)));
}
}
}
}
Ok((ret, sl))
}
Ok((ret, sl))
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/miniscript/astelem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,16 +412,20 @@ impl_from_tree!(
;Ctx; ScriptContext,
Terminal<Pk, Ctx>,
fn from_tree(top: &expression::Tree) -> Result<Terminal<Pk, Ctx>, Error> {
dbg!("from_tree of Terminal<Pk, Ctx");
dbg!(top);
let mut aliased_wrap;
let frag_name;
let frag_wrap;
let mut name_split = top.name.split(':');
dbg!(&name_split);
match (name_split.next(), name_split.next(), name_split.next()) {
(None, _, _) => {
frag_name = "";
frag_wrap = "";
}
(Some(name), None, _) => {
dbg!("inside pk and pkh case");
if name == "pk" {
frag_name = "pk_k";
frag_wrap = "c";
Expand Down Expand Up @@ -452,6 +456,7 @@ impl_from_tree!(
frag_wrap = wrap;
}
}
// Why is this error ?? consider s:c:pk() two times wrapped
(Some(_), Some(_), Some(_)) => {
return Err(Error::MultiColon(top.name.to_owned()));
}
Expand Down Expand Up @@ -551,9 +556,11 @@ impl_from_tree!(
top.args.len(),
))),
}?;
dbg!(&unwrapped);
for ch in frag_wrap.chars().rev() {
// Check whether the wrapper is valid under the current context
let ms = Miniscript::from_ast(unwrapped)?;
dbg!(&ms);
Ctx::check_global_validity(&ms)?;
match ch {
'a' => unwrapped = Terminal::Alt(Arc::new(ms)),
Expand Down
3 changes: 3 additions & 0 deletions src/miniscript/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Display for Miniscript<Pk, Ctx>
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
/// Extracts the `AstElem` representing the root of the miniscript
pub fn into_inner(self) -> Terminal<Pk, Ctx> {
dbg!("into inner of Miniscript<Pk, Ctx");
self.node
}

Expand Down Expand Up @@ -418,7 +419,9 @@ impl_from_tree!(
/// Parse an expression tree into a Miniscript. As a general rule, this
/// should not be called directly; rather go through the descriptor API.
fn from_tree(top: &expression::Tree) -> Result<Miniscript<Pk, Ctx>, Error> {
dbg!("from_tree inside impl of Miniscript<Pk, Ctx>");
let inner: Terminal<Pk, Ctx> = expression::FromTree::from_tree(top)?;
dbg!(&inner);
Ok(Miniscript {
ty: Type::type_check(&inner, |_| None)?,
ext: ExtData::type_check(&inner, |_| None)?,
Expand Down