Merge rust-bitcoin/rust-bitcoin#6787: Move `from_script` to `Address` and drop `AddressExt`
What changed, and why it matters
This change is a routine code cleanup, not a security fix. It moves a method that converts Bitcoin output scripts into human-readable addresses from a temporary 'extension trait' directly onto the main Address type. The actual conversion logic is copied unchanged, and the old extension trait is removed so users can call the method more naturally. There is no indication this fixes a bug or vulnerability.
No security action required. Treat as a normal API refactor; verify downstream code compiles after removing `AddressExt` imports.
Security signals we found
No strong security signals were identified.
Evidence from the diff
PR #6787 refactors AddressExt::from_script into Address::from_script inside the addresses crate. The implementation is moved verbatim from bitcoin/src/address.rs to addresses/src/lib.rs. The signature changes from taking impl Into<AddressParams> via the extension trait to the same parameter on the inherent Address impl. Imports and re-exports are updated accordingly, and a fuzz target is adjusted to drop the AddressExt import. No logic changes are visible in the diff.
Changed components
addresses/src/lib.rsbitcoin/src/address.rsbitcoin/src/lib.rsfuzz/fuzz_targets/bitcoin/arbitrary_script.rsInspect captured patch +38 / −41
### addresses/src/lib.rs
@@ -879,6 +879,38 @@ impl Address {
///
pub fn is_spend_standard(&self) -> bool { self.address_type().is_some() }
+ /// Constructs a new [`Address`] from an output script (`scriptPubkey`).
+ ///
+ /// # Errors
+ ///
+ /// - [`FromScriptError::UnrecognizedScript`] if the given script is not p2pkh, p2sh, or
+ /// SegWit program.
+ /// - [`FromScriptError::WitnessProgram`] if the given script has a valid SegWit version, but
+ /// is not a valid witness program. See [`WitnessProgram::new`] for more details.
+ #[cfg(feature = "alloc")]
+ #[allow(clippy::missing_panics_doc)] // Slices have known lengths before array casts
+ pub fn from_script(
+ script: &ScriptPubKey,
+ params: impl Into<AddressParams>,
+ ) -> Result<Self, FromScriptError> {
+ let params = params.into();
+ if script.is_p2pkh() {
+ let bytes = script.as_bytes()[3..23].try_into().expect("statically 20B long");
+ let hash = PubkeyHash::from_byte_array(bytes);
+ Ok(Self::p2pkh(hash, params))
+ } else if script.is_p2sh() {
+ let bytes = script.as_bytes()[2..22].try_into().expect("statically 20B long");
+ let hash = ScriptHash::from_byte_array(bytes);
+ Ok(Self::p2sh_from_hash(hash, params))
+ } else if let Some(version) = script.witness_version() {
+ let program = WitnessProgram::new(version, &script.as_bytes()[2..])
+ .map_err(FromScriptError::WitnessProgram)?;
+ Ok(Self::from_witness_program(program, params))
+ } else {
+ Err(FromScriptError::UnrecognizedScript)
+ }
+ }
+
/// Generates a script pubkey spending to this address.
#[cfg(feature = "alloc")]
pub fn script_pubkey(&self) -> ScriptPubKeyBuf {
### bitcoin/src/address.rs
@@ -40,10 +40,7 @@
//! # }
//! ```
-use addresses::witness_program::WitnessProgram;
-use crypto::key::PubkeyHash;
use network::Network;
-use primitives::script::{ScriptHash, ScriptPubKey};
use crate::network::Params;
@@ -77,39 +74,6 @@ impl From<Params> for AddressParams {
fn from(params: Params) -> Self { Self::from(¶ms) }
}
-mod sealed {
- pub trait Sealed {}
- impl Sealed for super::Address {}
-}
-
-crate::internal_macros::define_extension_trait! {
- /// Extension functionality for the [`Address`] type
- pub trait AddressExt impl for Address {
- /// Constructs a new [`Address`] from an output script (`scriptPubkey`).
- fn from_script(
- script: &ScriptPubKey,
- params: impl Into<AddressParams>,
- ) -> Result<Address, FromScriptError> {
- let params = params.into();
- if script.is_p2pkh() {
- let bytes = script.as_bytes()[3..23].try_into().expect("statically 20B long");
- let hash = PubkeyHash::from_byte_array(bytes);
- Ok(Self::p2pkh(hash, params))
- } else if script.is_p2sh() {
- let bytes = script.as_bytes()[2..22].try_into().expect("statically 20B long");
- let hash = ScriptHash::from_byte_array(bytes);
- Ok(Self::p2sh_from_hash(hash, params))
- } else if let Some(version) = script.witness_version() {
- let program = WitnessProgram::new(version, &script.as_bytes()[2..])
- .map_err(FromScriptError::WitnessProgram)?;
- Ok(Self::from_witness_program(program, params))
- } else {
- Err(FromScriptError::UnrecognizedScript)
- }
- }
- }
-}
-
/// Error code for the address module.
pub mod error {
#[doc(inline)]
@@ -126,13 +90,15 @@ mod tests {
use alloc::borrow::ToOwned;
use alloc::string::ToString;
+ use addresses::witness_program::WitnessProgram;
+ use crypto::key::{FullPublicKey, LegacyPublicKey, PubkeyHash, XOnlyPublicKey};
use hex::hex;
+ use primitives::witness_version::WitnessVersion;
use super::*;
use crate::network::params;
- use crate::script::{RedeemScriptBuf, ScriptPubKeyBuf, WitnessScriptBuf};
- use crate::witness_version::WitnessVersion;
- use crate::{FullPublicKey, LegacyPublicKey, XOnlyPublicKey};
+ use crate::script::ScriptHash;
+ use crate::{RedeemScriptBuf, ScriptPubKeyBuf, WitnessScriptBuf};
fn roundtrips(addr: &Address, params: AddressParams) {
assert_eq!(
### bitcoin/src/lib.rs
@@ -103,7 +103,6 @@ pub mod ext {
//! ```
#[rustfmt::skip] // Use terse custom grouping.
pub use crate::{
- address::AddressExt as _,
block::{BlockCheckedExt as _, HeaderExt as _},
key::{FullPublicKeyExt as _, LegacyPublicKeyExt as _},
network::NetworkExt as _,
### fuzz/fuzz_targets/bitcoin/arbitrary_script.rs
@@ -2,7 +2,7 @@
#![cfg_attr(not(fuzzing), allow(unused))]
use arbitrary::{Arbitrary, Unstructured};
-use bitcoin::address::{Address, AddressExt as _, AddressParams};
+use bitcoin::address::{Address, AddressParams};
use bitcoin::encoding::encode_to_vec;
use bitcoin::script::{self, ScriptBuf, ScriptExt as _, ScriptPubKeyExt as _};
use bitcoin::Network;Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.