Skip to content

Commit 768dc39

Browse files
committed
Merge rust-bitcoin/rust-bitcoin#1038: Modify from_script functions in address.rs to return result
66e852c Update format of ExcessiveScriptSize error message (eunoia_1729) 89bd4b6 Modify from_script functions in address.rs to return result (eunoia_1729) Pull request description: 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 ACKs for top commit: sanket1729: ACK 66e852c. LGTM tcharding: ACK 66e852c apoelstra: ACK 66e852c Tree-SHA512: 0d9529aee0a5459351bed2cc8b2c5571736d3293e2931c43d98f53330e9ac5f3d998a19da2b4575af0a3c1c4dcfd5a24c8813390bf6f5492a689c36ebb9cb426
2 parents 6638619 + 2bf566b commit 768dc39

File tree

2 files changed

+22
-19
lines changed

2 files changed

+22
-19
lines changed

fuzz/fuzz_targets/deserialize_script.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn do_test(data: &[u8]) {
3737
assert_eq!(data, &encode::serialize(&script)[..]);
3838

3939
// Check if valid address and if that address roundtrips.
40-
if let Some(addr) = Address::from_script(&script, Network::Bitcoin) {
40+
if let Ok(addr) = Address::from_script(&script, Network::Bitcoin) {
4141
assert_eq!(addr.script_pubkey(), script);
4242
}
4343
}

src/util/address.rs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ pub enum Error {
8181
/// An uncompressed pubkey was used where it is not allowed.
8282
UncompressedPubkey,
8383
/// Address size more than 520 bytes is not allowed.
84-
ExcessiveScriptSize
84+
ExcessiveScriptSize,
85+
/// Script is not a p2pkh, p2sh or witness program.
86+
UnrecognizedScript,
8587
}
8688

8789
impl fmt::Display for Error {
@@ -97,7 +99,8 @@ impl fmt::Display for Error {
9799
Error::InvalidWitnessProgramLength(l) => write!(f, "the witness program must be between 2 and 40 bytes in length: length={}", l),
98100
Error::InvalidSegwitV0ProgramLength(l) => write!(f, "a v0 witness program must be either of length 20 or 32 bytes: length={}", l),
99101
Error::UncompressedPubkey => write!(f, "an uncompressed pubkey was used where it is not allowed"),
100-
Error::ExcessiveScriptSize => write!(f, "Script size exceed 520 bytes"),
102+
Error::ExcessiveScriptSize => write!(f, "script size exceed 520 bytes"),
103+
Error::UnrecognizedScript => write!(f, "script is not a p2pkh, p2sh or witness program")
101104
}
102105
}
103106
}
@@ -119,7 +122,8 @@ impl std::error::Error for Error {
119122
| InvalidWitnessProgramLength(_)
120123
| InvalidSegwitV0ProgramLength(_)
121124
| UncompressedPubkey
122-
| ExcessiveScriptSize => None,
125+
| ExcessiveScriptSize
126+
| UnrecognizedScript => None,
123127
}
124128
}
125129
}
@@ -386,8 +390,8 @@ pub enum Payload {
386390

387391
impl Payload {
388392
/// Constructs a [Payload] from an output script (`scriptPubkey`).
389-
pub fn from_script(script: &script::Script) -> Option<Payload> {
390-
Some(if script.is_p2pkh() {
393+
pub fn from_script(script: &script::Script) -> Result<Payload, Error> {
394+
Ok(if script.is_p2pkh() {
391395
let mut hash_inner = [0u8; 20];
392396
hash_inner.copy_from_slice(&script.as_bytes()[3..23]);
393397
Payload::PubkeyHash(PubkeyHash::from_inner(hash_inner))
@@ -396,12 +400,16 @@ impl Payload {
396400
hash_inner.copy_from_slice(&script.as_bytes()[2..22]);
397401
Payload::ScriptHash(ScriptHash::from_inner(hash_inner))
398402
} else if script.is_witness_program() {
403+
if script.witness_version() == Some(WitnessVersion::V0) && !(script.is_v0_p2wpkh() || script.is_v0_p2wsh()) {
404+
return Err(Error::InvalidSegwitV0ProgramLength(script.len()));
405+
}
406+
399407
Payload::WitnessProgram {
400-
version: WitnessVersion::from_opcode(opcodes::All::from(script[0])).ok()?,
408+
version: WitnessVersion::from_opcode(opcodes::All::from(script[0]))?,
401409
program: script[2..].to_vec(),
402410
}
403411
} else {
404-
return None;
412+
return Err(Error::UnrecognizedScript);
405413
})
406414
}
407415

@@ -692,14 +700,8 @@ impl Address {
692700
}
693701

694702
/// Constructs an [`Address`] from an output script (`scriptPubkey`).
695-
pub fn from_script(script: &script::Script, network: Network) -> Option<Address> {
696-
if script.is_witness_program()
697-
&& script.witness_version() == Some(WitnessVersion::V0)
698-
&& !(script.is_v0_p2wpkh() || script.is_v0_p2wsh()) {
699-
return None
700-
}
701-
702-
Some(Address {
703+
pub fn from_script(script: &script::Script, network: Network) -> Result<Address, Error> {
704+
Ok(Address {
703705
payload: Payload::from_script(script)?,
704706
network,
705707
})
@@ -959,7 +961,7 @@ mod tests {
959961
);
960962
assert_eq!(
961963
Address::from_script(&addr.script_pubkey(), addr.network).as_ref(),
962-
Some(addr),
964+
Ok(addr),
963965
"script round-trip failed for {}",
964966
addr,
965967
);
@@ -1428,8 +1430,9 @@ mod tests {
14281430
fn test_fail_address_from_script() {
14291431
let bad_p2wpkh = hex_script!("0014dbc5b0a8f9d4353b4b54c3db48846bb15abfec");
14301432
let bad_p2wsh = hex_script!("00202d4fa2eb233d008cc83206fa2f4f2e60199000f5b857a835e3172323385623");
1433+
let expected = Err(Error::UnrecognizedScript);
14311434

1432-
assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), None);
1433-
assert_eq!(Address::from_script(&bad_p2wsh, Network::Bitcoin), None);
1435+
assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), expected);
1436+
assert_eq!(Address::from_script(&bad_p2wsh, Network::Bitcoin), expected);
14341437
}
14351438
}

0 commit comments

Comments
 (0)