Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ cancellation = "0.1.0"
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.5", features = ["derive", "env", "cargo"] }
crossbeam = "0.8.4"
dyn-clone = "1.0"
dyn-eq = "0.1.3"
either = "1.13"
eventsource-stream = "0.2"
futures = "0.3"
Expand Down
2 changes: 1 addition & 1 deletion crates/app/src/node/wire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ pub async fn wire_core_workflow(
Arc::new(move |duty: Duty, pubkey: PubKey| {
let aggsigdb = aggsigdb.clone();
Box::pin(async move {
let signed: Box<dyn SignedData> = aggsigdb.wait_for(duty, pubkey).await?;
let signed: SignedData = aggsigdb.wait_for(duty, pubkey).await?;
Ok(signed)
})
})
Expand Down
3 changes: 1 addition & 2 deletions crates/app/tests/wiring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,7 @@ async fn wiring_exercises_fetcher_back_edges() {
// Store the RANDAO into the *same* wired AggSigDB; the back-edge must
// unblock.
let randao: phase0::BLSSignature = [7u8; 96];
let randao_set: SignedDataSet =
HashMap::from([(pubkey, Box::new(randao) as Box<dyn SignedData>)]);
let randao_set: SignedDataSet = HashMap::from([(pubkey, SignedData::from(randao))]);
tokio::time::timeout(
GUARD,
aggsigdb.store(Duty::new_randao_duty(SlotNumber::new(SLOT)), randao_set),
Expand Down
2 changes: 0 additions & 2 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ axum.workspace = true
cancellation.workspace = true
chrono.workspace = true
crossbeam.workspace = true
dyn-clone.workspace = true
dyn-eq.workspace = true
futures.workspace = true
hex.workspace = true
vise.workspace = true
Expand Down
135 changes: 57 additions & 78 deletions crates/core/src/aggsigdb/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ use std::collections::{HashMap, hash_map::Entry};
use tokio::sync;
use tokio_util::sync::CancellationToken;

type Waiters =
HashMap<(types::Duty, types::PubKey), Vec<sync::oneshot::Sender<Box<dyn types::SignedData>>>>;
type Waiters = HashMap<(types::Duty, types::PubKey), Vec<sync::oneshot::Sender<types::SignedData>>>;

struct MemoryDBActor {
entries: HashMap<types::Duty, HashMap<types::PubKey, Box<dyn types::SignedData>>>,
entries: HashMap<types::Duty, HashMap<types::PubKey, types::SignedData>>,
waiters: Waiters,
deadliner: deadline::DeadlinerHandle,
}
Expand Down Expand Up @@ -101,11 +100,7 @@ impl MemoryDBActor {
Ok(())
}

fn get(
&self,
duty: &types::Duty,
pub_key: &types::PubKey,
) -> Option<Box<dyn types::SignedData>> {
fn get(&self, duty: &types::Duty, pub_key: &types::PubKey) -> Option<types::SignedData> {
self.entries
.get(duty)
.and_then(|for_duty| for_duty.get(pub_key))
Expand Down Expand Up @@ -134,7 +129,7 @@ enum Message {
WaitFor {
duty: types::Duty,
pub_key: types::PubKey,
response: sync::oneshot::Sender<Box<dyn types::SignedData>>,
response: sync::oneshot::Sender<types::SignedData>,
},
}

Expand Down Expand Up @@ -186,7 +181,7 @@ impl AggSigDB for MemoryDBHandle {
&self,
duty: types::Duty,
pub_key: types::PubKey,
) -> Result<Box<dyn types::SignedData>, Error> {
) -> Result<types::SignedData, Error> {
let (response_tx, response_rx) = sync::oneshot::channel();
let msg = Message::WaitFor {
duty,
Expand All @@ -206,48 +201,25 @@ mod tests {
types::{AggSigDB, Error},
},
deadline,
signeddata::SignedDataError,
types::{Duty, PubKey, Signature, SignedData, SignedDataSet, SlotNumber},
signeddata::MockSignedData,
types::{Duty, PubKey, SignedData, SignedDataSet, SlotNumber},
};
use pluto_ssz::HashRoot;
use tokio::sync;
use tokio_util::sync::CancellationToken;

/// Some mock signed data type for testing.
#[derive(Debug, Clone, PartialEq, Eq)]
struct MockSignedData(u8);

impl SignedData for MockSignedData {
fn signature(&self) -> Result<Signature, SignedDataError> {
Ok([self.0; 96])
}

fn set_signature(&self, _signature: Signature) -> Result<Self, SignedDataError> {
Ok(self.clone())
}

fn set_signature_boxed(
&self,
signature: Signature,
) -> Result<Box<dyn SignedData>, SignedDataError> {
Ok(Box::new(self.set_signature(signature)?))
}

fn message_root(&self) -> Result<HashRoot, SignedDataError> {
Ok([self.0; 32])
}
/// Builds mock signed data whose signature and message root are derived
/// from `byte`, so distinct values are distinguishable.
fn mock_signed_data(byte: u8) -> SignedData {
MockSignedData::new([byte; 96])
.with_message_root([byte; 32])
.into()
}

impl MockSignedData {
fn singleton(&self, pub_key: PubKey) -> SignedDataSet {
let mut set = SignedDataSet::new();
set.insert(pub_key, self.boxed());
set
}

fn boxed(&self) -> Box<dyn SignedData> {
Box::new(self.clone())
}
/// Wraps mock signed data for `pub_key` in a single-entry set.
fn singleton(pub_key: PubKey, data: SignedData) -> SignedDataSet {
let mut set = SignedDataSet::new();
set.insert(pub_key, data);
set
}

/// Create a test deadline handle and an expiration channel.
Expand All @@ -269,15 +241,15 @@ mod tests {

let duty = Duty::new_proposer_duty(SlotNumber::new(10));
let pub_key = PubKey::new([7u8; 48]);
let signed_data = MockSignedData(42);
let signed_data = mock_signed_data(42);

store
.store(duty.clone(), signed_data.singleton(pub_key))
.store(duty.clone(), singleton(pub_key, signed_data.clone()))
.await
.unwrap();

let result = store.wait_for(duty, pub_key).await.unwrap();
assert_eq!(result, signed_data.boxed());
assert_eq!(result, signed_data.clone());
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
Expand All @@ -287,7 +259,7 @@ mod tests {

let duty = Duty::new_attester_duty(SlotNumber::new(1));
let pub_key = PubKey::new([7u8; 48]);
let signed_data = MockSignedData(0);
let signed_data = mock_signed_data(0);

let reader = {
let store = store.clone();
Expand All @@ -302,11 +274,13 @@ mod tests {
tokio::task::yield_now().await;
assert!(!reader.is_finished(), "wait_for should block until store");

let write = store.store(duty, signed_data.singleton(pub_key)).await;
let write = store
.store(duty, singleton(pub_key, signed_data.clone()))
.await;
let read = reader.await.unwrap().unwrap();

assert!(write.is_ok());
assert_eq!(read, signed_data.boxed());
assert_eq!(read, signed_data.clone());
}

#[tokio::test]
Expand All @@ -318,11 +292,13 @@ mod tests {

let duty = Duty::new_proposer_duty(SlotNumber::new(10));
let pub_key = PubKey::new([7u8; 48]);
let signed_data = MockSignedData(42);
let signed_data = mock_signed_data(42);

ct.cancel();

let res = store.store(duty, signed_data.singleton(pub_key)).await;
let res = store
.store(duty, singleton(pub_key, signed_data.clone()))
.await;
assert!(matches!(res, Err(Error::Terminated)));
}

Expand All @@ -333,16 +309,16 @@ mod tests {

let duty = Duty::new_proposer_duty(SlotNumber::new(10));
let pub_key = PubKey::new([7u8; 48]);
let first = MockSignedData(1);
let second = MockSignedData(2);
let first = mock_signed_data(1);
let second = mock_signed_data(2);

store
.store(duty.clone(), first.singleton(pub_key))
.store(duty.clone(), singleton(pub_key, first.clone()))
.await
.unwrap();

let err = store
.store(duty, second.singleton(pub_key))
.store(duty, singleton(pub_key, second.clone()))
.await
.expect_err("storing mismatching data should fail");
assert!(matches!(err, super::Error::MismatchingData));
Expand All @@ -355,19 +331,19 @@ mod tests {

let duty = Duty::new_proposer_duty(SlotNumber::new(10));
let pub_key = PubKey::new([7u8; 48]);
let signed_data = MockSignedData(42);
let signed_data = mock_signed_data(42);

store
.store(duty.clone(), signed_data.singleton(pub_key))
.store(duty.clone(), singleton(pub_key, signed_data.clone()))
.await
.unwrap();
store
.store(duty.clone(), signed_data.singleton(pub_key))
.store(duty.clone(), singleton(pub_key, signed_data.clone()))
.await
.unwrap();

let result = store.wait_for(duty, pub_key).await.unwrap();
assert_eq!(result, signed_data.boxed());
assert_eq!(result, signed_data.clone());
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
Expand All @@ -378,11 +354,11 @@ mod tests {

let duty = Duty::new_attester_duty(SlotNumber::new(1));
let pub_key = PubKey::new([7u8; 48]);
let first = MockSignedData(1);
let second = MockSignedData(2);
let first = mock_signed_data(1);
let second = mock_signed_data(2);

store
.store(duty.clone(), first.singleton(pub_key))
.store(duty.clone(), singleton(pub_key, first.clone()))
.await
.unwrap();

Expand All @@ -392,7 +368,7 @@ mod tests {
{
let dummy = Duty::new_attester_duty(SlotNumber::new(u64::MAX));
store
.store(dummy, MockSignedData(0).singleton(pub_key))
.store(dummy, singleton(pub_key, mock_signed_data(0)))
.await
.unwrap();
}
Expand All @@ -411,11 +387,14 @@ mod tests {

// Store new data for the same duty and pubkey. The reader should wake
// up and return the new data, not the evicted data.
store.store(duty, second.singleton(pub_key)).await.unwrap();
store
.store(duty, singleton(pub_key, second.clone()))
.await
.unwrap();

let read = reader.await.unwrap().unwrap();
assert_eq!(read, second.boxed());
assert_ne!(read, first.boxed());
assert_eq!(read, second.clone());
assert_ne!(read, first.clone());
}

#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
Expand All @@ -426,7 +405,7 @@ mod tests {
let store = MemoryDBHandle::new(deadliner, expiration_rx, CancellationToken::new());
let duty = Duty::new_proposer_duty(SlotNumber::new(10));
let pub_key = PubKey::new([7u8; 48]);
let signed_data = MockSignedData(42);
let signed_data = mock_signed_data(42);

let readers: Vec<_> = (0..N)
.map(|_| {
Expand All @@ -447,13 +426,13 @@ mod tests {

// A single store unblocks all readers.
store
.store(duty, signed_data.singleton(pub_key))
.store(duty, singleton(pub_key, signed_data.clone()))
.await
.unwrap();

for reader in readers {
let read = reader.await.unwrap().unwrap();
assert_eq!(read, signed_data.boxed());
assert_eq!(read, signed_data.clone());
}
}

Expand All @@ -463,10 +442,10 @@ mod tests {
let store = MemoryDBHandle::new(deadliner, expiration_rx, CancellationToken::new());

let duty_a = Duty::new_proposer_duty(SlotNumber::new(10));
let data_a = MockSignedData(1);
let data_a = mock_signed_data(1);

let duty_b = Duty::new_attester_duty(SlotNumber::new(20));
let data_b = MockSignedData(2);
let data_b = mock_signed_data(2);

let pub_key = PubKey::new([7u8; 48]);

Expand All @@ -481,7 +460,7 @@ mod tests {

// Storing an unrelated key does not affect readers.
store
.store(duty_b, data_b.singleton(pub_key))
.store(duty_b, singleton(pub_key, data_b.clone()))
.await
.unwrap();

Expand All @@ -493,12 +472,12 @@ mod tests {

// Storing the actual key unblocks the reader.
store
.store(duty_a, data_a.singleton(pub_key))
.store(duty_a, singleton(pub_key, data_a.clone()))
.await
.unwrap();

let read = reader.await.unwrap().unwrap();
assert_eq!(read, data_a.boxed());
assert_ne!(read, data_b.boxed());
assert_eq!(read, data_a.clone());
assert_ne!(read, data_b.clone());
}
}
2 changes: 1 addition & 1 deletion crates/core/src/aggsigdb/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ pub trait AggSigDB {
&self,
duty: types::Duty,
pub_key: types::PubKey,
) -> Result<Box<dyn types::SignedData>, Error>;
) -> Result<types::SignedData, Error>;
}
Loading
Loading