cargo +nightly fmt (#3540)

* cargo +nightly fmt

* add cargo-fmt check to ci

* update ci

* fmt

* fmt

* skip macro

* ignore bridges
This commit is contained in:
Shawn Tabrizi
2021-08-02 12:47:33 +02:00
committed by GitHub
parent 30e3012270
commit ff5d56fb76
350 changed files with 20617 additions and 21266 deletions
@@ -16,13 +16,14 @@
//! Utilities for checking whether a candidate has been approved under a given block.
use bitvec::{order::Lsb0 as BitOrderLsb0, slice::BitSlice};
use polkadot_node_primitives::approval::DelayTranche;
use polkadot_primitives::v1::ValidatorIndex;
use bitvec::slice::BitSlice;
use bitvec::order::Lsb0 as BitOrderLsb0;
use crate::persisted_entries::{TrancheEntry, ApprovalEntry, CandidateEntry};
use crate::time::Tick;
use crate::{
persisted_entries::{ApprovalEntry, CandidateEntry, TrancheEntry},
time::Tick,
};
/// The required tranches of assignments needed to determine whether a candidate is approved.
#[derive(Debug, PartialEq, Clone)]
@@ -57,7 +58,7 @@ pub enum RequiredTranches {
/// event that there are some assignments that don't have corresponding approval votes. If this
/// is `None`, all assignments have approvals.
next_no_show: Option<Tick>,
}
},
}
/// The result of a check.
@@ -96,12 +97,11 @@ pub fn check_approval(
approval: &ApprovalEntry,
required: RequiredTranches,
) -> Check {
// any set of size f+1 contains at least one honest node. If at least one
// honest node approves, the candidate should be approved.
let approvals = candidate.approvals();
if 3 * approvals.count_ones() > approvals.len() {
return Check::ApprovedOneThird;
return Check::ApprovedOneThird
}
match required {
@@ -134,7 +134,7 @@ pub fn check_approval(
} else {
Check::Unapproved
}
}
},
}
}
@@ -182,7 +182,7 @@ impl State {
) -> RequiredTranches {
let covering = if self.depth == 0 { 0 } else { self.covering };
if self.depth != 0 && self.assignments + covering + self.uncovered >= n_validators {
return RequiredTranches::All;
return RequiredTranches::All
}
// If we have enough assignments and all no-shows are covered, we have reached the number
@@ -192,7 +192,7 @@ impl State {
needed: tranche,
tolerated_missing: self.covered,
next_no_show: self.next_no_show,
};
}
}
// We're pending more assignments and should look at more tranches.
@@ -245,10 +245,7 @@ impl State {
self.covered + new_covered
};
let uncovered = self.uncovered + new_no_shows;
let next_no_show = super::min_prefer_some(
self.next_no_show,
next_no_show,
);
let next_no_show = super::min_prefer_some(self.next_no_show, next_no_show);
let (depth, covering, uncovered) = if covering == 0 {
if uncovered == 0 {
@@ -271,27 +268,25 @@ fn filled_tranche_iterator<'a>(
) -> impl Iterator<Item = (DelayTranche, &[(ValidatorIndex, Tick)])> {
let mut gap_end = None;
let approval_entries_filled = tranches
.iter()
.flat_map(move |tranche_entry| {
let tranche = tranche_entry.tranche();
let assignments = tranche_entry.assignments();
let approval_entries_filled = tranches.iter().flat_map(move |tranche_entry| {
let tranche = tranche_entry.tranche();
let assignments = tranche_entry.assignments();
// The new gap_start immediately follows the prior gap_end, if one exists.
// Otherwise, on the first pass, the new gap_start is set to the first
// tranche so that the range below will be empty.
let gap_start = gap_end.map(|end| end + 1).unwrap_or(tranche);
gap_end = Some(tranche);
// The new gap_start immediately follows the prior gap_end, if one exists.
// Otherwise, on the first pass, the new gap_start is set to the first
// tranche so that the range below will be empty.
let gap_start = gap_end.map(|end| end + 1).unwrap_or(tranche);
gap_end = Some(tranche);
(gap_start..tranche).map(|i| (i, &[] as &[_]))
.chain(std::iter::once((tranche, assignments)))
});
(gap_start..tranche)
.map(|i| (i, &[] as &[_]))
.chain(std::iter::once((tranche, assignments)))
});
let pre_end = tranches.first().map(|t| t.tranche());
let post_start = tranches.last().map_or(0, |t| t.tranche() + 1);
let pre = pre_end.into_iter()
.flat_map(|pre_end| (0..pre_end).map(|i| (i, &[] as &[_])));
let pre = pre_end.into_iter().flat_map(|pre_end| (0..pre_end).map(|i| (i, &[] as &[_])));
let post = (post_start..).map(|i| (i, &[] as &[_]));
pre.chain(approval_entries_filled).chain(post)
@@ -313,13 +308,14 @@ fn count_no_shows(
drifted_tick_now: Tick,
) -> (usize, Option<u64>) {
let mut next_no_show = None;
let no_shows = assignments.iter()
let no_shows = assignments
.iter()
.map(|(v_index, tick)| (v_index, tick.saturating_sub(clock_drift) + no_show_duration))
.filter(|&(v_index, no_show_at)| {
let has_approved = if let Some(approved) = approvals.get(v_index.0 as usize) {
*approved
} else {
return false;
return false
};
let is_no_show = !has_approved && no_show_at <= drifted_tick_now;
@@ -331,14 +327,12 @@ fn count_no_shows(
// *this node* should observe whether or not the validator is a no show. Recall
// that when the when drifted_tick_now is computed during that subsequent wake up,
// the clock drift will be removed again to do the comparison above.
next_no_show = super::min_prefer_some(
next_no_show,
Some(no_show_at + clock_drift),
);
next_no_show = super::min_prefer_some(next_no_show, Some(no_show_at + clock_drift));
}
is_no_show
}).count();
})
.count();
(no_shows, next_no_show)
}
@@ -430,9 +424,8 @@ pub fn tranches_to_approve(
mod tests {
use super::*;
use bitvec::{bitvec, order::Lsb0 as BitOrderLsb0};
use polkadot_primitives::v1::GroupIndex;
use bitvec::bitvec;
use bitvec::order::Lsb0 as BitOrderLsb0;
use crate::approval_db;
@@ -443,7 +436,8 @@ mod tests {
session: 0,
block_assignments: Default::default(),
approvals: Default::default(),
}.into();
}
.into();
let approval_entry = approval_db::v1::ApprovalEntry {
tranches: Vec::new(),
@@ -452,7 +446,8 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
assert!(!check_approval(
&candidate,
@@ -463,7 +458,8 @@ mod tests {
maximum_broadcast: 0,
clock_drift: 0,
},
).is_approved());
)
.is_approved());
}
#[test]
@@ -473,7 +469,8 @@ mod tests {
session: 0,
block_assignments: Default::default(),
approvals: bitvec![BitOrderLsb0, u8; 0; 10],
}.into();
}
.into();
for i in 0..3 {
candidate.mark_approval(ValidatorIndex(i));
@@ -499,35 +496,27 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
assert!(check_approval(
&candidate,
&approval_entry,
RequiredTranches::Exact {
needed: 0,
tolerated_missing: 0,
next_no_show: None,
},
).is_approved());
RequiredTranches::Exact { needed: 0, tolerated_missing: 0, next_no_show: None },
)
.is_approved());
assert!(!check_approval(
&candidate,
&approval_entry,
RequiredTranches::Exact {
needed: 1,
tolerated_missing: 0,
next_no_show: None,
},
).is_approved());
RequiredTranches::Exact { needed: 1, tolerated_missing: 0, next_no_show: None },
)
.is_approved());
assert!(check_approval(
&candidate,
&approval_entry,
RequiredTranches::Exact {
needed: 1,
tolerated_missing: 2,
next_no_show: None,
},
).is_approved());
RequiredTranches::Exact { needed: 1, tolerated_missing: 2, next_no_show: None },
)
.is_approved());
}
#[test]
@@ -537,7 +526,8 @@ mod tests {
session: 0,
block_assignments: Default::default(),
approvals: bitvec![BitOrderLsb0, u8; 0; 10],
}.into();
}
.into();
for i in 0..3 {
candidate.mark_approval(ValidatorIndex(i));
@@ -563,13 +553,11 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
let exact_all = RequiredTranches::Exact {
needed: 10,
tolerated_missing: 0,
next_no_show: None,
};
let exact_all =
RequiredTranches::Exact { needed: 10, tolerated_missing: 0, next_no_show: None };
let pending_all = RequiredTranches::Pending {
considered: 5,
@@ -578,44 +566,20 @@ mod tests {
clock_drift: 12,
};
assert!(!check_approval(
&candidate,
&approval_entry,
RequiredTranches::All,
).is_approved());
assert!(!check_approval(&candidate, &approval_entry, RequiredTranches::All,).is_approved());
assert!(!check_approval(
&candidate,
&approval_entry,
exact_all.clone(),
).is_approved());
assert!(!check_approval(&candidate, &approval_entry, exact_all.clone(),).is_approved());
assert!(!check_approval(
&candidate,
&approval_entry,
pending_all.clone(),
).is_approved());
assert!(!check_approval(&candidate, &approval_entry, pending_all.clone(),).is_approved());
// This creates a set of 4/10 approvals, which is always an approval.
candidate.mark_approval(ValidatorIndex(3));
assert!(check_approval(
&candidate,
&approval_entry,
RequiredTranches::All,
).is_approved());
assert!(check_approval(&candidate, &approval_entry, RequiredTranches::All,).is_approved());
assert!(check_approval(
&candidate,
&approval_entry,
exact_all,
).is_approved());
assert!(check_approval(&candidate, &approval_entry, exact_all,).is_approved());
assert!(check_approval(
&candidate,
&approval_entry,
pending_all,
).is_approved());
assert!(check_approval(&candidate, &approval_entry, pending_all,).is_approved());
}
#[test]
@@ -631,15 +595,16 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
approval_entry.import_assignment(0,ValidatorIndex(0), block_tick);
approval_entry.import_assignment(0,ValidatorIndex(1), block_tick);
approval_entry.import_assignment(0, ValidatorIndex(0), block_tick);
approval_entry.import_assignment(0, ValidatorIndex(1), block_tick);
approval_entry.import_assignment(1,ValidatorIndex(2), block_tick + 1);
approval_entry.import_assignment(1,ValidatorIndex(3), block_tick + 1);
approval_entry.import_assignment(1, ValidatorIndex(2), block_tick + 1);
approval_entry.import_assignment(1, ValidatorIndex(3), block_tick + 1);
approval_entry.import_assignment(2,ValidatorIndex(4), block_tick + 2);
approval_entry.import_assignment(2, ValidatorIndex(4), block_tick + 2);
let approvals = bitvec![BitOrderLsb0, u8; 1; 5];
@@ -669,7 +634,8 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
approval_entry.import_assignment(0, ValidatorIndex(0), block_tick);
approval_entry.import_assignment(1, ValidatorIndex(2), block_tick);
@@ -708,7 +674,8 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
approval_entry.import_assignment(0, ValidatorIndex(0), block_tick);
approval_entry.import_assignment(0, ValidatorIndex(1), block_tick);
@@ -752,7 +719,8 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
approval_entry.import_assignment(0, ValidatorIndex(0), block_tick);
approval_entry.import_assignment(0, ValidatorIndex(1), block_tick);
@@ -818,7 +786,8 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
approval_entry.import_assignment(0, ValidatorIndex(0), block_tick);
approval_entry.import_assignment(0, ValidatorIndex(1), block_tick);
@@ -868,7 +837,7 @@ mod tests {
RequiredTranches::Exact {
needed: 2,
tolerated_missing: 1,
next_no_show: Some(block_tick + 2*no_show_duration + 2),
next_no_show: Some(block_tick + 2 * no_show_duration + 2),
},
);
@@ -906,7 +875,8 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
approval_entry.import_assignment(0, ValidatorIndex(0), block_tick);
approval_entry.import_assignment(0, ValidatorIndex(1), block_tick);
@@ -935,11 +905,7 @@ mod tests {
no_show_duration,
needed_approvals,
),
RequiredTranches::Exact {
needed: 2,
tolerated_missing: 1,
next_no_show: None,
},
RequiredTranches::Exact { needed: 2, tolerated_missing: 1, next_no_show: None },
);
// Even though tranche 2 has 2 validators, it only covers 1 no-show.
@@ -977,11 +943,7 @@ mod tests {
no_show_duration,
needed_approvals,
),
RequiredTranches::Exact {
needed: 3,
tolerated_missing: 2,
next_no_show: None,
},
RequiredTranches::Exact { needed: 3, tolerated_missing: 2, next_no_show: None },
);
}
@@ -996,7 +958,8 @@ mod tests {
session: 0,
block_assignments: Default::default(),
approvals: bitvec![BitOrderLsb0, u8; 0; 3],
}.into();
}
.into();
for i in 0..3 {
candidate.mark_approval(ValidatorIndex(i));
@@ -1015,7 +978,8 @@ mod tests {
our_approval_sig: None,
backing_group: GroupIndex(0),
approved: false,
}.into();
}
.into();
let approvals = bitvec![BitOrderLsb0, u8; 0; 3];
@@ -1043,14 +1007,14 @@ mod tests {
const PREFIX: u32 = 10;
let test_tranches = vec![
vec![], // empty set
vec![0], // zero start
vec![0, 3], // zero start with gap
vec![2], // non-zero start
vec![2, 4], // non-zero start with gap
vec![0, 1, 2], // zero start with run and no gap
vec![2, 3, 4, 8], // non-zero start with run and gap
vec![0, 1, 2, 5, 6, 7], // zero start with runs and gap
vec![], // empty set
vec![0], // zero start
vec![0, 3], // zero start with gap
vec![2], // non-zero start
vec![2, 4], // non-zero start with gap
vec![0, 1, 2], // zero start with run and no gap
vec![2, 3, 4, 8], // non-zero start with run and gap
vec![0, 1, 2, 5, 6, 7], // zero start with runs and gap
];
for test_tranche in test_tranches {
@@ -1061,7 +1025,8 @@ mod tests {
our_approval_sig: None,
assignments: bitvec![BitOrderLsb0, u8; 0; 3],
approved: false,
}.into();
}
.into();
// Populate the requested tranches. The assignemnts aren't inspected in
// this test.
@@ -1072,10 +1037,8 @@ mod tests {
let filled_tranches = filled_tranche_iterator(approval_entry.tranches());
// Take the first PREFIX entries and map them to their tranche.
let tranches: Vec<DelayTranche> = filled_tranches
.take(PREFIX as usize)
.map(|e| e.0)
.collect();
let tranches: Vec<DelayTranche> =
filled_tranches.take(PREFIX as usize).map(|e| e.0).collect();
// We expect this sequence to be sequential.
let exp_tranches: Vec<DelayTranche> = (0..PREFIX).collect();
@@ -1194,7 +1157,11 @@ mod tests {
#[test]
fn count_no_shows_three_validators_one_almost_late_one_no_show_one_approving() {
test_count_no_shows(NoShowTest {
assignments: vec![(ValidatorIndex(1), 21), (ValidatorIndex(2), 20), (ValidatorIndex(3), 20)],
assignments: vec![
(ValidatorIndex(1), 21),
(ValidatorIndex(2), 20),
(ValidatorIndex(3), 20),
],
approvals: vec![3],
clock_drift: 10,
no_show_duration: 10,
@@ -1207,7 +1174,11 @@ mod tests {
#[test]
fn count_no_shows_three_no_show_validators() {
test_count_no_shows(NoShowTest {
assignments: vec![(ValidatorIndex(1), 20), (ValidatorIndex(2), 20), (ValidatorIndex(3), 20)],
assignments: vec![
(ValidatorIndex(1), 20),
(ValidatorIndex(2), 20),
(ValidatorIndex(3), 20),
],
approvals: vec![],
clock_drift: 10,
no_show_duration: 10,
@@ -1220,7 +1191,11 @@ mod tests {
#[test]
fn count_no_shows_three_approving_validators() {
test_count_no_shows(NoShowTest {
assignments: vec![(ValidatorIndex(1), 20), (ValidatorIndex(2), 20), (ValidatorIndex(3), 20)],
assignments: vec![
(ValidatorIndex(1), 20),
(ValidatorIndex(2), 20),
(ValidatorIndex(3), 20),
],
approvals: vec![1, 2, 3],
clock_drift: 10,
no_show_duration: 10,
@@ -1270,17 +1245,17 @@ mod tests {
}
#[test]
fn count_no_shows_validator_index_out_of_approvals_range_is_ignored_as_next_no_show() {
test_count_no_shows(NoShowTest {
assignments: vec![(ValidatorIndex(1000), 21)],
approvals: vec![],
clock_drift: 10,
no_show_duration: 10,
drifted_tick_now: 20,
exp_no_shows: 0,
exp_next_no_show: None,
})
}
fn count_no_shows_validator_index_out_of_approvals_range_is_ignored_as_next_no_show() {
test_count_no_shows(NoShowTest {
assignments: vec![(ValidatorIndex(1000), 21)],
approvals: vec![],
clock_drift: 10,
no_show_duration: 10,
drifted_tick_now: 20,
exp_no_shows: 0,
exp_next_no_show: None,
})
}
}
#[test]
@@ -1318,10 +1293,6 @@ fn depth_0_issued_as_exact_even_when_all() {
assert_eq!(
state.output(0, 10, 10, 20),
RequiredTranches::Exact {
needed: 0,
tolerated_missing: 0,
next_no_show: None,
},
RequiredTranches::Exact { needed: 0, tolerated_missing: 0, next_no_show: None },
);
}
@@ -17,21 +17,22 @@
//! Version 1 of the DB schema.
use kvdb::{DBTransaction, KeyValueDB};
use polkadot_node_subsystem::{SubsystemResult, SubsystemError};
use polkadot_node_primitives::approval::{DelayTranche, AssignmentCert};
use parity_scale_codec::{Decode, Encode};
use polkadot_node_primitives::approval::{AssignmentCert, DelayTranche};
use polkadot_node_subsystem::{SubsystemError, SubsystemResult};
use polkadot_primitives::v1::{
ValidatorIndex, GroupIndex, CandidateReceipt, SessionIndex, CoreIndex,
BlockNumber, Hash, CandidateHash, ValidatorSignature,
BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, SessionIndex,
ValidatorIndex, ValidatorSignature,
};
use sp_consensus_slots::Slot;
use parity_scale_codec::{Encode, Decode};
use std::collections::BTreeMap;
use std::sync::Arc;
use bitvec::{vec::BitVec, order::Lsb0 as BitOrderLsb0};
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
use std::{collections::BTreeMap, sync::Arc};
use crate::backend::{Backend, BackendWriteOp};
use crate::persisted_entries;
use crate::{
backend::{Backend, BackendWriteOp},
persisted_entries,
};
const STORED_BLOCKS_KEY: &[u8] = b"Approvals_StoredBlocks";
@@ -48,10 +49,7 @@ impl DbBackend {
/// Create a new [`DbBackend`] with the supplied key-value store and
/// config.
pub fn new(db: Arc<dyn KeyValueDB>, config: Config) -> Self {
DbBackend {
inner: db,
config,
}
DbBackend { inner: db, config }
}
}
@@ -60,22 +58,17 @@ impl Backend for DbBackend {
&self,
block_hash: &Hash,
) -> SubsystemResult<Option<persisted_entries::BlockEntry>> {
load_block_entry(&*self.inner, &self.config, block_hash)
.map(|e| e.map(Into::into))
load_block_entry(&*self.inner, &self.config, block_hash).map(|e| e.map(Into::into))
}
fn load_candidate_entry(
&self,
candidate_hash: &CandidateHash,
) -> SubsystemResult<Option<persisted_entries::CandidateEntry>> {
load_candidate_entry(&*self.inner, &self.config, candidate_hash)
.map(|e| e.map(Into::into))
load_candidate_entry(&*self.inner, &self.config, candidate_hash).map(|e| e.map(Into::into))
}
fn load_blocks_at_height(
&self,
block_height: &BlockNumber
) -> SubsystemResult<Vec<Hash>> {
fn load_blocks_at_height(&self, block_height: &BlockNumber) -> SubsystemResult<Vec<Hash>> {
load_blocks_at_height(&*self.inner, &self.config, block_height)
}
@@ -89,7 +82,8 @@ impl Backend for DbBackend {
/// Atomically write the list of operations, with later operations taking precedence over prior.
fn write<I>(&mut self, ops: I) -> SubsystemResult<()>
where I: IntoIterator<Item = BackendWriteOp>
where
I: IntoIterator<Item = BackendWriteOp>,
{
let mut tx = DBTransaction::new();
for op in ops {
@@ -100,20 +94,13 @@ impl Backend for DbBackend {
&STORED_BLOCKS_KEY,
stored_block_range.encode(),
);
}
},
BackendWriteOp::WriteBlocksAtHeight(h, blocks) => {
tx.put_vec(
self.config.col_data,
&blocks_at_height_key(h),
blocks.encode(),
);
}
tx.put_vec(self.config.col_data, &blocks_at_height_key(h), blocks.encode());
},
BackendWriteOp::DeleteBlocksAtHeight(h) => {
tx.delete(
self.config.col_data,
&blocks_at_height_key(h),
);
}
tx.delete(self.config.col_data, &blocks_at_height_key(h));
},
BackendWriteOp::WriteBlockEntry(block_entry) => {
let block_entry: BlockEntry = block_entry.into();
tx.put_vec(
@@ -121,13 +108,10 @@ impl Backend for DbBackend {
&block_entry_key(&block_entry.block_hash),
block_entry.encode(),
);
}
},
BackendWriteOp::DeleteBlockEntry(hash) => {
tx.delete(
self.config.col_data,
&block_entry_key(&hash),
);
}
tx.delete(self.config.col_data, &block_entry_key(&hash));
},
BackendWriteOp::WriteCandidateEntry(candidate_entry) => {
let candidate_entry: CandidateEntry = candidate_entry.into();
tx.put_vec(
@@ -135,13 +119,10 @@ impl Backend for DbBackend {
&candidate_entry_key(&candidate_entry.candidate.hash()),
candidate_entry.encode(),
);
}
},
BackendWriteOp::DeleteCandidateEntry(candidate_hash) => {
tx.delete(
self.config.col_data,
&candidate_entry_key(&candidate_hash),
);
}
tx.delete(self.config.col_data, &candidate_entry_key(&candidate_hash));
},
}
}
@@ -257,13 +238,14 @@ impl std::error::Error for Error {}
/// Result alias for DB errors.
pub type Result<T> = std::result::Result<T, Error>;
pub(crate) fn load_decode<D: Decode>(store: &dyn KeyValueDB, col_data: u32, key: &[u8]) -> Result<Option<D>>
{
pub(crate) fn load_decode<D: Decode>(
store: &dyn KeyValueDB,
col_data: u32,
key: &[u8],
) -> Result<Option<D>> {
match store.get(col_data, key)? {
None => Ok(None),
Some(raw) => D::decode(&mut &raw[..])
.map(Some)
.map_err(Into::into),
Some(raw) => D::decode(&mut &raw[..]).map(Some).map_err(Into::into),
}
}
@@ -308,7 +290,6 @@ pub fn load_all_blocks(store: &dyn KeyValueDB, config: &Config) -> SubsystemResu
let blocks = load_blocks_at_height(store, config, &height)?;
hashes.extend(blocks);
}
}
Ok(hashes)
@@ -16,21 +16,19 @@
//! Tests for the aux-schema of approval voting.
use super::*;
use std::sync::Arc;
use std::collections::HashMap;
use polkadot_primitives::v1::Id as ParaId;
use super::{DbBackend, StoredBlockRange, *};
use crate::{
backend::{Backend, OverlayedBackend},
ops::{add_block_entry, canonicalize, force_approve, NewCandidateInfo},
};
use kvdb::KeyValueDB;
use super::{DbBackend, StoredBlockRange};
use crate::backend::{Backend, OverlayedBackend};
use crate::ops::{NewCandidateInfo, add_block_entry, force_approve, canonicalize};
use polkadot_primitives::v1::Id as ParaId;
use std::{collections::HashMap, sync::Arc};
const DATA_COL: u32 = 0;
const NUM_COLUMNS: u32 = 1;
const TEST_CONFIG: Config = Config {
col_data: DATA_COL,
};
const TEST_CONFIG: Config = Config { col_data: DATA_COL };
fn make_db() -> (DbBackend, Arc<dyn KeyValueDB>) {
let db_writer: Arc<dyn KeyValueDB> = Arc::new(kvdb_memorydb::create(NUM_COLUMNS));
@@ -80,26 +78,25 @@ fn read_write() {
let range = StoredBlockRange(10, 20);
let at_height = vec![hash_a, hash_b];
let block_entry = make_block_entry(
hash_a,
Default::default(),
1,
vec![(CoreIndex(0), candidate_hash)],
);
let block_entry =
make_block_entry(hash_a, Default::default(), 1, vec![(CoreIndex(0), candidate_hash)]);
let candidate_entry = CandidateEntry {
candidate: Default::default(),
session: 5,
block_assignments: vec![
(hash_a, ApprovalEntry {
block_assignments: vec![(
hash_a,
ApprovalEntry {
tranches: Vec::new(),
backing_group: GroupIndex(1),
our_assignment: None,
our_approval_sig: None,
assignments: Default::default(),
approved: false,
})
].into_iter().collect(),
},
)]
.into_iter()
.collect(),
approvals: Default::default(),
};
@@ -114,7 +111,10 @@ fn read_write() {
assert_eq!(load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap(), Some(range));
assert_eq!(load_blocks_at_height(store.as_ref(), &TEST_CONFIG, &1).unwrap(), at_height);
assert_eq!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap(), Some(block_entry.into()));
assert_eq!(
load_block_entry(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap(),
Some(block_entry.into())
);
assert_eq!(
load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash).unwrap(),
Some(candidate_entry.into()),
@@ -129,7 +129,9 @@ fn read_write() {
assert!(load_blocks_at_height(store.as_ref(), &TEST_CONFIG, &1).unwrap().is_empty());
assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap().is_none());
assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash).unwrap().is_none());
assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash)
.unwrap()
.is_none());
}
#[test]
@@ -165,47 +167,48 @@ fn add_block_entry_works() {
let n_validators = 10;
let mut new_candidate_info = HashMap::new();
new_candidate_info.insert(candidate_hash_a, NewCandidateInfo::new(
candidate_receipt_a,
GroupIndex(0),
None,
));
new_candidate_info
.insert(candidate_hash_a, NewCandidateInfo::new(candidate_receipt_a, GroupIndex(0), None));
let mut overlay_db = OverlayedBackend::new(&db);
add_block_entry(
&mut overlay_db,
block_entry_a.clone().into(),
n_validators,
|h| new_candidate_info.get(h).map(|x| x.clone()),
).unwrap();
add_block_entry(&mut overlay_db, block_entry_a.clone().into(), n_validators, |h| {
new_candidate_info.get(h).map(|x| x.clone())
})
.unwrap();
let write_ops = overlay_db.into_write_ops();
db.write(write_ops).unwrap();
new_candidate_info.insert(candidate_hash_b, NewCandidateInfo::new(
candidate_receipt_b,
GroupIndex(1),
None,
));
new_candidate_info
.insert(candidate_hash_b, NewCandidateInfo::new(candidate_receipt_b, GroupIndex(1), None));
let mut overlay_db = OverlayedBackend::new(&db);
add_block_entry(
&mut overlay_db,
block_entry_b.clone().into(),
n_validators,
|h| new_candidate_info.get(h).map(|x| x.clone()),
).unwrap();
add_block_entry(&mut overlay_db, block_entry_b.clone().into(), n_validators, |h| {
new_candidate_info.get(h).map(|x| x.clone())
})
.unwrap();
let write_ops = overlay_db.into_write_ops();
db.write(write_ops).unwrap();
assert_eq!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), Some(block_entry_a.into()));
assert_eq!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), Some(block_entry_b.into()));
assert_eq!(
load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(),
Some(block_entry_a.into())
);
assert_eq!(
load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(),
Some(block_entry_b.into())
);
let candidate_entry_a = load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash_a)
.unwrap().unwrap();
assert_eq!(candidate_entry_a.block_assignments.keys().collect::<Vec<_>>(), vec![&block_hash_a, &block_hash_b]);
.unwrap()
.unwrap();
assert_eq!(
candidate_entry_a.block_assignments.keys().collect::<Vec<_>>(),
vec![&block_hash_a, &block_hash_b]
);
let candidate_entry_b = load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash_b)
.unwrap().unwrap();
.unwrap()
.unwrap();
assert_eq!(candidate_entry_b.block_assignments.keys().collect::<Vec<_>>(), vec![&block_hash_b]);
}
@@ -217,44 +220,30 @@ fn add_block_entry_adds_child() {
let block_hash_a = Hash::repeat_byte(2);
let block_hash_b = Hash::repeat_byte(69);
let mut block_entry_a = make_block_entry(
block_hash_a,
parent_hash,
1,
Vec::new(),
);
let mut block_entry_a = make_block_entry(block_hash_a, parent_hash, 1, Vec::new());
let block_entry_b = make_block_entry(
block_hash_b,
block_hash_a,
2,
Vec::new(),
);
let block_entry_b = make_block_entry(block_hash_b, block_hash_a, 2, Vec::new());
let n_validators = 10;
let mut overlay_db = OverlayedBackend::new(&db);
add_block_entry(
&mut overlay_db,
block_entry_a.clone().into(),
n_validators,
|_| None,
).unwrap();
add_block_entry(&mut overlay_db, block_entry_a.clone().into(), n_validators, |_| None).unwrap();
add_block_entry(
&mut overlay_db,
block_entry_b.clone().into(),
n_validators,
|_| None,
).unwrap();
add_block_entry(&mut overlay_db, block_entry_b.clone().into(), n_validators, |_| None).unwrap();
let write_ops = overlay_db.into_write_ops();
db.write(write_ops).unwrap();
block_entry_a.children.push(block_hash_b);
assert_eq!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), Some(block_entry_a.into()));
assert_eq!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), Some(block_entry_b.into()));
assert_eq!(
load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(),
Some(block_entry_a.into())
);
assert_eq!(
load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(),
Some(block_entry_b.into())
);
}
#[test]
@@ -305,12 +294,8 @@ fn canonicalize_works() {
let block_entry_a = make_block_entry(block_hash_a, genesis, 1, Vec::new());
let block_entry_b1 = make_block_entry(block_hash_b1, block_hash_a, 2, Vec::new());
let block_entry_b2 = make_block_entry(
block_hash_b2,
block_hash_a,
2,
vec![(CoreIndex(0), cand_hash_1)],
);
let block_entry_b2 =
make_block_entry(block_hash_b2, block_hash_a, 2, vec![(CoreIndex(0), cand_hash_1)]);
let block_entry_c1 = make_block_entry(block_hash_c1, block_hash_b1, 3, Vec::new());
let block_entry_c2 = make_block_entry(
block_hash_c2,
@@ -324,44 +309,27 @@ fn canonicalize_works() {
4,
vec![(CoreIndex(0), cand_hash_3), (CoreIndex(1), cand_hash_4)],
);
let block_entry_d2 = make_block_entry(
block_hash_d2,
block_hash_c2,
4,
vec![(CoreIndex(0), cand_hash_5)],
);
let block_entry_d2 =
make_block_entry(block_hash_d2, block_hash_c2, 4, vec![(CoreIndex(0), cand_hash_5)]);
let candidate_info = {
let mut candidate_info = HashMap::new();
candidate_info.insert(cand_hash_1, NewCandidateInfo::new(
candidate_receipt_genesis,
GroupIndex(1),
None,
));
candidate_info.insert(
cand_hash_1,
NewCandidateInfo::new(candidate_receipt_genesis, GroupIndex(1), None),
);
candidate_info.insert(cand_hash_2, NewCandidateInfo::new(
candidate_receipt_a,
GroupIndex(2),
None,
));
candidate_info
.insert(cand_hash_2, NewCandidateInfo::new(candidate_receipt_a, GroupIndex(2), None));
candidate_info.insert(cand_hash_3, NewCandidateInfo::new(
candidate_receipt_b,
GroupIndex(3),
None,
));
candidate_info
.insert(cand_hash_3, NewCandidateInfo::new(candidate_receipt_b, GroupIndex(3), None));
candidate_info.insert(cand_hash_4, NewCandidateInfo::new(
candidate_receipt_b1,
GroupIndex(4),
None,
));
candidate_info
.insert(cand_hash_4, NewCandidateInfo::new(candidate_receipt_b1, GroupIndex(4), None));
candidate_info.insert(cand_hash_5, NewCandidateInfo::new(
candidate_receipt_c1,
GroupIndex(5),
None,
));
candidate_info
.insert(cand_hash_5, NewCandidateInfo::new(candidate_receipt_c1, GroupIndex(5), None));
candidate_info
};
@@ -379,12 +347,10 @@ fn canonicalize_works() {
let mut overlay_db = OverlayedBackend::new(&db);
for block_entry in blocks {
add_block_entry(
&mut overlay_db,
block_entry.into(),
n_validators,
|h| candidate_info.get(h).map(|x| x.clone()),
).unwrap();
add_block_entry(&mut overlay_db, block_entry.into(), n_validators, |h| {
candidate_info.get(h).map(|x| x.clone())
})
.unwrap();
}
let write_ops = overlay_db.into_write_ops();
db.write(write_ops).unwrap();
@@ -393,9 +359,11 @@ fn canonicalize_works() {
for (c_hash, in_blocks) in expected {
let (entry, in_blocks) = match in_blocks {
None => {
assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &c_hash).unwrap().is_none());
assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &c_hash)
.unwrap()
.is_none());
continue
}
},
Some(i) => (
load_candidate_entry(store.as_ref(), &TEST_CONFIG, &c_hash).unwrap().unwrap(),
i,
@@ -414,13 +382,13 @@ fn canonicalize_works() {
for (hash, with_candidates) in expected {
let (entry, with_candidates) = match with_candidates {
None => {
assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash).unwrap().is_none());
assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash)
.unwrap()
.is_none());
continue
}
Some(i) => (
load_block_entry(store.as_ref(), &TEST_CONFIG, &hash).unwrap().unwrap(),
i,
),
},
Some(i) =>
(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash).unwrap().unwrap(), i),
};
assert_eq!(entry.candidates.len(), with_candidates.len());
@@ -454,7 +422,10 @@ fn canonicalize_works() {
let write_ops = overlay_db.into_write_ops();
db.write(write_ops).unwrap();
assert_eq!(load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap().unwrap(), StoredBlockRange(4, 5));
assert_eq!(
load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap().unwrap(),
StoredBlockRange(4, 5)
);
check_candidates_in_store(vec![
(cand_hash_1, None),
@@ -489,25 +460,31 @@ fn force_approve_works() {
let single_candidate_vec = vec![(CoreIndex(0), candidate_hash)];
let candidate_info = {
let mut candidate_info = HashMap::new();
candidate_info.insert(candidate_hash, NewCandidateInfo::new(
make_candidate(1.into(), Default::default()),
GroupIndex(1),
None,
));
candidate_info.insert(
candidate_hash,
NewCandidateInfo::new(
make_candidate(1.into(), Default::default()),
GroupIndex(1),
None,
),
);
candidate_info
};
let block_hash_a = Hash::repeat_byte(1); // 1
let block_hash_b = Hash::repeat_byte(2);
let block_hash_c = Hash::repeat_byte(3);
let block_hash_d = Hash::repeat_byte(4); // 4
let block_entry_a = make_block_entry(block_hash_a, Default::default(), 1, single_candidate_vec.clone());
let block_entry_b = make_block_entry(block_hash_b, block_hash_a, 2, single_candidate_vec.clone());
let block_entry_c = make_block_entry(block_hash_c, block_hash_b, 3, single_candidate_vec.clone());
let block_entry_d = make_block_entry(block_hash_d, block_hash_c, 4, single_candidate_vec.clone());
let block_entry_a =
make_block_entry(block_hash_a, Default::default(), 1, single_candidate_vec.clone());
let block_entry_b =
make_block_entry(block_hash_b, block_hash_a, 2, single_candidate_vec.clone());
let block_entry_c =
make_block_entry(block_hash_c, block_hash_b, 3, single_candidate_vec.clone());
let block_entry_d =
make_block_entry(block_hash_d, block_hash_c, 4, single_candidate_vec.clone());
let blocks = vec![
block_entry_a.clone(),
@@ -518,41 +495,36 @@ fn force_approve_works() {
let mut overlay_db = OverlayedBackend::new(&db);
for block_entry in blocks {
add_block_entry(
&mut overlay_db,
block_entry.into(),
n_validators,
|h| candidate_info.get(h).map(|x| x.clone()),
).unwrap();
add_block_entry(&mut overlay_db, block_entry.into(), n_validators, |h| {
candidate_info.get(h).map(|x| x.clone())
})
.unwrap();
}
let approved_hashes = force_approve(&mut overlay_db, block_hash_d, 2).unwrap();
let approved_hashes = force_approve(&mut overlay_db, block_hash_d, 2).unwrap();
let write_ops = overlay_db.into_write_ops();
db.write(write_ops).unwrap();
assert!(load_block_entry(
store.as_ref(),
&TEST_CONFIG,
&block_hash_a,
).unwrap().unwrap().approved_bitfield.all());
assert!(load_block_entry(
store.as_ref(),
&TEST_CONFIG,
&block_hash_b,
).unwrap().unwrap().approved_bitfield.all());
assert!(load_block_entry(
store.as_ref(),
&TEST_CONFIG,
&block_hash_c,
).unwrap().unwrap().approved_bitfield.not_any());
assert!(load_block_entry(
store.as_ref(),
&TEST_CONFIG,
&block_hash_d,
).unwrap().unwrap().approved_bitfield.not_any());
assert_eq!(
approved_hashes,
vec![block_hash_b, block_hash_a],
);
assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a,)
.unwrap()
.unwrap()
.approved_bitfield
.all());
assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b,)
.unwrap()
.unwrap()
.approved_bitfield
.all());
assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_c,)
.unwrap()
.unwrap()
.approved_bitfield
.not_any());
assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_d,)
.unwrap()
.unwrap()
.approved_bitfield
.not_any());
assert_eq!(approved_hashes, vec![block_hash_b, block_hash_a],);
}
#[test]
@@ -566,60 +538,27 @@ fn load_all_blocks_works() {
let block_number = 10;
let block_entry_a = make_block_entry(
block_hash_a,
parent_hash,
block_number,
vec![],
);
let block_entry_a = make_block_entry(block_hash_a, parent_hash, block_number, vec![]);
let block_entry_b = make_block_entry(
block_hash_b,
parent_hash,
block_number,
vec![],
);
let block_entry_b = make_block_entry(block_hash_b, parent_hash, block_number, vec![]);
let block_entry_c = make_block_entry(
block_hash_c,
block_hash_a,
block_number + 1,
vec![],
);
let block_entry_c = make_block_entry(block_hash_c, block_hash_a, block_number + 1, vec![]);
let n_validators = 10;
let mut overlay_db = OverlayedBackend::new(&db);
add_block_entry(
&mut overlay_db,
block_entry_a.clone().into(),
n_validators,
|_| None
).unwrap();
add_block_entry(&mut overlay_db, block_entry_a.clone().into(), n_validators, |_| None).unwrap();
// add C before B to test sorting.
add_block_entry(
&mut overlay_db,
block_entry_c.clone().into(),
n_validators,
|_| None
).unwrap();
add_block_entry(&mut overlay_db, block_entry_c.clone().into(), n_validators, |_| None).unwrap();
add_block_entry(
&mut overlay_db,
block_entry_b.clone().into(),
n_validators,
|_| None
).unwrap();
add_block_entry(&mut overlay_db, block_entry_b.clone().into(), n_validators, |_| None).unwrap();
let write_ops = overlay_db.into_write_ops();
db.write(write_ops).unwrap();
assert_eq!(
load_all_blocks(
store.as_ref(),
&TEST_CONFIG
).unwrap(),
load_all_blocks(store.as_ref(), &TEST_CONFIG).unwrap(),
vec![block_hash_a, block_hash_b, block_hash_c],
)
}
@@ -21,13 +21,15 @@
//! [`Backend`], maintaining consistency between queries and temporary writes,
//! before any commit to the underlying storage is made.
use polkadot_node_subsystem::{SubsystemResult};
use polkadot_node_subsystem::SubsystemResult;
use polkadot_primitives::v1::{BlockNumber, CandidateHash, Hash};
use std::collections::HashMap;
use super::approval_db::v1::StoredBlockRange;
use super::persisted_entries::{BlockEntry, CandidateEntry};
use super::{
approval_db::v1::StoredBlockRange,
persisted_entries::{BlockEntry, CandidateEntry},
};
#[derive(Debug)]
pub enum BackendWriteOp {
@@ -45,7 +47,10 @@ pub trait Backend {
/// Load a block entry from the DB.
fn load_block_entry(&self, hash: &Hash) -> SubsystemResult<Option<BlockEntry>>;
/// Load a candidate entry from the DB.
fn load_candidate_entry(&self, candidate_hash: &CandidateHash) -> SubsystemResult<Option<CandidateEntry>>;
fn load_candidate_entry(
&self,
candidate_hash: &CandidateHash,
) -> SubsystemResult<Option<CandidateEntry>>;
/// Load all blocks at a specific height.
fn load_blocks_at_height(&self, height: &BlockNumber) -> SubsystemResult<Vec<Hash>>;
/// Load all block from the DB.
@@ -54,7 +59,8 @@ pub trait Backend {
fn load_stored_blocks(&self) -> SubsystemResult<Option<StoredBlockRange>>;
/// Atomically write the list of operations, with later operations taking precedence over prior.
fn write<I>(&mut self, ops: I) -> SubsystemResult<()>
where I: IntoIterator<Item = BackendWriteOp>;
where
I: IntoIterator<Item = BackendWriteOp>;
}
/// An in-memory overlay over the backend.
@@ -128,7 +134,10 @@ impl<'a, B: 'a + Backend> OverlayedBackend<'a, B> {
self.inner.load_block_entry(hash)
}
pub fn load_candidate_entry(&self, candidate_hash: &CandidateHash) -> SubsystemResult<Option<CandidateEntry>> {
pub fn load_candidate_entry(
&self,
candidate_hash: &CandidateHash,
) -> SubsystemResult<Option<CandidateEntry>> {
if let Some(val) = self.candidate_entries.get(&candidate_hash) {
return Ok(val.clone())
}
+123 -117
View File
@@ -16,21 +16,20 @@
//! Assignment criteria VRF generation and checking.
use parity_scale_codec::{Decode, Encode};
use polkadot_node_primitives::approval::{
self as approval_types, AssignmentCert, AssignmentCertKind, DelayTranche, RelayVRFStory,
};
use polkadot_primitives::v1::{
CoreIndex, ValidatorIndex, SessionInfo, AssignmentPair, AssignmentId, GroupIndex, CandidateHash,
AssignmentId, AssignmentPair, CandidateHash, CoreIndex, GroupIndex, SessionInfo, ValidatorIndex,
};
use sc_keystore::LocalKeystore;
use parity_scale_codec::{Encode, Decode};
use sp_application_crypto::Public;
use merlin::Transcript;
use schnorrkel::vrf::VRFInOut;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::{hash_map::Entry, HashMap};
use super::LOG_TARGET;
@@ -88,10 +87,7 @@ impl From<OurAssignment> for crate::approval_db::v1::OurAssignment {
}
}
fn relay_vrf_modulo_transcript(
relay_vrf_story: RelayVRFStory,
sample: u32,
) -> Transcript {
fn relay_vrf_modulo_transcript(relay_vrf_story: RelayVRFStory, sample: u32) -> Transcript {
// combine the relay VRF story with a sample number.
let mut t = Transcript::new(approval_types::RELAY_VRF_MODULO_CONTEXT);
t.append_message(b"RC-VRF", &relay_vrf_story.0);
@@ -100,10 +96,7 @@ fn relay_vrf_modulo_transcript(
t
}
fn relay_vrf_modulo_core(
vrf_in_out: &VRFInOut,
n_cores: u32,
) -> CoreIndex {
fn relay_vrf_modulo_core(vrf_in_out: &VRFInOut, n_cores: u32) -> CoreIndex {
let bytes: [u8; 4] = vrf_in_out.make_bytes(approval_types::CORE_RANDOMNESS_CONTEXT);
// interpret as little-endian u32.
@@ -111,10 +104,7 @@ fn relay_vrf_modulo_core(
CoreIndex(random_core)
}
fn relay_vrf_delay_transcript(
relay_vrf_story: RelayVRFStory,
core_index: CoreIndex,
) -> Transcript {
fn relay_vrf_delay_transcript(relay_vrf_story: RelayVRFStory, core_index: CoreIndex) -> Transcript {
let mut t = Transcript::new(approval_types::RELAY_VRF_DELAY_CONTEXT);
t.append_message(b"RC-VRF", &relay_vrf_story.0);
core_index.0.using_encoded(|s| t.append_message(b"core", s));
@@ -129,7 +119,8 @@ fn relay_vrf_delay_tranche(
let bytes: [u8; 4] = vrf_in_out.make_bytes(approval_types::TRANCHE_RANDOMNESS_CONTEXT);
// interpret as little-endian u32 and reduce by the number of tranches.
let wide_tranche = u32::from_le_bytes(bytes) % (num_delay_tranches + zeroth_delay_tranche_width);
let wide_tranche =
u32::from_le_bytes(bytes) % (num_delay_tranches + zeroth_delay_tranche_width);
// Consolidate early results to tranche zero so tranche zero is extra wide.
wide_tranche.saturating_sub(zeroth_delay_tranche_width)
@@ -202,12 +193,7 @@ impl AssignmentCriteria for RealAssignmentCriteria {
config: &Config,
leaving_cores: Vec<(CandidateHash, CoreIndex, GroupIndex)>,
) -> HashMap<CoreIndex, OurAssignment> {
compute_assignments(
keystore,
relay_vrf_story,
config,
leaving_cores,
)
compute_assignments(keystore, relay_vrf_story, config, leaving_cores)
}
fn check_assignment_cert(
@@ -246,13 +232,16 @@ pub(crate) fn compute_assignments(
config: &Config,
leaving_cores: impl IntoIterator<Item = (CandidateHash, CoreIndex, GroupIndex)> + Clone,
) -> HashMap<CoreIndex, OurAssignment> {
if config.n_cores == 0 || config.assignment_keys.is_empty() || config.validator_groups.is_empty() {
if config.n_cores == 0 ||
config.assignment_keys.is_empty() ||
config.validator_groups.is_empty()
{
return HashMap::new()
}
let (index, assignments_key): (ValidatorIndex, AssignmentPair) = {
let key = config.assignment_keys.iter().enumerate()
.find_map(|(i, p)| match keystore.key_pair(p) {
let key = config.assignment_keys.iter().enumerate().find_map(|(i, p)| {
match keystore.key_pair(p) {
Ok(Some(pair)) => Some((ValidatorIndex(i as _), pair)),
Ok(None) => None,
Err(sc_keystore::Error::Unavailable) => None,
@@ -260,8 +249,9 @@ pub(crate) fn compute_assignments(
Err(e) => {
tracing::warn!(target: LOG_TARGET, "Encountered keystore error: {:?}", e);
None
}
});
},
}
});
match key {
None => return Default::default(),
@@ -270,7 +260,8 @@ pub(crate) fn compute_assignments(
};
// Ignore any cores where the assigned group is our own.
let leaving_cores = leaving_cores.into_iter()
let leaving_cores = leaving_cores
.into_iter()
.filter(|&(_, _, ref g)| !is_in_backing_group(&config.validator_groups, index, *g))
.map(|(c_hash, core, _)| (c_hash, core))
.collect::<Vec<_>>();
@@ -322,8 +313,8 @@ fn compute_relay_vrf_modulo_assignments(
relay_vrf_modulo_transcript(relay_vrf_story.clone(), rvm_sample),
|vrf_in_out| {
*core = relay_vrf_modulo_core(&vrf_in_out, config.n_cores);
if let Some((candidate_hash, _))
= leaving_cores.clone().into_iter().find(|(_, c)| c == core)
if let Some((candidate_hash, _)) =
leaving_cores.clone().into_iter().find(|(_, c)| c == core)
{
tracing::trace!(
target: LOG_TARGET,
@@ -338,7 +329,7 @@ fn compute_relay_vrf_modulo_assignments(
} else {
None
}
}
},
)
};
@@ -347,7 +338,10 @@ fn compute_relay_vrf_modulo_assignments(
// has been executed.
let cert = AssignmentCert {
kind: AssignmentCertKind::RelayVRFModulo { sample: rvm_sample },
vrf: (approval_types::VRFOutput(vrf_in_out.to_output()), approval_types::VRFProof(vrf_proof)),
vrf: (
approval_types::VRFOutput(vrf_in_out.to_output()),
approval_types::VRFProof(vrf_proof),
),
};
// All assignments of type RelayVRFModulo have tranche 0.
@@ -370,9 +364,8 @@ fn compute_relay_vrf_delay_assignments(
assignments: &mut HashMap<CoreIndex, OurAssignment>,
) {
for (candidate_hash, core) in leaving_cores {
let (vrf_in_out, vrf_proof, _) = assignments_key.vrf_sign(
relay_vrf_delay_transcript(relay_vrf_story.clone(), core),
);
let (vrf_in_out, vrf_proof, _) =
assignments_key.vrf_sign(relay_vrf_delay_transcript(relay_vrf_story.clone(), core));
let tranche = relay_vrf_delay_tranche(
&vrf_in_out,
@@ -382,24 +375,26 @@ fn compute_relay_vrf_delay_assignments(
let cert = AssignmentCert {
kind: AssignmentCertKind::RelayVRFDelay { core_index: core },
vrf: (approval_types::VRFOutput(vrf_in_out.to_output()), approval_types::VRFProof(vrf_proof)),
vrf: (
approval_types::VRFOutput(vrf_in_out.to_output()),
approval_types::VRFProof(vrf_proof),
),
};
let our_assignment = OurAssignment {
cert,
tranche,
validator_index,
triggered: false,
};
let our_assignment = OurAssignment { cert, tranche, validator_index, triggered: false };
let used = match assignments.entry(core) {
Entry::Vacant(e) => { let _ = e.insert(our_assignment); true }
Entry::Occupied(mut e) => if e.get().tranche > our_assignment.tranche {
e.insert(our_assignment);
Entry::Vacant(e) => {
let _ = e.insert(our_assignment);
true
} else {
false
},
Entry::Occupied(mut e) =>
if e.get().tranche > our_assignment.tranche {
e.insert(our_assignment);
true
} else {
false
},
};
if used {
@@ -425,7 +420,7 @@ impl std::fmt::Display for InvalidAssignment {
}
}
impl std::error::Error for InvalidAssignment { }
impl std::error::Error for InvalidAssignment {}
/// Checks the crypto of an assignment cert. Failure conditions:
/// * Validator index out of bounds
@@ -446,7 +441,8 @@ pub(crate) fn check_assignment_cert(
assignment: &AssignmentCert,
backing_group: GroupIndex,
) -> Result<DelayTranche, InvalidAssignment> {
let validator_public = config.assignment_keys
let validator_public = config
.assignment_keys
.get(validator_index.0 as usize)
.ok_or(InvalidAssignment)?;
@@ -454,34 +450,33 @@ pub(crate) fn check_assignment_cert(
.map_err(|_| InvalidAssignment)?;
if claimed_core_index.0 >= config.n_cores {
return Err(InvalidAssignment);
return Err(InvalidAssignment)
}
// Check that the validator was not part of the backing group
// and not already assigned.
let is_in_backing = is_in_backing_group(
&config.validator_groups,
validator_index,
backing_group,
);
let is_in_backing =
is_in_backing_group(&config.validator_groups, validator_index, backing_group);
if is_in_backing {
return Err(InvalidAssignment);
return Err(InvalidAssignment)
}
let &(ref vrf_output, ref vrf_proof) = &assignment.vrf;
match assignment.kind {
AssignmentCertKind::RelayVRFModulo { sample } => {
if sample >= config.relay_vrf_modulo_samples {
return Err(InvalidAssignment);
return Err(InvalidAssignment)
}
let (vrf_in_out, _) = public.vrf_verify_extra(
relay_vrf_modulo_transcript(relay_vrf_story, sample),
&vrf_output.0,
&vrf_proof.0,
assigned_core_transcript(claimed_core_index),
).map_err(|_| InvalidAssignment)?;
let (vrf_in_out, _) = public
.vrf_verify_extra(
relay_vrf_modulo_transcript(relay_vrf_story, sample),
&vrf_output.0,
&vrf_proof.0,
assigned_core_transcript(claimed_core_index),
)
.map_err(|_| InvalidAssignment)?;
// ensure that the `vrf_in_out` actually gives us the claimed core.
if relay_vrf_modulo_core(&vrf_in_out, config.n_cores) == claimed_core_index {
@@ -489,24 +484,26 @@ pub(crate) fn check_assignment_cert(
} else {
Err(InvalidAssignment)
}
}
},
AssignmentCertKind::RelayVRFDelay { core_index } => {
if core_index != claimed_core_index {
return Err(InvalidAssignment);
return Err(InvalidAssignment)
}
let (vrf_in_out, _) = public.vrf_verify(
relay_vrf_delay_transcript(relay_vrf_story, core_index),
&vrf_output.0,
&vrf_proof.0,
).map_err(|_| InvalidAssignment)?;
let (vrf_in_out, _) = public
.vrf_verify(
relay_vrf_delay_transcript(relay_vrf_story, core_index),
&vrf_output.0,
&vrf_proof.0,
)
.map_err(|_| InvalidAssignment)?;
Ok(relay_vrf_delay_tranche(
&vrf_in_out,
config.n_delay_tranches,
config.zeroth_delay_tranche_width,
))
}
},
}
}
@@ -521,22 +518,22 @@ fn is_in_backing_group(
#[cfg(test)]
mod tests {
use super::*;
use sp_keystore::CryptoStore;
use sp_keyring::sr25519::Keyring as Sr25519Keyring;
use polkadot_node_primitives::approval::{VRFOutput, VRFProof};
use polkadot_primitives::v1::{Hash, ASSIGNMENT_KEY_TYPE_ID};
use sp_application_crypto::sr25519;
use sp_core::crypto::Pair as PairT;
use polkadot_primitives::v1::{ASSIGNMENT_KEY_TYPE_ID, Hash};
use polkadot_node_primitives::approval::{VRFOutput, VRFProof};
use sp_keyring::sr25519::Keyring as Sr25519Keyring;
use sp_keystore::CryptoStore;
// sets up a keystore with the given keyring accounts.
async fn make_keystore(accounts: &[Sr25519Keyring]) -> LocalKeystore {
let store = LocalKeystore::in_memory();
for s in accounts.iter().copied().map(|k| k.to_seed()) {
store.sr25519_generate_new(
ASSIGNMENT_KEY_TYPE_ID,
Some(s.as_str()),
).await.unwrap();
store
.sr25519_generate_new(ASSIGNMENT_KEY_TYPE_ID, Some(s.as_str()))
.await
.unwrap();
}
store
@@ -546,12 +543,15 @@ mod tests {
assignment_keys_plus_random(accounts, 0)
}
fn assignment_keys_plus_random(accounts: &[Sr25519Keyring], random: usize) -> Vec<AssignmentId> {
let gen_random = (0..random).map(|_|
AssignmentId::from(sr25519::Pair::generate().0.public())
);
fn assignment_keys_plus_random(
accounts: &[Sr25519Keyring],
random: usize,
) -> Vec<AssignmentId> {
let gen_random =
(0..random).map(|_| AssignmentId::from(sr25519::Pair::generate().0.public()));
accounts.iter()
accounts
.iter()
.map(|k| AssignmentId::from(k.public()))
.chain(gen_random)
.collect()
@@ -562,12 +562,14 @@ mod tests {
let big_groups = n_validators % n_groups;
let scraps = n_groups * size;
(0..n_groups).map(|i| {
(i * size .. (i + 1) *size)
.chain(if i < big_groups { Some(scraps + i) } else { None })
.map(|j| ValidatorIndex(j as _))
.collect::<Vec<_>>()
}).collect()
(0..n_groups)
.map(|i| {
(i * size..(i + 1) * size)
.chain(if i < big_groups { Some(scraps + i) } else { None })
.map(|j| ValidatorIndex(j as _))
.collect::<Vec<_>>()
})
.collect()
}
// used for generating assignments where the validity of the VRF doesn't matter.
@@ -581,9 +583,7 @@ mod tests {
#[test]
fn assignments_produced_for_non_backing() {
let keystore = futures::executor::block_on(
make_keystore(&[Sr25519Keyring::Alice])
);
let keystore = futures::executor::block_on(make_keystore(&[Sr25519Keyring::Alice]));
let c_a = CandidateHash(Hash::repeat_byte(0));
let c_b = CandidateHash(Hash::repeat_byte(1));
@@ -598,7 +598,10 @@ mod tests {
Sr25519Keyring::Bob,
Sr25519Keyring::Charlie,
]),
validator_groups: vec![vec![ValidatorIndex(0)], vec![ValidatorIndex(1), ValidatorIndex(2)]],
validator_groups: vec![
vec![ValidatorIndex(0)],
vec![ValidatorIndex(1), ValidatorIndex(2)],
],
n_cores: 2,
zeroth_delay_tranche_width: 10,
relay_vrf_modulo_samples: 3,
@@ -615,9 +618,7 @@ mod tests {
#[test]
fn assign_to_nonzero_core() {
let keystore = futures::executor::block_on(
make_keystore(&[Sr25519Keyring::Alice])
);
let keystore = futures::executor::block_on(make_keystore(&[Sr25519Keyring::Alice]));
let c_a = CandidateHash(Hash::repeat_byte(0));
let c_b = CandidateHash(Hash::repeat_byte(1));
@@ -632,7 +633,10 @@ mod tests {
Sr25519Keyring::Bob,
Sr25519Keyring::Charlie,
]),
validator_groups: vec![vec![ValidatorIndex(0)], vec![ValidatorIndex(1), ValidatorIndex(2)]],
validator_groups: vec![
vec![ValidatorIndex(0)],
vec![ValidatorIndex(1), ValidatorIndex(2)],
],
n_cores: 2,
zeroth_delay_tranche_width: 10,
relay_vrf_modulo_samples: 3,
@@ -647,9 +651,7 @@ mod tests {
#[test]
fn succeeds_empty_for_0_cores() {
let keystore = futures::executor::block_on(
make_keystore(&[Sr25519Keyring::Alice])
);
let keystore = futures::executor::block_on(make_keystore(&[Sr25519Keyring::Alice]));
let relay_vrf_story = RelayVRFStory([42u8; 32]);
let assignments = compute_assignments(
@@ -689,14 +691,15 @@ mod tests {
rotation_offset: usize,
f: impl Fn(&mut MutatedAssignment) -> Option<bool>, // None = skip
) {
let keystore = futures::executor::block_on(
make_keystore(&[Sr25519Keyring::Alice])
);
let keystore = futures::executor::block_on(make_keystore(&[Sr25519Keyring::Alice]));
let group_for_core = |i| GroupIndex(((i + rotation_offset) % n_cores) as _);
let config = Config {
assignment_keys: assignment_keys_plus_random(&[Sr25519Keyring::Alice], n_validators - 1),
assignment_keys: assignment_keys_plus_random(
&[Sr25519Keyring::Alice],
n_validators - 1,
),
validator_groups: basic_groups(n_validators, n_cores),
n_cores: n_cores as u32,
zeroth_delay_tranche_width: 10,
@@ -710,11 +713,13 @@ mod tests {
relay_vrf_story.clone(),
&config,
(0..n_cores)
.map(|i| (
CandidateHash(Hash::repeat_byte(i as u8)),
CoreIndex(i as u32),
group_for_core(i),
))
.map(|i| {
(
CandidateHash(Hash::repeat_byte(i as u8)),
CoreIndex(i as u32),
group_for_core(i),
)
})
.collect::<Vec<_>>(),
);
@@ -743,7 +748,8 @@ mod tests {
relay_vrf_story.clone(),
&mutated.cert,
mutated.group,
).is_ok();
)
.is_ok();
assert_eq!(expected, is_good)
}
@@ -787,7 +793,7 @@ mod tests {
AssignmentCertKind::RelayVRFDelay { .. } => {
m.cert.vrf = garbage_vrf();
Some(false)
}
},
_ => None, // skip everything else.
}
});
@@ -800,7 +806,7 @@ mod tests {
AssignmentCertKind::RelayVRFModulo { .. } => {
m.cert.vrf = garbage_vrf();
Some(false)
}
},
_ => None, // skip everything else.
}
});
@@ -813,7 +819,7 @@ mod tests {
AssignmentCertKind::RelayVRFModulo { sample } => {
m.config.relay_vrf_modulo_samples = sample;
Some(false)
}
},
_ => None, // skip everything else.
}
});
@@ -826,7 +832,7 @@ mod tests {
AssignmentCertKind::RelayVRFDelay { .. } => {
m.core = CoreIndex((m.core.0 + 1) % 100);
Some(false)
}
},
_ => None, // skip everything else.
}
});
@@ -839,7 +845,7 @@ mod tests {
AssignmentCertKind::RelayVRFModulo { .. } => {
m.core = CoreIndex((m.core.0 + 1) % 100);
Some(false)
}
},
_ => None, // skip everything else.
}
});
+172 -196
View File
@@ -28,43 +28,42 @@
//!
//! We maintain a rolling window of session indices. This starts as empty
use polkadot_node_subsystem::{
overseer,
messages::{
RuntimeApiMessage, RuntimeApiRequest, ChainApiMessage, ApprovalDistributionMessage,
ChainSelectionMessage,
},
SubsystemContext, SubsystemError, SubsystemResult,
};
use polkadot_node_subsystem_util::determine_new_blocks;
use polkadot_node_subsystem_util::rolling_session_window::{
RollingSessionWindow, SessionWindowUpdate,
};
use polkadot_primitives::v1::{
Hash, SessionIndex, CandidateEvent, Header, CandidateHash,
CandidateReceipt, CoreIndex, GroupIndex, BlockNumber, ConsensusLog,
};
use polkadot_node_jaeger as jaeger;
use polkadot_node_primitives::approval::{
self as approval_types, BlockApprovalMeta, RelayVRFStory,
};
use polkadot_node_jaeger as jaeger;
use polkadot_node_subsystem::{
messages::{
ApprovalDistributionMessage, ChainApiMessage, ChainSelectionMessage, RuntimeApiMessage,
RuntimeApiRequest,
},
overseer, SubsystemContext, SubsystemError, SubsystemResult,
};
use polkadot_node_subsystem_util::{
determine_new_blocks,
rolling_session_window::{RollingSessionWindow, SessionWindowUpdate},
};
use polkadot_primitives::v1::{
BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, ConsensusLog, CoreIndex,
GroupIndex, Hash, Header, SessionIndex,
};
use sc_keystore::LocalKeystore;
use sp_consensus_slots::Slot;
use futures::prelude::*;
use futures::channel::oneshot;
use bitvec::order::Lsb0 as BitOrderLsb0;
use futures::{channel::oneshot, prelude::*};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::{collections::HashMap, convert::TryFrom};
use super::approval_db::v1;
use crate::backend::{Backend, OverlayedBackend};
use crate::persisted_entries::CandidateEntry;
use crate::criteria::{AssignmentCriteria, OurAssignment};
use crate::time::{slot_number_to_tick, Tick};
use crate::{
backend::{Backend, OverlayedBackend},
criteria::{AssignmentCriteria, OurAssignment},
persisted_entries::CandidateEntry,
time::{slot_number_to_tick, Tick},
};
use super::{LOG_TARGET, State};
use super::{State, LOG_TARGET};
struct ImportedBlockInfo {
included_candidates: Vec<(CandidateHash, CandidateReceipt, CoreIndex, GroupIndex)>,
@@ -99,7 +98,8 @@ async fn imported_block_info(
ctx.send_message(RuntimeApiMessage::Request(
block_hash,
RuntimeApiRequest::CandidateEvents(c_tx),
)).await;
))
.await;
let events: Vec<CandidateEvent> = match c_rx.await {
Ok(Ok(events)) => events,
@@ -107,11 +107,14 @@ async fn imported_block_info(
Err(_) => return Ok(None),
};
events.into_iter().filter_map(|e| match e {
CandidateEvent::CandidateIncluded(receipt, _, core, group)
=> Some((receipt.hash(), receipt, core, group)),
_ => None,
}).collect()
events
.into_iter()
.filter_map(|e| match e {
CandidateEvent::CandidateIncluded(receipt, _, core, group) =>
Some((receipt.hash(), receipt, core, group)),
_ => None,
})
.collect()
};
// fetch session. ignore blocks that are too old, but unless sessions are really
@@ -121,7 +124,8 @@ async fn imported_block_info(
ctx.send_message(RuntimeApiMessage::Request(
block_header.parent_hash,
RuntimeApiRequest::SessionIndexForChild(s_tx),
)).await;
))
.await;
let session_index = match s_rx.await {
Ok(Ok(s)) => s,
@@ -130,10 +134,14 @@ async fn imported_block_info(
};
if env.session_window.earliest_session().map_or(true, |e| session_index < e) {
tracing::debug!(target: LOG_TARGET, "Block {} is from ancient session {}. Skipping",
block_hash, session_index);
tracing::debug!(
target: LOG_TARGET,
"Block {} is from ancient session {}. Skipping",
block_hash,
session_index
);
return Ok(None);
return Ok(None)
}
session_index
@@ -162,7 +170,8 @@ async fn imported_block_info(
ctx.send_message(RuntimeApiMessage::Request(
block_hash,
RuntimeApiRequest::CurrentBabeEpoch(s_tx),
)).await;
))
.await;
match s_rx.await {
Ok(Ok(s)) => s,
@@ -180,8 +189,8 @@ async fn imported_block_info(
block_hash,
);
return Ok(None);
}
return Ok(None)
},
};
let (assignments, slot, relay_vrf_story) = {
@@ -201,7 +210,8 @@ async fn imported_block_info(
&env.keystore,
relay_vrf.clone(),
&crate::criteria::Config::from(session_info),
included_candidates.iter()
included_candidates
.iter()
.map(|(c_hash, _, core, group)| (*c_hash, *core, *group))
.collect(),
);
@@ -210,7 +220,7 @@ async fn imported_block_info(
},
Err(_) => return Ok(None),
}
}
},
None => {
tracing::debug!(
target: LOG_TARGET,
@@ -218,16 +228,12 @@ async fn imported_block_info(
block_hash,
);
return Ok(None);
}
return Ok(None)
},
}
};
tracing::trace!(
target: LOG_TARGET,
n_assignments = assignments.len(),
"Produced assignments"
);
tracing::trace!(target: LOG_TARGET, n_assignments = assignments.len(), "Produced assignments");
let force_approve =
block_header.digest.convert_first(|l| match ConsensusLog::from_digest_item(l) {
@@ -241,7 +247,7 @@ async fn imported_block_info(
);
Some(num)
}
},
Ok(Some(_)) => None,
Ok(None) => None,
Err(err) => {
@@ -253,7 +259,7 @@ async fn imported_block_info(
);
None
}
},
});
Ok(Some(ImportedBlockInfo {
@@ -291,8 +297,7 @@ pub(crate) async fn handle_new_head(
db: &mut OverlayedBackend<'_, impl Backend>,
head: Hash,
finalized_number: &Option<BlockNumber>,
) -> SubsystemResult<Vec<BlockImportedCandidates>>
{
) -> SubsystemResult<Vec<BlockImportedCandidates>> {
// Update session info based on most recent head.
let mut span = jaeger::Span::new(head, "approval-checking-import");
@@ -309,13 +314,13 @@ pub(crate) async fn handle_new_head(
e,
);
return Ok(Vec::new());
}
return Ok(Vec::new())
},
Ok(None) => {
tracing::warn!(target: LOG_TARGET, "Missing header for new head {}", head);
return Ok(Vec::new());
}
Ok(Some(h)) => h
return Ok(Vec::new())
},
Ok(Some(h)) => h,
}
};
@@ -329,15 +334,15 @@ pub(crate) async fn handle_new_head(
);
return Ok(Vec::new())
}
},
Ok(a @ SessionWindowUpdate::Advanced { .. }) => {
tracing::info!(
target: LOG_TARGET,
update = ?a,
"Advanced session window for approvals",
);
}
Ok(_) => {}
},
Ok(_) => {},
}
// If we've just started the node and haven't yet received any finality notifications,
@@ -351,12 +356,14 @@ pub(crate) async fn handle_new_head(
&header,
lower_bound_number,
)
.map_err(|e| SubsystemError::with_origin("approval-voting", e))
.await?;
.map_err(|e| SubsystemError::with_origin("approval-voting", e))
.await?;
span.add_uint_tag("new-blocks", new_blocks.len() as u64);
if new_blocks.is_empty() { return Ok(Vec::new()) }
if new_blocks.is_empty() {
return Ok(Vec::new())
}
let mut approval_meta: Vec<BlockApprovalMeta> = Vec::with_capacity(new_blocks.len());
let mut imported_candidates = Vec::with_capacity(new_blocks.len());
@@ -376,9 +383,11 @@ pub(crate) async fn handle_new_head(
None => {
// It's possible that we've lost a race with finality.
let (tx, rx) = oneshot::channel();
ctx.send_message(
ChainApiMessage::FinalizedBlockHash(block_header.number.clone(), tx)
).await;
ctx.send_message(ChainApiMessage::FinalizedBlockHash(
block_header.number.clone(),
tx,
))
.await;
let lost_to_finality = match rx.await {
Ok(Ok(Some(h))) if h != block_hash => true,
@@ -395,7 +404,7 @@ pub(crate) async fn handle_new_head(
);
}
return Ok(Vec::new());
return Ok(Vec::new())
},
};
}
@@ -420,7 +429,9 @@ pub(crate) async fn handle_new_head(
force_approve,
} = imported_block_info;
let session_info = state.session_window.session_info(session_index)
let session_info = state
.session_window
.session_info(session_index)
.expect("imported_block_info requires session to be available; qed");
let (block_tick, no_show_duration) = {
@@ -432,7 +443,8 @@ pub(crate) async fn handle_new_head(
(block_tick, no_show_duration)
};
let needed_approvals = session_info.needed_approvals;
let validator_group_lens: Vec<usize> = session_info.validator_groups.iter().map(|v| v.len()).collect();
let validator_group_lens: Vec<usize> =
session_info.validator_groups.iter().map(|v| v.len()).collect();
// insta-approve candidates on low-node testnets:
// cf. https://github.com/paritytech/polkadot/issues/2411
let num_candidates = included_candidates.len();
@@ -447,10 +459,10 @@ pub(crate) async fn handle_new_head(
} else {
let mut result = bitvec::bitvec![BitOrderLsb0, u8; 0; num_candidates];
for (i, &(_, _, _, backing_group)) in included_candidates.iter().enumerate() {
let backing_group_size = validator_group_lens.get(backing_group.0 as usize)
.copied()
.unwrap_or(0);
let needed_approvals = usize::try_from(needed_approvals).expect("usize is at least u32; qed");
let backing_group_size =
validator_group_lens.get(backing_group.0 as usize).copied().unwrap_or(0);
let needed_approvals =
usize::try_from(needed_approvals).expect("usize is at least u32; qed");
if n_validators.saturating_sub(backing_group_size) < needed_approvals {
result.set(i, true);
}
@@ -481,19 +493,16 @@ pub(crate) async fn handle_new_head(
session: session_index,
slot,
relay_vrf_story: relay_vrf_story.0,
candidates: included_candidates.iter()
.map(|(hash, _, core, _)| (*core, *hash)).collect(),
candidates: included_candidates
.iter()
.map(|(hash, _, core, _)| (*core, *hash))
.collect(),
approved_bitfield,
children: Vec::new(),
};
if let Some(up_to) = force_approve {
tracing::debug!(
target: LOG_TARGET,
?block_hash,
up_to,
"Enacting force-approve",
);
tracing::debug!(target: LOG_TARGET, ?block_hash, up_to, "Enacting force-approve",);
let approved_hashes = crate::ops::force_approve(db, block_hash, up_to)
.map_err(|e| SubsystemError::with_origin("approval-voting", e))?;
@@ -511,19 +520,19 @@ pub(crate) async fn handle_new_head(
"Writing BlockEntry",
);
let candidate_entries = crate::ops::add_block_entry(
db,
block_entry.into(),
n_validators,
|candidate_hash| {
included_candidates.iter().find(|(hash, _, _, _)| candidate_hash == hash)
.map(|(_, receipt, core, backing_group)| super::ops::NewCandidateInfo::new(
receipt.clone(),
*backing_group,
assignments.get(core).map(|a| a.clone().into()),
))
}
).map_err(|e| SubsystemError::with_origin("approval-voting", e))?;
let candidate_entries =
crate::ops::add_block_entry(db, block_entry.into(), n_validators, |candidate_hash| {
included_candidates.iter().find(|(hash, _, _, _)| candidate_hash == hash).map(
|(_, receipt, core, backing_group)| {
super::ops::NewCandidateInfo::new(
receipt.clone(),
*backing_group,
assignments.get(core).map(|a| a.clone().into()),
)
},
)
})
.map_err(|e| SubsystemError::with_origin("approval-voting", e))?;
approval_meta.push(BlockApprovalMeta {
hash: block_hash,
number: block_header.number,
@@ -532,18 +541,16 @@ pub(crate) async fn handle_new_head(
slot,
});
imported_candidates.push(
BlockImportedCandidates {
block_hash,
block_number: block_header.number,
block_tick,
no_show_duration,
imported_candidates: candidate_entries
.into_iter()
.map(|(h, e)| (h, e.into()))
.collect(),
}
);
imported_candidates.push(BlockImportedCandidates {
block_hash,
block_number: block_header.number,
block_tick,
no_show_duration,
imported_candidates: candidate_entries
.into_iter()
.map(|(h, e)| (h, e.into()))
.collect(),
});
}
tracing::trace!(
@@ -562,33 +569,30 @@ pub(crate) async fn handle_new_head(
pub(crate) mod tests {
use super::*;
use crate::approval_db::v1::DbBackend;
use polkadot_node_subsystem_test_helpers::make_subsystem_context;
use polkadot_node_primitives::approval::{VRFOutput, VRFProof};
use polkadot_primitives::v1::{SessionInfo, ValidatorIndex};
use polkadot_node_subsystem::messages::AllMessages;
use sp_core::testing::TaskExecutor;
pub(crate) use sp_runtime::{Digest, DigestItem};
pub(crate) use sp_consensus_babe::{
Epoch as BabeEpoch, BabeEpochConfiguration, AllowedSlots,
};
pub(crate) use sp_consensus_babe::digests::{CompatibleDigestItem, PreDigest, SecondaryVRFPreDigest};
use sp_keyring::sr25519::Keyring as Sr25519Keyring;
use assert_matches::assert_matches;
use merlin::Transcript;
use std::{pin::Pin, sync::Arc};
use kvdb::KeyValueDB;
use merlin::Transcript;
use polkadot_node_primitives::approval::{VRFOutput, VRFProof};
use polkadot_node_subsystem::messages::AllMessages;
use polkadot_node_subsystem_test_helpers::make_subsystem_context;
use polkadot_primitives::v1::{SessionInfo, ValidatorIndex};
pub(crate) use sp_consensus_babe::{
digests::{CompatibleDigestItem, PreDigest, SecondaryVRFPreDigest},
AllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch,
};
use sp_core::testing::TaskExecutor;
use sp_keyring::sr25519::Keyring as Sr25519Keyring;
pub(crate) use sp_runtime::{Digest, DigestItem};
use std::{pin::Pin, sync::Arc};
use crate::{
APPROVAL_SESSIONS, criteria, BlockEntry,
approval_db::v1::Config as DatabaseConfig,
approval_db::v1::Config as DatabaseConfig, criteria, BlockEntry, APPROVAL_SESSIONS,
};
const DATA_COL: u32 = 0;
const NUM_COLUMNS: u32 = 1;
const TEST_CONFIG: DatabaseConfig = DatabaseConfig {
col_data: DATA_COL,
};
const TEST_CONFIG: DatabaseConfig = DatabaseConfig { col_data: DATA_COL };
#[derive(Default)]
struct MockClock;
@@ -598,9 +602,7 @@ pub(crate) mod tests {
}
fn wait(&self, _tick: Tick) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> {
Box::pin(async move {
()
})
Box::pin(async move { () })
}
}
@@ -633,7 +635,11 @@ pub(crate) mod tests {
_keystore: &LocalKeystore,
_relay_vrf_story: polkadot_node_primitives::approval::RelayVRFStory,
_config: &criteria::Config,
_leaving_cores: Vec<(CandidateHash, polkadot_primitives::v1::CoreIndex, polkadot_primitives::v1::GroupIndex)>,
_leaving_cores: Vec<(
CandidateHash,
polkadot_primitives::v1::CoreIndex,
polkadot_primitives::v1::GroupIndex,
)>,
) -> HashMap<polkadot_primitives::v1::CoreIndex, criteria::OurAssignment> {
HashMap::new()
}
@@ -675,7 +681,6 @@ pub(crate) mod tests {
}
}
#[test]
fn imported_block_info_is_good() {
let pool = TaskExecutor::new();
@@ -691,12 +696,7 @@ pub(crate) mod tests {
let mut d = Digest::default();
let (vrf_output, vrf_proof) = garbage_vrf();
d.push(DigestItem::babe_pre_digest(PreDigest::SecondaryVRF(
SecondaryVRFPreDigest {
authority_index: 0,
slot,
vrf_output,
vrf_proof,
}
SecondaryVRFPreDigest { authority_index: 0, slot, vrf_output, vrf_proof },
)));
d
@@ -719,13 +719,15 @@ pub(crate) mod tests {
(make_candidate(2.into()), CoreIndex(1), GroupIndex(3)),
];
let inclusion_events = candidates.iter().cloned()
let inclusion_events = candidates
.iter()
.cloned()
.map(|(r, c, g)| CandidateEvent::CandidateIncluded(r, Vec::new().into(), c, g))
.collect::<Vec<_>>();
let test_fut = {
let included_candidates = candidates.iter()
let included_candidates = candidates
.iter()
.map(|(r, c, g)| (r.hash(), r.clone(), *c, *g))
.collect::<Vec<_>>();
@@ -743,12 +745,8 @@ pub(crate) mod tests {
keystore: &LocalKeystore::in_memory(),
};
let info = imported_block_info(
&mut ctx,
env,
hash,
&header,
).await.unwrap().unwrap();
let info =
imported_block_info(&mut ctx, env, hash, &header).await.unwrap().unwrap();
assert_eq!(info.included_candidates, included_candidates);
assert_eq!(info.session_index, session);
@@ -835,7 +833,9 @@ pub(crate) mod tests {
(make_candidate(2.into()), CoreIndex(1), GroupIndex(3)),
];
let inclusion_events = candidates.iter().cloned()
let inclusion_events = candidates
.iter()
.cloned()
.map(|(r, c, g)| CandidateEvent::CandidateIncluded(r, Vec::new().into(), c, g))
.collect::<Vec<_>>();
@@ -854,12 +854,7 @@ pub(crate) mod tests {
keystore: &LocalKeystore::in_memory(),
};
let info = imported_block_info(
&mut ctx,
env,
hash,
&header,
).await.unwrap();
let info = imported_block_info(&mut ctx, env, hash, &header).await.unwrap();
assert!(info.is_none());
})
@@ -940,7 +935,9 @@ pub(crate) mod tests {
(make_candidate(2.into()), CoreIndex(1), GroupIndex(3)),
];
let inclusion_events = candidates.iter().cloned()
let inclusion_events = candidates
.iter()
.cloned()
.map(|(r, c, g)| CandidateEvent::CandidateIncluded(r, Vec::new().into(), c, g))
.collect::<Vec<_>>();
@@ -955,12 +952,7 @@ pub(crate) mod tests {
keystore: &LocalKeystore::in_memory(),
};
let info = imported_block_info(
&mut ctx,
env,
hash,
&header,
).await.unwrap();
let info = imported_block_info(&mut ctx, env, hash, &header).await.unwrap();
assert!(info.is_none());
})
@@ -1008,12 +1000,7 @@ pub(crate) mod tests {
let mut d = Digest::default();
let (vrf_output, vrf_proof) = garbage_vrf();
d.push(DigestItem::babe_pre_digest(PreDigest::SecondaryVRF(
SecondaryVRFPreDigest {
authority_index: 0,
slot,
vrf_output,
vrf_proof,
}
SecondaryVRFPreDigest { authority_index: 0, slot, vrf_output, vrf_proof },
)));
d.push(ConsensusLog::ForceApprove(3).into());
@@ -1038,13 +1025,15 @@ pub(crate) mod tests {
(make_candidate(2.into()), CoreIndex(1), GroupIndex(3)),
];
let inclusion_events = candidates.iter().cloned()
let inclusion_events = candidates
.iter()
.cloned()
.map(|(r, c, g)| CandidateEvent::CandidateIncluded(r, Vec::new().into(), c, g))
.collect::<Vec<_>>();
let test_fut = {
let included_candidates = candidates.iter()
let included_candidates = candidates
.iter()
.map(|(r, c, g)| (r.hash(), r.clone(), *c, *g))
.collect::<Vec<_>>();
@@ -1062,12 +1051,8 @@ pub(crate) mod tests {
keystore: &LocalKeystore::in_memory(),
};
let info = imported_block_info(
&mut ctx,
env,
hash,
&header,
).await.unwrap().unwrap();
let info =
imported_block_info(&mut ctx, env, hash, &header).await.unwrap().unwrap();
assert_eq!(info.included_candidates, included_candidates);
assert_eq!(info.session_index, session);
@@ -1159,12 +1144,7 @@ pub(crate) mod tests {
let mut d = Digest::default();
let (vrf_output, vrf_proof) = garbage_vrf();
d.push(DigestItem::babe_pre_digest(PreDigest::SecondaryVRF(
SecondaryVRFPreDigest {
authority_index: 0,
slot,
vrf_output,
vrf_proof,
}
SecondaryVRFPreDigest { authority_index: 0, slot, vrf_output, vrf_proof },
)));
d
@@ -1186,7 +1166,9 @@ pub(crate) mod tests {
(make_candidate(1.into()), CoreIndex(0), GroupIndex(0)),
(make_candidate(2.into()), CoreIndex(1), GroupIndex(1)),
];
let inclusion_events = candidates.iter().cloned()
let inclusion_events = candidates
.iter()
.cloned()
.map(|(r, c, g)| CandidateEvent::CandidateIncluded(r, Vec::new().into(), c, g))
.collect::<Vec<_>>();
@@ -1202,7 +1184,8 @@ pub(crate) mod tests {
candidates: Vec::new(),
approved_bitfield: Default::default(),
children: Vec::new(),
}.into()
}
.into(),
);
let write_ops = overlay_db.into_write_ops();
@@ -1211,13 +1194,9 @@ pub(crate) mod tests {
let test_fut = {
Box::pin(async move {
let mut overlay_db = OverlayedBackend::new(&db);
let result = handle_new_head(
&mut ctx,
&mut state,
&mut overlay_db,
hash,
&Some(1),
).await.unwrap();
let result = handle_new_head(&mut ctx, &mut state, &mut overlay_db, hash, &Some(1))
.await
.unwrap();
let write_ops = overlay_db.into_write_ops();
db.write(write_ops).unwrap();
@@ -1229,14 +1208,11 @@ pub(crate) mod tests {
assert_eq!(candidates[1].1.approvals().len(), 6);
// the first candidate should be insta-approved
// the second should not
let entry: BlockEntry = v1::load_block_entry(
db_writer.as_ref(),
&TEST_CONFIG,
&hash,
)
.unwrap()
.unwrap()
.into();
let entry: BlockEntry =
v1::load_block_entry(db_writer.as_ref(), &TEST_CONFIG, &hash)
.unwrap()
.unwrap()
.into();
assert!(entry.is_candidate_approved(&candidates[0].0));
assert!(!entry.is_candidate_approved(&candidates[1].0));
})
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+33 -51
View File
@@ -19,21 +19,18 @@
use polkadot_node_subsystem::SubsystemResult;
use polkadot_primitives::v1::{
CandidateHash, CandidateReceipt, BlockNumber, GroupIndex, Hash,
use bitvec::order::Lsb0 as BitOrderLsb0;
use polkadot_primitives::v1::{BlockNumber, CandidateHash, CandidateReceipt, GroupIndex, Hash};
use std::{
collections::{hash_map::Entry, BTreeMap, HashMap},
convert::Into,
};
use bitvec::{order::Lsb0 as BitOrderLsb0};
use std::convert::Into;
use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map::Entry;
use super::persisted_entries::{ApprovalEntry, CandidateEntry, BlockEntry};
use super::backend::{Backend, OverlayedBackend};
use super::approval_db::{
v1::{
OurAssignment, StoredBlockRange,
},
use super::{
approval_db::v1::{OurAssignment, StoredBlockRange},
backend::{Backend, OverlayedBackend},
persisted_entries::{ApprovalEntry, BlockEntry, CandidateEntry},
};
/// Information about a new candidate necessary to instantiate the requisite
@@ -75,7 +72,7 @@ fn visit_and_remove_block_entry(
None => continue, // Should not happen except for corrupt DB
Some(c) => c,
})
}
},
};
candidate.block_assignments.remove(&block_hash);
@@ -111,11 +108,7 @@ pub fn canonicalize(
overlay_db.delete_blocks_at_height(i);
for b in at_height {
let _ = visit_and_remove_block_entry(
b,
overlay_db,
&mut visited_candidates,
)?;
let _ = visit_and_remove_block_entry(b, overlay_db, &mut visited_candidates)?;
}
}
@@ -129,11 +122,7 @@ pub fn canonicalize(
let mut pruned_branches = Vec::new();
for b in at_height {
let children = visit_and_remove_block_entry(
b,
overlay_db,
&mut visited_candidates,
)?;
let children = visit_and_remove_block_entry(b, overlay_db, &mut visited_candidates)?;
if b != canon_hash {
pruned_branches.extend(children);
@@ -145,13 +134,11 @@ pub fn canonicalize(
// Follow all children of non-canonicalized blocks.
{
let mut frontier: Vec<(BlockNumber, Hash)> = pruned_branches.into_iter().map(|h| (canon_number + 1, h)).collect();
let mut frontier: Vec<(BlockNumber, Hash)> =
pruned_branches.into_iter().map(|h| (canon_number + 1, h)).collect();
while let Some((height, next_child)) = frontier.pop() {
let children = visit_and_remove_block_entry(
next_child,
overlay_db,
&mut visited_candidates,
)?;
let children =
visit_and_remove_block_entry(next_child, overlay_db, &mut visited_candidates)?;
// extend the frontier of branches to include the given height.
frontier.extend(children.into_iter().map(|h| (height + 1, h)));
@@ -188,10 +175,7 @@ pub fn canonicalize(
// due to the fork pruning, this range actually might go too far above where our actual highest block is,
// if a relatively short fork is canonicalized.
// TODO https://github.com/paritytech/polkadot/issues/3389
let new_range = StoredBlockRange(
canon_number + 1,
std::cmp::max(range.1, canon_number + 2),
);
let new_range = StoredBlockRange(canon_number + 1, std::cmp::max(range.1, canon_number + 2));
overlay_db.write_stored_block_range(new_range);
@@ -246,21 +230,20 @@ pub fn add_block_entry(
// read and write all updated entries.
{
for &(_, ref candidate_hash) in entry.candidates() {
let NewCandidateInfo {
candidate,
backing_group,
our_assignment,
} = match candidate_info(candidate_hash) {
None => return Ok(Vec::new()),
Some(info) => info,
};
let NewCandidateInfo { candidate, backing_group, our_assignment } =
match candidate_info(candidate_hash) {
None => return Ok(Vec::new()),
Some(info) => info,
};
let mut candidate_entry = store.load_candidate_entry(&candidate_hash)?
.unwrap_or_else(move || CandidateEntry {
candidate,
session,
block_assignments: BTreeMap::new(),
approvals: bitvec::bitvec![BitOrderLsb0, u8; 0; n_validators],
let mut candidate_entry =
store.load_candidate_entry(&candidate_hash)?.unwrap_or_else(move || {
CandidateEntry {
candidate,
session,
block_assignments: BTreeMap::new(),
approvals: bitvec::bitvec![BitOrderLsb0, u8; 0; n_validators],
}
});
candidate_entry.block_assignments.insert(
@@ -272,7 +255,7 @@ pub fn add_block_entry(
None,
bitvec::bitvec![BitOrderLsb0, u8; 0; n_validators],
false,
)
),
);
store.write_candidate_entry(candidate_entry.clone());
@@ -313,7 +296,6 @@ pub fn force_approve(
// iterate back to the `up_to` block, and then iterate backwards until all blocks
// are updated.
while let Some(mut entry) = store.load_block_entry(&cur_hash)? {
if entry.block_number() <= up_to {
state = State::Approving;
}
@@ -326,7 +308,7 @@ pub fn force_approve(
entry.approved_bitfield.iter_mut().for_each(|mut b| *b = true);
approved_hashes.push(entry.block_hash());
store.write_block_entry(entry);
}
},
}
}
@@ -20,18 +20,17 @@
//! Within that context, things are plain-old-data. Within this module,
//! data and logic are intertwined.
use polkadot_node_primitives::approval::{DelayTranche, RelayVRFStory, AssignmentCert};
use polkadot_node_primitives::approval::{AssignmentCert, DelayTranche, RelayVRFStory};
use polkadot_primitives::v1::{
ValidatorIndex, CandidateReceipt, SessionIndex, GroupIndex, CoreIndex,
Hash, CandidateHash, BlockNumber, ValidatorSignature,
BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, SessionIndex,
ValidatorIndex, ValidatorSignature,
};
use sp_consensus_slots::Slot;
use bitvec::{order::Lsb0 as BitOrderLsb0, slice::BitSlice, vec::BitVec};
use std::collections::BTreeMap;
use bitvec::{slice::BitSlice, vec::BitVec, order::Lsb0 as BitOrderLsb0};
use super::time::Tick;
use super::criteria::OurAssignment;
use super::{criteria::OurAssignment, time::Tick};
/// Metadata regarding a specific tranche of assignments for a specific candidate.
#[derive(Debug, Clone, PartialEq)]
@@ -105,11 +104,14 @@ impl ApprovalEntry {
}
// Note that our assignment is triggered. No-op if already triggered.
pub fn trigger_our_assignment(&mut self, tick_now: Tick)
-> Option<(AssignmentCert, ValidatorIndex, DelayTranche)>
{
pub fn trigger_our_assignment(
&mut self,
tick_now: Tick,
) -> Option<(AssignmentCert, ValidatorIndex, DelayTranche)> {
let our = self.our_assignment.as_mut().and_then(|a| {
if a.triggered() { return None }
if a.triggered() {
return None
}
a.mark_triggered();
Some(a.clone())
@@ -143,22 +145,16 @@ impl ApprovalEntry {
let idx = match self.tranches.iter().position(|t| t.tranche >= tranche) {
Some(pos) => {
if self.tranches[pos].tranche > tranche {
self.tranches.insert(pos, TrancheEntry {
tranche: tranche,
assignments: Vec::new(),
});
self.tranches.insert(pos, TrancheEntry { tranche, assignments: Vec::new() });
}
pos
}
},
None => {
self.tranches.push(TrancheEntry {
tranche: tranche,
assignments: Vec::new(),
});
self.tranches.push(TrancheEntry { tranche, assignments: Vec::new() });
self.tranches.len() - 1
}
},
};
self.tranches[idx].assignments.push((validator_index, tick_now));
@@ -168,15 +164,16 @@ impl ApprovalEntry {
// Produce a bitvec indicating the assignments of all validators up to and
// including `tranche`.
pub fn assignments_up_to(&self, tranche: DelayTranche) -> BitVec<BitOrderLsb0, u8> {
self.tranches.iter()
.take_while(|e| e.tranche <= tranche)
.fold(bitvec::bitvec![BitOrderLsb0, u8; 0; self.assignments.len()], |mut a, e| {
self.tranches.iter().take_while(|e| e.tranche <= tranche).fold(
bitvec::bitvec![BitOrderLsb0, u8; 0; self.assignments.len()],
|mut a, e| {
for &(v, _) in &e.assignments {
a.set(v.0 as _, true);
}
a
})
},
)
}
/// Whether the approval entry is approved
@@ -299,11 +296,7 @@ impl CandidateEntry {
}
#[cfg(test)]
pub fn add_approval_entry(
&mut self,
block_hash: Hash,
approval_entry: ApprovalEntry,
) {
pub fn add_approval_entry(&mut self, block_hash: Hash, approval_entry: ApprovalEntry) {
self.block_assignments.insert(block_hash, approval_entry);
}
}
@@ -313,7 +306,11 @@ impl From<crate::approval_db::v1::CandidateEntry> for CandidateEntry {
CandidateEntry {
candidate: entry.candidate,
session: entry.session,
block_assignments: entry.block_assignments.into_iter().map(|(h, ae)| (h, ae.into())).collect(),
block_assignments: entry
.block_assignments
.into_iter()
.map(|(h, ae)| (h, ae.into()))
.collect(),
approvals: entry.approvals,
}
}
@@ -324,7 +321,11 @@ impl From<CandidateEntry> for crate::approval_db::v1::CandidateEntry {
Self {
candidate: entry.candidate,
session: entry.session,
block_assignments: entry.block_assignments.into_iter().map(|(h, ae)| (h, ae.into())).collect(),
block_assignments: entry
.block_assignments
.into_iter()
.map(|(h, ae)| (h, ae.into()))
.collect(),
approvals: entry.approvals,
}
}
@@ -360,7 +361,9 @@ impl BlockEntry {
/// Whether a candidate is approved in the bitfield.
pub fn is_candidate_approved(&self, candidate_hash: &CandidateHash) -> bool {
self.candidates.iter().position(|(_, h)| h == candidate_hash)
self.candidates
.iter()
.position(|(_, h)| h == candidate_hash)
.and_then(|p| self.approved_bitfield.get(p).map(|b| *b))
.unwrap_or(false)
}
@@ -372,10 +375,12 @@ impl BlockEntry {
/// Iterate over all unapproved candidates.
pub fn unapproved_candidates(&self) -> impl Iterator<Item = CandidateHash> + '_ {
self.approved_bitfield.iter().enumerate().filter_map(move |(i, a)| if !*a {
Some(self.candidates[i].1)
} else {
None
self.approved_bitfield.iter().enumerate().filter_map(move |(i, a)| {
if !*a {
Some(self.candidates[i].1)
} else {
None
}
})
}
@@ -385,9 +390,7 @@ impl BlockEntry {
/// Panics if the core is already used.
#[cfg(test)]
pub fn add_candidate(&mut self, core: CoreIndex, candidate_hash: CandidateHash) -> usize {
let pos = self.candidates
.binary_search_by_key(&core, |(c, _)| *c)
.unwrap_err();
let pos = self.candidates.binary_search_by_key(&core, |(c, _)| *c).unwrap_err();
self.candidates.insert(pos, (core, candidate_hash));
+191 -273
View File
@@ -16,34 +16,39 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*;
use std::time::Duration;
use polkadot_overseer::HeadSupportsParachains;
use polkadot_primitives::v1::{
CoreIndex, GroupIndex, ValidatorSignature, Header, CandidateEvent,
};
use polkadot_node_subsystem::{ActivatedLeaf, ActiveLeavesUpdate, LeafStatus};
use polkadot_node_primitives::approval::{
AssignmentCert, AssignmentCertKind, VRFOutput, VRFProof,
RELAY_VRF_MODULO_CONTEXT, DelayTranche,
AssignmentCert, AssignmentCertKind, DelayTranche, VRFOutput, VRFProof, RELAY_VRF_MODULO_CONTEXT,
};
use polkadot_node_subsystem::{
messages::{AllMessages, ApprovalVotingMessage, AssignmentCheckResult},
ActivatedLeaf, ActiveLeavesUpdate, LeafStatus,
};
use polkadot_node_subsystem_test_helpers as test_helpers;
use polkadot_node_subsystem::messages::{AllMessages, ApprovalVotingMessage, AssignmentCheckResult};
use polkadot_node_subsystem_util::TimeoutExt;
use polkadot_overseer::HeadSupportsParachains;
use polkadot_primitives::v1::{CandidateEvent, CoreIndex, GroupIndex, Header, ValidatorSignature};
use std::time::Duration;
use assert_matches::assert_matches;
use parking_lot::Mutex;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use sp_keyring::sr25519::Keyring as Sr25519Keyring;
use sp_keystore::CryptoStore;
use assert_matches::assert_matches;
use super::import::tests::{
BabeEpoch, BabeEpochConfiguration, AllowedSlots, Digest, garbage_vrf, DigestItem, PreDigest,
SecondaryVRFPreDigest, CompatibleDigestItem,
use std::{
pin::Pin,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};
use super::{
approval_db::v1::StoredBlockRange,
backend::BackendWriteOp,
import::tests::{
garbage_vrf, AllowedSlots, BabeEpoch, BabeEpochConfiguration, CompatibleDigestItem, Digest,
DigestItem, PreDigest, SecondaryVRFPreDigest,
},
};
use super::approval_db::v1::StoredBlockRange;
use super::backend::BackendWriteOp;
const SLOT_DURATION_MILLIS: u64 = 5000;
@@ -92,14 +97,8 @@ fn make_sync_oracle(val: bool) -> (TestSyncOracle, TestSyncOracleHandle) {
let flag = Arc::new(AtomicBool::new(val));
(
TestSyncOracle {
flag: flag.clone(),
done_syncing_sender: Arc::new(Mutex::new(Some(tx))),
},
TestSyncOracleHandle {
flag,
done_syncing_receiver: rx,
}
TestSyncOracle { flag: flag.clone(), done_syncing_sender: Arc::new(Mutex::new(Some(tx))) },
TestSyncOracleHandle { flag, done_syncing_receiver: rx },
)
}
@@ -114,9 +113,7 @@ pub mod test_constants {
const DATA_COL: u32 = 0;
pub(crate) const NUM_COLUMNS: u32 = 1;
pub(crate) const TEST_CONFIG: DatabaseConfig = DatabaseConfig {
col_data: DATA_COL,
};
pub(crate) const TEST_CONFIG: DatabaseConfig = DatabaseConfig { col_data: DATA_COL };
}
struct MockSupportsParachains;
@@ -175,10 +172,8 @@ impl MockClockInner {
fn wakeup_all(&mut self, up_to: Tick) {
// This finds the position of the first wakeup after
// the given tick, or the end of the map.
let drain_up_to = self.wakeups.binary_search_by_key(
&(up_to + 1),
|w| w.0,
).unwrap_or_else(|i| i);
let drain_up_to =
self.wakeups.binary_search_by_key(&(up_to + 1), |w| w.0).unwrap_or_else(|i| i);
for (_, wakeup) in self.wakeups.drain(..drain_up_to) {
let _ = wakeup.send(());
@@ -201,10 +196,7 @@ impl MockClockInner {
fn register_wakeup(&mut self, tick: Tick, pre_emptive: bool) -> oneshot::Receiver<()> {
let (tx, rx) = oneshot::channel();
let pos = self.wakeups.binary_search_by_key(
&tick,
|w| w.0,
).unwrap_or_else(|i| i);
let pos = self.wakeups.binary_search_by_key(&tick, |w| w.0).unwrap_or_else(|i| i);
self.wakeups.insert(pos, (tick, tx));
@@ -223,14 +215,18 @@ struct MockAssignmentCriteria<Compute, Check>(Compute, Check);
impl<Compute, Check> AssignmentCriteria for MockAssignmentCriteria<Compute, Check>
where
Compute: Fn() -> HashMap<polkadot_primitives::v1::CoreIndex, criteria::OurAssignment>,
Check: Fn() -> Result<DelayTranche, criteria::InvalidAssignment>
Check: Fn() -> Result<DelayTranche, criteria::InvalidAssignment>,
{
fn compute_assignments(
&self,
_keystore: &LocalKeystore,
_relay_vrf_story: polkadot_node_primitives::approval::RelayVRFStory,
_config: &criteria::Config,
_leaving_cores: Vec<(CandidateHash, polkadot_primitives::v1::CoreIndex, polkadot_primitives::v1::GroupIndex)>,
_leaving_cores: Vec<(
CandidateHash,
polkadot_primitives::v1::CoreIndex,
polkadot_primitives::v1::GroupIndex,
)>,
) -> HashMap<polkadot_primitives::v1::CoreIndex, criteria::OurAssignment> {
self.0()
}
@@ -248,10 +244,12 @@ where
}
}
impl<F> MockAssignmentCriteria<
fn() -> HashMap<polkadot_primitives::v1::CoreIndex, criteria::OurAssignment>,
F,
> {
impl<F>
MockAssignmentCriteria<
fn() -> HashMap<polkadot_primitives::v1::CoreIndex, criteria::OurAssignment>,
F,
>
{
fn check_only(f: F) -> Self {
MockAssignmentCriteria(Default::default, f)
}
@@ -266,10 +264,7 @@ struct TestStore {
}
impl Backend for TestStore {
fn load_block_entry(
&self,
block_hash: &Hash,
) -> SubsystemResult<Option<BlockEntry>> {
fn load_block_entry(&self, block_hash: &Hash) -> SubsystemResult<Option<BlockEntry>> {
Ok(self.block_entries.get(block_hash).cloned())
}
@@ -280,10 +275,7 @@ impl Backend for TestStore {
Ok(self.candidate_entries.get(candidate_hash).cloned())
}
fn load_blocks_at_height(
&self,
height: &BlockNumber,
) -> SubsystemResult<Vec<Hash>> {
fn load_blocks_at_height(&self, height: &BlockNumber) -> SubsystemResult<Vec<Hash>> {
Ok(self.blocks_at_height.get(height).cloned().unwrap_or_default())
}
@@ -300,31 +292,33 @@ impl Backend for TestStore {
}
fn write<I>(&mut self, ops: I) -> SubsystemResult<()>
where I: IntoIterator<Item = BackendWriteOp>
where
I: IntoIterator<Item = BackendWriteOp>,
{
for op in ops {
match op {
BackendWriteOp::WriteStoredBlockRange(stored_block_range) => {
self.stored_block_range = Some(stored_block_range);
}
},
BackendWriteOp::WriteBlocksAtHeight(h, blocks) => {
self.blocks_at_height.insert(h, blocks);
}
},
BackendWriteOp::DeleteBlocksAtHeight(h) => {
let _ = self.blocks_at_height.remove(&h);
}
},
BackendWriteOp::WriteBlockEntry(block_entry) => {
self.block_entries.insert(block_entry.block_hash(), block_entry);
}
},
BackendWriteOp::DeleteBlockEntry(hash) => {
let _ = self.block_entries.remove(&hash);
}
},
BackendWriteOp::WriteCandidateEntry(candidate_entry) => {
self.candidate_entries.insert(candidate_entry.candidate_receipt().hash(), candidate_entry);
}
self.candidate_entries
.insert(candidate_entry.candidate_receipt().hash(), candidate_entry);
},
BackendWriteOp::DeleteCandidateEntry(candidate_hash) => {
let _ = self.candidate_entries.remove(&candidate_hash);
}
},
}
}
@@ -340,10 +334,7 @@ fn garbage_assignment_cert(kind: AssignmentCertKind) -> AssignmentCert {
let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg));
let out = inout.to_output();
AssignmentCert {
kind,
vrf: (VRFOutput(out), VRFProof(proof)),
}
AssignmentCert { kind, vrf: (VRFOutput(out), VRFProof(proof)) }
}
fn sign_approval(
@@ -383,47 +374,40 @@ fn test_harness<T: Future<Output = VirtualOverseer>>(
let store = TestStore::default();
let HarnessConfig {
tick_start,
assigned_tranche,
} = config;
let HarnessConfig { tick_start, assigned_tranche } = config;
let clock = Box::new(MockClock::new(tick_start));
let subsystem = run(
context,
ApprovalVotingSubsystem::with_config(
Config{
col_data: test_constants::TEST_CONFIG.col_data,
slot_duration_millis: 100u64,
},
Config { col_data: test_constants::TEST_CONFIG.col_data, slot_duration_millis: 100u64 },
Arc::new(kvdb_memorydb::create(test_constants::NUM_COLUMNS)),
Arc::new(keystore),
sync_oracle,
Metrics::default(),
),
clock.clone(),
Box::new(MockAssignmentCriteria::check_only(move || { Ok(assigned_tranche) })),
Box::new(MockAssignmentCriteria::check_only(move || Ok(assigned_tranche))),
store,
);
let test_fut = test(TestHarness {
virtual_overseer,
clock,
});
let test_fut = test(TestHarness { virtual_overseer, clock });
futures::pin_mut!(test_fut);
futures::pin_mut!(subsystem);
futures::executor::block_on(future::join(async move {
let mut overseer = test_fut.await;
overseer_signal(&mut overseer, OverseerSignal::Conclude).await;
}, subsystem)).1.unwrap();
futures::executor::block_on(future::join(
async move {
let mut overseer = test_fut.await;
overseer_signal(&mut overseer, OverseerSignal::Conclude).await;
},
subsystem,
))
.1
.unwrap();
}
async fn overseer_send(
overseer: &mut VirtualOverseer,
msg: FromOverseer<ApprovalVotingMessage>,
) {
async fn overseer_send(overseer: &mut VirtualOverseer, msg: FromOverseer<ApprovalVotingMessage>) {
tracing::trace!("Sending message:\n{:?}", &msg);
overseer
.send(msg)
@@ -432,9 +416,7 @@ async fn overseer_send(
.expect(&format!("{:?} is enough for sending messages.", TIMEOUT));
}
async fn overseer_recv(
overseer: &mut VirtualOverseer,
) -> AllMessages {
async fn overseer_recv(overseer: &mut VirtualOverseer) -> AllMessages {
let msg = overseer_recv_with_timeout(overseer, TIMEOUT)
.await
.expect(&format!("{:?} is enough to receive messages.", TIMEOUT));
@@ -449,17 +431,11 @@ async fn overseer_recv_with_timeout(
timeout: Duration,
) -> Option<AllMessages> {
tracing::trace!("Waiting for message...");
overseer
.recv()
.timeout(timeout)
.await
overseer.recv().timeout(timeout).await
}
const TIMEOUT: Duration = Duration::from_millis(2000);
async fn overseer_signal(
overseer: &mut VirtualOverseer,
signal: OverseerSignal,
) {
async fn overseer_signal(overseer: &mut VirtualOverseer, signal: OverseerSignal) {
overseer
.send(FromOverseer::Signal(signal))
.timeout(TIMEOUT)
@@ -471,10 +447,7 @@ async fn overseer_signal(
fn blank_subsystem_act_on_bad_block() {
let (oracle, handle) = make_sync_oracle(false);
test_harness(Default::default(), Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
..
} = test_harness;
let TestHarness { mut virtual_overseer, .. } = test_harness;
let (tx, rx) = oneshot::channel();
@@ -484,18 +457,19 @@ fn blank_subsystem_act_on_bad_block() {
&mut virtual_overseer,
FromOverseer::Communication {
msg: ApprovalVotingMessage::CheckAndImportAssignment(
IndirectAssignmentCert{
IndirectAssignmentCert {
block_hash: bad_block_hash.clone(),
validator: 0u32.into(),
cert: garbage_assignment_cert(
AssignmentCertKind::RelayVRFModulo { sample: 0 }
),
cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo {
sample: 0,
}),
},
0u32,
tx,
)
}
).await;
),
},
)
.await;
handle.await_mode_switch().await;
@@ -516,10 +490,7 @@ fn blank_subsystem_act_on_bad_block() {
fn ss_rejects_approval_if_no_block_entry() {
let (oracle, _handle) = make_sync_oracle(false);
test_harness(Default::default(), Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
..
} = test_harness;
let TestHarness { mut virtual_overseer, .. } = test_harness;
let block_hash = Hash::repeat_byte(0x01);
let candidate_index = 0;
@@ -535,7 +506,8 @@ fn ss_rejects_approval_if_no_block_entry() {
candidate_hash,
session_index,
false,
).await;
)
.await;
assert_matches!(
rx.await,
@@ -552,10 +524,7 @@ fn ss_rejects_approval_if_no_block_entry() {
fn ss_rejects_approval_before_assignment() {
let (oracle, _handle) = make_sync_oracle(false);
test_harness(Default::default(), Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
..
} = test_harness;
let TestHarness { mut virtual_overseer, .. } = test_harness;
let block_hash = Hash::repeat_byte(0x01);
@@ -584,7 +553,8 @@ fn ss_rejects_approval_before_assignment() {
candidate_hash,
session_index,
false,
).await;
)
.await;
assert_matches!(
rx.await,
@@ -600,59 +570,49 @@ fn ss_rejects_approval_before_assignment() {
#[test]
fn ss_rejects_assignment_in_future() {
let (oracle, _handle) = make_sync_oracle(false);
test_harness(HarnessConfig {
tick_start: 0,
assigned_tranche: TICK_TOO_FAR_IN_FUTURE as _,
..Default::default()
}, Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
clock,
} = test_harness;
test_harness(
HarnessConfig {
tick_start: 0,
assigned_tranche: TICK_TOO_FAR_IN_FUTURE as _,
..Default::default()
},
Box::new(oracle),
|test_harness| async move {
let TestHarness { mut virtual_overseer, clock } = test_harness;
let block_hash = Hash::repeat_byte(0x01);
let candidate_index = 0;
let validator = ValidatorIndex(0);
let block_hash = Hash::repeat_byte(0x01);
let candidate_index = 0;
let validator = ValidatorIndex(0);
// Add block hash 00.
ChainBuilder::new()
.add_block(block_hash, ChainBuilder::GENESIS_HASH, Slot::from(1), 1)
.build(&mut virtual_overseer)
.await;
// Add block hash 00.
ChainBuilder::new()
.add_block(block_hash, ChainBuilder::GENESIS_HASH, Slot::from(1), 1)
.build(&mut virtual_overseer)
.await;
let rx = cai_assignment(
&mut virtual_overseer,
block_hash,
candidate_index,
validator,
).await;
let rx =
cai_assignment(&mut virtual_overseer, block_hash, candidate_index, validator).await;
assert_eq!(rx.await, Ok(AssignmentCheckResult::TooFarInFuture));
assert_eq!(rx.await, Ok(AssignmentCheckResult::TooFarInFuture));
// Advance clock to make assignment reasonably near.
clock.inner.lock().set_tick(1);
// Advance clock to make assignment reasonably near.
clock.inner.lock().set_tick(1);
let rx = cai_assignment(
&mut virtual_overseer,
block_hash,
candidate_index,
validator,
).await;
let rx =
cai_assignment(&mut virtual_overseer, block_hash, candidate_index, validator).await;
assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted));
assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted));
virtual_overseer
});
virtual_overseer
},
);
}
#[test]
fn ss_accepts_duplicate_assignment() {
let (oracle, _handle) = make_sync_oracle(false);
test_harness(Default::default(), Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
..
} = test_harness;
let TestHarness { mut virtual_overseer, .. } = test_harness;
let block_hash = Hash::repeat_byte(0x01);
let candidate_index = 0;
@@ -664,21 +624,13 @@ fn ss_accepts_duplicate_assignment() {
.build(&mut virtual_overseer)
.await;
let rx = cai_assignment(
&mut virtual_overseer,
block_hash,
candidate_index,
validator,
).await;
let rx =
cai_assignment(&mut virtual_overseer, block_hash, candidate_index, validator).await;
assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted));
let rx = cai_assignment(
&mut virtual_overseer,
block_hash,
candidate_index,
validator,
).await;
let rx =
cai_assignment(&mut virtual_overseer, block_hash, candidate_index, validator).await;
assert_eq!(rx.await, Ok(AssignmentCheckResult::AcceptedDuplicate));
@@ -690,10 +642,7 @@ fn ss_accepts_duplicate_assignment() {
fn ss_rejects_assignment_with_unknown_candidate() {
let (oracle, _handle) = make_sync_oracle(false);
test_harness(Default::default(), Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
..
} = test_harness;
let TestHarness { mut virtual_overseer, .. } = test_harness;
let block_hash = Hash::repeat_byte(0x01);
let candidate_index = 7;
@@ -705,16 +654,14 @@ fn ss_rejects_assignment_with_unknown_candidate() {
.build(&mut virtual_overseer)
.await;
let rx = cai_assignment(
&mut virtual_overseer,
block_hash,
candidate_index,
validator,
).await;
let rx =
cai_assignment(&mut virtual_overseer, block_hash, candidate_index, validator).await;
assert_eq!(
rx.await,
Ok(AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCandidateIndex(candidate_index))),
Ok(AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCandidateIndex(
candidate_index
))),
);
virtual_overseer
@@ -725,10 +672,7 @@ fn ss_rejects_assignment_with_unknown_candidate() {
fn ss_accepts_and_imports_approval_after_assignment() {
let (oracle, _handle) = make_sync_oracle(false);
test_harness(Default::default(), Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
..
} = test_harness;
let TestHarness { mut virtual_overseer, .. } = test_harness;
let block_hash = Hash::repeat_byte(0x01);
@@ -749,12 +693,8 @@ fn ss_accepts_and_imports_approval_after_assignment() {
.build(&mut virtual_overseer)
.await;
let rx = cai_assignment(
&mut virtual_overseer,
block_hash,
candidate_index,
validator,
).await;
let rx =
cai_assignment(&mut virtual_overseer, block_hash, candidate_index, validator).await;
assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted));
@@ -766,7 +706,8 @@ fn ss_accepts_and_imports_approval_after_assignment() {
candidate_hash,
session_index,
true,
).await;
)
.await;
assert_eq!(rx.await, Ok(ApprovalCheckResult::Accepted));
@@ -777,10 +718,7 @@ fn ss_accepts_and_imports_approval_after_assignment() {
fn ss_assignment_import_updates_candidate_entry_and_schedules_wakeup() {
let (oracle, _handle) = make_sync_oracle(false);
test_harness(Default::default(), Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
..
} = test_harness;
let TestHarness { mut virtual_overseer, .. } = test_harness;
let block_hash = Hash::repeat_byte(0x01);
@@ -800,12 +738,8 @@ fn ss_assignment_import_updates_candidate_entry_and_schedules_wakeup() {
.build(&mut virtual_overseer)
.await;
let rx = cai_assignment(
&mut virtual_overseer,
block_hash,
candidate_index,
validator,
).await;
let rx =
cai_assignment(&mut virtual_overseer, block_hash, candidate_index, validator).await;
assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted));
@@ -831,16 +765,12 @@ async fn cai_approval(
overseer,
FromOverseer::Communication {
msg: ApprovalVotingMessage::CheckAndImportApproval(
IndirectSignedApprovalVote {
block_hash,
candidate_index,
validator,
signature,
},
IndirectSignedApprovalVote { block_hash, candidate_index, validator, signature },
tx,
),
}
).await;
},
)
.await;
if expect_coordinator {
assert_matches!(
@@ -870,17 +800,14 @@ async fn cai_assignment(
IndirectAssignmentCert {
block_hash,
validator,
cert: garbage_assignment_cert(
AssignmentCertKind::RelayVRFModulo {
sample: 0,
},
),
cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }),
},
candidate_index,
tx,
),
}
).await;
},
)
.await;
rx
}
@@ -889,16 +816,13 @@ struct ChainBuilder {
blocks_at_height: BTreeMap<u32, Vec<Hash>>,
}
impl ChainBuilder {
const GENESIS_HASH: Hash = Hash::repeat_byte(0xff);
const GENESIS_PARENT_HASH: Hash = Hash::repeat_byte(0x00);
pub fn new() -> Self {
let mut builder = Self {
blocks_by_hash: HashMap::new(),
blocks_at_height: BTreeMap::new(),
};
let mut builder =
Self { blocks_by_hash: HashMap::new(), blocks_at_height: BTreeMap::new() };
builder.add_block_inner(Self::GENESIS_HASH, Self::GENESIS_PARENT_HASH, Slot::from(0), 0);
builder
}
@@ -912,7 +836,10 @@ impl ChainBuilder {
) -> &'a mut Self {
assert!(number != 0, "cannot add duplicate genesis block");
assert!(hash != Self::GENESIS_HASH, "cannot add block with genesis hash");
assert!(parent_hash != Self::GENESIS_PARENT_HASH, "cannot add block with genesis parent hash");
assert!(
parent_hash != Self::GENESIS_PARENT_HASH,
"cannot add block with genesis parent hash"
);
assert!(self.blocks_by_hash.len() < u8::MAX.into());
self.add_block_inner(hash, parent_hash, slot, number)
}
@@ -927,7 +854,8 @@ impl ChainBuilder {
let header = ChainBuilder::make_header(parent_hash, slot, number);
assert!(
self.blocks_by_hash.insert(hash, header).is_none(),
"block with hash {:?} already exists", hash,
"block with hash {:?} already exists",
hash,
);
self.blocks_at_height.entry(number).or_insert_with(Vec::new).push(hash);
self
@@ -939,7 +867,8 @@ impl ChainBuilder {
let mut cur_hash = *hash;
let mut ancestry = Vec::new();
while cur_hash != Self::GENESIS_PARENT_HASH {
let cur_header = self.blocks_by_hash.get(&cur_hash).expect("chain is not contiguous");
let cur_header =
self.blocks_by_hash.get(&cur_hash).expect("chain is not contiguous");
ancestry.push((cur_hash, cur_header.clone()));
cur_hash = cur_header.parent_hash;
}
@@ -950,21 +879,12 @@ impl ChainBuilder {
}
}
fn make_header(
parent_hash: Hash,
slot: Slot,
number: u32,
) -> Header {
fn make_header(parent_hash: Hash, slot: Slot, number: u32) -> Header {
let digest = {
let mut digest = Digest::default();
let (vrf_output, vrf_proof) = garbage_vrf();
digest.push(DigestItem::babe_pre_digest(PreDigest::SecondaryVRF(
SecondaryVRFPreDigest {
authority_index: 0,
slot,
vrf_output,
vrf_proof,
}
SecondaryVRFPreDigest { authority_index: 0, slot, vrf_output, vrf_proof },
)));
digest
};
@@ -976,8 +896,8 @@ impl ChainBuilder {
state_root: Default::default(),
parent_hash,
}
}
}
}
}
async fn import_block(
overseer: &mut VirtualOverseer,
@@ -1003,13 +923,16 @@ async fn import_block(
let (new_head, new_header) = &hashes[hashes.len() - 1];
overseer_send(
overseer,
FromOverseer::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(ActivatedLeaf {
hash: *new_head,
number: session,
status: LeafStatus::Fresh,
span: Arc::new(jaeger::Span::Disabled),
})),
)).await;
FromOverseer::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(
ActivatedLeaf {
hash: *new_head,
number: session,
status: LeafStatus::Fresh,
span: Arc::new(jaeger::Span::Disabled),
},
))),
)
.await;
assert_matches!(
overseer_recv(overseer).await,
@@ -1070,22 +993,21 @@ async fn import_block(
let (hash, header) = hashes[i as usize].clone();
assert_eq!(hash, *new_head);
h_tx.send(Ok(Some(header))).unwrap();
}
},
AllMessages::ChainApi(ChainApiMessage::Ancestors {
hash,
k,
response_channel,
}) => {
assert_eq!(hash, *new_head);
assert_eq!(k as u32, session-1);
assert_eq!(k as u32, session - 1);
let history: Vec<Hash> = hashes.iter().map(|v| v.0).take(k).collect();
response_channel.send(Ok(history)).unwrap();
}
_ => unreachable!{},
},
_ => unreachable! {},
}
}
}
}
if session > 0 {
@@ -1184,10 +1106,7 @@ fn linear_import_act_on_leaf() {
let (oracle, _handle) = make_sync_oracle(false);
test_harness(Default::default(), Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
..
} = test_harness;
let TestHarness { mut virtual_overseer, .. } = test_harness;
let mut head: Hash = ChainBuilder::GENESIS_HASH;
let mut builder = ChainBuilder::new();
@@ -1197,7 +1116,7 @@ fn linear_import_act_on_leaf() {
let hash = Hash::repeat_byte(i as u8);
builder.add_block(hash, head, slot, i);
head = hash;
}
}
builder.build(&mut virtual_overseer).await;
@@ -1207,18 +1126,19 @@ fn linear_import_act_on_leaf() {
&mut virtual_overseer,
FromOverseer::Communication {
msg: ApprovalVotingMessage::CheckAndImportAssignment(
IndirectAssignmentCert{
IndirectAssignmentCert {
block_hash: head,
validator: 0u32.into(),
cert: garbage_assignment_cert(
AssignmentCertKind::RelayVRFModulo { sample: 0 }
),
cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo {
sample: 0,
}),
},
0u32,
tx,
)
}
).await;
),
},
)
.await;
assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted));
@@ -1232,10 +1152,7 @@ fn forkful_import_at_same_height_act_on_leaf() {
let (oracle, _handle) = make_sync_oracle(false);
test_harness(Default::default(), Box::new(oracle), |test_harness| async move {
let TestHarness {
mut virtual_overseer,
..
} = test_harness;
let TestHarness { mut virtual_overseer, .. } = test_harness;
let mut head: Hash = ChainBuilder::GENESIS_HASH;
let mut builder = ChainBuilder::new();
@@ -1252,7 +1169,7 @@ fn forkful_import_at_same_height_act_on_leaf() {
let slot = Slot::from(session as u64);
let hash = Hash::repeat_byte(session as u8 + i);
builder.add_block(hash, head, slot, session);
}
}
builder.build(&mut virtual_overseer).await;
for head in forks.into_iter() {
@@ -1262,18 +1179,19 @@ fn forkful_import_at_same_height_act_on_leaf() {
&mut virtual_overseer,
FromOverseer::Communication {
msg: ApprovalVotingMessage::CheckAndImportAssignment(
IndirectAssignmentCert{
IndirectAssignmentCert {
block_hash: head,
validator: 0u32.into(),
cert: garbage_assignment_cert(
AssignmentCertKind::RelayVRFModulo { sample: 0 }
),
cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo {
sample: 0,
}),
},
0u32,
tx,
)
}
).await;
),
},
)
.await;
assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted));
}
@@ -16,11 +16,13 @@
//! Time utilities for approval voting.
use futures::prelude::*;
use polkadot_node_primitives::approval::DelayTranche;
use sp_consensus_slots::Slot;
use futures::prelude::*;
use std::time::{Duration, SystemTime};
use std::pin::Pin;
use std::{
pin::Pin,
time::{Duration, SystemTime},
};
const TICK_DURATION_MILLIS: u64 = 500;