Skip to content

[params_manager] Uses std::sync::Mutex while every other manager uses tokio::sync::Mutex (deadlock risk across .await) #16

Description

@GideonBature

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:74pub 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions