Skip to content

Commit 251f499

Browse files
committed
Add descriptor trait
1 parent b13e187 commit 251f499

File tree

1 file changed

+162
-1
lines changed

1 file changed

+162
-1
lines changed

src/descriptor/mod.rs

Lines changed: 162 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
//!
2525
2626
use std::collections::HashMap;
27-
use std::fmt;
2827
use std::{
28+
fmt,
2929
marker::PhantomData,
3030
str::{self, FromStr},
3131
};
@@ -66,6 +66,166 @@ pub use self::key::{
6666
/// public key from the descriptor.
6767
pub type KeyMap = HashMap<DescriptorPublicKey, DescriptorSecretKey>;
6868

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+
69229
/// Script descriptor
70230
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
71231
pub enum Descriptor<Pk: MiniscriptKey> {
@@ -899,6 +1059,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
8991059
.iter()
9001060
.map(|sub| expression::terminal(sub, Pk::from_str))
9011061
.collect();
1062+
9021063
pks.map(|pks| SortedMultiVec::new(k as usize, pks))?
9031064
}
9041065
}

0 commit comments

Comments
 (0)