@@ -33,7 +33,7 @@ import Data.Set qualified as Set
33
33
import Data.Function (on )
34
34
import Data.Hashable
35
35
import Data.List as List (foldl' , groupBy , sortBy , transpose )
36
- import Data.Maybe (mapMaybe )
36
+ import Data.Maybe (fromMaybe , mapMaybe )
37
37
import Data.Set (Set )
38
38
39
39
import Control.Exception (assert )
@@ -473,8 +473,19 @@ empty fetch range, but this is ok since we never request empty ranges.
473
473
--
474
474
-- A 'ChainSuffix' must be non-empty, as an empty suffix, i.e. the candidate
475
475
-- chain is equal to the current chain, would not be a plausible candidate.
476
- newtype ChainSuffix header =
477
- ChainSuffix { getChainSuffix :: AnchoredFragment header }
476
+ --
477
+ -- Additionally, we store the full candidate (with the same anchor as our
478
+ -- current chain), as this is needed for comparing different candidates via
479
+ -- 'compareCandidateChains'.
480
+ data ChainSuffix header = ChainSuffix {
481
+ -- | The suffix of the candidate after the intersection with the current
482
+ -- chain.
483
+ getChainSuffix :: ! (AnchoredFragment header ),
484
+ -- | The full candidate, characterized by having the same tip as
485
+ -- 'getChainSuffix' and the same anchor as our current chain. In particular,
486
+ -- 'getChainSuffix' is a suffix of 'getFullCandidate'.
487
+ getFullCandidate :: ! (AnchoredFragment header )
488
+ }
478
489
479
490
{-
480
491
We define the /chain suffix/ as the suffix of the candidate chain up until (but
@@ -511,25 +522,31 @@ interested in this candidate at all.
511
522
-- current chain.
512
523
--
513
524
chainForkSuffix
514
- :: (HasHeader header , HasHeader block ,
515
- HeaderHash header ~ HeaderHash block )
516
- => AnchoredFragment block -- ^ Current chain.
517
- -> AnchoredFragment header -- ^ Candidate chain
525
+ :: HasHeader header
526
+ => AnchoredFragment header
527
+ -> AnchoredFragment header
518
528
-> Maybe (ChainSuffix header )
519
529
chainForkSuffix current candidate =
520
530
case AF. intersect current candidate of
521
531
Nothing -> Nothing
522
- Just (_ , _, _, candidateSuffix) ->
532
+ Just (currentChainPrefix , _, _, candidateSuffix) ->
523
533
-- If the suffix is empty, it means the candidate chain was equal to
524
534
-- the current chain and didn't fork off. Such a candidate chain is
525
535
-- not a plausible candidate, so it must have been filtered out.
526
536
assert (not (AF. null candidateSuffix)) $
527
- Just (ChainSuffix candidateSuffix)
537
+ Just ChainSuffix {
538
+ getChainSuffix = candidateSuffix,
539
+ getFullCandidate = fullCandidate
540
+ }
541
+ where
542
+ fullCandidate =
543
+ fromMaybe (error " invariant violation of AF.intersect" ) $
544
+ AF. join currentChainPrefix candidateSuffix
545
+
528
546
529
547
selectForkSuffixes
530
- :: (HasHeader header , HasHeader block ,
531
- HeaderHash header ~ HeaderHash block )
532
- => AnchoredFragment block
548
+ :: HasHeader header
549
+ => AnchoredFragment header
533
550
-> [(FetchDecision (AnchoredFragment header ), peerinfo )]
534
551
-> [(FetchDecision (ChainSuffix header ), peerinfo )]
535
552
selectForkSuffixes current chains =
@@ -743,7 +760,11 @@ prioritisePeerChains FetchModeDeadline salt compareCandidateChains blockFetchSiz
743
760
(equatingPair
744
761
-- compare on probability band first, then preferred chain
745
762
(==)
746
- (equateCandidateChains `on` getChainSuffix)
763
+ -- Precondition of 'compareCandidateChains' (used by
764
+ -- 'equateCandidateChains') is fulfilled as all
765
+ -- 'getFullCandidate's intersect pairwise (due to having the
766
+ -- same anchor as our current chain).
767
+ (equateCandidateChains `on` getFullCandidate)
747
768
`on`
748
769
(\ (band, chain, _fragments) -> (band, chain)))))
749
770
. sortBy (descendingOrder
@@ -752,7 +773,10 @@ prioritisePeerChains FetchModeDeadline salt compareCandidateChains blockFetchSiz
752
773
(comparingPair
753
774
-- compare on probability band first, then preferred chain
754
775
compare
755
- (compareCandidateChains `on` getChainSuffix)
776
+ -- Precondition of 'compareCandidateChains' is fulfilled as
777
+ -- all 'getFullCandidate's intersect pairwise (due to
778
+ -- having the same anchor as our current chain).
779
+ (compareCandidateChains `on` getFullCandidate)
756
780
`on`
757
781
(\ (band, chain, _fragments) -> (band, chain))))))
758
782
. map annotateProbabilityBand
@@ -776,7 +800,7 @@ prioritisePeerChains FetchModeDeadline salt compareCandidateChains blockFetchSiz
776
800
| EQ <- compareCandidateChains chain1 chain2 = True
777
801
| otherwise = False
778
802
779
- chainHeadPoint (_,ChainSuffix c ,_) = AF. headPoint c
803
+ chainHeadPoint (_,ChainSuffix {getChainSuffix = c} ,_) = AF. headPoint c
780
804
781
805
prioritisePeerChains FetchModeBulkSync salt compareCandidateChains blockFetchSize =
782
806
map (\ (decision, peer) ->
@@ -785,7 +809,11 @@ prioritisePeerChains FetchModeBulkSync salt compareCandidateChains blockFetchSiz
785
809
(comparingRight
786
810
(comparingPair
787
811
-- compare on preferred chain first, then duration
788
- (compareCandidateChains `on` getChainSuffix)
812
+ --
813
+ -- Precondition of 'compareCandidateChains' is fulfilled as
814
+ -- all 'getFullCandidate's intersect pairwise (due to having
815
+ -- the same anchor as our current chain).
816
+ (compareCandidateChains `on` getFullCandidate)
789
817
compare
790
818
`on`
791
819
(\ (duration, chain, _fragments) -> (chain, duration)))))
0 commit comments