use std::{
collections::{BTreeMap, HashMap, HashSet},
sync::Arc,
};
use anyhow::Context;
use async_lock::RwLock;
use async_trait::async_trait;
use hotshot::{
tasks::EventTransformerState,
types::{SignatureKey, SystemContextHandle},
};
use hotshot_task_impls::{
events::HotShotEvent,
network::{
test::{ModifierClosure, NetworkEventTaskStateModifier},
NetworkEventTaskState,
},
};
use hotshot_types::{
consensus::{Consensus, OuterConsensus},
data::QuorumProposal2,
message::{Proposal, UpgradeLock},
simple_vote::QuorumVote2,
traits::node_implementation::{ConsensusTime, NodeImplementation, NodeType, Versions},
};
#[derive(Debug)]
pub struct BadProposalViewDos {
pub multiplier: u64,
pub increment: u64,
}
#[async_trait]
impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> EventTransformerState<TYPES, I, V>
for BadProposalViewDos
{
async fn recv_handler(&mut self, event: &HotShotEvent<TYPES>) -> Vec<HotShotEvent<TYPES>> {
vec![event.clone()]
}
async fn send_handler(
&mut self,
event: &HotShotEvent<TYPES>,
_public_key: &TYPES::SignatureKey,
_private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
_upgrade_lock: &UpgradeLock<TYPES, V>,
consensus: Arc<RwLock<Consensus<TYPES>>>,
) -> Vec<HotShotEvent<TYPES>> {
match event {
HotShotEvent::QuorumProposalSend(proposal, signature) => {
let mut result = Vec::new();
for n in 1..self.multiplier {
let mut modified_proposal = proposal.clone();
modified_proposal.data.view_number += n * self.increment;
result.push(HotShotEvent::QuorumProposalSend(
modified_proposal,
signature.clone(),
));
}
consensus.write().await.reset_actions();
result
}
_ => vec![event.clone()],
}
}
}
#[derive(Debug)]
pub struct DoubleProposeVote;
#[async_trait]
impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> EventTransformerState<TYPES, I, V>
for DoubleProposeVote
{
async fn recv_handler(&mut self, event: &HotShotEvent<TYPES>) -> Vec<HotShotEvent<TYPES>> {
vec![event.clone()]
}
async fn send_handler(
&mut self,
event: &HotShotEvent<TYPES>,
_public_key: &TYPES::SignatureKey,
_private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
_upgrade_lock: &UpgradeLock<TYPES, V>,
_consensus: Arc<RwLock<Consensus<TYPES>>>,
) -> Vec<HotShotEvent<TYPES>> {
match event {
HotShotEvent::QuorumProposalSend(_, _) | HotShotEvent::QuorumVoteSend(_) => {
vec![event.clone(), event.clone()]
}
_ => vec![event.clone()],
}
}
}
#[derive(Debug)]
pub struct DishonestLeader<TYPES: NodeType> {
pub validated_proposals: Vec<QuorumProposal2<TYPES>>,
pub total_proposals_from_node: u64,
pub dishonest_at_proposal_numbers: HashSet<u64>,
pub view_look_back: usize,
pub dishonest_proposal_view_numbers: Arc<RwLock<HashSet<TYPES::View>>>,
}
impl<TYPES: NodeType> DishonestLeader<TYPES> {
async fn handle_proposal_send_event(
&self,
event: &HotShotEvent<TYPES>,
proposal: &Proposal<TYPES, QuorumProposal2<TYPES>>,
sender: &TYPES::SignatureKey,
) -> HotShotEvent<TYPES> {
let length = self.validated_proposals.len();
if !self
.dishonest_at_proposal_numbers
.contains(&self.total_proposals_from_node)
|| length == 0
{
return event.clone();
}
let proposal_from_look_back = if length - 1 < self.view_look_back {
self.validated_proposals[0].clone()
} else {
let index = (self.validated_proposals.len() - 1) - self.view_look_back;
self.validated_proposals[index].clone()
};
let mut dishonest_proposal = proposal.clone();
dishonest_proposal.data.justify_qc = proposal_from_look_back.justify_qc;
let mut dishonest_proposal_sent = self.dishonest_proposal_view_numbers.write().await;
dishonest_proposal_sent.insert(proposal.data.view_number);
HotShotEvent::QuorumProposalSend(dishonest_proposal, sender.clone())
}
}
#[async_trait]
impl<TYPES: NodeType, I: NodeImplementation<TYPES> + std::fmt::Debug, V: Versions>
EventTransformerState<TYPES, I, V> for DishonestLeader<TYPES>
{
async fn recv_handler(&mut self, event: &HotShotEvent<TYPES>) -> Vec<HotShotEvent<TYPES>> {
vec![event.clone()]
}
async fn send_handler(
&mut self,
event: &HotShotEvent<TYPES>,
_public_key: &TYPES::SignatureKey,
_private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
_upgrade_lock: &UpgradeLock<TYPES, V>,
_consensus: Arc<RwLock<Consensus<TYPES>>>,
) -> Vec<HotShotEvent<TYPES>> {
match event {
HotShotEvent::QuorumProposalSend(proposal, sender) => {
self.total_proposals_from_node += 1;
return vec![
self.handle_proposal_send_event(event, proposal, sender)
.await,
];
}
HotShotEvent::QuorumProposalValidated(proposal, _) => {
self.validated_proposals.push(proposal.data.clone());
}
_ => {}
}
vec![event.clone()]
}
}
#[derive(Debug)]
pub struct DishonestDa {
pub total_da_certs_sent_from_node: u64,
pub dishonest_at_da_cert_sent_numbers: HashSet<u64>,
pub total_views_add_to_cert: u64,
}
#[async_trait]
impl<TYPES: NodeType, I: NodeImplementation<TYPES> + std::fmt::Debug, V: Versions>
EventTransformerState<TYPES, I, V> for DishonestDa
{
async fn recv_handler(&mut self, event: &HotShotEvent<TYPES>) -> Vec<HotShotEvent<TYPES>> {
vec![event.clone()]
}
async fn send_handler(
&mut self,
event: &HotShotEvent<TYPES>,
_public_key: &TYPES::SignatureKey,
_private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
_upgrade_lock: &UpgradeLock<TYPES, V>,
_consensus: Arc<RwLock<Consensus<TYPES>>>,
) -> Vec<HotShotEvent<TYPES>> {
if let HotShotEvent::DacSend(cert, sender) = event {
self.total_da_certs_sent_from_node += 1;
if self
.dishonest_at_da_cert_sent_numbers
.contains(&self.total_da_certs_sent_from_node)
{
let mut result = vec![HotShotEvent::DacSend(cert.clone(), sender.clone())];
for i in 1..=self.total_views_add_to_cert {
let mut bad_cert = cert.clone();
bad_cert.view_number = cert.view_number + i;
result.push(HotShotEvent::DacSend(bad_cert, sender.clone()));
}
return result;
}
}
vec![event.clone()]
}
}
#[derive(Debug)]
pub struct ViewDelay<TYPES: NodeType> {
pub number_of_views_to_delay: u64,
pub events_for_view: HashMap<TYPES::View, Vec<HotShotEvent<TYPES>>>,
pub stop_view_delay_at_view_number: u64,
}
#[async_trait]
impl<TYPES: NodeType, I: NodeImplementation<TYPES> + std::fmt::Debug, V: Versions>
EventTransformerState<TYPES, I, V> for ViewDelay<TYPES>
{
async fn recv_handler(&mut self, event: &HotShotEvent<TYPES>) -> Vec<HotShotEvent<TYPES>> {
let correct_event = vec![event.clone()];
if let Some(view_number) = event.view_number() {
if *view_number >= self.stop_view_delay_at_view_number {
return correct_event;
}
let events_for_current_view = self.events_for_view.entry(view_number).or_default();
events_for_current_view.push(event.clone());
let view_diff = (*view_number).saturating_sub(self.number_of_views_to_delay);
if view_diff > 0 {
return match self
.events_for_view
.remove(&<TYPES as NodeType>::View::new(view_diff))
{
Some(lookback_events) => lookback_events.clone(),
None => vec![],
};
}
}
correct_event
}
async fn send_handler(
&mut self,
event: &HotShotEvent<TYPES>,
_public_key: &TYPES::SignatureKey,
_private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
_upgrade_lock: &UpgradeLock<TYPES, V>,
_consensus: Arc<RwLock<Consensus<TYPES>>>,
) -> Vec<HotShotEvent<TYPES>> {
vec![event.clone()]
}
}
pub struct DishonestVoting<TYPES: NodeType> {
pub view_increment: u64,
pub modifier: Arc<ModifierClosure<TYPES>>,
}
#[async_trait]
impl<TYPES: NodeType, I: NodeImplementation<TYPES> + std::fmt::Debug, V: Versions>
EventTransformerState<TYPES, I, V> for DishonestVoting<TYPES>
{
async fn recv_handler(&mut self, event: &HotShotEvent<TYPES>) -> Vec<HotShotEvent<TYPES>> {
vec![event.clone()]
}
async fn send_handler(
&mut self,
event: &HotShotEvent<TYPES>,
public_key: &TYPES::SignatureKey,
private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
upgrade_lock: &UpgradeLock<TYPES, V>,
_consensus: Arc<RwLock<Consensus<TYPES>>>,
) -> Vec<HotShotEvent<TYPES>> {
if let HotShotEvent::QuorumVoteSend(vote) = event {
let new_view = vote.view_number + self.view_increment;
let spoofed_vote = QuorumVote2::<TYPES>::create_signed_vote(
vote.data.clone(),
new_view,
public_key,
private_key,
upgrade_lock,
)
.await
.context("Failed to sign vote")
.unwrap();
tracing::debug!("Sending Quorum Vote for view: {new_view:?}");
return vec![HotShotEvent::QuorumVoteSend(spoofed_vote)];
}
vec![event.clone()]
}
fn add_network_event_task(
&self,
handle: &mut SystemContextHandle<TYPES, I, V>,
network: Arc<<I as NodeImplementation<TYPES>>::Network>,
membership: Arc<RwLock<TYPES::Membership>>,
) {
let network_state: NetworkEventTaskState<_, V, _, _> = NetworkEventTaskState {
network,
view: TYPES::View::genesis(),
epoch: TYPES::Epoch::genesis(),
membership,
storage: Arc::clone(&handle.storage()),
consensus: OuterConsensus::new(handle.consensus()),
upgrade_lock: handle.hotshot.upgrade_lock.clone(),
transmit_tasks: BTreeMap::new(),
};
let modified_network_state = NetworkEventTaskStateModifier {
network_event_task_state: network_state,
modifier: Arc::clone(&self.modifier),
};
handle.add_task(modified_network_state);
}
}
impl<TYPES: NodeType> std::fmt::Debug for DishonestVoting<TYPES> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DishonestVoting")
.field("view_increment", &self.view_increment)
.finish_non_exhaustive()
}
}
#[derive(Debug)]
pub struct DishonestVoter<TYPES: NodeType> {
pub votes_sent: Vec<QuorumVote2<TYPES>>,
pub dishonest_proposal_view_numbers: Arc<RwLock<HashSet<TYPES::View>>>,
}
#[async_trait]
impl<TYPES: NodeType, I: NodeImplementation<TYPES> + std::fmt::Debug, V: Versions>
EventTransformerState<TYPES, I, V> for DishonestVoter<TYPES>
{
async fn recv_handler(&mut self, event: &HotShotEvent<TYPES>) -> Vec<HotShotEvent<TYPES>> {
vec![event.clone()]
}
async fn send_handler(
&mut self,
event: &HotShotEvent<TYPES>,
public_key: &TYPES::SignatureKey,
private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
upgrade_lock: &UpgradeLock<TYPES, V>,
_consensus: Arc<RwLock<Consensus<TYPES>>>,
) -> Vec<HotShotEvent<TYPES>> {
match event {
HotShotEvent::QuorumProposalRecv(proposal, _sender) => {
let dishonest_proposals = self.dishonest_proposal_view_numbers.read().await;
if dishonest_proposals.contains(&proposal.data.view_number) {
let vote = QuorumVote2::<TYPES>::create_signed_vote(
self.votes_sent.last().unwrap().data.clone(),
event.view_number().unwrap(),
public_key,
private_key,
upgrade_lock,
)
.await
.context("Failed to sign vote")
.unwrap();
return vec![HotShotEvent::QuorumVoteSend(vote)];
}
}
HotShotEvent::TimeoutVoteSend(vote) => {
let dishonest_proposals = self.dishonest_proposal_view_numbers.read().await;
if dishonest_proposals.contains(&vote.view_number) {
return vec![];
}
}
HotShotEvent::QuorumVoteSend(vote) => {
self.votes_sent.push(vote.clone());
}
_ => {}
}
vec![event.clone()]
}
}