Integrate Approval Voting into Overseer / Service / GRANDPA (#2412)

* integrate approval voting into overseer

* expose public API and make keystore arc

* integrate overseer in service

* guide: `ApprovedAncestor` returns block number

* return block number along with hash from ApprovedAncestor

* introduce a voting rule for reporting on approval checking

* integrate the delay voting rule

* Rococo configuration

* fix compilation and add slack

* fix web-wasm build

* tweak parameterization

* migrate voting rules to asycn

* remove hack comment
This commit is contained in:
Robert Habermeier
2021-02-15 22:37:13 -06:00
committed by GitHub
parent 5c68e6f9cc
commit 4f21cc7e5c
11 changed files with 321 additions and 66 deletions
+23 -9
View File
@@ -76,11 +76,23 @@ const LOG_TARGET: &str = "approval_voting";
/// The approval voting subsystem.
pub struct ApprovalVotingSubsystem<T> {
keystore: LocalKeystore,
keystore: Arc<LocalKeystore>,
slot_duration_millis: u64,
db: Arc<T>,
}
impl<T> ApprovalVotingSubsystem<T> {
/// Create a new approval voting subsystem with the given keystore, slot duration,
/// and underlying DB.
pub fn new(keystore: Arc<LocalKeystore>, slot_duration_millis: u64, db: Arc<T>) -> Self {
ApprovalVotingSubsystem {
keystore,
slot_duration_millis,
db,
}
}
}
impl<T, C> Subsystem<C> for ApprovalVotingSubsystem<T>
where T: AuxStore + Send + Sync + 'static, C: SubsystemContext<Message = ApprovalVotingMessage> {
fn start(self, ctx: C) -> SpawnedSubsystem {
@@ -229,7 +241,7 @@ use approval_db_v1_reader::ApprovalDBV1Reader;
struct State<T> {
session_window: import::RollingSessionWindow,
keystore: LocalKeystore,
keystore: Arc<LocalKeystore>,
slot_duration_millis: u64,
db: T,
clock: Box<dyn Clock + Send + Sync>,
@@ -529,10 +541,10 @@ async fn handle_approved_ancestor(
db: &impl DBReader,
target: Hash,
lower_bound: BlockNumber,
) -> SubsystemResult<Option<Hash>> {
) -> SubsystemResult<Option<(Hash, BlockNumber)>> {
let mut all_approved_max = None;
let block_number = {
let target_number = {
let (tx, rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::BlockNumber(target, tx).into()).await;
@@ -544,17 +556,17 @@ async fn handle_approved_ancestor(
}
};
if block_number <= lower_bound { return Ok(None) }
if target_number <= lower_bound { return Ok(None) }
// request ancestors up to but not including the lower bound,
// as a vote on the lower bound is implied if we cannot find
// anything else.
let ancestry = if block_number > lower_bound + 1 {
let ancestry = if target_number > lower_bound + 1 {
let (tx, rx) = oneshot::channel();
ctx.send_message(ChainApiMessage::Ancestors {
hash: target,
k: (block_number - (lower_bound + 1)) as usize,
k: (target_number - (lower_bound + 1)) as usize,
response_channel: tx,
}.into()).await;
@@ -566,7 +578,7 @@ async fn handle_approved_ancestor(
Vec::new()
};
for block_hash in std::iter::once(target).chain(ancestry) {
for (i, block_hash) in std::iter::once(target).chain(ancestry).enumerate() {
// Block entries should be present as the assumption is that
// nothing here is finalized. If we encounter any missing block
// entries we can fail.
@@ -577,7 +589,9 @@ async fn handle_approved_ancestor(
if entry.is_fully_approved() {
if all_approved_max.is_none() {
all_approved_max = Some(block_hash);
// First iteration of the loop is target, i = 0. After that,
// ancestry is moving backwards.
all_approved_max = Some((block_hash, target_number - i as BlockNumber));
}
} else {
all_approved_max = None;
@@ -184,7 +184,7 @@ impl DBReader for TestStore {
fn blank_state() -> State<TestStore> {
State {
session_window: import::RollingSessionWindow::default(),
keystore: LocalKeystore::in_memory(),
keystore: Arc::new(LocalKeystore::in_memory()),
slot_duration_millis: SLOT_DURATION_MILLIS,
db: TestStore::default(),
clock: Box::new(MockClock::default()),
@@ -1490,7 +1490,7 @@ fn approved_ancestor_all_approved() {
let test_fut = Box::pin(async move {
assert_eq!(
handle_approved_ancestor(&mut ctx, &state.db, block_hash_4, 0).await.unwrap(),
Some(block_hash_4),
Some((block_hash_4, 4)),
)
});
@@ -1572,7 +1572,7 @@ fn approved_ancestor_missing_approval() {
let test_fut = Box::pin(async move {
assert_eq!(
handle_approved_ancestor(&mut ctx, &state.db, block_hash_4, 0).await.unwrap(),
Some(block_hash_2),
Some((block_hash_2, 2)),
)
});