Version
latest (next branch)
Other packages versions
miden-client: latest (next branch)
What happened?
authentication_staleness_check in crates/block-producer/src/mempool/mod.rs uses assert! for the upper-bound check instead of returning a typed error:
assert!(
authentication_height <= self.chain_tip(),
"Authentication height {authentication_height} exceeded the chain tip {}",
self.chain_tip()
);
If a client submits a transaction with authentication_height above the current chain tip (race condition or malformed request), this panics while the Mutex<Mempool> lock is held. A panic while holding a mutex causes it to become poisoned. All subsequent SharedMempool::lock() calls then return MempoolPoisonError, which propagates as a fatal error throughout the entire block producer making it permanently unavailable.
What should have happened?
The upper-bound check should return a typed Err like the lower-bound check directly above it does:
// Lower bound correct:
if authentication_height < limit {
return Err(MempoolSubmissionError::StaleInputs { .. });
}
// Upper bound should also return Err, not panic:
if authentication_height > self.chain_tip() {
return Err(MempoolSubmissionError::StaleInputs { .. });
}
This way a malformed or racing transaction is rejected cleanly without crashing the block producer.
How can this be reproduced?
- Run a block producer node
- Submit a transaction where
authentication_height is set to a block number higher than the current chain tip (e.g. chain tip = 100, authentication_height = 200)
- The block producer panics and the mempool mutex becomes poisoned
- All subsequent transaction submissions fail with a poison error until the process is restarted
Relevant log output
Version
latest (next branch)
Other packages versions
miden-client: latest (next branch)
What happened?
authentication_staleness_checkincrates/block-producer/src/mempool/mod.rsusesassert!for the upper-bound check instead of returning a typed error:If a client submits a transaction with
authentication_heightabove the current chain tip (race condition or malformed request), this panics while theMutex<Mempool>lock is held. A panic while holding a mutex causes it to become poisoned. All subsequentSharedMempool::lock()calls then returnMempoolPoisonError, which propagates as a fatal error throughout the entire block producer making it permanently unavailable.What should have happened?
The upper-bound check should return a typed
Errlike the lower-bound check directly above it does:This way a malformed or racing transaction is rejected cleanly without crashing the block producer.
How can this be reproduced?
authentication_heightis set to a block number higher than the current chain tip (e.g. chain tip = 100, authentication_height = 200)Relevant log output