Summary
ParamsManager is the only storage manager in src/inscriptive/ guarded by std::sync::Mutex instead of tokio::sync::Mutex. All ten other managers (CoinManager, StateManager, Registry, FlameManager, PrivilegesManager, Graveyard, ArchivalManager, UTXOSet, SyncManager, and the params delta/backup) use tokio::sync::Mutex. Holding a std::sync::Mutex across an .await (or holding it while another task awaits) can deadlock the async runtime; even when it doesn't, it blocks a worker thread for the entire critical section.
Affected file(s)
src/inscriptive/params_manager/params_manager.rs
Location
src/inscriptive/params_manager/params_manager.rs:4:
use std::sync::{Arc, Mutex};
src/inscriptive/params_manager/params_manager.rs:33:
#[allow(non_camel_case_types)]
pub type PARAMS_MANAGER = Arc<Mutex<ParamsManager>>; // std::sync::Mutex
For contrast, every sibling manager's type alias is Arc<tokio::sync::Mutex<...>>, e.g.:
coin_manager.rs:74 → pub type COIN_MANAGER = Arc<Mutex<CoinManager>>; with use tokio::sync::Mutex; at coin_manager.rs:29
state_manager.rs, registry.rs:95, flame_manager.rs:46, privileges_manager.rs:62, graveyard.rs:43, archival_manager.rs:50, utxo_set.rs:38, sync_manager.rs:30 — all tokio::sync::Mutex.
Root cause / analysis
std::sync::Mutex is fine only if it is never held across an .await and never held for long. In an async codebase where the manager is shared across tasks, std::sync::Mutex:
- Deadlocks if the holding task is suspended by the runtime while it still holds the guard (another task on the same worker blocks forever waiting for it).
- Blocks the executor thread, not just the logical task — under contention this stalls unrelated futures on that worker.
Even if today's call sites only do cheap in-memory/disk reads under the lock and don't .await while holding it, the type signature invites a future caller to do so, and the inconsistency with the rest of the layer is a maintenance hazard. clippy even has a lint for the "held across await" case (await_holding_lock) which only trips for std locks; switching to tokio::sync::Mutex makes the contract uniform.
Impact
- Latent deadlock / executor stall under contention or if a call site ever awaits while holding the params lock.
- Inconsistency: every other manager is await-safe; this one silently isn't.
Summary
ParamsManageris the only storage manager insrc/inscriptive/guarded bystd::sync::Mutexinstead oftokio::sync::Mutex. All ten other managers (CoinManager,StateManager,Registry,FlameManager,PrivilegesManager,Graveyard,ArchivalManager,UTXOSet,SyncManager, and the params delta/backup) usetokio::sync::Mutex. Holding astd::sync::Mutexacross an.await(or holding it while another task awaits) can deadlock the async runtime; even when it doesn't, it blocks a worker thread for the entire critical section.Affected file(s)
src/inscriptive/params_manager/params_manager.rsLocation
src/inscriptive/params_manager/params_manager.rs:4:src/inscriptive/params_manager/params_manager.rs:33:For contrast, every sibling manager's type alias is
Arc<tokio::sync::Mutex<...>>, e.g.:coin_manager.rs:74→pub type COIN_MANAGER = Arc<Mutex<CoinManager>>;withuse tokio::sync::Mutex;atcoin_manager.rs:29state_manager.rs,registry.rs:95,flame_manager.rs:46,privileges_manager.rs:62,graveyard.rs:43,archival_manager.rs:50,utxo_set.rs:38,sync_manager.rs:30— alltokio::sync::Mutex.Root cause / analysis
std::sync::Mutexis fine only if it is never held across an.awaitand never held for long. In an async codebase where the manager is shared across tasks,std::sync::Mutex:Even if today's call sites only do cheap in-memory/disk reads under the lock and don't
.awaitwhile holding it, the type signature invites a future caller to do so, and the inconsistency with the rest of the layer is a maintenance hazard.clippyeven has a lint for the "held across await" case (await_holding_lock) which only trips forstdlocks; switching totokio::sync::Mutexmakes the contract uniform.Impact