Sync: validate block responses for required data (#5052)

* Less verbose state-db logging

* Validate block responses for block bodies

* Update client/network/src/protocol.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Added validation test

* Disconnect on missing header as well

* Typo

Co-Authored-By: André Silva <andre.beat@gmail.com>

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: André Silva <andre.beat@gmail.com>
This commit is contained in:
Arkadiy Paronyan
2020-02-25 22:17:42 +01:00
committed by GitHub
parent e2776f42f9
commit 492a820c6c
6 changed files with 111 additions and 24 deletions
+57 -14
View File
@@ -237,7 +237,7 @@ impl<D> Peer<D> {
where F: FnMut(BlockBuilder<Block, PeersFullClient, substrate_test_runtime_client::Backend>) -> Block
{
let best_hash = self.client.info().best_hash;
self.generate_blocks_at(BlockId::Hash(best_hash), count, origin, edit_block)
self.generate_blocks_at(BlockId::Hash(best_hash), count, origin, edit_block, false)
}
/// Add blocks to the peer -- edit the block before adding. The chain will
@@ -247,7 +247,8 @@ impl<D> Peer<D> {
at: BlockId<Block>,
count: usize,
origin: BlockOrigin,
mut edit_block: F
mut edit_block: F,
headers_only: bool,
) -> H256 where F: FnMut(BlockBuilder<Block, PeersFullClient, substrate_test_runtime_client::Backend>) -> Block {
let full_client = self.client.as_full()
.expect("blocks could only be generated by full clients");
@@ -272,7 +273,7 @@ impl<D> Peer<D> {
origin,
header.clone(),
None,
Some(block.extrinsics)
if headers_only { None } else { Some(block.extrinsics) },
).unwrap();
let cache = if let Some(cache) = cache {
cache.into_iter().collect()
@@ -294,28 +295,46 @@ impl<D> Peer<D> {
self.push_blocks_at(BlockId::Hash(best_hash), count, with_tx)
}
/// Push blocks to the peer (simplified: with or without a TX)
pub fn push_headers(&mut self, count: usize) -> H256 {
let best_hash = self.client.info().best_hash;
self.generate_tx_blocks_at(BlockId::Hash(best_hash), count, false, true)
}
/// Push blocks to the peer (simplified: with or without a TX) starting from
/// given hash.
pub fn push_blocks_at(&mut self, at: BlockId<Block>, count: usize, with_tx: bool) -> H256 {
self.generate_tx_blocks_at(at, count, with_tx, false)
}
/// Push blocks/headers to the peer (simplified: with or without a TX) starting from
/// given hash.
fn generate_tx_blocks_at(&mut self, at: BlockId<Block>, count: usize, with_tx: bool, headers_only:bool) -> H256 {
let mut nonce = 0;
if with_tx {
self.generate_blocks_at(at, count, BlockOrigin::File, |mut builder| {
let transfer = Transfer {
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Alice.into(),
amount: 1,
nonce,
};
builder.push(transfer.into_signed_tx()).unwrap();
nonce = nonce + 1;
builder.build().unwrap().block
})
self.generate_blocks_at(
at,
count,
BlockOrigin::File, |mut builder| {
let transfer = Transfer {
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Alice.into(),
amount: 1,
nonce,
};
builder.push(transfer.into_signed_tx()).unwrap();
nonce = nonce + 1;
builder.build().unwrap().block
},
headers_only
)
} else {
self.generate_blocks_at(
at,
count,
BlockOrigin::File,
|builder| builder.build().unwrap().block,
headers_only,
)
}
}
@@ -748,6 +767,23 @@ pub trait TestNetFactory: Sized {
Async::Ready(())
}
/// Polls the testnet until theres' no activiy of any kind.
///
/// Must be executed in a task context.
fn poll_until_idle(&mut self) -> Async<()> {
self.poll();
for peer in self.peers().iter() {
if peer.is_major_syncing() || peer.network.num_queued_blocks() != 0 {
return Async::NotReady
}
if peer.network.num_sync_requests() != 0 {
return Async::NotReady
}
}
Async::Ready(())
}
/// Blocks the current thread until we are sync'ed.
///
/// Calls `poll_until_sync` repeatedly with the runtime passed as parameter.
@@ -755,6 +791,13 @@ pub trait TestNetFactory: Sized {
runtime.block_on(futures::future::poll_fn::<(), (), _>(|| Ok(self.poll_until_sync()))).unwrap();
}
/// Blocks the current thread until there are no pending packets.
///
/// Calls `poll_until_idle` repeatedly with the runtime passed as parameter.
fn block_until_idle(&mut self, runtime: &mut tokio::runtime::current_thread::Runtime) {
runtime.block_on(futures::future::poll_fn::<(), (), _>(|| Ok(self.poll_until_idle()))).unwrap();
}
/// Polls the testnet. Processes all the pending actions and returns `NotReady`.
fn poll(&mut self) {
self.mut_peers(|peers| {