use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, Mutex};
use hashgraph_like_consensus::{
events::ConsensusEventBus, scope::ConsensusScope, signing::EthereumConsensusSigner,
storage::InMemoryConsensusStorage, types::ConsensusEvent,
};
use crate::{
ConsensusPlugin, DeterministicStewardList, PeerScoreStorage, PeerScoringService,
SyncConsensusReceiver,
};
#[derive(Debug, Clone, Default)]
pub struct InMemoryPeerScoreStorage {
scores: HashMap<Vec<u8>, i64>,
}
impl InMemoryPeerScoreStorage {
pub fn new() -> Self {
Self::default()
}
}
impl PeerScoreStorage for InMemoryPeerScoreStorage {
fn get(&self, member_id: &[u8]) -> Option<i64> {
self.scores.get(member_id).copied()
}
fn set(&mut self, member_id: &[u8], score: i64) {
self.scores.insert(member_id.to_vec(), score);
}
fn remove(&mut self, member_id: &[u8]) {
self.scores.remove(member_id);
}
fn all_scores(&self) -> Vec<(Vec<u8>, i64)> {
self.scores.iter().map(|(k, v)| (k.clone(), *v)).collect()
}
}
#[derive(Clone)]
pub struct SyncEventBus<Scope: ConsensusScope> {
queue: Arc<Mutex<VecDeque<(Scope, ConsensusEvent)>>>,
}
impl<Scope: ConsensusScope> Default for SyncEventBus<Scope> {
fn default() -> Self {
Self {
queue: Arc::new(Mutex::new(VecDeque::new())),
}
}
}
impl<Scope: ConsensusScope> ConsensusEventBus<Scope> for SyncEventBus<Scope> {
type Receiver = SyncEventReceiver<Scope>;
fn subscribe(&self) -> Self::Receiver {
SyncEventReceiver {
queue: Arc::clone(&self.queue),
}
}
fn publish(&self, scope: Scope, event: ConsensusEvent) {
if let Ok(mut q) = self.queue.lock() {
q.push_back((scope, event));
}
}
}
pub struct SyncEventReceiver<Scope: ConsensusScope> {
queue: Arc<Mutex<VecDeque<(Scope, ConsensusEvent)>>>,
}
impl<Scope: ConsensusScope> SyncConsensusReceiver<Scope> for SyncEventReceiver<Scope> {
fn try_recv(&mut self) -> Option<(Scope, ConsensusEvent)> {
self.queue.lock().ok()?.pop_front()
}
}
pub struct DefaultConsensusPlugin;
impl ConsensusPlugin for DefaultConsensusPlugin {
type Scope = String;
type ConsensusStorage = InMemoryConsensusStorage<String>;
type EventBus = SyncEventBus<String>;
type Signer = EthereumConsensusSigner;
fn new_storage() -> Self::ConsensusStorage {
InMemoryConsensusStorage::new()
}
fn new_event_bus() -> Self::EventBus {
SyncEventBus::default()
}
}
pub type DefaultPeerScoring = PeerScoringService<InMemoryPeerScoreStorage>;
pub type DefaultStewardList = DeterministicStewardList;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn in_memory_storage_round_trip() {
let mut storage = InMemoryPeerScoreStorage::new();
assert_eq!(storage.get(b"alice"), None);
storage.set(b"alice", 42);
assert_eq!(storage.get(b"alice"), Some(42));
storage.set(b"bob", -3);
let all = storage.all_scores();
assert_eq!(all.len(), 2);
storage.remove(b"alice");
assert_eq!(storage.get(b"alice"), None);
assert_eq!(storage.all_scores().len(), 1);
}
}