Skip to content

Commit e340ad8

Browse files
committed
Change options to result for various APIs
1 parent 95811b2 commit e340ad8

File tree

7 files changed

+66
-43
lines changed

7 files changed

+66
-43
lines changed

src/descriptor/bare.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@ where
111111
Ok(())
112112
}
113113

114-
fn address(&self, _network: bitcoin::Network) -> Option<bitcoin::Address>
114+
fn address(&self, _network: bitcoin::Network) -> Result<bitcoin::Address, Error>
115115
where
116116
Pk: ToPublicKey,
117117
{
118-
None
118+
Err(Error::BareDescriptorAddr)
119119
}
120120

121121
fn script_pubkey(&self) -> Script
@@ -150,9 +150,9 @@ where
150150
Ok((witness, script_sig))
151151
}
152152

153-
fn max_satisfaction_weight(&self) -> Option<usize> {
153+
fn max_satisfaction_weight(&self) -> Result<usize, Error> {
154154
let scriptsig_len = self.ms.max_satisfaction_size()?;
155-
Some(4 * (varint_len(scriptsig_len) + scriptsig_len))
155+
Ok(4 * (varint_len(scriptsig_len) + scriptsig_len))
156156
}
157157

158158
fn script_code(&self) -> Script
@@ -267,11 +267,11 @@ where
267267
Ok(())
268268
}
269269

270-
fn address(&self, network: bitcoin::Network) -> Option<bitcoin::Address>
270+
fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error>
271271
where
272272
Pk: ToPublicKey,
273273
{
274-
Some(bitcoin::Address::p2pkh(&self.pk.to_public_key(), network))
274+
Ok(bitcoin::Address::p2pkh(&self.pk.to_public_key(), network))
275275
}
276276

277277
fn script_pubkey(&self) -> Script
@@ -315,8 +315,8 @@ where
315315
}
316316
}
317317

318-
fn max_satisfaction_weight(&self) -> Option<usize> {
319-
Some(4 * (1 + 73 + self.pk.serialized_len()))
318+
fn max_satisfaction_weight(&self) -> Result<usize, Error> {
319+
Ok(4 * (1 + 73 + self.pk.serialized_len()))
320320
}
321321

322322
fn script_code(&self) -> Script

src/descriptor/mod.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ pub trait DescriptorTrait<Pk: MiniscriptKey> {
8181
fn sanity_check(&self) -> Result<(), Error>;
8282

8383
/// Computes the Bitcoin address of the descriptor, if one exists
84-
fn address(&self, network: bitcoin::Network) -> Option<bitcoin::Address>
84+
/// Some descriptors like pk() don't have any address.
85+
fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error>
8586
where
8687
Pk: ToPublicKey;
8788

@@ -137,7 +138,8 @@ pub trait DescriptorTrait<Pk: MiniscriptKey> {
137138
/// transaction. Assumes all signatures are 73 bytes, including push opcode
138139
/// and sighash suffix. Includes the weight of the VarInts encoding the
139140
/// scriptSig and witness stack length.
140-
fn max_satisfaction_weight(&self) -> Option<usize>;
141+
/// Returns Error when the descriptor is impossible to safisfy (ex: sh(OP_FALSE))
142+
fn max_satisfaction_weight(&self) -> Result<usize, Error>;
141143

142144
/// Get the `scriptCode` of a transaction output.
143145
///
@@ -308,7 +310,7 @@ where
308310
}
309311
}
310312
/// Computes the Bitcoin address of the descriptor, if one exists
311-
fn address(&self, network: bitcoin::Network) -> Option<bitcoin::Address>
313+
fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error>
312314
where
313315
Pk: ToPublicKey,
314316
{
@@ -394,7 +396,7 @@ where
394396
/// transaction. Assumes all signatures are 73 bytes, including push opcode
395397
/// and sighash suffix. Includes the weight of the VarInts encoding the
396398
/// scriptSig and witness stack length.
397-
fn max_satisfaction_weight(&self) -> Option<usize> {
399+
fn max_satisfaction_weight(&self) -> Result<usize, Error> {
398400
match *self {
399401
Descriptor::Bare(ref bare) => bare.max_satisfaction_weight(),
400402
Descriptor::Pkh(ref pkh) => pkh.max_satisfaction_weight(),
@@ -668,7 +670,12 @@ mod tests {
668670
"512102000000000000000000000000000000000000000000000000000000000000000251ae"
669671
)
670672
);
671-
assert_eq!(bare.address(bitcoin::Network::Bitcoin,), None);
673+
assert_eq!(
674+
bare.address(bitcoin::Network::Bitcoin)
675+
.unwrap_err()
676+
.to_string(),
677+
"Bare descriptors don't have address"
678+
);
672679

673680
let pk = StdDescriptor::from_str(TEST_PK).unwrap();
674681
assert_eq!(

src/descriptor/segwitv0.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,13 @@ where
154154
Ok(())
155155
}
156156

157-
fn address(&self, network: bitcoin::Network) -> Option<bitcoin::Address>
157+
fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error>
158158
where
159159
Pk: ToPublicKey,
160160
{
161161
match self.inner {
162-
WshInner::SortedMulti(ref smv) => Some(bitcoin::Address::p2wsh(&smv.encode(), network)),
163-
WshInner::Ms(ref ms) => Some(bitcoin::Address::p2wsh(&ms.encode(), network)),
162+
WshInner::SortedMulti(ref smv) => Ok(bitcoin::Address::p2wsh(&smv.encode(), network)),
163+
WshInner::Ms(ref ms) => Ok(bitcoin::Address::p2wsh(&ms.encode(), network)),
164164
}
165165
}
166166

@@ -202,7 +202,7 @@ where
202202
Ok((witness, script_sig))
203203
}
204204

205-
fn max_satisfaction_weight(&self) -> Option<usize> {
205+
fn max_satisfaction_weight(&self) -> Result<usize, Error> {
206206
let (script_size, max_sat_elems, max_sat_size) = match self.inner {
207207
WshInner::SortedMulti(ref smv) => (
208208
smv.script_size(),
@@ -215,13 +215,11 @@ where
215215
ms.max_satisfaction_size()?,
216216
),
217217
};
218-
Some(
219-
4 + // scriptSig length byte
218+
Ok(4 + // scriptSig length byte
220219
varint_len(script_size) +
221220
script_size +
222221
varint_len(max_sat_elems) +
223-
max_sat_size,
224-
)
222+
max_sat_size)
225223
}
226224

227225
fn script_code(&self) -> Script
@@ -348,11 +346,12 @@ where
348346
}
349347
}
350348

351-
fn address(&self, network: bitcoin::Network) -> Option<bitcoin::Address>
349+
fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error>
352350
where
353351
Pk: ToPublicKey,
354352
{
355-
bitcoin::Address::p2wpkh(&self.pk.to_public_key(), network).ok()
353+
Ok(bitcoin::Address::p2wpkh(&self.pk.to_public_key(), network)
354+
.expect("Rust Miniscript types don't allow uncompressed pks in segwit descriptors"))
356355
}
357356

358357
fn script_pubkey(&self) -> Script
@@ -394,8 +393,8 @@ where
394393
}
395394
}
396395

397-
fn max_satisfaction_weight(&self) -> Option<usize> {
398-
Some(4 + 1 + 73 + self.pk.serialized_len())
396+
fn max_satisfaction_weight(&self) -> Result<usize, Error> {
397+
Ok(4 + 1 + 73 + self.pk.serialized_len())
399398
}
400399

401400
fn script_code(&self) -> Script

src/descriptor/sh.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,15 @@ where
196196
Ok(())
197197
}
198198

199-
fn address(&self, network: bitcoin::Network) -> Option<bitcoin::Address>
199+
fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error>
200200
where
201201
Pk: ToPublicKey,
202202
{
203203
match self.inner {
204-
ShInner::Wsh(ref wsh) => Some(bitcoin::Address::p2sh(&wsh.script_pubkey(), network)),
205-
ShInner::Wpkh(ref wpkh) => Some(bitcoin::Address::p2sh(&wpkh.script_pubkey(), network)),
206-
ShInner::SortedMulti(ref smv) => Some(bitcoin::Address::p2sh(&smv.encode(), network)),
207-
ShInner::Ms(ref ms) => Some(bitcoin::Address::p2sh(&ms.encode(), network)),
204+
ShInner::Wsh(ref wsh) => Ok(bitcoin::Address::p2sh(&wsh.script_pubkey(), network)),
205+
ShInner::Wpkh(ref wpkh) => Ok(bitcoin::Address::p2sh(&wpkh.script_pubkey(), network)),
206+
ShInner::SortedMulti(ref smv) => Ok(bitcoin::Address::p2sh(&smv.encode(), network)),
207+
ShInner::Ms(ref ms) => Ok(bitcoin::Address::p2sh(&ms.encode(), network)),
208208
}
209209
}
210210

@@ -285,8 +285,8 @@ where
285285
}
286286
}
287287

288-
fn max_satisfaction_weight(&self) -> Option<usize> {
289-
Some(match self.inner {
288+
fn max_satisfaction_weight(&self) -> Result<usize, Error> {
289+
Ok(match self.inner {
290290
// add weighted script sig, len byte stays the same
291291
ShInner::Wsh(ref wsh) => 4 * 35 + wsh.max_satisfaction_weight()?,
292292
ShInner::SortedMulti(ref smv) => {

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,10 @@ pub enum Error {
481481
NonStandardBareScript,
482482
/// Analysis Error
483483
AnalysisError(miniscript::analyzable::AnalysisError),
484+
/// Miniscript is equivalent to false. No possible satisfaction
485+
ImpossibleSatisfaction,
486+
/// Bare descriptors don't have any addresses
487+
BareDescriptorAddr,
484488
}
485489

486490
#[doc(hidden)]
@@ -600,6 +604,8 @@ impl fmt::Display for Error {
600604
"
601605
),
602606
Error::AnalysisError(ref e) => e.fmt(f),
607+
Error::ImpossibleSatisfaction => write!(f, "Impossible to satisfy Miniscript"),
608+
Error::BareDescriptorAddr => write!(f, "Bare descriptors don't have address"),
603609
}
604610
}
605611
}

src/miniscript/context.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ pub enum ScriptContextError {
5151
MaxRedeemScriptSizeExceeded,
5252
/// The policy rules of bitcoin core only permit Script size upto 1650 bytes
5353
MaxScriptSigSizeExceeded,
54+
/// Impossible to satisfy the miniscript under the current context
55+
ImpossibleSatisfaction,
5456
}
5557

5658
impl fmt::Display for ScriptContextError {
@@ -89,6 +91,12 @@ impl fmt::Display for ScriptContextError {
8991
"At least one satisfaction in Miniscript would be larger than \
9092
MAX_SCRIPTSIG_SIZE scriptsig"
9193
),
94+
ScriptContextError::ImpossibleSatisfaction => {
95+
write!(
96+
f,
97+
"Impossible to satisfy Miniscript under the current context"
98+
)
99+
}
92100
}
93101
}
94102
}
@@ -293,8 +301,8 @@ impl ScriptContext for Legacy {
293301
// on P2SH size, it is not possible to reach the 1000 elements limit and hence
294302
// we do not check it.
295303
match ms.max_satisfaction_size() {
296-
None => Err(ScriptContextError::MaxScriptSigSizeExceeded),
297-
Some(size) if size > MAX_SCRIPTSIG_SIZE => {
304+
Err(_e) => Err(ScriptContextError::ImpossibleSatisfaction),
305+
Ok(size) if size > MAX_SCRIPTSIG_SIZE => {
298306
Err(ScriptContextError::MaxScriptSigSizeExceeded)
299307
}
300308
_ => Ok(()),
@@ -375,8 +383,9 @@ impl ScriptContext for Segwitv0 {
375383
// other Segwitv0 defined programs all require (much) less than 100 elements.
376384
// The witness script item is accounted for in max_satisfaction_witness_elements().
377385
match ms.max_satisfaction_witness_elements() {
378-
None => Err(ScriptContextError::MaxWitnessItemssExceeded),
379-
Some(max_witness_items) if max_witness_items > MAX_STANDARD_P2WSH_STACK_ITEMS => {
386+
// No possible satisfactions
387+
Err(_e) => Err(ScriptContextError::ImpossibleSatisfaction),
388+
Ok(max_witness_items) if max_witness_items > MAX_STANDARD_P2WSH_STACK_ITEMS => {
380389
Err(ScriptContextError::MaxWitnessItemssExceeded)
381390
}
382391
_ => Ok(()),

src/miniscript/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,13 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
206206
/// the weight of the `VarInt` that specifies this number in a serialized
207207
/// transaction.
208208
///
209-
/// This function may return None on malformed `Miniscript` objects which do
210-
/// not correspond to semantically sane Scripts. (Such scripts should be
211-
/// rejected at parse time. Any exceptions are bugs.)
212-
pub fn max_satisfaction_witness_elements(&self) -> Option<usize> {
213-
self.ext.stack_elem_count_sat.map(|x| x + 1)
209+
/// This function may returns Error when the Miniscript is
210+
/// impossible to satisfy
211+
pub fn max_satisfaction_witness_elements(&self) -> Result<usize, Error> {
212+
self.ext
213+
.stack_elem_count_sat
214+
.map(|x| x + 1)
215+
.ok_or(Error::ImpossibleSatisfaction)
214216
}
215217

216218
/// Maximum size, in bytes, of a satisfying witness. For Segwit outputs
@@ -225,8 +227,8 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
225227
/// All signatures are assumed to be 73 bytes in size, including the
226228
/// length prefix (segwit) or push opcode (pre-segwit) and sighash
227229
/// postfix.
228-
pub fn max_satisfaction_size(&self) -> Option<usize> {
229-
Ctx::max_satisfaction_size(self)
230+
pub fn max_satisfaction_size(&self) -> Result<usize, Error> {
231+
Ctx::max_satisfaction_size(self).ok_or(Error::ImpossibleSatisfaction)
230232
}
231233
}
232234

0 commit comments

Comments
 (0)