block_state_inner.rs
Overview
This file defines the BlockStateInner struct and implements concurrency-safe access patterns for managing the mutable state of a blockchain block. It encapsulates shared mutable access to an internal block state (AckiNackiBlockState) alongside a block identifier (BlockIdentifier). The primary functionality revolves around synchronized read and write access using a read-write lock (RwLock), enabling safe concurrent operations on the block state within multiple threads.
The file also provides trait implementations for hashing and equality comparison based on the block identifier. Additionally, it implements the Guarded, GuardedMut, and TryGuardedMut traits for the concurrency-safe access abstraction, which allow executing closures over immutable or mutable references of the inner state. Optional instrumentation for detecting long lock hold times is conditionally included via feature flags.
Structures and Traits
BlockStateInner
pub struct BlockStateInner {
pub(super) block_identifier: BlockIdentifier,
pub(super) shared_access: RwLock<AckiNackiBlockState>,
}
Purpose: Holds the unique identifier of a block and a thread-safe mutable reference to its state.
Fields:
block_identifier: Uniquely identifies the block. Used for hash and equality operations.shared_access: A read-write lock protecting access to the internalAckiNackiBlockState.
Visibility: Fields are
pub(super), i.e., public within the current module and its submodules.
Trait Implementations
Hash for BlockStateInner
impl Hash for BlockStateInner {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.block_identifier.hash(state)
}
}
Implements hashing by delegating to the block identifier's hash.
Enables use in hash-based collections keyed by block identity.
PartialEq and Eq for BlockStateInner
impl PartialEq for BlockStateInner {
fn eq(&self, other: &Self) -> bool {
self.block_identifier == other.block_identifier
}
}
impl Eq for BlockStateInner {}
Equality is determined solely by comparing the block identifiers.
This behavior ensures that blocks with the same identifier are considered equal regardless of internal state.
Concurrency and Guarded Access Traits
The file implements the following traits for Arc<BlockStateInner>, enabling safe concurrent access to the internal state:
Guarded<AckiNackiBlockState>— for immutable accessGuardedMut<AckiNackiBlockState>— for mutable accessTryGuardedMut<AckiNackiBlockState>— for fallible mutable access
These traits come from the crate::utilities::guarded module and provide controlled access via closures.
Guarded<AckiNackiBlockState>
impl Guarded<AckiNackiBlockState> for Arc<BlockStateInner> {
#[track_caller]
fn guarded<F, T>(&self, action: F) -> T
where
F: FnOnce(&AckiNackiBlockState) -> T,
{
let guard = self.shared_access.read();
// Optional instrumentation for detecting long locks
#[cfg(feature = "fail_on_long_lock")]
let start = std::time::Instant::now();
let result = action(&guard);
drop(guard);
#[cfg(feature = "fail_on_long_lock")]
if start.elapsed() > std::time::Duration::from_millis(MAX_LOCK_TIME_MS) {
eprintln!("{:?}", std::backtrace::Backtrace::force_capture());
eprintln!("Block state lock has taken too long");
// panic!("Block state lock has taken too long");
}
result
}
}
Acquires a shared (read) lock on the block state.
Executes the provided closure with an immutable reference to the state.
Drops the lock after execution.
If compiled with the
fail_on_long_lockfeature, logs a backtrace when the lock is held for longer than the configured threshold (MAX_LOCK_TIME_MS = 20ms).
Usage Example:
let block_state: Arc<BlockStateInner> = ...;
let block_id = block_state.guarded(|state| state.get_id());
GuardedMut<AckiNackiBlockState>
impl GuardedMut<AckiNackiBlockState> for Arc<BlockStateInner> {
#[track_caller]
fn guarded_mut<F, T>(&self, action: F) -> T
where
F: FnOnce(&mut AckiNackiBlockState) -> T,
{
let mut guard = self.shared_access.write();
#[cfg(feature = "fail_on_long_lock")]
let start = std::time::Instant::now();
let result = guard.inner_guarded_mut(action);
drop(guard);
#[cfg(feature = "fail_on_long_lock")]
if start.elapsed() > std::time::Duration::from_millis(MAX_LOCK_TIME_MS) {
eprintln!("{:?}", std::backtrace::Backtrace::force_capture());
panic!("Block state lock has taken too long");
}
result
}
}
Acquires an exclusive (write) lock on the block state.
Executes the closure with a mutable reference to the state, delegated through
inner_guarded_mutmethod onAckiNackiBlockState.Releases the lock after completion.
Enforces the same optional instrumentation for long lock durations, but panics instead of just logging.
Usage Example:
block_state.guarded_mut(|state| {
state.update_field(new_value);
});
TryGuardedMut<AckiNackiBlockState>
impl TryGuardedMut<AckiNackiBlockState> for Arc<BlockStateInner> {
#[track_caller]
fn try_guarded_mut<F, T>(&self, action: F) -> Option<T>
where
F: FnOnce(&mut AckiNackiBlockState) -> T,
{
self.shared_access.try_write().map(|mut guard| guard.inner_guarded_mut(action))
}
}
Attempts to acquire a non-blocking exclusive lock.
If successful, executes the closure on the mutable state and returns
Some(result).If the lock is not available, immediately returns
None.This enables conditional mutation attempts without blocking the calling thread.
Usage Example:
if let Some(result) = block_state.try_guarded_mut(|state| state.modify_something()) {
// Mutation succeeded
} else {
// Could not acquire lock for mutation
}
Implementation Details
The
BlockStateInnerstruct usesparking_lot::RwLockfor efficient synchronization primitives.The internal state is stored in
AckiNackiBlockState, which is expected to provide aninner_guarded_mutmethod for controlled mutable access.The file uses Rust's standard traits
Hash,PartialEq, andEqto allowBlockStateInnerinstances to be used in hash maps or sets keyed by block identity.The optional feature
fail_on_long_lockenables runtime detection of excessive lock holding durations to aid debugging and prevent deadlocks or performance degradation.The concurrency patterns follow a guard-based approach where closures encapsulate the logic operating on the guarded state, ensuring lock acquisition and release are correctly paired.
Interaction with Other Components
Depends on the
AckiNackiBlockStatestruct defined in the sibling modulestate.Uses
BlockIdentifierfromcrate::typesto uniquely identify blocks.Implements traits from
crate::utilities::guardedto provide a uniform interface for guarded access, which is likely used elsewhere in the system for state mutations or queries.The use of
ArcwrappingBlockStateInnersuggests this struct is shared across multiple threads or asynchronous tasks.The guarded access pattern aligns with typical concurrency control in larger stateful systems, allowing safe parallel read access and exclusive write access.
Mermaid Diagram
classDiagram
class BlockStateInner {
-block_identifier: BlockIdentifier
-shared_access: RwLock<AckiNackiBlockState>
}
class ArcBlockStateInner {
+guarded()
+guarded_mut()
+try_guarded_mut()
}
BlockStateInner <.. ArcBlockStateInner : wraps
ArcBlockStateInner ..|> Guarded
ArcBlockStateInner ..|> GuardedMut
ArcBlockStateInner ..|> TryGuardedMut
This diagram illustrates the core struct BlockStateInner and its concurrency-safe access via Arc<BlockStateInner> implementing the guarded access traits. The private fields and the key methods for guarded access are highlighted, showing the encapsulation and trait-based interface.