ant_bootstrap/
initial_peers.rs1use crate::{
10 craft_valid_multiaddr, craft_valid_multiaddr_from_str,
11 error::{Error, Result},
12 BootstrapCacheConfig, BootstrapCacheStore, ContactsFetcher,
13};
14use ant_protocol::version::{get_network_id, ALPHANET_ID, MAINNET_ID};
15use clap::Args;
16use libp2p::Multiaddr;
17use serde::{Deserialize, Serialize};
18use std::path::PathBuf;
19use url::Url;
20
21pub const ANT_PEERS_ENV: &str = "ANT_PEERS";
23
24#[derive(Args, Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
27pub struct InitialPeersConfig {
28 #[clap(long, default_value = "false")]
33 pub first: bool,
34 #[clap(
45 long = "peer",
46 value_name = "multiaddr",
47 value_delimiter = ',',
48 conflicts_with = "first"
49 )]
50 pub addrs: Vec<Multiaddr>,
51 #[clap(long, conflicts_with = "first", value_delimiter = ',')]
56 pub network_contacts_url: Vec<String>,
57 #[clap(long, conflicts_with = "network_contacts_url", default_value = "false")]
59 pub local: bool,
60 #[clap(long, default_value = "false")]
62 pub ignore_cache: bool,
63 #[clap(long)]
72 pub bootstrap_cache_dir: Option<PathBuf>,
73}
74
75impl InitialPeersConfig {
76 pub async fn get_bootstrap_addr(
78 &self,
79 config: Option<BootstrapCacheConfig>,
80 count: Option<usize>,
81 ) -> Result<Vec<Multiaddr>> {
82 if self.first {
84 info!("First node in network, no initial bootstrap peers");
85 return Ok(vec![]);
86 }
87
88 let mut bootstrap_addresses = vec![];
89
90 bootstrap_addresses.extend(Self::read_bootstrap_addr_from_env());
92
93 if !bootstrap_addresses.is_empty() {
94 info!(
95 "Found {} bootstrap addresses from environment variable",
96 bootstrap_addresses.len()
97 );
98 return Ok(bootstrap_addresses);
99 }
100
101 for addr in &self.addrs {
103 if let Some(addr) = craft_valid_multiaddr(addr, false) {
104 info!("Adding addr from arguments: {addr}");
105 bootstrap_addresses.push(addr);
106 } else {
107 warn!("Invalid multiaddress format from arguments: {addr}");
108 }
109 }
110
111 if let Some(count) = count {
112 if bootstrap_addresses.len() >= count {
113 bootstrap_addresses.truncate(count);
114 info!(
115 "Found {} bootstrap addresses. Returning early.",
116 bootstrap_addresses.len()
117 );
118 return Ok(bootstrap_addresses);
119 }
120 }
121
122 if !self.ignore_cache {
124 let cfg = if let Some(config) = config {
125 Some(config)
126 } else {
127 BootstrapCacheConfig::new(self.local)
128 .inspect_err(|err| {
129 error!("Failed to create cache config: {err}",);
130 })
131 .ok()
132 };
133 if let Some(cfg) = cfg {
134 if let Ok(data) = BootstrapCacheStore::load_cache_data(&cfg) {
135 bootstrap_addresses.extend(data.get_all_addrs().cloned());
136
137 if let Some(count) = count {
138 if bootstrap_addresses.len() >= count {
139 bootstrap_addresses.truncate(count);
140 info!(
141 "Found {} bootstrap addresses. Returning early.",
142 bootstrap_addresses.len()
143 );
144 return Ok(bootstrap_addresses);
145 }
146 }
147 }
148 }
149 } else {
150 info!("Ignoring cache, not loading bootstrap addresses from cache");
151 }
152
153 if !self.local && !self.network_contacts_url.is_empty() {
155 info!(
156 "Fetching bootstrap address from network contacts URLs: {:?}",
157 self.network_contacts_url
158 );
159 let addrs = self
160 .network_contacts_url
161 .iter()
162 .map(|url| url.parse::<Url>().map_err(|_| Error::FailedToParseUrl))
163 .collect::<Result<Vec<Url>>>()?;
164 let mut contacts_fetcher = ContactsFetcher::with_endpoints(addrs)?;
165 if let Some(count) = count {
166 contacts_fetcher.set_max_addrs(count);
167 }
168 let addrs = contacts_fetcher.fetch_bootstrap_addresses().await?;
169 bootstrap_addresses.extend(addrs);
170
171 if let Some(count) = count {
172 if bootstrap_addresses.len() >= count {
173 bootstrap_addresses.truncate(count);
174 info!(
175 "Found {} bootstrap addresses. Returning early.",
176 bootstrap_addresses.len()
177 );
178 return Ok(bootstrap_addresses);
179 }
180 }
181 }
182
183 if !self.local && get_network_id() == MAINNET_ID {
184 let mut contacts_fetcher = ContactsFetcher::with_mainnet_endpoints()?;
185 if let Some(count) = count {
186 contacts_fetcher.set_max_addrs(count);
187 }
188 info!("Fetching bootstrap address from mainnet contacts");
189 let addrs = contacts_fetcher.fetch_bootstrap_addresses().await?;
190 bootstrap_addresses.extend(addrs);
191 } else if !self.local && get_network_id() == ALPHANET_ID {
192 let mut contacts_fetcher = ContactsFetcher::with_alphanet_endpoints()?;
193 if let Some(count) = count {
194 contacts_fetcher.set_max_addrs(count);
195 }
196 info!("Fetching bootstrap address from alphanet contacts");
197 let addrs = contacts_fetcher.fetch_bootstrap_addresses().await?;
198 bootstrap_addresses.extend(addrs);
199 }
200
201 if !bootstrap_addresses.is_empty() {
202 if let Some(count) = count {
203 bootstrap_addresses.truncate(count);
204 }
205 info!(
206 "Found {} bootstrap addresses. Returning early.",
207 bootstrap_addresses.len()
208 );
209 Ok(bootstrap_addresses)
210 } else {
211 error!("No initial bootstrap peers found through any means");
212 Err(Error::NoBootstrapPeersFound)
213 }
214 }
215
216 pub fn read_bootstrap_addr_from_env() -> Vec<Multiaddr> {
217 let mut bootstrap_addresses = Vec::new();
218 if let Ok(addrs) = std::env::var(ANT_PEERS_ENV) {
220 for addr_str in addrs.split(',') {
221 if let Some(addr) = craft_valid_multiaddr_from_str(addr_str, false) {
222 info!("Adding addr from environment variable: {addr}");
223 bootstrap_addresses.push(addr);
224 } else {
225 warn!("Invalid multiaddress format from environment variable: {addr_str}");
226 }
227 }
228 }
229 bootstrap_addresses
230 }
231}