Skip to content

Commit e1bc60b

Browse files
committed
Merge #957: Introduce ValidationParams structure; use in Miniscript constructors
f7756f5 remove all sanity_check and ext_check methods from the library (Andrew Poelstra) cb2fa85 miniscript: replace from_str_ext with from_str_with_validation_params (Andrew Poelstra) 93ca9fa miniscript: replace decode_ext with decode_with_validation_params (Andrew Poelstra) e10b48f miniscript: add validate() method to Miniscript type (Andrew Poelstra) 163ba3e miniscript: add CONSENSUS and SANE consts to all contexts (Andrew Poelstra) 9320f36 miniscript: introduce ValidationParams type (Andrew Poelstra) Pull request description: This PR begins the process of overhauling the validation framework of this library. It introduces a `ValidationParams` struct which is a huge struct containing knobs for every single validation check that this library does. The goal is to centralize all these knobs, document them, apply them consistently, and make it possible for the user to choose any set of them. Currently validation is spread across a variety of `sanity_check` methods, inconsistently applied in various constructors for `Miniscript` and `Descriptor`, and only configurable in some ad-hoc inconsistent ways via methods like `from_str_insane`. There is no place where these are all listed; the closest thing is the `Ctx` type parameter, which has a bunch of methods like `check_local_policy_validity` which have inscrutable names and are all implemented by calling each other in slightly-different ways. In short, it's a mess. As a side-effect of this PR, we introduce some new validation errors which let us eliminate two variants from the top-level `Error` mega-enum. We also delete the `ExtParams` struct, which was similar in spirit to `ValidationParams`, except that it was incomplete and all its names sucked. This PR also introduces a soft-deprecation of the term "insane", which was used to mean "validate a bunch of rules, but not the ones that we decided are the boundary between a Miniscript that is 'sane' and not". We now use the term "consensus", i.e., "validate the consensus rules but no additional rules". Note that the new notion allows raw pkh fragments while the old one did not. I am open to reverting this change, but my feeling is that nobody will notice because nobody is pushing the boundaries of any of these validation rules. (If they were, they'd be filing a lot more bugs.) ACKs for top commit: Tree-SHA512: baced93e3a89aa0e6f3a0e02e4ed13ea5600d55fa345bbc60bf12eadd3aae8fe526115a4758198c6f5f54be5edf35aa8c2172411bba39d1be33ba76ced8fe376
2 parents 3b7e596 + f7756f5 commit e1bc60b

23 files changed

Lines changed: 727 additions & 417 deletions

File tree

embedded/src/main.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,6 @@ fn main() -> ! {
4444
hprintln!("p2sh address {}", p2sh_addr).unwrap();
4545
assert_eq!(p2sh_addr, "3CJxbQBfWAe1ZkKiGQNEYrioV73ZwvBWns");
4646

47-
// Check whether the descriptor is safe
48-
// This checks whether all spend paths are accessible in bitcoin network.
49-
// It maybe possible that some of the spend require more than 100 elements in Wsh scripts
50-
// Or they contain a combination of timelock and heightlock.
51-
assert!(desc.sanity_check().is_ok());
52-
5347
// Estimate the satisfaction cost
5448
assert_eq!(desc.max_weight_to_satisfy().unwrap().to_wu(), 288);
5549
// end miniscript test

examples/big.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ fn use_descriptor<K: MiniscriptKey>(d: Descriptor<K>) {
7575
println!("{}", d);
7676
println!("{:?}", d);
7777
println!("{:?}", d.desc_type());
78-
println!("{:?}", d.sanity_check());
7978
}
8079

8180
struct StrPkTranslator {

examples/htlc.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ fn main() {
2525
)
2626
.expect("Resource limits");
2727

28-
// Check whether the descriptor is safe. This checks whether all spend paths are accessible in
29-
// the Bitcoin network. It may be possible that some of the spend paths require more than 100
30-
// elements in Wsh scripts or they contain a combination of timelock and heightlock.
31-
assert!(htlc_descriptor.sanity_check().is_ok());
3228
assert_eq!(
3329
format!("{}", htlc_descriptor),
3430
"wsh(andor(pk(022222222222222222222222222222222222222222222222222222222222222222),sha256(1111111111111111111111111111111111111111111111111111111111111111),and_v(v:pkh(020202020202020202020202020202020202020202020202020202020202020202),older(4444))))#lfytrjen"

examples/parse.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,6 @@ fn main() {
1313
)
1414
.unwrap();
1515

16-
// Check whether the descriptor is safe. This checks whether all spend paths are accessible in
17-
// the Bitcoin network. It may be possible that some of the spend paths require more than 100
18-
// elements in Wsh scripts or they contain a combination of timelock and heightlock.
19-
assert!(desc.sanity_check().is_ok());
20-
2116
// Compute the script pubkey. As mentioned in the documentation, script_pubkey only fails
2217
// for Tr descriptors that don't have some pre-computed data.
2318
assert_eq!(

examples/psbt_sign_finalize.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ fn main() {
2020
let s = "wsh(t:or_c(pk(027a3565454fe1b749bccaef22aff72843a9c3efefd7b16ac54537a0c23f0ec0de),v:thresh(1,pkh(032d672a1a91cc39d154d366cd231983661b0785c7f27bc338447565844f4a6813),a:pkh(03417129311ed34c242c012cd0a3e0b9bca0065f742d0dfb63c78083ea6a02d4d9),a:pkh(025a687659658baeabdfc415164528065be7bcaade19342241941e556557f01e28))))#7hut9ukn";
2121
let bridge_descriptor = Descriptor::from_str(s).unwrap();
2222
//let bridge_descriptor = Descriptor::<bitcoin::PublicKey>::from_str(&s).expect("parse descriptor string");
23-
assert!(bridge_descriptor.sanity_check().is_ok());
2423
println!("Bridge pubkey script: {}", bridge_descriptor.script_pubkey());
2524
println!("Bridge address: {}", bridge_descriptor.address(Network::Regtest).unwrap());
2625
println!(

examples/taproot.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,6 @@ fn main() {
5252
.unwrap();
5353
assert_eq!(desc, expected_desc);
5454

55-
// Check whether the descriptors are safe.
56-
assert!(desc.sanity_check().is_ok());
57-
5855
// Descriptor type and version should match respectively for taproot
5956
let desc_type = desc.desc_type();
6057
assert_eq!(desc_type, DescriptorType::Tr);

fuzz/fuzz_targets/parse_descriptor_priv.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ fn do_test(data: &[u8]) {
1010

1111
if let Ok((desc, _)) = Descriptor::parse_descriptor(secp, &data_str) {
1212
let _output = desc.to_string();
13-
let _sanity_check = desc.sanity_check();
1413
}
1514
}
1615

src/descriptor/bare.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,6 @@ impl<Pk: MiniscriptKey> Bare<Pk> {
4747
/// get the inner
4848
pub fn as_inner(&self) -> &Miniscript<Pk, BareCtx> { &self.ms }
4949

50-
/// Checks whether the descriptor is safe.
51-
pub fn sanity_check(&self) -> Result<(), Error> {
52-
self.ms.sanity_check()?;
53-
Ok(())
54-
}
55-
5650
/// Computes an upper bound on the difference between a non-satisfied
5751
/// `TxIn`'s `segwit_weight` and a satisfied `TxIn`'s `segwit_weight`
5852
///

src/descriptor/mod.rs

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use sync::Arc;
2424
use crate::expression::FromTree as _;
2525
use crate::miniscript::decode::Terminal;
2626
use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG;
27-
use crate::miniscript::{satisfy, Legacy, Miniscript, Segwitv0};
27+
use crate::miniscript::{satisfy, Legacy, Miniscript, ScriptContext as _, Segwitv0, Tap};
2828
use crate::plan::{AssetProvider, Plan};
2929
use crate::prelude::*;
3030
use crate::{
@@ -305,26 +305,6 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
305305
}
306306
}
307307

308-
/// Checks whether the descriptor is safe.
309-
///
310-
/// Checks whether all the spend paths in the descriptor are possible on the
311-
/// bitcoin network under the current standardness and consensus rules. Also
312-
/// checks whether the descriptor requires signatures on all spend paths and
313-
/// whether the script is malleable.
314-
///
315-
/// In general, all the guarantees of miniscript hold only for safe scripts.
316-
/// The signer may not be able to find satisfactions even if one exists.
317-
pub fn sanity_check(&self) -> Result<(), Error> {
318-
match *self {
319-
Descriptor::Bare(ref bare) => bare.sanity_check(),
320-
Descriptor::Pkh(_) => Ok(()),
321-
Descriptor::Wpkh(ref wpkh) => wpkh.sanity_check(),
322-
Descriptor::Wsh(ref wsh) => wsh.sanity_check(),
323-
Descriptor::Sh(ref sh) => sh.sanity_check(),
324-
Descriptor::Tr(ref tr) => tr.sanity_check(),
325-
}
326-
}
327-
328308
/// Computes an upper bound on the difference between a non-satisfied
329309
/// `TxIn`'s `segwit_weight` and a satisfied `TxIn`'s `segwit_weight`
330310
///
@@ -1186,12 +1166,10 @@ impl<Pk: FromStrKey> FromStr for Descriptor<Pk> {
11861166
let top = expression::Tree::from_str(s)?;
11871167
let ret = Self::from_tree(top.root())?;
11881168
if let Descriptor::Tr(ref inner) = ret {
1189-
// FIXME preserve weird/broken behavior from 12.x.
1190-
// See https://github.com/rust-bitcoin/rust-miniscript/issues/734
1191-
ret.sanity_check()?;
11921169
for item in inner.leaves() {
11931170
item.miniscript()
1194-
.ext_check(&crate::miniscript::analyzable::ExtParams::sane())?;
1171+
.validate(&Tap::SANE)
1172+
.map_err(Error::Validation)?;
11951173
}
11961174
}
11971175
Ok(ret)

src/descriptor/segwitv0.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,6 @@ impl<Pk: MiniscriptKey> Wsh<Pk> {
5353
#[deprecated(since = "8.0.0", note = "use format!(\"{:#}\") instead")]
5454
pub fn to_string_no_checksum(&self) -> String { format!("{:#}", self) }
5555

56-
/// Checks whether the descriptor is safe.
57-
pub fn sanity_check(&self) -> Result<(), Error> {
58-
self.ms.sanity_check()?;
59-
Ok(())
60-
}
61-
6256
/// Computes an upper bound on the difference between a non-satisfied
6357
/// `TxIn`'s `segwit_weight` and a satisfied `TxIn`'s `segwit_weight`
6458
///
@@ -249,15 +243,6 @@ impl<Pk: MiniscriptKey> Wpkh<Pk> {
249243
#[deprecated(since = "8.0.0", note = "use format!(\"{:#}\") instead")]
250244
pub fn to_string_no_checksum(&self) -> String { format!("{:#}", self) }
251245

252-
/// Checks whether the descriptor is safe.
253-
pub fn sanity_check(&self) -> Result<(), Error> {
254-
if self.pk.is_uncompressed() {
255-
Err(Error::ContextError(ScriptContextError::CompressedOnly(self.pk.to_string())))
256-
} else {
257-
Ok(())
258-
}
259-
}
260-
261246
/// Computes an upper bound on the difference between a non-satisfied
262247
/// `TxIn`'s `segwit_weight` and a satisfied `TxIn`'s `segwit_weight`
263248
///

0 commit comments

Comments
 (0)