Skip to content

Commit

Permalink
Address::address_type returns Result instead of Option
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Sep 17, 2021
1 parent ad60698 commit 1767bcc
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 40 deletions.
75 changes: 41 additions & 34 deletions src/util/address.rs
Expand Up @@ -79,31 +79,40 @@ pub enum Error {
InvalidSegwitV0ProgramLength(usize),
/// An uncompressed pubkey was used where it is not allowed.
UncompressedPubkey,
/// Witness version which is not (yet) supported
UnsupportedWitnessVersion {
/// Witness version that was found during address decoding
version: WitnessVersion,
/// Length of the witness program
length: usize
},
/// Address size more than 520 bytes is not allowed.
ExcessiveScriptSize
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Base58(_) => write!(f, "base58 address encoding error"),
Error::Bech32(_) => write!(f, "bech32 address encoding error"),
Error::EmptyBech32Payload => write!(f, "the bech32 payload was empty"),
Error::Base58(_) => f.write_str("base58 address encoding error"),
Error::Bech32(_) => f.write_str( "bech32 address encoding error"),
Error::EmptyBech32Payload => f.write_str( "the bech32 payload was empty"),
Error::InvalidBech32Variant { expected, found } => write!(f, "invalid bech32 checksum variant found {:?} when {:?} was expected", found, expected),
Error::InvalidWitnessVersion(v) => write!(f, "invalid witness script version: {}", v),
Error::UnparsableWitnessVersion(_) => write!(f, "incorrect format of a witness version byte"),
Error::UnparsableWitnessVersion(_) => f.write_str( "incorrect format of a witness version byte"),
Error::MalformedWitnessVersion => f.write_str("bitcoin script opcode does not match any known witness version, the script is malformed"),
Error::InvalidWitnessProgramLength(l) => write!(f,
"the witness program must be between 2 and 40 bytes in length: length={}", l,
Error::InvalidWitnessProgramLength(len) => write!(f,
"the witness program must be between 2 and 40 bytes in length: length={}", len,
),
Error::InvalidSegwitV0ProgramLength(l) => write!(f,
"a v0 witness program must be either of length 20 or 32 bytes: length={}", l,
Error::InvalidSegwitV0ProgramLength(len) => write!(f,
"a v0 witness program must be either of length 20 or 32 bytes: length={}", len,
),
Error::UncompressedPubkey => write!(f,
Error::UncompressedPubkey => f.write_str(
"an uncompressed pubkey was used where it is not allowed",
),
Error::ExcessiveScriptSize => write!(f,
"Script size exceed 520 bytes")
Error::UnsupportedWitnessVersion { version, length } => write!(
f, "witness version {:?} is not supported yet for witness program length {}", version, length
),
Error::ExcessiveScriptSize => write!(f, "Script size exceed 520 bytes")
}
}
}
Expand Down Expand Up @@ -531,23 +540,21 @@ impl Address {

/// Get the address type of the address.
/// None if unknown, non-standard or related to the future witness version.
pub fn address_type(&self) -> Option<AddressType> {
pub fn address_type(&self) -> Result<AddressType, Error> {
match self.payload {
Payload::PubkeyHash(_) => Some(AddressType::P2pkh),
Payload::ScriptHash(_) => Some(AddressType::P2sh),
Payload::PubkeyHash(_) => Ok(AddressType::P2pkh),
Payload::ScriptHash(_) => Ok(AddressType::P2sh),
Payload::WitnessProgram {
version,
program: ref prog,
} => {
// BIP-141 p2wpkh or p2wsh addresses.
match version {
WitnessVersion::V0 => match prog.len() {
20 => Some(AddressType::P2wpkh),
32 => Some(AddressType::P2wsh),
_ => None,
},
WitnessVersion::V1 if prog.len() == 32 => Some(AddressType::P2tr),
_ => None,
match (version, prog.len()) {
(WitnessVersion::V0, 20) => Ok(AddressType::P2wpkh),
(WitnessVersion::V0, 32) => Ok(AddressType::P2wsh),
(WitnessVersion::V0, len) => Err(Error::InvalidWitnessProgramLength(len)),
(WitnessVersion::V1, 32) => Ok(AddressType::P2tr),
(version, length) => Err(Error::UnsupportedWitnessVersion { version, length }),
}
}
}
Expand All @@ -559,7 +566,7 @@ impl Address {
/// SegWit addresses with unassigned witness versions or non-standard
/// program sizes are considered non-standard.
pub fn is_standard(&self) -> bool {
self.address_type().is_some()
self.address_type().is_ok()
}

/// Get an [Address] from an output script (scriptPubkey).
Expand Down Expand Up @@ -612,7 +619,7 @@ impl Address {
/// ```
pub fn is_valid_for_network(&self, network: Network) -> bool {
let is_legacy = match self.address_type() {
Some(AddressType::P2pkh) | Some(AddressType::P2sh) => true,
Ok(AddressType::P2pkh) | Ok(AddressType::P2sh) => true,
_ => false
};

Expand Down Expand Up @@ -830,7 +837,7 @@ mod tests {
hex_script!("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac")
);
assert_eq!(&addr.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
assert_eq!(addr.address_type(), Ok(AddressType::P2pkh));
roundtrips(&addr);
}

Expand All @@ -843,7 +850,7 @@ mod tests {
let key = hex_key!(&"03df154ebfcf29d29cc10d5c2565018bce2d9edbab267c31d2caf44a63056cf99f");
let addr = Address::p2pkh(&key, Testnet);
assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC");
assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
assert_eq!(addr.address_type(), Ok(AddressType::P2pkh));
roundtrips(&addr);
}

Expand All @@ -859,7 +866,7 @@ mod tests {
hex_script!("a914162c5ea71c0b23f5b9022ef047c4a86470a5b07087")
);
assert_eq!(&addr.to_string(), "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k");
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
assert_eq!(addr.address_type(), Ok(AddressType::P2sh));
roundtrips(&addr);
}

Expand All @@ -868,7 +875,7 @@ mod tests {
let script = hex_script!("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae");
let addr = Address::p2sh(&script, Testnet).unwrap();
assert_eq!(&addr.to_string(), "2N3zXjbwdTcPsJiy8sUK9FhWJhqQCxA8Jjr");
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
assert_eq!(addr.address_type(), Ok(AddressType::P2sh));
roundtrips(&addr);
}

Expand All @@ -884,7 +891,7 @@ mod tests {
let mut key = hex_key!("033bc8c83c52df5712229a2f72206d90192366c36428cb0c12b6af98324d97bfbc");
let addr = Address::p2wpkh(&key, Bitcoin).unwrap();
assert_eq!(&addr.to_string(), "bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw");
assert_eq!(addr.address_type(), Some(AddressType::P2wpkh));
assert_eq!(addr.address_type(), Ok(AddressType::P2wpkh));
roundtrips(&addr);

// Test uncompressed pubkey
Expand All @@ -901,7 +908,7 @@ mod tests {
&addr.to_string(),
"bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej"
);
assert_eq!(addr.address_type(), Some(AddressType::P2wsh));
assert_eq!(addr.address_type(), Ok(AddressType::P2wsh));
roundtrips(&addr);
}

Expand All @@ -911,7 +918,7 @@ mod tests {
let mut key = hex_key!("026c468be64d22761c30cd2f12cbc7de255d592d7904b1bab07236897cc4c2e766");
let addr = Address::p2shwpkh(&key, Bitcoin).unwrap();
assert_eq!(&addr.to_string(), "3QBRmWNqqBGme9er7fMkGqtZtp4gjMFxhE");
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
assert_eq!(addr.address_type(), Ok(AddressType::P2sh));
roundtrips(&addr);

// Test uncompressed pubkey
Expand All @@ -925,7 +932,7 @@ mod tests {
let script = hex_script!("522103e5529d8eaa3d559903adb2e881eb06c86ac2574ffa503c45f4e942e2a693b33e2102e5f10fcdcdbab211e0af6a481f5532536ec61a5fdbf7183770cf8680fe729d8152ae");
let addr = Address::p2shwsh(&script, Bitcoin);
assert_eq!(&addr.to_string(), "36EqgNnsWW94SreZgBWc1ANC6wpFZwirHr");
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
assert_eq!(addr.address_type(), Ok(AddressType::P2sh));
roundtrips(&addr);
}

Expand Down Expand Up @@ -959,8 +966,8 @@ mod tests {
("bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0", "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")
];
for vector in &valid_vectors {
let addr: Address = vector.0.parse().unwrap();
assert_eq!(&addr.script_pubkey().as_bytes().to_hex(), vector.1);
let addr: Address = vector.0.parse().expect(&format!("error in test vector {}", vector.0));
assert_eq!(&addr.script_pubkey().as_bytes().to_hex(), vector.1, "failure for test vector {}", vector.0);
roundtrips(&addr);
}

Expand Down
12 changes: 6 additions & 6 deletions src/util/misc.rs
Expand Up @@ -162,14 +162,14 @@ mod message_signing {
) -> Result<bool, secp256k1::Error> {
let pubkey = self.recover_pubkey(&secp_ctx, msg_hash)?;
Ok(match address.address_type() {
Some(AddressType::P2pkh) => {
Ok(AddressType::P2pkh) => {
*address == Address::p2pkh(&pubkey, address.network)
}
Some(AddressType::P2sh) => false,
Some(AddressType::P2wpkh) => false,
Some(AddressType::P2wsh) => false,
Some(AddressType::P2tr) => false,
None => false,
Ok(AddressType::P2sh) => false,
Ok(AddressType::P2wpkh) => false,
Ok(AddressType::P2wsh) => false,
Ok(AddressType::P2tr) => false,
Err(_) => false,
})
}

Expand Down

0 comments on commit 1767bcc

Please sign in to comment.