hopr_internal_types/
account.rs1use std::fmt::{Display, Formatter};
2
3use hopr_crypto_types::prelude::*;
4use hopr_primitive_types::prelude::*;
5use multiaddr::Multiaddr;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub enum AccountType {
11 NotAnnounced,
13 Announced(Vec<Multiaddr>),
15}
16
17impl Display for AccountType {
18 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
19 match &self {
20 Self::NotAnnounced => {
21 write!(f, "not announced")
22 }
23 Self::Announced(multiaddr) => write!(f, "announced via {multiaddr:?}"),
24 }
25 }
26}
27
28#[derive(Clone, Debug, PartialEq, Eq)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct AccountEntry {
33 pub public_key: OffchainPublicKey,
34 pub chain_addr: Address,
35 pub entry_type: AccountType,
36 pub safe_address: Option<Address>,
37 pub key_id: KeyIdent<4>,
38}
39
40impl AccountEntry {
41 pub fn has_announced(&self) -> bool {
43 matches!(&self.entry_type, AccountType::Announced(addrs) if !addrs.is_empty())
44 }
45
46 pub fn has_announced_with_routing_info(&self) -> bool {
48 match &self.entry_type {
49 AccountType::NotAnnounced => false,
50 AccountType::Announced(multiaddrs) => {
51 !multiaddrs.is_empty()
52 && multiaddrs.iter().all(|multiaddr| {
53 multiaddr
54 .protocol_stack()
55 .any(|p| p == "ip4" || p == "dns4" || p == "ip6" || p == "dns6")
56 && multiaddr.protocol_stack().any(|p| p == "tcp" || p == "udp")
57 })
58 }
59 }
60 }
61
62 pub fn get_multiaddrs(&self) -> &[Multiaddr] {
63 match &self.entry_type {
64 AccountType::NotAnnounced => &[],
65 AccountType::Announced(multiaddrs) => multiaddrs.as_slice(),
66 }
67 }
68
69 pub fn update(&mut self, new_entry_type: AccountType) {
76 self.entry_type = new_entry_type;
77 }
78}
79
80impl Display for AccountEntry {
81 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
82 write!(
83 f,
84 "account {} ({}:{}) (safe: {:?}) {}",
85 self.key_id,
86 self.chain_addr,
87 self.public_key.to_peerid_str(),
88 self.safe_address,
89 self.entry_type
90 )
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use hex_literal::hex;
97 use hopr_crypto_types::types::OffchainPublicKey;
98 use hopr_primitive_types::prelude::*;
99
100 use crate::account::{
101 AccountEntry,
102 AccountType::{Announced, NotAnnounced},
103 };
104
105 const PRIVATE_KEY: [u8; 32] = hex!("c14b8faa0a9b8a5fa4453664996f23a7e7de606d42297d723fc4a794f375e260");
106 const CHAIN_ADDR: [u8; 20] = hex!("2cDD13ddB0346E0F620C8E5826Da5d7230341c6E");
107
108 #[test]
109 fn test_account_entry_non_routable() -> anyhow::Result<()> {
110 let public_key = OffchainPublicKey::from_privkey(&PRIVATE_KEY)?;
111 let chain_addr = Address::try_from(CHAIN_ADDR.as_ref())?;
112
113 let ae1 = AccountEntry {
114 public_key,
115 chain_addr,
116 key_id: 1.into(),
117 entry_type: Announced(vec![
118 "/p2p/16Uiu2HAm3rUQdpCz53tK1MVUUq9NdMAU6mFgtcXrf71Ltw6AStzk".parse()?,
119 ]),
120 safe_address: None,
121 };
122
123 assert!(ae1.has_announced());
124 assert!(!ae1.has_announced_with_routing_info());
125
126 Ok(())
127 }
128
129 #[test]
130 fn test_account_entry_routable() -> anyhow::Result<()> {
131 let public_key = OffchainPublicKey::from_privkey(&PRIVATE_KEY)?;
132 let chain_addr = Address::try_from(CHAIN_ADDR.as_ref())?;
133
134 let ae1 = AccountEntry {
135 public_key,
136 chain_addr,
137 key_id: 1.into(),
138 entry_type: Announced(vec![
139 "/ip4/34.65.237.196/tcp/9091/p2p/16Uiu2HAm3rUQdpCz53tK1MVUUq9NdMAU6mFgtcXrf71Ltw6AStzk".parse()?,
140 ]),
141 safe_address: None,
142 };
143
144 assert!(ae1.has_announced());
145 assert!(ae1.has_announced_with_routing_info());
146
147 let ae1 = AccountEntry {
148 public_key,
149 chain_addr,
150 key_id: 1.into(),
151 entry_type: Announced(vec![
152 "/ip4/34.65.237.196/udp/9091/p2p/16Uiu2HAm3rUQdpCz53tK1MVUUq9NdMAU6mFgtcXrf71Ltw6AStzk".parse()?,
153 ]),
154 safe_address: None,
155 };
156
157 assert!(ae1.has_announced());
158 assert!(ae1.has_announced_with_routing_info());
159
160 Ok(())
161 }
162
163 #[test]
164 fn test_account_entry_not_announced() -> anyhow::Result<()> {
165 let public_key = OffchainPublicKey::from_privkey(&PRIVATE_KEY)?;
166 let chain_addr = Address::try_from(CHAIN_ADDR.as_ref())?;
167
168 let ae1 = AccountEntry {
169 public_key,
170 chain_addr,
171 key_id: 0.into(),
172 entry_type: NotAnnounced,
173 safe_address: None,
174 };
175
176 assert!(!ae1.has_announced());
177 assert!(!ae1.has_announced_with_routing_info());
178
179 Ok(())
180 }
181}