refactor(zcash): display shielded pool names
What changed, and why it matters
This commit is a small code cleanup in the Zcash transaction handling code. It replaces a custom `label()` method on the `ShieldedPool` type with Rust's standard `Display` trait, so the pool name prints the same way in error messages. There is no security-relevant change: the strings shown to users remain identical ('Orchard' and 'Ironwood'), and no transaction validation logic is altered.
No security action required. Treat as a normal maintainability refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors ShieldedPool in rust/apps/zcash/src/pczt/mod.rs to implement core::fmt::Display instead of a bespoke label(self) -> &'static str method. Call sites in check.rs, mod.rs, parse.rs, and sign.rs are updated from pool.label() to pool, relying on implicit Display formatting in format! and error strings. The emitted labels are unchanged. No cryptographic checks, parsing rules, or signing behavior are modified.
Changed components
rust/apps/zcash/src/pczt/mod.rsrust/apps/zcash/src/pczt/check.rsrust/apps/zcash/src/pczt/parse.rsrust/apps/zcash/src/pczt/sign.rsInspect captured patch +16 / −19
diff --git a/rust/apps/zcash/src/pczt/check.rs b/rust/apps/zcash/src/pczt/check.rs
index 7acd520..ca9d8f7 100644
--- a/rust/apps/zcash/src/pczt/check.rs
+++ b/rust/apps/zcash/src/pczt/check.rs
@@ -396,7 +396,7 @@ fn check_shielded_bundle<P: consensus::Parameters>(
bundle: &orchard::pczt::Bundle,
pool: ShieldedPool,
) -> Result<(), ZcashError> {
- let pool_label = pool.label();
+ let pool_label = pool;
let fvk = ufvk.orchard().ok_or(ZcashError::InvalidDataError(
"orchard fvk is not present".to_string(),
))?;
@@ -446,7 +446,7 @@ fn check_and_parse_shielded_bundle<P: consensus::Parameters>(
pool: ShieldedPool,
checked_actions: &mut alloc::vec::Vec<ShieldedAction>,
) -> Result<Option<ParsedOrchard>, ZcashError> {
- let pool_label = pool.label();
+ let pool_label = pool;
let fvk = ufvk.orchard().ok_or(ZcashError::InvalidDataError(
"orchard fvk is not present".to_string(),
))?;
@@ -537,7 +537,7 @@ fn check_action<P: consensus::Parameters>(
flags: &orchard::bundle::Flags,
pool: ShieldedPool,
) -> Result<ParsedTo, ZcashError> {
- let pool_label = pool.label();
+ let pool_label = pool;
// Check `cv_net` first so we know that the `value` fields for both the spend and the
// output are present and correct.
action.verify_cv_net().map_err(|e| {
@@ -565,7 +565,7 @@ fn check_action_spend<P: consensus::Parameters>(
spend: &orchard::pczt::Spend,
pool: ShieldedPool,
) -> Result<(), ZcashError> {
- let pool_label = pool.label();
+ let pool_label = pool;
if let (Some(value), Some(zip32_derivation)) = (spend.value(), spend.zip32_derivation()) {
if value.inner() != 0 && zip32_derivation.seed_fingerprint() == seed_fingerprint {
let matched_account = super::matching_seed_supported_orchard_account(
@@ -622,7 +622,7 @@ fn check_action_output<P: consensus::Parameters>(
flags: &orchard::bundle::Flags,
pool: ShieldedPool,
) -> Result<ParsedTo, ZcashError> {
- let pool_label = pool.label();
+ let pool_label = pool;
action
.output()
.verify_note_commitment(action.spend())
@@ -651,15 +651,12 @@ fn check_restricted_zero_value_output(
}
let recipient = action.output().recipient().ok_or_else(|| {
- ZcashError::InvalidPczt(format!(
- "missing recipient for funded {} output",
- pool.label()
- ))
+ ZcashError::InvalidPczt(format!("missing recipient for funded {} output", pool))
})?;
if !super::parse::is_wallet_orchard_address(keys, &recipient)? {
return Err(ZcashError::InvalidPczt(format!(
"funded {} output paired with a zero-value spend does not belong to the selected account",
- pool.label()
+ pool
)));
}
diff --git a/rust/apps/zcash/src/pczt/mod.rs b/rust/apps/zcash/src/pczt/mod.rs
index 30fb485..5e236b2 100644
--- a/rust/apps/zcash/src/pczt/mod.rs
+++ b/rust/apps/zcash/src/pczt/mod.rs
@@ -146,11 +146,11 @@ pub(crate) enum ShieldedPool {
}
#[cfg(feature = "cypherpunk")]
-impl ShieldedPool {
- pub(crate) fn label(self) -> &'static str {
+impl core::fmt::Display for ShieldedPool {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
- ShieldedPool::Orchard => "Orchard",
- ShieldedPool::Ironwood => "Ironwood",
+ ShieldedPool::Orchard => f.write_str("Orchard"),
+ ShieldedPool::Ironwood => f.write_str("Ironwood"),
}
}
}
@@ -189,7 +189,7 @@ pub(crate) fn matching_seed_supported_orchard_account_parts(
coin_type: u32,
pool: ShieldedPool,
) -> Result<Option<zcash_vendor::zip32::AccountId>, crate::errors::ZcashError> {
- let pool_label = pool.label();
+ let pool_label = pool;
let Some((derivation_seed_fingerprint, derivation_path)) = derivation else {
return Ok(None);
};
diff --git a/rust/apps/zcash/src/pczt/parse.rs b/rust/apps/zcash/src/pczt/parse.rs
index 1eef6b1..26d87d0 100644
--- a/rust/apps/zcash/src/pczt/parse.rs
+++ b/rust/apps/zcash/src/pczt/parse.rs
@@ -191,7 +191,7 @@ pub(crate) fn decode_output_enc_ciphertext(
})
} else {
// If we reached here, none of our OVKs matched; recover directly as the fallback.
- let pool_label = pool.label();
+ let pool_label = pool;
let recipient = action.output().recipient().ok_or_else(|| {
ZcashError::InvalidPczt(format!("Missing recipient field for {pool_label} action"))
@@ -705,7 +705,7 @@ pub(crate) fn parse_orchard_output<P: consensus::Parameters>(
action: &orchard::pczt::Action,
pool: ShieldedPool,
) -> Result<ParsedTo, ZcashError> {
- let pool_label = pool.label();
+ let pool_label = pool;
let output = action.output();
// we should verify the cv_net in checking phrase, the transaction checking should failed if the net value is not correct
diff --git a/rust/apps/zcash/src/pczt/sign.rs b/rust/apps/zcash/src/pczt/sign.rs
index ec079b5..023c862 100644
--- a/rust/apps/zcash/src/pczt/sign.rs
+++ b/rust/apps/zcash/src/pczt/sign.rs
@@ -256,7 +256,7 @@ impl<'a> SeedSigner<'a> {
|e| {
ZcashError::SigningError(format!(
"failed to derive {} spending key: {e:?}",
- self.pool.label()
+ self.pool
))
},
)?,
@@ -324,7 +324,7 @@ impl PcztSigner for SeedSigner<'_> {
// Strict per-action validation, ported verbatim from the previous
// collect_orchard_bundle_signing_keys so the lean signer keeps identical
// skip/reject semantics to the RoleSigner path.
- let pool_label = self.pool.label();
+ let pool_label = self.pool;
if action.spend().spend_auth_sig().is_some() {
return Ok(());
}
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.