use std::fmt::Formatter;
use crate::crypto::prelude::HashFast;
use crate::crypto_random::Randomizable;
use crate::primitive::{
bounded::{BoundedSize, BoundedVec},
errors::GeneralError,
prelude::BytesRepresentable,
};
use crate::internal::{NodeId, path::ValidatedPath, prelude::HoprPseudonym};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum RoutingOptions {
IntermediatePath(BoundedVec<NodeId, { RoutingOptions::MAX_INTERMEDIATE_HOPS }>),
Hops(BoundedSize<{ RoutingOptions::MAX_INTERMEDIATE_HOPS }>),
}
impl RoutingOptions {
pub const MAX_INTERMEDIATE_HOPS: usize = 3;
pub fn invert(self) -> RoutingOptions {
match self {
RoutingOptions::IntermediatePath(v) => {
RoutingOptions::IntermediatePath(v.into_iter().rev().collect())
}
_ => self,
}
}
pub fn count_hops(&self) -> usize {
match &self {
RoutingOptions::IntermediatePath(v) => v.as_ref().len(),
RoutingOptions::Hops(h) => (*h).into(),
}
}
}
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SurbMatcher {
Exact(HoprSenderId),
Pseudonym(HoprPseudonym),
}
impl SurbMatcher {
pub fn pseudonym(&self) -> HoprPseudonym {
match self {
SurbMatcher::Exact(id) => id.pseudonym(),
SurbMatcher::Pseudonym(p) => *p,
}
}
}
impl From<HoprPseudonym> for SurbMatcher {
fn from(value: HoprPseudonym) -> Self {
Self::Pseudonym(value)
}
}
impl From<&HoprPseudonym> for SurbMatcher {
fn from(pseudonym: &HoprPseudonym) -> Self {
(*pseudonym).into()
}
}
pub type PathId = [u64; 5];
#[derive(Debug, Clone, PartialEq, Eq, strum::EnumIs)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DestinationRouting {
Forward {
destination: Box<NodeId>,
pseudonym: Option<HoprPseudonym>,
forward_options: RoutingOptions,
return_options: Option<RoutingOptions>,
},
Return(SurbMatcher),
}
impl DestinationRouting {
pub fn forward_only<T: Into<NodeId>>(destination: T, forward_options: RoutingOptions) -> Self {
Self::Forward {
destination: Box::new(destination.into()),
pseudonym: None,
forward_options,
return_options: None,
}
}
}
#[derive(Clone, Debug, strum::EnumIs)]
pub enum ResolvedTransportRouting<S> {
Forward {
pseudonym: HoprPseudonym,
forward_path: ValidatedPath,
return_paths: Vec<ValidatedPath>,
},
Return(HoprSenderId, S),
}
impl<S> ResolvedTransportRouting<S> {
pub fn forward_only(forward_path: ValidatedPath) -> Self {
Self::Forward {
pseudonym: HoprPseudonym::random(),
forward_path,
return_paths: vec![],
}
}
pub fn count_return_paths(&self) -> usize {
match self {
ResolvedTransportRouting::Forward { return_paths, .. } => return_paths.len(),
ResolvedTransportRouting::Return(..) => 0,
}
}
}
pub const SURB_ID_SIZE: usize = 8;
pub type HoprSurbId = [u8; SURB_ID_SIZE];
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct HoprSenderId(
#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; Self::SIZE],
);
impl std::fmt::Debug for HoprSenderId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("HoprSenderId")
.field(&hex::encode(&self.0[0..HoprPseudonym::SIZE]))
.field(&hex::encode(&self.0[HoprPseudonym::SIZE..]))
.finish()
}
}
impl HoprSenderId {
pub fn new(pseudonym: &HoprPseudonym) -> Self {
let mut ret: [u8; Self::SIZE] = crate::crypto_random::random_bytes();
ret[..HoprPseudonym::SIZE].copy_from_slice(pseudonym.as_ref());
Self(ret)
}
pub fn from_pseudonym_and_id(pseudonym: &HoprPseudonym, id: HoprSurbId) -> Self {
let mut ret = [0u8; Self::SIZE];
ret[..HoprPseudonym::SIZE].copy_from_slice(pseudonym.as_ref());
ret[HoprPseudonym::SIZE..HoprPseudonym::SIZE + SURB_ID_SIZE].copy_from_slice(&id);
Self(ret)
}
pub fn pseudonym(&self) -> HoprPseudonym {
HoprPseudonym::try_from(&self.0[..HoprPseudonym::SIZE]).expect("must have valid pseudonym")
}
pub fn surb_id(&self) -> HoprSurbId {
self.0[HoprPseudonym::SIZE..HoprPseudonym::SIZE + SURB_ID_SIZE]
.try_into()
.expect("must have valid nonce")
}
pub fn into_sequence(self) -> impl Iterator<Item = Self> {
std::iter::successors(Some((1u32, self)), |&(i, prev)| {
let hash = HashFast::create(&[&i.to_be_bytes(), prev.as_ref()]);
Some((
i + 1,
Self::from_pseudonym_and_id(
&prev.pseudonym(),
hash.as_ref()[0..SURB_ID_SIZE].try_into().unwrap(),
),
))
})
.map(|(_, v)| v)
}
}
impl AsRef<[u8]> for HoprSenderId {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl<'a> TryFrom<&'a [u8]> for HoprSenderId {
type Error = GeneralError;
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
value
.try_into()
.map(Self)
.map_err(|_| GeneralError::ParseError("HoprSenderId.size".into()))
}
}
impl BytesRepresentable for HoprSenderId {
const SIZE: usize = HoprPseudonym::SIZE + SURB_ID_SIZE;
}
impl crate::crypto_random::Randomizable for HoprSenderId {
fn random() -> Self {
Self::new(&HoprPseudonym::random())
}
}