Make test hash map iteration order configurable for deterministic runs
What changed, and why it matters
This commit adds a test-only option to make hash map iteration order deterministic. It does not change production code and has no security relevance. It is purely a testing convenience for comparing test logs across runs.
No security action required. This is a benign test infrastructure change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces a test-only RandomState wrapper in lightning/src/util/hash_tables.rs that, when the LDK_TEST_DETERMINISTIC_HASHES=1 environment variable is set, uses core::hash::SipHasher::new_with_keys(0, 0) instead of std::collections::hash_map::RandomState. The default behavior remains unchanged. The change is gated behind #[cfg(all(feature = "std", test))] and only affects test builds. No production code paths are modified.
Changed components
lightning/src/util/hash_tables.rs (test-only hasher module)Inspect captured patch +68 / −1
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e7825ac..d837c87 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -190,6 +190,8 @@ welcomed.
* `FULL_BLOCK_VIA_LISTEN`
* `FULL_BLOCK_DISCONNECTIONS_SKIPPING_VIA_LISTEN`
+* `LDK_TEST_DETERMINISTIC_HASHES` - When set to `1`, uses deterministic hash map iteration order in tests. This ensures consistent test output across runs, useful for comparing logs before and after changes.
+
C/C++ Bindings
--------------
diff --git a/lightning/src/util/hash_tables.rs b/lightning/src/util/hash_tables.rs
index 00341d5..b655597 100644
--- a/lightning/src/util/hash_tables.rs
+++ b/lightning/src/util/hash_tables.rs
@@ -6,10 +6,75 @@
pub use hashbrown::hash_map;
mod hashbrown_tables {
- #[cfg(feature = "std")]
+ #[cfg(all(feature = "std", not(test)))]
mod hasher {
pub use std::collections::hash_map::RandomState;
}
+ #[cfg(all(feature = "std", test))]
+ mod hasher {
+ #![allow(deprecated)] // hash::SipHasher was deprecated in favor of something only in std.
+ use core::hash::{BuildHasher, Hasher};
+
+ /// A [`BuildHasher`] for tests that supports deterministic behavior via environment variable.
+ ///
+ /// When `LDK_TEST_DETERMINISTIC_HASHES` is set, uses fixed keys for deterministic iteration.
+ /// Otherwise, delegates to std's RandomState for random hashing.
+ #[derive(Clone)]
+ pub enum RandomState {
+ Std(std::collections::hash_map::RandomState),
+ Deterministic,
+ }
+
+ impl RandomState {
+ pub fn new() -> RandomState {
+ if std::env::var("LDK_TEST_DETERMINISTIC_HASHES").map(|v| v == "1").unwrap_or(false)
+ {
+ RandomState::Deterministic
+ } else {
+ RandomState::Std(std::collections::hash_map::RandomState::new())
+ }
+ }
+ }
+
+ impl Default for RandomState {
+ fn default() -> RandomState {
+ RandomState::new()
+ }
+ }
+
+ /// A hasher wrapper that delegates to either std's DefaultHasher or a deterministic SipHasher.
+ pub enum RandomStateHasher {
+ Std(std::collections::hash_map::DefaultHasher),
+ Deterministic(core::hash::SipHasher),
+ }
+
+ impl Hasher for RandomStateHasher {
+ fn finish(&self) -> u64 {
+ match self {
+ RandomStateHasher::Std(h) => h.finish(),
+ RandomStateHasher::Deterministic(h) => h.finish(),
+ }
+ }
+ fn write(&mut self, bytes: &[u8]) {
+ match self {
+ RandomStateHasher::Std(h) => h.write(bytes),
+ RandomStateHasher::Deterministic(h) => h.write(bytes),
+ }
+ }
+ }
+
+ impl BuildHasher for RandomState {
+ type Hasher = RandomStateHasher;
+ fn build_hasher(&self) -> RandomStateHasher {
+ match self {
+ RandomState::Std(s) => RandomStateHasher::Std(s.build_hasher()),
+ RandomState::Deterministic => {
+ RandomStateHasher::Deterministic(core::hash::SipHasher::new_with_keys(0, 0))
+ },
+ }
+ }
+ }
+ }
#[cfg(not(feature = "std"))]
mod hasher {
#![allow(deprecated)] // hash::SipHasher was deprecated in favor of something only in std.
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.