Sync block justifications (#1410)

* core: sync protocol for justifications

* core: basic test for justification sync

* core: pass block number with justification

* grandpa: request justifications when importing change blocks

* core: pass finality notifications to chain sync

* core: require justifications for pending change blocks on start

* core: avoid requesting justifications from previous failed peers

* core: timeout block justification requests

* core: add some docs

* core: fix unused variables warning

* core: tick pending justifications fetch periodically

* grandpa: add test for syncing justifications

* core: early exit dispatch of pending justifications

* core: style fix

* core: grandpa: change logging level

* core: sync: add missing docs

* core: network: report peer on bad justification

* core: replace mem::replace with Option::take

* core: revert authority set changes on failed block finalization

* core: grandpa: add docs to import_justification

* core: warn on re-finalization of last finalized block

* core: only notify sync with last finality notification

* core: style fix

* core: add docs for PendingJustifications

* core: network: use BlockRequest messages for justification requests

* core: reference issues in todo comments

* core: grandpa: revert authority set changes on db

* core: grandpa: remove inconsistent state warning
This commit is contained in:
André Silva
2019-01-21 06:04:01 +00:00
committed by Gav Wood
parent 3ea681998a
commit 399cee310a
13 changed files with 747 additions and 140 deletions
+54 -2
View File
@@ -494,7 +494,7 @@ fn transition_3_voters_twice_1_observer() {
let transitions = api.scheduled_changes.clone();
let net = Arc::new(Mutex::new(GrandpaTestNet::new(api, 8)));
let mut runtime = tokio::runtime::Runtime::new().unwrap();
let mut runtime = current_thread::Runtime::new().unwrap();
net.lock().peer(0).push_blocks(1, false);
net.lock().sync();
@@ -619,6 +619,7 @@ fn transition_3_voters_twice_1_observer() {
let drive_to_completion = ::tokio::timer::Interval::new_interval(TEST_ROUTING_INTERVAL)
.for_each(move |_| {
net.lock().send_import_notifications();
net.lock().send_finality_notifications();
net.lock().sync();
Ok(())
})
@@ -682,4 +683,55 @@ fn consensus_changes_works() {
changes.note_change((1, 1.into()));
changes.note_change((1, 101.into()));
assert_eq!(changes.finalize((10, 10.into()), |_| Ok(Some(1.into()))).unwrap(), (true, true));
}
}
#[test]
fn sync_justifications_on_change_blocks() {
::env_logger::init();
let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let peers_b = &[Keyring::Alice, Keyring::Bob];
let voters = make_ids(peers_b);
// 4 peers, 3 of them are authorities and participate in grandpa
let api = TestApi::new(voters);
let transitions = api.scheduled_changes.clone();
let mut net = GrandpaTestNet::new(api, 4);
// add 20 blocks
net.peer(0).push_blocks(20, false);
// at block 21 we do add a transition which is instant
net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
let block = builder.bake().unwrap();
transitions.lock().insert(*block.header.parent_hash(), ScheduledChange {
next_authorities: make_ids(peers_b),
delay: 0,
});
block
});
// add more blocks on top of it (until we have 25)
net.peer(0).push_blocks(4, false);
net.sync();
for i in 0..4 {
assert_eq!(net.peer(i).client().info().unwrap().chain.best_number, 25,
"Peer #{} failed to sync", i);
}
let net = Arc::new(Mutex::new(net));
run_to_completion(25, net.clone(), peers_a);
// the first 3 peers are grandpa voters and therefore have already finalized
// block 21 and stored a justification
for i in 0..3 {
assert!(net.lock().peer(i).client().justification(&BlockId::Number(21)).unwrap().is_some());
}
// the last peer should get the justification by syncing from other peers
assert!(net.lock().peer(3).client().justification(&BlockId::Number(21)).unwrap().is_none());
while net.lock().peer(3).client().justification(&BlockId::Number(21)).unwrap().is_none() {
net.lock().sync_steps(100);
}
}