Skip to content

Commit 5000ce9

Browse files
authored
fix(orchestrator): make non-zero timestamp when running benchmark (#9446)
# Description of change Add configurable genesis chain start timestamp to the IOTA orchestrator and benchmarking infrastructure, replacing the hardcoded timestamp of 0 with the current system time computed at benchmark runtime. ## Links to any relevant issues Fixes #9445 ## How the change has been tested - [x] Basic tests (linting, compilation, formatting, unit/integration tests) - [ ] Patch-specific tests (correctness, functionality coverage) - [ ] I have added tests that prove my fix is effective or that my feature works - [x] I have checked that new and existing unit tests pass locally with my changes
1 parent 4146bf6 commit 5000ce9

File tree

6 files changed

+103
-33
lines changed

6 files changed

+103
-33
lines changed

crates/iota-aws-orchestrator/src/benchmark.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ pub struct BenchmarkParameters<T> {
6565
pub protocol_switch_each_epoch: bool,
6666
/// Optional: Epoch duration in milliseconds, default is 1h
6767
pub epoch_duration_ms: Option<u64>,
68+
/// Computed chain start timestamp (computed once in next() if
69+
/// use_current_timestamp_for_genesis is true)
70+
pub chain_start_timestamp_ms: Option<u64>,
6871
}
6972

7073
impl<T: BenchmarkType> Default for BenchmarkParameters<T> {
@@ -81,6 +84,7 @@ impl<T: BenchmarkType> Default for BenchmarkParameters<T> {
8184
protocol_switch_each_epoch: false,
8285
maximum_latency: 400,
8386
epoch_duration_ms: None,
87+
chain_start_timestamp_ms: None,
8488
}
8589
}
8690
}
@@ -89,8 +93,13 @@ impl<T: BenchmarkType> Debug for BenchmarkParameters<T> {
8993
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9094
write!(
9195
f,
92-
"{:?}-{:?}-{}-{}-{}",
93-
self.benchmark_type, self.faults, self.nodes, self.load, self.use_internal_ip_address,
96+
"{:?}-{:?}-{}-{}-{}-{:?}",
97+
self.benchmark_type,
98+
self.faults,
99+
self.nodes,
100+
self.load,
101+
self.use_internal_ip_address,
102+
self.chain_start_timestamp_ms,
94103
)
95104
}
96105
}
@@ -99,8 +108,12 @@ impl<T> Display for BenchmarkParameters<T> {
99108
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100109
write!(
101110
f,
102-
"{} nodes ({}) - {} tx/s (use internal IPs: {})",
103-
self.nodes, self.faults, self.load, self.use_internal_ip_address
111+
"{} nodes ({}) - {} tx/s (use internal IPs: {}; use current timestamp: {:?})",
112+
self.nodes,
113+
self.faults,
114+
self.load,
115+
self.use_internal_ip_address,
116+
self.chain_start_timestamp_ms,
104117
)
105118
}
106119
}
@@ -119,6 +132,7 @@ impl<T> BenchmarkParameters<T> {
119132
protocol_switch_each_epoch: bool,
120133
maximum_latency: u16,
121134
epoch_duration_ms: Option<u64>,
135+
chain_start_timestamp_ms: Option<u64>,
122136
) -> Self {
123137
Self {
124138
benchmark_type,
@@ -132,6 +146,7 @@ impl<T> BenchmarkParameters<T> {
132146
protocol_switch_each_epoch,
133147
maximum_latency,
134148
epoch_duration_ms,
149+
chain_start_timestamp_ms,
135150
}
136151
}
137152
}
@@ -187,13 +202,26 @@ pub struct BenchmarkParametersGenerator<T> {
187202
pub protocol_switch_each_epoch: bool,
188203
/// Optional: Epoch duration in milliseconds, default is 1h
189204
epoch_duration_ms: Option<u64>,
205+
/// Use current system time as genesis chain start timestamp instead of 0
206+
use_current_timestamp_for_genesis: bool,
190207
}
191208

192209
impl<T: BenchmarkType> Iterator for BenchmarkParametersGenerator<T> {
193210
type Item = BenchmarkParameters<T>;
194211

195212
/// Return the next set of benchmark parameters to run.
196213
fn next(&mut self) -> Option<Self::Item> {
214+
// Compute timestamp once if needed
215+
let chain_start_timestamp_ms = if self.use_current_timestamp_for_genesis {
216+
Some(
217+
std::time::SystemTime::now()
218+
.duration_since(std::time::UNIX_EPOCH)
219+
.unwrap()
220+
.as_millis() as u64,
221+
)
222+
} else {
223+
None
224+
};
197225
self.next_load.map(|load| {
198226
BenchmarkParameters::new(
199227
self.benchmark_type.clone(),
@@ -207,6 +235,7 @@ impl<T: BenchmarkType> Iterator for BenchmarkParametersGenerator<T> {
207235
self.protocol_switch_each_epoch,
208236
self.maximum_latency,
209237
self.epoch_duration_ms,
238+
chain_start_timestamp_ms,
210239
)
211240
})
212241
}
@@ -244,6 +273,7 @@ impl<T: BenchmarkType> BenchmarkParametersGenerator<T> {
244273
protocol_switch_each_epoch: false,
245274
maximum_latency: 400,
246275
epoch_duration_ms: None,
276+
use_current_timestamp_for_genesis: false,
247277
}
248278
}
249279

@@ -290,6 +320,11 @@ impl<T: BenchmarkType> BenchmarkParametersGenerator<T> {
290320
self
291321
}
292322

323+
pub fn with_current_timestamp_for_genesis(mut self, use_current_timestamp: bool) -> Self {
324+
self.use_current_timestamp_for_genesis = use_current_timestamp;
325+
self
326+
}
327+
293328
/// Detects whether the latest benchmark parameters run the system out of
294329
/// capacity.
295330
fn out_of_capacity(

crates/iota-aws-orchestrator/src/main.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ pub enum Operation {
175175
/// latency_perturbation_spec
176176
#[arg(long, value_name = "INT", default_value = "1", global = true)]
177177
blocking_connections: usize,
178+
179+
/// Use current system time as genesis chain start timestamp instead of
180+
/// 0
181+
#[arg(long, action, default_value_t = false)]
182+
use_current_timestamp_for_genesis: bool,
178183
},
179184

180185
/// Print a summary of the specified measurements collection.
@@ -389,6 +394,7 @@ async fn run<C: ServerProviderClient>(settings: Settings, client: C, opts: Opts)
389394
maximum_latency,
390395
epoch_duration_ms,
391396
blocking_connections,
397+
use_current_timestamp_for_genesis,
392398
} => {
393399
// Create a new orchestrator to instruct the testbed.
394400
let username = testbed.username();
@@ -468,6 +474,7 @@ async fn run<C: ServerProviderClient>(settings: Settings, client: C, opts: Opts)
468474
.with_protocol_switch_each_epoch(protocol_switch_each_epoch)
469475
.with_max_latency(maximum_latency)
470476
.with_epoch_duration(epoch_duration_ms)
477+
.with_current_timestamp_for_genesis(use_current_timestamp_for_genesis)
471478
.with_faults(fault_type);
472479

473480
Orchestrator::new(

crates/iota-aws-orchestrator/src/protocol/iota.rs

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,24 @@ impl ProtocolCommands<IotaBenchmarkType> for IotaProtocol {
9696
})
9797
.collect::<Vec<_>>()
9898
.join(" ");
99+
let epoch_duration_flag = parameters
100+
.epoch_duration_ms
101+
.map(|epoch_duration_ms| format!("--epoch-duration-ms {epoch_duration_ms}"))
102+
.unwrap_or_default();
103+
let chain_start_timestamp_flag = parameters
104+
.chain_start_timestamp_ms
105+
.map(|timestamp_ms| format!("--chain-start-timestamp-ms {timestamp_ms}"))
106+
.unwrap_or_default();
99107
let genesis = [
100108
"cargo run --release --bin iota --",
101109
"genesis",
102110
&format!("-f --working-dir {working_dir} --benchmark-ips {ips}"),
103-
parameters
104-
.epoch_duration_ms
105-
.map(|epoch_duration_ms| format!("--epoch-duration-ms {epoch_duration_ms}"))
106-
.as_deref()
107-
.unwrap_or(""),
111+
&epoch_duration_flag,
112+
&chain_start_timestamp_flag,
108113
]
114+
.into_iter()
115+
.filter(|s| !s.is_empty())
116+
.collect::<Vec<_>>()
109117
.join(" ");
110118

111119
[
@@ -325,7 +333,11 @@ impl IotaProtocol {
325333
false => x.main_ip.to_string(),
326334
})
327335
.collect();
328-
let genesis_config = GenesisConfig::new_for_benchmarks(&ips, parameters.epoch_duration_ms);
336+
let genesis_config = GenesisConfig::new_for_benchmarks(
337+
&ips,
338+
parameters.epoch_duration_ms,
339+
parameters.chain_start_timestamp_ms,
340+
);
329341
let mut addresses = Vec::new();
330342
if let Some(validator_configs) = genesis_config.validator_config_info.as_ref() {
331343
for (i, validator_info) in validator_configs.iter().enumerate() {
@@ -366,25 +378,28 @@ impl ProtocolMetrics for IotaProtocol {
366378
)
367379
})
368380
.unzip();
369-
370-
GenesisConfig::new_for_benchmarks(&ips, parameters.epoch_duration_ms)
371-
.validator_config_info
372-
.expect("No validator in genesis")
373-
.iter()
374-
.zip(instances)
375-
.map(|(config, instance)| {
376-
let path = format!(
377-
"{}:{}{}",
378-
match parameters.use_internal_ip_address {
379-
true => instance.private_ip,
380-
false => instance.main_ip,
381-
},
382-
config.metrics_address.port(),
383-
iota_metrics::METRICS_ROUTE
384-
);
385-
(instance, path)
386-
})
387-
.collect()
381+
GenesisConfig::new_for_benchmarks(
382+
&ips,
383+
parameters.epoch_duration_ms,
384+
parameters.chain_start_timestamp_ms,
385+
)
386+
.validator_config_info
387+
.expect("No validator in genesis")
388+
.iter()
389+
.zip(instances)
390+
.map(|(config, instance)| {
391+
let path = format!(
392+
"{}:{}{}",
393+
match parameters.use_internal_ip_address {
394+
true => instance.private_ip,
395+
false => instance.main_ip,
396+
},
397+
config.metrics_address.port(),
398+
iota_metrics::METRICS_ROUTE
399+
);
400+
(instance, path)
401+
})
402+
.collect()
388403
}
389404

390405
fn clients_metrics_path<I, T>(

crates/iota-swarm-config/src/genesis_config.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,11 @@ impl GenesisConfig {
344344
/// predictable to facilitate benchmarks orchestration. Only the main ip
345345
/// addresses of the validators are specified (as those are often
346346
/// dictated by the cloud provider hosing the testbed).
347-
pub fn new_for_benchmarks(ips: &[String], epoch_duration_ms: Option<u64>) -> Self {
347+
pub fn new_for_benchmarks(
348+
ips: &[String],
349+
epoch_duration_ms: Option<u64>,
350+
chain_start_timestamp_ms: Option<u64>,
351+
) -> Self {
348352
// Set the validator's configs. They should be the same across multiple runs to
349353
// ensure reproducibility.
350354
let mut rng = StdRng::seed_from_u64(Self::BENCHMARKS_RNG_SEED);
@@ -385,7 +389,7 @@ impl GenesisConfig {
385389
// Benchmarks require a deterministic genesis. Every validator locally generates
386390
// it own genesis; it is thus important they have the same parameters.
387391
let parameters = GenesisCeremonyParameters {
388-
chain_start_timestamp_ms: 0,
392+
chain_start_timestamp_ms: chain_start_timestamp_ms.unwrap_or(0),
389393
epoch_duration_ms: if let Some(duration_ms) = epoch_duration_ms {
390394
duration_ms
391395
} else {

crates/iota/src/iota_commands.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ pub enum IotaCommand {
266266
force: bool,
267267
#[arg(long)]
268268
epoch_duration_ms: Option<u64>,
269+
#[arg(long, help = "Set the genesis chain start timestamp in milliseconds")]
270+
chain_start_timestamp_ms: Option<u64>,
269271
#[arg(
270272
long,
271273
value_name = "ADDR",
@@ -431,6 +433,7 @@ impl IotaCommand {
431433
from_config,
432434
write_config,
433435
epoch_duration_ms,
436+
chain_start_timestamp_ms,
434437
benchmark_ips,
435438
with_faucet,
436439
committee_size,
@@ -444,6 +447,7 @@ impl IotaCommand {
444447
working_dir,
445448
force,
446449
epoch_duration_ms,
450+
chain_start_timestamp_ms,
447451
benchmark_ips,
448452
with_faucet,
449453
committee_size,
@@ -740,6 +744,7 @@ async fn start(
740744
false,
741745
epoch_duration_ms,
742746
None,
747+
None,
743748
false,
744749
committee_size.unwrap_or(DEFAULT_COMMITTEE_SIZE),
745750
local_migration_snapshots,
@@ -1007,6 +1012,7 @@ async fn genesis(
10071012
working_dir: Option<PathBuf>,
10081013
force: bool,
10091014
epoch_duration_ms: Option<u64>,
1015+
chain_start_timestamp_ms: Option<u64>,
10101016
benchmark_ips: Option<Vec<String>>,
10111017
with_faucet: bool,
10121018
committee_size: usize,
@@ -1094,8 +1100,9 @@ async fn genesis(
10941100
}
10951101
keystore.save()?;
10961102

1097-
// Make a new genesis config from the provided ip addresses.
1098-
GenesisConfig::new_for_benchmarks(&ips, epoch_duration_ms)
1103+
// Make a new genesis config from the provided ip addresses with given epoch
1104+
// duration and timestamp.
1105+
GenesisConfig::new_for_benchmarks(&ips, epoch_duration_ms, chain_start_timestamp_ms)
10991106
} else if keystore_path.exists() {
11001107
let existing_keys = FileBasedKeystore::new(&keystore_path)?.addresses();
11011108
GenesisConfig::for_local_testing_with_addresses(existing_keys)

crates/iota/tests/cli_tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ async fn test_genesis() -> Result<(), anyhow::Error> {
361361
local_migration_snapshots: vec![],
362362
remote_migration_snapshots: vec![],
363363
delegator: None,
364+
chain_start_timestamp_ms: None,
364365
}
365366
.execute()
366367
.await?;
@@ -403,6 +404,7 @@ async fn test_genesis() -> Result<(), anyhow::Error> {
403404
local_migration_snapshots: vec![],
404405
remote_migration_snapshots: vec![],
405406
delegator: None,
407+
chain_start_timestamp_ms: None,
406408
}
407409
.execute()
408410
.await;

0 commit comments

Comments
 (0)