Add the `FromScriptError` for handling errors in `address`

This commit adds the `FromScriptError` struct to handle the errors
while generating address from any script. It includes :
- Unrecognized script error.
- Witness Program error.
- Witness Version error.
This commit is contained in:
harshit933 2024-02-23 01:48:59 +05:30
parent 975ada3570
commit 05b24946eb
2 changed files with 49 additions and 5 deletions

View File

@ -73,6 +73,50 @@ impl From<witness_program::Error> for Error {
fn from(e: witness_program::Error) -> Error { Error::WitnessProgram(e) } fn from(e: witness_program::Error) -> Error { Error::WitnessProgram(e) }
} }
/// Error while generating address from script.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FromScriptError {
/// Script is not a p2pkh, p2sh or witness program.
UnrecognizedScript,
/// A witness program error.
WitnessProgram(witness_program::Error),
/// A witness version construction error.
WitnessVersion(witness_version::TryFromError),
}
impl fmt::Display for FromScriptError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use FromScriptError::*;
match *self {
WitnessVersion(ref e) => write_err!(f, "witness version construction error"; e),
WitnessProgram(ref e) => write_err!(f, "witness program error"; e),
UnrecognizedScript => write!(f, "script is not a p2pkh, p2sh or witness program"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for FromScriptError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use FromScriptError::*;
match self {
WitnessVersion(e) => Some(e),
WitnessProgram(e) => Some(e),
UnrecognizedScript => None,
}
}
}
impl From<witness_program::Error> for FromScriptError {
fn from(e : witness_program::Error) -> Self { FromScriptError::WitnessProgram(e)}
}
impl From<witness_version::TryFromError> for FromScriptError {
fn from(e: witness_version::TryFromError) -> Self { FromScriptError::WitnessVersion(e) }
}
/// Address type is either invalid or not supported in rust-bitcoin. /// Address type is either invalid or not supported in rust-bitcoin.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]

View File

@ -54,7 +54,7 @@ use crate::taproot::TapNodeHash;
#[rustfmt::skip] // Keep public re-exports separate. #[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)] #[doc(inline)]
pub use self::{ pub use self::{
error::{Error, ParseError, UnknownAddressTypeError, UnknownHrpError}, error::{Error, ParseError, UnknownAddressTypeError, UnknownHrpError, FromScriptError},
}; };
/// The different types of addresses. /// The different types of addresses.
@ -503,7 +503,7 @@ impl Address {
pub fn is_spend_standard(&self) -> bool { self.address_type().is_some() } pub fn is_spend_standard(&self) -> bool { self.address_type().is_some() }
/// Constructs an [`Address`] from an output script (`scriptPubkey`). /// Constructs an [`Address`] from an output script (`scriptPubkey`).
pub fn from_script(script: &Script, network: Network) -> Result<Address, Error> { pub fn from_script(script: &Script, network: Network) -> Result<Address, FromScriptError> {
if script.is_p2pkh() { if script.is_p2pkh() {
let bytes = script.as_bytes()[3..23].try_into().expect("statically 20B long"); let bytes = script.as_bytes()[3..23].try_into().expect("statically 20B long");
let hash = PubkeyHash::from_byte_array(bytes); let hash = PubkeyHash::from_byte_array(bytes);
@ -519,7 +519,7 @@ impl Address {
let program = WitnessProgram::new(version, &script.as_bytes()[2..])?; let program = WitnessProgram::new(version, &script.as_bytes()[2..])?;
Ok(Address::from_witness_program(program, network)) Ok(Address::from_witness_program(program, network))
} else { } else {
Err(Error::UnrecognizedScript) Err(FromScriptError::UnrecognizedScript)
} }
} }
@ -1236,13 +1236,13 @@ mod tests {
.unwrap(); .unwrap();
let invalid_segwitv0_script = let invalid_segwitv0_script =
ScriptBuf::from_hex("001161458e330389cd0437ee9fe3641d70cc18").unwrap(); ScriptBuf::from_hex("001161458e330389cd0437ee9fe3641d70cc18").unwrap();
let expected = Err(Error::UnrecognizedScript); let expected = Err(FromScriptError::UnrecognizedScript);
assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), expected); assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), expected);
assert_eq!(Address::from_script(&bad_p2wsh, Network::Bitcoin), expected); assert_eq!(Address::from_script(&bad_p2wsh, Network::Bitcoin), expected);
assert_eq!( assert_eq!(
Address::from_script(&invalid_segwitv0_script, Network::Bitcoin), Address::from_script(&invalid_segwitv0_script, Network::Bitcoin),
Err(Error::WitnessProgram(witness_program::Error::InvalidSegwitV0Length(17))) Err(FromScriptError::WitnessProgram(witness_program::Error::InvalidSegwitV0Length(17)))
); );
} }