Skip to content

Commit 28820d6

Browse files
authored
Merge pull request #191 from rust-bitcoin/2020-11--satconstraints
overhaul interpreter ("satisfied constraints") API
2 parents e18d52c + 8c35525 commit 28820d6

File tree

14 files changed

+1757
-1335
lines changed

14 files changed

+1757
-1335
lines changed

.github/workflows/rust.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ jobs:
2727
DO_LINT: true
2828
run: ./contrib/test.sh
2929

30-
bench_miri_nightly:
31-
name: Bench + Miri + Tests
30+
bench_nightly:
31+
name: Bench + Tests
3232
runs-on: ubuntu-latest
3333
strategy:
3434
matrix:
@@ -42,11 +42,10 @@ jobs:
4242
with:
4343
profile: minimal
4444
toolchain: ${{ matrix.rust }}
45-
override: false
45+
override: true
4646
- name: Running cargo test
4747
env:
4848
DO_BENCH: true
49-
DO_MIRI: true
5049
run: ./contrib/test.sh
5150

5251
Tests:

contrib/test.sh

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,6 @@ cargo build --examples
4444
# run all examples
4545
run-parts ./target/debug/examples
4646

47-
# Miri Checks if told to
48-
# Only supported in nightly
49-
if [ "$DO_MIRI" = true ]
50-
then
51-
(
52-
MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri)
53-
echo "Installing latest nightly with Miri: $MIRI_NIGHTLY"
54-
rustup set profile minimal
55-
rustup default "$MIRI_NIGHTLY"
56-
rustup component add miri
57-
cargo miri test miri_
58-
59-
# Change back to latest nightly possibly without Miri
60-
rustup default nightly
61-
)
62-
fi
63-
6447
# Bench if told to
6548
if [ "$DO_BENCH" = true ]
6649
then

examples/verify_tx.rs

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ extern crate miniscript;
1919

2020
use bitcoin::consensus::Decodable;
2121
use bitcoin::secp256k1; // secp256k1 re-exported from rust-bitcoin
22-
use miniscript::NullCtx;
22+
use std::str::FromStr;
23+
2324
fn main() {
2425
// tx `f27eba163c38ad3f34971198687a3f1882b7ec818599ffe469a8440d82261c98`
2526
#[cfg_attr(feature="cargo-fmt", rustfmt_skip)]
@@ -83,30 +84,32 @@ fn main() {
8384
0x49, 0xe5, 0x32, 0xde, 0x59, 0xf4, 0xbc, 0x87,
8485
]);
8586

86-
let (desc, stack) = miniscript::descriptor::from_txin_with_witness_stack(
87+
let mut interpreter = miniscript::Interpreter::from_txdata(
8788
&spk_input_1,
8889
&transaction.input[0].script_sig,
8990
&transaction.input[0].witness,
91+
0,
92+
0,
9093
)
9194
.unwrap();
9295

93-
println!("Descriptor: {}", desc);
96+
let desc_string = interpreter.inferred_descriptor_string();
97+
println!("Descriptor: {}", desc_string);
98+
miniscript::Descriptor::<bitcoin::PublicKey>::from_str(&desc_string)
99+
.expect("this descriptor can be reparsed with sanity checks passing");
100+
interpreter
101+
.inferred_descriptor()
102+
.expect("we can use this method to do the above from_str for us");
94103

95104
// 1. Example one: learn which keys were used, not bothering
96105
// to verify the signatures (trusting that if they're on
97106
// the blockchain, standardness would've required they be
98107
// either valid or 0-length.
99-
let iter = miniscript::descriptor::SatisfiedConstraints::from_descriptor(
100-
&desc,
101-
stack.clone(),
102-
|_, _| true, // Don't bother checking signatures
103-
0,
104-
0,
105-
);
106108
println!("\nExample one");
107-
for elem in iter {
109+
for elem in interpreter.iter(|_, _| true) {
110+
// Don't bother checking signatures
108111
match elem.expect("no evaluation error") {
109-
miniscript::descriptor::SatisfiedConstraint::PublicKey { key, sig } => {
112+
miniscript::interpreter::SatisfiedConstraint::PublicKey { key, sig } => {
110113
println!("Signed with {}: {}", key, sig);
111114
}
112115
_ => {}
@@ -120,22 +123,28 @@ fn main() {
120123
// from the MiniscriptKey which can supplied by `to_pk_ctx` parameter. For example,
121124
// when calculating the script pubkey of a descriptor with xpubs, the secp context and
122125
// child information maybe required.
123-
let sighash = transaction.signature_hash(0, &desc.witness_script(NullCtx), 1);
124-
let message = secp256k1::Message::from_slice(&sighash[..]).expect("32-byte hash");
125-
126-
let iter = miniscript::descriptor::SatisfiedConstraints::from_descriptor(
127-
&desc,
128-
stack.clone(),
129-
|pk, (sig, sighashtype)| {
130-
sighashtype == bitcoin::SigHashType::All && secp.verify(&message, &sig, &pk.key).is_ok()
131-
},
126+
let mut interpreter = miniscript::Interpreter::from_txdata(
127+
&spk_input_1,
128+
&transaction.input[0].script_sig,
129+
&transaction.input[0].witness,
132130
0,
133131
0,
134-
);
132+
)
133+
.unwrap();
134+
135+
// We can set the amount passed to `sighash_verify` to 0 because this is a legacy
136+
// transaction and so the amount won't actually be checked by the signature
137+
let vfyfn = interpreter.sighash_verify(&secp, &transaction, 0, 0);
138+
// Restrict to sighash_all just to demonstrate how to add additional filters
139+
// `&_` needed here because of https://github.com/rust-lang/rust/issues/79187
140+
let vfyfn = move |pk: &_, bitcoinsig: miniscript::BitcoinSig| {
141+
bitcoinsig.1 == bitcoin::SigHashType::All && vfyfn(pk, bitcoinsig)
142+
};
143+
135144
println!("\nExample two");
136-
for elem in iter {
145+
for elem in interpreter.iter(vfyfn) {
137146
match elem.expect("no evaluation error") {
138-
miniscript::descriptor::SatisfiedConstraint::PublicKey { key, sig } => {
147+
miniscript::interpreter::SatisfiedConstraint::PublicKey { key, sig } => {
139148
println!("Signed with {}: {}", key, sig);
140149
}
141150
_ => {}
@@ -147,15 +156,18 @@ fn main() {
147156
let secp = secp256k1::Secp256k1::new();
148157
let message = secp256k1::Message::from_slice(&[0x01; 32][..]).expect("32-byte hash");
149158

150-
let iter = miniscript::descriptor::SatisfiedConstraints::from_descriptor(
151-
&desc,
152-
stack.clone(),
153-
|pk, (sig, sighashtype)| {
154-
sighashtype == bitcoin::SigHashType::All && secp.verify(&message, &sig, &pk.key).is_ok()
155-
},
159+
let mut interpreter = miniscript::Interpreter::from_txdata(
160+
&spk_input_1,
161+
&transaction.input[0].script_sig,
162+
&transaction.input[0].witness,
156163
0,
157164
0,
158-
);
165+
)
166+
.unwrap();
167+
168+
let iter = interpreter.iter(|pk, (sig, sighashtype)| {
169+
sighashtype == bitcoin::SigHashType::All && secp.verify(&message, &sig, &pk.key).is_ok()
170+
});
159171
println!("\nExample three");
160172
for elem in iter {
161173
let error = elem.expect_err("evaluation error");

0 commit comments

Comments
 (0)