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