1use cfx_addr::{cfx_addr_decode, cfx_addr_encode, EncodingOptions, Network};
6use cfx_types::H160;
7use once_cell::sync::OnceCell;
8use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
9use std::fmt;
10
11pub static USE_SIMPLE_RPC_ADDRESS: OnceCell<bool> = OnceCell::new();
14
15#[derive(Clone, Debug, PartialEq, Eq, Hash)]
18pub struct RpcAddress {
19 pub base32_address: String,
21 pub hex_address: H160,
22 pub network: Network,
23}
24
25impl RpcAddress {
26 pub fn try_from_h160(
27 hex_address: H160, network: Network,
28 ) -> Result<Self, String> {
29 let simple_mode = *USE_SIMPLE_RPC_ADDRESS.get().unwrap_or(&false);
30 let mode = if simple_mode {
31 EncodingOptions::Simple
32 } else {
33 EncodingOptions::QrCode
34 };
35 let base32_address = cfx_addr_encode(&hex_address.0, network, mode)
36 .map_err(|e| e.to_string())?;
37 Ok(Self {
38 base32_address,
39 hex_address,
40 network,
41 })
42 }
43
44 pub fn null(network: Network) -> Result<Self, String> {
45 Self::try_from_h160(H160::default(), network)
46 }
47}
48
49impl From<RpcAddress> for H160 {
50 fn from(x: RpcAddress) -> Self { x.hex_address }
51}
52
53impl<'a> Deserialize<'a> for RpcAddress {
54 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
55 where D: Deserializer<'a> {
56 let s: String = Deserialize::deserialize(deserializer)?;
57
58 let parsed_address = cfx_addr_decode(&s).map_err(|e| {
59 de::Error::custom(format!(
60 "Invalid base32 address: input {} error {}",
61 s, e
62 ))
63 })?;
64 match parsed_address.hex_address {
65 None => Err(de::Error::custom(format!(
66 "Invalid base32 address: input {} not a SIZE_160 address.",
67 s
68 ))),
69 Some(hex_address) => Ok(Self {
70 base32_address: parsed_address.input_base32_address,
71 hex_address,
72 network: parsed_address.network,
73 }),
74 }
75 }
76}
77
78impl Serialize for RpcAddress {
79 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
80 where S: Serializer {
81 serializer.serialize_str(&self.base32_address)
82 }
83}
84
85#[derive(Debug)]
86pub struct RcpAddressNetworkInconsistent {
87 pub from_network: Network,
88 pub to_network: Network,
89}
90
91impl fmt::Display for RcpAddressNetworkInconsistent {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 write!(
94 f,
95 "network prefix inconsistent in from({}) and to({})",
96 self.from_network, self.to_network
97 )
98 }
99}
100
101pub fn check_rpc_address_network(
102 rpc_request_network: Option<Network>, expected: &Network,
103) -> Result<(), UnexpectedRpcAddressNetwork> {
104 if let Some(rpc_network) = rpc_request_network {
105 if rpc_network != *expected {
106 return Err(UnexpectedRpcAddressNetwork {
107 expected: *expected,
108 got: rpc_network,
109 });
110 }
111 }
112 Ok(())
113}
114
115pub fn check_two_rpc_address_network_match(
116 from: Option<&RpcAddress>, to: Option<&RpcAddress>,
117) -> Result<Option<Network>, RcpAddressNetworkInconsistent> {
118 match (from, to) {
119 (None, None) => Ok(None),
120 (None, Some(b)) => Ok(Some(b.network)),
121 (Some(a), None) => Ok(Some(a.network)),
122 (Some(a), Some(b)) => {
123 if a.network != b.network {
124 return Err(RcpAddressNetworkInconsistent {
125 from_network: a.network,
126 to_network: b.network,
127 });
128 }
129 Ok(Some(a.network))
130 }
131 }
132}
133
134#[derive(Debug)]
135pub struct UnexpectedRpcAddressNetwork {
136 pub expected: Network,
137 pub got: Network,
138}
139
140impl fmt::Display for UnexpectedRpcAddressNetwork {
141 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142 write!(
143 f,
144 "network prefix unexpected: ours {}, got {}",
145 self.expected, self.got
146 )
147 }
148}
149#[cfg(test)]
150mod tests {
151 use super::RpcAddress;
152 use cfx_addr::{cfx_addr_encode, EncodingOptions, Network};
153 use cfx_types::H160;
154 use log::debug;
155 use serde_json;
156
157 fn check_deserialize(base32_address: &str, hex: &str, network: Network) {
158 let addr_hex: H160 = hex.trim_start_matches("0x").parse().unwrap();
159 let parsed_result = serde_json::from_str::<RpcAddress>(base32_address);
160 debug!(
161 "parsed: {:?}, expected hex addr {:?}, expected base32 addr {:?}",
162 parsed_result,
163 addr_hex,
164 cfx_addr_encode(
165 addr_hex.as_bytes(),
166 network,
167 EncodingOptions::Simple
168 )
169 );
170 let parsed = parsed_result.unwrap();
171 assert_eq!(parsed.network, network);
172 assert_eq!(parsed.hex_address, addr_hex);
173 }
174
175 #[test]
176 fn test_deserialize_address() {
177 check_deserialize(
178 "\"cfx:acc7uawf5ubtnmezvhu9dhc6sghea0403y2dgpyfjp\"",
179 "0x85d80245dc02f5a89589e1f19c5c718e405b56cd",
180 Network::Main,
181 );
182
183 check_deserialize(
184 "\"cfxtest:acc7uawf5ubtnmezvhu9dhc6sghea0403ywjz6wtpg\"",
185 "0x85d80245dc02f5a89589e1f19c5c718e405b56cd",
186 Network::Test,
187 );
188
189 check_deserialize(
190 "\"cfxtest:type.contract:acc7uawf5ubtnmezvhu9dhc6sghea0403ywjz6wtpg\"",
191 "0x85d80245dc02f5a89589e1f19c5c718e405b56cd",
192 Network::Test,
193 );
194 }
195
196 #[test]
197 #[should_panic]
198 fn test_deserialize_incorrect_network_prefix() {
199 check_deserialize(
200 "\"cfy:acc7uawf5ubtnmezvhu9dhc6sghea0403y2dgpyfjp\"",
201 "0x85d80245dc02f5a89589e1f19c5c718e405b56cd",
202 Network::Main,
203 );
204 }
205
206 #[test]
207 #[should_panic]
208 fn test_deserialize_no_network_prefix() {
209 check_deserialize(
210 "\"acc7uawf5ubtnmezvhu9dhc6sghea0403ywjz6wtpg\"",
211 "0x85d80245dc02f5a89589e1f19c5c718e405b56cd",
212 Network::Main,
213 );
214 }
215
216 #[test]
217 #[should_panic]
218 fn test_deserialize_incorrect_type() {
219 check_deserialize(
220 "\"cfx:type.user:acc7uawf5ubtnmezvhu9dhc6sghea0403y2dgpyfjp\"",
221 "0x85d80245dc02f5a89589e1f19c5c718e405b56cd",
222 Network::Main,
223 );
224 }
225
226 #[test]
227 #[should_panic]
228 fn test_deserialize_incorrect_checksum() {
229 check_deserialize(
230 "\"cfx:acc7uawf5ubtnmezvhu9dhc6sghea0403ywjz6wtpg\"",
231 "0x85d80245dc02f5a89589e1f19c5c718e405b56cd",
232 Network::Main,
233 );
234 }
235}