Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion data/simulation/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,10 @@ export interface LateTXAttackConfig {
"tx-generation-distribution": Distribution,
}

export type NodeSelection = NodesNodeSelection;
export type NodeSelection = NodesNodeSelection | StakeFractionNodeSelection;
export interface NodesNodeSelection {
"nodes": string[];
}
export interface StakeFractionNodeSelection {
"stake-fraction": number,
}
22 changes: 20 additions & 2 deletions data/simulation/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"description": "Configuration for a \"late EB\" attack,\nwhere nodes deliberately withhold EBs until near the end of the voting phase.",
"properties": {
"attackers": {
"$ref": "#/definitions/NodesNodeSelection",
"$ref": "#/definitions/NodeSelection",
"description": "The set of stake pools which are participating in the attack."
},
"propagation-delay-ms": {
Expand All @@ -98,7 +98,7 @@
"type": "number"
},
"attackers": {
"$ref": "#/definitions/NodesNodeSelection",
"$ref": "#/definitions/NodeSelection",
"description": "The set of stake pools which are participating in the attack."
},
"tx-generation-distribution": {
Expand Down Expand Up @@ -138,6 +138,16 @@
"enum": ["ordered-by-id", "random"],
"type": "string"
},
"NodeSelection": {
"anyOf": [
{
"$ref": "#/definitions/NodesNodeSelection"
},
{
"$ref": "#/definitions/StakeFractionNodeSelection"
}
]
},
"NodesNodeSelection": {
"properties": {
"nodes": {
Expand Down Expand Up @@ -167,6 +177,14 @@
"RelayStrategy": {
"enum": ["request-from-all", "request-from-first"],
"type": "string"
},
"StakeFractionNodeSelection": {
"properties": {
"stake-fraction": {
"type": "number"
}
},
"type": "object"
}
},
"description": "A configuration for a Leios simulation.",
Expand Down
17 changes: 17 additions & 0 deletions sim-rs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Changelog

## v1.0.0

### Linear Leios

- Allow RBs to include EB certificates produced at least `L_diff` slots ago, instead of `L_vote + L_diff` slots ago. When `L_diff` is 0, this removes any direct time factor from the decision to include an EB cert.
- Add TXs to the mempool, even if they belong to an EB we've already seen.
- Support choosing attackers by selecting a fraction of stake

### Other

- Add version number to the CLI tool's output.

## v0.1.0

This version was arbitrarily chosen as the point to start tracking major changes to the simulation.
4 changes: 2 additions & 2 deletions sim-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 23 additions & 4 deletions sim-rs/implementations/LINEAR_LEIOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ When a node receives an RB body, it immediately removes all referenced/conflicti

A set of nodes can be configured to collude with each other, to distribute an EB close to the end of L_diff.

Example config:
Example config (with explicit list of attackers):
```yaml
late-eb-attack:
attackers:
Expand All @@ -85,15 +85,23 @@ late-eb-attack:
propagation-delay-ms: 4500.0
```

The `attackers` list controls which nodes are participating in the attack. (I will get around to letting you just choose a `stake` sometime soon). These nodes can communicate out of band, without taking latency or bandwidth into account.
Example config (with fraction of stake):
```yaml
late-eb-attack:
attackers:
stake-fraction: 0.51
propagation-delay-ms: 4500.0
```

The `attackers` list controls which nodes are participating in the attack. These nodes can communicate out of band, without taking latency or bandwidth into account.

When one of the attackers generates an EB, it will instantly and instantaneously send that EB to all other attackers. The attackers will all wait for `propagation-delay-ms` to elapse, and _then_ announce the EB to all peers.

### TX Withholding

A set of nodes can be configured to "withhold" some number of TXs until the moment they generate an EB.

Example config:
Example config (with explicit list of attackers):
```yaml
late-tx-attack:
attackers:
Expand All @@ -110,7 +118,18 @@ late-tx-attack:
value: 3
```

The `attackers` list controls which nodes are participating in the attack. (I will get around to letting you just choose a `stake` sometime soon).
Example config (with fraction of stake):
```yaml
late-tx-attack:
attackers:
stake-fraction: 0.51
attack-probability: 1.0
tx-generation-distribution:
distribution: constant
value: 3
```

The `attackers` list controls which nodes are participating in the attack.

When an attacker generates an EB, with probability `attack-probability` they will also generate `tx-generation-distribution` brand-new transactions. Both the EB and the transactions will be immediately announced to peers as normal.

Expand Down
2 changes: 1 addition & 1 deletion sim-rs/sim-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sim-cli"
version = "0.1.0"
version = "1.0.0"
edition = "2024"
default-run = "sim-cli"
rust-version = "1.88"
Expand Down
2 changes: 1 addition & 1 deletion sim-rs/sim-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const DEFAULT_TOPOLOGY_PATHS: &[&str] = &[
];

#[derive(Parser)]
#[command(version = env!("VERGEN_GIT_SHA"))]
#[command(version = concat!(env!("CARGO_PKG_VERSION"), "-", env!("VERGEN_GIT_SHA")))]
struct Args {
#[clap(default_value = None)]
topology: Option<PathBuf>,
Expand Down
2 changes: 1 addition & 1 deletion sim-rs/sim-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sim-core"
version = "0.1.0"
version = "1.0.0"
edition = "2024"
rust-version = "1.88"

Expand Down
40 changes: 30 additions & 10 deletions sim-rs/sim-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use rand::Rng;
use rand_chacha::ChaCha20Rng;
use rand_distr::Distribution;
use serde::{Deserialize, Serialize};
use tracing::info;

use crate::{
clock::Timestamp,
Expand Down Expand Up @@ -214,6 +215,7 @@ pub struct RawLateTXAttackConfig {
#[serde(rename_all = "kebab-case")]
pub enum NodeSelection {
Nodes(HashSet<String>),
StakeFraction(f64),
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -305,10 +307,7 @@ impl Topology {
Ok(())
}

pub fn select(
&mut self,
selection: &NodeSelection,
) -> impl Iterator<Item = &mut NodeConfiguration> {
pub fn select(&mut self, selection: &NodeSelection) -> Vec<&mut NodeConfiguration> {
let mut nodes = vec![];
match selection {
NodeSelection::Nodes(names) => {
Expand All @@ -318,8 +317,22 @@ impl Topology {
.filter(|node| names.contains(&node.name)),
);
}
NodeSelection::StakeFraction(fraction) => {
let mut all_nodes = self.nodes.iter_mut().collect::<Vec<_>>();
all_nodes.sort_by_key(|n| std::cmp::Reverse(n.stake));
let total_stake = all_nodes.iter().map(|n| n.stake).sum::<u64>();
let target_stake = ((total_stake as f64) * *fraction) as u64;
let mut stake_so_far = 0;
for node in all_nodes {
if stake_so_far >= target_stake {
break;
}
stake_so_far += node.stake;
nodes.push(node);
}
}
}
nodes.into_iter()
nodes
}
}

Expand Down Expand Up @@ -632,10 +645,12 @@ pub(crate) struct LateEBAttackConfig {

impl LateEBAttackConfig {
fn build(raw: &RawLateEBAttackConfig, topology: &mut Topology) -> Self {
let attackers = topology
.select(&raw.attackers)
.map(|node| node.id)
.collect();
let all_attackers = topology.select(&raw.attackers);
info!(
"Late EB attackers: {:?}",
all_attackers.iter().map(|n| &n.name).collect::<Vec<_>>()
);
let attackers = all_attackers.into_iter().map(|node| node.id).collect();
Self {
attackers,
propagation_delay: duration_ms(raw.propagation_delay_ms),
Expand All @@ -653,7 +668,12 @@ pub(crate) struct LateTXAttackConfig {

impl LateTXAttackConfig {
fn build(raw: &RawLateTXAttackConfig, topology: &mut Topology, params: &RawParameters) -> Self {
for attacker in topology.select(&raw.attackers) {
let all_attackers = topology.select(&raw.attackers);
info!(
"Late TX attackers: {:?}",
all_attackers.iter().map(|n| &n.name).collect::<Vec<_>>()
);
for attacker in all_attackers {
attacker.behaviours.withhold_txs = true;
}
Self {
Expand Down
Loading