0866b739d0
## Proposed Changes Clippy 1.67.0 put us on blast for the size of some of our errors, most of them written by me ( 👀 ). This PR shrinks the size of `BeaconChainError` by dropping some extraneous info and boxing an inner error which should only occur infrequently anyway. For the `AttestationSlashInfo` and `BlockSlashInfo` I opted to ignore the lint as they are always used in a `Result<A, Info>` where `A` is a similar size. This means they don't bloat the size of the `Result`, so it's a bit annoying for Clippy to report this as an issue. I also chose to ignore `clippy::uninlined-format-args` because I think the benefit-to-churn ratio is too low. E.g. sometimes we have long identifiers in `format!` args and IMO the non-inlined form is easier to read: ```rust // I prefer this... format!( "{} did {} to {}", REALLY_LONG_CONSTANT_NAME, ANOTHER_REALLY_LONG_CONSTANT_NAME, regular_long_identifier_name ); // To this format!("{REALLY_LONG_CONSTANT_NAME} did {ANOTHER_REALLY_LONG_CONSTANT_NAME} to {regular_long_identifier_name}"); ``` I tried generating an automatic diff with `cargo clippy --fix` but it came out at: ``` 250 files changed, 1209 insertions(+), 1469 deletions(-) ``` Which seems like a bad idea when we'd have to back-merge it to `capella` and `eip4844` 😱
98 lines
2.9 KiB
Rust
98 lines
2.9 KiB
Rust
//! Concurrency helpers for synchronising block proposal with fork choice.
|
|
//!
|
|
//! The transmitter provides a way for a thread runnning fork choice on a schedule to signal
|
|
//! to the receiver that fork choice has been updated for a given slot.
|
|
use crate::BeaconChainError;
|
|
use parking_lot::{Condvar, Mutex};
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
use types::Slot;
|
|
|
|
/// Sender, for use by the per-slot task timer.
|
|
pub struct ForkChoiceSignalTx {
|
|
pair: Arc<(Mutex<Slot>, Condvar)>,
|
|
}
|
|
|
|
/// Receiver, for use by the beacon chain waiting on fork choice to complete.
|
|
pub struct ForkChoiceSignalRx {
|
|
pair: Arc<(Mutex<Slot>, Condvar)>,
|
|
}
|
|
|
|
pub enum ForkChoiceWaitResult {
|
|
/// Successfully reached a slot greater than or equal to the awaited slot.
|
|
Success(Slot),
|
|
/// Fork choice was updated to a lower slot, indicative of lag or processing delays.
|
|
Behind(Slot),
|
|
/// Timed out waiting for the fork choice update from the sender.
|
|
TimeOut,
|
|
}
|
|
|
|
impl ForkChoiceSignalTx {
|
|
pub fn new() -> Self {
|
|
let pair = Arc::new((Mutex::new(Slot::new(0)), Condvar::new()));
|
|
Self { pair }
|
|
}
|
|
|
|
pub fn get_receiver(&self) -> ForkChoiceSignalRx {
|
|
ForkChoiceSignalRx {
|
|
pair: self.pair.clone(),
|
|
}
|
|
}
|
|
|
|
/// Signal to the receiver that fork choice has been updated to `slot`.
|
|
///
|
|
/// Return an error if the provided `slot` is strictly less than any previously provided slot.
|
|
pub fn notify_fork_choice_complete(&self, slot: Slot) -> Result<(), BeaconChainError> {
|
|
let (lock, condvar) = &*self.pair;
|
|
|
|
let mut current_slot = lock.lock();
|
|
|
|
if slot < *current_slot {
|
|
return Err(BeaconChainError::ForkChoiceSignalOutOfOrder {
|
|
current: *current_slot,
|
|
latest: slot,
|
|
});
|
|
} else {
|
|
*current_slot = slot;
|
|
}
|
|
|
|
// We use `notify_all` because there may be multiple block proposals waiting simultaneously.
|
|
// Usually there'll be 0-1.
|
|
condvar.notify_all();
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Default for ForkChoiceSignalTx {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl ForkChoiceSignalRx {
|
|
pub fn wait_for_fork_choice(&self, slot: Slot, timeout: Duration) -> ForkChoiceWaitResult {
|
|
let (lock, condvar) = &*self.pair;
|
|
|
|
let mut current_slot = lock.lock();
|
|
|
|
// Wait for `current_slot >= slot`.
|
|
//
|
|
// Do not loop and wait, if we receive an update for the wrong slot then something is
|
|
// quite out of whack and we shouldn't waste more time waiting.
|
|
if *current_slot < slot {
|
|
let timeout_result = condvar.wait_for(&mut current_slot, timeout);
|
|
|
|
if timeout_result.timed_out() {
|
|
return ForkChoiceWaitResult::TimeOut;
|
|
}
|
|
}
|
|
|
|
if *current_slot >= slot {
|
|
ForkChoiceWaitResult::Success(*current_slot)
|
|
} else {
|
|
ForkChoiceWaitResult::Behind(*current_slot)
|
|
}
|
|
}
|
|
}
|