@feltdb/core 0.4.11 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/cli/commands.js +5 -2
  2. package/dist/cli/index.js +1 -1
  3. package/dist/create/cli.js +16 -1
  4. package/dist/create/create.js +30 -16
  5. package/dist/create/docker-compose-generator.js +48 -9
  6. package/dist/create/package-versions.js +1 -1
  7. package/dist/create/server-source/Cargo.lock +2238 -0
  8. package/dist/create/server-source/Cargo.toml +7 -0
  9. package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
  10. package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
  11. package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
  12. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
  13. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
  14. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
  15. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
  16. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
  17. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
  18. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
  19. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
  20. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
  21. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
  22. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
  23. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
  24. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
  25. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
  26. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
  27. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
  28. package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
  29. package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
  30. package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
  31. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
  32. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
  33. package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
  34. package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
  35. package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
  36. package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
  37. package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
  38. package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
  39. package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
  40. package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
  41. package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
  42. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
  43. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
  44. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
  45. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
  46. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
  47. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
  48. package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
  49. package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
  50. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
  51. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
  52. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
  53. package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
  54. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
  55. package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
  56. package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
  57. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
  58. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
  59. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
  60. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
  61. package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
  62. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
  63. package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
  64. package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
  65. package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
  66. package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
  67. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
  68. package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
  69. package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
  70. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
  71. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
  72. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
  73. package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
  74. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
  75. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
  76. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
  77. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
  78. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
  79. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
  80. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
  81. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
  82. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
  83. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
  84. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
  85. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
  86. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
  87. package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
  88. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
  89. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
  90. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
  91. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
  92. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
  93. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
  94. package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
  95. package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
  96. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
  97. package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
  98. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
  99. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
  100. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
  101. package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
  102. package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
  103. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
  104. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
  105. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
  106. package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
  107. package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
  108. package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
  109. package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
  110. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
  111. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
  112. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
  113. package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
  114. package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
  115. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
  116. package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
  117. package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
  118. package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
  119. package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
  120. package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
  121. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
  122. package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
  123. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
  124. package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
  125. package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
  126. package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
  127. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
  128. package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
  129. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
  130. package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
  131. package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
  132. package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
  133. package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
  134. package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
  135. package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
  136. package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
  137. package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
  138. package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
  139. package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
  140. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
  141. package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
  142. package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
  143. package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
  144. package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
  145. package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
  146. package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
  147. package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
  148. package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
  149. package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
  150. package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
  151. package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
  152. package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
  153. package/dist/flowspec.d.ts +2 -0
  154. package/dist/flowspec.d.ts.map +1 -1
  155. package/dist/flowspec.js +28 -4
  156. package/dist/state-contract.d.ts +7 -1
  157. package/dist/state-contract.d.ts.map +1 -1
  158. package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
  159. package/dist/studio/components/index.js +1 -1
  160. package/dist/studio/{components-q43NSTTH.js → components-bHTARBin.js} +160 -89
  161. package/dist/studio/index.js +31 -28
  162. package/dist/studio-app/assets/{index-DZpBoVMp.js → index-BqKquLuU.js} +8 -8
  163. package/dist/studio-app/index.html +1 -1
  164. package/package.json +1 -1
@@ -0,0 +1,566 @@
1
+ /// Adversarial Transport Layer (Gate 8)
2
+ ///
3
+ /// Network fault injection that proves FeltDB converges despite:
4
+ /// delivery delays, reordering, duplication, drops,
5
+ /// partitions, asymmetric connectivity, and arbitrary restarts
6
+ ///
7
+ /// Critical constraint: Transport has NO knowledge of FeltDB's replication logic.
8
+ /// Transport only controls what happens to a message:
9
+ /// send → maybe delay → maybe duplicate → maybe drop → eventually deliver
10
+ ///
11
+ /// FeltDB must converge itself. Simulator cannot help.
12
+
13
+ use std::collections::{HashMap, VecDeque};
14
+
15
+ /// Reproducible fault seed
16
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
17
+ pub struct FaultSeed(pub u64);
18
+
19
+ /// Unique message identifier (for tracking through faults)
20
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
21
+ pub struct MessageId(pub u64);
22
+
23
+ /// Node identifier
24
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
25
+ pub struct NodeId(pub u64);
26
+
27
+ /// Connection between two nodes
28
+ #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
29
+ pub struct ConnectionId {
30
+ pub from: NodeId,
31
+ pub to: NodeId,
32
+ }
33
+
34
+ /// State of a network link
35
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
36
+ pub enum LinkState {
37
+ /// Connected, messages delivered
38
+ Connected,
39
+ /// Partitioned, all messages dropped
40
+ Partitioned,
41
+ }
42
+
43
+ /// Explicit network event (deterministic from seed)
44
+ #[derive(Clone, Debug, Eq, PartialEq)]
45
+ pub enum NetworkEvent {
46
+ /// Delay a message by N ticks
47
+ Delay {
48
+ message_id: MessageId,
49
+ ticks: u64,
50
+ },
51
+ /// Drop a message permanently
52
+ Drop {
53
+ message_id: MessageId,
54
+ },
55
+ /// Duplicate a message
56
+ Duplicate {
57
+ message_id: MessageId,
58
+ },
59
+ /// Partition a directional link
60
+ Partition {
61
+ from: NodeId,
62
+ to: NodeId,
63
+ },
64
+ /// Heal a directional link
65
+ Heal {
66
+ from: NodeId,
67
+ to: NodeId,
68
+ },
69
+ /// Reorder messages on a connection
70
+ Reorder {
71
+ connection: ConnectionId,
72
+ },
73
+ }
74
+
75
+ /// Deterministic network schedule (fully reproducible from seed)
76
+ #[derive(Clone, Debug)]
77
+ pub struct NetworkSchedule {
78
+ pub seed: FaultSeed,
79
+ pub events: Vec<NetworkEvent>,
80
+ }
81
+
82
+ impl NetworkSchedule {
83
+ pub fn new(seed: FaultSeed) -> Self {
84
+ Self {
85
+ seed,
86
+ events: Vec::new(),
87
+ }
88
+ }
89
+
90
+ pub fn add_event(&mut self, event: NetworkEvent) {
91
+ self.events.push(event);
92
+ }
93
+
94
+ pub fn get_seed(&self) -> FaultSeed {
95
+ self.seed
96
+ }
97
+ }
98
+
99
+ /// In-flight message
100
+ #[derive(Clone, Debug)]
101
+ struct InFlightMessage {
102
+ id: MessageId,
103
+ from: NodeId,
104
+ to: NodeId,
105
+ payload: Vec<u8>,
106
+ delivery_tick: u64,
107
+ }
108
+
109
+ /// Connectivity matrix for asymmetric partitions
110
+ #[derive(Clone, Debug)]
111
+ pub struct ConnectivityMatrix {
112
+ links: HashMap<ConnectionId, LinkState>,
113
+ }
114
+
115
+ impl ConnectivityMatrix {
116
+ pub fn new() -> Self {
117
+ Self {
118
+ links: HashMap::new(),
119
+ }
120
+ }
121
+
122
+ pub fn can_reach(&self, from: NodeId, to: NodeId) -> bool {
123
+ let conn = ConnectionId { from, to };
124
+ matches!(self.links.get(&conn), Some(LinkState::Connected) | None)
125
+ }
126
+
127
+ pub fn partition(&mut self, from: NodeId, to: NodeId) {
128
+ self.links.insert(ConnectionId { from, to }, LinkState::Partitioned);
129
+ }
130
+
131
+ pub fn heal(&mut self, from: NodeId, to: NodeId) {
132
+ self.links.insert(ConnectionId { from, to }, LinkState::Connected);
133
+ }
134
+
135
+ pub fn get_state(&self, from: NodeId, to: NodeId) -> LinkState {
136
+ let conn = ConnectionId { from, to };
137
+ *self.links.get(&conn).unwrap_or(&LinkState::Connected)
138
+ }
139
+ }
140
+
141
+ impl Default for ConnectivityMatrix {
142
+ fn default() -> Self {
143
+ Self::new()
144
+ }
145
+ }
146
+
147
+ /// Trait: Replication transport (decoupled from FeltDB logic)
148
+ pub trait ReplicationTransport: Send + Sync {
149
+ /// Send a message from one node to another
150
+ fn send(&mut self, from: NodeId, to: NodeId, message: Vec<u8>) -> MessageId;
151
+
152
+ /// Advance simulation by one tick
153
+ fn tick(&mut self);
154
+
155
+ /// Receive all messages waiting for a node
156
+ fn receive(&mut self, node: NodeId) -> Vec<(NodeId, Vec<u8>)>;
157
+
158
+ /// Apply a fault event
159
+ fn apply_fault(&mut self, event: NetworkEvent);
160
+
161
+ /// Get current tick
162
+ fn current_tick(&self) -> u64;
163
+
164
+ /// Get connectivity status
165
+ fn get_connectivity(&self, from: NodeId, to: NodeId) -> LinkState;
166
+ }
167
+
168
+ /// In-memory transport with no faults (baseline)
169
+ pub struct InMemoryTransport {
170
+ current_tick: u64,
171
+ message_counter: u64,
172
+ queues: HashMap<NodeId, VecDeque<(NodeId, Vec<u8>)>>,
173
+ }
174
+
175
+ impl InMemoryTransport {
176
+ pub fn new() -> Self {
177
+ Self {
178
+ current_tick: 0,
179
+ message_counter: 0,
180
+ queues: HashMap::new(),
181
+ }
182
+ }
183
+ }
184
+
185
+ impl Default for InMemoryTransport {
186
+ fn default() -> Self {
187
+ Self::new()
188
+ }
189
+ }
190
+
191
+ impl ReplicationTransport for InMemoryTransport {
192
+ fn send(&mut self, from: NodeId, to: NodeId, message: Vec<u8>) -> MessageId {
193
+ let id = MessageId(self.message_counter);
194
+ self.message_counter += 1;
195
+
196
+ self.queues
197
+ .entry(to)
198
+ .or_insert_with(VecDeque::new)
199
+ .push_back((from, message));
200
+
201
+ id
202
+ }
203
+
204
+ fn tick(&mut self) {
205
+ self.current_tick += 1;
206
+ }
207
+
208
+ fn receive(&mut self, node: NodeId) -> Vec<(NodeId, Vec<u8>)> {
209
+ self.queues
210
+ .remove(&node)
211
+ .map(|q| q.into_iter().collect())
212
+ .unwrap_or_default()
213
+ }
214
+
215
+ fn apply_fault(&mut self, _event: NetworkEvent) {
216
+ // No-op for in-memory transport
217
+ }
218
+
219
+ fn current_tick(&self) -> u64 {
220
+ self.current_tick
221
+ }
222
+
223
+ fn get_connectivity(&self, _from: NodeId, _to: NodeId) -> LinkState {
224
+ LinkState::Connected
225
+ }
226
+ }
227
+
228
+ /// Adversarial transport with full fault injection
229
+ pub struct AdversarialTransport {
230
+ current_tick: u64,
231
+ message_counter: u64,
232
+ in_flight: Vec<InFlightMessage>,
233
+ delivered_queues: HashMap<NodeId, VecDeque<(NodeId, Vec<u8>)>>,
234
+ connectivity: ConnectivityMatrix,
235
+ dropped_messages: std::collections::HashSet<MessageId>,
236
+ }
237
+
238
+ impl AdversarialTransport {
239
+ pub fn new() -> Self {
240
+ Self {
241
+ current_tick: 0,
242
+ message_counter: 0,
243
+ in_flight: Vec::new(),
244
+ delivered_queues: HashMap::new(),
245
+ connectivity: ConnectivityMatrix::new(),
246
+ dropped_messages: std::collections::HashSet::new(),
247
+ }
248
+ }
249
+
250
+ pub fn get_in_flight_count(&self) -> usize {
251
+ self.in_flight.len()
252
+ }
253
+
254
+ pub fn get_delivered_count(&self, node: NodeId) -> usize {
255
+ self.delivered_queues
256
+ .get(&node)
257
+ .map(|q| q.len())
258
+ .unwrap_or(0)
259
+ }
260
+ }
261
+
262
+ impl Default for AdversarialTransport {
263
+ fn default() -> Self {
264
+ Self::new()
265
+ }
266
+ }
267
+
268
+ impl ReplicationTransport for AdversarialTransport {
269
+ fn send(&mut self, from: NodeId, to: NodeId, message: Vec<u8>) -> MessageId {
270
+ let id = MessageId(self.message_counter);
271
+ self.message_counter += 1;
272
+
273
+ // Check if link is partitioned
274
+ if !self.connectivity.can_reach(from, to) {
275
+ // Message is dropped by partition
276
+ self.dropped_messages.insert(id);
277
+ return id;
278
+ }
279
+
280
+ // Message enters in-flight, scheduled for immediate delivery
281
+ self.in_flight.push(InFlightMessage {
282
+ id,
283
+ from,
284
+ to,
285
+ payload: message,
286
+ delivery_tick: self.current_tick,
287
+ });
288
+
289
+ id
290
+ }
291
+
292
+ fn tick(&mut self) {
293
+ self.current_tick += 1;
294
+
295
+ // Deliver messages that are ready
296
+ let mut to_deliver = Vec::new();
297
+ let mut remaining = Vec::new();
298
+
299
+ for msg in self.in_flight.drain(..) {
300
+ if msg.delivery_tick <= self.current_tick {
301
+ to_deliver.push(msg);
302
+ } else {
303
+ remaining.push(msg);
304
+ }
305
+ }
306
+
307
+ self.in_flight = remaining;
308
+
309
+ // Queue delivered messages
310
+ for msg in to_deliver {
311
+ if !self.dropped_messages.contains(&msg.id) {
312
+ self.delivered_queues
313
+ .entry(msg.to)
314
+ .or_insert_with(VecDeque::new)
315
+ .push_back((msg.from, msg.payload));
316
+ }
317
+ }
318
+ }
319
+
320
+ fn receive(&mut self, node: NodeId) -> Vec<(NodeId, Vec<u8>)> {
321
+ self.delivered_queues
322
+ .remove(&node)
323
+ .map(|q| q.into_iter().collect())
324
+ .unwrap_or_default()
325
+ }
326
+
327
+ fn apply_fault(&mut self, event: NetworkEvent) {
328
+ match event {
329
+ NetworkEvent::Delay {
330
+ message_id,
331
+ ticks,
332
+ } => {
333
+ // Find message and delay delivery
334
+ for msg in &mut self.in_flight {
335
+ if msg.id == message_id {
336
+ msg.delivery_tick += ticks;
337
+ break;
338
+ }
339
+ }
340
+ }
341
+ NetworkEvent::Drop { message_id } => {
342
+ self.dropped_messages.insert(message_id);
343
+ }
344
+ NetworkEvent::Duplicate { message_id } => {
345
+ // Clone the in-flight message
346
+ if let Some(orig) = self.in_flight.iter().find(|m| m.id == message_id) {
347
+ let dup = InFlightMessage {
348
+ id: MessageId(self.message_counter),
349
+ from: orig.from,
350
+ to: orig.to,
351
+ payload: orig.payload.clone(),
352
+ delivery_tick: orig.delivery_tick,
353
+ };
354
+ self.message_counter += 1;
355
+ self.in_flight.push(dup);
356
+ }
357
+ }
358
+ NetworkEvent::Partition { from, to } => {
359
+ self.connectivity.partition(from, to);
360
+ }
361
+ NetworkEvent::Heal { from, to } => {
362
+ self.connectivity.heal(from, to);
363
+ }
364
+ NetworkEvent::Reorder { connection } => {
365
+ // Reorder messages on this connection
366
+ let mut msgs_on_conn: Vec<_> = self
367
+ .in_flight
368
+ .iter()
369
+ .enumerate()
370
+ .filter(|(_, m)| m.from == connection.from && m.to == connection.to)
371
+ .collect();
372
+
373
+ if msgs_on_conn.len() > 1 {
374
+ // Reverse order of messages on this connection
375
+ msgs_on_conn.reverse();
376
+ let indices: Vec<_> = msgs_on_conn.iter().map(|(i, _)| *i).collect();
377
+
378
+ for (new_pos, &old_pos) in indices.iter().enumerate() {
379
+ if new_pos != old_pos {
380
+ self.in_flight.swap(new_pos, old_pos);
381
+ }
382
+ }
383
+ }
384
+ }
385
+ }
386
+ }
387
+
388
+ fn current_tick(&self) -> u64 {
389
+ self.current_tick
390
+ }
391
+
392
+ fn get_connectivity(&self, from: NodeId, to: NodeId) -> LinkState {
393
+ self.connectivity.get_state(from, to)
394
+ }
395
+ }
396
+
397
+ #[cfg(test)]
398
+ mod tests {
399
+ use super::*;
400
+
401
+ #[test]
402
+ fn test_in_memory_transport_basic() {
403
+ let mut transport = InMemoryTransport::new();
404
+
405
+ let n1 = NodeId(1);
406
+ let n2 = NodeId(2);
407
+
408
+ transport.send(n1, n2, vec![1, 2, 3]);
409
+ let messages = transport.receive(n2);
410
+
411
+ assert_eq!(messages.len(), 1);
412
+ assert_eq!(messages[0].0, n1);
413
+ assert_eq!(messages[0].1, vec![1, 2, 3]);
414
+ }
415
+
416
+ #[test]
417
+ fn test_adversarial_transport_basic() {
418
+ let mut transport = AdversarialTransport::new();
419
+
420
+ let n1 = NodeId(1);
421
+ let n2 = NodeId(2);
422
+
423
+ let msg_id = transport.send(n1, n2, vec![1, 2, 3]);
424
+ assert!(msg_id.0 >= 0);
425
+
426
+ transport.tick();
427
+ let messages = transport.receive(n2);
428
+
429
+ assert_eq!(messages.len(), 1);
430
+ assert_eq!(messages[0].0, n1);
431
+ }
432
+
433
+ #[test]
434
+ fn test_partition() {
435
+ let mut transport = AdversarialTransport::new();
436
+
437
+ let n1 = NodeId(1);
438
+ let n2 = NodeId(2);
439
+
440
+ // Partition n1 → n2
441
+ transport.apply_fault(NetworkEvent::Partition {
442
+ from: n1,
443
+ to: n2,
444
+ });
445
+
446
+ // Message should be dropped
447
+ let _msg_id = transport.send(n1, n2, vec![1, 2, 3]);
448
+ transport.tick();
449
+
450
+ let messages = transport.receive(n2);
451
+ assert_eq!(messages.len(), 0);
452
+ }
453
+
454
+ #[test]
455
+ fn test_delay() {
456
+ let mut transport = AdversarialTransport::new();
457
+
458
+ let n1 = NodeId(1);
459
+ let n2 = NodeId(2);
460
+
461
+ let msg_id = transport.send(n1, n2, vec![1, 2, 3]);
462
+
463
+ // Delay the message by 5 ticks
464
+ transport.apply_fault(NetworkEvent::Delay {
465
+ message_id: msg_id,
466
+ ticks: 5,
467
+ });
468
+
469
+ // Tick 1-4: no messages
470
+ for _ in 0..4 {
471
+ transport.tick();
472
+ let messages = transport.receive(n2);
473
+ assert_eq!(messages.len(), 0);
474
+ }
475
+
476
+ // Tick 5: message delivered
477
+ transport.tick();
478
+ let messages = transport.receive(n2);
479
+ assert_eq!(messages.len(), 1);
480
+ }
481
+
482
+ #[test]
483
+ fn test_duplicate() {
484
+ let mut transport = AdversarialTransport::new();
485
+
486
+ let n1 = NodeId(1);
487
+ let n2 = NodeId(2);
488
+
489
+ let msg_id = transport.send(n1, n2, vec![1, 2, 3]);
490
+
491
+ // Duplicate the message
492
+ transport.apply_fault(NetworkEvent::Duplicate {
493
+ message_id: msg_id,
494
+ });
495
+
496
+ transport.tick();
497
+ let messages = transport.receive(n2);
498
+
499
+ assert_eq!(messages.len(), 2);
500
+ assert_eq!(messages[0].1, vec![1, 2, 3]);
501
+ assert_eq!(messages[1].1, vec![1, 2, 3]);
502
+ }
503
+
504
+ #[test]
505
+ fn test_drop() {
506
+ let mut transport = AdversarialTransport::new();
507
+
508
+ let n1 = NodeId(1);
509
+ let n2 = NodeId(2);
510
+
511
+ let msg_id = transport.send(n1, n2, vec![1, 2, 3]);
512
+
513
+ transport.apply_fault(NetworkEvent::Drop {
514
+ message_id: msg_id,
515
+ });
516
+
517
+ transport.tick();
518
+ let messages = transport.receive(n2);
519
+
520
+ assert_eq!(messages.len(), 0);
521
+ }
522
+
523
+ #[test]
524
+ fn test_asymmetric_partition() {
525
+ let mut transport = AdversarialTransport::new();
526
+
527
+ let n1 = NodeId(1);
528
+ let n2 = NodeId(2);
529
+
530
+ // Partition n1 → n2 only (asymmetric)
531
+ transport.apply_fault(NetworkEvent::Partition {
532
+ from: n1,
533
+ to: n2,
534
+ });
535
+
536
+ // n1 → n2 blocked
537
+ let _msg_id = transport.send(n1, n2, vec![1, 2, 3]);
538
+ transport.tick();
539
+ assert_eq!(transport.receive(n2).len(), 0);
540
+
541
+ // n2 → n1 allowed
542
+ let msg_id = transport.send(n2, n1, vec![4, 5, 6]);
543
+ assert!(msg_id.0 >= 0);
544
+ transport.tick();
545
+ assert_eq!(transport.receive(n1).len(), 1);
546
+ }
547
+
548
+ #[test]
549
+ fn test_connectivity_matrix() {
550
+ let mut connectivity = ConnectivityMatrix::new();
551
+
552
+ let n1 = NodeId(1);
553
+ let n2 = NodeId(2);
554
+
555
+ // Initially connected
556
+ assert!(connectivity.can_reach(n1, n2));
557
+
558
+ // Partition
559
+ connectivity.partition(n1, n2);
560
+ assert!(!connectivity.can_reach(n1, n2));
561
+
562
+ // Heal
563
+ connectivity.heal(n1, n2);
564
+ assert!(connectivity.can_reach(n1, n2));
565
+ }
566
+ }