use crate::network_head_v2::*;
use crate::network_head_v3::*;
use crate::{NodeFullId, NodeId};
use dubp_documents::blockstamp::*;
use dup_crypto::bases::BaseConvertionError;
use dup_crypto::keys::*;
use serde_json;
use std::collections::HashMap;
use std::num::ParseIntError;
use std::ops::Deref;
use std::str::FromStr;
#[derive(Debug, Clone, Eq, Ord, PartialOrd, PartialEq, Serialize, Deserialize)]
pub enum NetworkHead {
V2(Box<NetworkHeadV2>),
V3(Box<NetworkHeadV3>),
}
impl ToString for NetworkHead {
fn to_string(&self) -> String {
match *self {
NetworkHead::V2(ref head_v2) => head_v2.deref().to_string(),
_ => panic!("NetworkHead version not supported !"),
}
}
}
#[derive(Debug)]
pub enum NetworkHeadParseErr {
BaseConvertionError(BaseConvertionError),
ParseIntError(ParseIntError),
BlockstampParseError(BlockstampParseError),
NetworkHeadMessageParseErr(NetworkHeadMessageParseErr),
InvalidMessageVersion(),
InvalidStep(),
InvalidStr(&'static str),
MissingField(&'static str),
}
impl From<NetworkHeadMessageParseErr> for NetworkHeadParseErr {
fn from(e: NetworkHeadMessageParseErr) -> Self {
NetworkHeadParseErr::NetworkHeadMessageParseErr(e)
}
}
impl From<BaseConvertionError> for NetworkHeadParseErr {
fn from(e: BaseConvertionError) -> Self {
NetworkHeadParseErr::BaseConvertionError(e)
}
}
impl From<BlockstampParseError> for NetworkHeadParseErr {
fn from(e: BlockstampParseError) -> Self {
NetworkHeadParseErr::BlockstampParseError(e)
}
}
impl From<ParseIntError> for NetworkHeadParseErr {
fn from(e: ParseIntError) -> Self {
NetworkHeadParseErr::ParseIntError(e)
}
}
impl NetworkHead {
pub fn version(&self) -> u32 {
match *self {
NetworkHead::V2(_) => 2,
_ => panic!("This HEAD version is not supported !"),
}
}
pub fn blockstamp(&self) -> Blockstamp {
match *self {
NetworkHead::V2(ref head_v2) => head_v2.message_v2.blockstamp(),
_ => panic!("This HEAD version is not supported !"),
}
}
pub fn pubkey(&self) -> PubKey {
match *self {
NetworkHead::V2(ref head_v2) => match head_v2.message_v2 {
NetworkHeadMessage::V2(ref head_message_v2) => head_message_v2.pubkey,
_ => panic!("This HEAD message version is not supported !"),
},
_ => panic!("This HEAD version is not supported !"),
}
}
pub fn uid(&self) -> Option<String> {
match *self {
NetworkHead::V2(ref head_v2) => head_v2.uid(),
_ => panic!("This HEAD version is not supported !"),
}
}
pub fn set_uid(&mut self, uid: &str) {
match *self {
NetworkHead::V2(ref mut head_v2) => head_v2.uid = Some(String::from(uid)),
_ => panic!("This HEAD version is not supported !"),
}
}
pub fn step(&self) -> u32 {
match *self {
NetworkHead::V2(ref head_v2) => head_v2.step,
_ => panic!("This HEAD version is not supported !"),
}
}
pub fn verify(&self) -> bool {
match *self {
NetworkHead::V2(ref head_v2) => {
self.pubkey()
.verify(head_v2.message.to_string().as_bytes(), &head_v2.sig)
&& self
.pubkey()
.verify(head_v2.message_v2.to_string().as_bytes(), &head_v2.sig_v2)
}
_ => panic!("This HEAD version is not supported !"),
}
}
pub fn node_uuid(&self) -> NodeId {
match *self {
NetworkHead::V2(ref head_v2) => head_v2.message_v2.node_uuid(),
_ => panic!("This HEAD version is not supported !"),
}
}
pub fn node_full_id(&self) -> NodeFullId {
NodeFullId(self.node_uuid(), self.pubkey())
}
pub fn apply(&self, heads_cache: &mut HashMap<NodeFullId, NetworkHead>) -> bool {
let heads_cache_copy = heads_cache.clone();
if let Some(head) = heads_cache_copy.get(&self.node_full_id()) {
if self.blockstamp().id.0 > head.blockstamp().id.0
|| (self.blockstamp().id.0 == head.blockstamp().id.0
&& self.version() >= head.version()
&& self.step() < head.step())
{
if let Some(head_mut) = heads_cache.get_mut(&self.node_full_id()) {
*head_mut = self.clone();
true
} else {
false
}
} else {
false
}
} else {
heads_cache.insert(self.node_full_id(), self.clone());
true
}
}
pub fn from_json_value(source: &serde_json::Value) -> Result<NetworkHead, NetworkHeadParseErr> {
let message = NetworkHeadMessage::from_str(if let Some(str_msg) = source.get("message") {
if let Some(str_msg) = str_msg.as_str() {
str_msg
} else {
return Err(NetworkHeadParseErr::InvalidStr("message"));
}
} else {
return Err(NetworkHeadParseErr::MissingField("message"));
})?;
match message {
NetworkHeadMessage::V2(_) => Ok(NetworkHead::V2(Box::new(NetworkHeadV2 {
message,
sig: Sig::Ed25519(ed25519::Signature::from_base64(
if let Some(str_sig) = source.get("sig") {
if let Some(str_sig) = str_sig.as_str() {
str_sig
} else {
return Err(NetworkHeadParseErr::InvalidStr("sig"));
}
} else {
return Err(NetworkHeadParseErr::MissingField("sigV2"));
},
)?),
message_v2: NetworkHeadMessage::from_str(
if let Some(str_msg) = source.get("messageV2") {
if let Some(str_msg) = str_msg.as_str() {
str_msg
} else {
return Err(NetworkHeadParseErr::InvalidStr("messageV2"));
}
} else {
return Err(NetworkHeadParseErr::MissingField("messageV2"));
},
)?,
sig_v2: Sig::Ed25519(ed25519::Signature::from_base64(
if let Some(str_sig) = source.get("sigV2") {
if let Some(str_sig) = str_sig.as_str() {
str_sig
} else {
return Err(NetworkHeadParseErr::InvalidStr("sigV2"));
}
} else {
return Err(NetworkHeadParseErr::MissingField("sigV2"));
},
)?),
step: if let Some(step) = source.get("step") {
if let Some(step) = step.as_u64() {
step as u32
} else {
return Err(NetworkHeadParseErr::InvalidStep());
}
} else {
return Err(NetworkHeadParseErr::MissingField("step"));
},
uid: None,
}))),
_ => Err(NetworkHeadParseErr::InvalidMessageVersion()),
}
}
pub fn to_human_string(&self, max_len: usize) -> String {
match *self {
NetworkHead::V2(ref head_v2) => head_v2.deref().to_human_string(max_len),
_ => panic!("NetworkHead version not supported !"),
}
}
}