Skip to content

Commit 245acbd

Browse files
committed
Merge ElementsProject#33: Update rust-miniscript to 8fcbeb1 (right before bitcoin 0.29 update)
5093ba4 fix some CI things (Andrew Poelstra) a45342f remove crate pinning for dev-dependencies (Andrew Poelstra) c6d89cd Pin dependencies when using MSRV (Tobin C. Harding) 15b57cd Remove TOOLCHAIN (Tobin C. Harding) 3bfb938 Disable honggfuzz features (Tobin C. Harding) cd8da9e Pin serde to 1.0.142 (sanket1729) 88b1f53 Add feature "seder" (Tobin C. Harding) 2ad6555 Rename "derive" things that are not doing derivation (LLFourn) 6dc6aca Make DerivedDescriptorKey first-class citizen (LLFourn) d02c313 Explicitly do not support 16 bit architectures (Tobin C. Harding) edf7587 Remove ToPublicKey bound for max_satisfaction_weight (eunoia_1729) 4ccd4f7 Add support for string images in ripemd160 and hash160 (kanishk779) 905c5dc Rename Pk::Hash to Pk::RawPkHash (sanket1729) 5d36f9b Add Hash256 associated type (sanket1729) e22b081 Add Hash256 type (sanket1729) 169d849 Add policy to descriptor target compilation method (Aman Rojjha) ab79593 Use DescError instead of miniscript::Error (kanishk779) b446ced Add support for writing integration tests that fail (kanishk779) ef4249d Add taproot compiler example usage (Aman Rojjha) cef2a5b Add Tr-compiler write-up and doc-comment (Aman Rojjha) 5233c66 Add Taproot compiler API (Aman Rojjha) 8d0cf06 Remove `ForEach` Trait (Aman Rojjha) 5cb2bcf Refactor PkH to include key. (Aman Rojjha) 09299b0 Refactor ForEach to contain only Pk. (Aman Rojjha) 701c9cc Remove un-necessary lifetimes (Aman Rojjha) ca16bd8 Fix formatter configuration errors with latest nightly (sanket1729) Pull request description: This is already a nontrivial amount of work which needs to be done prior to updating rust-bitcoin and rust-elements. I think, before doing the next step, we should port the new `Locktime` and `Sequence` data structures from rust-bitcoin to rust-elements, and do a rust-elements 0.21 release. That way we can keep all the elements-miniscript code consistent with the rust-miniscript code (which very heavily makes use of locktimes). ACKs for top commit: sanket1729: ACK 5093ba4. Seemed simpler to review the entire diff at once. Carefully looked at changes touching elements specific things, skimmed through other changes. Tree-SHA512: fe4bfb824961f3ce5387d2df4057a3bc7e71acf1f22301409a813448f9c3b16db63acf5b3a6420ae9156f21e8ce59cda1cc9adc433860fbfa7381a028852d4ed
2 parents 5458e7c + 5093ba4 commit 245acbd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1506
-640
lines changed

Cargo.toml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,23 @@ edition = "2018"
1111
compiler = []
1212
trace = []
1313
unstable = []
14-
default = []
15-
use-serde = ["bitcoin/use-serde", "serde"]
14+
serde = ["actual-serde", "bitcoin/use-serde"]
1615
rand = ["bitcoin/rand"]
1716

1817
[dependencies]
1918
bitcoin = "0.28.1"
2019
elements = "0.19.0"
21-
bitcoin-miniscript = {package = "miniscript", git = "https://github.com/rust-bitcoin/rust-miniscript", rev = "44c0e4b8df30439bb22b13a0ee642a3330360613"}
20+
bitcoin-miniscript = {package = "miniscript", git = "https://github.com/rust-bitcoin/rust-miniscript", rev = "c7c39f1e9d1b8da9e2c9318a61fb508553619e6c"}
21+
22+
# Do NOT use this as a feature! Use the `serde` feature instead.
23+
actual-serde = { package = "serde", version = "1.0", optional = true }
24+
2225

2326
[dev-dependencies]
24-
serde_json = "<=1.0.44"
25-
ryu = "<1.0.5"
27+
serde_json = "1.0"
2628
elementsd = {version = "0.5.0", features=["0_21_0","bitcoind_22_0"]}
2729
actual-rand = { package = "rand", version = "0.8.4"}
28-
29-
[dependencies.serde]
30-
version = "1.0"
31-
optional = true
30+
secp256k1 = {version = "0.22.1", features = ["rand-std"]}
3231

3332
[[example]]
3433
name = "htlc"
@@ -45,3 +44,7 @@ name = "verify_tx"
4544

4645
[[example]]
4746
name = "xpub_descriptors"
47+
48+
[[example]]
49+
name = "taproot"
50+
required-features = ["compiler"]

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ or in [the `examples/` directory](https://github.com/ElementsProject/elements-mi
3434
This library should always compile with any combination of features on **Rust 1.41.1**.
3535

3636

37+
Some dependencies do not play nicely with our MSRV, if you are running the tests
38+
you may need to pin as follows:
39+
40+
```
41+
cargo update --package url --precise 2.2.2
42+
cargo update --package form_urlencoded --precise 1.0.1
43+
```
44+
3745
## Contributing
3846
Contributions are generally welcome. If you intend to make larger changes please
3947
discuss them in an issue before PRing them to avoid duplicate work and

contrib/test.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,21 @@
22

33
set -e
44

5-
FEATURES="compiler use-serde rand"
5+
FEATURES="compiler serde rand"
6+
7+
cargo update -p serde --precise 1.0.142
8+
cargo update -p serde_derive --precise 1.0.142
69

710
cargo --version
811
rustc --version
912

13+
# Work out if we are using a nightly toolchain.
1014
MSRV=false
1115
if cargo --version | grep "1\.41\.0"; then
1216
MSRV=true
1317
fi
1418

19+
# form_urlencoded 1.1.0 breaks MSRV.
1520
if [ "$MSRV" = true ]; then
1621
cargo update -p url --precise 2.2.2
1722
cargo update -p form_urlencoded --precise 1.0.1
@@ -57,6 +62,7 @@ then
5762
cargo run --example sign_multisig
5863
cargo run --example verify_tx > /dev/null
5964
cargo run --example xpub_descriptors
65+
cargo run --example taproot --features=compiler
6066
fi
6167

6268
# Bench if told to (this only works with the nightly toolchain)

doc/Tr Compiler.pdf

96.5 KB
Binary file not shown.

examples/taproot.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
extern crate elements_miniscript as miniscript;
2+
3+
use std::collections::HashMap;
4+
use std::str::FromStr;
5+
6+
use bitcoin::hashes::{hash160, ripemd160, sha256};
7+
use bitcoin::util::address::WitnessVersion;
8+
use miniscript::descriptor::DescriptorType;
9+
use miniscript::policy::Concrete;
10+
use miniscript::{hash256, Descriptor, Miniscript, NoExt, Tap, TranslatePk, Translator};
11+
use secp256k1::{rand, KeyPair};
12+
13+
// Refer to https://github.com/sanket1729/adv_btc_workshop/blob/master/workshop.md#creating-a-taproot-descriptor
14+
// for a detailed explanation of the policy and it's compilation
15+
16+
struct StrPkTranslator {
17+
pk_map: HashMap<String, bitcoin::XOnlyPublicKey>,
18+
}
19+
20+
impl Translator<String, bitcoin::XOnlyPublicKey, ()> for StrPkTranslator {
21+
fn pk(&mut self, pk: &String) -> Result<bitcoin::XOnlyPublicKey, ()> {
22+
self.pk_map.get(pk).copied().ok_or(())
23+
}
24+
25+
fn pkh(&mut self, _pkh: &String) -> Result<hash160::Hash, ()> {
26+
unreachable!("Policy doesn't contain any pkh fragment");
27+
}
28+
29+
fn sha256(&mut self, _sha256: &String) -> Result<sha256::Hash, ()> {
30+
unreachable!("Policy does not contain any sha256 fragment");
31+
}
32+
33+
fn hash256(&mut self, _sha256: &String) -> Result<hash256::Hash, ()> {
34+
unreachable!("Policy does not contain any hash256 fragment");
35+
}
36+
37+
fn ripemd160(&mut self, _ripemd160: &String) -> Result<ripemd160::Hash, ()> {
38+
unreachable!("Policy does not contain any ripemd160 fragment");
39+
}
40+
41+
fn hash160(&mut self, _hash160: &String) -> Result<hash160::Hash, ()> {
42+
unreachable!("Policy does not contain any hash160 fragment");
43+
}
44+
}
45+
46+
fn main() {
47+
let pol_str = "or(
48+
99@thresh(2,
49+
pk(hA), pk(S)
50+
),1@or(
51+
99@pk(Ca),
52+
1@and(pk(In), older(9))
53+
)
54+
)"
55+
.replace(&[' ', '\n', '\t'][..], "");
56+
57+
let _ms = Miniscript::<String, Tap>::from_str("and_v(v:ripemd160(H),pk(A))").unwrap();
58+
let pol: Concrete<String> = Concrete::from_str(&pol_str).unwrap();
59+
// In case we can't find an internal key for the given policy, we set the internal key to
60+
// a random pubkey as specified by BIP341 (which are *unspendable* by any party :p)
61+
let desc = pol.compile_tr(Some("UNSPENDABLE_KEY".to_string())).unwrap();
62+
63+
let expected_desc =
64+
Descriptor::<String, _>::from_str("eltr(Ca,{and_v(v:pk(In),older(9)),multi_a(2,hA,S)})")
65+
.unwrap();
66+
assert_eq!(desc, expected_desc);
67+
68+
// Check whether the descriptors are safe.
69+
assert!(desc.sanity_check().is_ok());
70+
71+
// Descriptor Type and Version should match respectively for Taproot
72+
let desc_type = desc.desc_type();
73+
assert_eq!(desc_type, DescriptorType::Tr);
74+
assert_eq!(desc_type.segwit_version().unwrap(), WitnessVersion::V1);
75+
76+
if let Descriptor::Tr(ref p) = desc {
77+
// Check if internal key is correctly inferred as Ca
78+
// assert_eq!(p.internal_key(), &pubkeys[2]);
79+
assert_eq!(p.internal_key(), "Ca");
80+
81+
// Iterate through scripts
82+
let mut iter = p.iter_scripts();
83+
assert_eq!(
84+
iter.next().unwrap(),
85+
(
86+
1,
87+
&Miniscript::<String, Tap, NoExt>::from_str("and_v(vc:pk_k(In),older(9))").unwrap()
88+
)
89+
);
90+
assert_eq!(
91+
iter.next().unwrap(),
92+
(
93+
1,
94+
&Miniscript::<String, Tap, NoExt>::from_str("multi_a(2,hA,S)").unwrap()
95+
)
96+
);
97+
assert_eq!(iter.next(), None);
98+
}
99+
100+
let mut pk_map = HashMap::new();
101+
102+
// We require secp for generating a random XOnlyPublicKey
103+
let secp = secp256k1::Secp256k1::new();
104+
let key_pair = KeyPair::new(&secp, &mut rand::thread_rng());
105+
// Random unspendable XOnlyPublicKey provided for compilation to Taproot Descriptor
106+
let unspendable_pubkey = bitcoin::XOnlyPublicKey::from_keypair(&key_pair);
107+
108+
pk_map.insert("UNSPENDABLE_KEY".to_string(), unspendable_pubkey);
109+
let pubkeys = hardcoded_xonlypubkeys();
110+
pk_map.insert("hA".to_string(), pubkeys[0]);
111+
pk_map.insert("S".to_string(), pubkeys[1]);
112+
pk_map.insert("Ca".to_string(), pubkeys[2]);
113+
pk_map.insert("In".to_string(), pubkeys[3]);
114+
let mut t = StrPkTranslator { pk_map };
115+
116+
let real_desc = desc.translate_pk(&mut t).unwrap();
117+
118+
// Max Satisfaction Weight for compilation, corresponding to the script-path spend
119+
// `multi_a(2,PUBKEY_1,PUBKEY_2) at taptree depth 1, having
120+
// Max Witness Size = scriptSig len + control_block size + varint(script_size) + script_size +
121+
// varint(max satisfaction elements) + max satisfaction size
122+
// = 4 + 65 + 1 + 70 + 1 + 132
123+
let max_sat_wt = real_desc.max_satisfaction_weight().unwrap();
124+
assert_eq!(max_sat_wt, 273);
125+
126+
// Compute the bitcoin address and check if it matches
127+
let addr = real_desc.address(&elements::AddressParams::ELEMENTS).unwrap();
128+
let expected_addr = elements::Address::from_str(
129+
"ert1pxx6wkfdnnx97akwws8l8xdmx5n03qftvx2t269k4sn9adm2emz0sdnytn4",
130+
)
131+
.unwrap();
132+
assert_eq!(addr, expected_addr);
133+
}
134+
135+
fn hardcoded_xonlypubkeys() -> Vec<bitcoin::XOnlyPublicKey> {
136+
let serialized_keys: [[u8; 32]; 4] = [
137+
[
138+
22, 37, 41, 4, 57, 254, 191, 38, 14, 184, 200, 133, 111, 226, 145, 183, 245, 112, 100,
139+
42, 69, 210, 146, 60, 179, 170, 174, 247, 231, 224, 221, 52,
140+
],
141+
[
142+
194, 16, 47, 19, 231, 1, 0, 143, 203, 11, 35, 148, 101, 75, 200, 15, 14, 54, 222, 208,
143+
31, 205, 191, 215, 80, 69, 214, 126, 10, 124, 107, 154,
144+
],
145+
[
146+
202, 56, 167, 245, 51, 10, 193, 145, 213, 151, 66, 122, 208, 43, 10, 17, 17, 153, 170,
147+
29, 89, 133, 223, 134, 220, 212, 166, 138, 2, 152, 122, 16,
148+
],
149+
[
150+
50, 23, 194, 4, 213, 55, 42, 210, 67, 101, 23, 3, 195, 228, 31, 70, 127, 79, 21, 188,
151+
168, 39, 134, 58, 19, 181, 3, 63, 235, 103, 155, 213,
152+
],
153+
];
154+
let mut keys: Vec<bitcoin::XOnlyPublicKey> = vec![];
155+
for idx in 0..4 {
156+
keys.push(bitcoin::XOnlyPublicKey::from_slice(&serialized_keys[idx][..]).unwrap());
157+
}
158+
keys
159+
}

examples/xpub_descriptors.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use std::str::FromStr;
2121
use elements::Address;
2222

2323
use crate::miniscript::elements::secp256k1_zkp::{Secp256k1, Verification};
24-
use crate::miniscript::{Descriptor, DescriptorPublicKey};
24+
use crate::miniscript::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
2525

2626
const XPUB_1: &str = "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB";
2727
const XPUB_2: &str = "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH";
@@ -43,9 +43,9 @@ fn p2wsh<C: Verification>(secp: &Secp256k1<C>) -> Address {
4343
let s = format!("elwsh(sortedmulti(1,{},{}))", XPUB_1, XPUB_2);
4444
// let s = format!("wsh(sortedmulti(1,{},{}))", XPUB_2, XPUB_1);
4545

46-
let address = Descriptor::<DescriptorPublicKey>::from_str(&s)
46+
let address = Descriptor::<DefiniteDescriptorKey>::from_str(&s)
4747
.unwrap()
48-
.derived_descriptor(&secp, 0) // dummy index value if it not a wildcard
48+
.derived_descriptor(&secp)
4949
.unwrap()
5050
.address(&elements::AddressParams::ELEMENTS)
5151
.unwrap();
@@ -68,7 +68,8 @@ fn p2sh_p2wsh<C: Verification>(secp: &Secp256k1<C>) -> Address {
6868

6969
let address = Descriptor::<DescriptorPublicKey>::from_str(&s)
7070
.unwrap()
71-
.derived_descriptor(secp, 5)
71+
.at_derivation_index(5)
72+
.derived_descriptor(secp)
7273
.unwrap()
7374
.address(&elements::AddressParams::ELEMENTS)
7475
.unwrap();

fuzz/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ afl_fuzz = ["afl"]
1212
honggfuzz_fuzz = ["honggfuzz"]
1313

1414
[dependencies]
15-
honggfuzz = { version = "0.5", optional = true, default-features = false }
15+
honggfuzz = { version = "0.5", default-features = false, optional = true }
1616
afl = { version = "0.8", optional = true }
1717
regex = { version = "1.4"}
1818
elements-miniscript = { path = "..", features = ["compiler"] }

rustfmt.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ format_code_in_doc_comments = false
1616
comment_width = 80
1717
normalize_comments = false
1818
normalize_doc_attributes = false
19-
license_template_path = ""
2019
format_strings = false
2120
format_macro_matchers = false
2221
format_macro_bodies = true
@@ -53,7 +52,7 @@ trailing_comma = "Vertical"
5352
match_block_trailing_comma = false
5453
blank_lines_upper_bound = 1
5554
blank_lines_lower_bound = 0
56-
edition = "2015"
55+
edition = "2018"
5756
version = "One"
5857
inline_attribute_width = 0
5958
format_generated_files = true
@@ -63,15 +62,12 @@ use_field_init_shorthand = false
6362
force_explicit_abi = true
6463
condense_wildcard_suffixes = false
6564
color = "Auto"
66-
required_version = "1.4.38"
6765
unstable_features = false
6866
disable_all_formatting = false
6967
skip_children = false
7068
hide_parse_errors = false
7169
error_on_line_overflow = false
7270
error_on_unformatted = false
73-
report_todo = "Never"
74-
report_fixme = "Never"
7571
ignore = []
7672
emit_mode = "Files"
7773
make_backup = false

src/descriptor/bare.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::miniscript::context::ScriptContext;
2929
use crate::policy::{semantic, Liftable};
3030
use crate::util::{varint_len, witness_to_scriptsig};
3131
use crate::{
32-
elementssig_to_rawsig, BareCtx, Error, ForEach, ForEachKey, Miniscript, MiniscriptKey,
32+
elementssig_to_rawsig, BareCtx, Error, ForEachKey, Miniscript, MiniscriptKey,
3333
Satisfier, ToPublicKey, TranslatePk, Translator,
3434
};
3535

@@ -172,10 +172,10 @@ impl_from_str!(
172172
);
173173

174174
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Bare<Pk> {
175-
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
175+
fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool
176176
where
177177
Pk: 'a,
178-
Pk::Hash: 'a,
178+
Pk::RawPkHash: 'a,
179179
{
180180
self.ms.for_each_key(pred)
181181
}
@@ -338,12 +338,12 @@ impl_from_str!(
338338
);
339339

340340
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Pkh<Pk> {
341-
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
341+
fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool
342342
where
343343
Pk: 'a,
344-
Pk::Hash: 'a,
344+
Pk::RawPkHash: 'a,
345345
{
346-
pred(ForEach::Key(&self.pk))
346+
pred(&self.pk)
347347
}
348348
}
349349

src/descriptor/csfs_cov/cov.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ use crate::miniscript::limits::{
5959
use crate::miniscript::{decode, types};
6060
use crate::util::varint_len;
6161
use crate::{
62-
Error, ExtTranslator, Extension, ForEach, ForEachKey, Miniscript, MiniscriptKey, Satisfier,
62+
Error, ExtTranslator, Extension, ForEachKey, Miniscript, MiniscriptKey, Satisfier,
6363
ScriptContext, Segwitv0, ToPublicKey, TranslateExt, TranslatePk, Translator,
6464
};
6565

@@ -457,12 +457,12 @@ where
457457
}
458458

459459
impl<Pk: MiniscriptKey, Ext: Extension> ForEachKey<Pk> for LegacyCSFSCov<Pk, Ext> {
460-
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
460+
fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool
461461
where
462462
Pk: 'a,
463-
Pk::Hash: 'a,
463+
Pk::RawPkHash: 'a,
464464
{
465-
pred(ForEach::Key(&self.pk)) && self.ms.for_any_key(pred)
465+
pred(&self.pk) && self.ms.for_any_key(pred)
466466
}
467467
}
468468

0 commit comments

Comments
 (0)