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
16 changes: 16 additions & 0 deletions sim-rs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## v1.3.0

### Linear Leios

- Respect timings according to the latest CIP draft:
- RB headers must be received within `Delta_header`
- Voting must wait until `3 * Delta_header`
- Voting must finish by `3 * Delta_header + L_vote`
- EB cannot be referenced until after `3 * Delta_header + L_vote + L_diff`
- Don't include transactions directly in an RB if it also includes an endorsement
- Don't produce empty EBs

### Other

- Fix linter warnings from newer rust version

## v1.2.0

### All Leios variants
Expand Down
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.

8 changes: 4 additions & 4 deletions sim-rs/implementations/LINEAR_LEIOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The log file schema is currently identical to every other variant (though `pipel

## Description

Whenever a node creates an RB, it also creates an EB. The RB header contains a reference to this new EB. If the RB producer has a certificate for the parent RB’s EB, it will include that certificate in the RB body.
Whenever a node creates an RB, it also has an opportunity to create an EB (though it will not produce empty EBs). The RB header contains a reference to this new EB. If the RB producer has a certificate for the parent RB’s EB, and at least `3 * Δhdr + L_vote + L_diff` has passed since that RB was created, it will include that certificate in the RB body.

RB headers are diffused separately from bodies. When a node receives an RB header, it checks whether that RB should be the new head of its chain. If so, it will request the RB body and the referenced EB (from the first peer which announces them).

Expand Down Expand Up @@ -36,17 +36,17 @@ A node will wait at least `3 * Δhdr` after an EB was created before voting for
For a node to vote for an EB, all of the following must be true.
- The RB which announced that EB is currently the head of that node's chain.
- The node received the relevant RB header at most `Δhdr` after it was created.
- The node received the EB body itself at most `L_vote` after it was created.
- The node finished validating the EB body itself at most `3 * Δhdr` + `L_vote` after it was created.

## Mempool behavior

When a node creates an RB, it will follow these steps in order:
1. Try to produce a cert for the parent RB's EB.
1. If this succeeds, remove all of this EB's transactions from its mempool.
2. Create an empty RB and empty EB.
2. Create an empty RB.
3. If we have received and fully validated the RB, along with all referenced transactions,
1. Fill the RB body with transactions from our mempool
2. Fill the EB with transactions from our mempool WITHOUT removing those transactions from the mempool.
2. Build an EB with transactions from our mempool WITHOUT removing those transactions from the mempool.

When a node receives an RB body, it immediately removes all referenced/conflicting transactions from its mempool. If the RB has an EB certificate, it also removes that EB’s transactions from its mempool. If the certified EB arrives after the RB body, we remove its TXs from the mempool once it arrives.

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 = "1.2.0"
version = "1.3.0"
edition = "2024"
default-run = "sim-cli"
rust-version = "1.88"
Expand Down
8 changes: 4 additions & 4 deletions sim-rs/sim-cli/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ impl EventMonitor {
remove_zero_decimal: Some(true),
});

if let Some(path) = &self.output_path {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).await?;
}
if let Some(path) = &self.output_path
&& let Some(parent) = path.parent()
{
fs::create_dir_all(parent).await?;
}

let mut output = match self.output_path.as_mut() {
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 = "1.2.0"
version = "1.3.0"
edition = "2024"
rust-version = "1.88"

Expand Down
6 changes: 3 additions & 3 deletions sim-rs/sim-core/src/clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,15 @@ impl ClockBarrier {
self.tasks.clone()
}

pub fn wait_until(&mut self, timestamp: Timestamp) -> Waiter {
pub fn wait_until(&mut self, timestamp: Timestamp) -> Waiter<'_> {
self.wait(Some(timestamp.with_resolution(self.timestamp_resolution)))
}

pub fn wait_forever(&mut self) -> Waiter {
pub fn wait_forever(&mut self) -> Waiter<'_> {
self.wait(None)
}

fn wait(&mut self, until: Option<Timestamp>) -> Waiter {
fn wait(&mut self, until: Option<Timestamp>) -> Waiter<'_> {
let (tx, rx) = oneshot::channel();
let done = until.is_some_and(|ts| ts == self.now())
|| self
Expand Down
34 changes: 18 additions & 16 deletions sim-rs/sim-core/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ use crate::{
clock::{Clock, Timestamp},
config::{NodeConfiguration, NodeId},
model::{
Block, BlockId, CpuTaskId, EndorserBlockId, InputBlockId, LinearEndorserBlock,
LinearRankingBlock, NoVoteReason, Transaction, TransactionId, TransactionLostReason,
VoteBundle, VoteBundleId,
Block, BlockId, CpuTaskId, EndorserBlockId, InputBlockId, LinearRankingBlock, NoVoteReason,
Transaction, TransactionId, TransactionLostReason, VoteBundle, VoteBundleId,
},
};

Expand Down Expand Up @@ -44,7 +43,7 @@ impl Eq for Node {}

impl PartialOrd for Node {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.id.cmp(&other.id))
Some(self.cmp(other))
}
}

Expand Down Expand Up @@ -407,7 +406,7 @@ impl EventTracker {
});
}

pub fn track_linear_rb_generated(&self, rb: &LinearRankingBlock, eb: &LinearEndorserBlock) {
pub fn track_linear_rb_generated(&self, rb: &LinearRankingBlock) {
self.send(Event::RBGenerated {
id: self.to_block(rb.header.id),
slot: rb.header.id.slot,
Expand All @@ -431,17 +430,6 @@ impl EventTracker {
}),
transactions: rb.transactions.iter().map(|tx| tx.id).collect(),
});
self.send(Event::EBGenerated {
id: self.to_endorser_block(eb.id()),
slot: eb.slot,
pipeline: 0,
producer: self.to_node(eb.producer),
shard: 0,
size_bytes: eb.bytes,
transactions: eb.txs.iter().map(|tx| BlockRef { id: tx.id }).collect(),
input_blocks: vec![],
endorser_blocks: vec![],
});
}

pub fn track_praos_block_sent(&self, block: &Block, sender: NodeId, recipient: NodeId) {
Expand Down Expand Up @@ -649,6 +637,20 @@ impl EventTracker {
});
}

pub fn track_linear_eb_generated(&self, block: &crate::model::LinearEndorserBlock) {
self.send(Event::EBGenerated {
id: self.to_endorser_block(block.id()),
slot: block.slot,
pipeline: 0,
producer: self.to_node(block.producer),
shard: 0,
size_bytes: block.bytes,
transactions: block.txs.iter().map(|tx| BlockRef { id: tx.id }).collect(),
input_blocks: vec![],
endorser_blocks: vec![],
});
}

pub fn track_no_eb_generated(&self, node: NodeId, slot: u64) {
self.send(Event::NoEBGenerated {
node: self.to_node(node),
Expand Down
2 changes: 1 addition & 1 deletion sim-rs/sim-core/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub struct LinearRankingBlockHeader {
pub vrf: u64,
pub parent: Option<BlockId>,
pub bytes: u64,
pub eb_announcement: EndorserBlockId,
pub eb_announcement: Option<EndorserBlockId>,
}

#[derive(Clone, Debug)]
Expand Down
12 changes: 6 additions & 6 deletions sim-rs/sim-core/src/sim/leios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,12 +1114,12 @@ impl LeiosNode {
}

fn receive_request_ib_header(&mut self, from: NodeId, id: InputBlockId) {
if let Some(ib) = self.leios.ibs.get(&id) {
if let Some(header) = ib.header() {
let have_body = matches!(ib, InputBlockState::Received { .. });
self.queued
.send_to(from, SimulationMessage::IBHeader(header.clone(), have_body));
}
if let Some(ib) = self.leios.ibs.get(&id)
&& let Some(header) = ib.header()
{
let have_body = matches!(ib, InputBlockState::Received { .. });
self.queued
.send_to(from, SimulationMessage::IBHeader(header.clone(), have_body));
}
}

Expand Down
Loading