ant_node/spawn/
network_spawner.rs1use crate::spawn::node_spawner::NodeSpawner;
10use crate::RunningNode;
11use ant_evm::{EvmNetwork, RewardsAddress};
12use libp2p::Multiaddr;
13use std::net::{IpAddr, Ipv4Addr, SocketAddr};
14use std::path::PathBuf;
15
16pub struct NetworkSpawner {
17 evm_network: EvmNetwork,
19 rewards_address: RewardsAddress,
21 local: bool,
25 no_upnp: bool,
27 root_dir: Option<PathBuf>,
29 size: usize,
31}
32
33impl NetworkSpawner {
34 pub fn new() -> Self {
44 Self {
45 evm_network: Default::default(),
46 rewards_address: Default::default(),
47 local: false,
48 no_upnp: false,
49 root_dir: None,
50 size: 5,
51 }
52 }
53
54 pub fn with_evm_network(mut self, evm_network: EvmNetwork) -> Self {
60 self.evm_network = evm_network;
61 self
62 }
63
64 pub fn with_rewards_address(mut self, rewards_address: RewardsAddress) -> Self {
70 self.rewards_address = rewards_address;
71 self
72 }
73
74 pub fn with_local(mut self, value: bool) -> Self {
81 self.local = value;
82 self
83 }
84
85 pub fn with_no_upnp(mut self, value: bool) -> Self {
91 self.no_upnp = value;
92 self
93 }
94
95 pub fn with_root_dir(mut self, root_dir: Option<PathBuf>) -> Self {
101 self.root_dir = root_dir;
102 self
103 }
104
105 pub fn with_size(mut self, size: usize) -> Self {
111 self.size = size;
112 self
113 }
114
115 pub async fn spawn(self) -> eyre::Result<RunningNetwork> {
122 spawn_network(
123 self.evm_network,
124 self.rewards_address,
125 self.local,
126 self.no_upnp,
127 self.root_dir,
128 self.size,
129 )
130 .await
131 }
132}
133
134impl Default for NetworkSpawner {
135 fn default() -> Self {
136 Self::new()
137 }
138}
139
140pub struct RunningNetwork {
141 running_nodes: Vec<RunningNode>,
142}
143
144impl RunningNetwork {
145 pub async fn bootstrap_peer(&self) -> Multiaddr {
147 self.running_nodes()
148 .first()
149 .expect("No nodes running, cannot get bootstrap peer")
150 .get_listen_addrs_with_peer_id()
151 .await
152 .expect("Could not get listen addresses for bootstrap peer")
153 .last()
154 .expect("Bootstrap peer has no listen addresses")
155 .clone()
156 }
157
158 pub fn running_nodes(&self) -> &Vec<RunningNode> {
160 &self.running_nodes
161 }
162
163 pub fn shutdown(self) {
165 for node in self.running_nodes.into_iter() {
166 node.shutdown();
167 }
168 }
169}
170
171async fn spawn_network(
172 evm_network: EvmNetwork,
173 rewards_address: RewardsAddress,
174 local: bool,
175 no_upnp: bool,
176 root_dir: Option<PathBuf>,
177 size: usize,
178) -> eyre::Result<RunningNetwork> {
179 let mut running_nodes: Vec<RunningNode> = vec![];
180
181 for i in 0..size {
182 let ip = match local {
183 true => IpAddr::V4(Ipv4Addr::LOCALHOST),
184 false => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
185 };
186
187 let socket_addr = SocketAddr::new(ip, 0);
188
189 let mut initial_peers: Vec<Multiaddr> = vec![];
191
192 for peer in running_nodes.iter() {
193 if let Ok(listen_addrs_with_peer_id) = peer.get_listen_addrs_with_peer_id().await {
194 initial_peers.extend(listen_addrs_with_peer_id);
195 }
196 }
197
198 let node = NodeSpawner::new()
199 .with_socket_addr(socket_addr)
200 .with_evm_network(evm_network.clone())
201 .with_rewards_address(rewards_address)
202 .with_initial_peers(initial_peers)
203 .with_local(local)
204 .with_no_upnp(no_upnp)
205 .with_root_dir(root_dir.clone())
206 .spawn()
207 .await?;
208
209 let listen_addrs = node.get_listen_addrs().await;
210
211 info!(
212 "Spawned node #{} with listen addresses: {:?}",
213 i + 1,
214 listen_addrs
215 );
216
217 running_nodes.push(node);
218 }
219
220 Ok(RunningNetwork { running_nodes })
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226 use std::time::Duration;
227 use tokio::time::sleep;
228
229 #[tokio::test(flavor = "multi_thread")]
230 async fn test_spawn_network() {
231 let network_size = 20;
232
233 let running_network = NetworkSpawner::new()
234 .with_evm_network(Default::default())
235 .with_local(true)
236 .with_no_upnp(true)
237 .with_size(network_size)
238 .spawn()
239 .await
240 .unwrap();
241
242 assert_eq!(running_network.running_nodes().len(), network_size);
243
244 sleep(Duration::from_secs(15)).await;
246
247 for node in running_network.running_nodes() {
249 let peers_in_routing_table = node
250 .get_swarm_local_state()
251 .await
252 .unwrap()
253 .peers_in_routing_table;
254
255 assert!(
256 peers_in_routing_table >= network_size - 2 && peers_in_routing_table < network_size
257 );
258 }
259
260 running_network.shutdown();
261 }
262}