From e4a968dfe4dc97aac834551e38fdf81073e4afe5 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 23 May 2026 06:52:07 +0000 Subject: [PATCH] fix: stop lowercasing CodeHash::encode Base58 output The BITCOIN Base58 alphabet is case-sensitive, so lowercasing the encoded output corrupted any hash containing uppercase characters and broke the encode -> ContractKey::from_params roundtrip, which decodes with the same case-sensitive alphabet. This aligns CodeHash::encode with ContractInstanceId::encode, ContractKey::encoded_code_hash, and ContractCode::hash_str, which already preserve case. Fixes freenet/freenet-core#4214 https://claude.ai/code/session_01ViYSqfF3NwQBiaVkzkWET6 --- CHANGELOG.md | 12 ++++++++++++ rust/src/code_hash.rs | 26 +++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13ae572..5d3b9c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [0.8.0] + +### Fixed +- `CodeHash::encode` no longer lowercases its Base58 output. The + BITCOIN alphabet is case-sensitive, so lowercasing corrupted the + bytes for any hash whose encoding contained uppercase characters and + broke the `encode` → `ContractKey::from_params` roundtrip (which + decodes with the same case-sensitive alphabet). `CodeHash::encode` + now matches `ContractInstanceId::encode`, + `ContractKey::encoded_code_hash`, and `ContractCode::hash_str`, all + of which already preserved case. See freenet/freenet-core#4214. + ## [0.7.0] ### Fixed (wire-format break in `NodeDiagnosticsResponse`) diff --git a/rust/src/code_hash.rs b/rust/src/code_hash.rs index dbd0356..3fd5836 100644 --- a/rust/src/code_hash.rs +++ b/rust/src/code_hash.rs @@ -32,7 +32,6 @@ impl CodeHash { bs58::encode(self.0) .with_alphabet(bs58::Alphabet::BITCOIN) .into_string() - .to_lowercase() } } @@ -80,3 +79,28 @@ impl std::fmt::Debug for CodeHash { f.debug_tuple("CodeHash").field(&self.encode()).finish() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn encode_roundtrips_with_case_sensitive_alphabet() { + // Bytes chosen so the base58 encoding contains uppercase characters, + // which a lowercasing `encode` would corrupt. + let original = CodeHash([0xFF; CONTRACT_KEY_SIZE]); + let encoded = original.encode(); + assert!( + encoded.chars().any(|c| c.is_ascii_uppercase()), + "test fixture must contain uppercase base58 chars, got {encoded}" + ); + + let mut decoded = [0u8; CONTRACT_KEY_SIZE]; + bs58::decode(&encoded) + .with_alphabet(bs58::Alphabet::BITCOIN) + .onto(&mut decoded) + .expect("encoded CodeHash must decode with the BITCOIN alphabet"); + + assert_eq!(original.0, decoded); + } +}