Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Closed
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
2 changes: 1 addition & 1 deletion client/finality-grandpa/src/communication/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub mod gossip;
mod periodic;

#[cfg(test)]
mod tests;
pub(crate) mod tests;

pub use sp_finality_grandpa::GRANDPA_ENGINE_ID;

Expand Down
21 changes: 15 additions & 6 deletions client/finality-grandpa/src/communication/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,16 @@ use sp_finality_grandpa::{AuthorityList, GRANDPA_ENGINE_ID};
use super::gossip::{self, GossipValidator};
use super::{AuthorityId, VoterSet, Round, SetId};

enum Event {
#[derive(Debug)]
pub(crate) enum Event {
EventStream(mpsc::UnboundedSender<NetworkEvent>),
WriteNotification(sc_network::PeerId, Vec<u8>),
Report(sc_network::PeerId, sc_network::ReputationChange),
Announce(Hash),
}

#[derive(Clone)]
struct TestNetwork {
pub(crate) struct TestNetwork {
sender: mpsc::UnboundedSender<Event>,
}

Expand Down Expand Up @@ -101,10 +102,10 @@ impl sc_network_gossip::ValidatorContext<Block> for TestNetwork {
fn send_topic(&mut self, _: &sc_network::PeerId, _: Hash, _: bool) { }
}

struct Tester {
net_handle: super::NetworkBridge<Block, TestNetwork>,
pub(crate) struct Tester {
pub(crate) net_handle: super::NetworkBridge<Block, TestNetwork>,
gossip_validator: Arc<GossipValidator<Block>>,
events: mpsc::UnboundedReceiver<Event>,
pub(crate) events: mpsc::UnboundedReceiver<Event>,
}

impl Tester {
Expand All @@ -122,6 +123,14 @@ impl Tester {
}
})
}

pub(crate) fn trigger_gossip_validator_reputation_change(&self, p: &PeerId) {
self.gossip_validator.validate(
&mut crate::communication::tests::NoopContext,
p,
&vec![1, 2, 3],
);
}
}

// some random config (not really needed)
Expand Down Expand Up @@ -156,7 +165,7 @@ fn voter_set_state() -> SharedVoterSetState<Block> {
}

// needs to run in a tokio runtime.
fn make_test_network(executor: &impl futures::task::Spawn) -> (
pub(crate) fn make_test_network(executor: &impl futures::task::Spawn) -> (
impl Future<Output = Tester>,
TestNetwork,
) {
Expand Down
81 changes: 81 additions & 0 deletions client/finality-grandpa/src/observer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,84 @@ where
Future::poll(Pin::new(&mut self.network), cx)
}
}

#[cfg(test)]
mod tests {
use super::*;

use crate::{aux_schema, communication::tests::{Event, make_test_network}};
use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt};
use sc_network::PeerId;

use futures::executor::{self, ThreadPool};

#[test]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put bellow the comment.

/// Ensure `Future` implementation of `ObserverWork` is polling its `NetworkBridge`. Regression
/// test for bug introduced in d4fbb897c and fixed in b7af8b339.
///
/// When polled, `NetworkBridge` forwards reputation change requests from the `GossipValidator`
/// to the underlying `dyn Network`. This test triggers a reputation change by calling
/// `GossipValidator::validate` with an invalid gossip message. After polling the `ObserverWork`
/// which should poll the `NetworkBridge`, the reputation change should be forwarded to the test
/// network.
fn observer_work_polls_underlying_network_bridge() {
let thread_pool = ThreadPool::new().unwrap();

// Create a test network.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

let (tester_fut, _network) = make_test_network(&thread_pool);
let mut tester = executor::block_on(tester_fut);

// Create an observer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

let (client, backend) = {
let builder = TestClientBuilder::with_default_backend();
let backend = builder.backend();
let (client, _) = builder.build_with_longest_chain();
(Arc::new(client), backend)
};

let persistent_data = aux_schema::load_persistent(
&*backend,
client.chain_info().genesis_hash,
0,
|| Ok(vec![]),
).unwrap();

let (_tx, voter_command_rx) = mpsc::unbounded();
let observer = ObserverWork::new(
client,
tester.net_handle.clone(),
persistent_data,
None,
voter_command_rx,
);

// Trigger a reputation change through the gossip validator.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

let peer_id = PeerId::random();
tester.trigger_gossip_validator_reputation_change(&peer_id);

executor::block_on(async move {
// Ignore initial event stream request by gossip engine.
match tester.events.next().now_or_never() {
Some(Some(Event::EventStream(_))) => {},
_ => panic!("expected event stream request"),
};

assert!(
tester.events.next().now_or_never().is_none(),
"expect no further network events",
);

// Poll the observer once and have it forward the reputation change from the gossip
// validator to the test network.
assert!(observer.now_or_never().is_none());

match tester.events.next().now_or_never() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert_matches! would be a better choice here

Some(Some(Event::Report(_, _))) => {},
_ => panic!("expected test network to receive reputation change event"),
};
});
}
}