Skip to content

Commit 54479e6

Browse files
committed
Merge rust-bitcoin/rust-bitcoin#1007: Implement TryFrom
b29ff9b Rename SchnorrSighashType::from_u8 -> from_consensus_u8 (Tobin C. Harding) af16286 Implement TryFrom sha256::Hash for TaprootMerkleBranch (Tobin C. Harding) 6b7b440 Implement TryFrom<Key> for ProprietaryKey (Tobin C. Harding) 5c49fe7 Implement TryFrom<TaprootBuilder> for TapTree (Tobin C. Harding) 632a5db Implement TryFrom for WitnessVersion (Tobin C. Harding) Pull request description: Audit the whole codebase checking for any method that is of the form `from_foo` where foo is not an interesting identifier (like 'consensus' and 'standard'). Implement `TryFrom` for any such methods, deprecating the original. Done as separate patches so any can be easily dropped if not liked. ACKs for top commit: apoelstra: ACK b29ff9b Kixunil: ACK b29ff9b Tree-SHA512: 40f1d96b505891080df1f7a9b3507979b0279a9e0f9d7cd32598bdc16c866785e6b13d5cb1face5ba50e3bc8484a5cd9c7f430d7abc86db9609962476dacd467
2 parents af29d51 + ac58e6e commit 54479e6

File tree

10 files changed

+224
-75
lines changed

10 files changed

+224
-75
lines changed

src/blockdata/script.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::consensus::encode::MAX_VEC_SIZE;
2727
use crate::prelude::*;
2828

2929
use crate::io;
30+
use core::convert::TryFrom;
3031
use core::{fmt, default::Default};
3132
use core::ops::Index;
3233

@@ -498,7 +499,7 @@ impl Script {
498499
/// Returns witness version of the script, if any, assuming the script is a `scriptPubkey`.
499500
#[inline]
500501
pub fn witness_version(&self) -> Option<WitnessVersion> {
501-
self.0.get(0).and_then(|opcode| WitnessVersion::from_opcode(opcodes::All::from(*opcode)).ok())
502+
self.0.get(0).and_then(|opcode| WitnessVersion::try_from(opcodes::All::from(*opcode)).ok())
502503
}
503504

504505
/// Checks whether a script pubkey is a P2SH output.
@@ -550,7 +551,7 @@ impl Script {
550551
}
551552
let ver_opcode = opcodes::All::from(self.0[0]); // Version 0 or PUSHNUM_1-PUSHNUM_16
552553
let push_opbyte = self.0[1]; // Second byte push opcode 2-40 bytes
553-
WitnessVersion::from_opcode(ver_opcode).is_ok()
554+
WitnessVersion::try_from(ver_opcode).is_ok()
554555
&& push_opbyte >= opcodes::all::OP_PUSHBYTES_2.to_u8()
555556
&& push_opbyte <= opcodes::all::OP_PUSHBYTES_40.to_u8()
556557
// Check that the rest of the script has the correct size

src/util/address.rs

Lines changed: 110 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
3535
use crate::prelude::*;
3636

37+
use core::convert::TryFrom;
3738
use core::fmt;
3839
use core::num::ParseIntError;
3940
use core::str::FromStr;
@@ -243,8 +244,8 @@ impl FromStr for WitnessVersion {
243244
type Err = Error;
244245

245246
fn from_str(s: &str) -> Result<Self, Self::Err> {
246-
let version = s.parse().map_err(Error::UnparsableWitnessVersion)?;
247-
WitnessVersion::from_num(version)
247+
let version: u8 = s.parse().map_err(Error::UnparsableWitnessVersion)?;
248+
WitnessVersion::try_from(version)
248249
}
249250
}
250251

@@ -258,8 +259,9 @@ impl WitnessVersion {
258259
/// # Errors
259260
/// If the integer does not correspond to any witness version, errors with
260261
/// [`Error::InvalidWitnessVersion`].
262+
#[deprecated(since = "0.29.0", note = "use try_from instead")]
261263
pub fn from_u5(value: ::bech32::u5) -> Result<Self, Error> {
262-
WitnessVersion::from_num(value.to_u8())
264+
Self::try_from(value)
263265
}
264266

265267
/// Converts an 8-bit unsigned integer value into [`WitnessVersion`] variant.
@@ -270,27 +272,9 @@ impl WitnessVersion {
270272
/// # Errors
271273
/// If the integer does not correspond to any witness version, errors with
272274
/// [`Error::InvalidWitnessVersion`].
275+
#[deprecated(since = "0.29.0", note = "use try_from instead")]
273276
pub fn from_num(no: u8) -> Result<Self, Error> {
274-
Ok(match no {
275-
0 => WitnessVersion::V0,
276-
1 => WitnessVersion::V1,
277-
2 => WitnessVersion::V2,
278-
3 => WitnessVersion::V3,
279-
4 => WitnessVersion::V4,
280-
5 => WitnessVersion::V5,
281-
6 => WitnessVersion::V6,
282-
7 => WitnessVersion::V7,
283-
8 => WitnessVersion::V8,
284-
9 => WitnessVersion::V9,
285-
10 => WitnessVersion::V10,
286-
11 => WitnessVersion::V11,
287-
12 => WitnessVersion::V12,
288-
13 => WitnessVersion::V13,
289-
14 => WitnessVersion::V14,
290-
15 => WitnessVersion::V15,
291-
16 => WitnessVersion::V16,
292-
wrong => return Err(Error::InvalidWitnessVersion(wrong)),
293-
})
277+
Self::try_from(no)
294278
}
295279

296280
/// Converts bitcoin script opcode into [`WitnessVersion`] variant.
@@ -301,13 +285,9 @@ impl WitnessVersion {
301285
/// # Errors
302286
/// If the opcode does not correspond to any witness version, errors with
303287
/// [`Error::MalformedWitnessVersion`].
288+
#[deprecated(since = "0.29.0", note = "use try_from instead")]
304289
pub fn from_opcode(opcode: opcodes::All) -> Result<Self, Error> {
305-
match opcode.to_u8() {
306-
0 => Ok(WitnessVersion::V0),
307-
version if version >= opcodes::all::OP_PUSHNUM_1.to_u8() && version <= opcodes::all::OP_PUSHNUM_16.to_u8() =>
308-
WitnessVersion::from_num(version - opcodes::all::OP_PUSHNUM_1.to_u8() + 1),
309-
_ => Err(Error::MalformedWitnessVersion)
310-
}
290+
Self::try_from(opcode)
311291
}
312292

313293
/// Converts bitcoin script [`Instruction`] (parsed opcode) into [`WitnessVersion`] variant.
@@ -319,12 +299,9 @@ impl WitnessVersion {
319299
/// # Errors
320300
/// If the opcode does not correspond to any witness version, errors with
321301
/// [`Error::MalformedWitnessVersion`] for the rest of opcodes.
302+
#[deprecated(since = "0.29.0", note = "use try_from instead")]
322303
pub fn from_instruction(instruction: Instruction) -> Result<Self, Error> {
323-
match instruction {
324-
Instruction::Op(op) => WitnessVersion::from_opcode(op),
325-
Instruction::PushBytes(bytes) if bytes.is_empty() => Ok(WitnessVersion::V0),
326-
Instruction::PushBytes(_) => Err(Error::MalformedWitnessVersion),
327-
}
304+
Self::try_from(instruction)
328305
}
329306

330307
/// Returns integer version number representation for a given [`WitnessVersion`] value.
@@ -355,6 +332,102 @@ impl WitnessVersion {
355332
}
356333
}
357334

335+
impl TryFrom<bech32::u5> for WitnessVersion {
336+
type Error = Error;
337+
338+
/// Converts 5-bit unsigned integer value matching single symbol from Bech32(m) address encoding
339+
/// ([`bech32::u5`]) into [`WitnessVersion`] variant.
340+
///
341+
/// # Returns
342+
/// Version of the Witness program.
343+
///
344+
/// # Errors
345+
/// If the integer does not correspond to any witness version, errors with
346+
/// [`Error::InvalidWitnessVersion`].
347+
fn try_from(value: bech32::u5) -> Result<Self, Self::Error> {
348+
Self::try_from(value.to_u8())
349+
}
350+
}
351+
352+
impl TryFrom<u8> for WitnessVersion {
353+
type Error = Error;
354+
355+
/// Converts an 8-bit unsigned integer value into [`WitnessVersion`] variant.
356+
///
357+
/// # Returns
358+
/// Version of the Witness program.
359+
///
360+
/// # Errors
361+
/// If the integer does not correspond to any witness version, errors with
362+
/// [`Error::InvalidWitnessVersion`].
363+
fn try_from(no: u8) -> Result<Self, Self::Error> {
364+
use WitnessVersion::*;
365+
366+
Ok(match no {
367+
0 => V0,
368+
1 => V1,
369+
2 => V2,
370+
3 => V3,
371+
4 => V4,
372+
5 => V5,
373+
6 => V6,
374+
7 => V7,
375+
8 => V8,
376+
9 => V9,
377+
10 => V10,
378+
11 => V11,
379+
12 => V12,
380+
13 => V13,
381+
14 => V14,
382+
15 => V15,
383+
16 => V16,
384+
wrong => return Err(Error::InvalidWitnessVersion(wrong)),
385+
})
386+
}
387+
}
388+
389+
impl TryFrom<opcodes::All> for WitnessVersion {
390+
type Error = Error;
391+
392+
/// Converts bitcoin script opcode into [`WitnessVersion`] variant.
393+
///
394+
/// # Returns
395+
/// Version of the Witness program (for opcodes in range of `OP_0`..`OP_16`).
396+
///
397+
/// # Errors
398+
/// If the opcode does not correspond to any witness version, errors with
399+
/// [`Error::MalformedWitnessVersion`].
400+
fn try_from(opcode: opcodes::All) -> Result<Self, Self::Error> {
401+
match opcode.to_u8() {
402+
0 => Ok(WitnessVersion::V0),
403+
version if version >= opcodes::all::OP_PUSHNUM_1.to_u8() && version <= opcodes::all::OP_PUSHNUM_16.to_u8() =>
404+
WitnessVersion::try_from(version - opcodes::all::OP_PUSHNUM_1.to_u8() + 1),
405+
_ => Err(Error::MalformedWitnessVersion)
406+
}
407+
}
408+
}
409+
410+
impl<'a> TryFrom<Instruction<'a>> for WitnessVersion {
411+
type Error = Error;
412+
413+
/// Converts bitcoin script [`Instruction`] (parsed opcode) into [`WitnessVersion`] variant.
414+
///
415+
/// # Returns
416+
/// Version of the Witness program for [`Instruction::Op`] and [`Instruction::PushBytes`] with
417+
/// byte value within `1..=16` range.
418+
///
419+
/// # Errors
420+
/// If the opcode does not correspond to any witness version, errors with
421+
/// [`Error::MalformedWitnessVersion`] for the rest of opcodes.
422+
fn try_from(instruction: Instruction) -> Result<Self, Self::Error> {
423+
match instruction {
424+
Instruction::Op(op) => WitnessVersion::try_from(op),
425+
Instruction::PushBytes(bytes) if bytes.is_empty() => Ok(WitnessVersion::V0),
426+
Instruction::PushBytes(_) => Err(Error::MalformedWitnessVersion),
427+
}
428+
}
429+
}
430+
358431
impl From<WitnessVersion> for ::bech32::u5 {
359432
/// Converts [`WitnessVersion`] instance into corresponding Bech32(m) u5-value ([`bech32::u5`]).
360433
fn from(version: WitnessVersion) -> Self {
@@ -405,7 +478,7 @@ impl Payload {
405478
}
406479

407480
Payload::WitnessProgram {
408-
version: WitnessVersion::from_opcode(opcodes::All::from(script[0]))?,
481+
version: WitnessVersion::try_from(opcodes::All::from(script[0]))?,
409482
program: script[2..].to_vec(),
410483
}
411484
} else {
@@ -856,7 +929,7 @@ impl FromStr for Address {
856929
// Get the script version and program (converted from 5-bit to 8-bit)
857930
let (version, program): (WitnessVersion, Vec<u8>) = {
858931
let (v, p5) = payload.split_at(1);
859-
(WitnessVersion::from_u5(v[0])?, bech32::FromBase32::from_base32(p5)?)
932+
(WitnessVersion::try_from(v[0])?, bech32::FromBase32::from_base32(p5)?)
860933
};
861934

862935
if program.len() < 2 || program.len() > 40 {
@@ -1277,7 +1350,7 @@ mod tests {
12771350
];
12781351
let segwit_payload = (0..=16).map(|version| {
12791352
Payload::WitnessProgram {
1280-
version: WitnessVersion::from_num(version).unwrap(),
1353+
version: WitnessVersion::try_from(version).unwrap(),
12811354
program: vec![]
12821355
}
12831356
}).collect::<Vec<_>>();

src/util/psbt/map/global.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
1313
//
1414

15+
use core::convert::TryFrom;
16+
1517
use crate::prelude::*;
1618

1719
use crate::io::{self, Cursor, Read};
@@ -191,7 +193,7 @@ impl PartiallySignedTransaction {
191193
return Err(Error::InvalidKey(pair.key).into())
192194
}
193195
}
194-
PSBT_GLOBAL_PROPRIETARY => match proprietary.entry(raw::ProprietaryKey::from_key(pair.key.clone())?) {
196+
PSBT_GLOBAL_PROPRIETARY => match proprietary.entry(raw::ProprietaryKey::try_from(pair.key.clone())?) {
195197
btree_map::Entry::Vacant(empty_key) => {
196198
empty_key.insert(pair.value);
197199
},

src/util/psbt/map/input.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::prelude::*;
1616
use crate::io;
1717
use core::fmt;
1818
use core::str::FromStr;
19+
use core::convert::TryFrom;
1920

2021
use secp256k1;
2122
use crate::blockdata::script::Script;
@@ -215,7 +216,7 @@ impl PsbtSighashType {
215216
if self.inner > 0xffu32 {
216217
Err(sighash::Error::InvalidSighashType(self.inner))
217218
} else {
218-
SchnorrSighashType::from_u8(self.inner as u8)
219+
SchnorrSighashType::from_consensus_u8(self.inner as u8)
219220
}
220221
}
221222

@@ -356,7 +357,7 @@ impl Input {
356357
}
357358
}
358359
PSBT_IN_PROPRIETARY => {
359-
let key = raw::ProprietaryKey::from_key(raw_key.clone())?;
360+
let key = raw::ProprietaryKey::try_from(raw_key.clone())?;
360361
match self.proprietary.entry(key) {
361362
btree_map::Entry::Vacant(empty_key) => {
362363
empty_key.insert(raw_value);

src/util/psbt/map/output.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
use crate::prelude::*;
1616
use core;
17+
use core::convert::TryFrom;
1718

1819
use crate::io;
1920

@@ -158,16 +159,12 @@ impl TapTree {
158159
/// # Returns
159160
/// A [`TapTree`] iff the `builder` is complete, otherwise return [`IncompleteTapTree`]
160161
/// error with the content of incomplete `builder` instance.
162+
#[deprecated(since = "0.29.0", note = "use try_from instead")]
161163
pub fn from_builder(builder: TaprootBuilder) -> Result<Self, IncompleteTapTree> {
162-
if !builder.is_finalized() {
163-
Err(IncompleteTapTree::NotFinalized(builder))
164-
} else if builder.has_hidden_nodes() {
165-
Err(IncompleteTapTree::HiddenParts(builder))
166-
} else {
167-
Ok(TapTree(builder))
168-
}
164+
Self::try_from(builder)
169165
}
170166

167+
171168
/// Converts self into builder [`TaprootBuilder`]. The builder is guaranteed to be finalized.
172169
pub fn into_builder(self) -> TaprootBuilder {
173170
self.0
@@ -194,6 +191,25 @@ impl TapTree {
194191
}
195192
}
196193

194+
impl TryFrom<TaprootBuilder> for TapTree {
195+
type Error = IncompleteTapTree;
196+
197+
/// Constructs [`TapTree`] from a [`TaprootBuilder`] if it is complete binary tree.
198+
///
199+
/// # Returns
200+
/// A [`TapTree`] iff the `builder` is complete, otherwise return [`IncompleteTapTree`]
201+
/// error with the content of incomplete `builder` instance.
202+
fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> {
203+
if !builder.is_finalized() {
204+
Err(IncompleteTapTree::NotFinalized(builder))
205+
} else if builder.has_hidden_nodes() {
206+
Err(IncompleteTapTree::HiddenParts(builder))
207+
} else {
208+
Ok(TapTree(builder))
209+
}
210+
}
211+
}
212+
197213
/// Iterator for a taproot script tree, operating in DFS order over leaf depth and
198214
/// leaf script pairs.
199215
pub struct TapTreeIter<'tree> {
@@ -233,7 +249,7 @@ impl Output {
233249
}
234250
}
235251
PSBT_OUT_PROPRIETARY => {
236-
let key = raw::ProprietaryKey::from_key(raw_key.clone())?;
252+
let key = raw::ProprietaryKey::try_from(raw_key.clone())?;
237253
match self.proprietary.entry(key) {
238254
btree_map::Entry::Vacant(empty_key) => {
239255
empty_key.insert(raw_value);

src/util/psbt/raw.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
2121
use crate::prelude::*;
2222
use core::fmt;
23+
use core::convert::TryFrom;
2324

2425
use crate::io;
2526
use crate::consensus::encode::{self, ReadExt, WriteExt, Decodable, Encodable, VarInt, serialize, deserialize, MAX_VEC_SIZE};
@@ -160,12 +161,9 @@ impl<Subtype> Decodable for ProprietaryKey<Subtype> where Subtype: Copy + From<u
160161
impl<Subtype> ProprietaryKey<Subtype> where Subtype: Copy + From<u8> + Into<u8> {
161162
/// Constructs [ProprietaryKey] from [Key]; returns
162163
/// [Error::InvalidProprietaryKey] if `key` do not starts with 0xFC byte
164+
#[deprecated(since = "0.29.0", note = "use try_from instead")]
163165
pub fn from_key(key: Key) -> Result<Self, Error> {
164-
if key.type_value != 0xFC {
165-
return Err(Error::InvalidProprietaryKey)
166-
}
167-
168-
Ok(deserialize(&key.key)?)
166+
Self::try_from(key)
169167
}
170168

171169
/// Constructs full [Key] corresponding to this proprietary key type
@@ -176,3 +174,21 @@ impl<Subtype> ProprietaryKey<Subtype> where Subtype: Copy + From<u8> + Into<u8>
176174
}
177175
}
178176
}
177+
178+
impl<Subtype> TryFrom<Key> for ProprietaryKey<Subtype>
179+
where
180+
Subtype:Copy + From<u8> + Into<u8> {
181+
type Error = Error;
182+
183+
/// Constructs a [`ProprietaryKey`] from a [`Key`].
184+
///
185+
/// # Errors
186+
/// Returns [`Error::InvalidProprietaryKey`] if `key` does not start with `0xFC` byte.
187+
fn try_from(key: Key) -> Result<Self, Self::Error> {
188+
if key.type_value != 0xFC {
189+
return Err(Error::InvalidProprietaryKey)
190+
}
191+
192+
Ok(deserialize(&key.key)?)
193+
}
194+
}

0 commit comments

Comments
 (0)