From c64ff787761f594abcc29b6c02bed3477fcd80c9 Mon Sep 17 00:00:00 2001 From: Robert Habermeier <rphmeier@gmail.com> Date: Wed, 31 Oct 2018 12:39:27 +0100 Subject: [PATCH] initial test to ensure auxiliary data is generated correctly --- .../core/finality-grandpa/src/authorities.rs | 21 ++- substrate/core/finality-grandpa/src/tests.rs | 175 ++++++++++++++++-- substrate/core/network/src/test/mod.rs | 12 +- 3 files changed, 186 insertions(+), 22 deletions(-) diff --git a/substrate/core/finality-grandpa/src/authorities.rs b/substrate/core/finality-grandpa/src/authorities.rs index 6a32e3ddb7c..8541a64123f 100644 --- a/substrate/core/finality-grandpa/src/authorities.rs +++ b/substrate/core/finality-grandpa/src/authorities.rs @@ -39,11 +39,7 @@ impl<H, N> SharedAuthoritySet<H, N> { /// The genesis authority set. pub(crate) fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self { SharedAuthoritySet { - inner: Arc::new(RwLock::new(AuthoritySet { - current_authorities: initial, - set_id: 0, - pending_changes: Vec::new(), - })) + inner: Arc::new(RwLock::new(AuthoritySet::genesis(initial))) } } @@ -91,6 +87,15 @@ pub(crate) struct AuthoritySet<H, N> { } impl<H, N> AuthoritySet<H, N> { + /// Get a genesis set with given authorities. + pub(crate) fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self { + AuthoritySet { + current_authorities: initial, + set_id: 0, + pending_changes: Vec::new(), + } + } + /// Get the current set id and a reference to the current authority set. pub(crate) fn current(&self) -> (u64, &[(AuthorityId, u64)]) { (self.set_id, &self.current_authorities[..]) @@ -113,6 +118,12 @@ impl<H: Eq, N> AuthoritySet<H, N> self.pending_changes.insert(idx, pending); } + + /// Inspect pending changes. + pub(crate) fn pending_changes(&self) -> &[PendingChange<H, N>] { + &self.pending_changes + } + /// Get the earliest limit-block number, if any. pub(crate) fn current_limit(&self) -> Option<N> { self.pending_changes.get(0).map(|change| change.effective_number().clone()) diff --git a/substrate/core/finality-grandpa/src/tests.rs b/substrate/core/finality-grandpa/src/tests.rs index adc16464130..252fbcf8305 100644 --- a/substrate/core/finality-grandpa/src/tests.rs +++ b/substrate/core/finality-grandpa/src/tests.rs @@ -1,3 +1,21 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see <http://www.gnu.org/licenses/>. + +//! Tests and test helpers for GRANDPA. + use super::*; use network::test::{Block, Hash, TestNetFactory, Peer, PeersClient}; use network::import_queue::{PassThroughVerifier}; @@ -7,6 +25,10 @@ use tokio::runtime::current_thread; use keyring::Keyring; use client::BlockchainEvents; use test_client::{self, runtime::BlockNumber}; +use codec::Decode; +use consensus_common::BlockOrigin; + +use authorities::AuthoritySet; type PeerData = Mutex<Option<LinkHalf<test_client::Backend, test_client::Executor, Block>>>; type GrandpaPeer = Peer<PassThroughVerifier, PeerData>; @@ -135,14 +157,14 @@ impl Network for MessageRouting { #[derive(Default, Clone)] struct TestApi { genesis_authorities: Vec<(AuthorityId, u64)>, - scheduled_changes: HashMap<BlockNumber, ScheduledChange<BlockNumber>>, + scheduled_changes: Arc<Mutex<HashMap<Hash, ScheduledChange<BlockNumber>>>>, } impl TestApi { fn new(genesis_authorities: Vec<(AuthorityId, u64)>) -> Self { TestApi { genesis_authorities, - scheduled_changes: HashMap::new(), + scheduled_changes: Arc::new(Mutex::new(HashMap::new())), } } } @@ -157,20 +179,29 @@ impl ApiClient<Block> for TestApi { { // we take only scheduled changes at given block number where there are no // extrinsics. - Ok(self.scheduled_changes.get(header.number()).map(|c| c.clone())) + let change = self.scheduled_changes.lock().get(&header.hash()).map(|c| c.clone()); + if change.is_some() { + println!("Found transition for {:?}", header.hash()); + } + + Ok(change) } } const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); const TEST_ROUTING_INTERVAL: Duration = Duration::from_millis(50); +fn make_ids(keys: &[Keyring]) -> Vec<(AuthorityId, u64)> { + keys.iter() + .map(|key| AuthorityId(key.to_raw_public())) + .map(|id| (id, 1)) + .collect() +} + #[test] fn finalize_3_voters_no_observers() { let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; - let voters: Vec<_> = peers.iter() - .map(|key| AuthorityId(key.to_raw_public())) - .map(|id| (id, 1)) - .collect(); + let voters = make_ids(peers); let mut net = GrandpaTestNet::new(TestApi::new(voters), 3); net.peer(0).push_blocks(20, false); @@ -229,10 +260,7 @@ fn finalize_3_voters_no_observers() { #[test] fn finalize_3_voters_1_observer() { let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; - let voters: Vec<_> = peers.iter() - .map(|key| AuthorityId(key.to_raw_public())) - .map(|id| (id, 1)) - .collect(); + let voters = make_ids(peers); let mut net = GrandpaTestNet::new(TestApi::new(voters), 4); net.peer(0).push_blocks(20, false); @@ -285,3 +313,128 @@ fn finalize_3_voters_1_observer() { runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap(); } + +#[test] +fn transition_3_voters_twice_1_observer() { + let peers_a = &[ + Keyring::Alice, + Keyring::Bob, + Keyring::Charlie, + ]; + + let peers_b = &[ + Keyring::Dave, + Keyring::Eve, + Keyring::Ferdie, + ]; + + let peers_c = &[ + Keyring::Alice, + Keyring::Eve, + Keyring::Two, + ]; + + let observer = &[Keyring::One]; + + let genesis_voters = make_ids(peers_a); + + let api = TestApi::new(genesis_voters); + let transitions = api.scheduled_changes.clone(); + let add_transition = move |hash, change| { + transitions.lock().insert(hash, change); + }; + + let mut net = GrandpaTestNet::new(api, 8); + + // first 20 blocks: transition at 15, applied at 20. + { + net.peer(0).push_blocks(14, false); + net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| { + let block = builder.bake().unwrap(); + println!("Adding transition for {:?}", block.header.hash()); + add_transition(block.header.hash(), ScheduledChange { + next_authorities: make_ids(peers_b), + delay: 4, + }); + + block + }); + net.peer(0).push_blocks(5, false); + } + + // at block 21 we do another transition, but this time instant. + // add more until we have 30. + { + net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| { + let block = builder.bake().unwrap(); + println!("Adding transition for {:?}", block.header.hash()); + add_transition(block.header.hash(), ScheduledChange { + next_authorities: make_ids(peers_c), + delay: 0, + }); + + block + }); + + net.peer(0).push_blocks(9, false); + } + net.sync(); + + for (i, peer) in net.peers().iter().enumerate() { + assert_eq!(peer.client().info().unwrap().chain.best_number, 30, + "Peer #{} failed to sync", i); + + let set_raw = peer.client().backend().get_aux(::AUTHORITY_SET_KEY).unwrap().unwrap(); + let set = AuthoritySet::<Hash, BlockNumber>::decode(&mut &set_raw[..]).unwrap(); + + assert_eq!(set.current(), (0, make_ids(peers_a).as_slice())); + assert_eq!(set.pending_changes().len(), 2); + } + + // let net = Arc::new(Mutex::new(net)); + // let mut finality_notifications = Vec::new(); + + // let mut runtime = current_thread::Runtime::new().unwrap(); + // let all_peers = peers.iter() + // .cloned() + // .map(|key| Some(Arc::new(key.into()))) + // .chain(::std::iter::once(None)); + + // for (peer_id, local_key) in all_peers.enumerate() { + // let (client, link) = { + // let mut net = net.lock(); + // let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); + // ( + // net.peers[peer_id].client().clone(), + // link, + // ) + // }; + // finality_notifications.push( + // client.finality_notification_stream() + // .take_while(|n| Ok(n.header.number() < &20)) + // .for_each(move |_| Ok(())) + // ); + // let voter = run_grandpa( + // Config { + // gossip_duration: TEST_GOSSIP_DURATION, + // local_key, + // }, + // link, + // MessageRouting::new(net.clone(), peer_id), + // ).expect("all in order with client and network"); + + // runtime.spawn(voter); + // } + + // // wait for all finalized on each. + // let wait_for = ::futures::future::join_all(finality_notifications) + // .map(|_| ()) + // .map_err(|_| ()); + + // let drive_to_completion = ::tokio::timer::Interval::new_interval(TEST_ROUTING_INTERVAL) + // .for_each(move |_| { net.lock().route_until_complete(); Ok(()) }) + // .map(|_| ()) + // .map_err(|_| ()); + + // runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap(); +} diff --git a/substrate/core/network/src/test/mod.rs b/substrate/core/network/src/test/mod.rs index c5addcd4e18..f8869fcc81f 100644 --- a/substrate/core/network/src/test/mod.rs +++ b/substrate/core/network/src/test/mod.rs @@ -236,14 +236,13 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> { /// Add blocks to the peer -- edit the block before adding pub fn generate_blocks<F>(&self, count: usize, origin: BlockOrigin, mut edit_block: F) - where F: FnMut(&mut BlockBuilder<test_client::Backend, test_client::Executor, Block, Blake2Hasher>) + where F: FnMut(BlockBuilder<test_client::Backend, test_client::Executor, Block, Blake2Hasher>) -> Block { use blocks::BlockData; for _ in 0..count { - let mut builder = self.client.new_block().unwrap(); - edit_block(&mut builder); - let block = builder.bake().unwrap(); + let builder = self.client.new_block().unwrap(); + let block = edit_block(builder); let hash = block.header.hash(); trace!("Generating {}, (#{}, parent={})", hash, block.header.number, block.header.parent_hash); let header = block.header.clone(); @@ -269,7 +268,7 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> { pub fn push_blocks(&self, count: usize, with_tx: bool) { let mut nonce = 0; if with_tx { - self.generate_blocks(count, BlockOrigin::File, |builder| { + self.generate_blocks(count, BlockOrigin::File, |mut builder| { let transfer = Transfer { from: Keyring::Alice.to_raw_public().into(), to: Keyring::Alice.to_raw_public().into(), @@ -279,9 +278,10 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> { let signature = Keyring::from_raw_public(transfer.from.0).unwrap().sign(&transfer.encode()).into(); builder.push(Extrinsic { transfer, signature }).unwrap(); nonce = nonce + 1; + builder.bake().unwrap() }); } else { - self.generate_blocks(count, BlockOrigin::File, |_| ()); + self.generate_blocks(count, BlockOrigin::File, |builder| builder.bake().unwrap()); } } -- GitLab