Skip to content

Commit 1563013

Browse files
timorltimorl
andauthored
A0-1797: Block sync service (#998)
* Block sync service * Handling justifications cannot result in responses * Explicit comment about notifier assumptions --------- Co-authored-by: timorl <timorl@disroot.org>
1 parent 60028b9 commit 1563013

File tree

8 files changed

+429
-100
lines changed

8 files changed

+429
-100
lines changed

finality-aleph/src/sync/forest/mod.rs

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
use std::collections::{
2-
hash_map::{Entry, OccupiedEntry, VacantEntry},
3-
HashMap, HashSet,
1+
use std::{
2+
collections::{
3+
hash_map::{Entry, OccupiedEntry, VacantEntry},
4+
HashMap, HashSet,
5+
},
6+
fmt::{Display, Error as FmtError, Formatter},
47
};
58

69
use crate::sync::{
@@ -25,23 +28,22 @@ enum VertexHandle<'a, I: PeerId, J: Justification> {
2528
Candidate(OccupiedEntry<'a, BlockIdFor<J>, VertexWithChildren<I, J>>),
2629
}
2730

28-
/// Information required to prepare a request for block.
29-
#[derive(Clone, PartialEq, Eq, Debug)]
30-
pub struct RequestInfo<I: PeerId, J: Justification> {
31-
know_most: HashSet<I>,
32-
branch_knowledge: BranchKnowledge<J>,
33-
}
34-
3531
/// Our interest in a block referred to by a vertex,
3632
/// including all the information required to prepare a request.
3733
#[derive(Clone, PartialEq, Eq, Debug)]
3834
pub enum Interest<I: PeerId, J: Justification> {
3935
/// We are not interested in this block.
4036
Uninterested,
4137
/// We would like to have this block.
42-
Required(RequestInfo<I, J>),
38+
Required {
39+
know_most: HashSet<I>,
40+
branch_knowledge: BranchKnowledge<J>,
41+
},
4342
/// We would like to have this block and its the highest on its branch.
44-
TopRequired(RequestInfo<I, J>),
43+
TopRequired {
44+
know_most: HashSet<I>,
45+
branch_knowledge: BranchKnowledge<J>,
46+
},
4547
}
4648

4749
/// What can go wrong when inserting data into the forest.
@@ -54,6 +56,24 @@ pub enum Error {
5456
TooNew,
5557
}
5658

59+
impl Display for Error {
60+
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
61+
use Error::*;
62+
match self {
63+
HeaderMissingParentId => write!(f, "header did not contain a parent ID"),
64+
IncorrectParentState => write!(
65+
f,
66+
"parent was in a state incompatible with importing this block"
67+
),
68+
IncorrectVertexState => write!(f, "block in a state incompatible with importing"),
69+
ParentNotImported => {
70+
write!(f, "parent was not imported when attempting to import block")
71+
}
72+
TooNew => write!(f, "block too new to be considered"),
73+
}
74+
}
75+
}
76+
5777
pub struct VertexWithChildren<I: PeerId, J: Justification> {
5878
vertex: Vertex<I, J>,
5979
children: HashSet<BlockIdFor<J>>,
@@ -364,7 +384,10 @@ impl<I: PeerId, J: Justification> Forest<I, J> {
364384

365385
/// Prepare additional info required to create a request for the block.
366386
/// Returns `None` if we're not interested in the block.
367-
fn prepare_request_info(&mut self, id: &BlockIdFor<J>) -> Option<RequestInfo<I, J>> {
387+
fn prepare_request_info(
388+
&mut self,
389+
id: &BlockIdFor<J>,
390+
) -> Option<(HashSet<I>, BranchKnowledge<J>)> {
368391
use VertexHandle::Candidate;
369392
match self.get_mut(id) {
370393
Candidate(entry) => {
@@ -375,10 +398,7 @@ impl<I: PeerId, J: Justification> Forest<I, J> {
375398
let know_most = entry.get().vertex.know_most().clone();
376399
// should always return Some, as the branch of a Candidate always exists
377400
self.branch_knowledge(id.clone())
378-
.map(|branch_knowledge| RequestInfo {
379-
know_most,
380-
branch_knowledge,
381-
})
401+
.map(|branch_knowledge| (know_most, branch_knowledge))
382402
}
383403
// request only Candidates
384404
_ => None,
@@ -388,9 +408,15 @@ impl<I: PeerId, J: Justification> Forest<I, J> {
388408
/// How much interest we have for the block.
389409
pub fn state(&mut self, id: &BlockIdFor<J>) -> Interest<I, J> {
390410
match self.prepare_request_info(id) {
391-
Some(request_info) => match self.top_required.contains(id) {
392-
true => Interest::TopRequired(request_info),
393-
false => Interest::Required(request_info),
411+
Some((know_most, branch_knowledge)) => match self.top_required.contains(id) {
412+
true => Interest::TopRequired {
413+
know_most,
414+
branch_knowledge,
415+
},
416+
false => Interest::Required {
417+
know_most,
418+
branch_knowledge,
419+
},
394420
},
395421
None => Interest::Uninterested,
396422
}
@@ -443,7 +469,7 @@ mod tests {
443469
.expect("it's not too high"));
444470
assert!(forest.try_finalize(&1).is_none());
445471
match forest.state(&child.id()) {
446-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
472+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
447473
other_state => panic!("Expected top required, got {:?}.", other_state),
448474
}
449475
assert!(!forest
@@ -487,7 +513,7 @@ mod tests {
487513
.expect("header was correct"));
488514
assert!(forest.try_finalize(&1).is_none());
489515
match forest.state(&child.id()) {
490-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
516+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
491517
other_state => panic!("Expected top required, got {:?}.", other_state),
492518
}
493519
assert!(!forest
@@ -516,7 +542,7 @@ mod tests {
516542
.expect("header was correct"));
517543
assert!(forest.try_finalize(&1).is_none());
518544
match forest.state(&child.header().id()) {
519-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
545+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
520546
other_state => panic!("Expected top required, got {:?}.", other_state),
521547
}
522548
}
@@ -568,7 +594,7 @@ mod tests {
568594
.expect("header was correct"));
569595
assert!(forest.try_finalize(&1).is_none());
570596
match forest.state(&child.header().id()) {
571-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
597+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
572598
other_state => panic!("Expected top required, got {:?}.", other_state),
573599
}
574600
forest
@@ -588,7 +614,7 @@ mod tests {
588614
.update_header(&fork_child, Some(fork_peer_id), true)
589615
.expect("header was correct"));
590616
match forest.state(&fork_child.id()) {
591-
TopRequired(request_info) => assert!(request_info.know_most.contains(&fork_peer_id)),
617+
TopRequired { know_most, .. } => assert!(know_most.contains(&fork_peer_id)),
592618
other_state => panic!("Expected top required, got {:?}.", other_state),
593619
}
594620
assert!(forest
@@ -614,7 +640,7 @@ mod tests {
614640
.update_header(header, Some(peer_id), true)
615641
.expect("header was correct"));
616642
match forest.state(&header.id()) {
617-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
643+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
618644
other_state => panic!("Expected top required, got {:?}.", other_state),
619645
}
620646
}
@@ -642,7 +668,7 @@ mod tests {
642668
.update_header(header, Some(peer_id), true)
643669
.expect("header was correct"));
644670
match forest.state(&header.id()) {
645-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
671+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
646672
other_state => panic!("Expected top required, got {:?}.", other_state),
647673
}
648674
let header = &branch[1];
@@ -657,7 +683,7 @@ mod tests {
657683
.update_header(header, Some(peer_id), true)
658684
.expect("header was correct"));
659685
match forest.state(&header.id()) {
660-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
686+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
661687
other_state => panic!("Expected top required, got {:?}.", other_state),
662688
}
663689
let header = &branch[2];
@@ -666,9 +692,9 @@ mod tests {
666692
.update_header(header, Some(peer_id), false)
667693
.expect("header was correct"));
668694
for header in branch.iter().take(3) {
669-
assert!(matches!(forest.state(&header.id()), Required(_)));
695+
assert!(matches!(forest.state(&header.id()), Required { .. }));
670696
}
671-
assert!(matches!(forest.state(&branch[3].id()), TopRequired(_)));
697+
assert!(matches!(forest.state(&branch[3].id()), TopRequired { .. }));
672698
}
673699

674700
#[test]
@@ -694,10 +720,13 @@ mod tests {
694720
.update_header(header, Some(peer_id), true)
695721
.expect("header was correct"));
696722
match forest.state(&header.id()) {
697-
TopRequired(request_info) => {
698-
assert!(request_info.know_most.contains(&peer_id));
723+
TopRequired {
724+
know_most,
725+
branch_knowledge,
726+
} => {
727+
assert!(know_most.contains(&peer_id));
699728
// we only know parent from branch[2], namely branch[1]
700-
assert_eq!(request_info.branch_knowledge, LowestId(branch[1].id()));
729+
assert_eq!(branch_knowledge, LowestId(branch[1].id()));
701730
}
702731
other_state => panic!("Expected top required, got {:?}.", other_state),
703732
}
@@ -708,24 +737,25 @@ mod tests {
708737
.update_header(header, Some(peer_id), false)
709738
.expect("header was correct"));
710739
for header in branch.iter().take(3) {
711-
assert!(matches!(forest.state(&header.id()), Required(_)));
740+
assert!(matches!(forest.state(&header.id()), Required { .. }));
712741
}
713742
match forest.state(&branch[3].id()) {
714-
TopRequired(request_info) => {
743+
TopRequired {
744+
branch_knowledge, ..
745+
} => {
715746
// now we know all ancestors
716-
assert_eq!(
717-
request_info.branch_knowledge,
718-
TopImported(initial_header.id())
719-
);
747+
assert_eq!(branch_knowledge, TopImported(initial_header.id()));
720748
}
721749
other_state => panic!("Expected top required, got {:?}.", other_state),
722750
}
723751
forest.update_body(&branch[0]).expect("should import");
724752
forest.update_body(&branch[1]).expect("should import");
725753
match forest.state(&branch[3].id()) {
726-
TopRequired(request_info) => {
754+
TopRequired {
755+
branch_knowledge, ..
756+
} => {
727757
// we know all ancestors, three blocks were imported
728-
assert_eq!(request_info.branch_knowledge, TopImported(branch[1].id()));
758+
assert_eq!(branch_knowledge, TopImported(branch[1].id()));
729759
}
730760
other_state => panic!("Expected top required, got {:?}.", other_state),
731761
}
@@ -747,7 +777,7 @@ mod tests {
747777
.update_justification(justification.clone(), Some(peer_id))
748778
.expect("header was correct"));
749779
match forest.state(&justification.header().id()) {
750-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
780+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
751781
other_state => panic!("Expected top required, got {:?}.", other_state),
752782
}
753783
forest
@@ -780,7 +810,7 @@ mod tests {
780810
.update_justification(justification.clone(), Some(peer_id))
781811
.expect("header was correct"));
782812
match forest.state(&justification.header().id()) {
783-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
813+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
784814
other_state => panic!("Expected top required, got {:?}.", other_state),
785815
}
786816
}
@@ -816,7 +846,7 @@ mod tests {
816846
.expect("header was correct"));
817847
assert!(forest.try_finalize(&1).is_none());
818848
match forest.state(&header.id()) {
819-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
849+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
820850
other_state => panic!("Expected top required, got {:?}.", other_state),
821851
}
822852
}
@@ -827,7 +857,7 @@ mod tests {
827857
.expect("header was correct"));
828858
assert!(forest.try_finalize(&1).is_none());
829859
match forest.state(&child.header().id()) {
830-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
860+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
831861
other_state => panic!("Expected top required, got {:?}.", other_state),
832862
}
833863
forest
@@ -859,11 +889,11 @@ mod tests {
859889
.update_header(header, Some(peer_id), true)
860890
.expect("header was correct"));
861891
match forest.state(&header.id()) {
862-
TopRequired(request_info) => assert!(request_info.know_most.contains(&peer_id)),
892+
TopRequired { know_most, .. } => assert!(know_most.contains(&peer_id)),
863893
other_state => panic!("Expected top required, got {:?}.", other_state),
864894
}
865895
for header in branch.iter().take(HUGE_BRANCH_LENGTH - 1) {
866-
assert!(matches!(forest.state(&header.id()), Required(_)));
896+
assert!(matches!(forest.state(&header.id()), Required { .. }));
867897
}
868898
}
869899
}

0 commit comments

Comments
 (0)