move_core_types/
account_address.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4use hex::FromHex;
5use rand::{rngs::OsRng, Rng};
6use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
7use std::{convert::TryFrom, fmt, str::FromStr};
8
9/// A struct that represents an account address.
10#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
11#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))]
12pub struct AccountAddress([u8; AccountAddress::LENGTH]);
13
14impl AccountAddress {
15    pub const fn new(address: [u8; Self::LENGTH]) -> Self {
16        Self(address)
17    }
18
19    /// The number of bytes in an address.
20    pub const LENGTH: usize = 16;
21
22    /// Hex address: 0x0
23    pub const ZERO: Self = Self([0u8; Self::LENGTH]);
24
25    pub fn random() -> Self {
26        let mut rng = OsRng;
27        let buf: [u8; Self::LENGTH] = rng.gen();
28        Self(buf)
29    }
30
31    pub fn short_str_lossless(&self) -> String {
32        let hex_str = hex::encode(&self.0).trim_start_matches('0').to_string();
33        if hex_str.is_empty() {
34            "0".to_string()
35        } else {
36            hex_str
37        }
38    }
39
40    pub fn to_vec(&self) -> Vec<u8> {
41        self.0.to_vec()
42    }
43
44    pub fn into_bytes(self) -> [u8; Self::LENGTH] {
45        self.0
46    }
47
48    pub fn from_hex_literal(literal: &str) -> Result<Self, AccountAddressParseError> {
49        if !literal.starts_with("0x") {
50            return Err(AccountAddressParseError);
51        }
52
53        let hex_len = literal.len() - 2;
54
55        // If the string is too short, pad it
56        if hex_len < Self::LENGTH * 2 {
57            let mut hex_str = String::with_capacity(Self::LENGTH * 2);
58            for _ in 0..Self::LENGTH * 2 - hex_len {
59                hex_str.push('0');
60            }
61            hex_str.push_str(&literal[2..]);
62            AccountAddress::from_hex(hex_str)
63        } else {
64            AccountAddress::from_hex(&literal[2..])
65        }
66    }
67
68    pub fn to_hex_literal(&self) -> String {
69        format!("0x{}", self.short_str_lossless())
70    }
71
72    pub fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AccountAddressParseError> {
73        <[u8; Self::LENGTH]>::from_hex(hex)
74            .map_err(|_| AccountAddressParseError)
75            .map(Self)
76    }
77
78    pub fn to_hex(&self) -> String {
79        format!("{:x}", self)
80    }
81
82    pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, AccountAddressParseError> {
83        <[u8; Self::LENGTH]>::try_from(bytes.as_ref())
84            .map_err(|_| AccountAddressParseError)
85            .map(Self)
86    }
87}
88
89impl AsRef<[u8]> for AccountAddress {
90    fn as_ref(&self) -> &[u8] {
91        &self.0
92    }
93}
94
95impl std::ops::Deref for AccountAddress {
96    type Target = [u8; Self::LENGTH];
97
98    fn deref(&self) -> &Self::Target {
99        &self.0
100    }
101}
102
103impl fmt::Display for AccountAddress {
104    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
105        write!(f, "{:X}", self)
106    }
107}
108
109impl fmt::Debug for AccountAddress {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        write!(f, "{:X}", self)
112    }
113}
114
115impl fmt::LowerHex for AccountAddress {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        if f.alternate() {
118            write!(f, "0x")?;
119        }
120
121        for byte in &self.0 {
122            write!(f, "{:02x}", byte)?;
123        }
124
125        Ok(())
126    }
127}
128
129impl fmt::UpperHex for AccountAddress {
130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131        if f.alternate() {
132            write!(f, "0x")?;
133        }
134
135        for byte in &self.0 {
136            write!(f, "{:02X}", byte)?;
137        }
138
139        Ok(())
140    }
141}
142
143impl From<[u8; AccountAddress::LENGTH]> for AccountAddress {
144    fn from(bytes: [u8; AccountAddress::LENGTH]) -> Self {
145        Self::new(bytes)
146    }
147}
148
149impl TryFrom<&[u8]> for AccountAddress {
150    type Error = AccountAddressParseError;
151
152    /// Tries to convert the provided byte array into Address.
153    fn try_from(bytes: &[u8]) -> Result<AccountAddress, AccountAddressParseError> {
154        Self::from_bytes(bytes)
155    }
156}
157
158impl TryFrom<Vec<u8>> for AccountAddress {
159    type Error = AccountAddressParseError;
160
161    /// Tries to convert the provided byte buffer into Address.
162    fn try_from(bytes: Vec<u8>) -> Result<AccountAddress, AccountAddressParseError> {
163        Self::from_bytes(bytes)
164    }
165}
166
167impl From<AccountAddress> for Vec<u8> {
168    fn from(addr: AccountAddress) -> Vec<u8> {
169        addr.0.to_vec()
170    }
171}
172
173impl From<&AccountAddress> for Vec<u8> {
174    fn from(addr: &AccountAddress) -> Vec<u8> {
175        addr.0.to_vec()
176    }
177}
178
179impl From<AccountAddress> for [u8; AccountAddress::LENGTH] {
180    fn from(addr: AccountAddress) -> Self {
181        addr.0
182    }
183}
184
185impl From<&AccountAddress> for [u8; AccountAddress::LENGTH] {
186    fn from(addr: &AccountAddress) -> Self {
187        addr.0
188    }
189}
190
191impl From<&AccountAddress> for String {
192    fn from(addr: &AccountAddress) -> String {
193        ::hex::encode(addr.as_ref())
194    }
195}
196
197impl TryFrom<String> for AccountAddress {
198    type Error = AccountAddressParseError;
199
200    fn try_from(s: String) -> Result<AccountAddress, AccountAddressParseError> {
201        Self::from_hex(s)
202    }
203}
204
205impl FromStr for AccountAddress {
206    type Err = AccountAddressParseError;
207
208    fn from_str(s: &str) -> Result<Self, AccountAddressParseError> {
209        Self::from_hex(s)
210    }
211}
212
213impl<'de> Deserialize<'de> for AccountAddress {
214    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
215    where
216        D: Deserializer<'de>,
217    {
218        if deserializer.is_human_readable() {
219            let s = <String>::deserialize(deserializer)?;
220            AccountAddress::from_hex(s).map_err(D::Error::custom)
221        } else {
222            // In order to preserve the Serde data model and help analysis tools,
223            // make sure to wrap our value in a container with the same name
224            // as the original type.
225            #[derive(::serde::Deserialize)]
226            #[serde(rename = "AccountAddress")]
227            struct Value([u8; AccountAddress::LENGTH]);
228
229            let value = Value::deserialize(deserializer)?;
230            Ok(AccountAddress::new(value.0))
231        }
232    }
233}
234
235impl Serialize for AccountAddress {
236    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
237    where
238        S: Serializer,
239    {
240        if serializer.is_human_readable() {
241            self.to_hex().serialize(serializer)
242        } else {
243            // See comment in deserialize.
244            serializer.serialize_newtype_struct("AccountAddress", &self.0)
245        }
246    }
247}
248
249#[derive(Clone, Copy, Debug)]
250pub struct AccountAddressParseError;
251
252impl fmt::Display for AccountAddressParseError {
253    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
254        write!(f, "unable to parse AccoutAddress")
255    }
256}
257
258impl std::error::Error for AccountAddressParseError {}
259
260#[cfg(test)]
261mod tests {
262    use super::AccountAddress;
263    use hex::FromHex;
264    use proptest::prelude::*;
265    use std::{
266        convert::{AsRef, TryFrom},
267        str::FromStr,
268    };
269
270    #[test]
271    fn test_display_impls() {
272        let hex = "ca843279e3427144cead5e4d5999a3d0";
273        let upper_hex = "CA843279E3427144CEAD5E4D5999A3D0";
274
275        let address = AccountAddress::from_hex(hex).unwrap();
276
277        assert_eq!(format!("{}", address), upper_hex);
278        assert_eq!(format!("{:?}", address), upper_hex);
279        assert_eq!(format!("{:X}", address), upper_hex);
280        assert_eq!(format!("{:x}", address), hex);
281
282        assert_eq!(format!("{:#x}", address), format!("0x{}", hex));
283        assert_eq!(format!("{:#X}", address), format!("0x{}", upper_hex));
284    }
285
286    #[test]
287    fn test_short_str_lossless() {
288        let address = AccountAddress::from_hex("00c0f1f95c5b1c5f0eda533eff269000").unwrap();
289
290        assert_eq!(
291            address.short_str_lossless(),
292            "c0f1f95c5b1c5f0eda533eff269000",
293        );
294    }
295
296    #[test]
297    fn test_short_str_lossless_zero() {
298        let address = AccountAddress::from_hex("00000000000000000000000000000000").unwrap();
299
300        assert_eq!(address.short_str_lossless(), "0");
301    }
302
303    #[test]
304    fn test_address() {
305        let hex = "ca843279e3427144cead5e4d5999a3d0";
306        let bytes = Vec::from_hex(hex).expect("You must provide a valid Hex format");
307
308        assert_eq!(
309            bytes.len(),
310            AccountAddress::LENGTH as usize,
311            "Address {:?} is not {}-bytes long. Addresses must be {} bytes",
312            bytes,
313            AccountAddress::LENGTH,
314            AccountAddress::LENGTH,
315        );
316
317        let address = AccountAddress::from_hex(hex).unwrap();
318
319        assert_eq!(address.as_ref().to_vec(), bytes);
320    }
321
322    #[test]
323    fn test_from_hex_literal() {
324        let hex_literal = "0x1";
325        let hex = "00000000000000000000000000000001";
326
327        let address_from_literal = AccountAddress::from_hex_literal(hex_literal).unwrap();
328        let address = AccountAddress::from_hex(hex).unwrap();
329
330        assert_eq!(address_from_literal, address);
331        assert_eq!(hex_literal, address.to_hex_literal());
332
333        // Missing '0x'
334        AccountAddress::from_hex_literal(hex).unwrap_err();
335        // Too long
336        AccountAddress::from_hex_literal("0x100000000000000000000000000000001").unwrap_err();
337    }
338
339    #[test]
340    fn test_ref() {
341        let address = AccountAddress::new([1u8; AccountAddress::LENGTH]);
342        let _: &[u8] = address.as_ref();
343    }
344
345    #[test]
346    fn test_address_from_proto_invalid_length() {
347        let bytes = vec![1; 123];
348        AccountAddress::from_bytes(bytes).unwrap_err();
349    }
350
351    #[test]
352    fn test_deserialize_from_json_value() {
353        let address = AccountAddress::random();
354        let json_value = serde_json::to_value(address).expect("serde_json::to_value fail.");
355        let address2: AccountAddress =
356            serde_json::from_value(json_value).expect("serde_json::from_value fail.");
357        assert_eq!(address, address2)
358    }
359
360    #[test]
361    fn test_serde_json() {
362        let hex = "ca843279e3427144cead5e4d5999a3d0";
363        let json_hex = "\"ca843279e3427144cead5e4d5999a3d0\"";
364
365        let address = AccountAddress::from_hex(hex).unwrap();
366
367        let json = serde_json::to_string(&address).unwrap();
368        let json_address: AccountAddress = serde_json::from_str(json_hex).unwrap();
369
370        assert_eq!(json, json_hex);
371        assert_eq!(address, json_address);
372    }
373
374    #[test]
375    fn test_address_from_empty_string() {
376        assert!(AccountAddress::try_from("".to_string()).is_err());
377        assert!(AccountAddress::from_str("").is_err());
378    }
379
380    proptest! {
381        #[test]
382        fn test_address_string_roundtrip(addr in any::<AccountAddress>()) {
383            let s = String::from(&addr);
384            let addr2 = AccountAddress::try_from(s).expect("roundtrip to string should work");
385            prop_assert_eq!(addr, addr2);
386        }
387
388        #[test]
389        fn test_address_protobuf_roundtrip(addr in any::<AccountAddress>()) {
390            let bytes = addr.to_vec();
391            prop_assert_eq!(bytes.clone(), addr.as_ref());
392            let addr2 = AccountAddress::try_from(&bytes[..]).unwrap();
393            prop_assert_eq!(addr, addr2);
394        }
395    }
396}