Offline fallback for GRANDPA (#1619)

Co-authored-by: André Silva <andre.beat@gmail.com>

* skeleton for finality tracker

* dispatch events when nothing finalized for a long time

* begin integrating finality tracker into grandpa

* add delay field to pending change

* add has_api_with function to sr_version for querying APIs

* partially integrate new force changes into grandpa

* implement forced changes

* get srml-grandpa compiling

* Update core/finality-grandpa/src/authorities.rs

Co-Authored-By: rphmeier <rphmeier@gmail.com>

* Update core/finality-grandpa/src/authorities.rs

Co-Authored-By: rphmeier <rphmeier@gmail.com>

* Update core/finality-grandpa/src/authorities.rs

Co-Authored-By: rphmeier <rphmeier@gmail.com>

* remove explicit dependence on CoreApi

* increase node runtime version

* integrate grandpa forced changes into node runtime

* add some tests to finality-tracker

* integrate finality tracking into node-runtime

* test forced-change logic

* test forced changes in the authority-set handler

* kill some unneeded bounds in client

* test forced-changes in finality-grandpa and fix logic

* build wasm and finality-tracker is no-std

* restart voter on forced change

* allow returning custom error type from lock_import_and_run

* extract out most DB logic to aux_schema and use atomic client ops

* unify authority set writing

* implement set pausing

* bump runtime version

* note on DB when we pause.

* core: grandpa: integrate forced changes with multiple pending standard changes

* core: grandpa: fix AuthoritySet tests

* runtime: bump impl_version

* core: clear pending justification requests after forced change import

* srml: finality-tracker: use FinalizedInherentData

* core: log requests for clearing justification requests

* core, node: update runtimes

* core: grandpa: fix tests

* core: grandpa: remove todos and add comments

* core: grandpa: use has_api_with from ApiExt

* core: fix tests

* core: grandpa: remove unnecessary mut modifier

* core: replace PostImportActions bitflags with struct

* core: grandpa: restrict genesis on forced authority set change

* core: grandpa: add more docs

* core: grandpa: prevent safety violations in Environment::finalize_block

* core: grandpa: register finality tracker inherent data provider

* core: grandpa: fix tests

* node: update runtime blobs

* core: grandpa: remove outdated todo

* core: aura: fix typo in log message

* core: grandpa: check re-finalization is on canonical chain

* srml: finality-tracker: fix initialization

* node: update runtime wasm

* srml: finality-tracker: don't re-initialize config keys
This commit is contained in:
Robert Habermeier
2019-03-05 16:41:35 +01:00
committed by André Silva
parent 128d164f2b
commit dfb48a2405
31 changed files with 2217 additions and 516 deletions
+95 -6
View File
@@ -24,12 +24,14 @@ use runtime_io::with_externalities;
use crate::mock::{Grandpa, System, new_test_ext};
use system::{EventRecord, Phase};
use crate::{RawLog, RawEvent};
use codec::{Decode, Encode};
use super::*;
#[test]
fn authorities_change_logged() {
with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || {
System::initialise(&1, &Default::default(), &Default::default());
Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 0).unwrap();
Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 0, None).unwrap();
System::note_finished_extrinsics();
Grandpa::on_finalise(1);
@@ -54,7 +56,7 @@ fn authorities_change_logged() {
fn authorities_change_logged_after_delay() {
with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || {
System::initialise(&1, &Default::default(), &Default::default());
Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1).unwrap();
Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1, None).unwrap();
Grandpa::on_finalise(1);
let header = System::finalise();
assert_eq!(header.digest, testing::Digest {
@@ -84,25 +86,112 @@ fn authorities_change_logged_after_delay() {
fn cannot_schedule_change_when_one_pending() {
with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || {
System::initialise(&1, &Default::default(), &Default::default());
Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1).unwrap();
Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1, None).unwrap();
assert!(Grandpa::pending_change().is_some());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1).is_err());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err());
Grandpa::on_finalise(1);
let header = System::finalise();
System::initialise(&2, &header.hash(), &Default::default());
assert!(Grandpa::pending_change().is_some());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1).is_err());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err());
Grandpa::on_finalise(2);
let header = System::finalise();
System::initialise(&3, &header.hash(), &Default::default());
assert!(Grandpa::pending_change().is_none());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1).is_ok());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_ok());
Grandpa::on_finalise(3);
let _header = System::finalise();
});
}
#[test]
fn new_decodes_from_old() {
let old = OldStoredPendingChange {
scheduled_at: 5u32,
delay: 100u32,
next_authorities: vec![(1u64, 5), (2u64, 10), (3u64, 2)],
};
let encoded = old.encode();
let new = StoredPendingChange::<u32, u64>::decode(&mut &encoded[..]).unwrap();
assert!(new.forced.is_none());
assert_eq!(new.scheduled_at, old.scheduled_at);
assert_eq!(new.delay, old.delay);
assert_eq!(new.next_authorities, old.next_authorities);
}
#[test]
fn dispatch_forced_change() {
with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || {
System::initialise(&1, &Default::default(), &Default::default());
Grandpa::schedule_change(
vec![(4, 1), (5, 1), (6, 1)],
5,
Some(0),
).unwrap();
assert!(Grandpa::pending_change().is_some());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, Some(0)).is_err());
Grandpa::on_finalise(1);
let mut header = System::finalise();
for i in 2..7 {
System::initialise(&i, &header.hash(), &Default::default());
assert!(Grandpa::pending_change().unwrap().forced.is_some());
assert_eq!(Grandpa::next_forced(), Some(11));
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, Some(0)).is_err());
Grandpa::on_finalise(i);
header = System::finalise();
}
// change has been applied at the end of block 6.
// add a normal change.
{
System::initialise(&7, &header.hash(), &Default::default());
assert!(Grandpa::pending_change().is_none());
assert_eq!(Grandpa::grandpa_authorities(), vec![(4, 1), (5, 1), (6, 1)]);
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_ok());
Grandpa::on_finalise(7);
header = System::finalise();
}
// run the normal change.
{
System::initialise(&8, &header.hash(), &Default::default());
assert!(Grandpa::pending_change().is_some());
assert_eq!(Grandpa::grandpa_authorities(), vec![(4, 1), (5, 1), (6, 1)]);
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err());
Grandpa::on_finalise(8);
header = System::finalise();
}
// normal change applied. but we can't apply a new forced change for some
// time.
for i in 9..11 {
System::initialise(&i, &header.hash(), &Default::default());
assert!(Grandpa::pending_change().is_none());
assert_eq!(Grandpa::grandpa_authorities(), vec![(5, 1)]);
assert_eq!(Grandpa::next_forced(), Some(11));
assert!(Grandpa::schedule_change(vec![(5, 1), (6, 1)], 5, Some(0)).is_err());
Grandpa::on_finalise(i);
header = System::finalise();
}
{
System::initialise(&11, &header.hash(), &Default::default());
assert!(Grandpa::pending_change().is_none());
assert!(Grandpa::schedule_change(vec![(5, 1), (6, 1), (7, 1)], 5, Some(0)).is_ok());
assert_eq!(Grandpa::next_forced(), Some(21));
Grandpa::on_finalise(11);
header = System::finalise();
}
});
}