Open
Conversation
Initial empty commit to open draft PR for tracking. Closes shieldedtech/shielded-security-engineering#114 Signed-off-by: Mike Clay <mike.clay@shielded.io>
…-059) `LedgerContext::with_wallets_from_seeds` previously acquired the wallets mutex twice in sequence, deadlocking on the second `lock()` because `std::sync::Mutex` is not reentrant. The function now acquires the lock exactly once and uses `HashMap::get_disjoint_mut` to obtain two disjoint `&mut Wallet<D>` references from a single `MutexGuard`, mirroring the locking shape of the sibling `with_wallet_from_seed`. The same-seed-twice case is rejected up front with a clear `assert!` panic (cannot produce two disjoint `&mut` to the same wallet); a missing seed panics with a message matching the existing `wallet_for_seed` style. Adds three regression tests in `mod tests` of `context.rs`: - `with_wallets_from_seeds_does_not_deadlock` — runs the call on a worker thread and joins via `recv_timeout(5s)` on an `mpsc` channel to discriminate "fixed" from "still hung". - `with_wallets_from_seeds_panics_on_aliased_seed` — `#[should_panic]` on `"origin_seed and destination_seed must differ"`. - `with_wallets_from_seeds_panics_on_missing_seed` — `#[should_panic]` on `"Wallet with seed"`. Includes a `changes/node/changed/PM-21800-...` change file referencing PR #1471 and JIRA PM-21800. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Mike Clay <mike.clay@shielded.io>
…m_seeds panic Addresses M-1 from post-impl-review: the missing-seed panic in with_wallets_from_seeds previously listed both origin and destination seeds, conflating two failure modes. Now matches the existing wallet_for_seed style and names only the absent seed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Mike Clay <mike.clay@shielded.io>
…tests Resolves clippy::cloned_ref_to_slice_refs at the regression-test call sites for with_wallets_from_seeds. The closure does not need ownership of the seed values, so a one-element slice via std::slice::from_ref avoids the clone and satisfies the lint under -D warnings at workspace scope. Signed-off-by: Mike Clay <mike.clay@shielded.io>
Add an Issue: line pointing at shieldedtech/shielded-security-engineering#114 so the change fragment links back to the upstream tracker. Sibling fragments use full URLs for PR and JIRA links; the cross-repo issue is included in the same form (a Closes: #114 line would refer to the wrong repository). Signed-off-by: Mike Clay <mike.clay@shielded.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix the guaranteed deadlock in
with_wallets_from_seeds(R-059) by restructuring mutex acquisition so the same non-reentrantstd::sync::Mutexis no longer locked twice while a guard is still alive. The function now acquiresself.walletsexactly once and produces two disjoint&mut Wallet<D>references from one guard viaHashMap::get_disjoint_mut.🎫 Issue 📐 Engineering
Motivation
with_wallets_from_seedsinledger/helpers/src/versions/common/context.rscalledself.wallets.lock()and took a&mut Walletreference from the resulting guard, then attempted to lock the same non-reentrantstd::sync::Mutexa second time. The first guard could not drop becauseorigin_walletborrowed from it, so the second.lock()deadlocked unconditionally on every invocation. The function is called fromtransient.rs:49, making any code path that triggers it a guaranteed hang.Eliminating the deadlock is required before any feature work that depends on
with_wallets_from_seedscan run reliably, and before tests covering this code path can be exercised end-to-end.Changes
ledger/helpers/src/versions/common/context.rs— body rewrite ofwith_wallets_from_seeds:self.wallets.lock()exactly once. The two disjoint&mut Wallet<D>references are obtained from a single guard viaHashMap::get_disjoint_mut([&origin_seed, &destination_seed])(stable since Rust 1.86; workspace pin is 1.95).assert!(origin_seed != destination_seed, ...)so aliased-seed misuse panics with a specific message ("origin_seed and destination_seed must differ") before the lock is taken, rather than producing the opaqueNonethatget_disjoint_mutreturns for aliased keys.Noneto a panic whose message style matches the existingwallet_for_seedpanic ("Wallet with seed ...").FnOnce(&mut Wallet<D>, &mut Wallet<D>) -> Ris preserved; the single live caller (transient.rs:49) compiles unchanged.Regression tests (added to the existing
#[cfg(test)] mod testsblock):with_wallets_from_seeds_does_not_deadlock— runs the fixed call on a worker thread and joins viampsc::recv_timeout(Duration::from_secs(5)). The 5s wall-clock deadline is several orders of magnitude above the expected return time but well below any plausible CI hard timeout, so it cleanly discriminates "fixed" from "still hung". Also asserts the closure side-effect (anAtomicU64counter) was observed.with_wallets_from_seeds_panics_on_aliased_seed—#[should_panic(expected = "origin_seed and destination_seed must differ")]pins the new aliased-seed panic message.with_wallets_from_seeds_panics_on_missing_seed—#[should_panic(expected = "Wallet with seed")]pins the missing-seed panic message.changes/node/changed/PM-21800-r059-deadlock-with-wallets-from-seeds.md— new change file with#ledger #helperstags, summary of bug + fix shape, and PR / JIRA links.📌 Submission Checklist
🔱 Fork Strategy
🗹 TODO before merging