diff --git a/src/blockchain/compact_filters/mod.rs b/src/blockchain/compact_filters/mod.rs index b7ee67e1..89c2f4d9 100644 --- a/src/blockchain/compact_filters/mod.rs +++ b/src/blockchain/compact_filters/mod.rs @@ -37,6 +37,8 @@ //! 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. //! +//! This is an **EXPERIMENTAL** feature, API and other major changes are expected. +//! //! ## Example //! //! ```no_run diff --git a/src/descriptor/error.rs b/src/descriptor/error.rs index 151487da..e470fea9 100644 --- a/src/descriptor/error.rs +++ b/src/descriptor/error.rs @@ -35,9 +35,9 @@ pub enum Error { InvalidHDKeyPath, //KeyParsingError(String), - #[allow(missing_docs)] + /// Error thrown while working with [`keys`](crate::keys) Key(crate::keys::KeyError), - #[allow(missing_docs)] + /// Error while extracting and manipulating policies Policy(crate::descriptor::policy::PolicyError), //InputIndexDoesntExist, @@ -47,15 +47,15 @@ pub enum Error { InvalidDescriptorCharacter(char), //CantDeriveWithMiniscript, - #[allow(missing_docs)] + /// BIP32 error BIP32(bitcoin::util::bip32::Error), - #[allow(missing_docs)] + /// Error during base58 decoding Base58(bitcoin::util::base58::Error), - #[allow(missing_docs)] + /// Key-related error PK(bitcoin::util::key::Error), - #[allow(missing_docs)] + /// Miniscript error Miniscript(miniscript::Error), - #[allow(missing_docs)] + /// Hex decoding error Hex(bitcoin::hashes::hex::Error), } diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 1fad0bae..83870135 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -44,9 +44,7 @@ pub use miniscript::{ pub mod checksum; mod dsl; pub mod error; -#[allow(missing_docs)] // TODO add missing docs and remove this allow pub mod policy; -#[allow(missing_docs)] // TODO add missing docs and remove this allow pub mod template; pub use self::checksum::get_checksum; @@ -67,9 +65,9 @@ pub type ExtendedDescriptor = Descriptor; /// [`psbt::Output`]: bitcoin::util::psbt::Output pub type HDKeyPaths = BTreeMap; -#[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`] pub trait ToWalletDescriptor { + /// Convert to wallet descriptor fn to_wallet_descriptor( self, 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`] pub trait ExtractPolicy { + /// Extract the spending [`policy`] fn extract_policy( &self, signers: &SignersContainer, diff --git a/src/descriptor/policy.rs b/src/descriptor/policy.rs index 252f2b18..a2085fe6 100644 --- a/src/descriptor/policy.rs +++ b/src/descriptor/policy.rs @@ -27,6 +27,8 @@ //! This module implements the logic to extract and represent the spending policies of a descriptor //! in a more human-readable format. //! +//! This is an **EXPERIMENTAL** feature, API and other major changes are expected. +//! //! ## 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)] #[serde(tag = "type", rename_all = "UPPERCASE")] pub enum SatisfiableItem { // Leaves + /// Signature for a raw public key Signature(PKOrF), + /// Signature for an extended key fingerprint SignatureKey(PKOrF), + /// SHA256 preimage hash SHA256Preimage { + /// The digest value hash: sha256::Hash, }, + /// Double SHA256 preimage hash HASH256Preimage { + /// The digest value hash: sha256d::Hash, }, + /// RIPEMD160 preimage hash RIPEMD160Preimage { + /// The digest value hash: ripemd160::Hash, }, + /// SHA256 then RIPEMD160 preimage hash HASH160Preimage { + /// The digest value hash: hash160::Hash, }, + /// Absolute timeclock timestamp AbsoluteTimelock { + /// The timestamp value value: u32, }, + /// Relative timelock locktime RelativeTimelock { + /// The locktime value value: u32, }, + /// Multi-signature public keys with threshold count + Multisig { + /// The raw public key or extended key fingerprint + keys: Vec, + /// The required threshold count + threshold: usize, + }, // Complex item + /// Threshold items with threshold count Thresh { + /// The policy items items: Vec, - threshold: usize, - }, - Multisig { - keys: Vec, + /// The required threshold count threshold: usize, }, } impl SatisfiableItem { + /// Returns whether the [`SatisfiableItem`] is a leaf item pub fn is_leaf(&self) -> bool { !matches!(self, SatisfiableItem::Thresh { @@ -149,6 +172,7 @@ impl SatisfiableItem { }) } + /// Returns a unique id for the [`SatisfiableItem`] pub fn id(&self) -> String { get_checksum(&serde_json::to_string(self).expect("Failed to serialize a SatisfiableItem")) .expect("Failed to compute a SatisfiableItem id") @@ -213,7 +237,9 @@ fn mix(vec: Vec>) -> Vec> { answer } +/// Type for a map of sets of [`Condition`] items keyed by each set's index pub type ConditionMap = BTreeMap>; +/// Type for a map of folded sets of [`Condition`] items keyed by a vector of the combined set's indexes pub type FoldedConditionMap = BTreeMap, HashSet>; fn serialize_folded_cond_map( @@ -279,6 +305,7 @@ pub enum Satisfaction { } impl Satisfaction { + /// Returns whether the [`Satisfaction`] is a leaf item pub fn is_leaf(&self) -> bool { match self { 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 .flatten() // .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)| { ( key, @@ -426,8 +453,10 @@ pub struct Policy { /// 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)] pub struct Condition { + /// Optional CheckSequenceVerify condition #[serde(skip_serializing_if = "Option::is_none")] pub csv: Option, + /// Optional timelock condition #[serde(skip_serializing_if = "Option::is_none")] pub timelock: Option, } @@ -459,6 +488,7 @@ impl Condition { Ok(self) } + /// Returns `true` if there are no extra conditions to verify pub fn is_null(&self) -> bool { self.csv.is_none() && self.timelock.is_none() } @@ -467,12 +497,19 @@ impl Condition { /// Errors that can happen while extracting and manipulating policies #[derive(Debug)] pub enum PolicyError { + /// Not enough items are selected to satisfy a [`SatisfiableItem::Thresh`] NotEnoughItemsSelected(String), + /// Too many items are selected to satisfy a [`SatisfiableItem::Thresh`] TooManyItemsSelected(String), + /// Index out of range for an item to satisfy a [`SatisfiableItem::Thresh`] IndexOutOfRange(usize), + /// Can not add to an item that is [`Satisfaction::None`] or [`Satisfaction::Complete`] AddOnLeaf, + /// Can not add to an item that is [`Satisfaction::PartialComplete`] AddOnPartialComplete, + /// Can not merge CSV or timelock values unless both are less than or both are equal or greater than 500_000_000 MixedTimelockUnits, + /// Incompatible conditions (not currently used) IncompatibleConditions, } diff --git a/src/descriptor/template.rs b/src/descriptor/template.rs index 9dbbf153..48609c19 100644 --- a/src/descriptor/template.rs +++ b/src/descriptor/template.rs @@ -60,6 +60,7 @@ pub type DescriptorTemplateOut = (ExtendedDescriptor, KeyMap, ValidNetworks); /// } /// ``` pub trait DescriptorTemplate { + /// Build the complete descriptor fn build(self) -> Result; }