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 {}
265
266#[derive(
277 Copy,
278 Clone,
279 Debug,
280 Hash,
281 PartialEq,
282 Eq,
283 PartialOrd,
284 Ord,
285 Serialize,
286 Deserialize,
287 derive_more::Display,
288 derive_more::From,
289 derive_more::Into,
290)]
291#[serde(transparent)]
292pub struct StrictAddress(pub Address);
293
294impl FromStr for StrictAddress {
295 type Err = <Address_latest as FromStr>::Err;
296
297 fn from_str(s: &str) -> Result<Self, Self::Err> {
298 let fvm_addr = CurrentNetwork::get().parse_address(s)?;
299 Ok(StrictAddress(fvm_addr.into()))
300 }
301}
302
303impl From<StrictAddress> for Address_v3 {
309 fn from(other: StrictAddress) -> Self {
310 other.0.into()
311 }
312}
313
314impl From<StrictAddress> for Address_v4 {
315 fn from(other: StrictAddress) -> Self {
316 other.0.into()
317 }
318}
319
320impl From<&Address_v4> for Address {
321 fn from(other: &Address_v4) -> Self {
322 Address(*other)
323 }
324}
325
326impl From<&Address> for Address_v4 {
327 fn from(other: &Address) -> Self {
328 other.0
329 }
330}
331
332impl<'a> From<&'a Address> for &'a Address_v4 {
333 fn from(addr: &'a Address) -> Self {
334 &addr.0
335 }
336}
337
338impl From<&Address_v3> for Address {
339 fn from(other: &Address_v3) -> Self {
340 Address::from(
341 Address_v4::from_bytes(&other.to_bytes()).unwrap_or_else(|e| {
342 panic!("Couldn't convert from FVM3 address to FVM4 address: {other}, {e}")
343 }),
344 )
345 }
346}
347
348impl From<Address_v3> for Address {
349 fn from(other: Address_v3) -> Self {
350 (&other).into()
351 }
352}
353
354impl From<&Address_v2> for Address {
355 fn from(other: &Address_v2) -> Self {
356 Address::from(
357 Address_v4::from_bytes(&other.to_bytes()).unwrap_or_else(|e| {
358 panic!("Couldn't convert from FVM2 address to FVM4 address: {other}, {e}")
359 }),
360 )
361 }
362}
363
364impl From<Address_v2> for Address {
365 fn from(other: Address_v2) -> Self {
366 (&other).into()
367 }
368}
369
370impl From<&Address> for Address_v3 {
371 fn from(other: &Address) -> Self {
372 Address_v3::from_bytes(&other.to_bytes()).unwrap_or_else(|e| {
373 panic!("Couldn't convert from FVM4 address to FVM3 address: {other}, {e}")
374 })
375 }
376}
377
378impl From<Address> for Address_v3 {
379 fn from(other: Address) -> Self {
380 (&other).into()
381 }
382}
383
384impl From<&Address> for Address_v2 {
385 fn from(other: &Address) -> Self {
386 Address_v2::from_bytes(&other.to_bytes()).unwrap_or_else(|e| {
387 panic!("Couldn't convert from FVM4 address to FVM2 address: {other}, {e}")
388 })
389 }
390}
391
392impl From<Address> for Address_v2 {
393 fn from(other: Address) -> Address_v2 {
394 (&other).into()
395 }
396}
397
398#[cfg(test)]
399fn flip_network(input: Network) -> Network {
400 match input {
401 Network::Mainnet => Network::Testnet,
402 Network::Testnet => Network::Mainnet,
403 }
404}
405
406#[test]
407fn relaxed_address_parsing() {
408 assert!(Address::from_str("t01234").is_ok());
409 assert!(Address::from_str("f01234").is_ok());
410}
411
412#[test]
413fn strict_address_parsing() {
414 CurrentNetwork::with(Network::Mainnet, || {
415 assert!(StrictAddress::from_str("f01234").is_ok());
416 assert!(StrictAddress::from_str("t01234").is_err());
417 });
418 CurrentNetwork::with(Network::Testnet, || {
419 assert!(StrictAddress::from_str("f01234").is_err());
420 assert!(StrictAddress::from_str("t01234").is_ok());
421 });
422}
423
424#[test]
425fn set_with_network() {
426 let outer_network = CurrentNetwork::get();
427 let inner_network = flip_network(outer_network);
428 CurrentNetwork::with(inner_network, || {
429 assert_eq!(CurrentNetwork::get(), inner_network);
430 });
431 assert_eq!(outer_network, CurrentNetwork::get());
432}
433
434#[test]
435fn unwind_current_network_on_panic() {
436 let outer_network = CurrentNetwork::get();
437 let inner_network = flip_network(outer_network);
438 assert!(
439 std::panic::catch_unwind(|| {
440 CurrentNetwork::with(inner_network, || {
441 panic!("unwinding stack");
442 })
443 })
444 .is_err()
445 );
446 let new_outer_network = CurrentNetwork::get();
447 assert_eq!(outer_network, new_outer_network);
448}
449
450#[test]
451fn inherit_global_network() {
452 let outer_network = CurrentNetwork::get_global();
453 let inner_network = flip_network(outer_network);
454 CurrentNetwork::set_global(inner_network);
455 std::thread::spawn(move || {
456 assert_eq!(CurrentNetwork::get(), inner_network);
457 })
458 .join()
459 .unwrap();
460 CurrentNetwork::set_global(outer_network);
461}