add some tests for authority set logic

This commit is contained in:
Robert Habermeier
2018-10-27 16:18:01 +02:00
parent e33a8dde4a
commit 25984d8dc8
3 changed files with 154 additions and 27 deletions
@@ -11,7 +11,6 @@ sr-primitives = { path = "../sr-primitives" }
substrate-consensus-common = { path = "../consensus/common" }
substrate-primitives = { path = "../primitives" }
substrate-client = { path = "../client" }
substrate-network = { path = "../network" }
log = "0.4"
parking_lot = "0.4"
tokio = "0.1.7"
@@ -23,5 +22,4 @@ features = ["derive-codec"]
[dev-dependencies]
substrate-network = { path = "../network", features = ["test-helpers"] }
parking_lot = "0.4"
substrate-keyring = { path = "../keyring" }
@@ -53,6 +53,11 @@ impl<H, N> SharedAuthoritySet<H, N> {
{
f(&*self.inner.read())
}
/// Execute a closure with the inner set mutably.
pub(crate) fn with_mut<F, U>(&self, f: F) -> U where F: FnOnce(&mut AuthoritySet<H, N>) -> U {
f(&mut *self.inner.write())
}
}
impl<H: Eq, N> SharedAuthoritySet<H, N>
@@ -60,17 +65,7 @@ impl<H: Eq, N> SharedAuthoritySet<H, N>
{
/// Note an upcoming pending transition.
pub(crate) fn add_pending_change(&self, pending: PendingChange<H, N>) {
// ordered first by effective number and then by signal-block number.
let mut inner = self.inner.write();
let key = (pending.effective_number(), pending.canon_height.clone());
let idx = inner.pending_changes
.binary_search_by_key(&key, |change| (
change.effective_number(),
change.canon_height.clone(),
))
.unwrap_or_else(|i| i);
inner.pending_changes.insert(idx, pending);
self.inner.write().add_pending_change(pending)
}
/// Get the earliest limit-block number, if any.
@@ -82,11 +77,6 @@ impl<H: Eq, N> SharedAuthoritySet<H, N>
pub(crate) fn set_id(&self) -> u64 {
self.inner.read().set_id
}
/// Execute a closure with the inner set mutably.
pub(crate) fn with_mut<F, U>(&self, f: F) -> U where F: FnOnce(&mut AuthoritySet<H, N>) -> U {
f(&mut *self.inner.write())
}
}
impl<H, N> From<AuthoritySet<H, N>> for SharedAuthoritySet<H, N> {
@@ -118,6 +108,19 @@ impl<H, N> AuthoritySet<H, N> {
impl<H: Eq, N> AuthoritySet<H, N>
where N: Add<Output=N> + Ord + Clone + Debug,
{
/// Note an upcoming pending transition.
pub(crate) fn add_pending_change(&mut self, pending: PendingChange<H, N>) {
// ordered first by effective number and then by signal-block number.
let key = (pending.effective_number(), pending.canon_height.clone());
let idx = self.pending_changes
.binary_search_by_key(&key, |change| (
change.effective_number(),
change.canon_height.clone(),
))
.unwrap_or_else(|i| i);
self.pending_changes.insert(idx, pending);
}
/// Get the earliest limit-block number, if any.
pub(crate) fn current_limit(&self) -> Option<N> {
self.pending_changes.get(0).map(|change| change.effective_number().clone())
@@ -173,7 +176,7 @@ impl<H: Eq, N> AuthoritySet<H, N>
///
/// This will be applied when the announcing block is at some depth within
/// the finalized chain.
#[derive(Debug, Clone, Encode, Decode)]
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub(crate) struct PendingChange<H, N> {
/// The new authorities and weights to apply.
pub(crate) next_authorities: Vec<(AuthorityId, u64)>,
@@ -192,3 +195,133 @@ impl<H, N: Add<Output=N> + Clone> PendingChange<H, N> {
self.canon_height.clone() + self.finalization_depth.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn changes_sorted_in_correct_order() {
let mut authorities = AuthoritySet {
current_authorities: Vec::new(),
set_id: 0,
pending_changes: Vec::new(),
};
let change_a = PendingChange {
next_authorities: Vec::new(),
finalization_depth: 10,
canon_height: 5,
canon_hash: "hash_a",
};
let change_b = PendingChange {
next_authorities: Vec::new(),
finalization_depth: 0,
canon_height: 16,
canon_hash: "hash_b",
};
let change_c = PendingChange {
next_authorities: Vec::new(),
finalization_depth: 5,
canon_height: 10,
canon_hash: "hash_c",
};
authorities.add_pending_change(change_a.clone());
authorities.add_pending_change(change_b.clone());
authorities.add_pending_change(change_c.clone());
assert_eq!(authorities.pending_changes, vec![change_a, change_c, change_b]);
}
#[test]
fn apply_change() {
let mut authorities = AuthoritySet {
current_authorities: Vec::new(),
set_id: 0,
pending_changes: Vec::new(),
};
let set_a = vec![([1; 32].into(), 5)];
let set_b = vec![([2; 32].into(), 5)];
let change_a = PendingChange {
next_authorities: set_a.clone(),
finalization_depth: 10,
canon_height: 5,
canon_hash: "hash_a",
};
let change_b = PendingChange {
next_authorities: set_b.clone(),
finalization_depth: 10,
canon_height: 5,
canon_hash: "hash_b",
};
authorities.add_pending_change(change_a.clone());
authorities.add_pending_change(change_b.clone());
authorities.apply_changes::<_, ()>(10, |_| panic!()).unwrap();
assert!(authorities.current_authorities.is_empty());
authorities.apply_changes::<_, ()>(
15,
|n| if n == 5 { Ok("hash_a") } else { panic!() }
).unwrap();
assert_eq!(authorities.current_authorities, set_a);
assert_eq!(authorities.set_id, 1);
}
#[test]
fn apply_many_changes_at_once() {
let mut authorities = AuthoritySet {
current_authorities: Vec::new(),
set_id: 0,
pending_changes: Vec::new(),
};
let set_a = vec![([1; 32].into(), 5)];
let set_b = vec![([2; 32].into(), 5)];
let set_c = vec![([3; 32].into(), 5)];
let change_a = PendingChange {
next_authorities: set_a.clone(),
finalization_depth: 10,
canon_height: 5,
canon_hash: "hash_a",
};
// will be ignored because it was signalled when change_a still pending.
let change_b = PendingChange {
next_authorities: set_b.clone(),
finalization_depth: 10,
canon_height: 15,
canon_hash: "hash_b",
};
let change_c = PendingChange {
next_authorities: set_c.clone(),
finalization_depth: 10,
canon_height: 16,
canon_hash: "hash_c",
};
authorities.add_pending_change(change_a.clone());
authorities.add_pending_change(change_b.clone());
authorities.add_pending_change(change_c.clone());
authorities.apply_changes(26, |n| match n {
5 => Ok("hash_a"),
15 => Ok("hash_b"),
16 => Ok("hash_c"),
_ => Err(()),
}).unwrap();
assert_eq!(authorities.current_authorities, set_c);
assert_eq!(authorities.set_id, 2); // has been bumped only twice
}
}
+4 -8
View File
@@ -24,7 +24,6 @@ extern crate substrate_client as client;
extern crate sr_primitives as runtime_primitives;
extern crate substrate_consensus_common as consensus_common;
extern crate substrate_primitives;
extern crate substrate_network as network;
extern crate tokio;
extern crate parking_lot;
extern crate parity_codec as codec;
@@ -35,9 +34,6 @@ extern crate log;
#[cfg(test)]
extern crate substrate_network as network;
#[cfg(test)]
extern crate parking_lot;
#[cfg(test)]
extern crate substrate_keyring as keyring;
@@ -871,10 +867,10 @@ mod tests {
.take_while(|n| Ok(n.header.number() < &20))
.for_each(move |_| Ok(()))
);
let voter = run_grandpa(
let (voter, _) = run_grandpa(
Config {
gossip_duration: TEST_GOSSIP_DURATION,
voters: voters.clone(),
genesis_voters: voters.clone(),
local_key: Some(Arc::new(key.clone().into())),
},
client,
@@ -930,10 +926,10 @@ mod tests {
.take_while(|n| Ok(n.header.number() < &20))
.for_each(move |_| Ok(()))
);
let voter = run_grandpa(
let (voter, _) = run_grandpa(
Config {
gossip_duration: TEST_GOSSIP_DURATION,
voters: voters.keys().cloned().collect(),
genesis_voters: voters.keys().cloned().collect(),
local_key,
},
client,