Skip to content

Commit 7d98460

Browse files
committed
sim-rs: support configuring tx-conflict-fraction
1 parent f00d83a commit 7d98460

File tree

8 files changed

+73
-19
lines changed

8 files changed

+73
-19
lines changed

data/simulation/config.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ export interface Config {
7575
"tx-validation-cpu-time-ms": number;
7676
/** Only supported by Rust simulation. */
7777
"tx-max-size-bytes": bigint;
78+
/**
79+
* What fraction of TXs (from 0 to 1) should introduce conflicts with transactions which were produced before?
80+
* Only supported by Rust simulation. */
81+
"tx-conflict-fraction": number | null;
7882
/**
7983
* When the first transaction should appear.
8084
* Only supported by Rust simulation. */

data/simulation/config.default.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ tx-size-bytes-distribution:
4848
sigma: 1.127
4949
tx-validation-cpu-time-ms: 1.5
5050
tx-max-size-bytes: 16384
51+
tx-conflict-fraction: 0
5152

5253
################################################################################
5354
# Ranking Block Configuration

data/simulation/config.schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,10 @@
355355
"description": "When `true`, any delays and message sizes are calculated as if\neach block contained as much data as the expected average, rounded up.\nIn particular, for the sake of the above, we consider that:\n - Each RB includes a certificate.\n - Certificates contain votes from `vote-threshold` nodes.\n - Vote bundles vote for `ceil eb-generation-probability` EBs.\n - EBs reference `ceil (ib-generation-probability * leios-stage-length-slots)` IBs.\nOnly supported by Haskell simulation.",
356356
"type": "boolean"
357357
},
358+
"tx-conflict-fraction": {
359+
"description": "What fraction of TXs (from 0 to 1) should introduce conflicts with transactions which were produced before?\nOnly supported by Rust simulation.",
360+
"type": "number"
361+
},
358362
"tx-generation-distribution": {
359363
"$ref": "#/definitions/Distribution",
360364
"description": "Only supported by Rust simulation."

data/simulation/topology.d.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
*/
1010
export interface Topology {
1111
nodes:
12-
| {
13-
[name: NodeName]: Node<Cluster>;
14-
}
15-
| {
16-
[name: NodeName]: Node<Coord2D>;
17-
};
12+
| {
13+
[name: NodeName]: Node<Cluster>;
14+
}
15+
| {
16+
[name: NodeName]: Node<Coord2D>;
17+
};
1818
}
1919

2020
/** A node. */
@@ -23,6 +23,10 @@ export interface Node<Location> {
2323
"cpu-core-count"?: bigint | null;
2424
location: Location;
2525
producers: { [producer: NodeName]: LinkInfo };
26+
/**
27+
* What fraction of TXs (from 0 to 1) should introduce conflicts with transactions which were produced before?
28+
* Only supported by Rust simulation. */
29+
"tx-conflict-fraction"?: number | null;
2630
/** If not null, the node will behave according to the given Behaviour.
2731
*
2832
* Only supported by Haskell simulation.

data/simulation/topology.schema.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@
4848
"additionalProperties": false,
4949
"properties": {},
5050
"type": "number"
51+
},
52+
"tx-conflict-fraction": {
53+
"description": "What fraction of TXs (from 0 to 1) should introduce conflicts with transactions which were produced before?\nOnly supported by Rust simulation.",
54+
"type": "number"
5155
}
5256
},
5357
"type": "object"
@@ -87,6 +91,10 @@
8791
"additionalProperties": false,
8892
"properties": {},
8993
"type": "number"
94+
},
95+
"tx-conflict-fraction": {
96+
"description": "What fraction of TXs (from 0 to 1) should introduce conflicts with transactions which were produced before?\nOnly supported by Rust simulation.",
97+
"type": "number"
9098
}
9199
},
92100
"type": "object"

sim-rs/sim-cli/src/bin/gen-test-data/strategy/utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ impl GraphBuilder {
170170
stake: n.stake,
171171
location: RawNodeLocation::Coords(n.location),
172172
cpu_core_count: n.cores,
173+
tx_conflict_fraction: None,
173174
producers: BTreeMap::new(),
174175
};
175176
(name, node)

sim-rs/sim-core/src/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub struct RawParameters {
7676
pub tx_size_bytes_distribution: DistributionConfig,
7777
pub tx_validation_cpu_time_ms: f64,
7878
pub tx_max_size_bytes: u64,
79+
pub tx_conflict_fraction: Option<f64>,
7980
pub tx_start_time: Option<f64>,
8081
pub tx_stop_time: Option<f64>,
8182

@@ -177,6 +178,8 @@ pub struct RawNode {
177178
pub location: RawNodeLocation,
178179
#[serde(skip_serializing_if = "Option::is_none")]
179180
pub cpu_core_count: Option<u64>,
181+
#[serde(skip_serializing_if = "Option::is_none")]
182+
pub tx_conflict_fraction: Option<f64>,
180183
pub producers: BTreeMap<String, RawLinkInfo>,
181184
}
182185

@@ -254,6 +257,7 @@ impl From<RawTopology> for Topology {
254257
stake: node.stake.unwrap_or_default(),
255258
cpu_multiplier: 1.0,
256259
cores: node.cpu_core_count,
260+
tx_conflict_fraction: node.tx_conflict_fraction,
257261
consumers: vec![],
258262
},
259263
);
@@ -403,6 +407,7 @@ impl TransactionConfig {
403407
max_size: params.tx_max_size_bytes,
404408
frequency_ms: params.tx_generation_distribution.into(),
405409
size_bytes: params.tx_size_bytes_distribution.into(),
410+
conflict_fraction: params.tx_conflict_fraction.unwrap_or_default(),
406411
start_time: params
407412
.tx_start_time
408413
.map(|t| Timestamp::zero() + Duration::from_secs_f64(t)),
@@ -425,6 +430,7 @@ pub(crate) struct RealTransactionConfig {
425430
pub max_size: u64,
426431
pub frequency_ms: FloatDistribution,
427432
pub size_bytes: FloatDistribution,
433+
pub conflict_fraction: f64,
428434
pub start_time: Option<Timestamp>,
429435
pub stop_time: Option<Timestamp>,
430436
}
@@ -547,6 +553,7 @@ pub struct NodeConfiguration {
547553
pub stake: u64,
548554
pub cpu_multiplier: f64,
549555
pub cores: Option<u64>,
556+
pub tx_conflict_fraction: Option<f64>,
550557
pub consumers: Vec<NodeId>,
551558
}
552559

sim-rs/sim-core/src/sim/tx.rs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ use crate::{
1111
model::{Transaction, TransactionId},
1212
};
1313

14+
struct NodeState {
15+
sink: mpsc::UnboundedSender<Arc<Transaction>>,
16+
tx_conflict_fraction: Option<f64>,
17+
}
18+
1419
pub struct TransactionProducer {
1520
rng: ChaChaRng,
1621
clock: ClockBarrier,
17-
node_tx_sinks: HashMap<NodeId, mpsc::UnboundedSender<Arc<Transaction>>>,
22+
nodes: HashMap<NodeId, NodeState>,
1823
ib_shards: u64,
1924
config: Option<RealTransactionConfig>,
2025
}
@@ -23,13 +28,25 @@ impl TransactionProducer {
2328
pub fn new(
2429
rng: ChaChaRng,
2530
clock: ClockBarrier,
26-
node_tx_sinks: HashMap<NodeId, mpsc::UnboundedSender<Arc<Transaction>>>,
31+
mut node_tx_sinks: HashMap<NodeId, mpsc::UnboundedSender<Arc<Transaction>>>,
2732
config: &SimConfiguration,
2833
) -> Self {
34+
let nodes = config
35+
.nodes
36+
.iter()
37+
.map(|node| {
38+
let sink = node_tx_sinks.remove(&node.id).unwrap();
39+
let state = NodeState {
40+
sink,
41+
tx_conflict_fraction: node.tx_conflict_fraction,
42+
};
43+
(node.id, state)
44+
})
45+
.collect();
2946
Self {
3047
rng,
3148
clock,
32-
node_tx_sinks,
49+
nodes,
3350
ib_shards: config.ib_shards,
3451
config: match &config.transactions {
3552
TransactionConfig::Real(config) => Some(config.clone()),
@@ -43,7 +60,7 @@ impl TransactionProducer {
4360
self.clock.wait_forever().await;
4461
return Ok(());
4562
};
46-
let node_count = self.node_tx_sinks.len();
63+
let node_count = self.nodes.len();
4764
let mut next_tx_id = 0;
4865
let mut next_tx_at = Timestamp::zero();
4966
let mut next_input_id = 0;
@@ -55,27 +72,35 @@ impl TransactionProducer {
5572
};
5673

5774
loop {
75+
let node_index = rng.random_range(0..node_count);
76+
let node_id = NodeId::new(node_index);
77+
let node = self.nodes.get(&node_id).unwrap();
78+
79+
let conflict_fraction = node
80+
.tx_conflict_fraction
81+
.unwrap_or(config.conflict_fraction);
82+
5883
let id = TransactionId::new(next_tx_id);
5984
let shard = rng.random_range(0..self.ib_shards);
6085
let bytes = (config.size_bytes.sample(&mut rng) as u64).min(config.max_size);
61-
let input_id = next_input_id;
86+
let input_id = if next_input_id > 0 && rng.random_bool(conflict_fraction) {
87+
next_input_id - 1
88+
} else {
89+
let id = next_input_id;
90+
next_input_id += 1;
91+
id
92+
};
93+
6294
let tx = Transaction {
6395
id,
6496
shard,
6597
bytes,
6698
input_id,
6799
};
68100

69-
let node_index = rng.random_range(0..node_count);
70-
let node_id = NodeId::new(node_index);
71-
72-
self.node_tx_sinks
73-
.get(&node_id)
74-
.unwrap()
75-
.send(Arc::new(tx))?;
101+
node.sink.send(Arc::new(tx))?;
76102

77103
next_tx_id += 1;
78-
next_input_id += 1;
79104
let millis_until_tx = config.frequency_ms.sample(&mut rng) as u64;
80105
next_tx_at += Duration::from_millis(millis_until_tx);
81106

0 commit comments

Comments
 (0)