Merge commit 'refs/pull/221/head' of github.com:bitcoindevkit/bdk

This commit is contained in:
Alekos Filini 2020-12-14 11:27:51 +01:00
commit c83cec3777
No known key found for this signature in database
GPG Key ID: 5E8AFC3034FDFA4F
5 changed files with 55 additions and 17 deletions

View File

@ -37,6 +37,8 @@
//! connecting to a single peer at a time, optionally by opening multiple connections if it's //! connecting to a single peer at a time, optionally by opening multiple connections if it's
//! desirable to use multiple threads at once to sync in parallel. //! desirable to use multiple threads at once to sync in parallel.
//! //!
//! This is an **EXPERIMENTAL** feature, API and other major changes are expected.
//!
//! ## Example //! ## Example
//! //!
//! ```no_run //! ```no_run

View File

@ -35,9 +35,9 @@ pub enum Error {
InvalidHDKeyPath, InvalidHDKeyPath,
//KeyParsingError(String), //KeyParsingError(String),
#[allow(missing_docs)] /// Error thrown while working with [`keys`](crate::keys)
Key(crate::keys::KeyError), Key(crate::keys::KeyError),
#[allow(missing_docs)] /// Error while extracting and manipulating policies
Policy(crate::descriptor::policy::PolicyError), Policy(crate::descriptor::policy::PolicyError),
//InputIndexDoesntExist, //InputIndexDoesntExist,
@ -47,15 +47,15 @@ pub enum Error {
InvalidDescriptorCharacter(char), InvalidDescriptorCharacter(char),
//CantDeriveWithMiniscript, //CantDeriveWithMiniscript,
#[allow(missing_docs)] /// BIP32 error
BIP32(bitcoin::util::bip32::Error), BIP32(bitcoin::util::bip32::Error),
#[allow(missing_docs)] /// Error during base58 decoding
Base58(bitcoin::util::base58::Error), Base58(bitcoin::util::base58::Error),
#[allow(missing_docs)] /// Key-related error
PK(bitcoin::util::key::Error), PK(bitcoin::util::key::Error),
#[allow(missing_docs)] /// Miniscript error
Miniscript(miniscript::Error), Miniscript(miniscript::Error),
#[allow(missing_docs)] /// Hex decoding error
Hex(bitcoin::hashes::hex::Error), Hex(bitcoin::hashes::hex::Error),
} }

View File

@ -44,9 +44,7 @@ pub use miniscript::{
pub mod checksum; pub mod checksum;
mod dsl; mod dsl;
pub mod error; pub mod error;
#[allow(missing_docs)] // TODO add missing docs and remove this allow
pub mod policy; pub mod policy;
#[allow(missing_docs)] // TODO add missing docs and remove this allow
pub mod template; pub mod template;
pub use self::checksum::get_checksum; pub use self::checksum::get_checksum;
@ -67,9 +65,9 @@ pub type ExtendedDescriptor = Descriptor<DescriptorPublicKey>;
/// [`psbt::Output`]: bitcoin::util::psbt::Output /// [`psbt::Output`]: bitcoin::util::psbt::Output
pub type HDKeyPaths = BTreeMap<PublicKey, KeySource>; pub type HDKeyPaths = BTreeMap<PublicKey, KeySource>;
#[allow(missing_docs)] // TODO add missing docs and remove this allow
/// Trait for types which can be converted into an [`ExtendedDescriptor`] and a [`KeyMap`] usable by a wallet in a specific [`Network`] /// Trait for types which can be converted into an [`ExtendedDescriptor`] and a [`KeyMap`] usable by a wallet in a specific [`Network`]
pub trait ToWalletDescriptor { pub trait ToWalletDescriptor {
/// Convert to wallet descriptor
fn to_wallet_descriptor( fn to_wallet_descriptor(
self, self,
network: Network, network: Network,
@ -189,9 +187,9 @@ impl ToWalletDescriptor for DescriptorTemplateOut {
} }
} }
#[allow(missing_docs)] // TODO add missing docs and remove this allow
/// 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 {
/// Extract the spending [`policy`]
fn extract_policy( fn extract_policy(
&self, &self,
signers: &SignersContainer, signers: &SignersContainer,

View File

@ -27,6 +27,8 @@
//! This module implements the logic to extract and represent the spending policies of a descriptor //! This module implements the logic to extract and represent the spending policies of a descriptor
//! in a more human-readable format. //! in a more human-readable format.
//! //!
//! This is an **EXPERIMENTAL** feature, API and other major changes are expected.
//!
//! ## Example //! ## Example
//! //!
//! ``` //! ```
@ -103,44 +105,65 @@ impl PKOrF {
} }
} }
/// An item that need to be satisfied /// An item that needs to be satisfied
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", rename_all = "UPPERCASE")] #[serde(tag = "type", rename_all = "UPPERCASE")]
pub enum SatisfiableItem { pub enum SatisfiableItem {
// Leaves // Leaves
/// Signature for a raw public key
Signature(PKOrF), Signature(PKOrF),
/// Signature for an extended key fingerprint
SignatureKey(PKOrF), SignatureKey(PKOrF),
/// SHA256 preimage hash
SHA256Preimage { SHA256Preimage {
/// The digest value
hash: sha256::Hash, hash: sha256::Hash,
}, },
/// Double SHA256 preimage hash
HASH256Preimage { HASH256Preimage {
/// The digest value
hash: sha256d::Hash, hash: sha256d::Hash,
}, },
/// RIPEMD160 preimage hash
RIPEMD160Preimage { RIPEMD160Preimage {
/// The digest value
hash: ripemd160::Hash, hash: ripemd160::Hash,
}, },
/// SHA256 then RIPEMD160 preimage hash
HASH160Preimage { HASH160Preimage {
/// The digest value
hash: hash160::Hash, hash: hash160::Hash,
}, },
/// Absolute timeclock timestamp
AbsoluteTimelock { AbsoluteTimelock {
/// The timestamp value
value: u32, value: u32,
}, },
/// Relative timelock locktime
RelativeTimelock { RelativeTimelock {
/// The locktime value
value: u32, value: u32,
}, },
/// Multi-signature public keys with threshold count
Multisig {
/// The raw public key or extended key fingerprint
keys: Vec<PKOrF>,
/// The required threshold count
threshold: usize,
},
// Complex item // Complex item
/// Threshold items with threshold count
Thresh { Thresh {
/// The policy items
items: Vec<Policy>, items: Vec<Policy>,
threshold: usize, /// The required threshold count
},
Multisig {
keys: Vec<PKOrF>,
threshold: usize, threshold: usize,
}, },
} }
impl SatisfiableItem { impl SatisfiableItem {
/// Returns whether the [`SatisfiableItem`] is a leaf item
pub fn is_leaf(&self) -> bool { pub fn is_leaf(&self) -> bool {
!matches!(self, !matches!(self,
SatisfiableItem::Thresh { SatisfiableItem::Thresh {
@ -149,6 +172,7 @@ impl SatisfiableItem {
}) })
} }
/// Returns a unique id for the [`SatisfiableItem`]
pub fn id(&self) -> String { pub fn id(&self) -> String {
get_checksum(&serde_json::to_string(self).expect("Failed to serialize a SatisfiableItem")) get_checksum(&serde_json::to_string(self).expect("Failed to serialize a SatisfiableItem"))
.expect("Failed to compute a SatisfiableItem id") .expect("Failed to compute a SatisfiableItem id")
@ -213,7 +237,9 @@ fn mix<T: Clone>(vec: Vec<Vec<T>>) -> Vec<Vec<T>> {
answer answer
} }
/// Type for a map of sets of [`Condition`] items keyed by each set's index
pub type ConditionMap = BTreeMap<usize, HashSet<Condition>>; pub type ConditionMap = BTreeMap<usize, HashSet<Condition>>;
/// Type for a map of folded sets of [`Condition`] items keyed by a vector of the combined set's indexes
pub type FoldedConditionMap = BTreeMap<Vec<usize>, HashSet<Condition>>; pub type FoldedConditionMap = BTreeMap<Vec<usize>, HashSet<Condition>>;
fn serialize_folded_cond_map<S>( fn serialize_folded_cond_map<S>(
@ -279,6 +305,7 @@ pub enum Satisfaction {
} }
impl Satisfaction { impl Satisfaction {
/// Returns whether the [`Satisfaction`] is a leaf item
pub fn is_leaf(&self) -> bool { pub fn is_leaf(&self) -> bool {
match self { match self {
Satisfaction::None | Satisfaction::Complete { .. } => true, Satisfaction::None | Satisfaction::Complete { .. } => true,
@ -363,7 +390,7 @@ impl Satisfaction {
// since the previous step can turn one item of the iterator into multiple ones, we call flatten to expand them out // since the previous step can turn one item of the iterator into multiple ones, we call flatten to expand them out
.flatten() .flatten()
// .inspect(|x| println!("flat {:?}", x)) // .inspect(|x| println!("flat {:?}", x))
// try to fold all the conditions for this specific combination of indexes/options. if they are not compatibile, try_fold will be Err // try to fold all the conditions for this specific combination of indexes/options. if they are not compatible, try_fold will be Err
.map(|(key, val)| { .map(|(key, val)| {
( (
key, key,
@ -426,8 +453,10 @@ pub struct Policy {
/// An extra condition that must be satisfied but that is out of control of the user /// An extra condition that must be satisfied but that is out of control of the user
#[derive(Hash, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize)] #[derive(Hash, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize)]
pub struct Condition { pub struct Condition {
/// Optional CheckSequenceVerify condition
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub csv: Option<u32>, pub csv: Option<u32>,
/// Optional timelock condition
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub timelock: Option<u32>, pub timelock: Option<u32>,
} }
@ -459,6 +488,7 @@ impl Condition {
Ok(self) Ok(self)
} }
/// Returns `true` if there are no extra conditions to verify
pub fn is_null(&self) -> bool { pub fn is_null(&self) -> bool {
self.csv.is_none() && self.timelock.is_none() self.csv.is_none() && self.timelock.is_none()
} }
@ -467,12 +497,19 @@ impl Condition {
/// Errors that can happen while extracting and manipulating policies /// Errors that can happen while extracting and manipulating policies
#[derive(Debug)] #[derive(Debug)]
pub enum PolicyError { pub enum PolicyError {
/// Not enough items are selected to satisfy a [`SatisfiableItem::Thresh`]
NotEnoughItemsSelected(String), NotEnoughItemsSelected(String),
/// Too many items are selected to satisfy a [`SatisfiableItem::Thresh`]
TooManyItemsSelected(String), TooManyItemsSelected(String),
/// Index out of range for an item to satisfy a [`SatisfiableItem::Thresh`]
IndexOutOfRange(usize), IndexOutOfRange(usize),
/// Can not add to an item that is [`Satisfaction::None`] or [`Satisfaction::Complete`]
AddOnLeaf, AddOnLeaf,
/// Can not add to an item that is [`Satisfaction::PartialComplete`]
AddOnPartialComplete, AddOnPartialComplete,
/// Can not merge CSV or timelock values unless both are less than or both are equal or greater than 500_000_000
MixedTimelockUnits, MixedTimelockUnits,
/// Incompatible conditions (not currently used)
IncompatibleConditions, IncompatibleConditions,
} }

View File

@ -60,6 +60,7 @@ pub type DescriptorTemplateOut = (ExtendedDescriptor, KeyMap, ValidNetworks);
/// } /// }
/// ``` /// ```
pub trait DescriptorTemplate { pub trait DescriptorTemplate {
/// Build the complete descriptor
fn build(self) -> Result<DescriptorTemplateOut, KeyError>; fn build(self) -> Result<DescriptorTemplateOut, KeyError>;
} }