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

expression: replace recursive Tree datatype with a non-recursive one #780

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .github/workflows/cron-daily-fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ compile_descriptor,
compile_taproot,
parse_descriptor,
parse_descriptor_secret,
regression_descriptor_parse,
roundtrip_concrete,
roundtrip_descriptor,
roundtrip_miniscript_script,
Expand Down
15 changes: 13 additions & 2 deletions Cargo-minimal.lock
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ name = "descriptor-fuzz"
version = "0.0.1"
dependencies = [
"honggfuzz",
"miniscript",
"miniscript 12.3.0",
"miniscript 13.0.0",
"regex",
]

Expand Down Expand Up @@ -181,7 +182,17 @@ dependencies = [

[[package]]
name = "miniscript"
version = "12.2.0"
version = "12.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d"
dependencies = [
"bech32",
"bitcoin",
]

[[package]]
name = "miniscript"
version = "13.0.0"
dependencies = [
"bech32",
"bitcoin",
Expand Down
15 changes: 13 additions & 2 deletions Cargo-recent.lock
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ name = "descriptor-fuzz"
version = "0.0.1"
dependencies = [
"honggfuzz",
"miniscript",
"miniscript 12.3.0",
"miniscript 13.0.0",
"regex",
]

Expand Down Expand Up @@ -181,7 +182,17 @@ dependencies = [

[[package]]
name = "miniscript"
version = "12.2.0"
version = "12.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d"
dependencies = [
"bech32",
"bitcoin",
]

[[package]]
name = "miniscript"
version = "13.0.0"
dependencies = [
"bech32",
"bitcoin",
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "miniscript"
version = "12.2.0"
version = "13.0.0"
authors = ["Andrew Poelstra <[email protected]>, Sanket Kanjalkar <[email protected]>"]
license = "CC0-1.0"
homepage = "https://github.com/rust-bitcoin/rust-miniscript/"
Expand Down
5 changes: 5 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ cargo-fuzz = true
[dependencies]
honggfuzz = { version = "0.5.56", default-features = false }
miniscript = { path = "..", features = [ "compiler" ] }
old_miniscript = { package = "miniscript", version = "12.3" }

regex = "1.0"

Expand All @@ -31,6 +32,10 @@ path = "fuzz_targets/parse_descriptor.rs"
name = "parse_descriptor_secret"
path = "fuzz_targets/parse_descriptor_secret.rs"

[[bin]]
name = "regression_descriptor_parse"
path = "fuzz_targets/regression_descriptor_parse.rs"

[[bin]]
name = "roundtrip_concrete"
path = "fuzz_targets/roundtrip_concrete.rs"
Expand Down
43 changes: 43 additions & 0 deletions fuzz/fuzz_targets/regression_descriptor_parse.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use core::str::FromStr;

use honggfuzz::fuzz;
use miniscript::{Descriptor, DescriptorPublicKey};
use old_miniscript::{Descriptor as OldDescriptor, DescriptorPublicKey as OldDescriptorPublicKey};

type Desc = Descriptor<DescriptorPublicKey>;
type OldDesc = OldDescriptor<OldDescriptorPublicKey>;

fn do_test(data: &[u8]) {
let data_str = String::from_utf8_lossy(data);
match (Desc::from_str(&data_str), OldDesc::from_str(&data_str)) {
(Err(_), Err(_)) => {}
(Ok(x), Err(e)) => panic!("new logic parses {} as {:?}, old fails with {}", data_str, x, e),
(Err(e), Ok(x)) => panic!("old logic parses {} as {:?}, new fails with {}", data_str, x, e),
(Ok(new), Ok(old)) => {
assert_eq!(
old.to_string(),
new.to_string(),
"input {} (left is old, right is new)",
data_str
)
}
}
}

fn main() {
loop {
fuzz!(|data| {
do_test(data);
});
}
}

#[cfg(test)]
mod tests {
#[test]
fn duplicate_crash() {
crate::do_test(
b"tr(02dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd,{1,unun:0})",
)
}
}
1 change: 1 addition & 0 deletions fuzz/generate-files.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ cargo-fuzz = true
[dependencies]
honggfuzz = { version = "0.5.56", default-features = false }
miniscript = { path = "..", features = [ "compiler" ] }
old_miniscript = { package = "miniscript", git = "https://github.com/apoelstra/rust-miniscript/", rev = "1259375d7b7c91053e09d1cbe3db983612fe301c" }
regex = "1.0"
EOF
Expand Down
12 changes: 6 additions & 6 deletions src/descriptor/bare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Bare<Pk> {
}

impl<Pk: FromStrKey> FromTree for Bare<Pk> {
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
let sub = Miniscript::<Pk, BareCtx>::from_tree(top)?;
fn from_tree(root: expression::TreeIterItem) -> Result<Self, Error> {
let sub = Miniscript::<Pk, BareCtx>::from_tree(root)?;
BareCtx::top_level_checks(&sub)?;
Bare::new(sub)
}
Expand All @@ -186,7 +186,7 @@ impl<Pk: FromStrKey> core::str::FromStr for Bare<Pk> {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let top = expression::Tree::from_str(s)?;
Self::from_tree(&top)
Self::from_tree(top.root())
}
}

Expand Down Expand Up @@ -369,8 +369,8 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Pkh<Pk> {
}

impl<Pk: FromStrKey> FromTree for Pkh<Pk> {
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
let pk = top
fn from_tree(root: expression::TreeIterItem) -> Result<Self, Error> {
let pk = root
.verify_terminal_parent("pkh", "public key")
.map_err(Error::Parse)?;
Pkh::new(pk).map_err(Error::ContextError)
Expand All @@ -381,7 +381,7 @@ impl<Pk: FromStrKey> core::str::FromStr for Pkh<Pk> {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let top = expression::Tree::from_str(s)?;
Self::from_tree(&top)
Self::from_tree(top.root())
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/descriptor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -965,8 +965,8 @@ impl Descriptor<DefiniteDescriptorKey> {

impl<Pk: FromStrKey> crate::expression::FromTree for Descriptor<Pk> {
/// Parse an expression tree into a descriptor.
fn from_tree(top: &expression::Tree) -> Result<Descriptor<Pk>, Error> {
Ok(match (top.name, top.args.len() as u32) {
fn from_tree(top: expression::TreeIterItem) -> Result<Descriptor<Pk>, Error> {
Ok(match (top.name(), top.n_children()) {
("pkh", 1) => Descriptor::Pkh(Pkh::from_tree(top)?),
("wpkh", 1) => Descriptor::Wpkh(Wpkh::from_tree(top)?),
("sh", 1) => Descriptor::Sh(Sh::from_tree(top)?),
Expand All @@ -981,7 +981,7 @@ impl<Pk: FromStrKey> FromStr for Descriptor<Pk> {
type Err = Error;
fn from_str(s: &str) -> Result<Descriptor<Pk>, Error> {
let top = expression::Tree::from_str(s)?;
let ret = Self::from_tree(&top)?;
let ret = Self::from_tree(top.root())?;
if let Descriptor::Tr(ref inner) = ret {
// FIXME preserve weird/broken behavior from 12.x.
// See https://github.com/rust-bitcoin/rust-miniscript/issues/734
Expand Down
10 changes: 5 additions & 5 deletions src/descriptor/segwitv0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,13 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Wsh<Pk> {
}

impl<Pk: FromStrKey> crate::expression::FromTree for Wsh<Pk> {
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
fn from_tree(top: expression::TreeIterItem) -> Result<Self, Error> {
let top = top
.verify_toplevel("wsh", 1..=1)
.map_err(From::from)
.map_err(Error::Parse)?;

if top.name == "sortedmulti" {
if top.name() == "sortedmulti" {
return Ok(Wsh { inner: WshInner::SortedMulti(SortedMultiVec::from_tree(top)?) });
}
let sub = Miniscript::from_tree(top)?;
Expand Down Expand Up @@ -284,7 +284,7 @@ impl<Pk: FromStrKey> core::str::FromStr for Wsh<Pk> {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let top = expression::Tree::from_str(s)?;
Wsh::<Pk>::from_tree(&top)
Wsh::<Pk>::from_tree(top.root())
}
}

Expand Down Expand Up @@ -483,7 +483,7 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Wpkh<Pk> {
}

impl<Pk: FromStrKey> crate::expression::FromTree for Wpkh<Pk> {
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
fn from_tree(top: expression::TreeIterItem) -> Result<Self, Error> {
let pk = top
.verify_terminal_parent("wpkh", "public key")
.map_err(Error::Parse)?;
Expand All @@ -495,7 +495,7 @@ impl<Pk: FromStrKey> core::str::FromStr for Wpkh<Pk> {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let top = expression::Tree::from_str(s)?;
Self::from_tree(&top)
Self::from_tree(top.root())
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/descriptor/sh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ impl<Pk: MiniscriptKey> fmt::Display for Sh<Pk> {
}

impl<Pk: FromStrKey> crate::expression::FromTree for Sh<Pk> {
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
fn from_tree(top: expression::TreeIterItem) -> Result<Self, Error> {
let top = top
.verify_toplevel("sh", 1..=1)
.map_err(From::from)
.map_err(Error::Parse)?;

let inner = match top.name {
let inner = match top.name() {
"wsh" => ShInner::Wsh(Wsh::from_tree(top)?),
"wpkh" => ShInner::Wpkh(Wpkh::from_tree(top)?),
"sortedmulti" => ShInner::SortedMulti(SortedMultiVec::from_tree(top)?),
Expand All @@ -105,7 +105,7 @@ impl<Pk: FromStrKey> core::str::FromStr for Sh<Pk> {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let top = expression::Tree::from_str(s)?;
Self::from_tree(&top)
Self::from_tree(top.root())
}
}

Expand Down
7 changes: 2 additions & 5 deletions src/descriptor/sortedmulti.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
}

/// Parse an expression tree into a SortedMultiVec
pub fn from_tree(tree: &expression::Tree) -> Result<Self, Error>
pub fn from_tree(tree: expression::TreeIterItem) -> Result<Self, Error>
where
Pk: FromStrKey,
{
Expand All @@ -69,10 +69,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {

let ret = Self {
inner: tree
.to_null_threshold()
.map_err(Error::ParseThreshold)?
.translate_by_index(|i| tree.args[i + 1].verify_terminal("public key"))
.map_err(Error::Parse)?,
.verify_threshold(|sub| sub.verify_terminal("public_key").map_err(Error::Parse))?,
phantom: PhantomData,
};
ret.constructor_check()
Expand Down
Loading
Loading