1use daggy::petgraph::visit::{
2 Bfs, EdgeRef, IntoEdgeReferences, IntoNodeReferences, NodeRef, Reversed,
3};
4use daggy::stable_dag::StableDag;
5use daggy::Walker;
6use ossa_crdt::CRDT;
7use std::cmp::{self, Reverse};
8use std::collections::{BTreeMap, BTreeSet, VecDeque};
9use std::fmt::Debug;
10use std::marker::PhantomData;
11use tracing::{debug, error};
12
13pub mod v0;
14
15pub trait ECGHeader {
17 type HeaderId: Ord + Copy + Debug;
18
19 fn get_parent_ids(&self) -> &[Self::HeaderId];
28
29 fn get_header_id(&self) -> Self::HeaderId;
31
32 fn validate_header(&self, header_id: Self::HeaderId) -> bool;
33
34 }
44
45pub trait ECGBody<Op, SerializedOp> {
46 type Header: ECGHeader;
48
49 fn new_body(operations: Vec<SerializedOp>) -> Self;
52
53 fn operations(
55 self,
56 header_id: <Self::Header as ECGHeader>::HeaderId,
57 ) -> impl Iterator<Item = Op>;
58
59 fn operations_count(&self) -> u8;
61
62 fn new_header(&self, parents: BTreeSet<<Self::Header as ECGHeader>::HeaderId>) -> Self::Header;
64 }
79
80pub(crate) type RawECGBody = Vec<u8>;
82
83#[derive(Clone, Debug)]
84pub(crate) struct NodeInfo<Header> {
85 graph_index: daggy::NodeIndex,
87 depth: u64,
89 header: Header,
91 operations: RawECGBody,
93}
94
95impl<Header> NodeInfo<Header> {
96 pub(crate) fn header(&self) -> &Header {
97 &self.header
98 }
99
100 pub(crate) fn operations(&self) -> &Vec<u8> {
101 &self.operations
102 }
103}
104
105#[derive(Clone, Debug)]
106pub struct UntypedState<HeaderId, Header> {
107 dependency_graph: StableDag<HeaderId, ()>, root_nodes: BTreeSet<HeaderId>,
111
112 node_info_map: BTreeMap<HeaderId, NodeInfo<Header>>,
114
115 tips: BTreeSet<HeaderId>,
118}
119
120impl<HeaderId, Header> UntypedState<HeaderId, Header> {
121 pub fn tips(&self) -> &BTreeSet<HeaderId> {
122 &self.tips
123 }
124
125 pub fn contains(&self, h: &HeaderId) -> bool
126 where
127 HeaderId: Ord,
128 {
129 if let Some(_node_info) = self.node_info_map.get(h) {
130 true
131 } else {
132 false
133 }
134 }
135
136 pub fn get_parents(&self, h: &HeaderId) -> Option<Vec<HeaderId>>
137 where
138 HeaderId: Ord + Copy,
139 {
140 let node_info = self.node_info_map.get(h)?;
141 self.dependency_graph
142 .parents(node_info.graph_index)
143 .iter(&self.dependency_graph)
144 .map(|(_, parent_idx)| self.dependency_graph.node_weight(parent_idx).map(|i| *i))
145 .try_collect()
146 }
147
148 pub fn get_parents_with_depth(&self, h: &HeaderId) -> Option<Vec<(u64, HeaderId)>>
149 where
150 HeaderId: Ord + Copy,
151 {
152 let node_info = self.node_info_map.get(h)?;
153 self.dependency_graph
154 .parents(node_info.graph_index)
155 .iter(&self.dependency_graph)
156 .map(|(_, parent_idx)| {
157 self.dependency_graph
158 .node_weight(parent_idx)
159 .and_then(|parent_id| {
160 self.node_info_map
161 .get(parent_id)
162 .map(|i| (i.depth, *parent_id))
163 })
164 })
165 .try_collect()
166 }
167
168 pub fn get_children_with_depth(&self, h: &HeaderId) -> Option<Vec<(Reverse<u64>, HeaderId)>>
171 where
172 HeaderId: Ord + Copy,
173 {
174 let node_info = self.node_info_map.get(h)?;
175 self.dependency_graph
176 .children(node_info.graph_index)
177 .iter(&self.dependency_graph)
178 .map(|(_, child_idx)| {
179 self.dependency_graph
180 .node_weight(child_idx)
181 .and_then(|child_id| {
182 self.node_info_map
183 .get(child_id)
184 .map(|i| (Reverse(i.depth), *child_id))
185 })
186 })
187 .try_collect()
188 }
189
190 pub(crate) fn get_header_depth(&self, n: &HeaderId) -> Option<u64>
191 where
192 HeaderId: Ord,
193 {
194 self.node_info_map.get(n).map(|i| i.depth)
195 }
196
197 pub(crate) fn get_header(&self, n: &HeaderId) -> Option<&Header>
198 where
199 HeaderId: Ord,
200 {
201 self.node_info_map.get(n).map(|i| &i.header)
202 }
203
204 pub(crate) fn get_node(&self, n: &HeaderId) -> Option<&NodeInfo<Header>>
205 where
206 HeaderId: Ord,
207 {
208 self.node_info_map.get(n)
209 }
210
211 pub(crate) fn is_root_node(&self, h: &HeaderId) -> bool
212 where
213 HeaderId: Ord,
214 {
215 self.root_nodes.contains(h)
216 }
217
218 pub fn get_root_nodes_with_depth<'a>(
219 &'a self,
220 ) -> impl Iterator<Item = (Reverse<u64>, HeaderId)> + 'a
221 where
222 HeaderId: Copy,
223 {
224 self.root_nodes.iter().map(|h| (Reverse(1), *h))
226 }
227}
228
229#[derive(Debug)]
230pub struct State<Header: ECGHeader, T> {
231 pub(crate) state: UntypedState<Header::HeaderId, Header>,
232
233 phantom: PhantomData<fn(T)>, }
235
236impl<Header: ECGHeader + Clone, T: CRDT> Clone for State<Header, T> {
237 fn clone(&self) -> Self {
238 let state = self.state.clone();
239 State {
240 state,
241 phantom: PhantomData,
242 }
243 }
244}
245
246impl<Header: ECGHeader, T: CRDT> State<Header, T> {
247 pub fn new() -> State<Header, T> {
248 let state = UntypedState {
249 dependency_graph: StableDag::new(),
250 root_nodes: BTreeSet::new(),
251 node_info_map: BTreeMap::new(),
252 tips: BTreeSet::new(),
253 };
254 State {
255 state,
256 phantom: PhantomData,
257 }
258 }
259
260 pub fn tips(&self) -> &BTreeSet<Header::HeaderId> {
261 &self.state.tips
262 }
263
264 pub fn is_root_node(&self, h: &Header::HeaderId) -> bool {
265 self.state.is_root_node(h)
266 }
267
268 pub fn get_parents_with_depth(
271 &self,
272 h: &Header::HeaderId,
273 ) -> Option<Vec<(u64, Header::HeaderId)>> {
274 self.state.get_parents_with_depth(h)
275 }
276
277 pub fn get_parents(&self, h: &Header::HeaderId) -> Option<Vec<Header::HeaderId>> {
280 self.state.get_parents(h)
281 }
282
283 pub fn get_children_with_depth(
286 &self,
287 h: &Header::HeaderId,
288 ) -> Option<Vec<(Reverse<u64>, Header::HeaderId)>> {
289 self.state.get_children_with_depth(h)
290 }
291
292 pub fn contains(&self, h: &Header::HeaderId) -> bool {
297 self.state.contains(h)
298 }
299
300 pub fn get_header(&self, n: &Header::HeaderId) -> Option<&Header> {
301 self.state.get_header(n)
302 }
303
304 pub fn get_header_depth(&self, n: &Header::HeaderId) -> Option<u64> {
305 self.state.get_header_depth(n)
306 }
307
308 pub fn insert_header(&mut self, header: Header, operations: RawECGBody) -> bool {
309 let header_id = header.get_header_id();
310
311 if !header.validate_header(header_id) {
313 debug!("Invalid header: {header_id:?}");
314 return false;
315 }
316
317 if self.state.node_info_map.contains_key(&header_id) {
319 debug!("Already have header: {header_id:?}");
320 return false;
321 }
322
323 let parents = header.get_parent_ids();
324 let (parent_idxs, depth) = if parents.is_empty() {
325 let is_new_insert = self.state.root_nodes.insert(header_id);
326 if !is_new_insert {
328 error!("Invariant violated: Header already existed in root_nodes but not in node_info_map: {header_id:?}");
331 return false;
332 }
333
334 self.state.tips.insert(header_id);
336
337 (vec![], 1)
338 } else {
339 let mut depth = u64::MAX;
340 if let Some(parent_idxs) = parents
341 .iter()
342 .map(|parent_id| {
343 self.state.node_info_map.get(&parent_id).map(|i| {
344 depth = cmp::min(depth, i.depth);
345 i.graph_index
346 })
347 })
348 .try_collect::<Vec<daggy::NodeIndex>>()
349 {
350 parents.iter().for_each(|parent_id| {
352 self.state.tips.remove(parent_id);
353 });
354 self.state.tips.insert(header_id);
356
357 (parent_idxs, depth + 1)
358 } else {
359 error!("They sent us a header but we don't know its parents: {header_id:?}");
361 return false;
362 }
363 };
364
365 let graph_index = self.state.dependency_graph.add_node(header_id);
368 let node_info = NodeInfo {
369 graph_index: graph_index.clone(),
370 depth,
371 header,
372 operations,
373 };
374 if let Err(_) = self.state.node_info_map.try_insert(header_id, node_info) {
375 error!("Unreachable: We already checked that it doesn't exist in node_info_map: {header_id:?}");
377 return false;
378 }
379
380 if let Err(_) = self.state.dependency_graph.add_edges(
382 parent_idxs
383 .into_iter()
384 .map(|parent_idx| (parent_idx, graph_index, ())),
385 ) {
386 error!("Invariant violated: Header already existed in dependency_graph but not in node_info_map: {header_id:?}");
388 return false;
389 }
390
391 true
392 }
393
394 fn is_ancestor_of(
397 &self,
398 ancestor: &Header::HeaderId,
399 descendent: &Header::HeaderId,
400 ) -> Option<bool> {
401 let anid = self.state.node_info_map.get(ancestor)?.graph_index;
402 let dnid = self.state.node_info_map.get(descendent)?.graph_index;
403
404 let mut queue = VecDeque::from([dnid]);
405 let mut visited = BTreeSet::from([dnid]);
406
407 while let Some(nid) = queue.pop_front() {
408 if nid == anid {
409 return Some(true);
410 }
411
412 for (_, pid) in self
413 .state
414 .dependency_graph
415 .parents(nid)
416 .iter(&self.state.dependency_graph)
417 {
418 if !visited.contains(&pid) {
419 visited.insert(pid);
420 queue.push_back(pid);
421 }
422 }
423 }
424
425 Some(false)
426 }
427
428 pub fn state(&self) -> &UntypedState<Header::HeaderId, Header> {
429 &self.state
430 }
431}
432
433#[cfg(test)]
435pub(crate) fn equal_dags<Header: ECGHeader, T>(l: &State<Header, T>, r: &State<Header, T>) -> bool
436where
437 Header::HeaderId: Copy,
438{
439 let edges = |g: &StableDag<Header::HeaderId, ()>| {
440 g.edge_references()
441 .map(|e| {
442 let n1 = g.node_weight(e.source()).unwrap();
443 let n2 = g.node_weight(e.target()).unwrap();
444 (*n1, *n2)
445 })
446 .collect()
447 };
448 let nodes =
449 |g: &StableDag<Header::HeaderId, ()>| g.node_references().map(|n| *n.weight()).collect();
450
451 let node_set_left: BTreeSet<_> = nodes(&l.state.dependency_graph);
452 let node_set_right = nodes(&r.state.dependency_graph);
453 let edge_set_left: BTreeSet<_> = edges(&l.state.dependency_graph);
454 let edge_set_right = edges(&r.state.dependency_graph);
455
456 l.state.root_nodes == r.state.root_nodes
457 && l.state.tips == r.state.tips
458 && edge_set_left == edge_set_right
459 && node_set_left == node_set_right
460}
461
462#[cfg(test)]
463pub(crate) fn print_dag<Header: ECGHeader, T>(s: &State<Header, T>) {
464 use petgraph::dot::{Config, Dot};
465 use petgraph::stable_graph::StableDiGraph;
466
467 let mut g = s
468 .state
469 .dependency_graph
470 .map(|_i, n| format!("{:?}", n), |_i, e| e);
471
472 let root = g.add_node("".to_string());
474 for n in &s.state.root_nodes {
475 g.add_edge(root, s.state.node_info_map[n].graph_index, &());
476 }
477
478 let g: StableDiGraph<_, _> = g.into();
479 let d = Dot::with_config(&g, &[Config::EdgeNoLabel]);
480 println!("{:?}", d);
481}