Skip to content

Commit f1c9394

Browse files
committed
Merge branch 'main' into feat/instrument_fjall_calls
2 parents 7073d93 + 3134785 commit f1c9394

3 files changed

Lines changed: 56 additions & 7 deletions

File tree

src/mempool/dissemination.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use crate::model::SharedRunContext;
3838
const REQUEST_BACKOFF_INITIAL: Duration = Duration::from_secs(1);
3939
const REQUEST_BACKOFF_MAX: Duration = Duration::from_secs(8);
4040
const HOUSEKEEPING_INTERVAL: Duration = Duration::from_millis(400);
41+
const RESEND_MIN_INTERVAL: Duration = Duration::from_secs(2);
4142
#[cfg(not(test))]
4243
const SYNC_REPLY_DEBOUNCE: Duration = Duration::from_secs(2);
4344
#[cfg(test)]
@@ -847,7 +848,11 @@ impl DisseminationManager {
847848
return Ok(false);
848849
}
849850

850-
let filtered_targets = candidate_targets;
851+
let now = TimestampMsClock::now();
852+
let filtered_targets: HashSet<ValidatorPublicKey> = candidate_targets
853+
.into_iter()
854+
.filter(|peer| self.can_send_to_peer(lane_id, dp_hash, peer, now.clone()))
855+
.collect();
851856
if filtered_targets.is_empty() {
852857
return Ok(false);
853858
}
@@ -991,6 +996,33 @@ impl DisseminationManager {
991996
.insert((lane_id.clone(), dp_hash.clone()), now);
992997
}
993998

999+
fn can_send_to_peer(
1000+
&self,
1001+
lane_id: &LaneId,
1002+
dp_hash: &DataProposalHash,
1003+
peer: &ValidatorPublicKey,
1004+
now: TimestampMs,
1005+
) -> bool {
1006+
let key = (lane_id.clone(), dp_hash.clone(), peer.clone());
1007+
let evidence = self.knowledge.by_dp.get(&key);
1008+
let should_rate_limit = matches!(
1009+
evidence,
1010+
Some(EvidenceState::WeakHas)
1011+
| Some(EvidenceState::StrongHas)
1012+
| Some(EvidenceState::ObservedHas)
1013+
);
1014+
1015+
if !should_rate_limit {
1016+
return true;
1017+
}
1018+
1019+
self.knowledge
1020+
.by_peer
1021+
.get(peer)
1022+
.and_then(|state| state.last_dp_sent.get(&(lane_id.clone(), dp_hash.clone())))
1023+
.is_none_or(|last_sent| now - last_sent.clone() >= RESEND_MIN_INTERVAL)
1024+
}
1025+
9941026
fn should_debounce_sync_reply(
9951027
&self,
9961028
lane_id: &LaneId,
@@ -1010,6 +1042,19 @@ impl DisseminationManager {
10101042
self.owned_lanes.insert(lane_id);
10111043
}
10121044

1045+
#[cfg(test)]
1046+
pub(crate) fn clear_last_dp_sent_for_test(
1047+
&mut self,
1048+
lane_id: &LaneId,
1049+
dp_hash: &DataProposalHash,
1050+
) {
1051+
for peer_state in self.knowledge.by_peer.values_mut() {
1052+
peer_state
1053+
.last_dp_sent
1054+
.remove(&(lane_id.clone(), dp_hash.clone()));
1055+
}
1056+
}
1057+
10131058
#[cfg(test)]
10141059
pub(crate) async fn process_sync_requests_and_replies_for_test(&mut self) -> Result<()> {
10151060
self.process_sync_requests_and_replies().await

src/mempool/own_lane.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -939,27 +939,27 @@ pub mod test {
939939
ctx1.submit_tx(&tx2);
940940
ctx1.timer_tick().await?;
941941

942-
// This ends up disseminating 4 DPs for now - when we receive it, then on tick, then the other, then on tick.
942+
// With resend gating, each new DP is disseminated once on creation in this flow.
943943
let mut dps = vec![];
944-
for _ in 0..4 {
944+
for _ in 0..2 {
945945
match ctx1.assert_broadcast("DataProposal").await.msg {
946946
MempoolNetMessage::DataProposal(_, hash, dp, _) => dps.push((hash, dp)),
947947
_ => panic!("Expected DataProposal message"),
948948
}
949949
}
950950

951-
assert!(dps.len() == 4, "Should have 4 DataProposals");
951+
assert!(dps.len() == 2, "Should have 2 DataProposals");
952952
assert_eq!(dps[0].1.txs, vec![tx1.clone()]);
953-
assert_eq!(dps[1].1.txs, vec![tx1.clone()]);
954-
assert_eq!(dps[2].1.txs, vec![tx2.clone()]);
955-
assert_eq!(dps[3].1.txs, vec![tx1.clone()]);
953+
assert_eq!(dps[1].1.txs, vec![tx2.clone()]);
956954

957955
// Redisseminate the oldest pending DataProposal
958956
// TODO: implement this as more of an integration test?
959957
let (oldest_hash, _) = dps
960958
.iter()
961959
.find(|(_, dp)| dp.parent_data_proposal_hash.is_lane_root())
962960
.expect("oldest dp should exist");
961+
ctx1.dissemination_manager
962+
.clear_last_dp_sent_for_test(&ctx1.own_lane(), oldest_hash);
963963
ctx1.maybe_disseminate_dp(&ctx1.own_lane(), oldest_hash)
964964
.expect("disseminate");
965965

src/mempool/tests/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,10 @@ async fn test_redisseminate_owned_lanes_sends_oldest_first() -> Result<()> {
604604
// Drain any prior outbound messages
605605
while ctx.out_receiver.try_recv().is_ok() {}
606606

607+
// Allow an immediate resend in this deterministic test.
608+
ctx.dissemination_manager
609+
.clear_last_dp_sent_for_test(&lane_id, &dp1_hash);
610+
607611
ctx.dissemination_manager
608612
.redisseminate_owned_lanes()
609613
.await?;

0 commit comments

Comments
 (0)