Fixed sync skipping some block announcements (#8459)

* Fixed sync missing some block announcements

* Apply suggestions from code review

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
This commit is contained in:
Arkadiy Paronyan
2021-04-01 00:02:31 +03:00
committed by GitHub
parent 0e6481d01a
commit 484a630db9
4 changed files with 144 additions and 31 deletions
+77
View File
@@ -740,6 +740,27 @@ impl BlockAnnounceValidator<Block> for NewBestBlockAnnounceValidator {
}
}
/// Returns `Validation::Failure` for specified block number
struct FailingBlockAnnounceValidator(u64);
impl BlockAnnounceValidator<Block> for FailingBlockAnnounceValidator {
fn validate(
&mut self,
header: &Header,
_: &[u8],
) -> Pin<Box<dyn Future<Output = Result<Validation, Box<dyn std::error::Error + Send>>> + Send>> {
let number = *header.number();
let target_number = self.0;
async move { Ok(
if number == target_number {
Validation::Failure { disconnect: false }
} else {
Validation::Success { is_new_best: true }
}
) }.boxed()
}
}
#[test]
fn sync_blocks_when_block_announce_validator_says_it_is_new_best() {
sp_tracing::try_init_simple();
@@ -1010,3 +1031,59 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() {
Poll::Ready(())
}));
}
#[test]
fn syncs_all_forks_from_single_peer() {
sp_tracing::try_init_simple();
let mut net = TestNet::new(2);
net.peer(0).push_blocks(10, false);
net.peer(1).push_blocks(10, false);
// poll until the two nodes connect, otherwise announcing the block will not work
net.block_until_connected();
// Peer 0 produces new blocks and announces.
let branch1 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, true);
// Wait till peer 1 starts downloading
block_on(futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
if net.peer(1).network().best_seen_block() != Some(12) {
return Poll::Pending
}
Poll::Ready(())
}));
// Peer 0 produces and announces another fork
let branch2 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, false);
net.block_until_sync();
// Peer 1 should have both branches,
assert!(net.peer(1).client().header(&BlockId::Hash(branch1)).unwrap().is_some());
assert!(net.peer(1).client().header(&BlockId::Hash(branch2)).unwrap().is_some());
}
#[test]
fn syncs_after_missing_announcement() {
sp_tracing::try_init_simple();
let mut net = TestNet::new(0);
net.add_full_peer_with_config(Default::default());
// Set peer 1 to ignore announcement
net.add_full_peer_with_config(FullPeerConfig {
block_announce_validator: Some(Box::new(FailingBlockAnnounceValidator(11))),
..Default::default()
});
net.peer(0).push_blocks(10, false);
net.peer(1).push_blocks(10, false);
net.block_until_connected();
// Peer 0 produces a new block and announces. Peer 1 ignores announcement.
net.peer(0).push_blocks_at(BlockId::Number(10), 1, false);
// Peer 0 produces another block and announces.
let final_block = net.peer(0).push_blocks_at(BlockId::Number(11), 1, false);
net.peer(1).push_blocks_at(BlockId::Number(10), 1, true);
net.block_until_sync();
assert!(net.peer(1).client().header(&BlockId::Hash(final_block)).unwrap().is_some());
}