Merge commit 'refs/pull/221/head' of github.com:bitcoindevkit/bdk
This commit is contained in:
commit
c83cec3777
@ -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
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user