Skip to content

Commit 322f85a

Browse files
authored
Support IB equivocations (#428)
* sim-rs: add ib-equivocations to schema * sim-rs: support IB equivocation * sim-rs: equivocation protection during propagation * sim-rs: output VRFs for IBs * sim-rs: transmit proofs of equivocation * sim-rs: support "adversarial" property for compat with old Haskell config * sim-rs: newline at end of config file * sim-rs: only vote on IBs which arrived quickly enough * sim-rs: account for IB generation time in equivocation guard * sim-rs: never vote for equivocated IBs
1 parent 90bf03d commit 322f85a

File tree

12 files changed

+323
-72
lines changed

12 files changed

+323
-72
lines changed

data/simulation/config.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ export interface Config {
4949
* This is Δhdr from the Leios paper.
5050
* */
5151
"leios-header-diffusion-time-ms": number;
52+
/**
53+
* The expected time it takes a node to generate an IB.
54+
* This is used as part of a validation rule to protect against equivocation attacks.
55+
* In practice, it should probably always equal ib-generation-cpu-time-ms.
56+
*/
57+
"leios-ib-generation-time-ms": number;
5258
/**
5359
* The strategy to use when selecting TXs from the Leios mempool.
5460
*/

data/simulation/config.default.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ leios-stage-active-voting-slots: 1
2929
leios-vote-send-recv-stages: false
3030
leios-late-ib-inclusion: true
3131
leios-header-diffusion-time-ms: 1000.0
32+
leios-ib-generation-time-ms: 130.0
3233
leios-mempool-sampling-strategy: ordered-by-id
3334
leios-mempool-aggressive-pruning: false
3435
# TODO: revise default

data/simulation/config.schema.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,12 @@
269269
"description": "The expected time it takes a header to fully diffuse across the network.\nThis is Δhdr from the Leios paper.",
270270
"type": "number"
271271
},
272+
"leios-ib-generation-time-ms": {
273+
"description": "The expected time it takes a node to generate an IB.\nThis is used as part of a validation rule to protect against equivocation attacks.\nIn practice, it should probably always equal ib-generation-cpu-time-ms.",
274+
"type": "number"
275+
},
272276
"leios-late-ib-inclusion": {
273-
"description": "Extends Leios so that EB producers include IBs directly from previous pipelines\nwhere no certified EB was observed.\n\nOnly supported by Rust simulation.",
277+
"description": "Extends Leios so that EB producers include IBs directly from previous pipelines.\nDue to casuality, the EB must always include them, even if those IBs end up being\ncertified in their own pipeline.",
274278
"type": "boolean"
275279
},
276280
"leios-mempool-aggressive-pruning": {
@@ -375,7 +379,7 @@
375379
},
376380
"tx-overcollateralization-factor-distribution": {
377381
"$ref": "#/definitions/Distribution",
378-
"description": "Distribution used to choose the \"over-collateralization factor\" for a transaction.\n0 means the transaction is not over-collateralized, n means it has enough extra collateral to be included in n shards.\nOnly supported by Rust simulation."
382+
"description": "Distribution used to choose the \"over-collateralization factor\" for a transaction.\nAn \"overcollateralization factor\" of n means the TX has enough collateral to be included in n+1 shards.\nA factor of 0 means the TX has enough collateral to be include in 1 shard; i.e. it is not over-collateralized.\nOnly supported by Rust simulation."
379383
},
380384
"tx-size-bytes-distribution": {
381385
"$ref": "#/definitions/Distribution",

data/simulation/topology.d.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@ export interface Node<Location> {
3333
* Only supported by Rust simulation.
3434
*/
3535
"tx-generation-weight"?: number | null;
36-
/** If not null, the node will behave according to the given Behaviour.
37-
*
38-
* Only supported by Haskell simulation.
39-
*/
36+
/** If not null, the node will behave according to the given Behaviour. */
4037
adversarial?: Behaviour | null;
38+
/** If not null, the node will follow the given behaviours.
39+
*
40+
*
41+
* Only supported by Rust simulation.
42+
*/
43+
behaviours?: Behaviour[] | null;
4144
}
4245

4346
/** Link information. */
@@ -70,3 +73,11 @@ export interface UnboundedIbs {
7073
"slot-of-generated-ibs": number;
7174
"ibs-per-slot": number;
7275
}
76+
77+
/** A node which generates equivocated IBs at any possible opportunity.
78+
*
79+
* Only supported by Rust simulation.
80+
*/
81+
export interface IbEquivocation {
82+
behaviour: "ib-equivocation";
83+
}

data/simulation/topology.schema.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,14 @@
2828
"properties": {
2929
"adversarial": {
3030
"$ref": "#/definitions/UnboundedIbs",
31-
"description": "If not null, the node will behave according to the given Behaviour.\n\nOnly supported by Haskell simulation."
31+
"description": "If not null, the node will behave according to the given Behaviour."
32+
},
33+
"behaviours": {
34+
"description": "If not null, the node will follow the given behaviours.\n\n\nOnly supported by Rust simulation.",
35+
"items": {
36+
"$ref": "#/definitions/UnboundedIbs"
37+
},
38+
"type": "array"
3239
},
3340
"cpu-core-count": {
3441
"additionalProperties": false,
@@ -65,7 +72,14 @@
6572
"properties": {
6673
"adversarial": {
6774
"$ref": "#/definitions/UnboundedIbs",
68-
"description": "If not null, the node will behave according to the given Behaviour.\n\nOnly supported by Haskell simulation."
75+
"description": "If not null, the node will behave according to the given Behaviour."
76+
},
77+
"behaviours": {
78+
"description": "If not null, the node will follow the given behaviours.\n\n\nOnly supported by Rust simulation.",
79+
"items": {
80+
"$ref": "#/definitions/UnboundedIbs"
81+
},
82+
"type": "array"
6983
},
7084
"cpu-core-count": {
7185
"additionalProperties": false,

data/simulation/trace.haskell.schema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@
9999
},
100100
"GeneratedEndorserBlock": {
101101
"properties": {
102+
"endorser_blocks": {
103+
"items": {
104+
"$ref": "#/definitions/BlockRef"
105+
},
106+
"type": "array"
107+
},
102108
"id": {
103109
"type": "string"
104110
},
@@ -125,6 +131,7 @@
125131
}
126132
},
127133
"required": [
134+
"endorser_blocks",
128135
"id",
129136
"input_blocks",
130137
"pipeline",

data/simulation/trace.rust.schema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@
9494
},
9595
"GeneratedEndorserBlock": {
9696
"properties": {
97+
"endorser_blocks": {
98+
"items": {
99+
"$ref": "#/definitions/BlockRef"
100+
},
101+
"type": "array"
102+
},
97103
"id": {
98104
"type": "string"
99105
},
@@ -120,6 +126,7 @@
120126
}
121127
},
122128
"required": [
129+
"endorser_blocks",
123130
"id",
124131
"input_blocks",
125132
"pipeline",

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ impl GraphBuilder {
173173
tx_conflict_fraction: None,
174174
tx_generation_weight: None,
175175
producers: BTreeMap::new(),
176+
adversarial: None,
177+
behaviours: vec![],
176178
};
177179
(name, node)
178180
})

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ pub struct RawParameters {
6767
pub leios_stage_active_voting_slots: u64,
6868
pub leios_late_ib_inclusion: bool,
6969
pub leios_header_diffusion_time_ms: f64,
70+
pub leios_ib_generation_time_ms: f64,
7071
pub leios_mempool_sampling_strategy: MempoolSamplingStrategy,
7172
pub leios_mempool_aggressive_pruning: bool,
7273
pub praos_chain_quality: u64,
@@ -185,6 +186,16 @@ pub struct RawNode {
185186
#[serde(skip_serializing_if = "Option::is_none")]
186187
pub tx_generation_weight: Option<u64>,
187188
pub producers: BTreeMap<String, RawLinkInfo>,
189+
#[serde(default, skip_serializing_if = "Option::is_none")]
190+
pub adversarial: Option<RawNodeBehaviour>,
191+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
192+
pub behaviours: Vec<RawNodeBehaviour>,
193+
}
194+
195+
#[derive(Debug, Serialize, Deserialize)]
196+
#[serde(rename_all = "kebab-case", tag = "behaviour")]
197+
pub enum RawNodeBehaviour {
198+
IbEquivocation,
188199
}
189200

190201
#[derive(Debug, Serialize, Deserialize)]
@@ -253,6 +264,7 @@ impl From<RawTopology> for Topology {
253264
for (index, (name, node)) in value.nodes.iter().enumerate() {
254265
let id = NodeId::new(index);
255266
node_ids.insert(name.clone(), id);
267+
let behaviours = NodeBehaviours::parse(&node.adversarial, &node.behaviours);
256268
nodes.insert(
257269
id,
258270
NodeConfiguration {
@@ -264,6 +276,7 @@ impl From<RawTopology> for Topology {
264276
tx_conflict_fraction: node.tx_conflict_fraction,
265277
tx_generation_weight: node.tx_generation_weight,
266278
consumers: vec![],
279+
behaviours,
267280
},
268281
);
269282
}
@@ -483,6 +496,7 @@ pub struct SimConfiguration {
483496
pub vote_threshold: u64,
484497
pub(crate) praos_fallback: bool,
485498
pub(crate) header_diffusion_time: Duration,
499+
pub(crate) ib_generation_time: Duration,
486500
pub(crate) relay_strategy: RelayStrategy,
487501
pub(crate) mempool_strategy: MempoolSamplingStrategy,
488502
pub(crate) mempool_aggressive_pruning: bool,
@@ -540,6 +554,7 @@ impl SimConfiguration {
540554
variant: params.leios_variant,
541555
praos_fallback: params.praos_fallback_enabled,
542556
header_diffusion_time: duration_ms(params.leios_header_diffusion_time_ms),
557+
ib_generation_time: duration_ms(params.leios_ib_generation_time_ms),
543558
relay_strategy: params.relay_strategy,
544559
mempool_strategy: params.leios_mempool_sampling_strategy,
545560
mempool_aggressive_pruning: params.leios_mempool_aggressive_pruning,
@@ -579,6 +594,7 @@ pub struct NodeConfiguration {
579594
pub tx_conflict_fraction: Option<f64>,
580595
pub tx_generation_weight: Option<u64>,
581596
pub consumers: Vec<NodeId>,
597+
pub behaviours: NodeBehaviours,
582598
}
583599

584600
#[derive(Debug, Clone)]
@@ -587,3 +603,22 @@ pub struct LinkConfiguration {
587603
pub latency: Duration,
588604
pub bandwidth_bps: Option<u64>,
589605
}
606+
607+
#[derive(Debug, Clone, Default)]
608+
pub struct NodeBehaviours {
609+
pub ib_equivocation: bool,
610+
}
611+
612+
impl NodeBehaviours {
613+
fn parse(adversarial: &Option<RawNodeBehaviour>, behaviours: &[RawNodeBehaviour]) -> Self {
614+
let mut result = NodeBehaviours::default();
615+
for behaviour in adversarial.iter().chain(behaviours) {
616+
match behaviour {
617+
RawNodeBehaviour::IbEquivocation => {
618+
result.ib_equivocation = true;
619+
}
620+
}
621+
}
622+
result
623+
}
624+
}

sim-rs/sim-core/src/events.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ pub enum Event {
165165
pipeline: u64,
166166
producer: Node,
167167
index: u64,
168+
vrf: u64,
168169
shard: u64,
169170
header_bytes: u64,
170171
tx_payload_bytes: u64,
@@ -477,6 +478,7 @@ impl EventTracker {
477478
pipeline: block.header.id.pipeline,
478479
producer: self.to_node(block.header.id.producer),
479480
index: block.header.id.index,
481+
vrf: block.header.vrf,
480482
shard: block.header.shard,
481483
header_bytes,
482484
tx_payload_bytes,

0 commit comments

Comments
 (0)