Bump rust-bitcoin to 0.25, fix Cargo dependencies

Closes #112, closes #113, closes #124
This commit is contained in:
Alekos Filini 2020-10-09 12:03:47 +02:00
parent 69ef56cfed
commit 100f0aaa0a
No known key found for this signature in database
GPG Key ID: 5E8AFC3034FDFA4F
11 changed files with 219 additions and 179 deletions

View File

@ -7,15 +7,15 @@ authors = ["Alekos Filini <alekos.filini@gmail.com>", "Riccardo Casatta <riccard
[dependencies] [dependencies]
bdk-macros = { version = "0.1.0-beta.1", path = "./macros" } bdk-macros = { version = "0.1.0-beta.1", path = "./macros" }
log = "^0.4" log = "^0.4"
bitcoin = { version = "0.23", features = ["use-serde"] } bitcoin = { version = "0.25", features = ["use-serde"] }
miniscript = { version = "1.0" } miniscript = { git = "https://github.com/MagicalBitcoin/rust-miniscript", rev = "dfc53201aa5796b6bf3b5a40581d192abaa84133" }
serde = { version = "^1.0", features = ["derive"] } serde = { version = "^1.0", features = ["derive"] }
serde_json = { version = "^1.0" } serde_json = { version = "^1.0" }
rand = "^0.7" rand = "^0.7"
# Optional dependencies # Optional dependencies
sled = { version = "0.34", optional = true } sled = { version = "0.34", optional = true }
electrum-client = { version = "0.2.0-beta.1", optional = true } electrum-client = { version = "0.3.0-beta.1", optional = true }
reqwest = { version = "0.10", optional = true, features = ["json"] } reqwest = { version = "0.10", optional = true, features = ["json"] }
futures = { version = "0.3", optional = true } futures = { version = "0.3", optional = true }
clap = { version = "2.33", optional = true } clap = { version = "2.33", optional = true }
@ -26,10 +26,6 @@ socks = { version = "0.3", optional = true }
lazy_static = { version = "1.4", optional = true } lazy_static = { version = "1.4", optional = true }
tiny-bip39 = { version = "^0.7", optional = true } tiny-bip39 = { version = "^0.7", optional = true }
[patch.crates-io]
bitcoin = { git = "https://github.com/rust-bitcoin/rust-bitcoin/", rev = "478e091" }
miniscript = { git = "https://github.com/MagicalBitcoin/rust-miniscript", rev = "d0322ac" }
# Platform-specific dependencies # Platform-specific dependencies
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "0.2", features = ["rt-core"] } tokio = { version = "0.2", features = ["rt-core"] }

View File

@ -46,7 +46,7 @@ fn main() {
let policy = extended_desc.extract_policy(signers).unwrap(); let policy = extended_desc.extract_policy(signers).unwrap();
println!("policy: {}", serde_json::to_string(&policy).unwrap()); println!("policy: {}", serde_json::to_string(&policy).unwrap());
let derived_desc = extended_desc.derive(&[ChildNumber::from_normal_idx(42).unwrap()]); let derived_desc = extended_desc.derive(ChildNumber::from_normal_idx(42).unwrap());
println!("{:?}", derived_desc); println!("{:?}", derived_desc);
let addr = derived_desc.address(Network::Testnet).unwrap(); let addr = derived_desc.address(Network::Testnet).unwrap();

View File

@ -31,6 +31,7 @@ pub enum Error {
InvalidPrefix(Vec<u8>), InvalidPrefix(Vec<u8>),
HardenedDerivationOnXpub, HardenedDerivationOnXpub,
MalformedInput, MalformedInput,
InvalidHDKeyPath,
KeyParsingError(String), KeyParsingError(String),
Key(crate::keys::KeyError), Key(crate::keys::KeyError),

View File

@ -31,7 +31,6 @@ use std::collections::{BTreeMap, HashMap};
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use bitcoin::hashes::hash160;
use bitcoin::secp256k1::Secp256k1; use bitcoin::secp256k1::Secp256k1;
use bitcoin::util::bip32::{ChildNumber, DerivationPath, Fingerprint}; use bitcoin::util::bip32::{ChildNumber, DerivationPath, Fingerprint};
use bitcoin::util::psbt; use bitcoin::util::psbt;
@ -122,9 +121,7 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap) {
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> { ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
use crate::keys::DescriptorKey; use crate::keys::DescriptorKey;
// check the network for the keys let check_key = |pk: &DescriptorPublicKey| {
let translated = self.0.translate_pk(
|pk| {
let (pk, _, networks) = if self.0.is_witness() { let (pk, _, networks) = if self.0.is_witness() {
let desciptor_key: DescriptorKey<miniscript::Segwitv0> = let desciptor_key: DescriptorKey<miniscript::Segwitv0> =
pk.clone().to_descriptor_key()?; pk.clone().to_descriptor_key()?;
@ -140,9 +137,10 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap) {
} else { } else {
Err(KeyError::InvalidNetwork) Err(KeyError::InvalidNetwork)
} }
}, };
|pkh| Ok::<_, KeyError>(*pkh),
)?; // check the network for the keys
let translated = self.0.translate_pk(check_key, check_key)?;
Ok((translated, self.1)) Ok((translated, self.1))
} }
@ -155,9 +153,7 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap, ValidNetworks) {
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> { ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
let valid_networks = &self.2; let valid_networks = &self.2;
// fixup the network for keys that need it let fix_key = |pk: &DescriptorPublicKey| {
let translated = self.0.translate_pk(
|pk| {
if valid_networks.contains(&network) { if valid_networks.contains(&network) {
// workaround for xpubs generated by other key types, like bip39: since when the // workaround for xpubs generated by other key types, like bip39: since when the
// conversion is made one network has to be chosen, what we generally choose // conversion is made one network has to be chosen, what we generally choose
@ -178,9 +174,10 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap, ValidNetworks) {
} else { } else {
Err(KeyError::InvalidNetwork) Err(KeyError::InvalidNetwork)
} }
}, };
|pkh| Ok::<_, KeyError>(*pkh),
)?; // fixup the network for keys that need it
let translated = self.0.translate_pk(fix_key, fix_key)?;
Ok((translated, self.1)) Ok((translated, self.1))
} }
@ -188,10 +185,7 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap, ValidNetworks) {
/// Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`] /// Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`]
pub trait ExtractPolicy { pub trait ExtractPolicy {
fn extract_policy( fn extract_policy(&self, signers: Arc<SignersContainer>) -> Result<Option<Policy>, Error>;
&self,
signers: Arc<SignersContainer<DescriptorPublicKey>>,
) -> Result<Option<Policy>, Error>;
} }
pub(crate) trait XKeyUtils { pub(crate) trait XKeyUtils {
@ -201,7 +195,7 @@ pub(crate) trait XKeyUtils {
impl<K: InnerXKey> XKeyUtils for DescriptorXKey<K> { impl<K: InnerXKey> XKeyUtils for DescriptorXKey<K> {
fn full_path(&self, append: &[ChildNumber]) -> DerivationPath { fn full_path(&self, append: &[ChildNumber]) -> DerivationPath {
let full_path = match self.source { let full_path = match self.origin {
Some((_, ref path)) => path Some((_, ref path)) => path
.into_iter() .into_iter()
.chain(self.derivation_path.into_iter()) .chain(self.derivation_path.into_iter())
@ -222,7 +216,7 @@ impl<K: InnerXKey> XKeyUtils for DescriptorXKey<K> {
} }
fn root_fingerprint(&self) -> Fingerprint { fn root_fingerprint(&self) -> Fingerprint {
match self.source { match self.origin {
Some((fingerprint, _)) => fingerprint, Some((fingerprint, _)) => fingerprint,
None => self.xkey.xkey_fingerprint(), None => self.xkey.xkey_fingerprint(),
} }
@ -280,11 +274,13 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
} }
fn get_hd_keypaths(&self, index: u32) -> Result<HDKeyPaths, Error> { fn get_hd_keypaths(&self, index: u32) -> Result<HDKeyPaths, Error> {
let mut answer = BTreeMap::new(); fn translate_key(
key: &DescriptorPublicKey,
let translatefpk = |key: &DescriptorPublicKey| -> Result<_, Error> { index: u32,
paths: &mut HDKeyPaths,
) -> Result<DummyKey, Error> {
match key { match key {
DescriptorPublicKey::PubKey(_) => {} DescriptorPublicKey::SinglePub(_) => {}
DescriptorPublicKey::XPub(xpub) => { DescriptorPublicKey::XPub(xpub) => {
let derive_path = if xpub.is_wildcard { let derive_path = if xpub.is_wildcard {
xpub.derivation_path xpub.derivation_path
@ -299,7 +295,7 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
.xkey .xkey
.derive_pub(&Secp256k1::verification_only(), &derive_path)?; .derive_pub(&Secp256k1::verification_only(), &derive_path)?;
answer.insert( paths.insert(
derived_pubkey.public_key, derived_pubkey.public_key,
( (
xpub.root_fingerprint(), xpub.root_fingerprint(),
@ -310,42 +306,54 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
} }
Ok(DummyKey::default()) Ok(DummyKey::default())
}; }
let translatefpkh = |_: &hash160::Hash| -> Result<_, Error> { Ok(DummyKey::default()) };
self.translate_pk(translatefpk, translatefpkh)?; let mut answer_pk = BTreeMap::new();
let mut answer_pkh = BTreeMap::new();
Ok(answer) self.translate_pk(
|pk| translate_key(pk, index, &mut answer_pk),
|pkh| translate_key(pkh, index, &mut answer_pkh),
)?;
answer_pk.append(&mut answer_pkh);
Ok(answer_pk)
} }
fn is_fixed(&self) -> bool { fn is_fixed(&self) -> bool {
let mut found_wildcard = false; fn check_key(key: &DescriptorPublicKey, flag: &mut bool) -> Result<DummyKey, Error> {
let translatefpk = |key: &DescriptorPublicKey| -> Result<_, Error> {
match key { match key {
DescriptorPublicKey::PubKey(_) => {} DescriptorPublicKey::SinglePub(_) => {}
DescriptorPublicKey::XPub(xpub) => { DescriptorPublicKey::XPub(xpub) => {
if xpub.is_wildcard { if xpub.is_wildcard {
found_wildcard = true; *flag = true;
} }
} }
} }
Ok(DummyKey::default()) Ok(DummyKey::default())
}; }
let translatefpkh = |_: &hash160::Hash| -> Result<_, Error> { Ok(DummyKey::default()) };
self.translate_pk(translatefpk, translatefpkh).unwrap(); let mut found_wildcard_pk = false;
let mut found_wildcard_pkh = false;
!found_wildcard self.translate_pk(
|pk| check_key(pk, &mut found_wildcard_pk),
|pkh| check_key(pkh, &mut found_wildcard_pkh),
)
.unwrap();
!found_wildcard_pk && !found_wildcard_pkh
} }
fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths) -> Option<Self> { fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths) -> Option<Self> {
let index: HashMap<_, _> = hd_keypaths.values().cloned().collect(); fn try_key(
key: &DescriptorPublicKey,
let mut derive_path = None::<DerivationPath>; index: &HashMap<Fingerprint, DerivationPath>,
let translatefpk = |key: &DescriptorPublicKey| -> Result<_, Error> { found_path: &mut Option<ChildNumber>,
if derive_path.is_some() { ) -> Result<DummyKey, Error> {
if found_path.is_some() {
// already found a matching path, we are done // already found a matching path, we are done
return Ok(DummyKey::default()); return Ok(DummyKey::default());
} }
@ -353,9 +361,10 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
if let DescriptorPublicKey::XPub(xpub) = key { if let DescriptorPublicKey::XPub(xpub) = key {
// Check if the key matches one entry in our `index`. If it does, `matches()` will // Check if the key matches one entry in our `index`. If it does, `matches()` will
// return the "prefix" that matched, so we remove that prefix from the full path // return the "prefix" that matched, so we remove that prefix from the full path
// found in `index` and save it in `derive_path` // found in `index` and save it in `derive_path`. We expect this to be a derivation
// path of length 1 if the key `is_wildcard` and an empty path otherwise.
let root_fingerprint = xpub.root_fingerprint(); let root_fingerprint = xpub.root_fingerprint();
derive_path = index let derivation_path: Option<Vec<ChildNumber>> = index
.get_key_value(&root_fingerprint) .get_key_value(&root_fingerprint)
.and_then(|(fingerprint, path)| xpub.matches(*fingerprint, path)) .and_then(|(fingerprint, path)| xpub.matches(*fingerprint, path))
.map(|prefix| { .map(|prefix| {
@ -367,15 +376,46 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
.cloned() .cloned()
.collect() .collect()
}); });
match derivation_path {
Some(path) if xpub.is_wildcard && path.len() == 1 => {
*found_path = Some(path[0])
}
Some(path) if !xpub.is_wildcard && path.is_empty() => {
*found_path = Some(ChildNumber::Normal { index: 0 })
}
Some(_) => return Err(Error::InvalidHDKeyPath),
_ => {}
}
} }
Ok(DummyKey::default()) Ok(DummyKey::default())
}; };
let translatefpkh = |_: &hash160::Hash| -> Result<_, Error> { Ok(DummyKey::default()) };
self.translate_pk(translatefpk, translatefpkh).unwrap(); let index: HashMap<_, _> = hd_keypaths.values().cloned().collect();
derive_path.map(|path| self.derive(path.as_ref())) let mut found_path_pk = None;
let mut found_path_pkh = None;
if self
.translate_pk(
|pk| try_key(pk, &index, &mut found_path_pk),
|pkh| try_key(pkh, &index, &mut found_path_pkh),
)
.is_err()
{
return None;
}
// if we have found a path for both `found_path_pk` and `found_path_pkh` but they are
// different we consider this an error and return None. we only return a path either if
// they are equal or if only one of them is Some(_)
let merged_path = match (found_path_pk, found_path_pkh) {
(Some(a), Some(b)) if a != b => return None,
(a, b) => a.or(b),
};
merged_path.map(|path| self.derive(path))
} }
fn derive_from_psbt_input( fn derive_from_psbt_input(

View File

@ -56,7 +56,7 @@ use bitcoin::util::bip32::Fingerprint;
use bitcoin::PublicKey; use bitcoin::PublicKey;
use miniscript::descriptor::DescriptorPublicKey; use miniscript::descriptor::DescriptorPublicKey;
use miniscript::{Descriptor, Miniscript, MiniscriptKey, ScriptContext, Terminal}; use miniscript::{Descriptor, Miniscript, MiniscriptKey, ScriptContext, Terminal, ToPublicKey};
#[allow(unused_imports)] #[allow(unused_imports)]
use log::{debug, error, info, trace}; use log::{debug, error, info, trace};
@ -82,8 +82,8 @@ pub struct PKOrF {
impl PKOrF { impl PKOrF {
fn from_key(k: &DescriptorPublicKey) -> Self { fn from_key(k: &DescriptorPublicKey) -> Self {
match k { match k {
DescriptorPublicKey::PubKey(pubkey) => PKOrF { DescriptorPublicKey::SinglePub(pubkey) => PKOrF {
pubkey: Some(*pubkey), pubkey: Some(pubkey.key),
..Default::default() ..Default::default()
}, },
DescriptorPublicKey::XPub(xpub) => PKOrF { DescriptorPublicKey::XPub(xpub) => PKOrF {
@ -524,7 +524,7 @@ impl Policy {
fn make_multisig( fn make_multisig(
keys: &[DescriptorPublicKey], keys: &[DescriptorPublicKey],
signers: Arc<SignersContainer<DescriptorPublicKey>>, signers: Arc<SignersContainer>,
threshold: usize, threshold: usize,
) -> Result<Option<Policy>, PolicyError> { ) -> Result<Option<Policy>, PolicyError> {
if threshold == 0 { if threshold == 0 {
@ -648,17 +648,14 @@ impl From<SatisfiableItem> for Policy {
} }
} }
fn signer_id(key: &DescriptorPublicKey) -> SignerId<DescriptorPublicKey> { fn signer_id(key: &DescriptorPublicKey) -> SignerId {
match key { match key {
DescriptorPublicKey::PubKey(pubkey) => pubkey.to_pubkeyhash().into(), DescriptorPublicKey::SinglePub(pubkey) => pubkey.key.to_pubkeyhash().into(),
DescriptorPublicKey::XPub(xpub) => xpub.root_fingerprint().into(), DescriptorPublicKey::XPub(xpub) => xpub.root_fingerprint().into(),
} }
} }
fn signature( fn signature(key: &DescriptorPublicKey, signers: Arc<SignersContainer>) -> Policy {
key: &DescriptorPublicKey,
signers: Arc<SignersContainer<DescriptorPublicKey>>,
) -> Policy {
let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key(key)).into(); let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key(key)).into();
policy.contribution = if signers.find(signer_id(key)).is_some() { policy.contribution = if signers.find(signer_id(key)).is_some() {
@ -673,12 +670,13 @@ fn signature(
} }
fn signature_key( fn signature_key(
key_hash: &<DescriptorPublicKey as MiniscriptKey>::Hash, key: &<DescriptorPublicKey as MiniscriptKey>::Hash,
signers: Arc<SignersContainer<DescriptorPublicKey>>, signers: Arc<SignersContainer>,
) -> Policy { ) -> Policy {
let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key_hash(*key_hash)).into(); let key_hash = key.to_public_key().to_pubkeyhash();
let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key_hash(key_hash)).into();
if signers.find(SignerId::PkHash(*key_hash)).is_some() { if signers.find(SignerId::PkHash(key_hash)).is_some() {
policy.contribution = Satisfaction::Complete { policy.contribution = Satisfaction::Complete {
condition: Default::default(), condition: Default::default(),
} }
@ -688,10 +686,7 @@ fn signature_key(
} }
impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx> { impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx> {
fn extract_policy( fn extract_policy(&self, signers: Arc<SignersContainer>) -> Result<Option<Policy>, Error> {
&self,
signers: Arc<SignersContainer<DescriptorPublicKey>>,
) -> Result<Option<Policy>, Error> {
Ok(match &self.node { Ok(match &self.node {
// Leaves // Leaves
Terminal::True | Terminal::False => None, Terminal::True | Terminal::False => None,
@ -781,10 +776,7 @@ impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx>
} }
impl ExtractPolicy for Descriptor<DescriptorPublicKey> { impl ExtractPolicy for Descriptor<DescriptorPublicKey> {
fn extract_policy( fn extract_policy(&self, signers: Arc<SignersContainer>) -> Result<Option<Policy>, Error> {
&self,
signers: Arc<SignersContainer<DescriptorPublicKey>>,
) -> Result<Option<Policy>, Error> {
match self { match self {
Descriptor::Pk(pubkey) Descriptor::Pk(pubkey)
| Descriptor::Pkh(pubkey) | Descriptor::Pkh(pubkey)

View File

@ -32,7 +32,9 @@ use std::ops::Deref;
use bitcoin::util::bip32; use bitcoin::util::bip32;
use bitcoin::{Network, PrivateKey, PublicKey}; use bitcoin::{Network, PrivateKey, PublicKey};
pub use miniscript::descriptor::{DescriptorPublicKey, DescriptorSecretKey}; pub use miniscript::descriptor::{
DescriptorPublicKey, DescriptorSecretKey, DescriptorSinglePriv, DescriptorSinglePub,
};
use miniscript::descriptor::{DescriptorXKey, KeyMap}; use miniscript::descriptor::{DescriptorXKey, KeyMap};
pub use miniscript::ScriptContext; pub use miniscript::ScriptContext;
use miniscript::{Miniscript, Terminal}; use miniscript::{Miniscript, Terminal};
@ -198,7 +200,7 @@ impl<Ctx: ScriptContext + 'static> ExtScriptContext for Ctx {
/// ``` /// ```
/// use bdk::bitcoin::PublicKey; /// use bdk::bitcoin::PublicKey;
/// ///
/// use bdk::keys::{mainnet_network, ScriptContext, ToDescriptorKey, DescriptorKey, DescriptorPublicKey, KeyError}; /// use bdk::keys::{mainnet_network, ScriptContext, ToDescriptorKey, DescriptorKey, DescriptorPublicKey, DescriptorSinglePub, KeyError};
/// ///
/// pub struct MyKeyType { /// pub struct MyKeyType {
/// pubkey: PublicKey, /// pubkey: PublicKey,
@ -206,7 +208,10 @@ impl<Ctx: ScriptContext + 'static> ExtScriptContext for Ctx {
/// ///
/// impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for MyKeyType { /// impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for MyKeyType {
/// fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> { /// fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
/// Ok(DescriptorKey::from_public(DescriptorPublicKey::PubKey(self.pubkey), mainnet_network())) /// Ok(DescriptorKey::from_public(DescriptorPublicKey::SinglePub(DescriptorSinglePub {
/// origin: None,
/// key: self.pubkey
/// }), mainnet_network()))
/// } /// }
/// } /// }
/// ``` /// ```
@ -286,7 +291,7 @@ pub trait DerivableKey<Ctx: ScriptContext> {
/// Add a extra metadata, consume `self` and turn it into a [`DescriptorKey`] /// Add a extra metadata, consume `self` and turn it into a [`DescriptorKey`]
fn add_metadata( fn add_metadata(
self, self,
source: Option<(bip32::Fingerprint, bip32::DerivationPath)>, origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
derivation_path: bip32::DerivationPath, derivation_path: bip32::DerivationPath,
) -> Result<DescriptorKey<Ctx>, KeyError>; ) -> Result<DescriptorKey<Ctx>, KeyError>;
} }
@ -294,11 +299,11 @@ pub trait DerivableKey<Ctx: ScriptContext> {
impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPubKey { impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPubKey {
fn add_metadata( fn add_metadata(
self, self,
source: Option<(bip32::Fingerprint, bip32::DerivationPath)>, origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
derivation_path: bip32::DerivationPath, derivation_path: bip32::DerivationPath,
) -> Result<DescriptorKey<Ctx>, KeyError> { ) -> Result<DescriptorKey<Ctx>, KeyError> {
DescriptorPublicKey::XPub(DescriptorXKey { DescriptorPublicKey::XPub(DescriptorXKey {
source, origin,
xkey: self, xkey: self,
derivation_path, derivation_path,
is_wildcard: true, is_wildcard: true,
@ -310,11 +315,11 @@ impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPubKey {
impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPrivKey { impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPrivKey {
fn add_metadata( fn add_metadata(
self, self,
source: Option<(bip32::Fingerprint, bip32::DerivationPath)>, origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
derivation_path: bip32::DerivationPath, derivation_path: bip32::DerivationPath,
) -> Result<DescriptorKey<Ctx>, KeyError> { ) -> Result<DescriptorKey<Ctx>, KeyError> {
DescriptorSecretKey::XPrv(DescriptorXKey { DescriptorSecretKey::XPrv(DescriptorXKey {
source, origin,
xkey: self, xkey: self,
derivation_path, derivation_path,
is_wildcard: true, is_wildcard: true,
@ -355,10 +360,10 @@ where
{ {
fn add_metadata( fn add_metadata(
self, self,
source: Option<(bip32::Fingerprint, bip32::DerivationPath)>, origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
derivation_path: bip32::DerivationPath, derivation_path: bip32::DerivationPath,
) -> Result<DescriptorKey<Ctx>, KeyError> { ) -> Result<DescriptorKey<Ctx>, KeyError> {
let descriptor_key = self.key.add_metadata(source, derivation_path)?; let descriptor_key = self.key.add_metadata(origin, derivation_path)?;
Ok(descriptor_key.override_valid_networks(self.valid_networks)) Ok(descriptor_key.override_valid_networks(self.valid_networks))
} }
} }
@ -483,7 +488,7 @@ impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorKey<Ctx> {
impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorPublicKey { impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorPublicKey {
fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> { fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
let networks = match self { let networks = match self {
DescriptorPublicKey::PubKey(_) => any_network(), DescriptorPublicKey::SinglePub(_) => any_network(),
DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. }) DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. })
if xkey.network == Network::Bitcoin => if xkey.network == Network::Bitcoin =>
{ {
@ -498,14 +503,20 @@ impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorPublicKey {
impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PublicKey { impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PublicKey {
fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> { fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
DescriptorPublicKey::PubKey(self).to_descriptor_key() DescriptorPublicKey::SinglePub(DescriptorSinglePub {
key: self,
origin: None,
})
.to_descriptor_key()
} }
} }
impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorSecretKey { impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorSecretKey {
fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> { fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
let networks = match self { let networks = match &self {
DescriptorSecretKey::PrivKey(sk) if sk.network == Network::Bitcoin => mainnet_network(), DescriptorSecretKey::SinglePriv(sk) if sk.key.network == Network::Bitcoin => {
mainnet_network()
}
DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. }) DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. })
if xkey.network == Network::Bitcoin => if xkey.network == Network::Bitcoin =>
{ {
@ -520,7 +531,11 @@ impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorSecretKey {
impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PrivateKey { impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PrivateKey {
fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> { fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
DescriptorSecretKey::PrivKey(self).to_descriptor_key() DescriptorSecretKey::SinglePriv(DescriptorSinglePriv {
key: self,
origin: None,
})
.to_descriptor_key()
} }
} }

View File

@ -37,7 +37,7 @@ use bitcoin::util::bip32::ChildNumber;
use bitcoin::util::psbt::PartiallySignedTransaction as PSBT; use bitcoin::util::psbt::PartiallySignedTransaction as PSBT;
use bitcoin::{Address, Network, OutPoint, Script, SigHashType, Transaction, TxOut, Txid}; use bitcoin::{Address, Network, OutPoint, Script, SigHashType, Transaction, TxOut, Txid};
use miniscript::descriptor::DescriptorPublicKey; use miniscript::psbt::PsbtInputSatisfier;
#[allow(unused_imports)] #[allow(unused_imports)]
use log::{debug, error, info, trace}; use log::{debug, error, info, trace};
@ -87,8 +87,8 @@ pub struct Wallet<B: BlockchainMarker, D: BatchDatabase> {
descriptor: ExtendedDescriptor, descriptor: ExtendedDescriptor,
change_descriptor: Option<ExtendedDescriptor>, change_descriptor: Option<ExtendedDescriptor>,
signers: Arc<SignersContainer<DescriptorPublicKey>>, signers: Arc<SignersContainer>,
change_signers: Arc<SignersContainer<DescriptorPublicKey>>, change_signers: Arc<SignersContainer>,
address_validators: Vec<Arc<Box<dyn AddressValidator>>>, address_validators: Vec<Arc<Box<dyn AddressValidator>>>,
@ -158,7 +158,7 @@ where
let index = self.fetch_and_increment_index(ScriptType::External)?; let index = self.fetch_and_increment_index(ScriptType::External)?;
self.descriptor self.descriptor
.derive(&[ChildNumber::from_normal_idx(index).unwrap()]) .derive(ChildNumber::from_normal_idx(index)?)
.address(self.network) .address(self.network)
.ok_or(Error::ScriptDoesntHaveAddressForm) .ok_or(Error::ScriptDoesntHaveAddressForm)
} }
@ -204,7 +204,7 @@ where
pub fn add_signer( pub fn add_signer(
&mut self, &mut self,
script_type: ScriptType, script_type: ScriptType,
id: SignerId<DescriptorPublicKey>, id: SignerId,
ordering: SignerOrdering, ordering: SignerOrdering,
signer: Arc<Box<dyn Signer>>, signer: Arc<Box<dyn Signer>>,
) { ) {
@ -803,7 +803,7 @@ where
match desc.satisfy( match desc.satisfy(
input, input,
( (
psbt_input.clone(), PsbtInputSatisfier::new(&psbt, n),
After::new(current_height, false), After::new(current_height, false),
Older::new(current_height, create_height, false), Older::new(current_height, create_height, false),
), ),
@ -846,7 +846,7 @@ where
.borrow() .borrow()
.get_path_from_script_pubkey(&txout.script_pubkey)? .get_path_from_script_pubkey(&txout.script_pubkey)?
.map(|(script_type, child)| (self.get_descriptor_for_script_type(script_type).0, child)) .map(|(script_type, child)| (self.get_descriptor_for_script_type(script_type).0, child))
.map(|(desc, child)| desc.derive(&[ChildNumber::from_normal_idx(child).unwrap()]))) .map(|(desc, child)| desc.derive(ChildNumber::from_normal_idx(child).unwrap())))
} }
fn get_change_address(&self) -> Result<Script, Error> { fn get_change_address(&self) -> Result<Script, Error> {
@ -854,7 +854,7 @@ where
let index = self.fetch_and_increment_index(script_type)?; let index = self.fetch_and_increment_index(script_type)?;
Ok(desc Ok(desc
.derive(&[ChildNumber::from_normal_idx(index).unwrap()]) .derive(ChildNumber::from_normal_idx(index)?)
.script_pubkey()) .script_pubkey())
} }
@ -879,7 +879,7 @@ where
let hd_keypaths = descriptor.get_hd_keypaths(index)?; let hd_keypaths = descriptor.get_hd_keypaths(index)?;
let script = descriptor let script = descriptor
.derive(&[ChildNumber::from_normal_idx(index).unwrap()]) .derive(ChildNumber::from_normal_idx(index)?)
.script_pubkey(); .script_pubkey();
for validator in &self.address_validators { for validator in &self.address_validators {
validator.validate(script_type, &hd_keypaths, &script)?; validator.validate(script_type, &hd_keypaths, &script)?;
@ -909,7 +909,7 @@ where
for i in from..(from + count) { for i in from..(from + count) {
address_batch.set_script_pubkey( address_batch.set_script_pubkey(
&descriptor &descriptor
.derive(&[ChildNumber::from_normal_idx(i).unwrap()]) .derive(ChildNumber::from_normal_idx(i)?)
.script_pubkey(), .script_pubkey(),
script_type, script_type,
i, i,
@ -1004,7 +1004,7 @@ where
let (desc, _) = self.get_descriptor_for_script_type(script_type); let (desc, _) = self.get_descriptor_for_script_type(script_type);
psbt_input.hd_keypaths = desc.get_hd_keypaths(child)?; psbt_input.hd_keypaths = desc.get_hd_keypaths(child)?;
let derived_descriptor = desc.derive(&[ChildNumber::from_normal_idx(child).unwrap()]); let derived_descriptor = desc.derive(ChildNumber::from_normal_idx(child)?);
psbt_input.redeem_script = derived_descriptor.psbt_redeem_script(); psbt_input.redeem_script = derived_descriptor.psbt_redeem_script();
psbt_input.witness_script = derived_descriptor.psbt_witness_script(); psbt_input.witness_script = derived_descriptor.psbt_witness_script();

View File

@ -102,7 +102,7 @@ use bitcoin::util::bip32::{ExtendedPrivKey, Fingerprint};
use bitcoin::util::{bip143, psbt}; use bitcoin::util::{bip143, psbt};
use bitcoin::{PrivateKey, Script, SigHash, SigHashType}; use bitcoin::{PrivateKey, Script, SigHash, SigHashType};
use miniscript::descriptor::{DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey, KeyMap}; use miniscript::descriptor::{DescriptorSecretKey, DescriptorSinglePriv, DescriptorXKey, KeyMap};
use miniscript::{Legacy, MiniscriptKey, Segwitv0}; use miniscript::{Legacy, MiniscriptKey, Segwitv0};
use crate::descriptor::XKeyUtils; use crate::descriptor::XKeyUtils;
@ -110,19 +110,19 @@ use crate::descriptor::XKeyUtils;
/// Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among /// Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among
/// multiple of them /// multiple of them
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SignerId<Pk: MiniscriptKey> { pub enum SignerId {
PkHash(<Pk as MiniscriptKey>::Hash), PkHash(hash160::Hash),
Fingerprint(Fingerprint), Fingerprint(Fingerprint),
} }
impl From<hash160::Hash> for SignerId<DescriptorPublicKey> { impl From<hash160::Hash> for SignerId {
fn from(hash: hash160::Hash) -> SignerId<DescriptorPublicKey> { fn from(hash: hash160::Hash) -> SignerId {
SignerId::PkHash(hash) SignerId::PkHash(hash)
} }
} }
impl From<Fingerprint> for SignerId<DescriptorPublicKey> { impl From<Fingerprint> for SignerId {
fn from(fing: Fingerprint) -> SignerId<DescriptorPublicKey> { fn from(fing: Fingerprint) -> SignerId {
SignerId::Fingerprint(fing) SignerId::Fingerprint(fing)
} }
} }
@ -284,7 +284,10 @@ impl Signer for PrivateKey {
} }
fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> { fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
Some(DescriptorSecretKey::PrivKey(*self)) Some(DescriptorSecretKey::SinglePriv(DescriptorSinglePriv {
key: *self,
origin: None,
}))
} }
} }
@ -303,13 +306,13 @@ impl std::default::Default for SignerOrdering {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct SignersContainerKey<Pk: MiniscriptKey> { struct SignersContainerKey {
id: SignerId<Pk>, id: SignerId,
ordering: SignerOrdering, ordering: SignerOrdering,
} }
impl<Pk: MiniscriptKey> From<(SignerId<Pk>, SignerOrdering)> for SignersContainerKey<Pk> { impl From<(SignerId, SignerOrdering)> for SignersContainerKey {
fn from(tuple: (SignerId<Pk>, SignerOrdering)) -> Self { fn from(tuple: (SignerId, SignerOrdering)) -> Self {
SignersContainerKey { SignersContainerKey {
id: tuple.0, id: tuple.0,
ordering: tuple.1, ordering: tuple.1,
@ -319,11 +322,9 @@ impl<Pk: MiniscriptKey> From<(SignerId<Pk>, SignerOrdering)> for SignersContaine
/// Container for multiple signers /// Container for multiple signers
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct SignersContainer<Pk: MiniscriptKey>( pub struct SignersContainer(BTreeMap<SignersContainerKey, Arc<Box<dyn Signer>>>);
BTreeMap<SignersContainerKey<Pk>, Arc<Box<dyn Signer>>>,
);
impl SignersContainer<DescriptorPublicKey> { impl SignersContainer {
pub fn as_key_map(&self) -> KeyMap { pub fn as_key_map(&self) -> KeyMap {
self.0 self.0
.values() .values()
@ -333,20 +334,21 @@ impl SignersContainer<DescriptorPublicKey> {
} }
} }
impl From<KeyMap> for SignersContainer<DescriptorPublicKey> { impl From<KeyMap> for SignersContainer {
fn from(keymap: KeyMap) -> SignersContainer<DescriptorPublicKey> { fn from(keymap: KeyMap) -> SignersContainer {
let mut container = SignersContainer::new(); let mut container = SignersContainer::new();
for (_, secret) in keymap { for (_, secret) in keymap {
match secret { match secret {
DescriptorSecretKey::PrivKey(private_key) => container.add_external( DescriptorSecretKey::SinglePriv(private_key) => container.add_external(
SignerId::from( SignerId::from(
private_key private_key
.key
.public_key(&Secp256k1::signing_only()) .public_key(&Secp256k1::signing_only())
.to_pubkeyhash(), .to_pubkeyhash(),
), ),
SignerOrdering::default(), SignerOrdering::default(),
Arc::new(Box::new(private_key)), Arc::new(Box::new(private_key.key)),
), ),
DescriptorSecretKey::XPrv(xprv) => container.add_external( DescriptorSecretKey::XPrv(xprv) => container.add_external(
SignerId::from(xprv.root_fingerprint()), SignerId::from(xprv.root_fingerprint()),
@ -360,7 +362,7 @@ impl From<KeyMap> for SignersContainer<DescriptorPublicKey> {
} }
} }
impl<Pk: MiniscriptKey> SignersContainer<Pk> { impl SignersContainer {
/// Default constructor /// Default constructor
pub fn new() -> Self { pub fn new() -> Self {
SignersContainer(Default::default()) SignersContainer(Default::default())
@ -370,7 +372,7 @@ impl<Pk: MiniscriptKey> SignersContainer<Pk> {
/// signer that was previosuly in the container, if any /// signer that was previosuly in the container, if any
pub fn add_external( pub fn add_external(
&mut self, &mut self,
id: SignerId<Pk>, id: SignerId,
ordering: SignerOrdering, ordering: SignerOrdering,
signer: Arc<Box<dyn Signer>>, signer: Arc<Box<dyn Signer>>,
) -> Option<Arc<Box<dyn Signer>>> { ) -> Option<Arc<Box<dyn Signer>>> {
@ -380,14 +382,14 @@ impl<Pk: MiniscriptKey> SignersContainer<Pk> {
/// Removes a signer from the container and returns it /// Removes a signer from the container and returns it
pub fn remove( pub fn remove(
&mut self, &mut self,
id: SignerId<Pk>, id: SignerId,
ordering: SignerOrdering, ordering: SignerOrdering,
) -> Option<Arc<Box<dyn Signer>>> { ) -> Option<Arc<Box<dyn Signer>>> {
self.0.remove(&(id, ordering).into()) self.0.remove(&(id, ordering).into())
} }
/// Returns the list of identifiers of all the signers in the container /// Returns the list of identifiers of all the signers in the container
pub fn ids(&self) -> Vec<&SignerId<Pk>> { pub fn ids(&self) -> Vec<&SignerId> {
self.0 self.0
.keys() .keys()
.map(|SignersContainerKey { id, .. }| id) .map(|SignersContainerKey { id, .. }| id)
@ -400,7 +402,7 @@ impl<Pk: MiniscriptKey> SignersContainer<Pk> {
} }
/// Finds the signer with lowest ordering for a given id in the container. /// Finds the signer with lowest ordering for a given id in the container.
pub fn find(&self, id: SignerId<Pk>) -> Option<&Arc<Box<dyn Signer>>> { pub fn find(&self, id: SignerId) -> Option<&Arc<Box<dyn Signer>>> {
self.0 self.0
.range(( .range((
Included(&(id.clone(), SignerOrdering(0)).into()), Included(&(id.clone(), SignerOrdering(0)).into()),
@ -515,22 +517,22 @@ impl ComputeSighash for Segwitv0 {
} }
} }
impl<Pk: MiniscriptKey> PartialOrd for SignersContainerKey<Pk> { impl PartialOrd for SignersContainerKey {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl<Pk: MiniscriptKey> Ord for SignersContainerKey<Pk> { impl Ord for SignersContainerKey {
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
self.ordering.cmp(&other.ordering) self.ordering.cmp(&other.ordering)
} }
} }
impl<Pk: MiniscriptKey> PartialEq for SignersContainerKey<Pk> { impl PartialEq for SignersContainerKey {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.ordering == other.ordering self.ordering == other.ordering
} }
} }
impl<Pk: MiniscriptKey> Eq for SignersContainerKey<Pk> {} impl Eq for SignersContainerKey {}

View File

@ -206,7 +206,7 @@ impl<Cs: CoinSelectionAlgorithm> TxBuilder<Cs> {
/// ///
/// The `version` should always be greater than `0` and greater than `1` if the wallet's /// The `version` should always be greater than `0` and greater than `1` if the wallet's
/// descriptors contain an "older" (OP_CSV) operator. /// descriptors contain an "older" (OP_CSV) operator.
pub fn version(mut self, version: u32) -> Self { pub fn version(mut self, version: i32) -> Self {
self.version = Some(Version(version)); self.version = Some(Version(version));
self self
} }
@ -316,7 +316,7 @@ impl TxOrdering {
/// ///
/// Has a default value of `1` /// Has a default value of `1`
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)] #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
pub(crate) struct Version(pub(crate) u32); pub(crate) struct Version(pub(crate) i32);
impl Default for Version { impl Default for Version {
fn default() -> Self { fn default() -> Self {

View File

@ -9,17 +9,11 @@ name = "testutils"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
# The latest bitcoincore-rpc depends on an older version of bitcoin, which in turns depends on an
# older version of secp256k1, which causes conflicts during linking. Use my fork right now, we can
# switch back to crates.io as soon as rust-bitcoin is updated in rust-bitcoincore-rpc.
#
# Tracking issue: https://github.com/rust-bitcoin/rust-bitcoincore-rpc/pull/80
[dependencies] [dependencies]
log = "0.4.8" log = "0.4.8"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
serial_test = "0.4" serial_test = "0.4"
bitcoin = "0.23" bitcoin = "0.25"
bitcoincore-rpc = "0.11" bitcoincore-rpc = "0.12"
electrum-client = "0.2.0-beta.1" electrum-client = "0.3.0-beta.1"

View File

@ -119,13 +119,13 @@ macro_rules! testutils {
use miniscript::descriptor::{Descriptor, DescriptorPublicKey}; use miniscript::descriptor::{Descriptor, DescriptorPublicKey};
let parsed = Descriptor::<DescriptorPublicKey>::parse_secret(&$descriptors.0).expect("Failed to parse descriptor in `testutils!(@external)`").0; let parsed = Descriptor::<DescriptorPublicKey>::parse_secret(&$descriptors.0).expect("Failed to parse descriptor in `testutils!(@external)`").0;
parsed.derive(&[bitcoin::util::bip32::ChildNumber::from_normal_idx($child).unwrap()]).address(bitcoin::Network::Regtest).expect("No address form") parsed.derive(bitcoin::util::bip32::ChildNumber::from_normal_idx($child).unwrap()).address(bitcoin::Network::Regtest).expect("No address form")
}); });
( @internal $descriptors:expr, $child:expr ) => ({ ( @internal $descriptors:expr, $child:expr ) => ({
use miniscript::descriptor::{Descriptor, DescriptorPublicKey}; use miniscript::descriptor::{Descriptor, DescriptorPublicKey};
let parsed = Descriptor::<DescriptorPublicKey>::parse_secret(&$descriptors.1.expect("Missing internal descriptor")).expect("Failed to parse descriptor in `testutils!(@internal)`").0; let parsed = Descriptor::<DescriptorPublicKey>::parse_secret(&$descriptors.1.expect("Missing internal descriptor")).expect("Failed to parse descriptor in `testutils!(@internal)`").0;
parsed.derive(&[bitcoin::util::bip32::ChildNumber::from_normal_idx($child).unwrap()]).address(bitcoin::Network::Regtest).expect("No address form") parsed.derive(bitcoin::util::bip32::ChildNumber::from_normal_idx($child).unwrap()).address(bitcoin::Network::Regtest).expect("No address form")
}); });
( @e $descriptors:expr, $child:expr ) => ({ testutils!(@external $descriptors, $child) }); ( @e $descriptors:expr, $child:expr ) => ({ testutils!(@external $descriptors, $child) });
( @i $descriptors:expr, $child:expr ) => ({ testutils!(@internal $descriptors, $child) }); ( @i $descriptors:expr, $child:expr ) => ({ testutils!(@internal $descriptors, $child) });
@ -386,7 +386,7 @@ impl TestClient {
trace!("getblocktemplate: {:#?}", block_template); trace!("getblocktemplate: {:#?}", block_template);
let header = BlockHeader { let header = BlockHeader {
version: block_template["version"].as_u64().unwrap() as u32, version: block_template["version"].as_i64().unwrap() as i32,
prev_blockhash: BlockHash::from_hex( prev_blockhash: BlockHash::from_hex(
block_template["previousblockhash"].as_str().unwrap(), block_template["previousblockhash"].as_str().unwrap(),
) )