diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index eb3b0fd3d..f0587d74a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -3,16 +3,27 @@ on: [push, pull_request] name: Continuous integration jobs: + Prepare: + runs-on: ubuntu-24.04 + outputs: + nightly_version: ${{ steps.read_toolchain.outputs.nightly_version }} + steps: + - name: "Checkout repo" + uses: actions/checkout@v4 + - name: "Read nightly version" + id: read_toolchain + run: echo "nightly_version=$(cat nightly-version)" >> $GITHUB_OUTPUT + Fuzz: name: Fuzz runs-on: ubuntu-latest strategy: matrix: rust: - - 1.58.0 + - 1.65.0 steps: - name: Checkout Crate - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install hongfuzz dependancies run: sudo apt update && sudo apt install build-essential binutils-dev libunwind-dev libblocksruntime-dev liblzma-dev - name: Checkout Toolchain @@ -29,15 +40,16 @@ jobs: Nightly: name: Nightly - Bench + Docs + Fmt + needs: Prepare runs-on: ubuntu-latest steps: - name: Checkout Crate - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Checkout Toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: ${{ needs.Prepare.outputs.nightly_version }} override: true - name: Running benchmarks env: @@ -55,19 +67,20 @@ jobs: Tests: name: Tests + needs: Prepare runs-on: ubuntu-latest strategy: matrix: include: - rust: stable - rust: beta - - rust: nightly + - rust: ${{ needs.Prepare.outputs.nightly_version }} - rust: 1.41.1 - rust: 1.47 DO_NO_STD: true steps: - name: Checkout Crate - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Checkout Toolchain uses: actions-rs/toolchain@v1 with: @@ -81,17 +94,18 @@ jobs: run: ./contrib/test.sh Embedded: + needs: Prepare runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up QEMU run: sudo apt update && sudo apt install -y qemu-system-arm gcc-arm-none-eabi - name: Checkout Toolchain uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: ${{ needs.Prepare.outputs.nightly_version }} override: true components: rust-src target: thumbv7m-none-eabi diff --git a/Cargo-recent.lock b/Cargo-recent.lock new file mode 100644 index 000000000..9783376e2 --- /dev/null +++ b/Cargo-recent.lock @@ -0,0 +1,258 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ahash" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" + +[[package]] +name = "ahash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa60d2eadd8b12a996add391db32bd1153eac697ba4869660c0016353611426" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bitcoin" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" +dependencies = [ + "bech32", + "bitcoin_hashes", + "core2", + "hashbrown 0.8.2", + "secp256k1", + "serde", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +dependencies = [ + "core2", + "serde", +] + +[[package]] +name = "cc" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core2" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239fa3ae9b63c2dc74bd3fa852d4792b8b305ae64eeede946265b6af62f1fff3" +dependencies = [ + "memchr", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" +dependencies = [ + "ahash 0.3.8", + "autocfg", +] + +[[package]] +name = "hashbrown" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "362385356d610bd1e5a408ddf8d022041774b683f345a1d2cfcb4f60f8ae2db5" +dependencies = [ + "ahash 0.7.0", +] + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "memchr" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" + +[[package]] +name = "miniscript" +version = "9.2.1" +dependencies = [ + "bitcoin", + "hashbrown 0.11.0", + "rand", + "secp256k1", + "serde", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "ppv-lite86" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" + +[[package]] +name = "proc-macro2" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5907a1b7c277254a8b15170f6e7c97cfa60ee7872a3217663bb81151e48184bb" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "secp256k1" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +dependencies = [ + "bitcoin_hashes", + "rand", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.156" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.156" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/Cargo.toml b/Cargo.toml index 74bdc567a..0a2b8de2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "miniscript" -version = "9.2.0" +version = "9.2.1" authors = ["Andrew Poelstra , Sanket Kanjalkar "] license = "CC0-1.0" homepage = "https://github.com/rust-bitcoin/rust-miniscript/" @@ -29,7 +29,6 @@ hashbrown = { version = "0.11", optional = true } actual-serde = { package = "serde", version = "1.0", optional = true } [dev-dependencies] -bitcoind = { version = "0.27.0", features=["23_0"] } actual-rand = { package = "rand", version = "0.8.4"} secp256k1 = {version = "0.24.0", features = ["rand-std"]} diff --git a/clippy.toml b/clippy.toml index 799264ef1..92cf0149a 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1 +1,9 @@ msrv = "1.41.1" +# PSBT API returns Self as an error type for an large-ish enum +large-error-threshold = 512 +# A couple tests have huge tuples instead of structs. This is fixed +# in a later major rev. For now we just turn down the lint. +type-complexity-threshold = 1000 +# Some internal compiler functions take a gazillion arguments. Again, +# this is fixed in a later major rev so just turn down the lint here. +too-many-arguments-threshold = 9 diff --git a/contrib/test.sh b/contrib/test.sh index a1f213b49..90bb175e2 100755 --- a/contrib/test.sh +++ b/contrib/test.sh @@ -10,23 +10,7 @@ cargo update -p serde_derive --precise 1.0.142 cargo --version rustc --version -# Work out if we are using a nightly toolchain. -MSRV=false -if cargo --version | grep "1\.41\.0"; then - MSRV=true -fi - -if cargo --version | grep "1\.47\.0"; then - cargo update -p once_cell --precise 1.13.1 -fi - -# form_urlencoded 1.1.0 breaks MSRV. -if [ "$MSRV" = true ]; then - cargo update -p url --precise 2.2.2 - cargo update -p form_urlencoded --precise 1.0.1 - cargo update -p once_cell --precise 1.13.1 - cargo update -p syn --precise 1.0.107 -fi +cp Cargo-recent.lock Cargo.lock # Format if told to if [ "$DO_FMT" = true ] diff --git a/examples/psbt_sign_finalize.rs b/examples/psbt_sign_finalize.rs index 9876c92d6..426c98b03 100644 --- a/examples/psbt_sign_finalize.rs +++ b/examples/psbt_sign_finalize.rs @@ -2,10 +2,9 @@ use std::collections::BTreeMap; use std::str::FromStr; use bitcoin::consensus::serialize; +use bitcoin::hashes::hex::ToHex as _; use bitcoin::util::sighash::SighashCache; use bitcoin::{PackedLockTime, PrivateKey}; -use bitcoind::bitcoincore_rpc::jsonrpc::base64; -use bitcoind::bitcoincore_rpc::RawTx; use miniscript::bitcoin::consensus::encode::deserialize; use miniscript::bitcoin::hashes::hex::FromHex; use miniscript::bitcoin::util::psbt; @@ -20,7 +19,7 @@ fn main() { let secp256k1 = secp256k1::Secp256k1::new(); let s = "wsh(t:or_c(pk(027a3565454fe1b749bccaef22aff72843a9c3efefd7b16ac54537a0c23f0ec0de),v:thresh(1,pkh(032d672a1a91cc39d154d366cd231983661b0785c7f27bc338447565844f4a6813),a:pkh(03417129311ed34c242c012cd0a3e0b9bca0065f742d0dfb63c78083ea6a02d4d9),a:pkh(025a687659658baeabdfc415164528065be7bcaade19342241941e556557f01e28))))#7hut9ukn"; - let bridge_descriptor = Descriptor::from_str(&s).unwrap(); + let bridge_descriptor = Descriptor::from_str(s).unwrap(); //let bridge_descriptor = Descriptor::::from_str(&s).expect("parse descriptor string"); assert!(bridge_descriptor.sanity_check().is_ok()); println!( @@ -98,10 +97,12 @@ fn main() { let (outpoint, witness_utxo) = get_vout(&depo_tx, bridge_descriptor.script_pubkey()); - let mut txin = TxIn::default(); - txin.previous_output = outpoint; + let txin = TxIn { + previous_output: outpoint, - txin.sequence = Sequence::from_height(26); //Sequence::MAX; // + sequence: Sequence::from_height(26), + ..TxIn::default() + }; psbt.unsigned_tx.input.push(txin); psbt.unsigned_tx.output.push(TxOut { @@ -148,24 +149,24 @@ fn main() { let pk2 = backup2_private.public_key(&secp256k1); assert!(secp256k1.verify_ecdsa(&msg, &sig2, &pk2.inner).is_ok()); - psbt.inputs[0].partial_sigs.insert( - pk1, - bitcoin::EcdsaSig { - sig: sig1, - hash_ty: hash_ty, - }, - ); + psbt.inputs[0] + .partial_sigs + .insert(pk1, bitcoin::EcdsaSig { sig: sig1, hash_ty }); println!("{:#?}", psbt); + /* + // In bitcoin 0.29.x there is no base64 encoding of PSBTs, so this line + // would require an entire extra dependency. let serialized = serialize(&psbt); println!("{}", base64::encode(&serialized)); + */ psbt.finalize_mut(&secp256k1).unwrap(); println!("{:#?}", psbt); let tx = psbt.extract_tx(); - println!("{}", tx.raw_hex()); + println!("{}", serialize(&tx).to_hex()); } // Find the Outpoint by spk diff --git a/examples/sign_multisig.rs b/examples/sign_multisig.rs index 7471ff16f..f4a2c6801 100644 --- a/examples/sign_multisig.rs +++ b/examples/sign_multisig.rs @@ -105,8 +105,8 @@ fn spending_transaction() -> bitcoin::Transaction { } } +#[rustfmt::skip] fn list_of_three_arbitrary_public_keys() -> Vec { - #[cfg_attr(feature="cargo-fmt", rustfmt_skip)] vec![ bitcoin::PublicKey::from_slice(&[2; 33]).expect("key 1"), bitcoin::PublicKey::from_slice(&[ diff --git a/examples/taproot.rs b/examples/taproot.rs index 576c0192f..5428d9b48 100644 --- a/examples/taproot.rs +++ b/examples/taproot.rs @@ -136,8 +136,8 @@ fn hardcoded_xonlypubkeys() -> Vec { ], ]; let mut keys: Vec = vec![]; - for idx in 0..4 { - keys.push(bitcoin::XOnlyPublicKey::from_slice(&serialized_keys[idx][..]).unwrap()); + for key in &serialized_keys { + keys.push(bitcoin::XOnlyPublicKey::from_slice(key).unwrap()); } keys } diff --git a/examples/verify_tx.rs b/examples/verify_tx.rs index 9b0e9731b..32965caa0 100644 --- a/examples/verify_tx.rs +++ b/examples/verify_tx.rs @@ -59,15 +59,12 @@ fn main() { for elem in interpreter.iter_assume_sigs() { // Don't bother checking signatures. - match elem.expect("no evaluation error") { - miniscript::interpreter::SatisfiedConstraint::PublicKey { key_sig } => { - let (key, sig) = key_sig - .as_ecdsa() - .expect("expected ecdsa sig, found schnorr sig"); - - println!("Signed with:\n key: {}\n sig: {}", key, sig); - } - _ => {} + if let Ok(miniscript::interpreter::SatisfiedConstraint::PublicKey { key_sig }) = elem { + let (key, sig) = key_sig + .as_ecdsa() + .expect("expected ecdsa sig, found schnorr sig"); + + println!("Signed with:\n key: {}\n sig: {}", key, sig); } } @@ -84,12 +81,9 @@ fn main() { let prevouts = sighash::Prevouts::All::(&[]); for elem in interpreter.iter(&secp, &tx, 0, &prevouts) { - match elem.expect("no evaluation error") { - miniscript::interpreter::SatisfiedConstraint::PublicKey { key_sig } => { - let (key, sig) = key_sig.as_ecdsa().unwrap(); - println!("Signed with:\n key: {}\n sig: {}", key, sig); - } - _ => {} + if let Ok(miniscript::interpreter::SatisfiedConstraint::PublicKey { key_sig }) = elem { + let (key, sig) = key_sig.as_ecdsa().unwrap(); + println!("Signed with:\n key: {}\n sig: {}", key, sig); } } @@ -117,9 +111,9 @@ fn main() { } /// Returns an arbitrary transaction. +#[rustfmt::skip] fn hard_coded_transaction() -> bitcoin::Transaction { // tx `f27eba163c38ad3f34971198687a3f1882b7ec818599ffe469a8440d82261c98` - #[cfg_attr(feature="cargo-fmt", rustfmt_skip)] let tx_bytes = vec![ 0x01, 0x00, 0x00, 0x00, 0x02, 0xc5, 0x11, 0x1d, 0xb7, 0x93, 0x50, 0xc1, 0x70, 0x28, 0x41, 0x39, 0xe8, 0xe3, 0x4e, 0xb0, 0xed, 0xba, 0x64, 0x7b, diff --git a/examples/xpub_descriptors.rs b/examples/xpub_descriptors.rs index 64f7d718b..b988f4683 100644 --- a/examples/xpub_descriptors.rs +++ b/examples/xpub_descriptors.rs @@ -42,7 +42,7 @@ fn p2wsh(secp: &Secp256k1) -> Address { let address = Descriptor::::from_str(&s) .unwrap() - .derived_descriptor(&secp) + .derived_descriptor(secp) .unwrap() .address(Network::Bitcoin) .unwrap(); @@ -63,7 +63,7 @@ fn p2sh_p2wsh(secp: &Secp256k1) -> Address { let address = Descriptor::::from_str(&s) .unwrap() - .derived_descriptor(&secp, 5) + .derived_descriptor(secp, 5) .unwrap() .address(Network::Bitcoin) .unwrap(); diff --git a/nightly-version b/nightly-version new file mode 100644 index 000000000..b54e2edfc --- /dev/null +++ b/nightly-version @@ -0,0 +1 @@ +nightly-2025-06-20 diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 6af0146e0..7137f8914 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -442,8 +442,24 @@ impl DescriptorPublicKey { } } + /// Whether or not the key has a wildcard + fn has_hardened_step(&self) -> bool { + let paths = match self { + DescriptorPublicKey::Single(..) => &[], + DescriptorPublicKey::XPub(xpub) => core::slice::from_ref(&xpub.derivation_path), + }; + for p in paths { + for step in p.into_iter() { + if step.is_hardened() { + return true; + } + } + } + false + } + + #[doc(hidden)] #[deprecated(note = "use at_derivation_index instead")] - /// Deprecated name of [`at_derivation_index`]. pub fn derive(self, index: u32) -> DefiniteDescriptorKey { self.at_derivation_index(index) } @@ -665,9 +681,7 @@ impl DescriptorXKey { let (compare_fingerprint, compare_path) = match self.origin { Some((fingerprint, ref path)) => ( fingerprint, - path.into_iter() - .chain(self.derivation_path.into_iter()) - .collect(), + path.into_iter().chain(&self.derivation_path).collect(), ), None => ( self.xkey.xkey_fingerprint(secp), @@ -761,7 +775,7 @@ impl DefiniteDescriptorKey { /// /// Returns `None` if the key contains a wildcard fn new(key: DescriptorPublicKey) -> Option { - if key.has_wildcard() { + if key.has_wildcard() || key.has_hardened_step() { None } else { Some(Self(key)) @@ -784,11 +798,9 @@ impl FromStr for DefiniteDescriptorKey { fn from_str(s: &str) -> Result { let inner = DescriptorPublicKey::from_str(s)?; - Ok( - DefiniteDescriptorKey::new(inner).ok_or(DescriptorKeyParseError( - "cannot parse key with a wilcard as a DerivedDescriptorKey", - ))?, - ) + DefiniteDescriptorKey::new(inner).ok_or(DescriptorKeyParseError( + "cannot parse multi-path keys, keys with a wildcard or keys with hardened derivation steps as a DerivedDescriptorKey", + )) } } @@ -848,7 +860,9 @@ mod test { use bitcoin::secp256k1; - use super::{DescriptorKeyParseError, DescriptorPublicKey, DescriptorSecretKey}; + use super::{ + DefiniteDescriptorKey, DescriptorKeyParseError, DescriptorPublicKey, DescriptorSecretKey, + }; use crate::prelude::*; #[test] @@ -948,17 +962,17 @@ mod test { let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2").unwrap(); assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00"); assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2"); - assert_eq!(public_key.has_wildcard(), false); + assert!(!public_key.has_wildcard()); let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*").unwrap(); assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00"); assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'"); - assert_eq!(public_key.has_wildcard(), true); + assert!(public_key.has_wildcard()); let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*h").unwrap(); assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00"); assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'"); - assert_eq!(public_key.has_wildcard(), true); + assert!(public_key.has_wildcard()); } #[test] @@ -970,7 +984,7 @@ mod test { assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2"); assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d"); assert_eq!(public_key.full_derivation_path().to_string(), "m/0'/1'/2"); - assert_eq!(public_key.has_wildcard(), false); + assert!(!public_key.has_wildcard()); let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2'").unwrap(); let public_key = secret_key.to_public(&secp).unwrap(); @@ -1012,4 +1026,23 @@ mod test { b"\xb0\x59\x11\x6a" ); } + + #[test] + fn definite_keys() { + // basic xpub + let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" + .parse::() + .unwrap(); + assert!(DefiniteDescriptorKey::new(desc).is_some()); + // xpub with wildcard + let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/*" + .parse::() + .unwrap(); + assert!(DefiniteDescriptorKey::new(desc).is_none()); + // xpub with hardened path + let desc = "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/1'/2" + .parse::() + .unwrap(); + assert!(DefiniteDescriptorKey::new(desc).is_none()); + } } diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 31a30b2e3..44411020f 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -542,8 +542,8 @@ impl Descriptor { .expect("BIP 32 key index substitution cannot fail") } + #[doc(hidden)] #[deprecated(note = "use at_derivation_index instead")] - /// Deprecated name for [`at_derivation_index`]. pub fn derive(&self, index: u32) -> Descriptor { self.at_derivation_index(index) } @@ -569,7 +569,7 @@ impl Descriptor { /// See [`at_derivation_index`] and `[derived_descriptor`] for more documentation. /// /// [`at_derivation_index`]: Self::at_derivation_index - /// [`derived_descriptor`]: crate::DerivedDescriptor::derived_descriptor + /// [`derived_descriptor`]: crate::Descriptor::derived_descriptor /// /// # Errors /// @@ -579,7 +579,7 @@ impl Descriptor { secp: &secp256k1::Secp256k1, index: u32, ) -> Result, ConversionError> { - self.at_derivation_index(index).derived_descriptor(&secp) + self.at_derivation_index(index).derived_descriptor(secp) } /// Parse a descriptor that may contain secret keys @@ -591,7 +591,7 @@ impl Descriptor { s: &str, ) -> Result<(Descriptor, KeyMap), Error> { fn parse_key( - s: &String, + s: &str, key_map: &mut KeyMap, secp: &secp256k1::Secp256k1, ) -> Result { @@ -762,7 +762,7 @@ impl Descriptor { &mut self, pk: &DefiniteDescriptorKey, ) -> Result { - pk.derive_public_key(&self.0) + pk.derive_public_key(self.0) } translate_hash_clone!(DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError); @@ -856,16 +856,15 @@ mod tests { use crate::{hex_script, Descriptor, DummyKey, Error, Miniscript, Satisfier}; type StdDescriptor = Descriptor; - const TEST_PK: &'static str = - "pk(020000000000000000000000000000000000000000000000000000000000000002)"; + const TEST_PK: &str = "pk(020000000000000000000000000000000000000000000000000000000000000002)"; impl cmp::PartialEq for DescriptorSecretKey { fn eq(&self, other: &Self) -> bool { match (self, other) { - (&DescriptorSecretKey::Single(ref a), &DescriptorSecretKey::Single(ref b)) => { + (DescriptorSecretKey::Single(a), DescriptorSecretKey::Single(b)) => { a.origin == b.origin && a.key == b.key } - (&DescriptorSecretKey::XPrv(ref a), &DescriptorSecretKey::XPrv(ref b)) => { + (DescriptorSecretKey::XPrv(a), DescriptorSecretKey::XPrv(b)) => { a.origin == b.origin && a.xkey == b.xkey && a.derivation_path == b.derivation_path @@ -877,7 +876,7 @@ mod tests { } fn roundtrip_descriptor(s: &str) { - let desc = Descriptor::::from_str(&s).unwrap(); + let desc = Descriptor::::from_str(s).unwrap(); let output = desc.to_string(); let normalize_aliases = s.replace("c:pk_k(", "pk(").replace("c:pk_h(", "pkh("); assert_eq!( @@ -940,9 +939,9 @@ mod tests { #[test] pub fn script_pubkey() { - let bare = StdDescriptor::from_str(&format!( - "multi(1,020000000000000000000000000000000000000000000000000000000000000002)" - )) + let bare = StdDescriptor::from_str( + "multi(1,020000000000000000000000000000000000000000000000000000000000000002)", + ) .unwrap(); assert_eq!( bare.script_pubkey(), @@ -1664,8 +1663,8 @@ mod tests { "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))##tjq09x4t" ); - Descriptor::parse_descriptor(&secp, "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy").expect("Valid descriptor with checksum"); - Descriptor::parse_descriptor(&secp, "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t").expect("Valid descriptor with checksum"); + Descriptor::parse_descriptor(secp, "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy").expect("Valid descriptor with checksum"); + Descriptor::parse_descriptor(secp, "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t").expect("Valid descriptor with checksum"); } #[test] @@ -1695,7 +1694,7 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; let secp = &secp256k1::Secp256k1::signing_only(); let descriptor_str = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)#v20xlvm9"; let (descriptor, keymap) = - Descriptor::::parse_descriptor(&secp, descriptor_str).unwrap(); + Descriptor::::parse_descriptor(secp, descriptor_str).unwrap(); let expected = "wpkh([a12b02f4/44'/0'/0']xpub6BzhLAQUDcBUfHRQHZxDF2AbcJqp4Kaeq6bzJpXrjrWuK26ymTFwkEFbxPra2bJ7yeZKbDjfDeFwxe93JMqpo5SsPJH6dZdvV9kMzJkAZ69/0/*)#u37l7u8u"; assert_eq!(expected, descriptor.to_string()); diff --git a/src/descriptor/sortedmulti.rs b/src/descriptor/sortedmulti.rs index 7857188b0..352ffd0fe 100644 --- a/src/descriptor/sortedmulti.rs +++ b/src/descriptor/sortedmulti.rs @@ -112,11 +112,11 @@ impl SortedMultiVec { } impl ForEachKey for SortedMultiVec { - fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, { - self.pks.iter().all(|key| pred(key)) + self.pks.iter().all(pred) } } @@ -258,11 +258,11 @@ mod tests { let mut pks = Vec::new(); for _ in 0..over { - pks.push(pk.clone()); + pks.push(pk); } let res: Result, Error> = SortedMultiVec::new(0, pks); - let error = res.err().expect("constructor should err"); + let error = res.expect_err("constructor should err"); match error { Error::BadDescriptor(_) => {} // ok diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 3607461b9..4a8999280 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -81,11 +81,7 @@ impl Eq for Tr {} impl PartialOrd for Tr { fn partial_cmp(&self, other: &Self) -> Option { - match self.internal_key.partial_cmp(&other.internal_key) { - Some(cmp::Ordering::Equal) => {} - ord => return ord, - } - self.tree.partial_cmp(&other.tree) + Some(self.cmp(other)) } } @@ -120,7 +116,7 @@ impl TapTree { } /// Iterate over all miniscripts - pub fn iter(&self) -> TapTreeIter { + pub fn iter(&self) -> TapTreeIter<'_, Pk> { TapTreeIter { stack: vec![(0, self)], } @@ -189,7 +185,7 @@ impl Tr { /// Iterate over all scripts in merkle tree. If there is no script path, the iterator /// yields [`None`] - pub fn iter_scripts(&self) -> TapTreeIter { + pub fn iter_scripts(&self) -> TapTreeIter<'_, Pk> { match self.tree { Some(ref t) => t.iter(), None => TapTreeIter { stack: vec![] }, @@ -352,9 +348,8 @@ where type Item = (u8, &'a Miniscript); fn next(&mut self) -> Option { - while !self.stack.is_empty() { - let (depth, last) = self.stack.pop().expect("Size checked above"); - match &*last { + while let Some((depth, last)) = self.stack.pop() { + match last { TapTree::Tree(l, r) => { self.stack.push((depth + 1, r)); self.stack.push((depth + 1, l)); @@ -467,7 +462,7 @@ impl fmt::Display for Tr { } // Helper function to parse string into miniscript tree form -fn parse_tr_tree(s: &str) -> Result { +fn parse_tr_tree(s: &str) -> Result, Error> { for ch in s.bytes() { if !ch.is_ascii() { return Err(Error::Unprintable(ch)); diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index 59c8eb213..eed1398f7 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -344,22 +344,20 @@ pub(super) fn from_txdata<'txin>( None => Err(Error::UnexpectedStackEnd), } // ** bare script ** + } else if wit_stack.is_empty() { + // Bare script parsed in BareCtx + let miniscript = Miniscript::::parse_with_ext( + spk, + &ExtParams::allow_all(), + )?; + let miniscript = miniscript.to_no_checks_ms(); + Ok(( + Inner::Script(miniscript, ScriptType::Bare), + ssig_stack, + Some(spk.clone()), + )) } else { - if wit_stack.is_empty() { - // Bare script parsed in BareCtx - let miniscript = Miniscript::::parse_with_ext( - spk, - &ExtParams::allow_all(), - )?; - let miniscript = miniscript.to_no_checks_ms(); - Ok(( - Inner::Script(miniscript, ScriptType::Bare), - ssig_stack, - Some(spk.clone()), - )) - } else { - Err(Error::NonEmptyWitness) - } + Err(Error::NonEmptyWitness) } } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 293fd3273..fb4908e5b 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -103,7 +103,7 @@ enum BitcoinKey { } impl BitcoinKey { - fn to_pubkeyhash(&self, sig_type: SigType) -> hash160::Hash { + fn to_pubkeyhash(self, sig_type: SigType) -> hash160::Hash { match self { BitcoinKey::Fullkey(pk) => pk.to_pubkeyhash(sig_type), BitcoinKey::XOnlyPublicKey(pk) => pk.to_pubkeyhash(sig_type), @@ -1123,7 +1123,7 @@ mod tests { let (pks, der_sigs, ecdsa_sigs, sighash, secp, xpks, schnorr_sigs, ser_schnorr_sigs) = setup_keys_sigs(10); let secp_ref = &secp; - let vfyfn_ = |pksig: &KeySigPair| match pksig { + let vfyfn = |pksig: &KeySigPair| match pksig { KeySigPair::Ecdsa(pk, ecdsa_sig) => secp_ref .verify_ecdsa(&sighash, &ecdsa_sig.sig, &pk.inner) .is_ok(), @@ -1139,10 +1139,10 @@ mod tests { ) -> Iter<'elem, 'txin> { Iter { verify_sig: verify_fn, - stack: stack, + stack, public_key: None, state: vec![NodeEvaluationState { - node: &ms, + node: ms, n_evaluated: 0, n_satisfied: 0, }], @@ -1159,7 +1159,7 @@ mod tests { let after = no_checks_ms(&format!("after({})", 1000)); let older = no_checks_ms(&format!("older({})", 1000)); //Hashes - let preimage = [0xab as u8; 32]; + let preimage = [0xab_u8; 32]; let sha256_hash = sha256::Hash::hash(&preimage); let sha256 = no_checks_ms(&format!("sha256({})", sha256_hash)); let hash256_hash = hash256::Hash::hash(&preimage); @@ -1170,7 +1170,6 @@ mod tests { let ripemd160 = no_checks_ms(&format!("ripemd160({})", ripemd160_hash)); let stack = Stack::from(vec![stack::Element::Push(&der_sigs[0])]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &pk); let pk_satisfied: Result, Error> = constraints.collect(); assert_eq!( @@ -1182,7 +1181,6 @@ mod tests { //Check Pk failure with wrong signature let stack = Stack::from(vec![stack::Element::Dissatisfied]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &pk); let pk_err: Result, Error> = constraints.collect(); assert!(pk_err.is_err()); @@ -1193,7 +1191,6 @@ mod tests { stack::Element::Push(&der_sigs[1]), stack::Element::Push(&pk_bytes), ]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &pkh); let pkh_satisfied: Result, Error> = constraints.collect(); assert_eq!( @@ -1206,7 +1203,6 @@ mod tests { //Check After let stack = Stack::from(vec![]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &after); let after_satisfied: Result, Error> = constraints.collect(); assert_eq!( @@ -1218,7 +1214,6 @@ mod tests { //Check Older let stack = Stack::from(vec![]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &older); let older_satisfied: Result, Error> = constraints.collect(); assert_eq!( @@ -1230,53 +1225,49 @@ mod tests { //Check Sha256 let stack = Stack::from(vec![stack::Element::Push(&preimage)]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &sha256); let sah256_satisfied: Result, Error> = constraints.collect(); assert_eq!( sah256_satisfied.unwrap(), vec![SatisfiedConstraint::HashLock { hash: HashLockType::Sha256(sha256_hash), - preimage: preimage, + preimage, }] ); //Check Shad256 let stack = Stack::from(vec![stack::Element::Push(&preimage)]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &hash256); let sha256d_satisfied: Result, Error> = constraints.collect(); assert_eq!( sha256d_satisfied.unwrap(), vec![SatisfiedConstraint::HashLock { hash: HashLockType::Hash256(hash256_hash), - preimage: preimage, + preimage, }] ); //Check hash160 let stack = Stack::from(vec![stack::Element::Push(&preimage)]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &hash160); let hash160_satisfied: Result, Error> = constraints.collect(); assert_eq!( hash160_satisfied.unwrap(), vec![SatisfiedConstraint::HashLock { hash: HashLockType::Hash160(hash160_hash), - preimage: preimage, + preimage, }] ); //Check ripemd160 let stack = Stack::from(vec![stack::Element::Push(&preimage)]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &ripemd160); let ripemd160_satisfied: Result, Error> = constraints.collect(); assert_eq!( ripemd160_satisfied.unwrap(), vec![SatisfiedConstraint::HashLock { hash: HashLockType::Ripemd160(ripemd160_hash), - preimage: preimage + preimage, }] ); @@ -1288,7 +1279,6 @@ mod tests { stack::Element::Push(&der_sigs[0]), ]); 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); let and_v_satisfied: Result, Error> = constraints.collect(); @@ -1314,7 +1304,6 @@ mod tests { "and_b(c:pk_k({}),sjtv:sha256({}))", pks[0], sha256_hash )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let and_b_satisfied: Result, Error> = constraints.collect(); @@ -1326,7 +1315,7 @@ mod tests { }, SatisfiedConstraint::HashLock { hash: HashLockType::Sha256(sha256_hash), - preimage: preimage, + preimage, } ] ); @@ -1340,7 +1329,6 @@ mod tests { "andor(c:pk_k({}),jtv:sha256({}),c:pk_h({}))", pks[0], sha256_hash, pks[1], )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let and_or_satisfied: Result, Error> = constraints.collect(); @@ -1352,7 +1340,7 @@ mod tests { }, SatisfiedConstraint::HashLock { hash: HashLockType::Sha256(sha256_hash), - preimage: preimage, + preimage, } ] ); @@ -1364,7 +1352,6 @@ mod tests { stack::Element::Push(&pk_bytes), stack::Element::Dissatisfied, ]); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let and_or_satisfied: Result, Error> = constraints.collect(); @@ -1385,7 +1372,6 @@ mod tests { "or_b(c:pk_k({}),sjtv:sha256({}))", pks[0], sha256_hash )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let or_b_satisfied: Result, Error> = constraints.collect(); @@ -1393,7 +1379,7 @@ mod tests { or_b_satisfied.unwrap(), vec![SatisfiedConstraint::HashLock { hash: HashLockType::Sha256(sha256_hash), - preimage: preimage, + preimage, }] ); @@ -1403,7 +1389,6 @@ mod tests { "or_d(c:pk_k({}),jtv:sha256({}))", pks[0], sha256_hash )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let or_d_satisfied: Result, Error> = constraints.collect(); @@ -1423,7 +1408,6 @@ mod tests { "t:or_c(jtv:sha256({}),vc:pk_k({}))", sha256_hash, pks[0] )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let or_c_satisfied: Result, Error> = constraints.collect(); @@ -1443,7 +1427,6 @@ mod tests { "or_i(jtv:sha256({}),c:pk_k({}))", sha256_hash, pks[0] )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let or_i_satisfied: Result, Error> = constraints.collect(); @@ -1466,7 +1449,6 @@ mod tests { "thresh(3,c:pk_k({}),sc:pk_k({}),sc:pk_k({}),sc:pk_k({}),sc:pk_k({}))", pks[4], pks[3], pks[2], pks[1], pks[0], )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let thresh_satisfied: Result, Error> = constraints.collect(); @@ -1496,7 +1478,6 @@ mod tests { "multi(3,{},{},{},{},{})", pks[4], pks[3], pks[2], pks[1], pks[0], )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let multi_satisfied: Result, Error> = constraints.collect(); @@ -1526,7 +1507,6 @@ mod tests { "multi(3,{},{},{},{},{})", pks[4], pks[3], pks[2], pks[1], pks[0], )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let multi_error: Result, Error> = constraints.collect(); @@ -1545,7 +1525,6 @@ mod tests { "multi_a(3,{},{},{},{},{})", xpks[0], xpks[1], xpks[2], xpks[3], xpks[4], )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let multi_a_satisfied: Result, Error> = constraints.collect(); @@ -1577,7 +1556,6 @@ mod tests { "multi_a(3,{},{},{},{},{})", xpks[0], xpks[1], xpks[2], xpks[3], xpks[4], )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack.clone(), &elem); let multi_a_error: Result, Error> = constraints.collect(); @@ -1588,7 +1566,6 @@ mod tests { "multi_a(2,{},{},{},{},{})", xpks[0], xpks[1], xpks[2], xpks[3], xpks[4], )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack.clone(), &elem); let multi_a_error: Result, Error> = constraints.collect(); @@ -1599,7 +1576,6 @@ mod tests { "multi_a(3,{},{},{},{},{},{})", xpks[0], xpks[1], xpks[2], xpks[3], xpks[4], xpks[5] )); - let vfyfn = vfyfn_.clone(); // sigh rust 1.29... let constraints = from_stack(Box::new(vfyfn), stack, &elem); let multi_a_error: Result, Error> = constraints.collect(); diff --git a/src/lib.rs b/src/lib.rs index 96bf0ae04..8fe0baf3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,13 +82,13 @@ #![cfg_attr(all(test, feature = "unstable"), feature(test))] // Coding conventions #![deny(unsafe_code)] -#![deny(non_upper_case_globals)] -#![deny(non_camel_case_types)] -#![deny(non_snake_case)] -#![deny(unused_mut)] -#![deny(dead_code)] -#![deny(unused_imports)] -#![deny(missing_docs)] +#![warn(non_upper_case_globals)] +#![warn(non_camel_case_types)] +#![warn(non_snake_case)] +#![warn(unused_mut)] +#![warn(dead_code)] +#![warn(unused_imports)] +#![warn(missing_docs)] #[cfg(target_pointer_width = "16")] compile_error!( @@ -167,7 +167,7 @@ pub trait MiniscriptKey: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Ha /// The associated [`hash256::Hash`] for this [`MiniscriptKey`], /// used in the hash256 fragment. type Hash256: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash; - /// The associated [`ripedmd160::Hash`] for this [`MiniscriptKey`] type. + /// The associated [`ripemd160::Hash`] for this [`MiniscriptKey`] type. /// used in the ripemd160 fragment type Ripemd160: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash; @@ -557,16 +557,6 @@ where T: Translator; } -/// 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 { -// 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 diff --git a/src/miniscript/analyzable.rs b/src/miniscript/analyzable.rs index a98d2acbf..e7ea2d73d 100644 --- a/src/miniscript/analyzable.rs +++ b/src/miniscript/analyzable.rs @@ -29,9 +29,7 @@ use crate::{Miniscript, MiniscriptKey, ScriptContext, Terminal}; /// /// This allows parsing miniscripts if /// 1. It is unsafe(does not require a digital signature to spend it) -/// 2. It contains a unspendable path because of either -/// a. Resource limitations -/// b. Timelock Mixing +/// 2. It contains a unspendable path because of either resource limitations or timelock mixing. /// 3. The script is malleable and thereby some of satisfaction weight /// guarantees are not satisfied. /// 4. It has repeated public keys @@ -137,9 +135,7 @@ impl ExtParams { /// Possible reasons Miniscript guarantees can fail /// We currently mark Miniscript as Non-Analyzable if /// 1. It is unsafe(does not require a digital signature to spend it) -/// 2. It contains a unspendable path because of either -/// a. Resource limitations -/// b. Timelock Mixing +/// 2. It contains a unspendable path because of either resource limitations or timelock mixing. /// 3. The script is malleable and thereby some of satisfaction weight /// guarantees are not satisfied. /// 4. It has repeated publickeys diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index e691ff931..c20660797 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -113,9 +113,7 @@ impl Terminal { && c.real_for_each_key(pred) } 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(key)) - } + Terminal::Multi(_, ref keys) | Terminal::MultiA(_, ref keys) => keys.iter().all(pred), } } @@ -131,10 +129,10 @@ impl Terminal { Terminal::RawPkH(ref p) => Terminal::RawPkH(*p), Terminal::After(n) => Terminal::After(n), Terminal::Older(n) => Terminal::Older(n), - Terminal::Sha256(ref x) => Terminal::Sha256(t.sha256(&x)?), - Terminal::Hash256(ref x) => Terminal::Hash256(t.hash256(&x)?), - Terminal::Ripemd160(ref x) => Terminal::Ripemd160(t.ripemd160(&x)?), - Terminal::Hash160(ref x) => Terminal::Hash160(t.hash160(&x)?), + Terminal::Sha256(ref x) => Terminal::Sha256(t.sha256(x)?), + Terminal::Hash256(ref x) => Terminal::Hash256(t.hash256(x)?), + Terminal::Ripemd160(ref x) => Terminal::Ripemd160(t.ripemd160(x)?), + Terminal::Hash160(ref x) => Terminal::Hash160(t.hash160(x)?), Terminal::True => Terminal::True, Terminal::False => Terminal::False, Terminal::Alt(ref sub) => Terminal::Alt(Arc::new(sub.real_translate_pk(t)?)), @@ -624,7 +622,7 @@ impl Terminal { Terminal::RawPkH(ref hash) => builder .push_opcode(opcodes::all::OP_DUP) .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&hash) + .push_slice(hash) .push_opcode(opcodes::all::OP_EQUALVERIFY), Terminal::After(t) => builder .push_int(t.to_u32().into()) @@ -637,28 +635,28 @@ impl Terminal { .push_int(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_SHA256) - .push_slice(&Pk::to_sha256(&h)) + .push_slice(&Pk::to_sha256(h)) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Hash256(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) .push_int(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_HASH256) - .push_slice(&Pk::to_hash256(&h)) + .push_slice(&Pk::to_hash256(h)) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Ripemd160(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) .push_int(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_RIPEMD160) - .push_slice(&Pk::to_ripemd160(&h)) + .push_slice(&Pk::to_ripemd160(h)) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Hash160(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) .push_int(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&Pk::to_hash160(&h)) + .push_slice(&Pk::to_hash160(h)) .push_opcode(opcodes::all::OP_EQUAL), Terminal::True => builder.push_opcode(opcodes::OP_TRUE), Terminal::False => builder.push_opcode(opcodes::OP_FALSE), diff --git a/src/miniscript/context.rs b/src/miniscript/context.rs index 410d65031..d17cb9509 100644 --- a/src/miniscript/context.rs +++ b/src/miniscript/context.rs @@ -712,12 +712,9 @@ impl ScriptContext for BareCtx { return Err(ScriptContextError::MaxWitnessScriptSizeExceeded); } match ms.node { - Terminal::PkK(ref key) if key.is_x_only_key() => { - return Err(ScriptContextError::XOnlyKeysNotAllowed( - key.to_string(), - Self::name_str(), - )) - } + Terminal::PkK(ref key) if key.is_x_only_key() => Err( + ScriptContextError::XOnlyKeysNotAllowed(key.to_string(), Self::name_str()), + ), Terminal::Multi(_k, ref pks) => { if pks.len() > MAX_PUBKEYS_PER_MULTISIG { return Err(ScriptContextError::CheckMultiSigLimitExceeded); diff --git a/src/miniscript/decode.rs b/src/miniscript/decode.rs index 472b35702..96f6f983f 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -32,7 +32,6 @@ use crate::miniscript::ScriptContext; use crate::prelude::*; use crate::{bitcoin, hash256, Error, Miniscript, MiniscriptKey, ToPublicKey}; - /// Trait for parsing keys from byte slices pub trait ParseableKey: Sized + ToPublicKey + private::Sealed { /// Parse a key from slice @@ -124,7 +123,6 @@ enum NonTerm { /// /// The average user should always use the [`crate::Descriptor`] APIs. Advanced users /// who want deal with Miniscript ASTs should use the [`crate::Miniscript`] APIs. -#[allow(broken_intra_doc_links)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Terminal { /// `1` @@ -165,38 +163,38 @@ pub enum Terminal { Check(Arc>), /// `DUP IF [V] ENDIF` DupIf(Arc>), - /// [T] VERIFY + /// `[T] VERIFY` Verify(Arc>), - /// SIZE 0NOTEQUAL IF [Fn] ENDIF + /// `SIZE 0NOTEQUAL IF [Fn] ENDIF` NonZero(Arc>), - /// [X] 0NOTEQUAL + /// `[X] 0NOTEQUAL` ZeroNotEqual(Arc>), // Conjunctions - /// [V] [T]/[V]/[F]/[Kt] + /// `[V] [T]/[V]/[F]/[Kt]` AndV(Arc>, Arc>), - /// [E] [W] BOOLAND + /// `[E] [W] BOOLAND` AndB(Arc>, Arc>), - /// [various] NOTIF [various] ELSE [various] ENDIF + /// `[various] NOTIF [various] ELSE [various] ENDIF` AndOr( Arc>, Arc>, Arc>, ), // Disjunctions - /// [E] [W] BOOLOR + /// `[E] [W] BOOLOR` OrB(Arc>, Arc>), - /// [E] IFDUP NOTIF [T]/[E] ENDIF + /// `[E] IFDUP NOTIF [T]/[E] ENDIF` OrD(Arc>, Arc>), - /// [E] NOTIF [V] ENDIF + /// `[E] NOTIF [V] ENDIF` OrC(Arc>, Arc>), - /// IF [various] ELSE [various] ENDIF + /// `IF [various] ELSE [various] ENDIF` OrI(Arc>, Arc>), // Thresholds - /// [E] ([W] ADD)* k EQUAL + /// `[E] ([W] ADD)* k EQUAL` Thresh(usize, Vec>>), - /// k ()* n CHECKMULTISIG + /// `k ()* n CHECKMULTISIG` Multi(usize, Vec), - /// CHECKSIG ( CHECKSIGADD)*(n-1) k NUMEQUAL + /// ` CHECKSIG ( CHECKSIGADD)*(n-1) k NUMEQUAL` MultiA(usize, Vec), } diff --git a/src/miniscript/iter.rs b/src/miniscript/iter.rs index 45f3ccbb3..0091ab30a 100644 --- a/src/miniscript/iter.rs +++ b/src/miniscript/iter.rs @@ -29,14 +29,14 @@ impl Miniscript { /// Creates a new [Iter] iterator that will iterate over all [Miniscript] items within /// AST by traversing its branches. For the specific algorithm please see /// [Iter::next] function. - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, Pk, Ctx> { Iter::new(self) } /// Creates a new [PkIter] iterator that will iterate over all plain public keys (and not /// key hash values) present in [Miniscript] items within AST by traversing all its branches. /// For the specific algorithm please see [PkIter::next] function. - pub fn iter_pk(&self) -> PkIter { + pub fn iter_pk(&self) -> PkIter<'_, Pk, Ctx> { PkIter::new(self) } @@ -74,30 +74,30 @@ impl Miniscript { /// Returns child node with given index, if any pub fn get_nth_child(&self, n: usize) -> Option<&Miniscript> { match (n, &self.node) { - (0, &Terminal::Alt(ref node)) - | (0, &Terminal::Swap(ref node)) - | (0, &Terminal::Check(ref node)) - | (0, &Terminal::DupIf(ref node)) - | (0, &Terminal::Verify(ref node)) - | (0, &Terminal::NonZero(ref node)) - | (0, &Terminal::ZeroNotEqual(ref node)) - | (0, &Terminal::AndV(ref node, _)) - | (0, &Terminal::AndB(ref node, _)) - | (0, &Terminal::OrB(ref node, _)) - | (0, &Terminal::OrD(ref node, _)) - | (0, &Terminal::OrC(ref node, _)) - | (0, &Terminal::OrI(ref node, _)) - | (1, &Terminal::AndV(_, ref node)) - | (1, &Terminal::AndB(_, ref node)) - | (1, &Terminal::OrB(_, ref node)) - | (1, &Terminal::OrD(_, ref node)) - | (1, &Terminal::OrC(_, ref node)) - | (1, &Terminal::OrI(_, ref node)) - | (0, &Terminal::AndOr(ref node, _, _)) - | (1, &Terminal::AndOr(_, ref node, _)) - | (2, &Terminal::AndOr(_, _, ref node)) => Some(node), - - (n, &Terminal::Thresh(_, ref node_vec)) => node_vec.get(n).map(|x| &**x), + (0, Terminal::Alt(node)) + | (0, Terminal::Swap(node)) + | (0, Terminal::Check(node)) + | (0, Terminal::DupIf(node)) + | (0, Terminal::Verify(node)) + | (0, Terminal::NonZero(node)) + | (0, Terminal::ZeroNotEqual(node)) + | (0, Terminal::AndV(node, _)) + | (0, Terminal::AndB(node, _)) + | (0, Terminal::OrB(node, _)) + | (0, Terminal::OrD(node, _)) + | (0, Terminal::OrC(node, _)) + | (0, Terminal::OrI(node, _)) + | (1, Terminal::AndV(_, node)) + | (1, Terminal::AndB(_, node)) + | (1, Terminal::OrB(_, node)) + | (1, Terminal::OrD(_, node)) + | (1, Terminal::OrC(_, node)) + | (1, Terminal::OrI(_, node)) + | (0, Terminal::AndOr(node, _, _)) + | (1, Terminal::AndOr(_, node, _)) + | (2, Terminal::AndOr(_, _, node)) => Some(node), + + (n, Terminal::Thresh(_, node_vec)) => node_vec.get(n).map(|x| &**x), _ => None, } @@ -222,10 +222,8 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkIter<'a, Pk, Ctx> } } -// Module is public since it export testcase generation which may be used in -// dependent libraries for their own tasts based on Miniscript AST #[cfg(test)] -pub mod test { +mod test { use bitcoin; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; use bitcoin::secp256k1; @@ -233,14 +231,14 @@ pub mod test { use super::Miniscript; use crate::miniscript::context::Segwitv0; - pub type TestData = ( + type TestData = ( Miniscript, Vec, Vec, bool, // Indicates that the top-level contains public key or hashes ); - pub fn gen_secp_pubkeys(n: usize) -> Vec { + fn gen_secp_pubkeys(n: usize) -> Vec { let mut ret = Vec::with_capacity(n); let secp = secp256k1::Secp256k1::new(); let mut sk = [0; 32]; @@ -258,24 +256,24 @@ pub mod test { ret } - pub fn gen_bitcoin_pubkeys(n: usize, compressed: bool) -> Vec { + fn gen_bitcoin_pubkeys(n: usize, compressed: bool) -> Vec { gen_secp_pubkeys(n) .into_iter() .map(|inner| bitcoin::PublicKey { inner, compressed }) .collect() } - pub fn gen_testcases() -> Vec { + fn gen_testcases() -> Vec { let k = gen_bitcoin_pubkeys(10, true); let _h: Vec = k .iter() .map(|pk| hash160::Hash::hash(&pk.to_bytes())) .collect(); - let preimage = vec![0xab as u8; 32]; + let preimage = vec![0xab_u8; 32]; let sha256_hash = sha256::Hash::hash(&preimage); let sha256d_hash_rev = sha256d::Hash::hash(&preimage); - let mut sha256d_hash_bytes = sha256d_hash_rev.clone().into_inner(); + let mut sha256d_hash_bytes = sha256d_hash_rev.into_inner(); sha256d_hash_bytes.reverse(); let sha256d_hash = sha256d::Hash::from_inner(sha256d_hash_bytes); let hash160_hash = hash160::Hash::hash(&preimage); diff --git a/src/miniscript/lex.rs b/src/miniscript/lex.rs index a113824d3..bb2e8f188 100644 --- a/src/miniscript/lex.rs +++ b/src/miniscript/lex.rs @@ -89,7 +89,7 @@ impl<'s> TokenIter<'s> { } /// Look at the top at Iterator - pub fn peek(&self) -> Option<&'s Token> { + pub fn peek(&self) -> Option<&'s Token<'_>> { self.0.last() } diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 8fb3d4988..471638714 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -77,7 +77,6 @@ mod private { phantom: PhantomData, } impl Miniscript { - /// Add type information(Type and Extdata) to Miniscript based on /// `AstElem` fragment. Dependent on display and clone because of Error /// Display code of type_check. @@ -109,7 +108,12 @@ mod private { ty: types::Type, ext: types::extra_props::ExtData, ) -> Miniscript { - Miniscript { node, ty, ext, phantom: PhantomData } + Miniscript { + node, + ty, + ext, + phantom: PhantomData, + } } } } @@ -121,7 +125,7 @@ pub use private::Miniscript; /// by the ast. impl PartialOrd for Miniscript { fn partial_cmp(&self, other: &Miniscript) -> Option { - Some(self.node.cmp(&other.node)) + Some(self.cmp(other)) } } @@ -167,7 +171,6 @@ impl fmt::Display for Miniscript } impl Miniscript { - /// Extracts the `AstElem` representing the root of the miniscript pub fn into_inner(self) -> Terminal { self.node @@ -360,8 +363,8 @@ impl Miniscript { T: Translator, { let inner = self.node.real_translate_pk(t)?; - let ms = Miniscript::from_ast(inner) - .expect("Translator should not change the type of the AST"); + let ms = + Miniscript::from_ast(inner).expect("Translator should not change the type of the AST"); Ok(ms) } } @@ -471,7 +474,7 @@ impl_from_tree!( /// should not be called directly; rather go through the descriptor API. fn from_tree(top: &expression::Tree) -> Result, Error> { let inner: Terminal = expression::FromTree::from_tree(top)?; - Ok(Miniscript::from_ast(inner)?) + Miniscript::from_ast(inner) } ); @@ -503,12 +506,11 @@ mod tests { use sync::Arc; use super::{Miniscript, ScriptContext, Segwitv0, Tap}; - use crate::miniscript::types; - use crate::miniscript::Terminal; + use crate::miniscript::{types, Terminal}; use crate::policy::Liftable; - use crate::{prelude::*, Error}; + use crate::prelude::*; use crate::test_utils::{StrKeyTranslator, StrXOnlyKeyTranslator}; - use crate::{hex_script, DummyKey, ExtParams, Satisfier, ToPublicKey, TranslatePk}; + use crate::{hex_script, DummyKey, Error, ExtParams, Satisfier, ToPublicKey, TranslatePk}; type Segwitv0Script = Miniscript; type Tapscript = Miniscript; @@ -625,7 +627,7 @@ mod tests { assert_eq!(ms.ty.mall.safe, need_sig); assert_eq!(ms.ext.ops.op_count().unwrap(), ops); } - (Err(_), false) => return, + (Err(_), false) => {} _ => unreachable!(), } } @@ -992,28 +994,28 @@ mod tests { #[test] fn test_tapscript_rtt() { // Test x-only invalid under segwitc0 context - let ms = Segwitv0Script::from_str_insane(&format!( - "pk(2788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)" - )); + let ms = Segwitv0Script::from_str_insane( + "pk(2788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)", + ); assert_eq!( - ms.unwrap_err().to_string(), - "unexpected «key hex decoding error»", + &ms.unwrap_err().to_string()[..35], + "unexpected «key hex decoding error", ); - Tapscript::from_str_insane(&format!( - "pk(2788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)" - )) + Tapscript::from_str_insane( + "pk(2788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)", + ) .unwrap(); // Now test that bitcoin::PublicKey works with Taproot context - Miniscript::::from_str_insane(&format!( - "pk(022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)" - )) + Miniscript::::from_str_insane( + "pk(022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)", + ) .unwrap(); // uncompressed keys should not be allowed - Miniscript::::from_str_insane(&format!( + Miniscript::::from_str_insane( "pk(04eed24a081bf1b1e49e3300df4bebe04208ac7e516b6f3ea8eb6e094584267c13483f89dcf194132e12238cc5a34b6b286fc7990d68ed1db86b69ebd826c63b29)" - )) + ) .unwrap_err(); //---------------- test script <-> miniscript --------------- @@ -1039,14 +1041,14 @@ mod tests { .unwrap(); // multi not allowed in tapscript - Tapscript::from_str_insane(&format!( - "multi(1,2788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)" - )) + Tapscript::from_str_insane( + "multi(1,2788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)", + ) .unwrap_err(); // but allowed in segwit - Segwitv0Script::from_str_insane(&format!( - "multi(1,022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)" - )) + Segwitv0Script::from_str_insane( + "multi(1,022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)", + ) .unwrap(); } @@ -1143,7 +1145,8 @@ mod tests { #[test] fn test_script_parse_dos() { - let mut script = bitcoin::blockdata::script::Builder::new().push_opcode(bitcoin::blockdata::opcodes::OP_TRUE); + let mut script = bitcoin::blockdata::script::Builder::new() + .push_opcode(bitcoin::blockdata::opcodes::OP_TRUE); for _ in 0..10000 { script = script.push_opcode(bitcoin::blockdata::opcodes::all::OP_0NOTEQUAL); } diff --git a/src/miniscript/ms_tests.rs b/src/miniscript/ms_tests.rs index 2b44e2025..5d9f33cb6 100644 --- a/src/miniscript/ms_tests.rs +++ b/src/miniscript/ms_tests.rs @@ -79,7 +79,7 @@ mod tests { } #[test] - #[cfg_attr(feature="cargo-fmt", rustfmt_skip)] + #[rustfmt::skip] fn invalid_tests_from_alloy() { invalid_ms("or_b(or_i(0,sha256(926a54995ca48600920a19bf7bc502ca5f2f7d07e6f804c4f00ebf0325084dbc)),after(1))"); invalid_ms("or_b(s:pk_h(A),after(500000001))"); @@ -5657,7 +5657,7 @@ mod tests { invalid_ms("c:or_b(sha256(926a54995ca48600920a19bf7bc502ca5f2f7d07e6f804c4f00ebf0325084dbc),pk_k(A))"); } #[test] - #[cfg_attr(feature="cargo-fmt", rustfmt_skip)] + #[rustfmt::skip] fn mall_8f1e8_tests_from_alloy() { ms_test("or_d(or_d(sha256(926a54995ca48600920a19bf7bc502ca5f2f7d07e6f804c4f00ebf0325084dbc),sha256(926a54995ca48600920a19bf7bc502ca5f2f7d07e6f804c4f00ebf0325084dbc)),after(500000001))", "Bf"); ms_test("andor(sha256(926a54995ca48600920a19bf7bc502ca5f2f7d07e6f804c4f00ebf0325084dbc),or_d(multi(2,A,B,C),sha256(926a54995ca48600920a19bf7bc502ca5f2f7d07e6f804c4f00ebf0325084dbc)),after(1))", "B"); @@ -9154,7 +9154,7 @@ mod tests { } #[test] - #[cfg_attr(feature="cargo-fmt", rustfmt_skip)] + #[rustfmt::skip] fn main_tests_from_alloy() { ms_test("or_d(or_d(multi(2,A,B,C),or_d(multi(2,D,E,F),multi(2,G,I,J))),multi(2,K,L,M))", "Bdusem"); ms_test("andor(multi(2,A,B,C),or_d(multi(2,D,E,F),sha256(926a54995ca48600920a19bf7bc502ca5f2f7d07e6f804c4f00ebf0325084dbc)),c:pk_h(G))", "Bdusem"); @@ -15055,7 +15055,7 @@ mod tests { } #[test] - #[cfg_attr(feature="cargo-fmt", rustfmt_skip)] + #[rustfmt::skip] fn malleable_tests_from_alloy() { ms_test("and_v(v:after(500000001),or_d(j:multi(2,A,B,C),multi(2,D,E,F)))", "usB"); ms_test("or_b(j:multi(2,A,B,C),a:andor(multi(2,D,E,F),multi(2,G,I,J),multi(2,K,L,M)))", "dBesu"); @@ -22085,8 +22085,8 @@ mod tests { } #[test] + #[rustfmt::skip] fn conflict_tests_from_alloy() { - #[cfg_attr(feature="cargo-fmt", rustfmt_skip)] { ms_test("andor(multi(2,A,B,C),andor(multi(2,D,E,F),after(500000001),n:after(1)),0)","Bedsm"); ms_test("and_v(v:after(500000001),or_d(multi(2,A,B,C),and_b(multi(2,D,E,F),a:after(1))))","Busm"); diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index 03f2e1b1c..826c3fdb9 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -220,7 +220,7 @@ where } } -impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &'a S { +impl> Satisfier for &'_ S { fn lookup_ecdsa_sig(&self, p: &Pk) -> Option { (**self).lookup_ecdsa_sig(p) } @@ -286,7 +286,7 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' } } -impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &'a mut S { +impl> Satisfier for &'_ mut S { fn lookup_ecdsa_sig(&self, p: &Pk) -> Option { (**self).lookup_ecdsa_sig(p) } @@ -548,17 +548,17 @@ impl PartialOrd for Witness { impl Ord for Witness { fn cmp(&self, other: &Self) -> cmp::Ordering { match (self, other) { - (&Witness::Stack(ref v1), &Witness::Stack(ref v2)) => { + (Witness::Stack(v1), Witness::Stack(v2)) => { let w1 = witness_size(v1); let w2 = witness_size(v2); w1.cmp(&w2) } - (&Witness::Stack(_), _) => cmp::Ordering::Less, - (_, &Witness::Stack(_)) => cmp::Ordering::Greater, - (&Witness::Impossible, &Witness::Unavailable) => cmp::Ordering::Less, - (&Witness::Unavailable, &Witness::Impossible) => cmp::Ordering::Greater, - (&Witness::Impossible, &Witness::Impossible) => cmp::Ordering::Equal, - (&Witness::Unavailable, &Witness::Unavailable) => cmp::Ordering::Equal, + (Witness::Stack(_), _) => cmp::Ordering::Less, + (_, Witness::Stack(_)) => cmp::Ordering::Greater, + (Witness::Impossible, Witness::Unavailable) => cmp::Ordering::Less, + (Witness::Unavailable, Witness::Impossible) => cmp::Ordering::Greater, + (Witness::Impossible, Witness::Impossible) => cmp::Ordering::Equal, + (Witness::Unavailable, Witness::Unavailable) => cmp::Ordering::Equal, } } } @@ -758,11 +758,11 @@ impl Satisfaction { let mut sat_indices = (0..subs.len()).collect::>(); sat_indices.sort_by_key(|&i| { let stack_weight = match (&sats[i].stack, &ret_stack[i].stack) { - (&Witness::Unavailable, _) | (&Witness::Impossible, _) => i64::MAX, + (Witness::Unavailable, _) | (Witness::Impossible, _) => i64::MAX, // This can only be the case when we have PkH without the corresponding // Pubkey. - (_, &Witness::Unavailable) | (_, &Witness::Impossible) => i64::MIN, - (&Witness::Stack(ref s), &Witness::Stack(ref d)) => { + (_, Witness::Unavailable) | (_, Witness::Impossible) => i64::MIN, + (Witness::Stack(s), Witness::Stack(d)) => { witness_size(s) as i64 - witness_size(d) as i64 } }; @@ -880,7 +880,7 @@ impl Satisfaction { (&Witness::Unavailable, _) | (&Witness::Impossible, _) => i64::MAX, // This is only possible when one of the branches has PkH (_, &Witness::Unavailable) | (_, &Witness::Impossible) => i64::MIN, - (&Witness::Stack(ref s), &Witness::Stack(ref d)) => { + (Witness::Stack(s), Witness::Stack(d)) => { witness_size(s) as i64 - witness_size(d) as i64 } } diff --git a/src/miniscript/types/correctness.rs b/src/miniscript/types/correctness.rs index 1beba0798..9c989c71e 100644 --- a/src/miniscript/types/correctness.rs +++ b/src/miniscript/types/correctness.rs @@ -496,10 +496,8 @@ impl Property for Correctness { if subtype.base != Base::B { return Err(ErrorKind::ThresholdBase(i, subtype.base)); } - } else { - if subtype.base != Base::W { - return Err(ErrorKind::ThresholdBase(i, subtype.base)); - } + } else if subtype.base != Base::W { + return Err(ErrorKind::ThresholdBase(i, subtype.base)); } if !subtype.unit { return Err(ErrorKind::ThresholdNonUnit(i)); diff --git a/src/miniscript/types/extra_props.rs b/src/miniscript/types/extra_props.rs index 1a55d68bc..490a0b210 100644 --- a/src/miniscript/types/extra_props.rs +++ b/src/miniscript/types/extra_props.rs @@ -166,7 +166,7 @@ impl Property for ExtData { timelock_info: TimelockInfo::default(), exec_stack_elem_count_sat: Some(1), exec_stack_elem_count_dissat: None, - tree_height : 0, + tree_height: 0, } } @@ -182,7 +182,7 @@ impl Property for ExtData { timelock_info: TimelockInfo::default(), exec_stack_elem_count_sat: None, exec_stack_elem_count_dissat: Some(1), - tree_height : 0, + tree_height: 0, } } @@ -406,7 +406,7 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat, - tree_height : self.tree_height + 1, + tree_height: self.tree_height + 1, }) } @@ -422,7 +422,7 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat, - tree_height : self.tree_height + 1, + tree_height: self.tree_height + 1, }) } @@ -438,7 +438,7 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat, - tree_height : self.tree_height + 1, + tree_height: self.tree_height + 1, }) } @@ -457,7 +457,7 @@ impl Property for ExtData { // Even all V types push something onto the stack and then remove them exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: Some(1), - tree_height : self.tree_height + 1, + tree_height: self.tree_height + 1, }) } @@ -474,7 +474,7 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: None, - tree_height : self.tree_height + 1, + tree_height: self.tree_height + 1, }) } @@ -490,7 +490,7 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: Some(1), - tree_height : self.tree_height + 1, + tree_height: self.tree_height + 1, }) } @@ -507,7 +507,7 @@ impl Property for ExtData { // Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat, - tree_height : self.tree_height + 1, + tree_height: self.tree_height + 1, }) } @@ -548,7 +548,7 @@ impl Property for ExtData { l.exec_stack_elem_count_dissat, r.exec_stack_elem_count_dissat.map(|x| x + 1), ), - tree_height : cmp::max(l.tree_height, r.tree_height) + 1, + tree_height: cmp::max(l.tree_height, r.tree_height) + 1, }) } @@ -576,7 +576,7 @@ impl Property for ExtData { r.exec_stack_elem_count_sat, ), exec_stack_elem_count_dissat: None, - tree_height : cmp::max(l.tree_height, r.tree_height) + 1, + tree_height: cmp::max(l.tree_height, r.tree_height) + 1, }) } @@ -625,7 +625,7 @@ impl Property for ExtData { l.exec_stack_elem_count_dissat, r.exec_stack_elem_count_dissat.map(|x| x + 1), ), - tree_height : cmp::max(l.tree_height, r.tree_height) + 1, + tree_height: cmp::max(l.tree_height, r.tree_height) + 1, }) } @@ -663,7 +663,7 @@ impl Property for ExtData { l.exec_stack_elem_count_dissat, r.exec_stack_elem_count_dissat.map(|x| x + 1), ), - tree_height : cmp::max(l.tree_height, r.tree_height) + 1, + tree_height: cmp::max(l.tree_height, r.tree_height) + 1, }; Ok(res) } @@ -695,7 +695,7 @@ impl Property for ExtData { opt_max(r.exec_stack_elem_count_sat, l.exec_stack_elem_count_dissat), ), exec_stack_elem_count_dissat: None, - tree_height : cmp::max(l.tree_height, r.tree_height) + 1, + tree_height: cmp::max(l.tree_height, r.tree_height) + 1, }) } @@ -743,7 +743,7 @@ impl Property for ExtData { l.exec_stack_elem_count_dissat, r.exec_stack_elem_count_dissat, ), - tree_height : cmp::max(l.tree_height, r.tree_height) + 1, + tree_height: cmp::max(l.tree_height, r.tree_height) + 1, }) } @@ -789,7 +789,7 @@ impl Property for ExtData { a.exec_stack_elem_count_dissat, c.exec_stack_elem_count_dissat, ), - tree_height : cmp::max(a.tree_height, cmp::max(b.tree_height, c.tree_height)) + 1, + tree_height: cmp::max(a.tree_height, cmp::max(b.tree_height, c.tree_height)) + 1, }) } @@ -852,11 +852,11 @@ impl Property for ExtData { .iter() .rev() .enumerate() - .fold(Some(0), |acc, (i, &(x, y))| { + .try_fold(0, |acc, (i, &(x, y))| { if i <= k { - opt_add(acc, x) + x.map(|x| acc + x) } else { - opt_add(acc, y) + y.map(|y| acc + y) } }); @@ -865,11 +865,11 @@ impl Property for ExtData { .iter() .rev() .enumerate() - .fold(Some(0), |acc, (i, &(x, y))| { + .try_fold(0, |acc, (i, &(x, y))| { if i <= k { - opt_max(acc, x) + x.map(|x| cmp::max(acc, x)) } else { - opt_max(acc, y) + y.map(|y| cmp::max(acc, y)) } }); @@ -879,26 +879,25 @@ impl Property for ExtData { max_sat_size_vec .iter() .enumerate() - .fold(Some((0, 0)), |acc, (i, &(x, y))| { + .try_fold((0, 0), |acc, (i, &(x, y))| { if i <= k { - opt_tuple_add(acc, x) + x.map(|x| (acc.0 + x.0, acc.1 + x.1)) } else { - opt_tuple_add(acc, y) + y.map(|y| (acc.0 + y.0, acc.1 + y.1)) } }); ops_count_sat_vec.sort_by(sat_minus_dissat); - let op_count_sat = - ops_count_sat_vec - .iter() - .enumerate() - .fold(Some(0), |acc, (i, &(x, y))| { - if i <= k { - opt_add(acc, x) - } else { - opt_add(acc, Some(y)) - } - }); + let op_count_sat = ops_count_sat_vec + .iter() + .enumerate() + .try_fold(0, |acc, (i, &(x, y))| { + if i <= k { + x.map(|x| acc + x) + } else { + Some(acc + y) + } + }); Ok(ExtData { pk_cost: pk_cost + n - 1, //all pk cost + (n-1)*ADD @@ -915,7 +914,7 @@ impl Property for ExtData { timelock_info: TimelockInfo::combine_threshold(k, timelocks), exec_stack_elem_count_sat, exec_stack_elem_count_dissat, - tree_height : max_child_height + 1, + tree_height: max_child_height + 1, }) } @@ -1064,10 +1063,7 @@ impl Property for ExtData { // costy satisfactions are satisfied, the most costy dissatisfactions are dissatisfied). // // Args are of form: (, ) -fn sat_minus_dissat<'r, 's>( - a: &'r (Option, usize), - b: &'s (Option, usize), -) -> cmp::Ordering { +fn sat_minus_dissat(a: &(Option, usize), b: &(Option, usize)) -> cmp::Ordering { a.0.map(|x| x as isize - a.1 as isize) .cmp(&b.0.map(|x| x as isize - b.1 as isize)) } @@ -1078,9 +1074,9 @@ fn sat_minus_dissat<'r, 's>( // costy satisfactions are satisfied, the most costy dissatisfactions are dissatisfied). // // Args are of form: (, ) -fn sat_minus_option_dissat<'r, 's>( - a: &'r (Option, Option), - b: &'s (Option, Option), +fn sat_minus_option_dissat( + a: &(Option, Option), + b: &(Option, Option), ) -> cmp::Ordering { a.0.map(|x| a.1.map(|y| x as isize - y as isize)) .cmp(&b.0.map(|x| b.1.map(|y| x as isize - y as isize))) @@ -1090,9 +1086,9 @@ fn sat_minus_option_dissat<'r, 's>( // // Args are of form: (, ) // max_[dis]sat_size of form: (, ) -fn sat_minus_dissat_witness<'r, 's>( - a: &'r (Option<(usize, usize)>, Option<(usize, usize)>), - b: &'s (Option<(usize, usize)>, Option<(usize, usize)>), +fn sat_minus_dissat_witness( + a: &(Option<(usize, usize)>, Option<(usize, usize)>), + b: &(Option<(usize, usize)>, Option<(usize, usize)>), ) -> cmp::Ordering { a.0.map(|x| a.1.map(|y| x.0 as isize - y.0 as isize)) .cmp(&b.0.map(|x| b.1.map(|y| x.0 as isize - y.0 as isize))) @@ -1112,11 +1108,6 @@ fn opt_add(a: Option, b: Option) -> Option { a.and_then(|x| b.map(|y| x + y)) } -/// Returns Some((x0+y0, x1+y1)) is both x and y are Some. Otherwise, returns `None`. -fn opt_tuple_add(a: Option<(usize, usize)>, b: Option<(usize, usize)>) -> Option<(usize, usize)> { - a.and_then(|x| b.map(|(w, s)| (w + x.0, s + x.1))) -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 77febf917..8372cabad 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -36,10 +36,15 @@ type PolicyCache = BTreeMap<(Concrete, OrdF64, Option), BTreeMap>>; ///Ordered f64 for comparison -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub(crate) struct OrdF64(pub f64); impl Eq for OrdF64 {} +impl PartialOrd for OrdF64 { + fn partial_cmp(&self, other: &OrdF64) -> Option { + Some(self.cmp(other)) + } +} impl Ord for OrdF64 { fn cmp(&self, other: &OrdF64) -> cmp::Ordering { // will panic if given NaN @@ -506,9 +511,7 @@ impl AstElemExt { let ext = types::ExtData::type_check(&ast, |_| None)?; let comp_ext_data = CompilerExtData::type_check(&ast, lookup_ext)?; Ok(AstElemExt { - ms: Arc::new( - Miniscript::from_components_unchecked(ast, ty, ext) - ), + ms: Arc::new(Miniscript::from_components_unchecked(ast, ty, ext)), comp_ext_data, }) } @@ -531,9 +534,7 @@ impl AstElemExt { let ext = types::ExtData::type_check(&ast, |_| None)?; let comp_ext_data = CompilerExtData::type_check(&ast, lookup_ext)?; Ok(AstElemExt { - ms: Arc::new( - Miniscript::from_components_unchecked(ast, ty, ext) - ), + ms: Arc::new(Miniscript::from_components_unchecked(ast, ty, ext)), comp_ext_data, }) } @@ -678,19 +679,16 @@ fn insert_elem( // Check whether the new element is worse than any existing element. If there // is an element which is a subtype of the current element and has better // cost, don't consider this element. - let is_worse = map - .iter() - .map(|(existing_key, existing_elem)| { - let existing_elem_cost = existing_elem.cost_1d(sat_prob, dissat_prob); - existing_key.is_subtype(elem_key) && existing_elem_cost <= elem_cost - }) - .any(|x| x); + let is_worse = map.iter().any(|(existing_key, existing_elem)| { + let existing_elem_cost = existing_elem.cost_1d(sat_prob, dissat_prob); + existing_key.is_subtype(elem_key) && existing_elem_cost <= elem_cost + }); if !is_worse { // If the element is not worse any element in the map, remove elements // whose subtype is the current element and have worse cost. *map = mem::take(map) .into_iter() - .filter(|&(ref existing_key, ref existing_elem)| { + .filter(|(existing_key, existing_elem)| { let existing_elem_cost = existing_elem.cost_1d(sat_prob, dissat_prob); !(elem_key.is_subtype(*existing_key) && existing_elem_cost >= elem_cost) }) @@ -879,7 +877,7 @@ where let rw = subs[1].0 as f64 / total; //and-or - if let (&Concrete::And(ref x), _) = (&subs[0].1, &subs[1].1) { + if let (Concrete::And(x), _) = (&subs[0].1, &subs[1].1) { let mut a1 = best_compilations( policy_cache, &x[0], @@ -902,7 +900,7 @@ where compile_tern!(&mut a1, &mut b2, &mut c, [lw, rw]); compile_tern!(&mut b1, &mut a2, &mut c, [lw, rw]); }; - if let (_, &Concrete::And(ref x)) = (&subs[0].1, &subs[1].1) { + if let (_, Concrete::And(x)) = (&subs[0].1, &subs[1].1) { let mut a1 = best_compilations( policy_cache, &x[0], @@ -974,11 +972,11 @@ where let mut best_es = Vec::with_capacity(n); let mut best_ws = Vec::with_capacity(n); - let mut min_value = (0, f64::INFINITY as f64); + let mut min_value = (0, f64::INFINITY); for (i, ast) in subs.iter().enumerate() { let sp = sat_prob * k_over_n; //Expressions must be dissatisfiable - let dp = Some(dissat_prob.unwrap_or(0 as f64) + (1.0 - k_over_n) * sat_prob); + let dp = Some(dissat_prob.unwrap_or(0.0) + (1.0 - k_over_n) * sat_prob); let be = best(types::Base::B, policy_cache, ast, sp, dp)?; let bw = best(types::Base::W, policy_cache, ast, sp, dp)?; @@ -1002,9 +1000,7 @@ where let ast = Terminal::Thresh(k, sub_ast); let ast_ext = AstElemExt { - ms: Arc::new( - Miniscript::from_ast(ast).map_err(|_| CompilerError::LimitsExceeded)?, - ), + ms: Arc::new(Miniscript::from_ast(ast).map_err(|_| CompilerError::LimitsExceeded)?), comp_ext_data: CompilerExtData::threshold(k, n, |i| Ok(sub_ext_data[i])) .expect("threshold subs, which we just compiled, typeck"), }; @@ -1177,7 +1173,7 @@ where { best_compilations(policy_cache, policy, sat_prob, dissat_prob)? .into_iter() - .filter(|&(ref key, ref val)| { + .filter(|(key, val)| { key.ty.corr.base == basic_type && key.ty.corr.unit && val.ms.ty.mall.dissat == types::Dissat::Unique @@ -1246,7 +1242,7 @@ mod tests { // artificially create a policy that is problematic and try to compile let pol: SPolicy = Concrete::And(vec![ Concrete::Key("A".to_string()), - Concrete::And(vec![Concrete::after(9), Concrete::after(1000_000_000)]), + Concrete::And(vec![Concrete::after(9), Concrete::after(1_000_000_000)]), ]); assert!(pol.compile::().is_err()); @@ -1320,7 +1316,7 @@ mod tests { let (keys, sig) = pubkeys_and_a_sig(10); let key_pol: Vec = keys.iter().map(|k| Concrete::Key(*k)).collect(); - let policy: BPolicy = Concrete::Key(keys[0].clone()); + let policy: BPolicy = Concrete::Key(keys[0]); let ms: SegwitMiniScript = policy.compile().unwrap(); assert_eq!( ms.encode(), @@ -1406,11 +1402,11 @@ mod tests { let mut right_sat = HashMap::::new(); - for i in 0..5 { - left_sat.insert(keys[i], bitcoinsig); + for key in &keys[0..5] { + left_sat.insert(*key, bitcoinsig); } - for i in 5..8 { - right_sat.insert(keys[i].to_pubkeyhash(SigType::Ecdsa), (keys[i], bitcoinsig)); + for key in &keys[5..8] { + right_sat.insert(key.to_pubkeyhash(SigType::Ecdsa), (*key, bitcoinsig)); } assert!(ms.satisfy(no_sat).is_err()); @@ -1519,7 +1515,7 @@ mod tests { (1, Concrete::Threshold(keys_b.len(), keys_b)), ]) .compile(); - let script_size = thresh_res.clone().and_then(|m| Ok(m.script_size())); + let script_size = thresh_res.clone().map(|m| m.script_size()); assert_eq!( thresh_res, Err(CompilerError::LimitsExceeded), @@ -1535,7 +1531,7 @@ mod tests { Concrete::Threshold(keys.len(), keys).compile(); let n_elements = thresh_res .clone() - .and_then(|m| Ok(m.max_satisfaction_witness_elements())); + .map(|m| m.max_satisfaction_witness_elements()); assert_eq!( thresh_res, Err(CompilerError::LimitsExceeded), @@ -1552,7 +1548,7 @@ mod tests { keys.iter().map(|pubkey| Concrete::Key(*pubkey)).collect(); let thresh_res: Result = Concrete::Threshold(keys.len() - 1, keys).compile(); - let ops_count = thresh_res.clone().and_then(|m| Ok(m.ext.ops.op_count())); + let ops_count = thresh_res.clone().map(|m| m.ext.ops.op_count()); assert_eq!( thresh_res, Err(CompilerError::LimitsExceeded), @@ -1564,7 +1560,7 @@ mod tests { let keys: Vec> = keys.iter().map(|pubkey| Concrete::Key(*pubkey)).collect(); let thresh_res = Concrete::Threshold(keys.len() - 1, keys).compile::(); - let ops_count = thresh_res.clone().and_then(|m| Ok(m.ext.ops.op_count())); + let ops_count = thresh_res.clone().map(|m| m.ext.ops.op_count()); assert_eq!( thresh_res, Err(CompilerError::LimitsExceeded), diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index a91545beb..71cbccf0f 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -228,7 +228,7 @@ pub enum DescriptorCtx { Wsh, /// Sh-wrapped [Wsh][`Descriptor::Wsh`] ShWsh, - /// [Tr][`Descriptor::Tr`] where the Option corresponds to the internal_key if no internal + /// [Tr][`Descriptor::Tr`] where the `Option` corresponds to the internal_key if no internal /// key can be inferred from the given policy Tr(Option), } @@ -315,17 +315,15 @@ impl Policy { Policy::Or(ref subs) => { let total_odds: usize = subs.iter().map(|(ref k, _)| k).sum(); subs.iter() - .map(|(k, ref policy)| { + .flat_map(|(k, ref policy)| { policy.to_tapleaf_prob_vec(prob * *k as f64 / total_odds as f64) }) - .flatten() .collect::>() } Policy::Threshold(k, ref subs) if *k == 1 => { let total_odds = subs.len(); subs.iter() - .map(|policy| policy.to_tapleaf_prob_vec(prob / total_odds as f64)) - .flatten() + .flat_map(|policy| policy.to_tapleaf_prob_vec(prob / total_odds as f64)) .collect::>() } x => vec![(prob, x.clone())], @@ -369,7 +367,7 @@ impl Policy { } } match (internal_key, unspendable_key) { - (Some(ref key), _) => Ok((key.clone(), self.translate_unsatisfiable_pk(&key))), + (Some(ref key), _) => Ok((key.clone(), self.translate_unsatisfiable_pk(key))), (_, Some(key)) => Ok((key, self)), _ => Err(errstr("No viable internal key found.")), } @@ -429,7 +427,7 @@ impl Policy { } /// Compile the [`Policy`] into a [`Tr`][`Descriptor::Tr`] Descriptor, with policy-enumeration - /// by [`Policy::enumerate_policy_tree`]. + /// by `Policy::enumerate_policy_tree`. /// /// ### TapTree compilation /// @@ -441,7 +439,7 @@ impl Policy { /// /// ### Policy enumeration /// - /// Refer to [`Policy::enumerate_policy_tree`] for the current strategy implemented. + /// Refer to `Policy::enumerate_policy_tree` for the current strategy implemented. #[cfg(feature = "compiler")] pub fn compile_tr_private_experimental( &self, @@ -675,7 +673,9 @@ impl Policy { Policy::Threshold(_, ref subs) | Policy::And(ref subs) => { subs.iter().all(|sub| sub.real_for_each_key(&mut *pred)) } - Policy::Or(ref subs) => subs.iter().all(|(_, sub)| sub.real_for_each_key(&mut *pred)), + Policy::Or(ref subs) => subs + .iter() + .all(|(_, sub)| sub.real_for_each_key(&mut *pred)), } } @@ -757,7 +757,7 @@ impl Policy { )), Policy::Or(ref subs) => Ok(Policy::Or( subs.iter() - .map(|&(ref prob, ref sub)| Ok((*prob, sub._translate_pk(t)?))) + .map(|(prob, sub)| Ok((*prob, sub._translate_pk(t)?))) .collect::)>, E>>()?, )), } @@ -887,9 +887,7 @@ impl Policy { TimelockInfo::combine_threshold(subs.len(), iter) } Policy::Or(ref subs) => { - let iter = subs - .iter() - .map(|&(ref _p, ref sub)| sub.check_timelocks_helper()); + let iter = subs.iter().map(|(_p, sub)| sub.check_timelocks_helper()); TimelockInfo::combine_threshold(1, iter) } } @@ -918,7 +916,7 @@ impl Policy { Err(PolicyError::NonBinaryArgOr) } else { subs.iter() - .map(|&(ref _prob, ref sub)| sub.is_valid()) + .map(|(_prob, sub)| sub.is_valid()) .collect::, PolicyError>>()?; Ok(()) } @@ -995,7 +993,7 @@ impl Policy { Policy::Or(ref subs) => { let (all_safe, atleast_one_safe, all_non_mall) = subs .iter() - .map(|&(_, ref sub)| sub.is_safe_nonmalleable()) + .map(|(_, sub)| sub.is_safe_nonmalleable()) .fold((true, false, true), |acc, x| { (acc.0 && x.0, acc.1 || x.0, acc.2 && x.1) }); @@ -1264,7 +1262,7 @@ fn with_huffman_tree( /// any one of the conditions exclusively. #[cfg(feature = "compiler")] fn generate_combination( - policy_vec: &Vec>>, + policy_vec: &[Arc>], prob: f64, k: usize, ) -> Vec<(f64, Arc>)> { @@ -1350,15 +1348,19 @@ mod compiler_tests { #[cfg(test)] mod tests { - use super::*; use std::str::FromStr; + use super::*; + #[test] fn for_each_key() { let liquid_pol = Policy::::from_str( "or(and(older(4096),thresh(2,pk(A),pk(B),pk(C))),thresh(11,pk(F1),pk(F2),pk(F3),pk(F4),pk(F5),pk(F6),pk(F7),pk(F8),pk(F9),pk(F10),pk(F11),pk(F12),pk(F13),pk(F14)))").unwrap(); let mut count = 0; - assert!(liquid_pol.for_each_key(|_| { count +=1; true })); + assert!(liquid_pol.for_each_key(|_| { + count += 1; + true + })); assert_eq!(count, 17); } } diff --git a/src/policy/mod.rs b/src/policy/mod.rs index c7cdcddf3..a18b848ab 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -215,7 +215,7 @@ impl Liftable for Concrete { } Concrete::Or(ref subs) => { let semantic_subs: Result<_, Error> = - subs.iter().map(|&(ref _p, ref sub)| sub.lift()).collect(); + subs.iter().map(|(_, sub)| sub.lift()).collect(); Semantic::Threshold(1, semantic_subs?) } Concrete::Threshold(k, ref subs) => { @@ -337,7 +337,7 @@ mod tests { #[test] fn heavy_nest() { let policy_string = "thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))"; - ConcretePol::from_str(&policy_string).unwrap_err(); + ConcretePol::from_str(policy_string).unwrap_err(); } #[test] @@ -454,7 +454,7 @@ mod tests { .iter() .zip(node_probabilities.iter()) .collect::>(); - sorted_policy_prob.sort_by(|a, b| (a.1).partial_cmp(&b.1).unwrap()); + sorted_policy_prob.sort_by(|a, b| (a.1).partial_cmp(b.1).unwrap()); let sorted_policies = sorted_policy_prob .into_iter() .map(|(x, _prob)| x) diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index 8239de456..4f51c42c7 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -91,7 +91,9 @@ impl Policy { | Policy::Hash160(..) | Policy::After(..) | Policy::Older(..) => true, - Policy::Threshold(_, ref subs) => subs.iter().all(|sub| sub.real_for_each_key(&mut *pred)), + Policy::Threshold(_, ref subs) => { + subs.iter().all(|sub| sub.real_for_each_key(&mut *pred)) + } } } @@ -172,7 +174,6 @@ impl Policy { /// A |- B means every satisfaction of A is also a satisfaction of B. /// This implementation will run slow for larger policies but should be sufficient for /// most practical policies. - // This algorithm has a naive implementation. It is possible to optimize this // by memoizing and maintaining a hashmap. pub fn entails(self, other: Policy) -> Result { @@ -227,11 +228,10 @@ impl Policy { // a normalized policy pub(crate) fn satisfy_constraint(self, witness: &Policy, available: bool) -> Policy { debug_assert!(self.clone().normalized() == self); - match *witness { + if let Policy::Threshold(..) = *witness { // only for internal purposes, safe to use unreachable! - Policy::Threshold(..) => unreachable!(), - _ => {} - }; + unreachable!() + } let ret = match self { Policy::Threshold(k, subs) => { let mut ret_subs = vec![]; @@ -554,10 +554,9 @@ impl Policy { Policy::Older(t) => { if t.is_height_locked() && age.is_time_locked() || t.is_time_locked() && age.is_height_locked() + || t.to_consensus_u32() > age.to_consensus_u32() { Policy::Unsatisfiable - } else if t.to_consensus_u32() > age.to_consensus_u32() { - Policy::Unsatisfiable } else { Policy::Older(t) } @@ -1004,7 +1003,10 @@ mod tests { let liquid_pol = StringPolicy::from_str( "or(and(older(4096),thresh(2,pk(A),pk(B),pk(C))),thresh(11,pk(F1),pk(F2),pk(F3),pk(F4),pk(F5),pk(F6),pk(F7),pk(F8),pk(F9),pk(F10),pk(F11),pk(F12),pk(F13),pk(F14)))").unwrap(); let mut count = 0; - assert!(liquid_pol.for_each_key(|_| { count +=1; true })); + assert!(liquid_pol.for_each_key(|_| { + count += 1; + true + })); assert_eq!(count, 17); } } diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index b6258c928..426a4dc64 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -397,6 +397,7 @@ impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier for PsbtInputSatisfie } } +#[allow(clippy::ptr_arg)] // this signature is forced by use in `and_then` fn try_vec_as_preimage32(vec: &Vec) -> Option { if vec.len() == 32 { let mut arr = [0u8; 32]; @@ -594,7 +595,7 @@ pub trait PsbtExt { /// Get the sighash message(data to sign) at input index `idx` based on the sighash /// flag specified in the [`Psbt`] sighash field. If the input sighash flag psbt field is `None` - /// the [`SchnorrSighashType::Default`](bitcoin::util::sighash::SchnorrSighashType::Default) is chosen + /// the [`SchnorrSighashType::Default`] is chosen /// for for taproot spends, otherwise [`EcdsaSignatureHashType::All`](bitcoin::EcdsaSighashType::All) is chosen. /// If the utxo at `idx` is a taproot output, returns a [`PsbtSighashMsg::TapSighash`] variant. /// If the utxo at `idx` is a pre-taproot output, returns a [`PsbtSighashMsg::EcdsaSighash`] variant. @@ -1045,8 +1046,6 @@ trait PsbtFields { fn tap_key_origins( &mut self, ) -> &mut BTreeMap, bip32::KeySource)>; - fn proprietary(&mut self) -> &mut BTreeMap>; - fn unknown(&mut self) -> &mut BTreeMap>; // `tap_tree` only appears in psbt::Output, so it's returned as an option of a mutable ref fn tap_tree(&mut self) -> Option<&mut Option> { @@ -1080,12 +1079,6 @@ impl PsbtFields for psbt::Input { ) -> &mut BTreeMap, bip32::KeySource)> { &mut self.tap_key_origins } - fn proprietary(&mut self) -> &mut BTreeMap> { - &mut self.proprietary - } - fn unknown(&mut self) -> &mut BTreeMap> { - &mut self.unknown - } fn tap_scripts(&mut self) -> Option<&mut BTreeMap> { Some(&mut self.tap_scripts) @@ -1113,12 +1106,6 @@ impl PsbtFields for psbt::Output { ) -> &mut BTreeMap, bip32::KeySource)> { &mut self.tap_key_origins } - fn proprietary(&mut self) -> &mut BTreeMap> { - &mut self.proprietary - } - fn unknown(&mut self) -> &mut BTreeMap> { - &mut self.unknown - } fn tap_tree(&mut self) -> Option<&mut Option> { Some(&mut self.tap_tree) @@ -1548,8 +1535,7 @@ mod tests { assert!(psbt_input .tap_scripts .values() - .find(|value| *value == &(first_script.clone(), LeafVersion::TapScript)) - .is_some()); + .any(|value| *value == (first_script.clone(), LeafVersion::TapScript))); TapLeafHash::from_script(&first_script, LeafVersion::TapScript) }; @@ -1655,8 +1641,8 @@ mod tests { #[test] fn test_update_input_checks() { - let desc = format!("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)"); - let desc = Descriptor::::from_str(&desc).unwrap(); + let desc = "tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)"; + let desc = Descriptor::::from_str(desc).unwrap(); let mut non_witness_utxo = bitcoin::Transaction { version: 1, @@ -1720,8 +1706,8 @@ mod tests { #[test] fn test_update_output_checks() { - let desc = format!("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)"); - let desc = Descriptor::::from_str(&desc).unwrap(); + let desc = "tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/0)"; + let desc = Descriptor::::from_str(desc).unwrap(); let tx = bitcoin::Transaction { version: 1, diff --git a/src/test_utils.rs b/src/test_utils.rs index 6ea900d91..5cb0c77bd 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -134,7 +134,7 @@ impl StrKeyTranslator { .collect(); let mut pk_map = HashMap::new(); let mut pkh_map = HashMap::new(); - for (i, c) in (b'A'..b'Z').enumerate() { + for (i, c) in (b'A'..=b'Z').enumerate() { let key = String::from_utf8(vec![c]).unwrap(); pk_map.insert(key.clone(), pks[i]); pkh_map.insert(key, pks[i].to_pubkeyhash(SigType::Ecdsa)); @@ -165,7 +165,7 @@ impl StrXOnlyKeyTranslator { .collect(); let mut pk_map = HashMap::new(); let mut pkh_map = HashMap::new(); - for (i, c) in (b'A'..b'Z').enumerate() { + for (i, c) in (b'A'..=b'Z').enumerate() { let key = String::from_utf8(vec![c]).unwrap(); pk_map.insert(key.clone(), pks[i]); pkh_map.insert(key, pks[i].to_pubkeyhash(SigType::Schnorr)); diff --git a/tests/setup/mod.rs b/tests/setup/mod.rs index 6a7f27e37..e7d9e1f23 100644 --- a/tests/setup/mod.rs +++ b/tests/setup/mod.rs @@ -1,24 +1,4 @@ extern crate miniscript; -use bitcoind::bitcoincore_rpc::RpcApi; -use bitcoind::BitcoinD; -use miniscript::bitcoin; - pub mod test_util; -// Launch an instance of bitcoind with -pub fn setup() -> BitcoinD { - let exe_path = bitcoind::exe_path().unwrap(); - let bitcoind = bitcoind::BitcoinD::new(exe_path).unwrap(); - let cl = &bitcoind.client; - // generate to an address by the wallet. And wait for funds to mature - let addr = cl.get_new_address(None, None).unwrap(); - let blks = cl.generate_to_address(101, &addr).unwrap(); - assert_eq!(blks.len(), 101); - - assert_eq!( - cl.get_balance(Some(1) /*min conf*/, None).unwrap(), - bitcoin::Amount::from_sat(100_000_000 * 50) - ); - bitcoind -} diff --git a/tests/setup/test_util.rs b/tests/setup/test_util.rs index fc8e079e2..f091efdf8 100644 --- a/tests/setup/test_util.rs +++ b/tests/setup/test_util.rs @@ -22,7 +22,6 @@ use std::str::FromStr; use actual_rand as rand; use bitcoin::hashes::hex::ToHex; use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; -use bitcoin::secp256k1; use miniscript::descriptor::{SinglePub, SinglePubKey}; use miniscript::{ hash256, Descriptor, DescriptorPublicKey, Error, Miniscript, ScriptContext, TranslatePk, @@ -54,81 +53,6 @@ pub struct TestData { pub secretdata: SecretData, } -// Setup (sk, pk) pairs -fn setup_keys( - n: usize, -) -> ( - Vec, - Vec, - Vec, - Vec, -) { - let secp_sign = secp256k1::Secp256k1::signing_only(); - let mut sk = [0; 32]; - let mut sks = vec![]; - let mut pks = vec![]; - for i in 1..n + 1 { - sk[0] = i as u8; - sk[1] = (i >> 8) as u8; - sk[2] = (i >> 16) as u8; - - let sk = secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"); - let pk = miniscript::bitcoin::PublicKey { - inner: secp256k1::PublicKey::from_secret_key(&secp_sign, &sk), - compressed: true, - }; - pks.push(pk); - sks.push(sk); - } - - let mut x_only_keypairs = vec![]; - let mut x_only_pks = vec![]; - - for i in 0..n { - let keypair = bitcoin::KeyPair::from_secret_key(&secp_sign, &sks[i]); - let (xpk, _parity) = bitcoin::XOnlyPublicKey::from_keypair(&keypair); - x_only_keypairs.push(keypair); - x_only_pks.push(xpk); - } - (sks, pks, x_only_keypairs, x_only_pks) -} - -impl TestData { - // generate a fixed data for n keys - pub(crate) fn new_fixed_data(n: usize) -> Self { - let (sks, pks, x_only_keypairs, x_only_pks) = setup_keys(n); - let sha256_pre = [0x12 as u8; 32]; - let sha256 = sha256::Hash::hash(&sha256_pre); - let hash256_pre = [0x34 as u8; 32]; - let hash256 = hash256::Hash::hash(&hash256_pre); - let hash160_pre = [0x56 as u8; 32]; - let hash160 = hash160::Hash::hash(&hash160_pre); - let ripemd160_pre = [0x78 as u8; 32]; - let ripemd160 = ripemd160::Hash::hash(&ripemd160_pre); - - let pubdata = PubData { - pks, - sha256, - hash256, - ripemd160, - hash160, - x_only_pks, - }; - let secretdata = SecretData { - sks, - sha256_pre, - hash256_pre, - ripemd160_pre, - hash160_pre, - x_only_keypairs, - }; - Self { - pubdata, - secretdata, - } - } -} - /// Obtain an insecure random public key with unknown secret key for testing pub fn random_pk(mut seed: u8) -> bitcoin::PublicKey { loop { diff --git a/tests/test_cpp.rs b/tests/test_cpp.rs deleted file mode 100644 index 4e5196724..000000000 --- a/tests/test_cpp.rs +++ /dev/null @@ -1,253 +0,0 @@ -//! # rust-miniscript integration test -//! -//! Read Miniscripts from file and translate into miniscripts -//! which we know how to satisfy -//! - -use std::collections::BTreeMap; -use std::fs::File; -use std::io::{self, BufRead}; -use std::path::Path; - -use bitcoin::hashes::{sha256d, Hash}; -use bitcoin::secp256k1::{self, Secp256k1}; -use bitcoin::util::psbt; -use bitcoin::util::psbt::PartiallySignedTransaction as Psbt; -use bitcoin::{self, Amount, LockTime, OutPoint, Sequence, Transaction, TxIn, TxOut, Txid}; -use bitcoind::bitcoincore_rpc::{json, Client, RpcApi}; -use miniscript::psbt::PsbtExt; -use miniscript::Descriptor; - -mod setup; -use setup::test_util::{self, PubData, TestData}; - -// parse ~30 miniscripts from file -pub(crate) fn parse_miniscripts( - secp: &Secp256k1, - pubdata: &PubData, -) -> Vec> { - // File must exist in current path before this produces output - let mut desc_vec = vec![]; - // Consumes the iterator, returns an (Optional) String - for line in read_lines("tests/data/random_ms.txt") { - let ms = test_util::parse_insane_ms(&line.unwrap(), pubdata); - let wsh = Descriptor::new_wsh(ms).unwrap(); - desc_vec.push(wsh.derived_descriptor(secp, 0).unwrap()); - } - desc_vec -} - -// The output is wrapped in a Result to allow matching on errors -// Returns an Iterator to the Reader of the lines of the file. -fn read_lines

(filename: P) -> io::Lines> -where - P: AsRef, -{ - let file = File::open(filename).expect("File not found"); - io::BufReader::new(file).lines() -} - -/// Quickly create a BTC amount. -fn btc>(btc: F) -> Amount { - Amount::from_btc(btc.into()).unwrap() -} - -// Find the Outpoint by value. -// Ideally, we should find by scriptPubkey, but this -// works for temp test case -fn get_vout(cl: &Client, txid: Txid, value: u64) -> (OutPoint, TxOut) { - let tx = cl - .get_transaction(&txid, None) - .unwrap() - .transaction() - .unwrap(); - for (i, txout) in tx.output.into_iter().enumerate() { - if txout.value == value { - return (OutPoint::new(txid, i as u32), txout); - } - } - unreachable!("Only call get vout on functions which have the expected outpoint"); -} - -pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { - let secp = secp256k1::Secp256k1::new(); - let desc_vec = parse_miniscripts(&secp, &testdata.pubdata); - let sks = &testdata.secretdata.sks; - let pks = &testdata.pubdata.pks; - // Generate some blocks - let blocks = cl - .generate_to_address(500, &cl.get_new_address(None, None).unwrap()) - .unwrap(); - assert_eq!(blocks.len(), 500); - - // Next send some btc to each address corresponding to the miniscript - let mut txids = vec![]; - for wsh in desc_vec.iter() { - let txid = cl - .send_to_address( - &wsh.address(bitcoin::Network::Regtest).unwrap(), - btc(1), - None, - None, - None, - None, - None, - None, - ) - .unwrap(); - txids.push(txid); - } - // Wait for the funds to mature. - let blocks = cl - .generate_to_address(50, &cl.get_new_address(None, None).unwrap()) - .unwrap(); - assert_eq!(blocks.len(), 50); - // Create a PSBT for each transaction. - // Spend one input and spend one output for simplicity. - let mut psbts = vec![]; - for (desc, txid) in desc_vec.iter().zip(txids) { - let mut psbt = Psbt { - unsigned_tx: Transaction { - version: 2, - lock_time: LockTime::from_time(1_603_866_330) - .expect("valid timestamp") - .into(), // 10/28/2020 @ 6:25am (UTC) - input: vec![], - output: vec![], - }, - unknown: BTreeMap::new(), - proprietary: BTreeMap::new(), - xpub: BTreeMap::new(), - version: 0, - inputs: vec![], - outputs: vec![], - }; - // figure out the outpoint from the txid - let (outpoint, witness_utxo) = get_vout(&cl, txid, btc(1.0).to_sat()); - let mut txin = TxIn::default(); - txin.previous_output = outpoint; - // set the sequence to a non-final number for the locktime transactions to be - // processed correctly. - // We waited 50 blocks, keep 49 for safety - txin.sequence = Sequence::from_height(49); - psbt.unsigned_tx.input.push(txin); - // Get a new script pubkey from the node so that - // the node wallet tracks the receiving transaction - // and we can check it by gettransaction RPC. - let addr = cl - .get_new_address(None, Some(json::AddressType::Bech32)) - .unwrap(); - psbt.unsigned_tx.output.push(TxOut { - value: 99_999_000, - script_pubkey: addr.script_pubkey(), - }); - let mut input = psbt::Input::default(); - input.witness_utxo = Some(witness_utxo); - input.witness_script = Some(desc.explicit_script().unwrap()); - psbt.inputs.push(input); - psbt.outputs.push(psbt::Output::default()); - psbts.push(psbt); - } - - let mut spend_txids = vec![]; - // Sign the transactions with all keys - // AKA the signer role of psbt - for i in 0..psbts.len() { - let ms = if let Descriptor::Wsh(wsh) = &desc_vec[i] { - match wsh.as_inner() { - miniscript::descriptor::WshInner::Ms(ms) => ms, - _ => unreachable!(), - } - } else { - unreachable!("Only Wsh descriptors are supported"); - }; - - let sks_reqd: Vec<_> = ms - .iter_pk() - .map(|pk| sks[pks.iter().position(|&x| x == pk).unwrap()]) - .collect(); - // Get the required sighash message - let amt = btc(1).to_sat(); - let mut sighash_cache = bitcoin::util::sighash::SighashCache::new(&psbts[i].unsigned_tx); - let sighash_ty = bitcoin::EcdsaSighashType::All; - let sighash = sighash_cache - .segwit_signature_hash(0, &ms.encode(), amt, sighash_ty) - .unwrap(); - - // requires both signing and verification because we check the tx - // after we psbt extract it - let msg = secp256k1::Message::from_slice(&sighash[..]).unwrap(); - - // Finally construct the signature and add to psbt - for sk in sks_reqd { - let sig = secp.sign_ecdsa(&msg, &sk); - let pk = pks[sks.iter().position(|&x| x == sk).unwrap()]; - psbts[i].inputs[0].partial_sigs.insert( - pk, - bitcoin::EcdsaSig { - sig, - hash_ty: sighash_ty, - }, - ); - } - // Add the hash preimages to the psbt - psbts[i].inputs[0].sha256_preimages.insert( - testdata.pubdata.sha256, - testdata.secretdata.sha256_pre.to_vec(), - ); - psbts[i].inputs[0].hash256_preimages.insert( - sha256d::Hash::from_inner(testdata.pubdata.hash256.into_inner()), - testdata.secretdata.hash256_pre.to_vec(), - ); - println!("{}", ms); - psbts[i].inputs[0].hash160_preimages.insert( - testdata.pubdata.hash160, - testdata.secretdata.hash160_pre.to_vec(), - ); - psbts[i].inputs[0].ripemd160_preimages.insert( - testdata.pubdata.ripemd160, - testdata.secretdata.ripemd160_pre.to_vec(), - ); - // Finalize the transaction using psbt - // Let miniscript do it's magic! - if let Err(e) = psbts[i].finalize_mall_mut(&secp) { - // All miniscripts should satisfy - panic!("Could not satisfy: error{} ms:{} at ind:{}", e[0], ms, i); - } else { - let tx = psbts[i].extract(&secp).unwrap(); - - // Send the transactions to bitcoin node for mining. - // Regtest mode has standardness checks - // Check whether the node accepts the transactions - let txid = cl - .send_raw_transaction(&tx) - .expect(&format!("{} send tx failed for ms {}", i, ms)); - spend_txids.push(txid); - } - } - // Finally mine the blocks and await confirmations - let _blocks = cl - .generate_to_address(10, &cl.get_new_address(None, None).unwrap()) - .unwrap(); - // Get the required transactions from the node mined in the blocks. - for txid in spend_txids { - // Check whether the transaction is mined in blocks - // Assert that the confirmations are > 0. - let num_conf = cl.get_transaction(&txid, None).unwrap().info.confirmations; - assert!(num_conf > 0); - } -} - -#[test] -#[ignore = "bitcoind crate breaking change"] -fn test_setup() { - setup::setup(); -} - -#[test] -#[ignore = "bitcoind crate breaking change"] -fn tests_from_cpp() { - let cl = &setup::setup().client; - let testdata = TestData::new_fixed_data(50); - test_from_cpp_ms(cl, &testdata); -} diff --git a/tests/test_desc.rs b/tests/test_desc.rs deleted file mode 100644 index 96281ae27..000000000 --- a/tests/test_desc.rs +++ /dev/null @@ -1,432 +0,0 @@ -//! # rust-miniscript integration test -//! -//! Read Miniscripts from file and translate into miniscripts -//! which we know how to satisfy -//! - -use std::collections::BTreeMap; -use std::{error, fmt}; - -use actual_rand as rand; -use bitcoin::blockdata::witness::Witness; -use bitcoin::hashes::{sha256d, Hash}; -use bitcoin::util::psbt::PartiallySignedTransaction as Psbt; -use bitcoin::util::sighash::SighashCache; -use bitcoin::util::taproot::{LeafVersion, TapLeafHash}; -use bitcoin::util::{psbt, sighash}; -use bitcoin::{ - self, secp256k1, Amount, LockTime, OutPoint, SchnorrSig, Script, Sequence, Transaction, TxIn, - TxOut, Txid, -}; -use bitcoind::bitcoincore_rpc::{json, Client, RpcApi}; -use miniscript::psbt::{PsbtExt, PsbtInputExt}; -use miniscript::{Descriptor, Miniscript, ScriptContext, ToPublicKey}; -mod setup; - -use rand::RngCore; -use setup::test_util::{self, TestData}; -/// Quickly create a BTC amount. -fn btc>(btc: F) -> Amount { - Amount::from_btc(btc.into()).unwrap() -} - -// Find the Outpoint by spk -fn get_vout(cl: &Client, txid: Txid, value: u64, spk: Script) -> (OutPoint, TxOut) { - let tx = cl - .get_transaction(&txid, None) - .unwrap() - .transaction() - .unwrap(); - for (i, txout) in tx.output.into_iter().enumerate() { - if txout.value == value && spk == txout.script_pubkey { - return (OutPoint::new(txid, i as u32), txout); - } - } - unreachable!("Only call get vout on functions which have the expected outpoint"); -} - -#[derive(Debug, PartialEq)] -pub enum DescError { - /// PSBT was not able to finalize - PsbtFinalizeError, - /// Problem with address computation - AddressComputationError, - /// Error while parsing the descriptor - DescParseError, -} - -impl fmt::Display for DescError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - DescError::PsbtFinalizeError => f.write_str("PSBT was not able to finalize"), - DescError::AddressComputationError => f.write_str("Problem with address computation"), - DescError::DescParseError => f.write_str("Not able to parse the descriptor"), - } - } -} - -impl error::Error for DescError {} - -pub fn test_desc_satisfy( - cl: &Client, - testdata: &TestData, - descriptor: &str, -) -> Result { - let secp = secp256k1::Secp256k1::new(); - let sks = &testdata.secretdata.sks; - let xonly_keypairs = &testdata.secretdata.x_only_keypairs; - let pks = &testdata.pubdata.pks; - let x_only_pks = &testdata.pubdata.x_only_pks; - // Generate some blocks - let blocks = cl - .generate_to_address(1, &cl.get_new_address(None, None).unwrap()) - .unwrap(); - assert_eq!(blocks.len(), 1); - - let definite_desc = test_util::parse_test_desc(&descriptor, &testdata.pubdata) - .map_err(|_| DescError::DescParseError)? - .at_derivation_index(0); - - let derived_desc = definite_desc.derived_descriptor(&secp).unwrap(); - let desc_address = derived_desc.address(bitcoin::Network::Regtest); - let desc_address = desc_address.map_err(|_x| DescError::AddressComputationError)?; - - // Next send some btc to each address corresponding to the miniscript - let txid = cl - .send_to_address(&desc_address, btc(1), None, None, None, None, None, None) - .unwrap(); - // Wait for the funds to mature. - let blocks = cl - .generate_to_address(2, &cl.get_new_address(None, None).unwrap()) - .unwrap(); - assert_eq!(blocks.len(), 2); - // Create a PSBT for each transaction. - // Spend one input and spend one output for simplicity. - let mut psbt = Psbt { - unsigned_tx: Transaction { - version: 2, - lock_time: LockTime::from_time(1_603_866_330) - .expect("valid timestamp") - .into(), // 10/28/2020 @ 6:25am (UTC) - input: vec![], - output: vec![], - }, - unknown: BTreeMap::new(), - proprietary: BTreeMap::new(), - xpub: BTreeMap::new(), - version: 0, - inputs: vec![], - outputs: vec![], - }; - // figure out the outpoint from the txid - let (outpoint, witness_utxo) = - get_vout(&cl, txid, btc(1.0).to_sat(), derived_desc.script_pubkey()); - let mut txin = TxIn::default(); - txin.previous_output = outpoint; - // set the sequence to a non-final number for the locktime transactions to be - // processed correctly. - // We waited 2 blocks, keep 1 for safety - txin.sequence = Sequence::from_height(1); - psbt.unsigned_tx.input.push(txin); - // Get a new script pubkey from the node so that - // the node wallet tracks the receiving transaction - // and we can check it by gettransaction RPC. - let addr = cl - .get_new_address(None, Some(json::AddressType::Bech32)) - .unwrap(); - // Had to decrease 'value', so that fees can be increased - // (Was getting insufficient fees error, for deep script trees) - psbt.unsigned_tx.output.push(TxOut { - value: 99_997_000, - script_pubkey: addr.script_pubkey(), - }); - let mut input = psbt::Input::default(); - input - .update_with_descriptor_unchecked(&definite_desc) - .unwrap(); - input.witness_utxo = Some(witness_utxo.clone()); - psbt.inputs.push(input); - psbt.outputs.push(psbt::Output::default()); - - // -------------------------------------------- - // Sign the transactions with all keys - // AKA the signer role of psbt - // Get all the pubkeys and the corresponding secret keys - - let mut sighash_cache = SighashCache::new(&psbt.unsigned_tx); - match derived_desc { - Descriptor::Tr(ref tr) => { - // Fixme: take a parameter - let hash_ty = sighash::SchnorrSighashType::Default; - - let internal_key_present = x_only_pks - .iter() - .position(|&x| x.to_public_key() == *tr.internal_key()); - let internal_keypair = internal_key_present.map(|idx| xonly_keypairs[idx].clone()); - let prevouts = [witness_utxo]; - let prevouts = sighash::Prevouts::All(&prevouts); - - if let Some(internal_keypair) = internal_keypair { - // ---------------------- Tr key spend -------------------- - let internal_keypair = internal_keypair - .add_xonly_tweak(&secp, &tr.spend_info().tap_tweak().to_scalar()) - .expect("Tweaking failed"); - let sighash_msg = sighash_cache - .taproot_key_spend_signature_hash(0, &prevouts, hash_ty) - .unwrap(); - let msg = secp256k1::Message::from_slice(&sighash_msg[..]).unwrap(); - let mut aux_rand = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut aux_rand); - let schnorr_sig = - secp.sign_schnorr_with_aux_rand(&msg, &internal_keypair, &aux_rand); - psbt.inputs[0].tap_key_sig = Some(SchnorrSig { - sig: schnorr_sig, - hash_ty: hash_ty, - }); - } else { - // No internal key - } - // ------------------ script spend ------------- - let x_only_keypairs_reqd: Vec<(secp256k1::KeyPair, TapLeafHash)> = tr - .iter_scripts() - .flat_map(|(_depth, ms)| { - let leaf_hash = TapLeafHash::from_script(&ms.encode(), LeafVersion::TapScript); - ms.iter_pk().filter_map(move |pk| { - let i = x_only_pks.iter().position(|&x| x.to_public_key() == pk); - i.map(|idx| (xonly_keypairs[idx].clone(), leaf_hash)) - }) - }) - .collect(); - for (keypair, leaf_hash) in x_only_keypairs_reqd { - let sighash_msg = sighash_cache - .taproot_script_spend_signature_hash(0, &prevouts, leaf_hash, hash_ty) - .unwrap(); - let msg = secp256k1::Message::from_slice(&sighash_msg[..]).unwrap(); - let mut aux_rand = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut aux_rand); - let sig = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &aux_rand); - // FIXME: uncomment when == is supported for secp256k1::KeyPair. (next major release) - // let x_only_pk = pks[xonly_keypairs.iter().position(|&x| x == keypair).unwrap()]; - // Just recalc public key - let (x_only_pk, _parity) = secp256k1::XOnlyPublicKey::from_keypair(&keypair); - psbt.inputs[0].tap_script_sigs.insert( - (x_only_pk, leaf_hash), - bitcoin::SchnorrSig { - sig, - hash_ty: hash_ty, - }, - ); - } - } - _ => { - // Non-tr descriptors - // Ecdsa sigs - let sks_reqd = match derived_desc { - Descriptor::Bare(bare) => find_sks_ms(&bare.as_inner(), testdata), - Descriptor::Pkh(pk) => find_sk_single_key(*pk.as_inner(), testdata), - Descriptor::Wpkh(pk) => find_sk_single_key(*pk.as_inner(), testdata), - Descriptor::Sh(sh) => match sh.as_inner() { - miniscript::descriptor::ShInner::Wsh(wsh) => match wsh.as_inner() { - miniscript::descriptor::WshInner::SortedMulti(ref smv) => { - let ms = Miniscript::from_ast(smv.sorted_node()).unwrap(); - find_sks_ms(&ms, testdata) - } - miniscript::descriptor::WshInner::Ms(ref ms) => find_sks_ms(&ms, testdata), - }, - miniscript::descriptor::ShInner::Wpkh(pk) => { - find_sk_single_key(*pk.as_inner(), testdata) - } - miniscript::descriptor::ShInner::SortedMulti(smv) => { - let ms = Miniscript::from_ast(smv.sorted_node()).unwrap(); - find_sks_ms(&ms, testdata) - } - miniscript::descriptor::ShInner::Ms(ms) => find_sks_ms(&ms, testdata), - }, - Descriptor::Wsh(wsh) => match wsh.as_inner() { - miniscript::descriptor::WshInner::SortedMulti(ref smv) => { - let ms = Miniscript::from_ast(smv.sorted_node()).unwrap(); - find_sks_ms(&ms, testdata) - } - miniscript::descriptor::WshInner::Ms(ref ms) => find_sks_ms(&ms, testdata), - }, - Descriptor::Tr(_tr) => unreachable!("Tr checked earlier"), - }; - let msg = psbt - .sighash_msg(0, &mut sighash_cache, None) - .unwrap() - .to_secp_msg(); - - // Fixme: Take a parameter - let hash_ty = bitcoin::EcdsaSighashType::All; - - // Finally construct the signature and add to psbt - for sk in sks_reqd { - let sig = secp.sign_ecdsa(&msg, &sk); - let pk = pks[sks.iter().position(|&x| x == sk).unwrap()]; - assert!(secp.verify_ecdsa(&msg, &sig, &pk.inner).is_ok()); - psbt.inputs[0].partial_sigs.insert( - pk, - bitcoin::EcdsaSig { - sig, - hash_ty: hash_ty, - }, - ); - } - } - } - // Add the hash preimages to the psbt - psbt.inputs[0].sha256_preimages.insert( - testdata.pubdata.sha256, - testdata.secretdata.sha256_pre.to_vec(), - ); - psbt.inputs[0].hash256_preimages.insert( - sha256d::Hash::from_inner(testdata.pubdata.hash256.into_inner()), - testdata.secretdata.hash256_pre.to_vec(), - ); - psbt.inputs[0].hash160_preimages.insert( - testdata.pubdata.hash160, - testdata.secretdata.hash160_pre.to_vec(), - ); - psbt.inputs[0].ripemd160_preimages.insert( - testdata.pubdata.ripemd160, - testdata.secretdata.ripemd160_pre.to_vec(), - ); - println!("Testing descriptor: {}", definite_desc); - // Finalize the transaction using psbt - // Let miniscript do it's magic! - if let Err(_) = psbt.finalize_mut(&secp) { - return Err(DescError::PsbtFinalizeError); - } - let tx = psbt.extract(&secp).expect("Extraction error"); - - // Send the transactions to bitcoin node for mining. - // Regtest mode has standardness checks - // Check whether the node accepts the transactions - let txid = cl - .send_raw_transaction(&tx) - .expect(&format!("send tx failed for desc {}", definite_desc)); - - // Finally mine the blocks and await confirmations - let _blocks = cl - .generate_to_address(1, &cl.get_new_address(None, None).unwrap()) - .unwrap(); - // Get the required transactions from the node mined in the blocks. - // Check whether the transaction is mined in blocks - // Assert that the confirmations are > 0. - let num_conf = cl.get_transaction(&txid, None).unwrap().info.confirmations; - assert!(num_conf > 0); - return Ok(tx.input[0].witness.clone()); -} - -// Find all secret corresponding to the known public keys in ms -fn find_sks_ms( - ms: &Miniscript, - testdata: &TestData, -) -> Vec { - let sks = &testdata.secretdata.sks; - let pks = &testdata.pubdata.pks; - let sks = ms - .iter_pk() - .filter_map(|pk| { - let i = pks.iter().position(|&x| x.to_public_key() == pk); - i.map(|idx| (sks[idx])) - }) - .collect(); - sks -} - -fn find_sk_single_key(pk: bitcoin::PublicKey, testdata: &TestData) -> Vec { - let sks = &testdata.secretdata.sks; - let pks = &testdata.pubdata.pks; - let i = pks.iter().position(|&x| x.to_public_key() == pk); - i.map(|idx| vec![sks[idx]]).unwrap_or(Vec::new()) -} - -fn test_descs(cl: &Client, testdata: &TestData) { - // K : Compressed key available - // K!: Compressed key with corresponding secret key unknown - // X: X-only key available - // X!: X-only key with corresponding secret key unknown - - // Test 1: Simple spend with internal key - let wit = test_desc_satisfy(cl, testdata, "tr(X)").unwrap(); - assert!(wit.len() == 1); - - // Test 2: Same as above, but with leaves - let wit = test_desc_satisfy(cl, testdata, "tr(X,{pk(X1!),pk(X2!)})").unwrap(); - assert!(wit.len() == 1); - - // Test 3: Force to spend with script spend. Unknown internal key and only one known script path - // X! -> Internal key unknown - // Leaf 1 -> pk(X1) with X1 known - // Leaf 2-> and_v(v:pk(X2),pk(X3!)) with partial witness only to X2 known - let wit = test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1),and_v(v:pk(X2),pk(X3!))})").unwrap(); - assert!(wit.len() == 3); // control block, script and signature - - // Test 4: Force to spend with script spend. Unknown internal key and multiple script paths - // Should select the one with minimum weight - // X! -> Internal key unknown - // Leaf 1 -> pk(X1!) with X1 unknown - // Leaf 2-> and_v(v:pk(X2),pk(X3)) X2 and X3 known - let wit = test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1),and_v(v:pk(X2),pk(X3))})").unwrap(); - assert!(wit.len() == 3); // control block, script and one signatures - - // Test 5: When everything is available, we should select the key spend path - let wit = test_desc_satisfy(cl, testdata, "tr(X,{pk(X1),and_v(v:pk(X2),pk(X3!))})").unwrap(); - assert!(wit.len() == 1); // control block, script and signature - - // Test 6: Test the new multi_a opcodes - test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(1,X2,X3!,X4!,X5!)})").unwrap(); - test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(2,X2,X3,X4!,X5!)})").unwrap(); - test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(3,X2,X3,X4,X5!)})").unwrap(); - test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(4,X2,X3,X4,X5)})").unwrap(); - - // Test 7: Test script tree of depth 127 is valid, only X128 is known - test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),{pk(X2!),{pk(X3!),{pk(X4!),{pk(X5!),{pk(X6!),{pk(X7!),{pk(X8!),{pk(X9!),{pk(X10!),{pk(X11!),{pk(X12!),{pk(X13!),{pk(X14!),{pk(X15!),{pk(X16!),{pk(X17!),{pk(X18!),{pk(X19!),{pk(X20!),{pk(X21!),{pk(X22!),{pk(X23!),{pk(X24!),{pk(X25!),{pk(X26!),{pk(X27!),{pk(X28!),{pk(X29!),{pk(X30!),{pk(X31!),{pk(X32!),{pk(X33!),{pk(X34!),{pk(X35!),{pk(X36!),{pk(X37!),{pk(X38!),{pk(X39!),{pk(X40!),{pk(X41!),{pk(X42!),{pk(X43!),{pk(X44!),{pk(X45!),{pk(X46!),{pk(X47!),{pk(X48!),{pk(X49!),{pk(X50!),{pk(X51!),{pk(X52!),{pk(X53!),{pk(X54!),{pk(X55!),{pk(X56!),{pk(X57!),{pk(X58!),{pk(X59!),{pk(X60!),{pk(X61!),{pk(X62!),{pk(X63!),{pk(X64!),{pk(X65!),{pk(X66!),{pk(X67!),{pk(X68!),{pk(X69!),{pk(X70!),{pk(X71!),{pk(X72!),{pk(X73!),{pk(X74!),{pk(X75!),{pk(X76!),{pk(X77!),{pk(X78!),{pk(X79!),{pk(X80!),{pk(X81!),{pk(X82!),{pk(X83!),{pk(X84!),{pk(X85!),{pk(X86!),{pk(X87!),{pk(X88!),{pk(X89!),{pk(X90!),{pk(X91!),{pk(X92!),{pk(X93!),{pk(X94!),{pk(X95!),{pk(X96!),{pk(X97!),{pk(X98!),{pk(X99!),{pk(X100!),{pk(X101!),{pk(X102!),{pk(X103!),{pk(X104!),{pk(X105!),{pk(X106!),{pk(X107!),{pk(X108!),{pk(X109!),{pk(X110!),{pk(X111!),{pk(X112!),{pk(X113!),{pk(X114!),{pk(X115!),{pk(X116!),{pk(X117!),{pk(X118!),{pk(X119!),{pk(X120!),{pk(X121!),{pk(X122!),{pk(X123!),{pk(X124!),{pk(X125!),{pk(X126!),{pk(X127!),pk(X128)}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})").unwrap(); - - // Test 8: Test script tree of depth 128 is valid, only X129 is known - test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),{pk(X2!),{pk(X3!),{pk(X4!),{pk(X5!),{pk(X6!),{pk(X7!),{pk(X8!),{pk(X9!),{pk(X10!),{pk(X11!),{pk(X12!),{pk(X13!),{pk(X14!),{pk(X15!),{pk(X16!),{pk(X17!),{pk(X18!),{pk(X19!),{pk(X20!),{pk(X21!),{pk(X22!),{pk(X23!),{pk(X24!),{pk(X25!),{pk(X26!),{pk(X27!),{pk(X28!),{pk(X29!),{pk(X30!),{pk(X31!),{pk(X32!),{pk(X33!),{pk(X34!),{pk(X35!),{pk(X36!),{pk(X37!),{pk(X38!),{pk(X39!),{pk(X40!),{pk(X41!),{pk(X42!),{pk(X43!),{pk(X44!),{pk(X45!),{pk(X46!),{pk(X47!),{pk(X48!),{pk(X49!),{pk(X50!),{pk(X51!),{pk(X52!),{pk(X53!),{pk(X54!),{pk(X55!),{pk(X56!),{pk(X57!),{pk(X58!),{pk(X59!),{pk(X60!),{pk(X61!),{pk(X62!),{pk(X63!),{pk(X64!),{pk(X65!),{pk(X66!),{pk(X67!),{pk(X68!),{pk(X69!),{pk(X70!),{pk(X71!),{pk(X72!),{pk(X73!),{pk(X74!),{pk(X75!),{pk(X76!),{pk(X77!),{pk(X78!),{pk(X79!),{pk(X80!),{pk(X81!),{pk(X82!),{pk(X83!),{pk(X84!),{pk(X85!),{pk(X86!),{pk(X87!),{pk(X88!),{pk(X89!),{pk(X90!),{pk(X91!),{pk(X92!),{pk(X93!),{pk(X94!),{pk(X95!),{pk(X96!),{pk(X97!),{pk(X98!),{pk(X99!),{pk(X100!),{pk(X101!),{pk(X102!),{pk(X103!),{pk(X104!),{pk(X105!),{pk(X106!),{pk(X107!),{pk(X108!),{pk(X109!),{pk(X110!),{pk(X111!),{pk(X112!),{pk(X113!),{pk(X114!),{pk(X115!),{pk(X116!),{pk(X117!),{pk(X118!),{pk(X119!),{pk(X120!),{pk(X121!),{pk(X122!),{pk(X123!),{pk(X124!),{pk(X125!),{pk(X126!),{pk(X127!),{pk(X128!),pk(X129)}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})").unwrap(); - - // Test 9: Test script complete tree having 128 leaves with depth log(128), only X1 is known - test_desc_satisfy(cl, testdata, "tr(X!,{{{{{{{pk(X1),pk(X2!)},{pk(X3!),pk(X4!)}},{{pk(X5!),pk(X6!)},{pk(X7!),pk(X8!)}}},{{{pk(X9!),pk(X10!)},{pk(X11!),pk(X12!)}},{{pk(X13!),pk(X14!)},{pk(X15!),pk(X16!)}}}},{{{{pk(X17!),pk(X18!)},{pk(X19!),pk(X20!)}},{{pk(X21!),pk(X22!)},{pk(X23!),pk(X24!)}}},{{{pk(X25!),pk(X26!)},{pk(X27!),pk(X28!)}},{{pk(X29!),pk(X30!)},{pk(X31!),pk(X32!)}}}}},{{{{{pk(X33!),pk(X34!)},{pk(X35!),pk(X36!)}},{{pk(X37!),pk(X38!)},{pk(X39!),pk(X40!)}}},{{{pk(X41!),pk(X42!)},{pk(X43!),pk(X44!)}},{{pk(X45!),pk(X46!)},{pk(X47!),pk(X48!)}}}},{{{{pk(X49!),pk(X50!)},{pk(X51!),pk(X52!)}},{{pk(X53!),pk(X54!)},{pk(X55!),pk(X56!)}}},{{{pk(X57!),pk(X58!)},{pk(X59!),pk(X60!)}},{{pk(X61!),pk(X62!)},{pk(X63!),pk(X64!)}}}}}},{{{{{{pk(X65!),pk(X66!)},{pk(X67!),pk(X68!)}},{{pk(X69!),pk(X70!)},{pk(X71!),pk(X72!)}}},{{{pk(X73!),pk(X74!)},{pk(X75!),pk(X76!)}},{{pk(X77!),pk(X78!)},{pk(X79!),pk(X80!)}}}},{{{{pk(X81!),pk(X82!)},{pk(X83!),pk(X84!)}},{{pk(X85!),pk(X86!)},{pk(X87!),pk(X88!)}}},{{{pk(X89!),pk(X90!)},{pk(X91!),pk(X92!)}},{{pk(X93!),pk(X94!)},{pk(X95!),pk(X96!)}}}}},{{{{{pk(X97!),pk(X98!)},{pk(X99!),pk(X100!)}},{{pk(X101!),pk(X102!)},{pk(X103!),pk(X104!)}}},{{{pk(X105!),pk(X106!)},{pk(X107!),pk(X108!)}},{{pk(X109!),pk(X110!)},{pk(X111!),pk(X112!)}}}},{{{{pk(X113!),pk(X114!)},{pk(X115!),pk(X116!)}},{{pk(X117!),pk(X118!)},{pk(X119!),pk(X120!)}}},{{{pk(X121!),pk(X122!)},{pk(X123!),pk(X124!)}},{{pk(X125!),pk(X126!)},{pk(X127!),pk(X128!)}}}}}}})").unwrap(); - - // Test 10: Test taproot desc with ZERO known keys - let result = test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),pk(X2!)})"); - assert_eq!(result, Err(DescError::PsbtFinalizeError)); - - // Test 11: Test taproot with insufficient known keys - let result = test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),multi_a(3,X2!,X3,X4)})"); - assert_eq!(result, Err(DescError::PsbtFinalizeError)); - - // Test 12: size exceeds the limit - let result = test_desc_satisfy(cl, testdata, "wsh(thresh(1,pk(K1),a:pk(K2),a:pk(K3),a:pk(K4),a:pk(K5),a:pk(K6),a:pk(K7),a:pk(K8),a:pk(K9),a:pk(K10),a:pk(K11),a:pk(K12),a:pk(K13),a:pk(K14),a:pk(K15),a:pk(K16),a:pk(K17),a:pk(K18),a:pk(K19),a:pk(K20),a:pk(K21),a:pk(K22),a:pk(K23),a:pk(K24),a:pk(K25),a:pk(K26),a:pk(K27),a:pk(K28),a:pk(K29),a:pk(K30),a:pk(K31),a:pk(K32),a:pk(K33),a:pk(K34),a:pk(K35),a:pk(K36),a:pk(K37),a:pk(K38),a:pk(K39),a:pk(K40),a:pk(K41),a:pk(K42),a:pk(K43),a:pk(K44),a:pk(K45),a:pk(K46),a:pk(K47),a:pk(K48),a:pk(K49),a:pk(K50),a:pk(K51),a:pk(K52),a:pk(K53),a:pk(K54),a:pk(K55),a:pk(K56),a:pk(K57),a:pk(K58),a:pk(K59),a:pk(K60),a:pk(K61),a:pk(K62),a:pk(K63),a:pk(K64),a:pk(K65),a:pk(K66),a:pk(K67),a:pk(K68),a:pk(K69),a:pk(K70),a:pk(K71),a:pk(K72),a:pk(K73),a:pk(K74),a:pk(K75),a:pk(K76),a:pk(K77),a:pk(K78),a:pk(K79),a:pk(K80),a:pk(K81),a:pk(K82),a:pk(K83),a:pk(K84),a:pk(K85),a:pk(K86),a:pk(K87),a:pk(K88),a:pk(K89),a:pk(K90),a:pk(K91),a:pk(K92),a:pk(K93),a:pk(K94),a:pk(K95),a:pk(K96),a:pk(K97),a:pk(K98),a:pk(K99),a:pk(K100)))"); - assert_eq!(result, Err(DescError::DescParseError)); - - // Test 13: Test script tree of depth > 128 is invalid - let result = test_desc_satisfy(cl, testdata, "tr(X!,{pk(X1!),{pk(X2!),{pk(X3!),{pk(X4!),{pk(X5!),{pk(X6!),{pk(X7!),{pk(X8!),{pk(X9!),{pk(X10!),{pk(X11!),{pk(X12!),{pk(X13!),{pk(X14!),{pk(X15!),{pk(X16!),{pk(X17!),{pk(X18!),{pk(X19!),{pk(X20!),{pk(X21!),{pk(X22!),{pk(X23!),{pk(X24!),{pk(X25!),{pk(X26!),{pk(X27!),{pk(X28!),{pk(X29!),{pk(X30!),{pk(X31!),{pk(X32!),{pk(X33!),{pk(X34!),{pk(X35!),{pk(X36!),{pk(X37!),{pk(X38!),{pk(X39!),{pk(X40!),{pk(X41!),{pk(X42!),{pk(X43!),{pk(X44!),{pk(X45!),{pk(X46!),{pk(X47!),{pk(X48!),{pk(X49!),{pk(X50!),{pk(X51!),{pk(X52!),{pk(X53!),{pk(X54!),{pk(X55!),{pk(X56!),{pk(X57!),{pk(X58!),{pk(X59!),{pk(X60!),{pk(X61!),{pk(X62!),{pk(X63!),{pk(X64!),{pk(X65!),{pk(X66!),{pk(X67!),{pk(X68!),{pk(X69!),{pk(X70!),{pk(X71!),{pk(X72!),{pk(X73!),{pk(X74!),{pk(X75!),{pk(X76!),{pk(X77!),{pk(X78!),{pk(X79!),{pk(X80!),{pk(X81!),{pk(X82!),{pk(X83!),{pk(X84!),{pk(X85!),{pk(X86!),{pk(X87!),{pk(X88!),{pk(X89!),{pk(X90!),{pk(X91!),{pk(X92!),{pk(X93!),{pk(X94!),{pk(X95!),{pk(X96!),{pk(X97!),{pk(X98!),{pk(X99!),{pk(X100!),{pk(X101!),{pk(X102!),{pk(X103!),{pk(X104!),{pk(X105!),{pk(X106!),{pk(X107!),{pk(X108!),{pk(X109!),{pk(X110!),{pk(X111!),{pk(X112!),{pk(X113!),{pk(X114!),{pk(X115!),{pk(X116!),{pk(X117!),{pk(X118!),{pk(X119!),{pk(X120!),{pk(X121!),{pk(X122!),{pk(X123!),{pk(X124!),{pk(X125!),{pk(X126!),{pk(X127!),{pk(X128!),{pk(X129!),pk(X130)}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})"); - assert_eq!(result, Err(DescError::DescParseError)); - - // Misc tests for other descriptors that we support - // Keys - test_desc_satisfy(cl, testdata, "wpkh(K)").unwrap(); - test_desc_satisfy(cl, testdata, "pkh(K)").unwrap(); - test_desc_satisfy(cl, testdata, "sh(wpkh(K))").unwrap(); - - // sorted multi - test_desc_satisfy(cl, testdata, "sh(sortedmulti(2,K1,K2,K3))").unwrap(); - test_desc_satisfy(cl, testdata, "wsh(sortedmulti(2,K1,K2,K3))").unwrap(); - test_desc_satisfy(cl, testdata, "sh(wsh(sortedmulti(2,K1,K2,K3)))").unwrap(); - - // Miniscripts - test_desc_satisfy(cl, testdata, "sh(and_v(v:pk(K1),pk(K2)))").unwrap(); - test_desc_satisfy(cl, testdata, "wsh(and_v(v:pk(K1),pk(K2)))").unwrap(); - test_desc_satisfy(cl, testdata, "sh(wsh(and_v(v:pk(K1),pk(K2))))").unwrap(); -} - -#[test] -#[ignore = "bitcoind crate made a breaking change"] -fn test_satisfy() { - let testdata = TestData::new_fixed_data(50); - let cl = &setup::setup().client; - test_descs(cl, &testdata); -}