mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-28 02:03:32 +00:00
Merge remote-tracking branch 'origin/unstable' into tree-states
This commit is contained in:
@@ -1233,17 +1233,17 @@ impl BeaconNodeHttpClient {
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
) -> Result<ForkVersionedResponse<BeaconBlock<T, Payload>>, Error> {
|
||||
self.get_validator_blocks_with_verify_randao(slot, Some(randao_reveal), graffiti, None)
|
||||
self.get_validator_blocks_modular(slot, randao_reveal, graffiti, SkipRandaoVerification::No)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blocks/{slot}`
|
||||
pub async fn get_validator_blocks_with_verify_randao<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
pub async fn get_validator_blocks_modular<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: Option<&SignatureBytes>,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
verify_randao: Option<bool>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
) -> Result<ForkVersionedResponse<BeaconBlock<T, Payload>>, Error> {
|
||||
let mut path = self.eth_path(V2)?;
|
||||
|
||||
@@ -1253,19 +1253,17 @@ impl BeaconNodeHttpClient {
|
||||
.push("blocks")
|
||||
.push(&slot.to_string());
|
||||
|
||||
if let Some(randao_reveal) = randao_reveal {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("randao_reveal", &randao_reveal.to_string());
|
||||
}
|
||||
path.query_pairs_mut()
|
||||
.append_pair("randao_reveal", &randao_reveal.to_string());
|
||||
|
||||
if let Some(graffiti) = graffiti {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("graffiti", &graffiti.to_string());
|
||||
}
|
||||
|
||||
if let Some(verify_randao) = verify_randao {
|
||||
if skip_randao_verification == SkipRandaoVerification::Yes {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("verify_randao", &verify_randao.to_string());
|
||||
.append_pair("skip_randao_verification", "");
|
||||
}
|
||||
|
||||
self.get(path).await
|
||||
@@ -1278,25 +1276,22 @@ impl BeaconNodeHttpClient {
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
) -> Result<ForkVersionedResponse<BeaconBlock<T, Payload>>, Error> {
|
||||
self.get_validator_blinded_blocks_with_verify_randao(
|
||||
self.get_validator_blinded_blocks_modular(
|
||||
slot,
|
||||
Some(randao_reveal),
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
None,
|
||||
SkipRandaoVerification::No,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v1/validator/blinded_blocks/{slot}`
|
||||
pub async fn get_validator_blinded_blocks_with_verify_randao<
|
||||
T: EthSpec,
|
||||
Payload: ExecPayload<T>,
|
||||
>(
|
||||
pub async fn get_validator_blinded_blocks_modular<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: Option<&SignatureBytes>,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
verify_randao: Option<bool>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
) -> Result<ForkVersionedResponse<BeaconBlock<T, Payload>>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
@@ -1306,19 +1301,17 @@ impl BeaconNodeHttpClient {
|
||||
.push("blinded_blocks")
|
||||
.push(&slot.to_string());
|
||||
|
||||
if let Some(randao_reveal) = randao_reveal {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("randao_reveal", &randao_reveal.to_string());
|
||||
}
|
||||
path.query_pairs_mut()
|
||||
.append_pair("randao_reveal", &randao_reveal.to_string());
|
||||
|
||||
if let Some(graffiti) = graffiti {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("graffiti", &graffiti.to_string());
|
||||
}
|
||||
|
||||
if let Some(verify_randao) = verify_randao {
|
||||
if skip_randao_verification == SkipRandaoVerification::Yes {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("verify_randao", &verify_randao.to_string());
|
||||
.append_key_only("skip_randao_verification");
|
||||
}
|
||||
|
||||
self.get(path).await
|
||||
|
||||
@@ -658,16 +658,34 @@ pub struct ProposerData {
|
||||
pub slot: Slot,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct ValidatorBlocksQuery {
|
||||
pub randao_reveal: Option<SignatureBytes>,
|
||||
pub randao_reveal: SignatureBytes,
|
||||
pub graffiti: Option<Graffiti>,
|
||||
#[serde(default = "default_verify_randao")]
|
||||
pub verify_randao: bool,
|
||||
pub skip_randao_verification: SkipRandaoVerification,
|
||||
}
|
||||
|
||||
fn default_verify_randao() -> bool {
|
||||
true
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize)]
|
||||
#[serde(try_from = "Option<String>")]
|
||||
pub enum SkipRandaoVerification {
|
||||
Yes,
|
||||
#[default]
|
||||
No,
|
||||
}
|
||||
|
||||
/// Parse a `skip_randao_verification` query parameter.
|
||||
impl TryFrom<Option<String>> for SkipRandaoVerification {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(opt: Option<String>) -> Result<Self, String> {
|
||||
match opt.as_deref() {
|
||||
None => Ok(SkipRandaoVerification::No),
|
||||
Some("") => Ok(SkipRandaoVerification::Yes),
|
||||
Some(s) => Err(format!(
|
||||
"skip_randao_verification does not take a value, got: {s}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
|
||||
9
common/oneshot_broadcast/Cargo.toml
Normal file
9
common/oneshot_broadcast/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "oneshot_broadcast"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
parking_lot = "0.12.0"
|
||||
190
common/oneshot_broadcast/src/lib.rs
Normal file
190
common/oneshot_broadcast/src/lib.rs
Normal file
@@ -0,0 +1,190 @@
|
||||
//! Provides a single-sender, multiple receiver one-shot channel where any message sent will be
|
||||
//! received by all senders.
|
||||
//!
|
||||
//! This implementation may not be blazingly fast but it should be simple enough to be reliable.
|
||||
use parking_lot::{Condvar, Mutex};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
SenderDropped,
|
||||
}
|
||||
|
||||
enum Future<T> {
|
||||
/// The future is ready and the item may be consumed.
|
||||
Ready(T),
|
||||
/// Future is not ready.
|
||||
NotReady,
|
||||
/// The sender has been dropped without sending a message.
|
||||
SenderDropped,
|
||||
}
|
||||
|
||||
struct MutexCondvar<T> {
|
||||
mutex: Mutex<Future<T>>,
|
||||
condvar: Condvar,
|
||||
}
|
||||
|
||||
/// The sending pair of the `oneshot` channel.
|
||||
pub struct Sender<T>(Arc<MutexCondvar<T>>);
|
||||
|
||||
impl<T> Sender<T> {
|
||||
/// Send a message, consuming `self` and delivering the message to *all* receivers.
|
||||
pub fn send(self, item: T) {
|
||||
*self.0.mutex.lock() = Future::Ready(item);
|
||||
// Condvar notification will be handled by the `Drop` implementation.
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Sender<T> {
|
||||
/// Flag the sender as dropped and notify all receivers.
|
||||
fn drop(&mut self) {
|
||||
let mut lock = self.0.mutex.lock();
|
||||
if !matches!(*lock, Future::Ready(_)) {
|
||||
*lock = Future::SenderDropped
|
||||
}
|
||||
self.0.condvar.notify_all();
|
||||
// The lock must be held whilst the condvar is notified.
|
||||
drop(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/// The receiving pair of the `oneshot` channel. Always receives the message sent by the `Sender`
|
||||
/// (if any).
|
||||
#[derive(Clone)]
|
||||
pub struct Receiver<T: Clone>(Arc<MutexCondvar<T>>);
|
||||
|
||||
impl<T: Clone> Receiver<T> {
|
||||
/// Check to see if there is a message to be read *without* blocking/waiting.
|
||||
///
|
||||
/// ## Note
|
||||
///
|
||||
/// This method will technically perform *some* blocking to access a `Mutex`. It is non-blocking
|
||||
/// in the sense that it won't block until a message is received (i.e., it may return `Ok(None)`
|
||||
/// if no message has been sent yet).
|
||||
pub fn try_recv(&self) -> Result<Option<T>, Error> {
|
||||
match &*self.0.mutex.lock() {
|
||||
Future::Ready(item) => Ok(Some(item.clone())),
|
||||
Future::NotReady => Ok(None),
|
||||
Future::SenderDropped => Err(Error::SenderDropped),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check to see if there is a message to be read whilst blocking/waiting until a message is
|
||||
/// sent or the `Sender` is dropped.
|
||||
pub fn recv(self) -> Result<T, Error> {
|
||||
let mut lock = self.0.mutex.lock();
|
||||
loop {
|
||||
match &*lock {
|
||||
Future::Ready(item) => return Ok(item.clone()),
|
||||
Future::NotReady => self.0.condvar.wait(&mut lock),
|
||||
Future::SenderDropped => return Err(Error::SenderDropped),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single-sender, multiple-receiver broadcast channel.
|
||||
///
|
||||
/// The sender may send *only one* message which will be received by *all* receivers.
|
||||
pub fn oneshot<T: Clone>() -> (Sender<T>, Receiver<T>) {
|
||||
let mutex_condvar = Arc::new(MutexCondvar {
|
||||
mutex: Mutex::new(Future::NotReady),
|
||||
condvar: Condvar::new(),
|
||||
});
|
||||
let receiver = Receiver(mutex_condvar.clone());
|
||||
let sender = Sender(mutex_condvar);
|
||||
(sender, receiver)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn single_thread_try_recv() {
|
||||
let (sender, receiver) = oneshot();
|
||||
assert_eq!(receiver.try_recv(), Ok(None));
|
||||
sender.send(42);
|
||||
assert_eq!(receiver.try_recv(), Ok(Some(42)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_thread_try_recv_no_message() {
|
||||
let (sender, receiver) = oneshot::<u8>();
|
||||
assert_eq!(receiver.try_recv(), Ok(None));
|
||||
drop(sender);
|
||||
assert_eq!(receiver.try_recv(), Err(Error::SenderDropped));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_thread_recv() {
|
||||
let (sender, receiver) = oneshot();
|
||||
assert_eq!(receiver.try_recv(), Ok(None));
|
||||
sender.send(42);
|
||||
assert_eq!(receiver.recv(), Ok(42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_thread_recv_no_message() {
|
||||
let (sender, receiver) = oneshot::<u8>();
|
||||
assert_eq!(receiver.try_recv(), Ok(None));
|
||||
drop(sender);
|
||||
assert_eq!(receiver.recv(), Err(Error::SenderDropped));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_threads_message_sent() {
|
||||
let (sender, receiver) = oneshot();
|
||||
|
||||
let handle = thread::spawn(|| receiver.recv().unwrap());
|
||||
|
||||
sender.send(42);
|
||||
assert_eq!(handle.join().unwrap(), 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn three_threads_message_set() {
|
||||
let (sender, receiver) = oneshot();
|
||||
|
||||
let receiver_a = receiver.clone();
|
||||
let handle_a = thread::spawn(|| receiver_a.recv().unwrap());
|
||||
let handle_b = thread::spawn(|| receiver.recv().unwrap());
|
||||
|
||||
sender.send(42);
|
||||
assert_eq!(handle_a.join().unwrap(), 42);
|
||||
assert_eq!(handle_b.join().unwrap(), 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn three_threads_sender_dropped() {
|
||||
let (sender, receiver) = oneshot::<u8>();
|
||||
|
||||
let receiver_a = receiver.clone();
|
||||
let handle_a = thread::spawn(|| receiver_a.recv());
|
||||
let handle_b = thread::spawn(|| receiver.recv());
|
||||
|
||||
drop(sender);
|
||||
assert_eq!(handle_a.join().unwrap(), Err(Error::SenderDropped));
|
||||
assert_eq!(handle_b.join().unwrap(), Err(Error::SenderDropped));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sender_dropped_after_recv() {
|
||||
let (sender_a, receiver_a) = oneshot();
|
||||
let (sender_b, receiver_b) = oneshot::<u8>();
|
||||
|
||||
let handle_0 = thread::spawn(|| {
|
||||
sender_a.send(1);
|
||||
receiver_b.recv()
|
||||
});
|
||||
|
||||
assert_eq!(receiver_a.recv(), Ok(1));
|
||||
// This is a slightly hacky sleep that assumes that the thread has had enough time after
|
||||
// sending down `sender_a` to start listening to `receiver_b`.
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
drop(sender_b);
|
||||
assert_eq!(handle_0.join().unwrap(), Err(Error::SenderDropped))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user