primitives: Split cfg(all(...)) into stacked attributes
What changed, and why it matters
This commit is a purely stylistic change in the Rust Bitcoin library. It rewrites conditional compilation attributes (the Rust equivalent of #ifdef feature flags) from a single combined form to a stacked form. For example, #[cfg(all(feature = "hex", feature = "alloc"))] becomes two separate #[cfg(...)] lines. This has no effect on which code is compiled or how the library behaves, and it does not fix or introduce any security issue.
No security action needed. Treat as a normal code-style/refactoring commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch converts all #[cfg(all(a, b, …))] attributes into stacked #[cfg(a)] #[cfg(b)] attributes across primitives/src/block.rs, lib.rs, script/borrowed.rs, script/owned.rs, and transaction.rs. In Rust, #[cfg(all(A, B))] and #[cfg(A)] #[cfg(B)] are semantically equivalent: the item is included only when all listed conditions are true. No item logic, signatures, feature gates, or test behavior changes. There is no bug fix, no bounds-check change, no cryptographic change, and no API change.
Changed components
primitives/src/block.rsprimitives/src/lib.rsprimitives/src/script/borrowed.rsprimitives/src/script/owned.rsprimitives/src/transaction.rsInspect captured patch +113 / −53
diff --git a/primitives/src/block.rs b/primitives/src/block.rs
index 2ce10c17..4c9dc2af 100644
--- a/primitives/src/block.rs
+++ b/primitives/src/block.rs
@@ -274,7 +274,8 @@ mod sealed {
impl Validation for super::Unchecked {}
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl core::str::FromStr for Block<Unchecked>
where
Self: encoding::Decodable,
@@ -286,7 +287,8 @@ where
}
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl<V: Validation> fmt::Display for Block<V>
where
Self: encoding::Encodable,
@@ -297,14 +299,16 @@ where
}
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl<V: Validation> fmt::LowerHex for Block<V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&HexPrimitive(self), f)
}
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl<V: Validation> fmt::UpperHex for Block<V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::UpperHex::fmt(&HexPrimitive(self), f)
@@ -312,23 +316,28 @@ impl<V: Validation> fmt::UpperHex for Block<V> {
}
/// An error that occurs during parsing of a [`Block`] from a hex string.
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseBlockError(ParsePrimitiveError<Block>);
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl From<Infallible> for ParseBlockError {
fn from(never: Infallible) -> Self { match never {} }
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl fmt::Display for ParseBlockError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write_err!(f, "parse block error"; self.0)
}
}
-#[cfg(all(feature = "hex", feature = "alloc", feature = "std"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
+#[cfg(feature = "std")]
impl std::error::Error for ParseBlockError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
}
@@ -631,7 +640,8 @@ impl fmt::Display for ParseHeaderError {
}
}
-#[cfg(all(feature = "hex", feature = "std"))]
+#[cfg(feature = "hex")]
+#[cfg(feature = "std")]
impl std::error::Error for ParseHeaderError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
}
@@ -1010,13 +1020,16 @@ mod tests {
use alloc::string::ToString;
#[cfg(feature = "alloc")]
use alloc::{format, vec};
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
use core::str::FromStr as _;
#[cfg(feature = "alloc")]
use encoding::Decodable as _;
use encoding::{Decoder as _, Encodable as _, Encoder as _};
- #[cfg(all(feature = "serde", feature = "hex", feature = "alloc"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
+ #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::*;
@@ -1511,7 +1524,8 @@ mod tests {
// Test vector provided by tm0 in issue #5023
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn merkle_tree_hash_collision() {
// https://learnmeabitcoin.com/explorer/block/00000000000008a662b4a95a46e4c54cb04852525ac0ef67d1bcac85238416d4
// this block has 7 transactions
@@ -1610,7 +1624,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn block_check_witness_commitment_with_witness() {
let mut txin = crate::TxIn::EMPTY_COINBASE;
// Single witness item of 32 bytes.
@@ -1654,7 +1669,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn block_check_witness_commitment_invalid_witness() {
let mut txin = crate::TxIn::EMPTY_COINBASE;
let witness_bytes: [u8; 32] = [11u8; 32];
@@ -1815,7 +1831,9 @@ mod tests {
}
/// A type that has a `Block` field and a `Header` field.
- #[cfg(all(feature = "serde", feature = "hex", feature = "alloc"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
+ #[cfg(feature = "serde")]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
struct Adt {
#[serde(with = "crate::serde_as_consensus")]
@@ -1825,7 +1843,9 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "serde", feature = "hex", feature = "alloc"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
+ #[cfg(feature = "serde")]
fn can_serde_as_consensus_json() {
let orig = Adt { header: dummy_header(), block: dummy_block() };
@@ -1839,7 +1859,9 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "serde", feature = "hex", feature = "alloc"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
+ #[cfg(feature = "serde")]
fn can_serde_as_consensus_bincode() {
let orig = Adt { header: dummy_header(), block: dummy_block() };
diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs
index 3e14fc71..08f4ab71 100644
--- a/primitives/src/lib.rs
+++ b/primitives/src/lib.rs
@@ -53,7 +53,9 @@ pub mod block;
pub mod merkle_tree;
#[cfg(feature = "alloc")]
pub mod script;
-#[cfg(all(feature = "serde", feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
+#[cfg(feature = "serde")]
pub mod serde_as_consensus;
pub mod transaction;
#[cfg(feature = "alloc")]
@@ -109,7 +111,8 @@ mod prelude {
#[cfg(feature = "alloc")]
pub use alloc::{string::{String, ToString}, vec::Vec, boxed::Box, borrow::{Borrow, BorrowMut, Cow, ToOwned}, slice, rc};
- #[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(target_has_atomic = "ptr")]
pub use alloc::sync;
}
diff --git a/primitives/src/script/borrowed.rs b/primitives/src/script/borrowed.rs
index 07feb004..c97f7be6 100644
--- a/primitives/src/script/borrowed.rs
+++ b/primitives/src/script/borrowed.rs
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: CC0-1.0
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
use alloc::string::String;
use core::marker::PhantomData;
use core::ops::{
@@ -125,7 +126,8 @@ impl<T> Script<T> {
///
/// Consensus encoding includes a length prefix. To hex encode without the length prefix use
/// `to_hex_string_no_length_prefix`.
- #[cfg(all(feature = "hex", feature = "alloc"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
pub fn to_hex_string_prefixed(&self) -> String {
use hex_unstable::{BytesToHexIter, Case};
@@ -137,7 +139,8 @@ impl<T> Script<T> {
///
/// This is **not** consensus encoding. The returned hex string will not include the length
/// prefix. See `to_hex_string_prefixed`.
- #[cfg(all(feature = "hex", feature = "alloc"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
pub fn to_hex_string_no_length_prefix(&self) -> String {
use hex_unstable::DisplayHex as _;
diff --git a/primitives/src/script/owned.rs b/primitives/src/script/owned.rs
index b5d043ee..d242d78e 100644
--- a/primitives/src/script/owned.rs
+++ b/primitives/src/script/owned.rs
@@ -261,7 +261,8 @@ impl fmt::Display for FromHexError {
}
}
-#[cfg(all(feature = "std", feature = "hex"))]
+#[cfg(feature = "hex")]
+#[cfg(feature = "std")]
impl std::error::Error for FromHexError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs
index ff8087d6..65ba7b79 100644
--- a/primitives/src/transaction.rs
+++ b/primitives/src/transaction.rs
@@ -29,12 +29,14 @@ use internals::array::ArrayExt as _;
use internals::write_err;
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
use units::parse_int;
#[cfg(feature = "alloc")]
use crate::amount::{AmountDecoder, AmountEncoder};
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
use crate::hex_codec::{HexPrimitive, ParsePrimitiveError};
#[cfg(feature = "alloc")]
use crate::locktime::absolute::{LockTimeDecoder, LockTimeDecoderError, LockTimeEncoder};
@@ -376,7 +378,8 @@ impl encoding::Encodable for Transaction {
}
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl core::str::FromStr for Transaction {
type Err = ParseTransactionError;
@@ -385,21 +388,24 @@ impl core::str::FromStr for Transaction {
}
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl fmt::Display for Transaction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&HexPrimitive(self), f)
}
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl fmt::LowerHex for Transaction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&HexPrimitive(self), f)
}
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl fmt::UpperHex for Transaction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::UpperHex::fmt(&HexPrimitive(self), f)
@@ -407,23 +413,28 @@ impl fmt::UpperHex for Transaction {
}
/// An error that occurs during parsing of a [`Transaction`] from a hex string.
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseTransactionError(ParsePrimitiveError<Transaction>);
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl From<Infallible> for ParseTransactionError {
fn from(never: Infallible) -> Self { match never {} }
}
-#[cfg(all(feature = "hex", feature = "alloc"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
impl fmt::Display for ParseTransactionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write_err!(f, "parse transaction error"; self.0)
}
}
-#[cfg(all(feature = "hex", feature = "alloc", feature = "std"))]
+#[cfg(feature = "alloc")]
+#[cfg(feature = "hex")]
+#[cfg(feature = "std")]
impl std::error::Error for ParseTransactionError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
}
@@ -1651,7 +1662,8 @@ mod tests {
use hex_unstable::hex;
use super::*;
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
use crate::absolute::LockTime;
const TC_TXID_BYTES: [u8; 32] = [
@@ -2062,7 +2074,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn encode_segwit_transaction() {
let tx = Transaction {
version: Version::TWO,
@@ -2287,7 +2300,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn decode_segwit_transaction() {
let tx_bytes = hex!(
"02000000000101595895ea20179de87052b4046dfe6fd515860505d6511a9004cf12a1f93cac7c01000000\
@@ -2336,7 +2350,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn decode_nonsegwit_transaction() {
let tx_bytes = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000");
@@ -2370,7 +2385,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn decode_segwit_without_witnesses_errors() {
// A SegWit-serialized transaction with 1 input but no witnesses for any input.
let tx_bytes = hex!(
@@ -2415,7 +2431,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn reject_null_prevout_in_non_coinbase_transaction() {
// Test vector taken from Bitcoin Core tx_invalid.json
// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L64
@@ -2434,7 +2451,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn reject_coinbase_scriptsig_too_small() {
// Test vector taken from Bitcoin Core tx_invalid.json
// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L57
@@ -2453,7 +2471,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn reject_coinbase_scriptsig_too_large() {
// Test vector taken from Bitcoin Core tx_invalid.json:
// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L62
@@ -2472,7 +2491,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn accept_coinbase_scriptsig_min_valid() {
// boundary test: 2 bytes is the minimum valid length
let tx_bytes = hex!("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000");
@@ -2486,7 +2506,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn accept_coinbase_scriptsig_max_valid() {
// boundary test: 100 bytes is the maximum valid length
let tx_bytes = hex!("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000");
@@ -2500,7 +2521,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn reject_duplicate_inputs() {
// Test vector from Bitcoin Core tx_invalid.json:
// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L50
@@ -2529,7 +2551,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn reject_output_value_sum_too_large() {
// Test vector taken from Bitcoin Core tx_invalid.json
// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L48
@@ -2545,7 +2568,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn accept_output_value_sum_equal_to_max_money() {
let tx_bytes = hex!("01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020080c6a47e8d0300015100c040b571e80300015100000000");
@@ -2559,7 +2583,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn reject_output_value_greater_than_max_money() {
// Test vector taken from Bitcoin Core tx_invalid.json
// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L44
@@ -2573,7 +2598,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn reject_transaction_with_no_outputs() {
// Test vector taken from Bitcoin Core tx_invalid.json
// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L36
@@ -3046,7 +3072,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn parse_out_point_txid_error() {
let err = ("z".repeat(64) + ":0").parse::<OutPoint>().unwrap_err();
assert!(matches!(err, ParseOutPointError::Txid(_)));
@@ -3057,7 +3084,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn parse_out_point_vout_error() {
let txid = "0".repeat(64);
@@ -3070,7 +3098,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn parse_out_point_format_error() {
let txid = "0".repeat(64);
let err = txid.parse::<OutPoint>().unwrap_err();
@@ -3082,7 +3111,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn parse_out_point_too_long_error() {
let txid = "0".repeat(64);
let err = format!("{}:{}", txid, "12345678900").parse::<OutPoint>().unwrap_err();
@@ -3094,7 +3124,8 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "alloc", feature = "hex"))]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
fn parse_out_point_vout_not_canonical_error() {
let txid = "0".repeat(64);
let err = format!("{}:{}", txid, "01").parse::<OutPoint>().unwrap_err();
Why this scored 15/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.