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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions