diff --git a/substrate/client/network/src/protocol/sync.rs b/substrate/client/network/src/protocol/sync.rs index 37af47011d..b720ba0aef 100644 --- a/substrate/client/network/src/protocol/sync.rs +++ b/substrate/client/network/src/protocol/sync.rs @@ -27,6 +27,7 @@ //! order to update it. //! +use codec::Encode; use blocks::BlockCollection; use sp_blockchain::{Error as ClientError, Info as BlockchainInfo, HeaderMetadata}; use sp_consensus::{BlockOrigin, BlockStatus, @@ -45,7 +46,7 @@ use log::{debug, trace, warn, info, error}; use sp_runtime::{ Justification, generic::BlockId, - traits::{Block as BlockT, Header, NumberFor, Zero, One, CheckedSub, SaturatedConversion} + traits::{Block as BlockT, Header, NumberFor, Zero, One, CheckedSub, SaturatedConversion, Hash, HashFor} }; use std::{fmt, ops::Range, collections::{HashMap, HashSet, VecDeque}, sync::Arc}; @@ -727,8 +728,10 @@ impl ChainSync { match &mut peer.state { PeerSyncState::DownloadingNew(start_block) => { self.blocks.clear_peer_download(&who); - self.blocks.insert(*start_block, blocks, who.clone()); + let start_block = *start_block; peer.state = PeerSyncState::Available; + validate_blocks::(&blocks, &who)?; + self.blocks.insert(start_block, blocks, who.clone()); self.blocks .drain(self.best_queued_number + One::one()) .into_iter() @@ -750,6 +753,7 @@ impl ChainSync { debug!(target: "sync", "Empty block response from {}", who); return Err(BadPeer(who, rep::NO_BLOCK)); } + validate_blocks::(&blocks, &who)?; blocks.into_iter().map(|b| { IncomingBlock { hash: b.hash, @@ -834,6 +838,7 @@ impl ChainSync { } } else { // When request.is_none() this is a block announcement. Just accept blocks. + validate_blocks::(&blocks, &who)?; blocks.into_iter().map(|b| { IncomingBlock { hash: b.hash, @@ -1500,6 +1505,40 @@ fn is_descendent_of(client: &T, base: &Block::Hash, block: &Block::Has Ok(ancestor.hash == *base) } +fn validate_blocks(blocks: &Vec>, who: &PeerId) -> Result<(), BadPeer> { + for b in blocks { + if let Some(header) = &b.header { + let hash = header.hash(); + if hash != b.hash { + debug!( + target:"sync", + "Bad header received from {}. Expected hash {:?}, got {:?}", + who, + b.hash, + hash, + ); + return Err(BadPeer(who.clone(), rep::BAD_BLOCK)) + } + } + if let (Some(header), Some(body)) = (&b.header, &b.body) { + let expected = *header.extrinsics_root(); + let got = HashFor::::ordered_trie_root(body.iter().map(Encode::encode).collect()); + if expected != got { + debug!( + target:"sync", + "Bad extrinsic root for a block {} received from {}. Expected {:?}, got {:?}", + b.hash, + who, + expected, + got, + ); + return Err(BadPeer(who.clone(), rep::BAD_BLOCK)) + } + } + } + Ok(()) +} + #[cfg(test)] mod test { use super::*;