Skip to content

Commit bcff78b

Browse files
facundominguezneilmayhew
authored andcommitted
Don't let GDD drop candidates that do not intersect with the selection
1 parent 906f397 commit bcff78b

File tree

1 file changed

+34
-9
lines changed
  • ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Genesis

1 file changed

+34
-9
lines changed

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Genesis/Governor.hs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import Data.List.NonEmpty (NonEmpty)
4343
import qualified Data.List.NonEmpty as NE
4444
import Data.Map.Strict (Map)
4545
import qualified Data.Map.Strict as Map
46-
import Data.Maybe (mapMaybe, maybeToList)
46+
import Data.Maybe (maybeToList)
4747
import Data.Maybe.Strict (StrictMaybe)
4848
import Data.Word (Word64)
4949
import Ouroboros.Consensus.Block
@@ -255,16 +255,41 @@ sharedCandidatePrefix curChain candidates =
255255
immutableTip = AF.anchorPoint curChain
256256

257257
splitAfterImmutableTip (peer, frag) =
258-
(,) peer . snd <$> AF.splitAfterPoint frag immutableTip
258+
case AF.splitAfterPoint frag immutableTip of
259+
-- When there is no intersection, we assume the candidate fragment is
260+
-- empty and anchored at the immutable tip.
261+
-- See Note [CSJ truncates the candidate fragments].
262+
Nothing -> (peer, AF.takeOldest 0 curChain)
263+
Just (_, suffix) -> (peer, suffix)
259264

260265
immutableTipSuffixes =
261-
-- If a ChainSync client's candidate forks off before the
262-
-- immutable tip, then this transaction is currently winning an
263-
-- innocuous race versus the thread that will fatally raise
264-
-- 'InvalidIntersection' within that ChainSync client, so it's
265-
-- sound to pre-emptively discard their candidate from this
266-
-- 'Map' via 'mapMaybe'.
267-
mapMaybe splitAfterImmutableTip candidates
266+
map splitAfterImmutableTip candidates
267+
268+
-- Note [CSJ truncates the candidate fragments]
269+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
270+
--
271+
-- Before CSJ, only rollback could cause truncation of a candidate fragment.
272+
-- Truncation is a serious business to GDD because the LoE might have allowed
273+
-- the selection to advance, based on the tips of the candidate fragments.
274+
--
275+
-- Truncating a candidate fragment risks moving the LoE back, which could be
276+
-- earlier than the anchor of the latest selection. When rollbacks where the
277+
-- only mechanism to truncate, it was fine to ignore candidate fragments that
278+
-- don't intersect with the current selection. This could only happen if the
279+
-- peer is rolling back more than k blocks, which is dishonest behavior.
280+
--
281+
-- With CSJ, however, the candidate fragments can recede without a rollback.
282+
-- A former objector might be asked to jump back when it becomes a jumper again.
283+
-- The jump point might still be a descendent of the immutable tip. But by the
284+
-- time the jump is accepted, the immutable tip might have advanced, and the
285+
-- candidate fragment of the otherwise honest peer might be ignored by GDD.
286+
--
287+
-- Therefore, at the moment, when there is no intersection with the current
288+
-- selection, the GDD assumes that the candidate fragment is empty and anchored
289+
-- at the immutable tip. It is the job of the ChainSync client to update the
290+
-- candidate fragment so it intersects with the selection or to disconnect the
291+
-- peer if no such fragment can be established.
292+
--
268293

269294
data DensityBounds blk =
270295
DensityBounds {

0 commit comments

Comments
 (0)