Skip to content

Commit 900a670

Browse files
committed
sim-rs: simplify mempool behavior
1 parent 112ca6f commit 900a670

File tree

2 files changed

+63
-61
lines changed

2 files changed

+63
-61
lines changed

sim-rs/implementations/LINEAR_LEIOS.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,21 @@ Whenever a node creates an RB, it also creates an EB. The RB header contains a r
1111

1212
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).
1313

14-
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 (note that this should be redundant based on the procedure below).
15-
1614
When a node receives an EB body, it runs lightweight validation and then propagates the body to peers. After this lightweight validation, it runs more expensive complete validation (presumably at the TX level) before voting.
1715

1816
To detect equivocation, a node will wait until at least `3 * Δhdr` after an EB was generated before voting for it.
1917

20-
When voting, a node runs a VRF lottery to decide how many times it can vote for that EB; if it has any votes, it will transmit them to all peers. If the EB has been certified after `L_vote` + `L_diff` slots have passed, the node removes all of its transactions from the mempool (under the assumption that the EB will make it on-chain).
18+
When voting, a node runs a VRF lottery to decide how many times it can vote for that EB; if it has any votes, it will transmit them to all peers.
19+
20+
## Mempool behavior
21+
22+
When a node creates an RB, it will follow these steps in order:
23+
1. Try to produce a cert for the parent RB's EB.
24+
1. If this succeeds, remove all of this EB's transactions from its mempool.
25+
2. Fill the RB body with transactions from its mempool
26+
3. Create a new EB, filled with transactions from its mempool WITHOUT removing those transactions from the mempool.
27+
28+
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.
2129

2230
## New parameters
2331

sim-rs/sim-core/src/sim/linear_leios.rs

Lines changed: 52 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,6 @@ impl NodeImpl for LinearLeiosNode {
325325
}
326326

327327
fn handle_new_slot(&mut self, slot: u64) -> EventResult {
328-
self.process_certified_ebs(slot);
329328
self.try_generate_rb(slot);
330329

331330
std::mem::take(&mut self.queued)
@@ -482,6 +481,41 @@ impl LinearLeiosNode {
482481
return;
483482
};
484483

484+
let parent = self.latest_rb().map(|rb| rb.header.id);
485+
let endorsement = parent.and_then(|rb_id| {
486+
if rb_id.slot
487+
+ self.sim_config.linear_vote_stage_length
488+
+ self.sim_config.linear_diffuse_stage_length
489+
> slot
490+
{
491+
// This RB was generated too quickly after another; hasn't been time to gather all the votes.
492+
// No endorsement.
493+
return None;
494+
}
495+
496+
let eb_id = self.leios.ebs_by_rb.get(&rb_id)?;
497+
let votes = self.leios.votes_by_eb.get(eb_id)?;
498+
let total_votes = votes.values().copied().sum::<usize>();
499+
if (total_votes as u64) < self.sim_config.vote_threshold {
500+
// Not enough votes. No endorsement.
501+
return None;
502+
}
503+
504+
let endorsement = Endorsement {
505+
eb: *eb_id,
506+
size_bytes: self.sim_config.sizes.cert(votes.len()),
507+
votes: votes.clone(),
508+
};
509+
510+
// We're endorsing this EB, so consider all of its transactions part of the ledger state
511+
let Some(EndorserBlockView::Received { eb }) = self.leios.ebs.get(eb_id) else {
512+
return None;
513+
};
514+
self.remove_eb_txs_from_mempool(&eb.clone());
515+
516+
Some(endorsement)
517+
});
518+
485519
let mut rb_transactions = vec![];
486520
if self.sim_config.praos_fallback {
487521
if let TransactionConfig::Mock(config) = &self.sim_config.transactions {
@@ -490,7 +524,11 @@ impl LinearLeiosNode {
490524
self.tracker.track_transaction_generated(&tx, self.id);
491525
rb_transactions.push(Arc::new(tx));
492526
} else {
493-
self.sample_from_mempool(&mut rb_transactions, self.sim_config.max_block_size);
527+
self.sample_from_mempool(
528+
&mut rb_transactions,
529+
self.sim_config.max_block_size,
530+
true,
531+
);
494532
}
495533
}
496534

@@ -516,36 +554,9 @@ impl LinearLeiosNode {
516554
eb_transactions.push(Arc::new(tx));
517555
}
518556
} else {
519-
self.sample_from_mempool(&mut eb_transactions, self.sim_config.max_eb_size);
557+
self.sample_from_mempool(&mut eb_transactions, self.sim_config.max_eb_size, false);
520558
}
521559

522-
let parent = self.latest_rb().map(|rb| rb.header.id);
523-
let endorsement = parent.and_then(|rb_id| {
524-
if rb_id.slot
525-
+ self.sim_config.linear_vote_stage_length
526-
+ self.sim_config.linear_diffuse_stage_length
527-
> slot
528-
{
529-
// This RB was generated too quickly after another; hasn't been time to gather all the votes.
530-
// No endorsement.
531-
return None;
532-
}
533-
534-
let eb_id = self.leios.ebs_by_rb.get(&rb_id)?;
535-
let votes = self.leios.votes_by_eb.get(eb_id)?;
536-
let total_votes = votes.values().copied().sum::<usize>();
537-
if (total_votes as u64) < self.sim_config.vote_threshold {
538-
// Not enough votes. No endorsement.
539-
return None;
540-
}
541-
542-
Some(Endorsement {
543-
eb: *eb_id,
544-
size_bytes: self.sim_config.sizes.cert(votes.len()),
545-
votes: votes.clone(),
546-
})
547-
});
548-
549560
let rb = RankingBlock {
550561
header: RankingBlockHeader {
551562
id: BlockId {
@@ -887,32 +898,6 @@ impl LinearLeiosNode {
887898
fn finish_validating_eb(&mut self, eb: Arc<EndorserBlock>, seen: Timestamp) {
888899
self.vote_for_endorser_block(&eb, seen);
889900
}
890-
891-
fn process_certified_ebs(&mut self, slot: u64) {
892-
let Some(eb_creation_slot) = slot.checked_sub(
893-
self.sim_config.linear_vote_stage_length + self.sim_config.linear_diffuse_stage_length,
894-
) else {
895-
return;
896-
};
897-
898-
let Some(rb) = self.latest_rb() else {
899-
return;
900-
};
901-
902-
if rb.header.id.slot != eb_creation_slot {
903-
return;
904-
}
905-
// The EB on the head of the chain has had enough time to get certified.
906-
907-
let eb_id = rb.header.eb_announcement;
908-
if self.leios.certified_ebs.contains(&eb_id) {
909-
// This certified EB is eventually going on-chain.
910-
// Get its contents out of the mempool.
911-
if let Some(EndorserBlockView::Received { eb }) = self.leios.ebs.get(&eb_id) {
912-
self.remove_eb_txs_from_mempool(&eb.clone());
913-
};
914-
}
915-
}
916901
}
917902

918903
// EB withholding:
@@ -1168,7 +1153,12 @@ impl LinearLeiosNode {
11681153

11691154
// Ledger/mempool operations
11701155
impl LinearLeiosNode {
1171-
fn sample_from_mempool(&mut self, txs: &mut Vec<Arc<Transaction>>, max_size: u64) {
1156+
fn sample_from_mempool(
1157+
&mut self,
1158+
txs: &mut Vec<Arc<Transaction>>,
1159+
max_size: u64,
1160+
remove: bool,
1161+
) {
11721162
let mut size = txs.iter().map(|tx| tx.bytes).sum::<u64>();
11731163
let mut candidates: Vec<_> = self.praos.mempool.keys().copied().collect();
11741164
if matches!(
@@ -1187,7 +1177,11 @@ impl LinearLeiosNode {
11871177
break;
11881178
}
11891179
size += tx.bytes;
1190-
txs.push(self.praos.mempool.remove(&id).unwrap());
1180+
if remove {
1181+
txs.push(self.praos.mempool.remove(&id).unwrap());
1182+
} else {
1183+
txs.push(tx.clone());
1184+
}
11911185
}
11921186
}
11931187

0 commit comments

Comments
 (0)