1use std::{fmt::Display, str::FromStr};
5
6use data_encoding::Encoding;
7use data_encoding_macro::new_encoding;
8use fvm_shared2::address::Address as Address_v2;
9use fvm_shared3::address::Address as Address_v3;
10use fvm_shared4::address::Address as Address_v4;
11use fvm_shared4::address::Address as Address_latest;
12pub use fvm_shared4::address::{Error, Network, PAYLOAD_HASH_LEN, Payload, Protocol};
13use get_size2::GetSize;
14use integer_encoding::VarInt;
15use num_traits::FromPrimitive;
16use serde::{Deserialize, Serialize};
17use std::sync::{
18 LazyLock,
19 atomic::{AtomicU8, Ordering},
20};
21
22pub static ZERO_ADDRESS: LazyLock<Address> = LazyLock::new(|| {
27 Network::Mainnet
28 .parse_address(
29 "f3yaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaby2smx7a",
30 )
31 .unwrap()
32 .into()
33});
34
35static GLOBAL_NETWORK: AtomicU8 = AtomicU8::new(Network::Mainnet as u8);
36
37thread_local! {
38 static LOCAL_NETWORK: AtomicU8 = AtomicU8::new(GLOBAL_NETWORK.load(Ordering::Acquire));
40}
41
42pub struct CurrentNetwork;
52impl CurrentNetwork {
53 pub fn get() -> Network {
54 FromPrimitive::from_u8(LOCAL_NETWORK.with(|ident| ident.load(Ordering::Acquire)))
55 .unwrap_or(Network::Mainnet)
56 }
57
58 pub fn set(network: Network) {
59 LOCAL_NETWORK.with(|ident| ident.store(network as u8, Ordering::Release));
60 }
61
62 pub fn set_global(network: Network) {
63 GLOBAL_NETWORK.store(network as u8, Ordering::Release);
64 CurrentNetwork::set(network);
65 }
66
67 #[cfg(test)]
68 pub fn with<X>(network: Network, cb: impl FnOnce() -> X) -> X {
69 let guard = NetworkGuard::new(network);
70 let result = cb();
71 drop(guard);
72 result
73 }
74
75 #[cfg(test)]
76 fn get_global() -> Network {
77 FromPrimitive::from_u8(GLOBAL_NETWORK.load(Ordering::Acquire)).unwrap_or(Network::Mainnet)
78 }
79}
80
81#[cfg(test)]
82struct NetworkGuard(Network);
83#[cfg(test)]
84mod network_guard_impl {
85 use super::*;
86
87 impl NetworkGuard {
88 pub fn new(new_network: Network) -> Self {
89 let previous_network = CurrentNetwork::get();
90 CurrentNetwork::set(new_network);
91 NetworkGuard(previous_network)
92 }
93 }
94
95 impl Drop for NetworkGuard {
96 fn drop(&mut self) {
97 CurrentNetwork::set(self.0);
98 }
99 }
100}
101
102#[derive(
113 Copy,
114 Clone,
115 Debug,
116 Hash,
117 PartialEq,
118 Eq,
119 PartialOrd,
120 Ord,
121 Serialize,
122 Deserialize,
123 derive_more::Deref,
124 derive_more::DerefMut,
125 derive_more::From,
126 derive_more::Into,
127)]
128#[serde(transparent)]
129#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
130pub struct Address(Address_latest);
131
132impl Default for Address {
133 fn default() -> Self {
134 Address(Address_latest::new_id(0))
135 }
136}
137
138impl Address {
139 pub const SYSTEM_ACTOR: Address = Address::new_id(0);
140 pub const INIT_ACTOR: Address = Address::new_id(1);
141 pub const REWARD_ACTOR: Address = Address::new_id(2);
142 pub const CRON_ACTOR: Address = Address::new_id(3);
143 pub const POWER_ACTOR: Address = Address::new_id(4);
144 pub const MARKET_ACTOR: Address = Address::new_id(5);
145 pub const VERIFIED_REGISTRY_ACTOR: Address = Address::new_id(6);
146 pub const DATACAP_TOKEN_ACTOR: Address = Address::new_id(7);
147 pub const ETHEREUM_ACCOUNT_MANAGER_ACTOR: Address = Address::new_id(10);
148 pub const SAFT_ACTOR: Address = Address::new_id(122);
149 pub const RESERVE_ACTOR: Address = Address::new_id(90);
150 pub const CHAOS_ACTOR: Address = Address::new_id(98);
151 pub const BURNT_FUNDS_ACTOR: Address = Address::new_id(99);
152
153 pub const fn new_id(id: u64) -> Self {
154 Address(Address_latest::new_id(id))
155 }
156
157 pub fn new_actor(data: &[u8]) -> Self {
158 Address(Address_latest::new_actor(data))
159 }
160
161 pub fn new_bls(pubkey: &[u8]) -> Result<Self, Error> {
162 Address_latest::new_bls(pubkey).map(Address::from)
163 }
164
165 pub fn new_secp256k1(pubkey: &[u8]) -> Result<Self, Error> {
166 Address_latest::new_secp256k1(pubkey).map(Address::from)
167 }
168
169 pub fn new_delegated(ns: u64, subaddress: &[u8]) -> Result<Self, Error> {
170 Ok(Self(Address_latest::new_delegated(ns, subaddress)?))
171 }
172
173 pub fn protocol(&self) -> Protocol {
174 self.0.protocol()
175 }
176
177 pub fn into_payload(self) -> Payload {
178 self.0.into_payload()
179 }
180
181 pub fn from_bytes(bz: &[u8]) -> Result<Self, Error> {
182 Address_latest::from_bytes(bz).map(Address)
183 }
184}
185
186impl FromStr for Address {
187 type Err = <Address_latest as FromStr>::Err;
188
189 fn from_str(s: &str) -> Result<Self, Self::Err> {
190 Network::Testnet
191 .parse_address(s)
192 .or_else(|_| Network::Mainnet.parse_address(s))
193 .map(Address::from)
194 }
195}
196
197const ADDRESS_ENCODER: Encoding = new_encoding! {
199 symbols: "abcdefghijklmnopqrstuvwxyz234567",
200 padding: None,
201};
202
203impl Display for Address {
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 use fvm_shared4::address::CHECKSUM_HASH_LEN;
206 const MAINNET_PREFIX: &str = "f";
207 const TESTNET_PREFIX: &str = "t";
208
209 let protocol = self.protocol();
210
211 let prefix = if matches!(CurrentNetwork::get(), Network::Mainnet) {
212 MAINNET_PREFIX
213 } else {
214 TESTNET_PREFIX
215 };
216
217 write!(f, "{prefix}{protocol}")?;
219
220 fn write_payload(
221 f: &mut std::fmt::Formatter<'_>,
222 protocol: Protocol,
223 prefix: Option<&[u8]>,
224 data: &[u8],
225 ) -> std::fmt::Result {
226 let mut hasher = blake2b_simd::Params::new()
227 .hash_length(CHECKSUM_HASH_LEN)
228 .to_state();
229 hasher.update(&[protocol as u8]);
230 if let Some(prefix) = prefix {
231 hasher.update(prefix);
232 }
233 hasher.update(data);
234
235 let mut buf = Vec::with_capacity(data.len() + CHECKSUM_HASH_LEN);
236 buf.extend(data);
237 buf.extend(hasher.finalize().as_bytes());
238
239 f.write_str(&ADDRESS_ENCODER.encode(&buf))
240 }
241
242 match self.payload() {
243 Payload::ID(id) => write!(f, "{id}"),
244 Payload::Secp256k1(data) | Payload::Actor(data) => {
245 write_payload(f, protocol, None, data)
246 }
247 Payload::BLS(data) => write_payload(f, protocol, None, data),
248 Payload::Delegated(addr) => {
249 write!(f, "{}f", addr.namespace())?;
250 write_payload(
251 f,
252 protocol,
253 Some(&addr.namespace().encode_var_vec()),
254 addr.subaddress(),
255 )
256 }
257 }
258 }
259}
260
261impl GetSize for Address {
262 fn get_heap_size(&self) -> usize {
263 0 }
265}
266
267#[derive(
278 Copy,
279 Clone,
280 Debug,
281 Hash,
282 PartialEq,
283 Eq,
284 PartialOrd,
285 Ord,
286 Serialize,
287 Deserialize,
288 derive_more::Display,
289 derive_more::From,
290 derive_more::Into,
291)]
292#[serde(transparent)]
293pub struct StrictAddress(pub Address);
294
295impl FromStr for StrictAddress {
296 type Err = <Address_latest as FromStr>::Err;
297
298 fn from_str(s: &str) -> Result<Self, Self::Err> {
299 let fvm_addr = CurrentNetwork::get().parse_address(s)?;
300 Ok(StrictAddress(fvm_addr.into()))
301 }
302}
303
304impl From<StrictAddress> for Address_v3 {
310 fn from(other: StrictAddress) -> Self {
311 other.0.into()
312 }
313}
314
315impl From<StrictAddress> for Address_v4 {
316 fn from(other: StrictAddress) -> Self {
317 other.0.into()
318 }
319}
320
321impl From<&Address_v4> for Address {
322 fn from(other: &Address_v4) -> Self {
323 Address(*other)
324 }
325}
326
327impl From<&Address> for Address_v4 {
328 fn from(other: &Address) -> Self {
329 other.0
330 }
331}
332
333impl<'a> From<&'a Address> for &'a Address_v4 {
334 fn from(addr: &'a Address) -> Self {
335 &addr.0
336 }
337}
338
339impl From<&Address_v3> for Address {
340 fn from(other: &Address_v3) -> Self {
341 Address::from(
342 Address_v4::from_bytes(&other.to_bytes()).unwrap_or_else(|e| {
343 panic!("Couldn't convert from FVM3 address to FVM4 address: {other}, {e}")
344 }),
345 )
346 }
347}
348
349impl From<Address_v3> for Address {
350 fn from(other: Address_v3) -> Self {
351 (&other).into()
352 }
353}
354
355impl From<&Address_v2> for Address {
356 fn from(other: &Address_v2) -> Self {
357 Address::from(
358 Address_v4::from_bytes(&other.to_bytes()).unwrap_or_else(|e| {
359 panic!("Couldn't convert from FVM2 address to FVM4 address: {other}, {e}")
360 }),
361 )
362 }
363}
364
365impl From<Address_v2> for Address {
366 fn from(other: Address_v2) -> Self {
367 (&other).into()
368 }
369}
370
371impl From<&Address> for Address_v3 {
372 fn from(other: &Address) -> Self {
373 Address_v3::from_bytes(&other.to_bytes()).unwrap_or_else(|e| {
374 panic!("Couldn't convert from FVM4 address to FVM3 address: {other}, {e}")
375 })
376 }
377}
378
379impl From<Address> for Address_v3 {
380 fn from(other: Address) -> Self {
381 (&other).into()
382 }
383}
384
385impl From<&Address> for Address_v2 {
386 fn from(other: &Address) -> Self {
387 Address_v2::from_bytes(&other.to_bytes()).unwrap_or_else(|e| {
388 panic!("Couldn't convert from FVM4 address to FVM2 address: {other}, {e}")
389 })
390 }
391}
392
393impl From<Address> for Address_v2 {
394 fn from(other: Address) -> Address_v2 {
395 (&other).into()
396 }
397}
398
399#[cfg(test)]
400fn flip_network(input: Network) -> Network {
401 match input {
402 Network::Mainnet => Network::Testnet,
403 Network::Testnet => Network::Mainnet,
404 }
405}
406
407#[test]
408fn relaxed_address_parsing() {
409 assert!(Address::from_str("t01234").is_ok());
410 assert!(Address::from_str("f01234").is_ok());
411}
412
413#[test]
414fn strict_address_parsing() {
415 CurrentNetwork::with(Network::Mainnet, || {
416 assert!(StrictAddress::from_str("f01234").is_ok());
417 assert!(StrictAddress::from_str("t01234").is_err());
418 });
419 CurrentNetwork::with(Network::Testnet, || {
420 assert!(StrictAddress::from_str("f01234").is_err());
421 assert!(StrictAddress::from_str("t01234").is_ok());
422 });
423}
424
425#[test]
426fn set_with_network() {
427 let outer_network = CurrentNetwork::get();
428 let inner_network = flip_network(outer_network);
429 CurrentNetwork::with(inner_network, || {
430 assert_eq!(CurrentNetwork::get(), inner_network);
431 });
432 assert_eq!(outer_network, CurrentNetwork::get());
433}
434
435#[test]
436fn unwind_current_network_on_panic() {
437 let outer_network = CurrentNetwork::get();
438 let inner_network = flip_network(outer_network);
439 assert!(
440 std::panic::catch_unwind(|| {
441 CurrentNetwork::with(inner_network, || {
442 panic!("unwinding stack");
443 })
444 })
445 .is_err()
446 );
447 let new_outer_network = CurrentNetwork::get();
448 assert_eq!(outer_network, new_outer_network);
449}
450
451#[test]
452fn inherit_global_network() {
453 let outer_network = CurrentNetwork::get_global();
454 let inner_network = flip_network(outer_network);
455 CurrentNetwork::set_global(inner_network);
456 std::thread::spawn(move || {
457 assert_eq!(CurrentNetwork::get(), inner_network);
458 })
459 .join()
460 .unwrap();
461 CurrentNetwork::set_global(outer_network);
462}