forest/rpc/methods/f3/
util.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use super::*;
5use std::sync::LazyLock;
6
7const F3_PERMANENT_PARTICIPATING_MINER_IDS_ENV_KEY: &str =
8    "FOREST_F3_PERMANENT_PARTICIPATING_MINER_ADDRESSES";
9
10pub static F3_PERMANENT_PARTICIPATING_MINER_IDS: LazyLock<Option<HashSet<u64>>> =
11    LazyLock::new(get_f3_permanent_participating_miner_ids);
12
13/// loads f3 permanent participating miner IDs.
14/// Note that this environment variable should only be used for testing purpose.
15fn get_f3_permanent_participating_miner_ids() -> Option<HashSet<u64>> {
16    if let Ok(permanent_addrs) = std::env::var(F3_PERMANENT_PARTICIPATING_MINER_IDS_ENV_KEY) {
17        let mut ids = HashSet::default();
18        for addr_str in permanent_addrs.split(",") {
19            let Ok(addr) = Address::from_str(addr_str.trim()) else {
20                tracing::warn!(
21                    "Failed to parse miner address {addr_str} set in {F3_PERMANENT_PARTICIPATING_MINER_IDS_ENV_KEY}"
22                );
23                continue;
24            };
25            let Ok(id) = addr.id() else {
26                tracing::warn!(
27                    "miner address {addr_str} set in {F3_PERMANENT_PARTICIPATING_MINER_IDS_ENV_KEY} is not an id address"
28                );
29                continue;
30            };
31            ids.insert(id);
32        }
33        if !ids.is_empty() { Some(ids) } else { None }
34    } else {
35        None
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn test_get_f3_permanent_participating_miner_ids() {
45        unsafe {
46            // empty
47            std::env::set_var(F3_PERMANENT_PARTICIPATING_MINER_IDS_ENV_KEY, "");
48            assert!(get_f3_permanent_participating_miner_ids().is_none());
49
50            // 1 valid address
51            std::env::set_var(F3_PERMANENT_PARTICIPATING_MINER_IDS_ENV_KEY, "t01000");
52            assert_eq!(
53                get_f3_permanent_participating_miner_ids(),
54                Some(HashSet::from_iter([1000])),
55            );
56
57            // 1 invalid address
58            std::env::set_var(F3_PERMANENT_PARTICIPATING_MINER_IDS_ENV_KEY, "tf1000");
59            assert!(get_f3_permanent_participating_miner_ids().is_none());
60
61            // 1 bls address
62            std::env::set_var(
63                F3_PERMANENT_PARTICIPATING_MINER_IDS_ENV_KEY,
64                "t3sw466j35hqjbch5x7tcr7ona6idsgzypoturfci2ajqsfrrwhp7ty3ythtd7x646adaidnvxpdr5b2ftcciq",
65            );
66            assert!(get_f3_permanent_participating_miner_ids().is_none());
67
68            // 1 valid address and 1 invalid address with extra whitespaces
69            std::env::set_var(
70                F3_PERMANENT_PARTICIPATING_MINER_IDS_ENV_KEY,
71                "t01000, t3sw466j35hqjbch5x7tcr7ona6idsgzypoturfci2ajqsfrrwhp7ty3ythtd7x646adaidnvxpdr5b2ftcciq, ",
72            );
73            assert_eq!(
74                get_f3_permanent_participating_miner_ids(),
75                Some(HashSet::from_iter([1000])),
76            );
77        }
78    }
79}