1use std::collections::BTreeSet;
2
3use serde::{Deserialize, Serialize};
4
5use crate::agent::AgentId;
6use crate::rng::DeterministicRng;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10pub struct FaultConfig {
11 pub max_delay_rounds: u8,
13 pub drop_rate_percent: u8,
15 pub duplicate_rate_percent: u8,
17 pub reorder_rate_percent: u8,
19 pub partition_rate_percent: u8,
21 pub freeze_rate_percent: u8,
23 pub freeze_duration_rounds: u8,
25}
26
27impl Default for FaultConfig {
28 fn default() -> Self {
29 Self {
30 max_delay_rounds: 2,
31 drop_rate_percent: 5,
32 duplicate_rate_percent: 3,
33 reorder_rate_percent: 5,
34 partition_rate_percent: 2,
35 freeze_rate_percent: 2,
36 freeze_duration_rounds: 2,
37 }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
43pub struct NetworkMessage {
44 pub from: AgentId,
46 pub to: AgentId,
48 pub event_id: u64,
50 pub seq: u64,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55struct PendingMessage {
56 deliver_at_round: u64,
57 message: NetworkMessage,
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub struct SendOutcome {
63 pub dropped: bool,
65 pub duplicated: bool,
67 pub delay_rounds: u8,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct DeliverOutcome {
74 pub delivered: Vec<NetworkMessage>,
76 pub reordered: bool,
78}
79
80#[derive(Debug, Clone, PartialEq, Eq)]
82pub struct SimulatedNetwork {
83 pending: Vec<PendingMessage>,
84 partitioned_agents: BTreeSet<AgentId>,
85 fault: FaultConfig,
86}
87
88impl SimulatedNetwork {
89 #[must_use]
91 pub const fn new(fault: FaultConfig) -> Self {
92 Self {
93 pending: Vec::new(),
94 partitioned_agents: BTreeSet::new(),
95 fault,
96 }
97 }
98
99 #[must_use]
101 pub const fn fault_config(&self) -> FaultConfig {
102 self.fault
103 }
104
105 pub fn set_partitioned(&mut self, agent: AgentId, isolated: bool) {
107 if isolated {
108 self.partitioned_agents.insert(agent);
109 } else {
110 self.partitioned_agents.remove(&agent);
111 }
112 }
113
114 #[must_use]
116 pub fn is_partitioned(&self, agent: AgentId) -> bool {
117 self.partitioned_agents.contains(&agent)
118 }
119
120 #[must_use]
122 pub const fn pending_len(&self) -> usize {
123 self.pending.len()
124 }
125
126 #[must_use]
128 pub fn send(
129 &mut self,
130 message: NetworkMessage,
131 round: u64,
132 rng: &mut DeterministicRng,
133 ) -> SendOutcome {
134 if self.is_partitioned(message.from) || self.is_partitioned(message.to) {
135 return SendOutcome {
136 dropped: true,
137 duplicated: false,
138 delay_rounds: 0,
139 };
140 }
141
142 if rng.hit_rate_percent(self.fault.drop_rate_percent) {
143 return SendOutcome {
144 dropped: true,
145 duplicated: false,
146 delay_rounds: 0,
147 };
148 }
149
150 let delay_bound = u64::from(self.fault.max_delay_rounds).saturating_add(1);
151 let primary_delay_u64 = rng.next_bounded(delay_bound);
152 let primary_delay = u8::try_from(primary_delay_u64).unwrap_or(self.fault.max_delay_rounds);
153
154 self.pending.push(PendingMessage {
155 deliver_at_round: round.saturating_add(u64::from(primary_delay)),
156 message,
157 });
158
159 let duplicated = rng.hit_rate_percent(self.fault.duplicate_rate_percent);
160 if duplicated {
161 self.pending.push(PendingMessage {
162 deliver_at_round: round.saturating_add(u64::from(primary_delay)),
163 message,
164 });
165 }
166
167 SendOutcome {
168 dropped: false,
169 duplicated,
170 delay_rounds: primary_delay,
171 }
172 }
173
174 #[must_use]
176 pub fn deliver_ready(&mut self, round: u64, rng: &mut DeterministicRng) -> DeliverOutcome {
177 let mut ready = Vec::new();
178 let mut future = Vec::new();
179
180 for pending in self.pending.drain(..) {
181 if pending.deliver_at_round <= round {
182 ready.push(pending.message);
183 } else {
184 future.push(pending);
185 }
186 }
187
188 self.pending = future;
189
190 let should_reorder =
191 ready.len() > 1 && rng.hit_rate_percent(self.fault.reorder_rate_percent);
192 if should_reorder {
193 ready.reverse();
194 }
195
196 DeliverOutcome {
197 delivered: ready,
198 reordered: should_reorder,
199 }
200 }
201}