Skip to content

Commit f10ecb7

Browse files
committed
Create units with ancient parents
1 parent 1a35839 commit f10ecb7

File tree

6 files changed

+421
-142
lines changed

6 files changed

+421
-142
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ More details are available [in the book][reference-link-implementation-details].
6060
- Import AlephBFT in your crate
6161
```toml
6262
[dependencies]
63-
aleph-bft = "^0.41"
63+
aleph-bft = "^0.42"
6464
```
6565
- The main entry point is the `run_session` function, which returns a Future that runs the
6666
consensus algorithm.

consensus/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "aleph-bft"
3-
version = "0.41.0"
3+
version = "0.42.0"
44
edition = "2021"
55
authors = ["Cardinal Cryptography"]
66
categories = ["algorithms", "data-structures", "cryptography", "database"]

consensus/src/creation/collector.rs

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
use crate::{units::Unit, Hasher, NodeCount, NodeIndex, NodeMap, Round};
2+
use anyhow::Result;
3+
use thiserror::Error;
4+
5+
#[derive(Eq, Error, Debug, PartialEq)]
6+
pub enum ConstraintError {
7+
#[error("Not enough parents.")]
8+
NotEnoughParents,
9+
#[error("Missing own parent.")]
10+
MissingOwnParent,
11+
}
12+
13+
#[derive(Clone)]
14+
pub struct UnitsCollector<H: Hasher> {
15+
candidates: NodeMap<(H::Hash, Round)>,
16+
for_round: Round,
17+
direct_parents: NodeCount,
18+
}
19+
20+
impl<H: Hasher> UnitsCollector<H> {
21+
pub fn new_initial(n_members: NodeCount) -> Self {
22+
UnitsCollector {
23+
candidates: NodeMap::with_size(n_members),
24+
for_round: 1,
25+
direct_parents: NodeCount(0),
26+
}
27+
}
28+
29+
pub fn from_previous(previous: &UnitsCollector<H>) -> Self {
30+
UnitsCollector {
31+
candidates: previous.candidates.clone(),
32+
for_round: previous.for_round + 1,
33+
direct_parents: NodeCount(0),
34+
}
35+
}
36+
37+
pub fn add_unit<U: Unit<Hasher = H>>(&mut self, unit: &U) {
38+
let node_id = unit.creator();
39+
let hash = unit.hash();
40+
let round = unit.round();
41+
42+
if round >= self.for_round {
43+
return;
44+
}
45+
46+
let to_insert = match self.candidates.get(node_id) {
47+
None => Some((hash, round)),
48+
Some((_, r)) if *r < round => Some((hash, round)),
49+
_ => None,
50+
};
51+
52+
if let Some(data) = to_insert {
53+
self.candidates.insert(node_id, data);
54+
if round == self.for_round - 1 {
55+
self.direct_parents += NodeCount(1);
56+
}
57+
}
58+
}
59+
60+
pub fn prospective_parents(
61+
&self,
62+
node_id: NodeIndex,
63+
) -> Result<&NodeMap<(H::Hash, Round)>, ConstraintError> {
64+
if self.direct_parents < self.candidates.size().consensus_threshold() {
65+
return Err(ConstraintError::NotEnoughParents);
66+
}
67+
match self.candidates.get(node_id) {
68+
Some((_, r)) if *r == self.for_round - 1 => Ok(&self.candidates),
69+
_ => Err(ConstraintError::MissingOwnParent),
70+
}
71+
}
72+
}
73+
74+
#[cfg(test)]
75+
mod tests {
76+
use crate::{
77+
creation::collector::{ConstraintError, UnitsCollector},
78+
units::{random_full_parent_units_up_to, Unit},
79+
NodeCount, NodeIndex,
80+
};
81+
use aleph_bft_mock::Hasher64;
82+
83+
#[test]
84+
fn initial_fails_without_parents() {
85+
let n_members = NodeCount(4);
86+
let units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
87+
88+
let err = units_collector
89+
.prospective_parents(NodeIndex(0))
90+
.expect_err("should fail without parents");
91+
assert_eq!(err, ConstraintError::NotEnoughParents);
92+
}
93+
94+
#[test]
95+
fn initial_fails_with_too_few_parents() {
96+
let n_members = NodeCount(4);
97+
let mut units_collector = UnitsCollector::new_initial(n_members);
98+
let units = random_full_parent_units_up_to(0, n_members, 43);
99+
units_collector.add_unit(&units[0][0]);
100+
101+
let err = units_collector
102+
.prospective_parents(NodeIndex(0))
103+
.expect_err("should fail without parents");
104+
assert_eq!(err, ConstraintError::NotEnoughParents);
105+
}
106+
107+
#[test]
108+
fn initial_fails_without_own_parent() {
109+
let n_members = NodeCount(4);
110+
let mut units_collector = UnitsCollector::new_initial(n_members);
111+
let units = random_full_parent_units_up_to(0, n_members, 43);
112+
for unit in units[0].iter().skip(1) {
113+
units_collector.add_unit(unit);
114+
}
115+
116+
let err = units_collector
117+
.prospective_parents(NodeIndex(0))
118+
.expect_err("should fail without parents");
119+
assert_eq!(err, ConstraintError::MissingOwnParent);
120+
}
121+
122+
#[test]
123+
fn initial_successfully_computes_minimal_parents() {
124+
let n_members = NodeCount(4);
125+
let mut units_collector = UnitsCollector::new_initial(n_members);
126+
let units = random_full_parent_units_up_to(0, n_members, 43);
127+
for unit in units[0].iter().take(3) {
128+
units_collector.add_unit(unit);
129+
}
130+
131+
let parents = units_collector
132+
.prospective_parents(NodeIndex(0))
133+
.expect("we should be able to retrieve parents");
134+
assert_eq!(parents.item_count(), 3);
135+
136+
let new_units: Vec<_> = units[0]
137+
.iter()
138+
.take(3)
139+
.map(|unit| (unit.hash(), unit.round()))
140+
.collect();
141+
let selected_parents: Vec<_> = parents.values().cloned().collect();
142+
assert_eq!(new_units, selected_parents);
143+
}
144+
145+
#[test]
146+
fn initial_successfully_computes_full_parents() {
147+
let n_members = NodeCount(4);
148+
let mut units_collector = UnitsCollector::new_initial(n_members);
149+
let units = random_full_parent_units_up_to(0, n_members, 43);
150+
for unit in &units[0] {
151+
units_collector.add_unit(unit);
152+
}
153+
154+
let parents = units_collector
155+
.prospective_parents(NodeIndex(0))
156+
.expect("we should be able to retrieve parents");
157+
assert_eq!(parents.item_count(), 4);
158+
159+
let new_units: Vec<_> = units[0]
160+
.iter()
161+
.map(|unit| (unit.hash(), unit.round()))
162+
.collect();
163+
let selected_parents: Vec<_> = parents.values().cloned().collect();
164+
assert_eq!(new_units, selected_parents);
165+
}
166+
167+
#[test]
168+
fn following_fails_without_parents() {
169+
let n_members = NodeCount(4);
170+
let initial_units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
171+
let units_collector = UnitsCollector::from_previous(&initial_units_collector);
172+
173+
let err = units_collector
174+
.prospective_parents(NodeIndex(0))
175+
.expect_err("should fail without parents");
176+
assert_eq!(err, ConstraintError::NotEnoughParents);
177+
}
178+
179+
#[test]
180+
fn following_fails_with_too_few_parents() {
181+
let n_members = NodeCount(4);
182+
let initial_units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
183+
let mut units_collector = UnitsCollector::from_previous(&initial_units_collector);
184+
let units = random_full_parent_units_up_to(1, n_members, 43);
185+
units_collector.add_unit(&units[1][0]);
186+
187+
let err = units_collector
188+
.prospective_parents(NodeIndex(0))
189+
.expect_err("should fail without parents");
190+
assert_eq!(err, ConstraintError::NotEnoughParents);
191+
}
192+
193+
#[test]
194+
fn following_fails_with_too_old_parents() {
195+
let n_members = NodeCount(4);
196+
let initial_units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
197+
let mut units_collector = UnitsCollector::from_previous(&initial_units_collector);
198+
let units = random_full_parent_units_up_to(0, n_members, 43);
199+
for unit in &units[0] {
200+
units_collector.add_unit(unit);
201+
}
202+
203+
let err = units_collector
204+
.prospective_parents(NodeIndex(0))
205+
.expect_err("should fail without parents");
206+
assert_eq!(err, ConstraintError::NotEnoughParents);
207+
}
208+
209+
#[test]
210+
fn following_fails_without_own_parent() {
211+
let n_members = NodeCount(4);
212+
let initial_units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
213+
let mut units_collector = UnitsCollector::from_previous(&initial_units_collector);
214+
let units = random_full_parent_units_up_to(1, n_members, 43);
215+
for unit in units[1].iter().skip(1) {
216+
units_collector.add_unit(unit);
217+
}
218+
219+
let err = units_collector
220+
.prospective_parents(NodeIndex(0))
221+
.expect_err("should fail without parents");
222+
assert_eq!(err, ConstraintError::MissingOwnParent);
223+
}
224+
225+
#[test]
226+
fn following_fails_with_too_old_own_parent() {
227+
let n_members = NodeCount(4);
228+
let initial_units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
229+
let mut units_collector = UnitsCollector::from_previous(&initial_units_collector);
230+
let units = random_full_parent_units_up_to(1, n_members, 43);
231+
for unit in units[1].iter().skip(1) {
232+
units_collector.add_unit(unit);
233+
}
234+
units_collector.add_unit(&units[0][0]);
235+
236+
let err = units_collector
237+
.prospective_parents(NodeIndex(0))
238+
.expect_err("should fail without parents");
239+
assert_eq!(err, ConstraintError::MissingOwnParent);
240+
}
241+
242+
#[test]
243+
fn following_successfully_computes_minimal_parents() {
244+
let n_members = NodeCount(4);
245+
let initial_units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
246+
let mut units_collector = UnitsCollector::from_previous(&initial_units_collector);
247+
let units = random_full_parent_units_up_to(1, n_members, 43);
248+
for unit in units[1].iter().take(3) {
249+
units_collector.add_unit(unit);
250+
}
251+
252+
let parents = units_collector
253+
.prospective_parents(NodeIndex(0))
254+
.expect("we should be able to retrieve parents");
255+
assert_eq!(parents.item_count(), 3);
256+
257+
let new_units: Vec<_> = units[1]
258+
.iter()
259+
.take(3)
260+
.map(|unit| (unit.hash(), unit.round()))
261+
.collect();
262+
let selected_parents: Vec<_> = parents.values().cloned().collect();
263+
assert_eq!(new_units, selected_parents);
264+
}
265+
266+
#[test]
267+
fn following_successfully_computes_minimal_parents_with_ancient() {
268+
let n_members = NodeCount(4);
269+
let initial_units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
270+
let mut units_collector = UnitsCollector::from_previous(&initial_units_collector);
271+
let units = random_full_parent_units_up_to(1, n_members, 43);
272+
for unit in units[1].iter().take(3) {
273+
units_collector.add_unit(unit);
274+
}
275+
units_collector.add_unit(&units[0][3]);
276+
277+
let parents = units_collector
278+
.prospective_parents(NodeIndex(0))
279+
.expect("we should be able to retrieve parents");
280+
assert_eq!(parents.item_count(), 4);
281+
282+
let mut new_units: Vec<_> = units[1]
283+
.iter()
284+
.take(3)
285+
.map(|unit| (unit.hash(), unit.round()))
286+
.collect();
287+
new_units.push((units[0][3].hash(), units[0][3].round()));
288+
let selected_parents: Vec<_> = parents.values().cloned().collect();
289+
assert_eq!(new_units, selected_parents);
290+
}
291+
292+
#[test]
293+
fn following_successfully_computes_full_parents() {
294+
let n_members = NodeCount(4);
295+
let initial_units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
296+
let mut units_collector = UnitsCollector::from_previous(&initial_units_collector);
297+
let units = random_full_parent_units_up_to(1, n_members, 43);
298+
for unit in &units[1] {
299+
units_collector.add_unit(unit);
300+
}
301+
302+
let parents = units_collector
303+
.prospective_parents(NodeIndex(0))
304+
.expect("we should be able to retrieve parents");
305+
assert_eq!(parents.item_count(), 4);
306+
307+
let new_units: Vec<_> = units[1]
308+
.iter()
309+
.map(|unit| (unit.hash(), unit.round()))
310+
.collect();
311+
let selected_parents: Vec<_> = parents.values().cloned().collect();
312+
assert_eq!(new_units, selected_parents);
313+
}
314+
315+
#[test]
316+
fn following_inherits_units() {
317+
let n_members = NodeCount(4);
318+
let mut initial_units_collector = UnitsCollector::<Hasher64>::new_initial(n_members);
319+
let units = random_full_parent_units_up_to(1, n_members, 43);
320+
for unit in &units[0] {
321+
initial_units_collector.add_unit(unit);
322+
}
323+
let mut units_collector = UnitsCollector::from_previous(&initial_units_collector);
324+
for unit in units[1].iter().take(3) {
325+
units_collector.add_unit(unit);
326+
}
327+
328+
let parents = units_collector
329+
.prospective_parents(NodeIndex(0))
330+
.expect("we should be able to retrieve parents");
331+
assert_eq!(parents.item_count(), 4);
332+
333+
let mut new_units: Vec<_> = units[1]
334+
.iter()
335+
.take(3)
336+
.map(|unit| (unit.hash(), unit.round()))
337+
.collect();
338+
new_units.push((units[0][3].hash(), units[0][3].round()));
339+
let selected_parents: Vec<_> = parents.values().cloned().collect();
340+
assert_eq!(new_units, selected_parents);
341+
}
342+
}

0 commit comments

Comments
 (0)