Get a basic first test working, and lots of changes to supporting code to facilitate this

This commit is contained in:
James Wilson
2021-07-09 17:27:49 +01:00
parent c043393e28
commit 28be68e65f
17 changed files with 980 additions and 350 deletions
+277
View File
@@ -0,0 +1,277 @@
use common::node_types::{BlockDetails, BlockHash, BlockNumber, NodeLocation, NodeStats, Timestamp};
use serde_json::value::RawValue;
#[derive(Debug, PartialEq)]
pub enum FeedMessage {
Version(usize),
BestBlock {
block_number: BlockNumber,
timestamp: Timestamp,
avg_block_time: Option<u64>,
},
BestFinalized {
block_number: BlockNumber,
block_hash: BlockHash,
},
AddedNode {
node_id: usize,
node: NodeDetails,
stats: NodeStats,
// io: NodeIO, // can't losslessly deserialize
// hardware: NodeHardware, // can't losslessly deserialize
block_details: BlockDetails,
location: NodeLocation,
startup_time: Option<Timestamp>,
},
RemovedNode {
node_id: usize,
},
LocatedNode {
node_id: usize,
lat: f32,
long: f32,
city: String,
},
ImportedBlock {
node_id: usize,
block_details: BlockDetails,
},
FinalizedBlock {
node_id: usize,
block_number: BlockNumber,
block_hash: BlockHash,
},
NodeStatsUpdate {
node_id: usize,
stats: NodeStats,
},
Hardware {
node_id: usize,
// hardware: NodeHardware, // Can't losslessly deserialize
},
TimeSync {
time: Timestamp,
},
AddedChain {
name: String,
node_count: usize,
},
RemovedChain {
name: String,
},
SubscribedTo {
name: String,
},
UnsubscribedFrom {
name: String,
},
Pong {
msg: String,
},
AfgFinalized {
address: String,
block_number: BlockNumber,
block_hash: BlockHash,
},
AfgReceivedPrevote {
address: String,
block_number: BlockNumber,
block_hash: BlockHash,
voter: Option<String>
},
AfgReceivedPrecommit {
address: String,
block_number: BlockNumber,
block_hash: BlockHash,
voter: Option<String>,
},
AfgAuthoritySet { // Not used currently; not sure what "address" params are:
a1: String,
a2: String,
a3: String,
block_number: BlockNumber,
block_hash: BlockHash,
},
StaleNode {
node_id: usize,
},
NodeIOUpdate {
node_id: usize,
// details: NodeIO, // can't losslessly deserialize
},
/// A "special" case when we don't know how to decode an action:
UnknownValue {
action: u8,
value: String
}
}
#[derive(Debug, PartialEq)]
pub struct NodeDetails {
pub name: String,
pub implementation: String,
pub version: String,
pub validator: Option<String>,
pub network_id: Option<String>,
}
impl FeedMessage {
/// Decode a slice of bytes into a vector of feed messages
pub fn from_bytes(bytes: &[u8]) -> Result<Vec<FeedMessage>, anyhow::Error> {
let v: Vec<&RawValue> = serde_json::from_slice(bytes)?;
let mut feed_messages = vec![];
for raw_keyval in v.windows(2) {
let raw_key = raw_keyval[0];
let raw_val = raw_keyval[1];
feed_messages.push(FeedMessage::decode(raw_key, raw_val)?);
}
Ok(feed_messages)
}
// Deserialize the feed message to a value based on the "action" key
fn decode(raw_key: &RawValue, raw_val: &RawValue) -> Result<FeedMessage, anyhow::Error> {
let action: u8 = serde_json::from_str(raw_key.get())?;
let feed_message = match action {
// Version:
0 => {
let version = serde_json::from_str(raw_val.get())?;
FeedMessage::Version(version)
},
// BestBlock
1 => {
let (block_number, timestamp, avg_block_time) = serde_json::from_str(raw_val.get())?;
FeedMessage::BestBlock { block_number, timestamp, avg_block_time }
},
// BestFinalized
2 => {
let (block_number, block_hash) = serde_json::from_str(raw_val.get())?;
FeedMessage::BestFinalized { block_number, block_hash }
}
// AddNode
3 => {
let (
node_id,
( name, implementation, version, validator, network_id ),
stats,
io,
hardware,
block_details,
location,
startup_time,
) = serde_json::from_str(raw_val.get())?;
// Give these two types but don't use the results:
let (_,_): (&RawValue, &RawValue) = (io, hardware);
FeedMessage::AddedNode {
node_id,
node: NodeDetails { name, implementation, version, validator, network_id },
stats,
block_details,
location,
startup_time,
}
},
// RemoveNode
4 => {
let node_id = serde_json::from_str(raw_val.get())?;
FeedMessage::RemovedNode { node_id }
},
// LocatedNode
5 => {
let (node_id, lat, long, city) = serde_json::from_str(raw_val.get())?;
FeedMessage::LocatedNode { node_id, lat, long, city }
},
// ImportedBlock
6 => {
let (node_id, block_details) = serde_json::from_str(raw_val.get())?;
FeedMessage::ImportedBlock { node_id, block_details }
},
// FinalizedBlock
7 => {
let (node_id, block_number, block_hash) = serde_json::from_str(raw_val.get())?;
FeedMessage::FinalizedBlock { node_id, block_number, block_hash }
},
// NodeStatsUpdate
8 => {
let (node_id, stats) = serde_json::from_str(raw_val.get())?;
FeedMessage::NodeStatsUpdate { node_id, stats }
},
// Hardware
9 => {
let (node_id, _hardware): (_, &RawValue) = serde_json::from_str(raw_val.get())?;
FeedMessage::Hardware { node_id }
},
// TimeSync
10 => {
let time = serde_json::from_str(raw_val.get())?;
FeedMessage::TimeSync { time }
},
// AddedChain
11 => {
let (name, node_count) = serde_json::from_str(raw_val.get())?;
FeedMessage::AddedChain { name, node_count }
},
// RemovedChain
12 => {
let name = serde_json::from_str(raw_val.get())?;
FeedMessage::RemovedChain { name }
},
// SubscribedTo
13 => {
let name = serde_json::from_str(raw_val.get())?;
FeedMessage::SubscribedTo { name }
},
// UnsubscribedFrom
14 => {
let name = serde_json::from_str(raw_val.get())?;
FeedMessage::UnsubscribedFrom { name }
},
// Pong
15 => {
let msg = serde_json::from_str(raw_val.get())?;
FeedMessage::Pong { msg }
},
// AfgFinalized
16 => {
let (address, block_number, block_hash) = serde_json::from_str(raw_val.get())?;
FeedMessage::AfgFinalized { address, block_number, block_hash }
},
// AfgReceivedPrevote
17 => {
let (address, block_number, block_hash, voter) = serde_json::from_str(raw_val.get())?;
FeedMessage::AfgReceivedPrevote { address, block_number, block_hash, voter }
},
// AfgReceivedPrecommit
18 => {
let (address, block_number, block_hash, voter) = serde_json::from_str(raw_val.get())?;
FeedMessage::AfgReceivedPrecommit { address, block_number, block_hash, voter }
},
// AfgAuthoritySet
19 => {
let (a1, a2, a3, block_number, block_hash) = serde_json::from_str(raw_val.get())?;
FeedMessage::AfgAuthoritySet { a1, a2, a3, block_number, block_hash }
},
// StaleNode
20 => {
let node_id = serde_json::from_str(raw_val.get())?;
FeedMessage::StaleNode { node_id }
},
// NodeIOUpdate
21 => {
// ignore NodeIO for now:
let (node_id, _node_io): (_, &RawValue) = serde_json::from_str(raw_val.get())?;
FeedMessage::NodeIOUpdate { node_id }
},
// A catchall for messages we don't know/care about yet:
_ => {
let value = raw_val.to_string();
FeedMessage::UnknownValue { action, value }
},
};
Ok(feed_message)
}
}