|
24 | 24 | //! |
25 | 25 |
|
26 | 26 | use std::collections::HashMap; |
27 | | -use std::fmt; |
28 | 27 | use std::{ |
| 28 | + fmt, |
29 | 29 | marker::PhantomData, |
30 | 30 | str::{self, FromStr}, |
31 | 31 | }; |
@@ -66,6 +66,166 @@ pub use self::key::{ |
66 | 66 | /// public key from the descriptor. |
67 | 67 | pub type KeyMap = HashMap<DescriptorPublicKey, DescriptorSecretKey>; |
68 | 68 |
|
| 69 | +/// A general trait for Bitcoin descriptor. |
| 70 | +/// Offers function for witness cost estimation, script pubkey creation |
| 71 | +/// satisfaction using the [Satisfier] trait. |
| 72 | +// Unfortunately, the translation function cannot be added to trait |
| 73 | +// because of traits cannot know underlying generic of Self. |
| 74 | +// Thus, we must implement additional trait for translate function |
| 75 | +pub trait DescriptorTrait<Pk: MiniscriptKey> { |
| 76 | + /// Whether the descriptor is safe |
| 77 | + /// Checks whether all the spend paths in the descriptor are possible |
| 78 | + /// on the bitcoin network under the current standardness and consensus rules |
| 79 | + /// Also checks whether the descriptor requires signauture on all spend paths |
| 80 | + /// And whether the script is malleable. |
| 81 | + /// In general, all the guarantees of miniscript hold only for safe scripts. |
| 82 | + /// All the analysis guarantees of miniscript only hold safe scripts. |
| 83 | + /// The signer may not be able to find satisfactions even if one exists |
| 84 | + fn sanity_check(&self) -> Result<(), Error>; |
| 85 | + |
| 86 | + /// Computes the Bitcoin address of the descriptor, if one exists |
| 87 | + /// `to_pk_ctx` denotes the ToPkCtx required for deriving bitcoin::PublicKey |
| 88 | + /// from MiniscriptKey using [ToPublicKey]. |
| 89 | + /// If MiniscriptKey is already is [bitcoin::PublicKey], then the context |
| 90 | + /// would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey] |
| 91 | + /// |
| 92 | + /// In general, this is defined by generic for the trait [trait.ToPublicKey] |
| 93 | + fn address<ToPkCtx: Copy>( |
| 94 | + &self, |
| 95 | + to_pk_ctx: ToPkCtx, |
| 96 | + network: bitcoin::Network, |
| 97 | + ) -> Option<bitcoin::Address> |
| 98 | + where |
| 99 | + Pk: ToPublicKey<ToPkCtx>; |
| 100 | + |
| 101 | + /// Computes the scriptpubkey of the descriptor |
| 102 | + /// `to_pk_ctx` denotes the ToPkCtx required for deriving bitcoin::PublicKey |
| 103 | + /// from MiniscriptKey using [ToPublicKey]. |
| 104 | + /// If MiniscriptKey is already is [bitcoin::PublicKey], then the context |
| 105 | + /// would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey] |
| 106 | + /// |
| 107 | + /// In general, this is defined by generic for the trait [ToPublicKey] |
| 108 | + fn script_pubkey<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 109 | + where |
| 110 | + Pk: ToPublicKey<ToPkCtx>; |
| 111 | + |
| 112 | + /// Computes the scriptSig that will be in place for an unsigned |
| 113 | + /// input spending an output with this descriptor. For pre-segwit |
| 114 | + /// descriptors, which use the scriptSig for signatures, this |
| 115 | + /// returns the empty script. |
| 116 | + /// |
| 117 | + /// This is used in Segwit transactions to produce an unsigned |
| 118 | + /// transaction whose txid will not change during signing (since |
| 119 | + /// only the witness data will change). |
| 120 | + /// `to_pk_ctx` denotes the ToPkCtx required for deriving bitcoin::PublicKey |
| 121 | + /// from MiniscriptKey using [ToPublicKey]. |
| 122 | + /// If MiniscriptKey is already is [bitcoin::PublicKey], then the context |
| 123 | + /// would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey] |
| 124 | + /// |
| 125 | + /// In general, this is defined by generic for the trait [ToPublicKey] |
| 126 | + fn unsigned_script_sig<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 127 | + where |
| 128 | + Pk: ToPublicKey<ToPkCtx>; |
| 129 | + |
| 130 | + /// Computes the "witness script" of the descriptor, i.e. the underlying |
| 131 | + /// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this |
| 132 | + /// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript; |
| 133 | + /// for the others it is the witness script. |
| 134 | + /// `to_pk_ctx` denotes the ToPkCtx required for deriving bitcoin::PublicKey |
| 135 | + /// from MiniscriptKey using [ToPublicKey]. |
| 136 | + /// If MiniscriptKey is already is [bitcoin::PublicKey], then the context |
| 137 | + /// would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey] |
| 138 | + /// |
| 139 | + /// In general, this is defined by generic for the trait [ToPublicKey] |
| 140 | + fn witness_script<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 141 | + where |
| 142 | + Pk: ToPublicKey<ToPkCtx>; |
| 143 | + |
| 144 | + /// Returns satisfying witness and scriptSig to spend an |
| 145 | + /// output controlled by the given descriptor if it possible to |
| 146 | + /// construct one using the satisfier S. |
| 147 | + /// `to_pk_ctx` denotes the ToPkCtx required for deriving bitcoin::PublicKey |
| 148 | + /// from MiniscriptKey using [ToPublicKey]. |
| 149 | + /// If MiniscriptKey is already is [bitcoin::PublicKey], then the context |
| 150 | + /// would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey] |
| 151 | + /// |
| 152 | + /// In general, this is defined by generic for the trait [ToPublicKey] |
| 153 | + fn get_satisfaction<ToPkCtx, S>( |
| 154 | + &self, |
| 155 | + satisfier: S, |
| 156 | + to_pk_ctx: ToPkCtx, |
| 157 | + ) -> Result<(Vec<Vec<u8>>, Script), Error> |
| 158 | + where |
| 159 | + ToPkCtx: Copy, |
| 160 | + Pk: ToPublicKey<ToPkCtx>, |
| 161 | + S: Satisfier<ToPkCtx, Pk>; |
| 162 | + |
| 163 | + /// Attempts to produce a satisfying witness and scriptSig to spend an |
| 164 | + /// output controlled by the given descriptor; add the data to a given |
| 165 | + /// `TxIn` output. |
| 166 | + fn satisfy<ToPkCtx, S>( |
| 167 | + &self, |
| 168 | + txin: &mut bitcoin::TxIn, |
| 169 | + satisfier: S, |
| 170 | + to_pk_ctx: ToPkCtx, |
| 171 | + ) -> Result<(), Error> |
| 172 | + where |
| 173 | + ToPkCtx: Copy, |
| 174 | + Pk: ToPublicKey<ToPkCtx>, |
| 175 | + S: Satisfier<ToPkCtx, Pk>, |
| 176 | + { |
| 177 | + // easy default implementation |
| 178 | + let (witness, script_sig) = self.get_satisfaction(satisfier, to_pk_ctx)?; |
| 179 | + txin.witness = witness; |
| 180 | + txin.script_sig = script_sig; |
| 181 | + Ok(()) |
| 182 | + } |
| 183 | + |
| 184 | + /// Computes an upper bound on the weight of a satisfying witness to the |
| 185 | + /// transaction. Assumes all signatures are 73 bytes, including push opcode |
| 186 | + /// and sighash suffix. Includes the weight of the VarInts encoding the |
| 187 | + /// scriptSig and witness stack length. |
| 188 | + fn max_satisfaction_weight<ToPkCtx: Copy>(&self) -> Option<usize> |
| 189 | + where |
| 190 | + Pk: ToPublicKey<ToPkCtx>; |
| 191 | + |
| 192 | + /// Get the `scriptCode` of a transaction output. |
| 193 | + /// |
| 194 | + /// The `scriptCode` is the Script of the previous transaction output being serialized in the |
| 195 | + /// sighash when evaluating a `CHECKSIG` & co. OP code. |
| 196 | + /// `to_pk_ctx` denotes the ToPkCtx required for deriving bitcoin::PublicKey |
| 197 | + /// from MiniscriptKey using [ToPublicKey]. |
| 198 | + /// If MiniscriptKey is already is [bitcoin::PublicKey], then the context |
| 199 | + /// would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey] |
| 200 | + /// |
| 201 | + /// In general, this is defined by generic for the trait [ToPublicKey] |
| 202 | + fn script_code<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 203 | + where |
| 204 | + Pk: ToPublicKey<ToPkCtx>; |
| 205 | +} |
| 206 | + |
| 207 | +/// Convert a descriptor using abstract keys to one using specific keys |
| 208 | +/// This will panic if translatefpk returns an uncompressed key when |
| 209 | +/// converting to a Segwit descriptor. To prevent this panic, ensure |
| 210 | +/// translatefpk returns an error in this case instead. |
| 211 | +pub trait PkTranslate<P: MiniscriptKey, Q: MiniscriptKey> { |
| 212 | + /// The associated output type. This must be Self<Q> |
| 213 | + type Output; |
| 214 | + |
| 215 | + /// Translate a struct from one Generic to another where the |
| 216 | + /// translation for Pk is provided by translatefpk, and translation for |
| 217 | + /// PkH is provided by translatefpkh |
| 218 | + fn translate_pk<Fpk, Fpkh, E>( |
| 219 | + &self, |
| 220 | + translatefpk: Fpk, |
| 221 | + translatefpkh: Fpkh, |
| 222 | + ) -> Result<Self::Output, E> |
| 223 | + where |
| 224 | + Fpk: FnMut(&P) -> Result<Q, E>, |
| 225 | + Fpkh: FnMut(&P::Hash) -> Result<Q::Hash, E>, |
| 226 | + Q: MiniscriptKey; |
| 227 | +} |
| 228 | + |
69 | 229 | /// Script descriptor |
70 | 230 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] |
71 | 231 | pub enum Descriptor<Pk: MiniscriptKey> { |
@@ -899,6 +1059,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> { |
899 | 1059 | .iter() |
900 | 1060 | .map(|sub| expression::terminal(sub, Pk::from_str)) |
901 | 1061 | .collect(); |
| 1062 | + |
902 | 1063 | pks.map(|pks| SortedMultiVec::new(k as usize, pks))? |
903 | 1064 | } |
904 | 1065 | } |
|
0 commit comments