Merge rust-bitcoin/rust-bitcoin#2497: Add the `FromScriptError` for handling errors in `address`
c2d658ac05
Add `P2shError` for handling errors related to P2sh (harshit933)5182a8d7a8
Remove unused variants from `Address::Error` (harshit933)05b24946eb
Add the `FromScriptError` for handling errors in `address` (harshit933) Pull request description: 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. ACKs for top commit: tcharding: ACKc2d658ac05
apoelstra: ACKc2d658ac05
Tree-SHA512: 891eed787129aaf1b664cc16d325178d5d2f77cc41a0543a3d9d1a5af1b58188daece1f6a653bdc6b76b82db0490a39e9bba7fc090e3727d15ee9b8977733698
This commit is contained in:
commit
d85817b880
|
@ -13,14 +13,6 @@ use crate::{base58, Network};
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
/// A witness version construction error.
|
||||
WitnessVersion(witness_version::TryFromError),
|
||||
/// A witness program error.
|
||||
WitnessProgram(witness_program::Error),
|
||||
/// Address size more than 520 bytes is not allowed.
|
||||
ExcessiveScriptSize,
|
||||
/// Script is not a p2pkh, p2sh or witness program.
|
||||
UnrecognizedScript,
|
||||
/// Address's network differs from required one.
|
||||
NetworkValidation {
|
||||
/// Network that was required.
|
||||
|
@ -37,10 +29,6 @@ impl fmt::Display for Error {
|
|||
use Error::*;
|
||||
|
||||
match *self {
|
||||
WitnessVersion(ref e) => write_err!(f, "witness version construction error"; e),
|
||||
WitnessProgram(ref e) => write_err!(f, "witness program error"; e),
|
||||
ExcessiveScriptSize => write!(f, "script size exceed 520 bytes"),
|
||||
UnrecognizedScript => write!(f, "script is not a p2pkh, p2sh or witness program"),
|
||||
NetworkValidation { required, ref address } => {
|
||||
write!(f, "address ")?;
|
||||
fmt::Display::fmt(&address.0, f)?;
|
||||
|
@ -56,21 +44,85 @@ impl std::error::Error for Error {
|
|||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
use Error::*;
|
||||
|
||||
match self {
|
||||
WitnessVersion(e) => Some(e),
|
||||
WitnessProgram(e) => Some(e),
|
||||
UnknownHrp(e) => Some(e),
|
||||
ExcessiveScriptSize | UnrecognizedScript | NetworkValidation { .. } => None,
|
||||
match *self {
|
||||
UnknownHrp(ref e) => Some(e),
|
||||
NetworkValidation { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<witness_version::TryFromError> for Error {
|
||||
fn from(e: witness_version::TryFromError) -> Error { Error::WitnessVersion(e) }
|
||||
/// Error while generating address from script.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
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 From<witness_program::Error> for Error {
|
||||
fn from(e: witness_program::Error) -> Error { Error::WitnessProgram(e) }
|
||||
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 {
|
||||
UnrecognizedScript => None,
|
||||
WitnessVersion(ref e) => Some(e),
|
||||
WitnessProgram(ref e) => Some(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<witness_program::Error> for FromScriptError {
|
||||
fn from(e : witness_program::Error) -> Self { Self::WitnessProgram(e) }
|
||||
}
|
||||
|
||||
impl From<witness_version::TryFromError> for FromScriptError {
|
||||
fn from(e: witness_version::TryFromError) -> Self { Self::WitnessVersion(e) }
|
||||
}
|
||||
|
||||
/// Error while generating address from a p2sh script.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum P2shError {
|
||||
/// Address size more than 520 bytes is not allowed.
|
||||
ExcessiveScriptSize,
|
||||
}
|
||||
|
||||
impl fmt::Display for P2shError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use P2shError::*;
|
||||
|
||||
match *self {
|
||||
ExcessiveScriptSize => write!(f, "script size exceed 520 bytes"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for P2shError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
use P2shError::*;
|
||||
|
||||
match self {
|
||||
ExcessiveScriptSize => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Address type is either invalid or not supported in rust-bitcoin.
|
||||
|
|
|
@ -51,10 +51,11 @@ use crate::network::{Network, NetworkKind};
|
|||
use crate::prelude::*;
|
||||
use crate::taproot::TapNodeHash;
|
||||
|
||||
use self::error::P2shError;
|
||||
#[rustfmt::skip] // Keep public re-exports separate.
|
||||
#[doc(inline)]
|
||||
pub use self::{
|
||||
error::{Error, ParseError, UnknownAddressTypeError, UnknownHrpError},
|
||||
error::{Error, ParseError, UnknownAddressTypeError, UnknownHrpError, FromScriptError},
|
||||
};
|
||||
|
||||
/// The different types of addresses.
|
||||
|
@ -373,9 +374,9 @@ impl Address {
|
|||
/// This address type was introduced with BIP16 and is the popular type to implement multi-sig
|
||||
/// these days.
|
||||
#[inline]
|
||||
pub fn p2sh(script: &Script, network: impl Into<NetworkKind>) -> Result<Address, Error> {
|
||||
pub fn p2sh(script: &Script, network: impl Into<NetworkKind>) -> Result<Address, P2shError> {
|
||||
if script.len() > MAX_SCRIPT_ELEMENT_SIZE {
|
||||
return Err(Error::ExcessiveScriptSize);
|
||||
return Err(P2shError::ExcessiveScriptSize);
|
||||
}
|
||||
let hash = script.script_hash();
|
||||
Ok(Address::p2sh_from_hash(hash, network))
|
||||
|
@ -503,7 +504,7 @@ impl Address {
|
|||
pub fn is_spend_standard(&self) -> bool { self.address_type().is_some() }
|
||||
|
||||
/// 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() {
|
||||
let bytes = script.as_bytes()[3..23].try_into().expect("statically 20B long");
|
||||
let hash = PubkeyHash::from_byte_array(bytes);
|
||||
|
@ -519,7 +520,7 @@ impl Address {
|
|||
let program = WitnessProgram::new(version, &script.as_bytes()[2..])?;
|
||||
Ok(Address::from_witness_program(program, network))
|
||||
} else {
|
||||
Err(Error::UnrecognizedScript)
|
||||
Err(FromScriptError::UnrecognizedScript)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -861,7 +862,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_p2sh_parse_for_large_script() {
|
||||
let script = ScriptBuf::from_hex("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123").unwrap();
|
||||
assert_eq!(Address::p2sh(&script, NetworkKind::Test), Err(Error::ExcessiveScriptSize));
|
||||
assert_eq!(Address::p2sh(&script, NetworkKind::Test), Err(P2shError::ExcessiveScriptSize));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1236,13 +1237,13 @@ mod tests {
|
|||
.unwrap();
|
||||
let invalid_segwitv0_script =
|
||||
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_p2wsh, Network::Bitcoin), expected);
|
||||
assert_eq!(
|
||||
Address::from_script(&invalid_segwitv0_script, Network::Bitcoin),
|
||||
Err(Error::WitnessProgram(witness_program::Error::InvalidSegwitV0Length(17)))
|
||||
Err(FromScriptError::WitnessProgram(witness_program::Error::InvalidSegwitV0Length(17)))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue