Skip to content

Commit a633039

Browse files
committed
sim-rs: fix mempool behavior with EBs propagated before TXs
1 parent 3225f33 commit a633039

File tree

2 files changed

+53
-38
lines changed

2 files changed

+53
-38
lines changed

sim-rs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
## Linear Leios
66
- 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.
7+
- Add TXs to the mempool, even if they belong to an EB we've already seen.
78

89
# v0.1.0
910

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

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -456,32 +456,20 @@ impl LinearLeiosNode {
456456
{
457457
return;
458458
}
459+
459460
let referenced_by_eb = self.acknowledge_tx(&tx);
460-
if !referenced_by_eb {
461-
let rb_ref = self.latest_rb().map(|rb| rb.header.id);
462-
let ledger_state = self.resolve_ledger_state(rb_ref);
463-
if ledger_state.is_some_and(|ls| ls.spent_inputs.contains(&tx.input_id)) {
464-
// Ignoring a TX which conflicts with something already onchain
465-
return;
466-
}
467-
if self
468-
.praos
469-
.mempool
470-
.values()
471-
.any(|mempool_tx| mempool_tx.input_id == tx.input_id)
472-
{
473-
// Ignoring a TX which conflicts with the current mempool contents.
474-
return;
475-
}
476-
self.praos.mempool.insert(tx.id, tx.clone());
477-
}
461+
let added_to_mempool = self.try_add_tx_to_mempool(&tx);
478462

463+
// If we added the TX to our mempool, we want to propagate it so our peers can as well.
464+
// If it was referenced by an EB, we want to propagate it so our peers have the full EB.
479465
// TODO: should send to producers instead (make configurable)
480-
for peer in &self.consumers {
481-
if *peer == from {
482-
continue;
466+
if referenced_by_eb || added_to_mempool {
467+
for peer in &self.consumers {
468+
if *peer == from {
469+
continue;
470+
}
471+
self.queued.send_to(*peer, Message::AnnounceTx(id));
483472
}
484-
self.queued.send_to(*peer, Message::AnnounceTx(id));
485473
}
486474
}
487475

@@ -1318,6 +1306,26 @@ impl LinearLeiosNode {
13181306

13191307
// Ledger/mempool operations
13201308
impl LinearLeiosNode {
1309+
fn try_add_tx_to_mempool(&mut self, tx: &Arc<Transaction>) -> bool {
1310+
let ledger_state = self.resolve_ledger_state(self.latest_rb().map(|rb| rb.header.id));
1311+
if ledger_state.spent_inputs.contains(&tx.input_id) {
1312+
// This TX conflicts with something already on-chain
1313+
return false;
1314+
}
1315+
1316+
if self
1317+
.praos
1318+
.mempool
1319+
.values()
1320+
.any(|t| t.input_id == tx.input_id)
1321+
{
1322+
// This TX conflicts with something already in the mempool
1323+
return false;
1324+
}
1325+
self.praos.mempool.insert(tx.id, tx.clone());
1326+
true
1327+
}
1328+
13211329
fn sample_from_mempool(
13221330
&mut self,
13231331
txs: &mut Vec<Arc<Transaction>>,
@@ -1373,12 +1381,12 @@ impl LinearLeiosNode {
13731381
.retain(|_, tx| !inputs.contains(&tx.input_id));
13741382
}
13751383

1376-
fn resolve_ledger_state(&mut self, rb_ref: Option<BlockId>) -> Option<Arc<LedgerState>> {
1384+
fn resolve_ledger_state(&mut self, rb_ref: Option<BlockId>) -> Arc<LedgerState> {
13771385
let Some(block_id) = rb_ref else {
1378-
return Some(Arc::new(LedgerState::default()));
1386+
return Arc::new(LedgerState::default());
13791387
};
13801388
if let Some(state) = self.ledger_states.get(&block_id) {
1381-
return Some(state.clone());
1389+
return state.clone();
13821390
};
13831391

13841392
let mut state = self
@@ -1388,6 +1396,7 @@ impl LinearLeiosNode {
13881396
.unwrap_or_default();
13891397

13901398
let mut block_queue = vec![block_id];
1399+
let mut complete = true;
13911400
while let Some(block_id) = block_queue.pop() {
13921401
if !state.seen_blocks.insert(block_id) {
13931402
continue;
@@ -1404,24 +1413,29 @@ impl LinearLeiosNode {
14041413
}
14051414

14061415
if let Some(endorsement) = &rb.endorsement {
1407-
let Some(EndorserBlockView::Received {
1408-
eb,
1409-
validated: true,
1410-
..
1411-
}) = self.leios.ebs.get(&endorsement.eb)
1412-
else {
1413-
// We haven't validated the EB yet, so we don't know the ledger state
1414-
return None;
1415-
};
1416-
for tx in &eb.txs {
1417-
state.spent_inputs.insert(tx.input_id);
1416+
match self.leios.ebs.get(&endorsement.eb) {
1417+
Some(EndorserBlockView::Received { eb, .. }) => {
1418+
for tx in &eb.txs {
1419+
if self.has_tx(tx.id) {
1420+
state.spent_inputs.insert(tx.input_id);
1421+
} else {
1422+
complete = false;
1423+
}
1424+
}
1425+
}
1426+
_ => {
1427+
// We haven't validated the EB yet, so we don't know the full ledger state
1428+
complete = false;
1429+
}
14181430
}
14191431
}
14201432
}
14211433

14221434
let state = Arc::new(state);
1423-
self.ledger_states.insert(block_id, state.clone());
1424-
Some(state)
1435+
if complete {
1436+
self.ledger_states.insert(block_id, state.clone());
1437+
}
1438+
state
14251439
}
14261440
}
14271441

0 commit comments

Comments
 (0)