GRANDPA: announce blocks we vote on to peers (#1593)

* announce blocks we vote on to peers (missing network impl)

* Implemented 'announce'

* Fixed test

* improve announce docs and add logging

* Track recently announced blocks
This commit is contained in:
Robert Habermeier
2019-01-28 13:41:36 -03:00
committed by André Silva
parent 0078927ac5
commit d027123059
6 changed files with 127 additions and 28 deletions
+28
View File
@@ -686,6 +686,34 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
self.transaction_pool.on_broadcasted(propagated_to);
}
/// Make sure an important block is propagated to peers.
///
/// In chain-based consensus, we often need to make sure non-best forks are
/// at least temporarily synced.
pub fn announce_block(&self, io: &mut SyncIo, hash: B::Hash) {
let header = match self.context_data.chain.header(&BlockId::Hash(hash)) {
Ok(Some(header)) => header,
Ok(None) => {
warn!("Trying to announce unknown block: {}", hash);
return;
}
Err(e) => {
warn!("Error reading block header {}: {:?}", hash, e);
return;
}
};
let mut peers = self.context_data.peers.write();
let hash = header.hash();
for (who, ref mut peer) in peers.iter_mut() {
if peer.known_blocks.insert(hash.clone()) {
trace!(target: "sync", "Reannouncing block {:?} to {}", hash, who);
self.send_message(io, *who, GenericMessage::BlockAnnounce(message::BlockAnnounce {
header: header.clone()
}));
}
}
}
/// Send Status message
fn send_status(&self, io: &mut SyncIo, who: NodeIndex) {
if let Ok(info) = self.context_data.chain.info() {
+8
View File
@@ -200,6 +200,14 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>, H: ExHashT> Service<B, S,
self.handler.propagate_extrinsics(&mut NetSyncIo::new(&self.network, self.protocol_id));
}
/// Make sure an important block is propagated to peers.
///
/// In chain-based consensus, we often need to make sure non-best forks are
/// at least temporarily synced.
pub fn announce_block(&self, hash: B::Hash) {
self.handler.announce_block(&mut NetSyncIo::new(&self.network, self.protocol_id), hash);
}
/// Send a consensus message through the gossip
pub fn gossip_consensus_message(&self, topic: B::Hash, message: Vec<u8>, broadcast: bool) {
self.handler.gossip_consensus_message(
+17 -3
View File
@@ -38,12 +38,15 @@ const MAX_IMPORTING_BLOCKS: usize = 2048;
const MAJOR_SYNC_BLOCKS: usize = 5;
// Time to wait before trying to get a justification from the same peer.
const JUSTIFICATION_RETRY_WAIT: Duration = Duration::from_secs(10);
// Number of recently announced blocks to track for each peer.
const ANNOUNCE_HISTORY_SIZE: usize = 64;
struct PeerSync<B: BlockT> {
pub common_number: NumberFor<B>,
pub best_hash: B::Hash,
pub best_number: NumberFor<B>,
pub state: PeerSyncState<B>,
pub recently_announced: VecDeque<B::Hash>,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
@@ -334,6 +337,7 @@ impl<B: BlockT> ChainSync<B> {
best_hash: info.best_hash,
best_number: info.best_number,
state: PeerSyncState::Available,
recently_announced: Default::default(),
});
}
(Ok(BlockStatus::Unknown), _) => {
@@ -346,6 +350,7 @@ impl<B: BlockT> ChainSync<B> {
best_hash: info.best_hash,
best_number: info.best_number,
state: PeerSyncState::AncestorSearch(common_best),
recently_announced: Default::default(),
});
Self::request_ancestry(protocol, who, common_best)
} else {
@@ -356,6 +361,7 @@ impl<B: BlockT> ChainSync<B> {
best_hash: info.best_hash,
best_number: info.best_number,
state: PeerSyncState::Available,
recently_announced: Default::default(),
});
self.download_new(protocol, who)
}
@@ -367,6 +373,7 @@ impl<B: BlockT> ChainSync<B> {
best_hash: info.best_hash,
best_number: info.best_number,
state: PeerSyncState::Available,
recently_announced: Default::default(),
});
}
}
@@ -457,13 +464,16 @@ impl<B: BlockT> ChainSync<B> {
Vec::new()
};
let best_seen = self.best_seen_block();
let is_best = new_blocks.first().and_then(|b| b.header.as_ref()).map(|h| best_seen.as_ref().map_or(false, |n| h.number() >= n));
let origin = if is_best.unwrap_or_default() { BlockOrigin::NetworkBroadcast } else { BlockOrigin::NetworkInitialSync };
let is_recent = new_blocks
.first()
.map(|block| self.peers.iter().any(|(_, peer)| peer.recently_announced.contains(&block.hash)))
.unwrap_or(false);
let origin = if is_recent { BlockOrigin::NetworkBroadcast } else { BlockOrigin::NetworkInitialSync };
if let Some((hash, number)) = new_blocks.last()
.and_then(|b| b.header.as_ref().map(|h| (b.hash.clone(), *h.number())))
{
trace!(target:"sync", "Accepted {} blocks ({:?}) with origin {:?}", new_blocks.len(), hash, origin);
self.block_queued(&hash, number);
}
self.maintain_sync(protocol);
@@ -586,6 +596,10 @@ impl<B: BlockT> ChainSync<B> {
let known_parent = self.is_known(protocol, &header.parent_hash());
let known = self.is_known(protocol, &hash);
if let Some(ref mut peer) = self.peers.get_mut(&who) {
while peer.recently_announced.len() >= ANNOUNCE_HISTORY_SIZE {
peer.recently_announced.pop_front();
}
peer.recently_announced.push_back(hash.clone());
if number > peer.best_number {
// update their best block
peer.best_number = number;