This commit is contained in:
James Wilson
2021-07-01 09:38:26 +01:00
parent 16747dd66c
commit 509542e460
25 changed files with 787 additions and 634 deletions
+15 -9
View File
@@ -1,5 +1,5 @@
use std::hash::Hash;
use bimap::BiMap;
use std::hash::Hash;
/// A struct that allows you to assign an ID to an arbitrary set of
/// details (so long as they are Eq+Hash+Clone), and then access
@@ -9,20 +9,20 @@ use bimap::BiMap;
pub struct AssignId<Id, Details> {
current_id: usize,
mapping: BiMap<usize, Details>,
_id_type: std::marker::PhantomData<Id>
_id_type: std::marker::PhantomData<Id>,
}
impl <Id, Details> AssignId<Id, Details>
impl<Id, Details> AssignId<Id, Details>
where
Details: Eq + Hash,
Id: From<usize> + Copy,
usize: From<Id>
usize: From<Id>,
{
pub fn new() -> Self {
Self {
current_id: 0,
mapping: BiMap::new(),
_id_type: std::marker::PhantomData
_id_type: std::marker::PhantomData,
}
}
@@ -42,11 +42,15 @@ where
}
pub fn remove_by_id(&mut self, id: Id) -> Option<Details> {
self.mapping.remove_by_left(&id.into()).map(|(_,details)| details)
self.mapping
.remove_by_left(&id.into())
.map(|(_, details)| details)
}
pub fn remove_by_details(&mut self, details: &Details) -> Option<Id> {
self.mapping.remove_by_right(&details).map(|(id,_)| id.into())
self.mapping
.remove_by_right(&details)
.map(|(id, _)| id.into())
}
pub fn clear(&mut self) {
@@ -54,6 +58,8 @@ where
}
pub fn iter(&self) -> impl Iterator<Item = (Id, &Details)> {
self.mapping.iter().map(|(&id, details)| (id.into(), details))
self.mapping
.iter()
.map(|(&id, details)| (id.into(), details))
}
}
}
+5 -9
View File
@@ -4,19 +4,19 @@ pub struct DenseMap<Id, T> {
/// All items
items: Vec<Option<T>>,
/// Our ID type
_id_type: std::marker::PhantomData<Id>
_id_type: std::marker::PhantomData<Id>,
}
impl<Id, T> DenseMap<Id, T>
where
Id: From<usize> + Copy,
usize: From<Id>
usize: From<Id>,
{
pub fn new() -> Self {
DenseMap {
retired: Vec::new(),
items: Vec::new(),
_id_type: std::marker::PhantomData
_id_type: std::marker::PhantomData,
}
}
@@ -90,12 +90,8 @@ where
/// Return the next Id that will be assigned.
pub fn next_id(&self) -> usize {
match self.retired.last() {
Some(id) => {
*id
}
None => {
self.items.len()
}
Some(id) => *id,
None => self.items.len(),
}
}
}
+5 -6
View File
@@ -33,7 +33,7 @@ mod test {
#[test]
fn create_and_use_new_id_type() {
id_type!{
id_type! {
Foo(usize)
};
let _ = Foo::new(123);
@@ -41,16 +41,15 @@ mod test {
let _: usize = id.into();
// Check that these don't lead to compile errors:
id_type!{
id_type! {
Bar(usize);
};
id_type!{
id_type! {
pub Wibble(u64)
};
id_type!{
id_type! {
/// We can have doc strings, too
pub(crate) Wobble(u16)
};
}
}
}
+13 -16
View File
@@ -1,8 +1,8 @@
use std::net::IpAddr;
use crate::node_message::Payload;
use crate::node_types::{NodeDetails, BlockHash};
use crate::id_type;
use crate::node_message::Payload;
use crate::node_types::{BlockHash, NodeDetails};
use serde::{Deserialize, Serialize};
id_type! {
@@ -12,16 +12,15 @@ id_type! {
pub ShardNodeId(usize);
}
/// Message sent from the shard to the backend core
#[derive(Deserialize, Serialize, Debug, Clone)]
pub enum FromShardAggregator {
/// Get information about a new node, passing IPv4
AddNode {
ip: Option<IpAddr>,
node: NodeDetails,
local_id: ShardNodeId,
genesis_hash: BlockHash
ip: Option<IpAddr>,
node: NodeDetails,
local_id: ShardNodeId,
genesis_hash: BlockHash,
},
/// Send a message payload to update details for a node
UpdateNode {
@@ -29,23 +28,21 @@ pub enum FromShardAggregator {
payload: Payload,
},
/// Inform the core that a node has been removed
RemoveNode {
local_id: ShardNodeId
}
RemoveNode { local_id: ShardNodeId },
}
/// Message sent form the backend core to the shard
#[derive(Deserialize, Serialize, Debug, Clone)]
pub enum FromTelemetryCore {
Mute {
local_id: ShardNodeId,
reason: MuteReason
}
Mute {
local_id: ShardNodeId,
reason: MuteReason,
},
}
/// Why is the thing being muted?
#[derive(Deserialize, Serialize, Debug, Clone)]
pub enum MuteReason {
Overquota,
ChainNotAllowed
}
ChainNotAllowed,
}
+7 -7
View File
@@ -1,20 +1,20 @@
pub mod node_message;
pub mod internal_messages;
pub mod node_types;
pub mod id_type;
pub mod internal_messages;
pub mod node_message;
pub mod node_types;
pub mod time;
mod log_level;
mod assign_id;
mod most_seen;
mod dense_map;
mod log_level;
mod mean_list;
mod most_seen;
mod num_stats;
// Export a bunch of common bits at the top level for ease of import:
pub use assign_id::AssignId;
pub use dense_map::DenseMap;
pub use log_level::LogLevel;
pub use mean_list::MeanList;
pub use num_stats::NumStats;
pub use most_seen::MostSeen;
pub use log_level::LogLevel;
pub use num_stats::NumStats;
+4 -4
View File
@@ -14,11 +14,11 @@ impl std::str::FromStr for LogLevel {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"error" => Ok(LogLevel::Error),
"warn" => Ok(LogLevel::Warn),
"info" => Ok(LogLevel::Info),
"warn" => Ok(LogLevel::Warn),
"info" => Ok(LogLevel::Info),
"debug" => Ok(LogLevel::Debug),
"trace" => Ok(LogLevel::Trace),
_ => Err("expected 'error', 'warn', 'info', 'debug' or 'trace'")
_ => Err("expected 'error', 'warn', 'info', 'debug' or 'trace'"),
}
}
}
@@ -33,4 +33,4 @@ impl From<&LogLevel> for log::LevelFilter {
LogLevel::Trace => log::LevelFilter::Trace,
}
}
}
}
+16 -20
View File
@@ -7,25 +7,25 @@ use std::hash::Hash;
pub struct MostSeen<T> {
current_best: T,
current_count: usize,
others: HashMap<T, usize>
others: HashMap<T, usize>,
}
impl <T: Default> Default for MostSeen<T> {
impl<T: Default> Default for MostSeen<T> {
fn default() -> Self {
Self {
current_best: T::default(),
current_count: 0,
others: HashMap::new()
others: HashMap::new(),
}
}
}
impl <T> MostSeen<T> {
impl<T> MostSeen<T> {
pub fn new(item: T) -> Self {
Self {
current_best: item,
current_count: 1,
others: HashMap::new()
others: HashMap::new(),
}
}
pub fn best(&self) -> &T {
@@ -36,7 +36,7 @@ impl <T> MostSeen<T> {
}
}
impl <T: Hash + Eq + Clone> MostSeen<T> {
impl<T: Hash + Eq + Clone> MostSeen<T> {
pub fn insert(&mut self, item: &T) -> ChangeResult {
if &self.current_best == item {
// Item already the best one; bump count.
@@ -50,9 +50,7 @@ impl <T: Hash + Eq + Clone> MostSeen<T> {
// Is item now the best?
if *item_count > self.current_count {
let (mut item, mut count) = self.others
.remove_entry(item)
.expect("item added above");
let (mut item, mut count) = self.others.remove_entry(item).expect("item added above");
// Swap the current best for the new best:
std::mem::swap(&mut item, &mut self.current_best);
@@ -72,13 +70,11 @@ impl <T: Hash + Eq + Clone> MostSeen<T> {
self.current_count = self.current_count.saturating_sub(1);
// Is there a new best?
let other_best = self.others
.iter()
.max_by_key(|f| f.1);
let other_best = self.others.iter().max_by_key(|f| f.1);
let (other_item, &other_count) = match other_best {
Some(item) => item,
None => { return ChangeResult::NoChange }
None => return ChangeResult::NoChange,
};
if other_count > self.current_count {
@@ -87,7 +83,8 @@ impl <T: Hash + Eq + Clone> MostSeen<T> {
// instead, but most of the time there is no change, so I'm
// aiming to keep that path cheaper.
let other_item = other_item.clone();
let (mut other_item, mut other_count) = self.others
let (mut other_item, mut other_count) = self
.others
.remove_entry(&other_item)
.expect("item returned above, so def exists");
@@ -113,19 +110,19 @@ impl <T: Hash + Eq + Clone> MostSeen<T> {
}
/// Record the result of adding/removing an entry
#[derive(Clone,Copy)]
#[derive(Clone, Copy)]
pub enum ChangeResult {
/// The best item has remained the same.
NoChange,
/// There is a new best item now.
NewMostSeenItem
NewMostSeenItem,
}
impl ChangeResult {
pub fn has_changed(self) -> bool {
match self {
ChangeResult::NewMostSeenItem => true,
ChangeResult::NoChange => false
ChangeResult::NoChange => false,
}
}
}
@@ -214,7 +211,7 @@ mod test {
a.insert(&"Second");
a.insert(&"Second"); // 3
a.insert(&"First"); // 2
a.insert(&"First"); // 2
assert_eq!(*a.best(), "Second");
assert_eq!(a.best_count(), 3);
@@ -231,5 +228,4 @@ mod test {
assert_eq!(a.best_count(), 2);
assert_eq!(*a.best(), "First"); // First is now ahead
}
}
}
+66 -87
View File
@@ -5,13 +5,8 @@ pub type NodeMessageId = u64;
#[derive(Serialize, Deserialize, Debug)]
pub enum NodeMessage {
V1 {
payload: Payload,
},
V2 {
id: NodeMessageId,
payload: Payload,
},
V1 { payload: Payload },
V2 { id: NodeMessageId, payload: Payload },
}
impl NodeMessage {
@@ -26,8 +21,7 @@ impl NodeMessage {
/// Return the payload associated with the message.
pub fn into_payload(self) -> Payload {
match self {
NodeMessage::V1 { payload, .. } |
NodeMessage::V2 { payload, .. } => payload,
NodeMessage::V1 { payload, .. } | NodeMessage::V2 { payload, .. } => payload,
}
}
}
@@ -133,7 +127,8 @@ mod tests {
// we test the different types we want to (de)serialize ourselves. We just need to test each
// type, not each variant.
fn bincode_can_serialize_and_deserialize<'de, T>(item: T)
where T: Serialize + serde::de::DeserializeOwned
where
T: Serialize + serde::de::DeserializeOwned,
{
let bytes = bincode::serialize(&item).expect("Serialization should work");
let _: T = bincode::deserialize(&bytes).expect("Deserialization should work");
@@ -141,111 +136,95 @@ mod tests {
#[test]
fn bincode_can_serialize_and_deserialize_node_message_system_connected() {
bincode_can_serialize_and_deserialize(
NodeMessage::V1 {
payload: Payload::SystemConnected(SystemConnected {
genesis_hash: BlockHash::zero(),
node: NodeDetails {
chain: "foo".into(),
name: "foo".into(),
implementation: "foo".into(),
version: "foo".into(),
validator: None,
network_id: None,
startup_time: None,
},
})
}
);
bincode_can_serialize_and_deserialize(NodeMessage::V1 {
payload: Payload::SystemConnected(SystemConnected {
genesis_hash: BlockHash::zero(),
node: NodeDetails {
chain: "foo".into(),
name: "foo".into(),
implementation: "foo".into(),
version: "foo".into(),
validator: None,
network_id: None,
startup_time: None,
},
}),
});
}
#[test]
fn bincode_can_serialize_and_deserialize_node_message_system_interval() {
bincode_can_serialize_and_deserialize(
NodeMessage::V1 {
payload: Payload::SystemInterval(SystemInterval {
peers: None,
txcount: None,
bandwidth_upload: None,
bandwidth_download: None,
finalized_height: None,
finalized_hash: None,
block: None,
used_state_cache_size: None,
})
}
);
bincode_can_serialize_and_deserialize(NodeMessage::V1 {
payload: Payload::SystemInterval(SystemInterval {
peers: None,
txcount: None,
bandwidth_upload: None,
bandwidth_download: None,
finalized_height: None,
finalized_hash: None,
block: None,
used_state_cache_size: None,
}),
});
}
#[test]
fn bincode_can_serialize_and_deserialize_node_message_block_import() {
bincode_can_serialize_and_deserialize(
NodeMessage::V1 {
payload: Payload::BlockImport(Block {
hash: BlockHash([0; 32]),
height: 0,
})
}
);
bincode_can_serialize_and_deserialize(NodeMessage::V1 {
payload: Payload::BlockImport(Block {
hash: BlockHash([0; 32]),
height: 0,
}),
});
}
#[test]
fn bincode_can_serialize_and_deserialize_node_message_notify_finalized() {
bincode_can_serialize_and_deserialize(
NodeMessage::V1 {
payload: Payload::NotifyFinalized(Finalized {
hash: BlockHash::zero(),
height: "foo".into(),
})
}
);
bincode_can_serialize_and_deserialize(NodeMessage::V1 {
payload: Payload::NotifyFinalized(Finalized {
hash: BlockHash::zero(),
height: "foo".into(),
}),
});
}
#[test]
fn bincode_can_serialize_and_deserialize_node_message_tx_pool_import() {
bincode_can_serialize_and_deserialize(
NodeMessage::V1 {
payload: Payload::TxPoolImport
}
);
bincode_can_serialize_and_deserialize(NodeMessage::V1 {
payload: Payload::TxPoolImport,
});
}
#[test]
fn bincode_can_serialize_and_deserialize_node_message_afg_finalized() {
bincode_can_serialize_and_deserialize(
NodeMessage::V1 {
payload: Payload::AfgFinalized(AfgFinalized {
finalized_hash: BlockHash::zero(),
finalized_number: "foo".into(),
})
}
);
bincode_can_serialize_and_deserialize(NodeMessage::V1 {
payload: Payload::AfgFinalized(AfgFinalized {
finalized_hash: BlockHash::zero(),
finalized_number: "foo".into(),
}),
});
}
#[test]
fn bincode_can_serialize_and_deserialize_node_message_afg_received() {
bincode_can_serialize_and_deserialize(
NodeMessage::V1 {
payload: Payload::AfgReceivedPrecommit(AfgReceived {
target_hash: BlockHash::zero(),
target_number: "foo".into(),
voter: None,
})
}
);
bincode_can_serialize_and_deserialize(NodeMessage::V1 {
payload: Payload::AfgReceivedPrecommit(AfgReceived {
target_hash: BlockHash::zero(),
target_number: "foo".into(),
voter: None,
}),
});
}
#[test]
fn bincode_can_serialize_and_deserialize_node_message_afg_authority_set() {
bincode_can_serialize_and_deserialize(
NodeMessage::V1 {
payload: Payload::AfgAuthoritySet(AfgAuthoritySet {
authority_id: "foo".into(),
authorities: "foo".into(),
authority_set_id: "foo".into(),
})
}
);
bincode_can_serialize_and_deserialize(NodeMessage::V1 {
payload: Payload::AfgAuthoritySet(AfgAuthoritySet {
authority_id: "foo".into(),
authorities: "foo".into(),
authority_set_id: "foo".into(),
}),
});
}
#[test]