|
| 1 | +use std::{ |
| 2 | + fmt, |
| 3 | + str::{self, FromStr}, |
| 4 | +}; |
| 5 | + |
| 6 | +use bitcoin::{self, Script}; |
| 7 | + |
| 8 | +use super::{checksum::verify_checksum, Bare, Pkh, Sh, Wpkh, Wsh}; |
| 9 | +use {expression, DescriptorTrait, Error, MiniscriptKey, Satisfier, ToPublicKey}; |
| 10 | + |
| 11 | +/// Script descriptor |
| 12 | +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| 13 | +pub enum PreTaprootDescriptor<Pk: MiniscriptKey> { |
| 14 | + /// Bare descriptor |
| 15 | + Bare(Bare<Pk>), |
| 16 | + /// Pay-to-PubKey-Hash |
| 17 | + Pkh(Pkh<Pk>), |
| 18 | + /// Pay-to-Witness-PubKey-Hash |
| 19 | + Wpkh(Wpkh<Pk>), |
| 20 | + /// Pay-to-ScriptHash(includes nested wsh/wpkh/sorted multi) |
| 21 | + Sh(Sh<Pk>), |
| 22 | + /// Pay-to-Witness-ScriptHash with Segwitv0 context |
| 23 | + Wsh(Wsh<Pk>), |
| 24 | +} |
| 25 | + |
| 26 | +impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for PreTaprootDescriptor<Pk> { |
| 27 | + /// Whether the descriptor is safe |
| 28 | + /// Checks whether all the spend paths in the descriptor are possible |
| 29 | + /// on the bitcoin network under the current standardness and consensus rules |
| 30 | + /// Also checks whether the descriptor requires signauture on all spend paths |
| 31 | + /// And whether the script is malleable. |
| 32 | + /// In general, all the guarantees of miniscript hold only for safe scripts. |
| 33 | + /// All the analysis guarantees of miniscript only hold safe scripts. |
| 34 | + /// The signer may not be able to find satisfactions even if one exists |
| 35 | + fn sanity_check(&self) -> Result<(), Error> { |
| 36 | + match *self { |
| 37 | + PreTaprootDescriptor::Bare(ref bare) => bare.sanity_check(), |
| 38 | + PreTaprootDescriptor::Pkh(ref pkh) => pkh.sanity_check(), |
| 39 | + PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.sanity_check(), |
| 40 | + PreTaprootDescriptor::Wsh(ref wsh) => wsh.sanity_check(), |
| 41 | + PreTaprootDescriptor::Sh(ref sh) => sh.sanity_check(), |
| 42 | + } |
| 43 | + } |
| 44 | + /// Computes the Bitcoin address of the descriptor, if one exists |
| 45 | + fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error> |
| 46 | + where |
| 47 | + Pk: ToPublicKey, |
| 48 | + { |
| 49 | + match *self { |
| 50 | + PreTaprootDescriptor::Bare(ref bare) => bare.address(network), |
| 51 | + PreTaprootDescriptor::Pkh(ref pkh) => pkh.address(network), |
| 52 | + PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.address(network), |
| 53 | + PreTaprootDescriptor::Wsh(ref wsh) => wsh.address(network), |
| 54 | + PreTaprootDescriptor::Sh(ref sh) => sh.address(network), |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + /// Computes the scriptpubkey of the descriptor |
| 59 | + fn script_pubkey(&self) -> Script |
| 60 | + where |
| 61 | + Pk: ToPublicKey, |
| 62 | + { |
| 63 | + match *self { |
| 64 | + PreTaprootDescriptor::Bare(ref bare) => bare.script_pubkey(), |
| 65 | + PreTaprootDescriptor::Pkh(ref pkh) => pkh.script_pubkey(), |
| 66 | + PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.script_pubkey(), |
| 67 | + PreTaprootDescriptor::Wsh(ref wsh) => wsh.script_pubkey(), |
| 68 | + PreTaprootDescriptor::Sh(ref sh) => sh.script_pubkey(), |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + /// Computes the scriptSig that will be in place for an unsigned |
| 73 | + /// input spending an output with this descriptor. For pre-segwit |
| 74 | + /// descriptors, which use the scriptSig for signatures, this |
| 75 | + /// returns the empty script. |
| 76 | + /// |
| 77 | + /// This is used in Segwit transactions to produce an unsigned |
| 78 | + /// transaction whose txid will not change during signing (since |
| 79 | + /// only the witness data will change). |
| 80 | + fn unsigned_script_sig(&self) -> Script |
| 81 | + where |
| 82 | + Pk: ToPublicKey, |
| 83 | + { |
| 84 | + match *self { |
| 85 | + PreTaprootDescriptor::Bare(ref bare) => bare.unsigned_script_sig(), |
| 86 | + PreTaprootDescriptor::Pkh(ref pkh) => pkh.unsigned_script_sig(), |
| 87 | + PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.unsigned_script_sig(), |
| 88 | + PreTaprootDescriptor::Wsh(ref wsh) => wsh.unsigned_script_sig(), |
| 89 | + PreTaprootDescriptor::Sh(ref sh) => sh.unsigned_script_sig(), |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + /// Computes the "witness script" of the descriptor, i.e. the underlying |
| 94 | + /// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this |
| 95 | + /// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript; |
| 96 | + /// for the others it is the witness script. |
| 97 | + /// Errors: |
| 98 | + /// - When the descriptor is Tr |
| 99 | + fn explicit_script(&self) -> Result<Script, Error> |
| 100 | + where |
| 101 | + Pk: ToPublicKey, |
| 102 | + { |
| 103 | + match *self { |
| 104 | + PreTaprootDescriptor::Bare(ref bare) => bare.explicit_script(), |
| 105 | + PreTaprootDescriptor::Pkh(ref pkh) => pkh.explicit_script(), |
| 106 | + PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.explicit_script(), |
| 107 | + PreTaprootDescriptor::Wsh(ref wsh) => wsh.explicit_script(), |
| 108 | + PreTaprootDescriptor::Sh(ref sh) => sh.explicit_script(), |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + /// Returns satisfying non-malleable witness and scriptSig to spend an |
| 113 | + /// output controlled by the given descriptor if it possible to |
| 114 | + /// construct one using the satisfier S. |
| 115 | + fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error> |
| 116 | + where |
| 117 | + Pk: ToPublicKey, |
| 118 | + S: Satisfier<Pk>, |
| 119 | + { |
| 120 | + match *self { |
| 121 | + PreTaprootDescriptor::Bare(ref bare) => bare.get_satisfaction(satisfier), |
| 122 | + PreTaprootDescriptor::Pkh(ref pkh) => pkh.get_satisfaction(satisfier), |
| 123 | + PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.get_satisfaction(satisfier), |
| 124 | + PreTaprootDescriptor::Wsh(ref wsh) => wsh.get_satisfaction(satisfier), |
| 125 | + PreTaprootDescriptor::Sh(ref sh) => sh.get_satisfaction(satisfier), |
| 126 | + } |
| 127 | + } |
| 128 | + |
| 129 | + /// Returns a possilbly mallable satisfying non-malleable witness and scriptSig to spend an |
| 130 | + /// output controlled by the given descriptor if it possible to |
| 131 | + /// construct one using the satisfier S. |
| 132 | + fn get_satisfaction_mall<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error> |
| 133 | + where |
| 134 | + Pk: ToPublicKey, |
| 135 | + S: Satisfier<Pk>, |
| 136 | + { |
| 137 | + match *self { |
| 138 | + PreTaprootDescriptor::Bare(ref bare) => bare.get_satisfaction_mall(satisfier), |
| 139 | + PreTaprootDescriptor::Pkh(ref pkh) => pkh.get_satisfaction_mall(satisfier), |
| 140 | + PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.get_satisfaction_mall(satisfier), |
| 141 | + PreTaprootDescriptor::Wsh(ref wsh) => wsh.get_satisfaction_mall(satisfier), |
| 142 | + PreTaprootDescriptor::Sh(ref sh) => sh.get_satisfaction_mall(satisfier), |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + /// Computes an upper bound on the weight of a satisfying witness to the |
| 147 | + /// transaction. Assumes all signatures are 73 bytes, including push opcode |
| 148 | + /// and sighash suffix. Includes the weight of the VarInts encoding the |
| 149 | + /// scriptSig and witness stack length. |
| 150 | + fn max_satisfaction_weight(&self) -> Result<usize, Error> { |
| 151 | + match *self { |
| 152 | + PreTaprootDescriptor::Bare(ref bare) => bare.max_satisfaction_weight(), |
| 153 | + PreTaprootDescriptor::Pkh(ref pkh) => pkh.max_satisfaction_weight(), |
| 154 | + PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.max_satisfaction_weight(), |
| 155 | + PreTaprootDescriptor::Wsh(ref wsh) => wsh.max_satisfaction_weight(), |
| 156 | + PreTaprootDescriptor::Sh(ref sh) => sh.max_satisfaction_weight(), |
| 157 | + } |
| 158 | + } |
| 159 | + |
| 160 | + /// Get the `scriptCode` of a transaction output. |
| 161 | + /// |
| 162 | + /// The `scriptCode` is the Script of the previous transaction output being serialized in the |
| 163 | + /// sighash when evaluating a `CHECKSIG` & co. OP code. |
| 164 | + /// Returns Error for Tr descriptors |
| 165 | + fn script_code(&self) -> Result<Script, Error> |
| 166 | + where |
| 167 | + Pk: ToPublicKey, |
| 168 | + { |
| 169 | + match *self { |
| 170 | + PreTaprootDescriptor::Bare(ref bare) => bare.script_code(), |
| 171 | + PreTaprootDescriptor::Pkh(ref pkh) => pkh.script_code(), |
| 172 | + PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.script_code(), |
| 173 | + PreTaprootDescriptor::Wsh(ref wsh) => wsh.script_code(), |
| 174 | + PreTaprootDescriptor::Sh(ref sh) => sh.script_code(), |
| 175 | + } |
| 176 | + } |
| 177 | +} |
| 178 | + |
| 179 | +impl<Pk> expression::FromTree for PreTaprootDescriptor<Pk> |
| 180 | +where |
| 181 | + Pk: MiniscriptKey + str::FromStr, |
| 182 | + Pk::Hash: str::FromStr, |
| 183 | + <Pk as FromStr>::Err: ToString, |
| 184 | + <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString, |
| 185 | +{ |
| 186 | + /// Parse an expression tree into a descriptor |
| 187 | + fn from_tree(top: &expression::Tree) -> Result<PreTaprootDescriptor<Pk>, Error> { |
| 188 | + Ok(match (top.name, top.args.len() as u32) { |
| 189 | + ("pkh", 1) => PreTaprootDescriptor::Pkh(Pkh::from_tree(top)?), |
| 190 | + ("wpkh", 1) => PreTaprootDescriptor::Wpkh(Wpkh::from_tree(top)?), |
| 191 | + ("sh", 1) => PreTaprootDescriptor::Sh(Sh::from_tree(top)?), |
| 192 | + ("wsh", 1) => PreTaprootDescriptor::Wsh(Wsh::from_tree(top)?), |
| 193 | + _ => PreTaprootDescriptor::Bare(Bare::from_tree(top)?), |
| 194 | + }) |
| 195 | + } |
| 196 | +} |
| 197 | + |
| 198 | +impl<Pk> FromStr for PreTaprootDescriptor<Pk> |
| 199 | +where |
| 200 | + Pk: MiniscriptKey + str::FromStr, |
| 201 | + Pk::Hash: str::FromStr, |
| 202 | + <Pk as FromStr>::Err: ToString, |
| 203 | + <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString, |
| 204 | +{ |
| 205 | + type Err = Error; |
| 206 | + |
| 207 | + fn from_str(s: &str) -> Result<PreTaprootDescriptor<Pk>, Error> { |
| 208 | + let desc_str = verify_checksum(s)?; |
| 209 | + let top = expression::Tree::from_str(desc_str)?; |
| 210 | + expression::FromTree::from_tree(&top) |
| 211 | + } |
| 212 | +} |
| 213 | + |
| 214 | +impl<Pk: MiniscriptKey> fmt::Debug for PreTaprootDescriptor<Pk> { |
| 215 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 216 | + match *self { |
| 217 | + PreTaprootDescriptor::Bare(ref sub) => write!(f, "{:?}", sub), |
| 218 | + PreTaprootDescriptor::Pkh(ref pkh) => write!(f, "{:?}", pkh), |
| 219 | + PreTaprootDescriptor::Wpkh(ref wpkh) => write!(f, "{:?}", wpkh), |
| 220 | + PreTaprootDescriptor::Sh(ref sub) => write!(f, "{:?}", sub), |
| 221 | + PreTaprootDescriptor::Wsh(ref sub) => write!(f, "{:?}", sub), |
| 222 | + } |
| 223 | + } |
| 224 | +} |
| 225 | + |
| 226 | +impl<Pk: MiniscriptKey> fmt::Display for PreTaprootDescriptor<Pk> { |
| 227 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 228 | + match *self { |
| 229 | + PreTaprootDescriptor::Bare(ref sub) => write!(f, "{}", sub), |
| 230 | + PreTaprootDescriptor::Pkh(ref pkh) => write!(f, "{}", pkh), |
| 231 | + PreTaprootDescriptor::Wpkh(ref wpkh) => write!(f, "{}", wpkh), |
| 232 | + PreTaprootDescriptor::Sh(ref sub) => write!(f, "{}", sub), |
| 233 | + PreTaprootDescriptor::Wsh(ref sub) => write!(f, "{}", sub), |
| 234 | + } |
| 235 | + } |
| 236 | +} |
| 237 | + |
| 238 | +serde_string_impl_pk!(PreTaprootDescriptor, "a pre-taproot script descriptor"); |
| 239 | + |
| 240 | +// Have the trait in a separate module to avoid conflicts |
| 241 | +pub(crate) mod traits { |
| 242 | + use bitcoin::Script; |
| 243 | + |
| 244 | + use { |
| 245 | + descriptor::{Pkh, Sh, Wpkh, Wsh}, |
| 246 | + DescriptorTrait, MiniscriptKey, ToPublicKey, |
| 247 | + }; |
| 248 | + |
| 249 | + use super::PreTaprootDescriptor; |
| 250 | + |
| 251 | + /// A general trait for Pre taproot bitcoin descriptor. |
| 252 | + /// Similar to [`DescriptorTrait`], but `explicit_script` and `script_code` methods cannot fail |
| 253 | + pub trait PreTaprootDescriptorTrait<Pk: MiniscriptKey>: DescriptorTrait<Pk> { |
| 254 | + /// Same as [`DescriptorTrait::explicit_script`], but a non failing version. |
| 255 | + /// All PreTaproot descriptors have a unique explicit script |
| 256 | + fn explicit_script(&self) -> Script |
| 257 | + where |
| 258 | + Pk: ToPublicKey, |
| 259 | + { |
| 260 | + // This expect can technically be avoided if we implement this for types, but |
| 261 | + // having this expect saves lots of LoC because of default implementation |
| 262 | + <Self as DescriptorTrait<Pk>>::explicit_script(&self) |
| 263 | + .expect("Pre taproot descriptor have explicit script") |
| 264 | + } |
| 265 | + |
| 266 | + /// Same as [`DescriptorTrait::script_code`], but a non failing version. |
| 267 | + /// All PreTaproot descriptors have a script code |
| 268 | + fn script_code(&self) -> Script |
| 269 | + where |
| 270 | + Pk: ToPublicKey, |
| 271 | + { |
| 272 | + <Self as DescriptorTrait<Pk>>::script_code(&self) |
| 273 | + .expect("Pre taproot descriptor have non-failing script code") |
| 274 | + } |
| 275 | + } |
| 276 | + |
| 277 | + impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Pkh<Pk> {} |
| 278 | + |
| 279 | + impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Sh<Pk> {} |
| 280 | + |
| 281 | + impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Wpkh<Pk> {} |
| 282 | + |
| 283 | + impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Wsh<Pk> {} |
| 284 | + |
| 285 | + impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for PreTaprootDescriptor<Pk> {} |
| 286 | +} |
0 commit comments