Skip to content

Commit b48743e

Browse files
committed
sim-rs: RB includes oldest non-expired EB first
1 parent f78f1dc commit b48743e

File tree

5 files changed

+40
-16
lines changed

5 files changed

+40
-16
lines changed

data/simulation/config.d.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,7 @@ export interface Config {
9191
/**
9292
* The maximum age of EBs included in RBs:
9393
* an EB from slot `s` can only be included in RBs
94-
* up to slot `s+eb-max-age-slots`.
95-
*
96-
* Only supported by Haskell simulation. */
94+
* up to slot `s+eb-max-age-slots`. */
9795
"eb-max-age-slots": bigint;
9896

9997
// Vote Configuration

data/simulation/config.schema.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@
165165
},
166166
"eb-max-age-slots": {
167167
"additionalProperties": false,
168-
"description": "The maximum age of EBs included in RBs:\nan EB from slot `s` can only be included in RBs\nup to slot `s+eb-max-age-slots`.\n\nOnly supported by Haskell simulation.",
168+
"description": "The maximum age of EBs included in RBs:\nan EB from slot `s` can only be included in RBs\nup to slot `s+eb-max-age-slots`.",
169169
"properties": {},
170170
"type": "number"
171171
},

sim-rs/sim-cli/src/events.rs

+22-8
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ enum OutputFormat {
4040
pub struct EventMonitor {
4141
node_ids: Vec<NodeId>,
4242
pool_ids: Vec<NodeId>,
43-
stage_length: u64,
4443
maximum_ib_age: u64,
44+
maximum_eb_age: u64,
4545
events_source: mpsc::UnboundedReceiver<(Event, Timestamp)>,
4646
output_path: Option<PathBuf>,
4747
}
@@ -63,8 +63,8 @@ impl EventMonitor {
6363
Self {
6464
node_ids,
6565
pool_ids,
66-
stage_length,
6766
maximum_ib_age,
67+
maximum_eb_age: config.max_eb_age,
6868
events_source,
6969
output_path,
7070
}
@@ -85,6 +85,7 @@ impl EventMonitor {
8585
let mut ibs_containing_tx: BTreeMap<TransactionId, f64> = BTreeMap::new();
8686
let mut ebs_containing_ib: BTreeMap<InputBlockId, f64> = BTreeMap::new();
8787
let mut pending_ibs: BTreeSet<InputBlockId> = BTreeSet::new();
88+
let mut pending_ebs: BTreeSet<EndorserBlockId> = BTreeSet::new();
8889
let mut votes_per_bundle: BTreeMap<VoteBundleId, f64> = BTreeMap::new();
8990
let mut votes_per_pool: BTreeMap<NodeId, f64> =
9091
self.pool_ids.into_iter().map(|id| (id, 0.0)).collect();
@@ -99,6 +100,7 @@ impl EventMonitor {
99100
let mut generated_ibs = 0u64;
100101
let mut empty_ibs = 0u64;
101102
let mut expired_ibs = 0u64;
103+
let mut expired_ebs = 0u64;
102104
let mut generated_ebs = 0u64;
103105
let mut total_votes = 0u64;
104106
let mut leios_blocks_with_endorsements = 0u64;
@@ -152,19 +154,24 @@ impl EventMonitor {
152154
Event::Slot { number } => {
153155
info!("Slot {number} has begun.");
154156
total_slots = number + 1;
155-
if number % self.stage_length == 0 {
156-
let Some(oldest_live_stage) = number.checked_sub(self.maximum_ib_age)
157-
else {
158-
continue;
159-
};
157+
if let Some(oldest_live_ib_slot) = number.checked_sub(self.maximum_ib_age) {
160158
pending_ibs.retain(|ib| {
161-
if ib.slot < oldest_live_stage {
159+
if ib.slot < oldest_live_ib_slot {
162160
expired_ibs += 1;
163161
return false;
164162
}
165163
true
166164
});
167165
}
166+
if let Some(oldest_live_eb_slot) = number.checked_sub(self.maximum_eb_age) {
167+
pending_ebs.retain(|eb| {
168+
if eb.slot < oldest_live_eb_slot {
169+
expired_ebs += 1;
170+
return false;
171+
}
172+
true
173+
});
174+
}
168175
}
169176
Event::CpuTaskScheduled { .. } => {}
170177
Event::CpuTaskFinished { .. } => {}
@@ -196,6 +203,8 @@ impl EventMonitor {
196203
praos_txs += all_txs.len() as u64;
197204
if let Some(endorsement) = endorsement {
198205
leios_blocks_with_endorsements += 1;
206+
pending_ebs.retain(|eb| eb.slot != endorsement.eb.slot);
207+
199208
let block_leios_txs: Vec<_> = eb_ibs
200209
.get(&endorsement.eb)
201210
.unwrap()
@@ -283,6 +292,7 @@ impl EventMonitor {
283292
id, input_blocks, ..
284293
} => {
285294
generated_ebs += 1;
295+
pending_ebs.insert(id.clone());
286296
eb_ibs.insert(id.clone(), input_blocks.clone());
287297
for ib_id in &input_blocks {
288298
*ibs_in_eb.entry(id.clone()).or_default() += 1.0;
@@ -454,6 +464,10 @@ impl EventMonitor {
454464
"{} out of {} IBs expired before they reached an EB.",
455465
expired_ibs, generated_ibs,
456466
);
467+
info!(
468+
"{} out of {} EBs expired before an EB from their stage reached an RB.",
469+
expired_ebs, generated_ebs,
470+
);
457471
info!(
458472
"{} out of {} transaction(s) were included in at least one EB.",
459473
times_to_reach_eb.len(), txs.len(),

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

+3
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub struct RawParameters {
9595
pub eb_validation_cpu_time_ms: f64,
9696
pub eb_size_bytes_constant: u64,
9797
pub eb_size_bytes_per_ib: u64,
98+
pub eb_max_age_slots: u64,
9899

99100
// Vote configuration
100101
pub vote_generation_probability: f64,
@@ -402,6 +403,7 @@ pub struct SimConfiguration {
402403
pub nodes: Vec<NodeConfiguration>,
403404
pub links: Vec<LinkConfiguration>,
404405
pub stage_length: u64,
406+
pub max_eb_age: u64,
405407
pub(crate) relay_strategy: RelayStrategy,
406408
pub(crate) block_generation_probability: f64,
407409
pub(crate) ib_generation_probability: f64,
@@ -440,6 +442,7 @@ impl SimConfiguration {
440442
ib_diffusion_strategy: params.ib_diffusion_strategy,
441443
max_ib_requests_per_peer: 1,
442444
ib_shards: params.ib_shards,
445+
max_eb_age: params.eb_max_age_slots,
443446
cpu_times: CpuTimeConfig::new(&params),
444447
sizes: BlockSizeConfig::new(&params),
445448
transactions: TransactionConfig::new(&params),

sim-rs/sim-core/src/sim/node.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ impl Node {
649649
};
650650

651651
// Let's see if we are minting an RB
652-
let endorsement = self.choose_endorsed_block();
652+
let endorsement = self.choose_endorsed_block(slot);
653653
if let Some(endorsement) = &endorsement {
654654
// If we are, get all referenced TXs out of the mempool
655655
let Some(eb) = self.leios.ebs.get(&endorsement.eb) else {
@@ -707,9 +707,11 @@ impl Node {
707707
Ok(())
708708
}
709709

710-
fn choose_endorsed_block(&mut self) -> Option<Endorsement> {
710+
fn choose_endorsed_block(&mut self, slot: u64) -> Option<Endorsement> {
711711
// an EB is eligible for endorsement if it has this many votes
712712
let vote_threshold = self.sim_config.vote_threshold;
713+
// and it is not older than this
714+
let max_eb_age = self.sim_config.max_eb_age;
713715
// and if it is not in a pipeline already represented in the chain
714716
// (NB: all EBs produced in a pipeline are produced during the same slot)
715717
let forbidden_slots: HashSet<u64> = self
@@ -720,18 +722,25 @@ impl Node {
720722
.map(|e| e.eb.slot)
721723
.collect();
722724

725+
// Choose an EB based on, in order,
726+
// - the age of the EB (older EBs take priority)
727+
// - the TXs in the EB (more TXs take priority)
728+
// - the number of votes (more votes is better)
723729
let (&block, _) = self
724730
.leios
725731
.votes_by_eb
726732
.iter()
727733
.filter_map(|(eb, votes)| {
734+
if slot - eb.slot > max_eb_age || forbidden_slots.contains(&eb.slot) {
735+
return None;
736+
}
728737
let vote_count: usize = votes.values().sum();
729-
if (vote_count as u64) < vote_threshold || forbidden_slots.contains(&eb.slot) {
738+
if (vote_count as u64) < vote_threshold {
730739
return None;
731740
}
732741
Some((eb, vote_count))
733742
})
734-
.max_by_key(|(eb, votes)| (self.count_txs_in_eb(eb), *votes))?;
743+
.max_by_key(|(eb, votes)| (slot - eb.slot, self.count_txs_in_eb(eb), *votes))?;
735744

736745
let (block, votes) = self.leios.votes_by_eb.remove_entry(&block)?;
737746
let bytes = self.sim_config.sizes.cert(votes.len());

0 commit comments

Comments
 (0)