Modify from_script functions in address.rs to return result
Modify from_script functions to return result instead of option so that, in case of errors, there is more information on what went wrong. Resolves: #1022
This commit is contained in:
parent
8fd700859a
commit
89bd4b61a4
|
@ -37,7 +37,7 @@ fn do_test(data: &[u8]) {
|
||||||
assert_eq!(data, &encode::serialize(&script)[..]);
|
assert_eq!(data, &encode::serialize(&script)[..]);
|
||||||
|
|
||||||
// Check if valid address and if that address roundtrips.
|
// Check if valid address and if that address roundtrips.
|
||||||
if let Some(addr) = Address::from_script(&script, Network::Bitcoin) {
|
if let Ok(addr) = Address::from_script(&script, Network::Bitcoin) {
|
||||||
assert_eq!(addr.script_pubkey(), script);
|
assert_eq!(addr.script_pubkey(), script);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,9 @@ pub enum Error {
|
||||||
/// An uncompressed pubkey was used where it is not allowed.
|
/// An uncompressed pubkey was used where it is not allowed.
|
||||||
UncompressedPubkey,
|
UncompressedPubkey,
|
||||||
/// Address size more than 520 bytes is not allowed.
|
/// Address size more than 520 bytes is not allowed.
|
||||||
ExcessiveScriptSize
|
ExcessiveScriptSize,
|
||||||
|
/// Script is not a p2pkh, p2sh or witness program.
|
||||||
|
UnrecognizedScript,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
@ -98,6 +100,7 @@ impl fmt::Display for Error {
|
||||||
Error::InvalidSegwitV0ProgramLength(l) => write!(f, "a v0 witness program must be either of length 20 or 32 bytes: length={}", l),
|
Error::InvalidSegwitV0ProgramLength(l) => write!(f, "a v0 witness program must be either of length 20 or 32 bytes: length={}", l),
|
||||||
Error::UncompressedPubkey => write!(f, "an uncompressed pubkey was used where it is not allowed"),
|
Error::UncompressedPubkey => write!(f, "an uncompressed pubkey was used where it is not allowed"),
|
||||||
Error::ExcessiveScriptSize => write!(f, "Script size exceed 520 bytes"),
|
Error::ExcessiveScriptSize => write!(f, "Script size exceed 520 bytes"),
|
||||||
|
Error::UnrecognizedScript => write!(f, "script is not a p2pkh, p2sh or witness program")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +122,8 @@ impl std::error::Error for Error {
|
||||||
| InvalidWitnessProgramLength(_)
|
| InvalidWitnessProgramLength(_)
|
||||||
| InvalidSegwitV0ProgramLength(_)
|
| InvalidSegwitV0ProgramLength(_)
|
||||||
| UncompressedPubkey
|
| UncompressedPubkey
|
||||||
| ExcessiveScriptSize => None,
|
| ExcessiveScriptSize
|
||||||
|
| UnrecognizedScript => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,8 +390,8 @@ pub enum Payload {
|
||||||
|
|
||||||
impl Payload {
|
impl Payload {
|
||||||
/// Constructs a [Payload] from an output script (`scriptPubkey`).
|
/// Constructs a [Payload] from an output script (`scriptPubkey`).
|
||||||
pub fn from_script(script: &script::Script) -> Option<Payload> {
|
pub fn from_script(script: &script::Script) -> Result<Payload, Error> {
|
||||||
Some(if script.is_p2pkh() {
|
Ok(if script.is_p2pkh() {
|
||||||
let mut hash_inner = [0u8; 20];
|
let mut hash_inner = [0u8; 20];
|
||||||
hash_inner.copy_from_slice(&script.as_bytes()[3..23]);
|
hash_inner.copy_from_slice(&script.as_bytes()[3..23]);
|
||||||
Payload::PubkeyHash(PubkeyHash::from_inner(hash_inner))
|
Payload::PubkeyHash(PubkeyHash::from_inner(hash_inner))
|
||||||
|
@ -396,12 +400,16 @@ impl Payload {
|
||||||
hash_inner.copy_from_slice(&script.as_bytes()[2..22]);
|
hash_inner.copy_from_slice(&script.as_bytes()[2..22]);
|
||||||
Payload::ScriptHash(ScriptHash::from_inner(hash_inner))
|
Payload::ScriptHash(ScriptHash::from_inner(hash_inner))
|
||||||
} else if script.is_witness_program() {
|
} else if script.is_witness_program() {
|
||||||
|
if script.witness_version() == Some(WitnessVersion::V0) && !(script.is_v0_p2wpkh() || script.is_v0_p2wsh()) {
|
||||||
|
return Err(Error::InvalidSegwitV0ProgramLength(script.len()));
|
||||||
|
}
|
||||||
|
|
||||||
Payload::WitnessProgram {
|
Payload::WitnessProgram {
|
||||||
version: WitnessVersion::from_opcode(opcodes::All::from(script[0])).ok()?,
|
version: WitnessVersion::from_opcode(opcodes::All::from(script[0]))?,
|
||||||
program: script[2..].to_vec(),
|
program: script[2..].to_vec(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return Err(Error::UnrecognizedScript);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,14 +700,8 @@ impl Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs an [`Address`] from an output script (`scriptPubkey`).
|
/// Constructs an [`Address`] from an output script (`scriptPubkey`).
|
||||||
pub fn from_script(script: &script::Script, network: Network) -> Option<Address> {
|
pub fn from_script(script: &script::Script, network: Network) -> Result<Address, Error> {
|
||||||
if script.is_witness_program()
|
Ok(Address {
|
||||||
&& script.witness_version() == Some(WitnessVersion::V0)
|
|
||||||
&& !(script.is_v0_p2wpkh() || script.is_v0_p2wsh()) {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Address {
|
|
||||||
payload: Payload::from_script(script)?,
|
payload: Payload::from_script(script)?,
|
||||||
network,
|
network,
|
||||||
})
|
})
|
||||||
|
@ -959,7 +961,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Address::from_script(&addr.script_pubkey(), addr.network).as_ref(),
|
Address::from_script(&addr.script_pubkey(), addr.network).as_ref(),
|
||||||
Some(addr),
|
Ok(addr),
|
||||||
"script round-trip failed for {}",
|
"script round-trip failed for {}",
|
||||||
addr,
|
addr,
|
||||||
);
|
);
|
||||||
|
@ -1428,8 +1430,9 @@ mod tests {
|
||||||
fn test_fail_address_from_script() {
|
fn test_fail_address_from_script() {
|
||||||
let bad_p2wpkh = hex_script!("0014dbc5b0a8f9d4353b4b54c3db48846bb15abfec");
|
let bad_p2wpkh = hex_script!("0014dbc5b0a8f9d4353b4b54c3db48846bb15abfec");
|
||||||
let bad_p2wsh = hex_script!("00202d4fa2eb233d008cc83206fa2f4f2e60199000f5b857a835e3172323385623");
|
let bad_p2wsh = hex_script!("00202d4fa2eb233d008cc83206fa2f4f2e60199000f5b857a835e3172323385623");
|
||||||
|
let expected = Err(Error::UnrecognizedScript);
|
||||||
|
|
||||||
assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), None);
|
assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), expected);
|
||||||
assert_eq!(Address::from_script(&bad_p2wsh, Network::Bitcoin), None);
|
assert_eq!(Address::from_script(&bad_p2wsh, Network::Bitcoin), expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue