1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use std::{collections::HashMap, fs};
use tentacle::multiaddr::Multiaddr;
use crate::{
blockchain::Network,
error::{Error, Result},
};
lazy_static::lazy_static! {
static ref BOOTNODES: BootNodes = BootNodes::initialize().unwrap();
}
pub struct BootNodes(HashMap<Network, Vec<Multiaddr>>);
fn load_raw_bootnodes_from_file(chain: &str) -> Result<Vec<String>> {
let out_dir = env!("OUT_DIR");
let file_path = format!("{}/{}/ckb.toml", out_dir, chain);
fs::read_to_string(&file_path)?
.parse::<toml::Value>()?
.get("network")
.ok_or_else(|| Error::Unreachable(format!("`network` for chain {} was not found", chain)))?
.get("bootnodes")
.ok_or_else(|| {
Error::Unreachable(format!(
"`network::bootnodes` for chain {} was not found",
chain
))
})?
.as_array()
.ok_or_else(|| {
Error::Unreachable(format!(
"`network::bootnodes` for chain {} was not array",
chain
))
})?
.iter()
.map(|v| {
v.as_str().map(ToOwned::to_owned).ok_or_else(|| {
Error::Unreachable(format!(
"at least one item in `network::bootnodes` for chain {} was not string",
chain
))
})
})
.collect::<Result<Vec<_>>>()
}
fn parse_multiaddrs(multiaddrs_str: &[String]) -> Result<Vec<Multiaddr>> {
multiaddrs_str
.iter()
.map(|addr| {
addr.parse()
.map_err(|_| Error::Unknown("bootnode", (*addr).to_owned()))
})
.collect()
}
impl BootNodes {
pub fn read() -> &'static Self {
&BOOTNODES
}
fn initialize() -> Result<Self> {
let mut bootnodes = Self(HashMap::new());
bootnodes.initialize_network(Network::Mainnet)?;
bootnodes.initialize_network(Network::Testnet)?;
bootnodes.initialize_network(Network::Staging)?;
bootnodes.initialize_network(Network::Develop)?;
Ok(bootnodes)
}
fn initialize_network(&mut self, network: Network) -> Result<()> {
let chain = network.to_string().to_lowercase();
let raw_bootnodes = load_raw_bootnodes_from_file(&chain)?;
self.0
.insert(network, parse_multiaddrs(&raw_bootnodes[..])?);
Ok(())
}
pub fn lookup(&self, network: Network) -> &[Multiaddr] {
self.0.get(&network).unwrap()
}
}