Download unknown but announced forks (#1604)

* test reproducing fork sync issues

* update to new announce_block API

* Download unknown forks

* Reverted download_stale

* Avoid cloning the hash

* Typo
This commit is contained in:
Robert Habermeier
2019-01-28 16:41:33 -03:00
committed by GitHub
parent 431ad3ca76
commit ced9e72824
5 changed files with 109 additions and 18 deletions
+26 -4
View File
@@ -399,6 +399,11 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> {
self.sync.gossip_consensus_message(&mut TestIo::new(&self.queue, None), topic, data, broadcast);
}
/// Announce a block to peers.
pub fn announce_block(&self, block: Hash) {
self.sync.announce_block(&mut TestIo::new(&self.queue, None), block);
}
/// Request a justification for the given block.
#[cfg(test)]
fn request_justification(&self, hash: &::primitives::H256, number: NumberFor<Block>) {
@@ -408,15 +413,25 @@ 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)
pub fn generate_blocks<F>(&self, count: usize, origin: BlockOrigin, edit_block: F)
where F: FnMut(BlockBuilder<Block, PeersClient>) -> Block
{
let best_hash = self.client.info().unwrap().chain.best_hash;
self.generate_blocks_at(BlockId::Hash(best_hash), count, origin, edit_block)
}
/// Add blocks to the peer -- edit the block before adding. The chain will
/// start at the given block iD.
pub fn generate_blocks_at<F>(&self, mut at: BlockId<Block>, count: usize, origin: BlockOrigin, mut edit_block: F)
where F: FnMut(BlockBuilder<Block, PeersClient>) -> Block
{
for _ in 0..count {
let builder = self.client.new_block().unwrap();
let builder = self.client.new_block_at(&at).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();
at = BlockId::Hash(hash);
// NOTE: if we use a non-synchronous queue in the test-net in the future,
// this may not work.
@@ -435,9 +450,16 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> {
/// Push blocks to the peer (simplified: with or without a TX)
pub fn push_blocks(&self, count: usize, with_tx: bool) {
let best_hash = self.client.info().unwrap().chain.best_hash;
self.push_blocks_at(BlockId::Hash(best_hash), count, with_tx);
}
/// Push blocks to the peer (simplified: with or without a TX) starting from
/// given hash.
pub fn push_blocks_at(&self, at: BlockId<Block>, count: usize, with_tx: bool) {
let mut nonce = 0;
if with_tx {
self.generate_blocks(count, BlockOrigin::File, |mut builder| {
self.generate_blocks_at(at, count, BlockOrigin::File, |mut builder| {
let transfer = Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Alice.to_raw_public().into(),
@@ -450,7 +472,7 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> {
builder.bake().unwrap()
});
} else {
self.generate_blocks(count, BlockOrigin::File, |builder| builder.bake().unwrap());
self.generate_blocks_at(at, count, BlockOrigin::File, |builder| builder.bake().unwrap());
}
}
+39
View File
@@ -178,3 +178,42 @@ fn blocks_are_not_announced_by_light_nodes() {
assert_eq!(net.peer(1).client.backend().blockchain().info().unwrap().best_number, 1);
assert_eq!(net.peer(2).client.backend().blockchain().info().unwrap().best_number, 0);
}
#[test]
fn can_sync_small_non_best_forks() {
let _ = ::env_logger::try_init();
let mut net = TestNet::new(2);
net.sync_step();
net.peer(0).push_blocks(30, false);
net.peer(1).push_blocks(30, false);
// small fork + reorg on peer 1.
net.peer(0).push_blocks_at(BlockId::Number(30), 2, true);
let small_hash = net.peer(0).client().info().unwrap().chain.best_hash;
net.peer(0).push_blocks_at(BlockId::Number(30), 10, false);
assert_eq!(net.peer(0).client().info().unwrap().chain.best_number, 40);
// peer 1 only ever had the long fork.
net.peer(1).push_blocks(10, false);
assert_eq!(net.peer(1).client().info().unwrap().chain.best_number, 40);
assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some());
assert!(net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_none());
net.sync();
// synchronization: 0 synced to longer chain and 1 didn't sync to small chain.
assert_eq!(net.peer(0).client().info().unwrap().chain.best_number, 40);
assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some());
assert!(!net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_some());
net.peer(0).announce_block(small_hash);
net.sync();
// after announcing, peer 1 downloads the block.
assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some());
assert!(net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_some());
}