iota_aws_orchestrator/protocol/
iota.rs1use std::{
6 fmt::{Debug, Display},
7 path::PathBuf,
8 str::FromStr,
9};
10
11use iota_swarm_config::genesis_config::GenesisConfig;
12use iota_types::{base_types::IotaAddress, multiaddr::Multiaddr};
13use serde::{Deserialize, Serialize};
14
15use super::{ProtocolCommands, ProtocolMetrics};
16use crate::{
17 benchmark::{BenchmarkParameters, BenchmarkType},
18 client::Instance,
19 display,
20 settings::Settings,
21};
22
23#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct IotaBenchmarkType {
25 shared_objects_ratio: u16,
28}
29
30impl Debug for IotaBenchmarkType {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 write!(f, "{}", self.shared_objects_ratio)
33 }
34}
35
36impl Display for IotaBenchmarkType {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 write!(f, "{}% shared objects", self.shared_objects_ratio)
39 }
40}
41
42impl FromStr for IotaBenchmarkType {
43 type Err = std::num::ParseIntError;
44
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 Ok(Self {
47 shared_objects_ratio: s.parse::<u16>()?.min(100),
48 })
49 }
50}
51
52impl BenchmarkType for IotaBenchmarkType {}
53
54pub struct IotaProtocol {
56 working_dir: PathBuf,
57}
58
59impl ProtocolCommands<IotaBenchmarkType> for IotaProtocol {
60 fn protocol_dependencies(&self) -> Vec<&'static str> {
61 vec![
62 "sudo apt-get -y install curl git-all clang cmake gcc libssl-dev pkg-config libclang-dev",
64 "sudo apt-get -y install libpq-dev",
66 ]
67 }
68
69 fn db_directories(&self) -> Vec<PathBuf> {
70 let authorities_db = [&self.working_dir, &iota_config::AUTHORITIES_DB_NAME.into()]
71 .iter()
72 .collect();
73 let consensus_db = [&self.working_dir, &iota_config::CONSENSUS_DB_NAME.into()]
74 .iter()
75 .collect();
76 vec![authorities_db, consensus_db]
77 }
78
79 fn genesis_command<'a, I>(
80 &self,
81 instances: I,
82 parameters: &BenchmarkParameters<IotaBenchmarkType>,
83 ) -> String
84 where
85 I: Iterator<Item = &'a Instance>,
86 {
87 let working_dir = self.working_dir.display();
88 let ips = instances
89 .map(|x| {
90 match parameters.use_internal_ip_address {
91 true => x.private_ip,
92 false => x.main_ip,
93 }
94 .to_string()
95 })
96 .collect::<Vec<_>>()
97 .join(" ");
98 let genesis = [
99 "cargo run --release --bin iota --",
100 "genesis",
101 &format!("-f --working-dir {working_dir} --benchmark-ips {ips}"),
102 ]
103 .join(" ");
104
105 [
106 &format!("mkdir -p {working_dir}"),
107 "source $HOME/.cargo/env",
108 &genesis,
109 ]
110 .join(" && ")
111 }
112
113 fn monitor_command<I>(&self, _instances: I) -> Vec<(Instance, String)>
114 where
115 I: IntoIterator<Item = Instance>,
116 {
117 vec![]
127 }
128
129 fn node_command<I>(
130 &self,
131 instances: I,
132 _parameters: &BenchmarkParameters<IotaBenchmarkType>,
133 ) -> Vec<(Instance, String)>
134 where
135 I: IntoIterator<Item = Instance>,
136 {
137 let working_dir = self.working_dir.clone();
138 let network_addresses = Self::resolve_network_addresses(instances);
139
140 network_addresses
141 .into_iter()
142 .enumerate()
143 .map(|(i, (instance, network_address))| {
144 let validator_config =
145 iota_config::validator_config_file(network_address.clone(), i);
146 let config_path: PathBuf = working_dir.join(validator_config);
147
148 let run = [
149 "cargo run --release --bin iota-node --",
150 &format!(
151 "--config-path {} --listen-address {}",
152 config_path.display(),
153 network_address.with_zero_ip()
154 ),
155 ]
156 .join(" ");
157 let command = ["source $HOME/.cargo/env", &run].join(" && ");
158
159 display::action(format!("\n Command ({i}): {command}"));
160
161 (instance, command)
162 })
163 .collect()
164 }
165
166 fn client_command<I>(
167 &self,
168 instances: I,
169 parameters: &BenchmarkParameters<IotaBenchmarkType>,
170 ) -> Vec<(Instance, String)>
171 where
172 I: IntoIterator<Item = Instance>,
173 {
174 let genesis_path: PathBuf = [
175 &self.working_dir,
176 &iota_config::IOTA_GENESIS_FILENAME.into(),
177 ]
178 .iter()
179 .collect();
180 let keystore_path: PathBuf = [
181 &self.working_dir,
182 &iota_config::IOTA_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME.into(),
183 ]
184 .iter()
185 .collect();
186
187 let committee_size = parameters.nodes;
188 let clients: Vec<_> = instances.into_iter().collect();
189 let load_share = parameters.load / clients.len();
190 let shared_counter = parameters.benchmark_type.shared_objects_ratio;
191 let transfer_objects = 100 - shared_counter;
192 let metrics_port = Self::CLIENT_METRICS_PORT;
193 let gas_keys = GenesisConfig::benchmark_gas_keys(committee_size);
194
195 clients
196 .into_iter()
197 .enumerate()
198 .map(|(i, instance)| {
199 let genesis = genesis_path.display();
200 let keystore = keystore_path.display();
201 let gas_key = &gas_keys[i % committee_size];
202 let gas_address = IotaAddress::from(&gas_key.public());
203
204 let run = [
205 "cargo run --release --bin stress --",
206 "--num-client-threads 24 --num-server-threads 1",
207 "--local false --num-transfer-accounts 2",
208 &format!("--genesis-blob-path {genesis} --keystore-path {keystore}",),
209 &format!("--primary-gas-owner-id {gas_address}"),
210 "bench",
211 &format!("--in-flight-ratio 30 --num-workers 24 --target-qps {load_share}"),
212 &format!(
213 "--shared-counter {shared_counter} --transfer-object {transfer_objects}"
214 ),
215 "--shared-counter-hotness-factor 50",
216 &format!("--client-metric-host 0.0.0.0 --client-metric-port {metrics_port}"),
217 ]
218 .join(" ");
219 let command = ["source $HOME/.cargo/env", &run].join(" && ");
220
221 (instance, command)
222 })
223 .collect()
224 }
225}
226
227impl IotaProtocol {
228 const CLIENT_METRICS_PORT: u16 = GenesisConfig::BENCHMARKS_PORT_OFFSET + 2000;
229
230 pub fn new(settings: &Settings) -> Self {
232 Self {
233 working_dir: [&settings.working_dir, &iota_config::IOTA_CONFIG_DIR.into()]
234 .iter()
235 .collect(),
236 }
237 }
238
239 pub fn resolve_network_addresses(
242 instances: impl IntoIterator<Item = Instance>,
243 ) -> Vec<(Instance, Multiaddr)> {
244 let instances: Vec<Instance> = instances.into_iter().collect();
245 let ips: Vec<_> = instances.iter().map(|x| x.main_ip.to_string()).collect();
246 let genesis_config = GenesisConfig::new_for_benchmarks(&ips);
247 let mut addresses = Vec::new();
248 if let Some(validator_configs) = genesis_config.validator_config_info.as_ref() {
249 for (i, validator_info) in validator_configs.iter().enumerate() {
250 let address = &validator_info.network_address;
251 addresses.push((instances[i].clone(), address.clone()));
252 }
253 }
254 addresses
255 }
256}
257
258impl ProtocolMetrics for IotaProtocol {
259 const BENCHMARK_DURATION: &'static str = "benchmark_duration";
260 const TOTAL_TRANSACTIONS: &'static str = "latency_s_count";
261 const LATENCY_BUCKETS: &'static str = "latency_s";
262 const LATENCY_SUM: &'static str = "latency_s_sum";
263 const LATENCY_SQUARED_SUM: &'static str = "latency_squared_s";
264
265 fn nodes_metrics_path<I, T>(
266 &self,
267 instances: I,
268 parameters: &BenchmarkParameters<T>,
269 ) -> Vec<(Instance, String)>
270 where
271 I: IntoIterator<Item = Instance>,
272 T: BenchmarkType,
273 {
274 let (ips, instances): (Vec<_>, Vec<_>) = instances
275 .into_iter()
276 .map(|x| {
277 (
278 match parameters.use_internal_ip_address {
279 true => x.private_ip,
280 false => x.main_ip,
281 }
282 .to_string(),
283 x,
284 )
285 })
286 .unzip();
287
288 GenesisConfig::new_for_benchmarks(&ips)
289 .validator_config_info
290 .expect("No validator in genesis")
291 .iter()
292 .zip(instances)
293 .map(|(config, instance)| {
294 let path = format!(
295 "{}:{}{}",
296 instance.main_ip,
297 config.metrics_address.port(),
298 iota_metrics::METRICS_ROUTE
299 );
300 (instance, path)
301 })
302 .collect()
303 }
304
305 fn clients_metrics_path<I>(&self, instances: I) -> Vec<(Instance, String)>
306 where
307 I: IntoIterator<Item = Instance>,
308 {
309 instances
310 .into_iter()
311 .map(|instance| {
312 let path = format!(
313 "{}:{}{}",
314 instance.main_ip,
315 Self::CLIENT_METRICS_PORT,
316 iota_metrics::METRICS_ROUTE
317 );
318 (instance, path)
319 })
320 .collect()
321 }
322}