Bump rust-bitcoin to 0.25, fix Cargo dependencies
Closes #112, closes #113, closes #124
This commit is contained in:
parent
69ef56cfed
commit
100f0aaa0a
10
Cargo.toml
10
Cargo.toml
@ -7,15 +7,15 @@ authors = ["Alekos Filini <alekos.filini@gmail.com>", "Riccardo Casatta <riccard
|
||||
[dependencies]
|
||||
bdk-macros = { version = "0.1.0-beta.1", path = "./macros" }
|
||||
log = "^0.4"
|
||||
bitcoin = { version = "0.23", features = ["use-serde"] }
|
||||
miniscript = { version = "1.0" }
|
||||
bitcoin = { version = "0.25", features = ["use-serde"] }
|
||||
miniscript = { git = "https://github.com/MagicalBitcoin/rust-miniscript", rev = "dfc53201aa5796b6bf3b5a40581d192abaa84133" }
|
||||
serde = { version = "^1.0", features = ["derive"] }
|
||||
serde_json = { version = "^1.0" }
|
||||
rand = "^0.7"
|
||||
|
||||
# Optional dependencies
|
||||
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"] }
|
||||
futures = { version = "0.3", 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 }
|
||||
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
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
tokio = { version = "0.2", features = ["rt-core"] }
|
||||
|
@ -46,7 +46,7 @@ fn main() {
|
||||
let policy = extended_desc.extract_policy(signers).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);
|
||||
|
||||
let addr = derived_desc.address(Network::Testnet).unwrap();
|
||||
|
@ -31,6 +31,7 @@ pub enum Error {
|
||||
InvalidPrefix(Vec<u8>),
|
||||
HardenedDerivationOnXpub,
|
||||
MalformedInput,
|
||||
InvalidHDKeyPath,
|
||||
|
||||
KeyParsingError(String),
|
||||
Key(crate::keys::KeyError),
|
||||
|
@ -31,7 +31,6 @@ use std::collections::{BTreeMap, HashMap};
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bitcoin::hashes::hash160;
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
use bitcoin::util::bip32::{ChildNumber, DerivationPath, Fingerprint};
|
||||
use bitcoin::util::psbt;
|
||||
@ -122,27 +121,26 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap) {
|
||||
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
|
||||
use crate::keys::DescriptorKey;
|
||||
|
||||
// check the network for the keys
|
||||
let translated = self.0.translate_pk(
|
||||
|pk| {
|
||||
let (pk, _, networks) = if self.0.is_witness() {
|
||||
let desciptor_key: DescriptorKey<miniscript::Segwitv0> =
|
||||
pk.clone().to_descriptor_key()?;
|
||||
desciptor_key.extract()?
|
||||
} else {
|
||||
let desciptor_key: DescriptorKey<miniscript::Legacy> =
|
||||
pk.clone().to_descriptor_key()?;
|
||||
desciptor_key.extract()?
|
||||
};
|
||||
let check_key = |pk: &DescriptorPublicKey| {
|
||||
let (pk, _, networks) = if self.0.is_witness() {
|
||||
let desciptor_key: DescriptorKey<miniscript::Segwitv0> =
|
||||
pk.clone().to_descriptor_key()?;
|
||||
desciptor_key.extract()?
|
||||
} else {
|
||||
let desciptor_key: DescriptorKey<miniscript::Legacy> =
|
||||
pk.clone().to_descriptor_key()?;
|
||||
desciptor_key.extract()?
|
||||
};
|
||||
|
||||
if networks.contains(&network) {
|
||||
Ok(pk)
|
||||
} else {
|
||||
Err(KeyError::InvalidNetwork)
|
||||
}
|
||||
},
|
||||
|pkh| Ok::<_, KeyError>(*pkh),
|
||||
)?;
|
||||
if networks.contains(&network) {
|
||||
Ok(pk)
|
||||
} else {
|
||||
Err(KeyError::InvalidNetwork)
|
||||
}
|
||||
};
|
||||
|
||||
// check the network for the keys
|
||||
let translated = self.0.translate_pk(check_key, check_key)?;
|
||||
|
||||
Ok((translated, self.1))
|
||||
}
|
||||
@ -155,32 +153,31 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap, ValidNetworks) {
|
||||
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
|
||||
let valid_networks = &self.2;
|
||||
|
||||
let fix_key = |pk: &DescriptorPublicKey| {
|
||||
if valid_networks.contains(&network) {
|
||||
// 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
|
||||
// "mainnet", but then override the set of valid networks to specify that all of
|
||||
// them are valid. here we reset the network to make sure the wallet struct gets a
|
||||
// descriptor with the right network everywhere.
|
||||
let pk = match pk {
|
||||
DescriptorPublicKey::XPub(ref xpub) => {
|
||||
let mut xpub = xpub.clone();
|
||||
xpub.xkey.network = network;
|
||||
|
||||
DescriptorPublicKey::XPub(xpub)
|
||||
}
|
||||
other => other.clone(),
|
||||
};
|
||||
|
||||
Ok(pk)
|
||||
} else {
|
||||
Err(KeyError::InvalidNetwork)
|
||||
}
|
||||
};
|
||||
|
||||
// fixup the network for keys that need it
|
||||
let translated = self.0.translate_pk(
|
||||
|pk| {
|
||||
if valid_networks.contains(&network) {
|
||||
// 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
|
||||
// "mainnet", but then override the set of valid networks to specify that all of
|
||||
// them are valid. here we reset the network to make sure the wallet struct gets a
|
||||
// descriptor with the right network everywhere.
|
||||
let pk = match pk {
|
||||
DescriptorPublicKey::XPub(ref xpub) => {
|
||||
let mut xpub = xpub.clone();
|
||||
xpub.xkey.network = network;
|
||||
|
||||
DescriptorPublicKey::XPub(xpub)
|
||||
}
|
||||
other => other.clone(),
|
||||
};
|
||||
|
||||
Ok(pk)
|
||||
} else {
|
||||
Err(KeyError::InvalidNetwork)
|
||||
}
|
||||
},
|
||||
|pkh| Ok::<_, KeyError>(*pkh),
|
||||
)?;
|
||||
let translated = self.0.translate_pk(fix_key, fix_key)?;
|
||||
|
||||
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`]
|
||||
pub trait ExtractPolicy {
|
||||
fn extract_policy(
|
||||
&self,
|
||||
signers: Arc<SignersContainer<DescriptorPublicKey>>,
|
||||
) -> Result<Option<Policy>, Error>;
|
||||
fn extract_policy(&self, signers: Arc<SignersContainer>) -> Result<Option<Policy>, Error>;
|
||||
}
|
||||
|
||||
pub(crate) trait XKeyUtils {
|
||||
@ -201,7 +195,7 @@ pub(crate) trait XKeyUtils {
|
||||
|
||||
impl<K: InnerXKey> XKeyUtils for DescriptorXKey<K> {
|
||||
fn full_path(&self, append: &[ChildNumber]) -> DerivationPath {
|
||||
let full_path = match self.source {
|
||||
let full_path = match self.origin {
|
||||
Some((_, ref path)) => 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 {
|
||||
match self.source {
|
||||
match self.origin {
|
||||
Some((fingerprint, _)) => 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> {
|
||||
let mut answer = BTreeMap::new();
|
||||
|
||||
let translatefpk = |key: &DescriptorPublicKey| -> Result<_, Error> {
|
||||
fn translate_key(
|
||||
key: &DescriptorPublicKey,
|
||||
index: u32,
|
||||
paths: &mut HDKeyPaths,
|
||||
) -> Result<DummyKey, Error> {
|
||||
match key {
|
||||
DescriptorPublicKey::PubKey(_) => {}
|
||||
DescriptorPublicKey::SinglePub(_) => {}
|
||||
DescriptorPublicKey::XPub(xpub) => {
|
||||
let derive_path = if xpub.is_wildcard {
|
||||
xpub.derivation_path
|
||||
@ -299,7 +295,7 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
|
||||
.xkey
|
||||
.derive_pub(&Secp256k1::verification_only(), &derive_path)?;
|
||||
|
||||
answer.insert(
|
||||
paths.insert(
|
||||
derived_pubkey.public_key,
|
||||
(
|
||||
xpub.root_fingerprint(),
|
||||
@ -310,42 +306,54 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
|
||||
}
|
||||
|
||||
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 {
|
||||
let mut found_wildcard = false;
|
||||
|
||||
let translatefpk = |key: &DescriptorPublicKey| -> Result<_, Error> {
|
||||
fn check_key(key: &DescriptorPublicKey, flag: &mut bool) -> Result<DummyKey, Error> {
|
||||
match key {
|
||||
DescriptorPublicKey::PubKey(_) => {}
|
||||
DescriptorPublicKey::SinglePub(_) => {}
|
||||
DescriptorPublicKey::XPub(xpub) => {
|
||||
if xpub.is_wildcard {
|
||||
found_wildcard = true;
|
||||
*flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
let index: HashMap<_, _> = hd_keypaths.values().cloned().collect();
|
||||
|
||||
let mut derive_path = None::<DerivationPath>;
|
||||
let translatefpk = |key: &DescriptorPublicKey| -> Result<_, Error> {
|
||||
if derive_path.is_some() {
|
||||
fn try_key(
|
||||
key: &DescriptorPublicKey,
|
||||
index: &HashMap<Fingerprint, DerivationPath>,
|
||||
found_path: &mut Option<ChildNumber>,
|
||||
) -> Result<DummyKey, Error> {
|
||||
if found_path.is_some() {
|
||||
// already found a matching path, we are done
|
||||
return Ok(DummyKey::default());
|
||||
}
|
||||
@ -353,9 +361,10 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
|
||||
if let DescriptorPublicKey::XPub(xpub) = key {
|
||||
// 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
|
||||
// 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();
|
||||
derive_path = index
|
||||
let derivation_path: Option<Vec<ChildNumber>> = index
|
||||
.get_key_value(&root_fingerprint)
|
||||
.and_then(|(fingerprint, path)| xpub.matches(*fingerprint, path))
|
||||
.map(|prefix| {
|
||||
@ -367,15 +376,46 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
|
||||
.cloned()
|
||||
.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())
|
||||
};
|
||||
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(
|
||||
|
@ -56,7 +56,7 @@ use bitcoin::util::bip32::Fingerprint;
|
||||
use bitcoin::PublicKey;
|
||||
|
||||
use miniscript::descriptor::DescriptorPublicKey;
|
||||
use miniscript::{Descriptor, Miniscript, MiniscriptKey, ScriptContext, Terminal};
|
||||
use miniscript::{Descriptor, Miniscript, MiniscriptKey, ScriptContext, Terminal, ToPublicKey};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace};
|
||||
@ -82,8 +82,8 @@ pub struct PKOrF {
|
||||
impl PKOrF {
|
||||
fn from_key(k: &DescriptorPublicKey) -> Self {
|
||||
match k {
|
||||
DescriptorPublicKey::PubKey(pubkey) => PKOrF {
|
||||
pubkey: Some(*pubkey),
|
||||
DescriptorPublicKey::SinglePub(pubkey) => PKOrF {
|
||||
pubkey: Some(pubkey.key),
|
||||
..Default::default()
|
||||
},
|
||||
DescriptorPublicKey::XPub(xpub) => PKOrF {
|
||||
@ -524,7 +524,7 @@ impl Policy {
|
||||
|
||||
fn make_multisig(
|
||||
keys: &[DescriptorPublicKey],
|
||||
signers: Arc<SignersContainer<DescriptorPublicKey>>,
|
||||
signers: Arc<SignersContainer>,
|
||||
threshold: usize,
|
||||
) -> Result<Option<Policy>, PolicyError> {
|
||||
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 {
|
||||
DescriptorPublicKey::PubKey(pubkey) => pubkey.to_pubkeyhash().into(),
|
||||
DescriptorPublicKey::SinglePub(pubkey) => pubkey.key.to_pubkeyhash().into(),
|
||||
DescriptorPublicKey::XPub(xpub) => xpub.root_fingerprint().into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn signature(
|
||||
key: &DescriptorPublicKey,
|
||||
signers: Arc<SignersContainer<DescriptorPublicKey>>,
|
||||
) -> Policy {
|
||||
fn signature(key: &DescriptorPublicKey, signers: Arc<SignersContainer>) -> Policy {
|
||||
let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key(key)).into();
|
||||
|
||||
policy.contribution = if signers.find(signer_id(key)).is_some() {
|
||||
@ -673,12 +670,13 @@ fn signature(
|
||||
}
|
||||
|
||||
fn signature_key(
|
||||
key_hash: &<DescriptorPublicKey as MiniscriptKey>::Hash,
|
||||
signers: Arc<SignersContainer<DescriptorPublicKey>>,
|
||||
key: &<DescriptorPublicKey as MiniscriptKey>::Hash,
|
||||
signers: Arc<SignersContainer>,
|
||||
) -> 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 {
|
||||
condition: Default::default(),
|
||||
}
|
||||
@ -688,10 +686,7 @@ fn signature_key(
|
||||
}
|
||||
|
||||
impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx> {
|
||||
fn extract_policy(
|
||||
&self,
|
||||
signers: Arc<SignersContainer<DescriptorPublicKey>>,
|
||||
) -> Result<Option<Policy>, Error> {
|
||||
fn extract_policy(&self, signers: Arc<SignersContainer>) -> Result<Option<Policy>, Error> {
|
||||
Ok(match &self.node {
|
||||
// Leaves
|
||||
Terminal::True | Terminal::False => None,
|
||||
@ -781,10 +776,7 @@ impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx>
|
||||
}
|
||||
|
||||
impl ExtractPolicy for Descriptor<DescriptorPublicKey> {
|
||||
fn extract_policy(
|
||||
&self,
|
||||
signers: Arc<SignersContainer<DescriptorPublicKey>>,
|
||||
) -> Result<Option<Policy>, Error> {
|
||||
fn extract_policy(&self, signers: Arc<SignersContainer>) -> Result<Option<Policy>, Error> {
|
||||
match self {
|
||||
Descriptor::Pk(pubkey)
|
||||
| Descriptor::Pkh(pubkey)
|
||||
|
@ -32,7 +32,9 @@ use std::ops::Deref;
|
||||
use bitcoin::util::bip32;
|
||||
use bitcoin::{Network, PrivateKey, PublicKey};
|
||||
|
||||
pub use miniscript::descriptor::{DescriptorPublicKey, DescriptorSecretKey};
|
||||
pub use miniscript::descriptor::{
|
||||
DescriptorPublicKey, DescriptorSecretKey, DescriptorSinglePriv, DescriptorSinglePub,
|
||||
};
|
||||
use miniscript::descriptor::{DescriptorXKey, KeyMap};
|
||||
pub use miniscript::ScriptContext;
|
||||
use miniscript::{Miniscript, Terminal};
|
||||
@ -198,7 +200,7 @@ impl<Ctx: ScriptContext + 'static> ExtScriptContext for Ctx {
|
||||
/// ```
|
||||
/// 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 {
|
||||
/// pubkey: PublicKey,
|
||||
@ -206,7 +208,10 @@ impl<Ctx: ScriptContext + 'static> ExtScriptContext for Ctx {
|
||||
///
|
||||
/// impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for MyKeyType {
|
||||
/// 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`]
|
||||
fn add_metadata(
|
||||
self,
|
||||
source: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
|
||||
origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
|
||||
derivation_path: bip32::DerivationPath,
|
||||
) -> Result<DescriptorKey<Ctx>, KeyError>;
|
||||
}
|
||||
@ -294,11 +299,11 @@ pub trait DerivableKey<Ctx: ScriptContext> {
|
||||
impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPubKey {
|
||||
fn add_metadata(
|
||||
self,
|
||||
source: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
|
||||
origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
|
||||
derivation_path: bip32::DerivationPath,
|
||||
) -> Result<DescriptorKey<Ctx>, KeyError> {
|
||||
DescriptorPublicKey::XPub(DescriptorXKey {
|
||||
source,
|
||||
origin,
|
||||
xkey: self,
|
||||
derivation_path,
|
||||
is_wildcard: true,
|
||||
@ -310,11 +315,11 @@ impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPubKey {
|
||||
impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPrivKey {
|
||||
fn add_metadata(
|
||||
self,
|
||||
source: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
|
||||
origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
|
||||
derivation_path: bip32::DerivationPath,
|
||||
) -> Result<DescriptorKey<Ctx>, KeyError> {
|
||||
DescriptorSecretKey::XPrv(DescriptorXKey {
|
||||
source,
|
||||
origin,
|
||||
xkey: self,
|
||||
derivation_path,
|
||||
is_wildcard: true,
|
||||
@ -355,10 +360,10 @@ where
|
||||
{
|
||||
fn add_metadata(
|
||||
self,
|
||||
source: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
|
||||
origin: Option<(bip32::Fingerprint, bip32::DerivationPath)>,
|
||||
derivation_path: bip32::DerivationPath,
|
||||
) -> 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))
|
||||
}
|
||||
}
|
||||
@ -483,7 +488,7 @@ impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorKey<Ctx> {
|
||||
impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorPublicKey {
|
||||
fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
|
||||
let networks = match self {
|
||||
DescriptorPublicKey::PubKey(_) => any_network(),
|
||||
DescriptorPublicKey::SinglePub(_) => any_network(),
|
||||
DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. })
|
||||
if xkey.network == Network::Bitcoin =>
|
||||
{
|
||||
@ -498,14 +503,20 @@ impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorPublicKey {
|
||||
|
||||
impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PublicKey {
|
||||
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 {
|
||||
fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
|
||||
let networks = match self {
|
||||
DescriptorSecretKey::PrivKey(sk) if sk.network == Network::Bitcoin => mainnet_network(),
|
||||
let networks = match &self {
|
||||
DescriptorSecretKey::SinglePriv(sk) if sk.key.network == Network::Bitcoin => {
|
||||
mainnet_network()
|
||||
}
|
||||
DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. })
|
||||
if xkey.network == Network::Bitcoin =>
|
||||
{
|
||||
@ -520,7 +531,11 @@ impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorSecretKey {
|
||||
|
||||
impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PrivateKey {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ use bitcoin::util::bip32::ChildNumber;
|
||||
use bitcoin::util::psbt::PartiallySignedTransaction as PSBT;
|
||||
use bitcoin::{Address, Network, OutPoint, Script, SigHashType, Transaction, TxOut, Txid};
|
||||
|
||||
use miniscript::descriptor::DescriptorPublicKey;
|
||||
use miniscript::psbt::PsbtInputSatisfier;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace};
|
||||
@ -87,8 +87,8 @@ pub struct Wallet<B: BlockchainMarker, D: BatchDatabase> {
|
||||
descriptor: ExtendedDescriptor,
|
||||
change_descriptor: Option<ExtendedDescriptor>,
|
||||
|
||||
signers: Arc<SignersContainer<DescriptorPublicKey>>,
|
||||
change_signers: Arc<SignersContainer<DescriptorPublicKey>>,
|
||||
signers: Arc<SignersContainer>,
|
||||
change_signers: Arc<SignersContainer>,
|
||||
|
||||
address_validators: Vec<Arc<Box<dyn AddressValidator>>>,
|
||||
|
||||
@ -158,7 +158,7 @@ where
|
||||
let index = self.fetch_and_increment_index(ScriptType::External)?;
|
||||
|
||||
self.descriptor
|
||||
.derive(&[ChildNumber::from_normal_idx(index).unwrap()])
|
||||
.derive(ChildNumber::from_normal_idx(index)?)
|
||||
.address(self.network)
|
||||
.ok_or(Error::ScriptDoesntHaveAddressForm)
|
||||
}
|
||||
@ -204,7 +204,7 @@ where
|
||||
pub fn add_signer(
|
||||
&mut self,
|
||||
script_type: ScriptType,
|
||||
id: SignerId<DescriptorPublicKey>,
|
||||
id: SignerId,
|
||||
ordering: SignerOrdering,
|
||||
signer: Arc<Box<dyn Signer>>,
|
||||
) {
|
||||
@ -803,7 +803,7 @@ where
|
||||
match desc.satisfy(
|
||||
input,
|
||||
(
|
||||
psbt_input.clone(),
|
||||
PsbtInputSatisfier::new(&psbt, n),
|
||||
After::new(current_height, false),
|
||||
Older::new(current_height, create_height, false),
|
||||
),
|
||||
@ -846,7 +846,7 @@ where
|
||||
.borrow()
|
||||
.get_path_from_script_pubkey(&txout.script_pubkey)?
|
||||
.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> {
|
||||
@ -854,7 +854,7 @@ where
|
||||
let index = self.fetch_and_increment_index(script_type)?;
|
||||
|
||||
Ok(desc
|
||||
.derive(&[ChildNumber::from_normal_idx(index).unwrap()])
|
||||
.derive(ChildNumber::from_normal_idx(index)?)
|
||||
.script_pubkey())
|
||||
}
|
||||
|
||||
@ -879,7 +879,7 @@ where
|
||||
|
||||
let hd_keypaths = descriptor.get_hd_keypaths(index)?;
|
||||
let script = descriptor
|
||||
.derive(&[ChildNumber::from_normal_idx(index).unwrap()])
|
||||
.derive(ChildNumber::from_normal_idx(index)?)
|
||||
.script_pubkey();
|
||||
for validator in &self.address_validators {
|
||||
validator.validate(script_type, &hd_keypaths, &script)?;
|
||||
@ -909,7 +909,7 @@ where
|
||||
for i in from..(from + count) {
|
||||
address_batch.set_script_pubkey(
|
||||
&descriptor
|
||||
.derive(&[ChildNumber::from_normal_idx(i).unwrap()])
|
||||
.derive(ChildNumber::from_normal_idx(i)?)
|
||||
.script_pubkey(),
|
||||
script_type,
|
||||
i,
|
||||
@ -1004,7 +1004,7 @@ where
|
||||
|
||||
let (desc, _) = self.get_descriptor_for_script_type(script_type);
|
||||
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.witness_script = derived_descriptor.psbt_witness_script();
|
||||
|
@ -102,7 +102,7 @@ use bitcoin::util::bip32::{ExtendedPrivKey, Fingerprint};
|
||||
use bitcoin::util::{bip143, psbt};
|
||||
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 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
|
||||
/// multiple of them
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum SignerId<Pk: MiniscriptKey> {
|
||||
PkHash(<Pk as MiniscriptKey>::Hash),
|
||||
pub enum SignerId {
|
||||
PkHash(hash160::Hash),
|
||||
Fingerprint(Fingerprint),
|
||||
}
|
||||
|
||||
impl From<hash160::Hash> for SignerId<DescriptorPublicKey> {
|
||||
fn from(hash: hash160::Hash) -> SignerId<DescriptorPublicKey> {
|
||||
impl From<hash160::Hash> for SignerId {
|
||||
fn from(hash: hash160::Hash) -> SignerId {
|
||||
SignerId::PkHash(hash)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Fingerprint> for SignerId<DescriptorPublicKey> {
|
||||
fn from(fing: Fingerprint) -> SignerId<DescriptorPublicKey> {
|
||||
impl From<Fingerprint> for SignerId {
|
||||
fn from(fing: Fingerprint) -> SignerId {
|
||||
SignerId::Fingerprint(fing)
|
||||
}
|
||||
}
|
||||
@ -284,7 +284,10 @@ impl Signer for PrivateKey {
|
||||
}
|
||||
|
||||
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)]
|
||||
struct SignersContainerKey<Pk: MiniscriptKey> {
|
||||
id: SignerId<Pk>,
|
||||
struct SignersContainerKey {
|
||||
id: SignerId,
|
||||
ordering: SignerOrdering,
|
||||
}
|
||||
|
||||
impl<Pk: MiniscriptKey> From<(SignerId<Pk>, SignerOrdering)> for SignersContainerKey<Pk> {
|
||||
fn from(tuple: (SignerId<Pk>, SignerOrdering)) -> Self {
|
||||
impl From<(SignerId, SignerOrdering)> for SignersContainerKey {
|
||||
fn from(tuple: (SignerId, SignerOrdering)) -> Self {
|
||||
SignersContainerKey {
|
||||
id: tuple.0,
|
||||
ordering: tuple.1,
|
||||
@ -319,11 +322,9 @@ impl<Pk: MiniscriptKey> From<(SignerId<Pk>, SignerOrdering)> for SignersContaine
|
||||
|
||||
/// Container for multiple signers
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct SignersContainer<Pk: MiniscriptKey>(
|
||||
BTreeMap<SignersContainerKey<Pk>, Arc<Box<dyn Signer>>>,
|
||||
);
|
||||
pub struct SignersContainer(BTreeMap<SignersContainerKey, Arc<Box<dyn Signer>>>);
|
||||
|
||||
impl SignersContainer<DescriptorPublicKey> {
|
||||
impl SignersContainer {
|
||||
pub fn as_key_map(&self) -> KeyMap {
|
||||
self.0
|
||||
.values()
|
||||
@ -333,20 +334,21 @@ impl SignersContainer<DescriptorPublicKey> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyMap> for SignersContainer<DescriptorPublicKey> {
|
||||
fn from(keymap: KeyMap) -> SignersContainer<DescriptorPublicKey> {
|
||||
impl From<KeyMap> for SignersContainer {
|
||||
fn from(keymap: KeyMap) -> SignersContainer {
|
||||
let mut container = SignersContainer::new();
|
||||
|
||||
for (_, secret) in keymap {
|
||||
match secret {
|
||||
DescriptorSecretKey::PrivKey(private_key) => container.add_external(
|
||||
DescriptorSecretKey::SinglePriv(private_key) => container.add_external(
|
||||
SignerId::from(
|
||||
private_key
|
||||
.key
|
||||
.public_key(&Secp256k1::signing_only())
|
||||
.to_pubkeyhash(),
|
||||
),
|
||||
SignerOrdering::default(),
|
||||
Arc::new(Box::new(private_key)),
|
||||
Arc::new(Box::new(private_key.key)),
|
||||
),
|
||||
DescriptorSecretKey::XPrv(xprv) => container.add_external(
|
||||
SignerId::from(xprv.root_fingerprint()),
|
||||
@ -360,7 +362,7 @@ impl From<KeyMap> for SignersContainer<DescriptorPublicKey> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Pk: MiniscriptKey> SignersContainer<Pk> {
|
||||
impl SignersContainer {
|
||||
/// Default constructor
|
||||
pub fn new() -> Self {
|
||||
SignersContainer(Default::default())
|
||||
@ -370,7 +372,7 @@ impl<Pk: MiniscriptKey> SignersContainer<Pk> {
|
||||
/// signer that was previosuly in the container, if any
|
||||
pub fn add_external(
|
||||
&mut self,
|
||||
id: SignerId<Pk>,
|
||||
id: SignerId,
|
||||
ordering: SignerOrdering,
|
||||
signer: 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
|
||||
pub fn remove(
|
||||
&mut self,
|
||||
id: SignerId<Pk>,
|
||||
id: SignerId,
|
||||
ordering: SignerOrdering,
|
||||
) -> Option<Arc<Box<dyn Signer>>> {
|
||||
self.0.remove(&(id, ordering).into())
|
||||
}
|
||||
|
||||
/// 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
|
||||
.keys()
|
||||
.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.
|
||||
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
|
||||
.range((
|
||||
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> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Pk: MiniscriptKey> Ord for SignersContainerKey<Pk> {
|
||||
impl Ord for SignersContainerKey {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.ordering.cmp(&other.ordering)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Pk: MiniscriptKey> PartialEq for SignersContainerKey<Pk> {
|
||||
impl PartialEq for SignersContainerKey {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.ordering == other.ordering
|
||||
}
|
||||
}
|
||||
|
||||
impl<Pk: MiniscriptKey> Eq for SignersContainerKey<Pk> {}
|
||||
impl Eq for SignersContainerKey {}
|
||||
|
@ -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
|
||||
/// 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
|
||||
}
|
||||
@ -316,7 +316,7 @@ impl TxOrdering {
|
||||
///
|
||||
/// Has a default value of `1`
|
||||
#[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 {
|
||||
fn default() -> Self {
|
||||
|
@ -9,17 +9,11 @@ name = "testutils"
|
||||
|
||||
# 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]
|
||||
log = "0.4.8"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serial_test = "0.4"
|
||||
bitcoin = "0.23"
|
||||
bitcoincore-rpc = "0.11"
|
||||
electrum-client = "0.2.0-beta.1"
|
||||
bitcoin = "0.25"
|
||||
bitcoincore-rpc = "0.12"
|
||||
electrum-client = "0.3.0-beta.1"
|
||||
|
@ -119,13 +119,13 @@ macro_rules! testutils {
|
||||
use miniscript::descriptor::{Descriptor, DescriptorPublicKey};
|
||||
|
||||
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 ) => ({
|
||||
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;
|
||||
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) });
|
||||
( @i $descriptors:expr, $child:expr ) => ({ testutils!(@internal $descriptors, $child) });
|
||||
@ -386,7 +386,7 @@ impl TestClient {
|
||||
trace!("getblocktemplate: {:#?}", block_template);
|
||||
|
||||
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(
|
||||
block_template["previousblockhash"].as_str().unwrap(),
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user