use super::relay::Relay;
use crate::{
simplex::{
elector::{Config as ElectorConfig, Elector},
scheme::Scheme,
types::{Certificate, Notarize, Proposal, Vote},
},
types::{Epoch, Participant, Round, View},
Viewable,
};
use commonware_codec::{Decode, Encode};
use commonware_cryptography::{certificate, Hasher};
use commonware_p2p::{Receiver, Recipients, Sender};
use commonware_runtime::{spawn_cell, Clock, ContextCell, Handle, Spawner};
use commonware_utils::ordered::Quorum;
use rand::{seq::IteratorRandom, Rng};
use std::{collections::HashSet, sync::Arc};
pub struct Config<S: certificate::Scheme, L: ElectorConfig<S>, H: Hasher> {
pub scheme: S,
pub elector: L,
pub epoch: Epoch,
pub relay: Arc<Relay<H::Digest, S::PublicKey>>,
pub hasher: H,
}
pub struct Equivocator<
E: Clock + Rng + Spawner,
S: Scheme<H::Digest>,
L: ElectorConfig<S>,
H: Hasher,
> {
context: ContextCell<E>,
scheme: S,
elector: L::Elector,
epoch: Epoch,
relay: Arc<Relay<H::Digest, S::PublicKey>>,
hasher: H,
sent: HashSet<View>,
}
impl<E: Clock + Rng + Spawner, S: Scheme<H::Digest>, L: ElectorConfig<S>, H: Hasher>
Equivocator<E, S, L, H>
{
pub fn new(context: E, cfg: Config<S, L, H>) -> Self {
let elector = cfg.elector.build(cfg.scheme.participants());
Self {
context: ContextCell::new(context),
scheme: cfg.scheme,
epoch: cfg.epoch,
relay: cfg.relay,
hasher: cfg.hasher,
elector,
sent: HashSet::new(),
}
}
pub fn start(
mut self,
vote_network: (impl Sender<PublicKey = S::PublicKey>, impl Receiver),
certificate_network: (impl Sender, impl Receiver),
) -> Handle<()> {
spawn_cell!(
self.context,
self.run(vote_network, certificate_network).await
)
}
async fn run(
mut self,
vote_network: (impl Sender<PublicKey = S::PublicKey>, impl Receiver),
certificate_network: (impl Sender, impl Receiver),
) {
let (mut vote_sender, _) = vote_network;
let (_, mut certificate_receiver) = certificate_network;
loop {
let (_, certificate) = certificate_receiver.recv().await.unwrap();
let (view, parent, certificate) = match Certificate::<S, H::Digest>::decode_cfg(
certificate,
&self.scheme.certificate_codec_config(),
)
.unwrap()
{
Certificate::Notarization(notarization) => (
notarization.view(),
notarization.proposal.payload,
notarization.certificate,
),
Certificate::Finalization(finalization) => (
finalization.view(),
finalization.proposal.payload,
finalization.certificate,
),
_ => continue, };
if !self.sent.insert(view) {
continue;
}
let next_view = view.next();
let next_round = Round::new(self.epoch, next_view);
let leader = self.elector.elect(next_round, Some(&certificate));
if leader != self.scheme.me().unwrap() {
continue;
}
let (_, victim) = self
.scheme
.participants()
.iter()
.enumerate()
.filter(|(index, _)| Participant::from_usize(*index) != self.scheme.me().unwrap())
.choose(&mut self.context)
.unwrap();
let payload_a = (next_round, parent, self.context.gen::<u64>()).encode();
let payload_b = (next_round, parent, self.context.gen::<u64>()).encode();
self.hasher.update(&payload_a);
let digest_a = self.hasher.finalize();
self.hasher.update(&payload_b);
let digest_b = self.hasher.finalize();
let proposal_a = Proposal::new(next_round, view, digest_a);
let proposal_b = Proposal::new(next_round, view, digest_b);
let me = self
.scheme
.participants()
.key(self.scheme.me().unwrap())
.unwrap();
self.relay.broadcast(me, (digest_a, payload_a));
self.relay.broadcast(me, (digest_b, payload_b));
let notarize_a = Notarize::<S, _>::sign(&self.scheme, proposal_a).expect("sign failed");
vote_sender
.send(
Recipients::One(victim.clone()),
Vote::Notarize(notarize_a).encode(),
true,
)
.await
.expect("send failed");
let notarize_b = Notarize::<S, _>::sign(&self.scheme, proposal_b).expect("sign failed");
let non_victims: Vec<_> = self
.scheme
.participants()
.iter()
.enumerate()
.filter(|(index, key)| {
Participant::from_usize(*index) != self.scheme.me().unwrap() && *key != victim
})
.map(|(_, key)| key.clone())
.collect();
vote_sender
.send(
Recipients::Some(non_victims),
Vote::Notarize(notarize_b).encode(),
true,
)
.await
.expect("send failed");
}
}
}