cfx_addr/
consts.rs

1// Copyright 2021 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4//
5// Modification based on https://github.com/hlb8122/rust-bitcoincash-addr in MIT License.
6// A copy of the original license is included in LICENSE.rust-bitcoincash-addr.
7
8use super::errors::{DecodingError, EncodingError};
9
10use cfx_types::address_util::{self, AddressUtil};
11use std::{fmt, string::ToString};
12
13pub const CHARSET_SIZE: usize = 32;
14
15pub const RESERVED_BITS_MASK: u8 = 0xf8;
16
17// Because we use a different CHARSET than BCH, it's OK that we disregard all of
18// the BITCOIN type bits.
19//
20// // pub const TYPE_MASK: u8 = 0x78;
21// // pub const TYPE_BITCOIN_P2PKH: u8 = 0x00;
22// // pub const TYPE_BITCOIN_P2SH: u8 = 0x08;
23//
24// In Conflux we have so far only one type of account key format. So we try to
25// use the 4 type bits differently. In the future we may use them in some
26// special transaction scenarios. e.g. A payment code, an address linked to
27// off-chain or cross-chain mechanism.
28
29pub const SIZE_MASK: u8 = 0x07;
30pub const SIZE_160: u8 = 0x00;
31// In Conflux we only have 160 bits hash size, however we keep these unused
32// sizes for unit test and compatibility.
33pub const SIZE_192: u8 = 0x01;
34pub const SIZE_224: u8 = 0x02;
35pub const SIZE_256: u8 = 0x03;
36pub const SIZE_320: u8 = 0x04;
37pub const SIZE_384: u8 = 0x05;
38pub const SIZE_448: u8 = 0x06;
39pub const SIZE_512: u8 = 0x07;
40
41#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
42pub enum Network {
43    /// Main network.
44    Main,
45    /// Test network.
46    Test,
47    /// Specific Network Id.
48    Id(u64),
49}
50
51// Prefixes
52const MAINNET_PREFIX: &str = "cfx";
53const TESTNET_PREFIX: &str = "cfxtest";
54const NETWORK_ID_PREFIX: &str = "net";
55// These two network_ids are reserved.
56const RESERVED_NETWORK_IDS: [u64; 2] = [1, 1029];
57
58#[derive(Debug, PartialEq, Eq, Clone)]
59pub enum AddressType {
60    Builtin,
61    Contract,
62    Null,
63    User,
64    Unknown,
65}
66
67impl fmt::Display for Network {
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        match self.to_prefix() {
70            Err(EncodingError::InvalidNetworkId(network_id)) => {
71                write!(f, "invalid network prefix net{}", network_id)
72            }
73            Err(_) => unreachable!(),
74            Ok(prefix) => write!(f, "{}", prefix),
75        }
76    }
77}
78
79impl Network {
80    pub fn to_prefix(&self) -> Result<String, EncodingError> {
81        match self {
82            Network::Main => Ok(MAINNET_PREFIX.into()),
83            Network::Test => Ok(TESTNET_PREFIX.into()),
84            Network::Id(network_id) => {
85                if RESERVED_NETWORK_IDS.contains(network_id) {
86                    Err(EncodingError::InvalidNetworkId(*network_id))
87                } else {
88                    Ok(format!("net{}", network_id))
89                }
90            }
91        }
92    }
93
94    pub fn from_prefix(prefix: &str) -> Result<Self, DecodingError> {
95        match prefix {
96            MAINNET_PREFIX => Ok(Network::Main),
97            TESTNET_PREFIX => Ok(Network::Test),
98            _ => {
99                let maybe_network_id = if !prefix.starts_with(NETWORK_ID_PREFIX)
100                {
101                    None
102                } else {
103                    match prefix[NETWORK_ID_PREFIX.len()..].parse::<u64>() {
104                        Err(_) => None,
105                        Ok(network_id) => {
106                            // Check if network_id is valid.
107                            if RESERVED_NETWORK_IDS.contains(&network_id) {
108                                None
109                            } else {
110                                Some(network_id)
111                            }
112                        }
113                    }
114                };
115
116                match maybe_network_id {
117                    None => {
118                        Err(DecodingError::InvalidPrefix(prefix.to_string()))
119                    }
120                    Some(network_id) => Ok(Network::Id(network_id)),
121                }
122            }
123        }
124    }
125}
126
127impl AddressType {
128    const BUILTIN: &'static str = "builtin";
129    const CONTRACT: &'static str = "contract";
130    const NULL: &'static str = "null";
131    const UNKNOWN: &'static str = "unknown";
132    const USER: &'static str = "user";
133
134    pub fn parse(text: &str) -> Result<Self, DecodingError> {
135        if text == Self::BUILTIN {
136            Ok(Self::Builtin)
137        } else if text == Self::CONTRACT {
138            Ok(Self::Contract)
139        } else if text == Self::NULL {
140            Ok(Self::Null)
141        } else if text == Self::USER {
142            Ok(Self::User)
143        } else {
144            Ok(Self::Unknown)
145        }
146    }
147
148    pub fn from_address<T: AddressUtil>(
149        address_hex: &T,
150    ) -> Result<Self, EncodingError> {
151        match address_hex.address_type_bits() {
152            address_util::TYPE_BITS_BUILTIN => {
153                if address_hex.is_null_address() {
154                    Ok(Self::Null)
155                } else {
156                    Ok(Self::Builtin)
157                }
158            }
159            address_util::TYPE_BITS_CONTRACT => Ok(Self::Contract),
160            address_util::TYPE_BITS_USER_ACCOUNT => Ok(Self::User),
161            _ => Ok(Self::Unknown),
162        }
163    }
164
165    pub fn to_str(&self) -> &'static str {
166        match self {
167            Self::Builtin => Self::BUILTIN,
168            Self::Contract => Self::CONTRACT,
169            Self::Null => Self::NULL,
170            Self::User => Self::USER,
171            Self::Unknown => Self::UNKNOWN,
172        }
173    }
174}
175
176impl ToString for AddressType {
177    fn to_string(&self) -> String { self.to_str().into() }
178}