From 8768646d6e1535280144860fa9a6279841afa069 Mon Sep 17 00:00:00 2001 From: Grzegorz Prusak Date: Wed, 13 Dec 2023 11:22:47 +0100 Subject: [PATCH] added a test --- node/actors/bft/src/testonly/make.rs | 15 +++++++++++++++ node/actors/bft/src/testonly/node.rs | 15 +++++++++++++-- node/actors/bft/src/testonly/run.rs | 4 ++-- node/actors/bft/src/tests.rs | 15 +++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/node/actors/bft/src/testonly/make.rs b/node/actors/bft/src/testonly/make.rs index d35291ba..2122ab98 100644 --- a/node/actors/bft/src/testonly/make.rs +++ b/node/actors/bft/src/testonly/make.rs @@ -20,6 +20,21 @@ impl PayloadSource for RandomPayloadSource { } } +/// Never provides a payload. +pub struct InavailablePayloadSource; + +#[async_trait::async_trait] +impl PayloadSource for InavailablePayloadSource { + async fn propose( + &self, + ctx: &ctx::Ctx, + _block_number: validator::BlockNumber, + ) -> ctx::Result { + ctx.canceled().await; + Err(ctx::Canceled.into()) + } +} + /// Creates a genesis block with the given payload /// and a validator set for the chain. pub fn make_genesis( diff --git a/node/actors/bft/src/testonly/node.rs b/node/actors/bft/src/testonly/node.rs index d696a325..edb569d0 100644 --- a/node/actors/bft/src/testonly/node.rs +++ b/node/actors/bft/src/testonly/node.rs @@ -1,5 +1,5 @@ use super::Fuzz; -use crate::io; +use crate::{io, testonly}; use rand::Rng; use std::sync::Arc; use zksync_concurrency::{ctx, scope}; @@ -13,6 +13,8 @@ use zksync_consensus_utils::pipe::DispatcherPipe; pub(crate) enum Behavior { /// A replica that is always online and behaves honestly. Honest, + /// Same as honest, except that it never proposes a block (which is a legit behavior) + HonestNotProposing, /// A replica that is always offline and does not produce any messages. Offline, /// A replica that is always online and behaves randomly. It will produce @@ -23,6 +25,15 @@ pub(crate) enum Behavior { Byzantine, } +impl Behavior { + pub(crate) fn payload_source(&self) -> Box { + match self { + Self::HonestNotProposing => Box::new(testonly::InavailablePayloadSource), + _ => Box::new(testonly::RandomPayloadSource), + } + } +} + /// Struct representing a node. pub(super) struct Node { pub(crate) net: network::testonly::Instance, @@ -64,7 +75,7 @@ impl Node { io::OutputMessage::Network(mut message) => { let message_to_send = match self.behavior { Behavior::Offline => continue, - Behavior::Honest => message, + Behavior::Honest | Behavior::HonestNotProposing => message, // Create a random consensus message and broadcast. Behavior::Random => ConsensusInputMessage { message: rng.gen(), diff --git a/node/actors/bft/src/testonly/run.rs b/node/actors/bft/src/testonly/run.rs index 929f3883..9522b86a 100644 --- a/node/actors/bft/src/testonly/run.rs +++ b/node/actors/bft/src/testonly/run.rs @@ -1,4 +1,4 @@ -use super::{Behavior, Node, RandomPayloadSource}; +use super::{Behavior, Node}; use crate::testonly; use anyhow::Context; use std::{collections::HashMap, sync::Arc}; @@ -108,7 +108,7 @@ async fn run_nodes(ctx: &ctx::Ctx, network: Network, nodes: &[Node]) -> anyhow:: node.net.consensus_config().key.clone(), validator_set, storage, - &RandomPayloadSource, + &*node.behavior.payload_source(), ) .await .context("consensus.run()") diff --git a/node/actors/bft/src/tests.rs b/node/actors/bft/src/tests.rs index 0d9c56bd..37dbd7bd 100644 --- a/node/actors/bft/src/tests.rs +++ b/node/actors/bft/src/tests.rs @@ -145,3 +145,18 @@ async fn timeout_leader_in_consecutive_prepare() { util.new_leader_commit(ctx).await; util.produce_block_after_timeout(ctx).await; } + +/// Not being able to propose a block shouldn't cause a deadlock. +#[tokio::test] +async fn non_proposing_leader() { + zksync_concurrency::testonly::abort_on_panic(); + let ctx = &ctx::test_root(&ctx::AffineClock::new(5.)); + Test { + network: Network::Real, + nodes: vec![Behavior::Honest, Behavior::HonestNotProposing], + blocks_to_finalize: 10, + } + .run(ctx) + .await + .unwrap() +}