Skip to content

Commit 37257f9

Browse files
committed
TOSPLIT fixup IB lifetimes
LateIbInclusion requires keeping IBs around two stages longer for building EBs and Votes correctly. This highlighted the fact that the simulator had been diffusing IBs for longer than it should, since it had been reusing the relay buffer for building Votes correctly. This mega-commit does several things. - Renames `shouldIgnore` to `shouldNotRequest` in order to emphasize that `shouldIgnore` only prevents late requests, not late arrivals. (Actually either late or early.) - IBs now stop diffusing when they should, ie after Endorse. Also, the `shouldNotRequest` logic for the relay buffer is simpler: just discard IBs that would be late if they diffused now. (Actually either late or early.) - Discards IBs that arrived too late, instead of processing them anyway. - Introduces a state variable `iBsForEBsAndVotesVar` dedicating to remembering IBs even after they stop diffusing, since building EBs and Votes requires information about such IBs. - Only records a classification `IbDeliveryStage` of when an IB arrived, instead of recording the low-level `UTCTime`. - Simplified the logic for choosing&judging IBs within EBs using the new `IbDeliveryStage` classification. - The node no longer ignores certificates when building an RB if it doesn't already have all of the IBs the certificate transitively includes---that rule is not in the Short Leios specification.
1 parent 6554ed2 commit 37257f9

File tree

5 files changed

+202
-112
lines changed

5 files changed

+202
-112
lines changed

simulation/src/LeiosProtocol/Relay.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ data SubmitPolicy = SubmitInOrder | SubmitAll
498498

499499
data RelayConsumerConfig id header body m = RelayConsumerConfig
500500
{ relay :: !RelayConfig
501-
, shouldIgnore :: m (header -> Bool)
501+
, shouldNotRequest :: m (header -> Bool)
502502
-- ^ headers to ignore, e.g. already received or coming too late.
503503
, validateHeaders :: [header] -> m ()
504504
, headerId :: !(header -> id)
@@ -761,7 +761,7 @@ relayConsumerPipelined config sst =
761761
if (min (Map.size lst0.available) (fromIntegral config.maxBodiesToRequest)) == 0
762762
then return (Left lst0)
763763
else return . Right . TS.Effect $ do
764-
isIgnored <- config.shouldIgnore
764+
isIgnored <- config.shouldNotRequest
765765
atomically $ do
766766
-- New headers are filtered before becoming available, but we have
767767
-- to filter `lst.available` again in the same STM tx that sets them as
@@ -987,7 +987,7 @@ relayConsumerPipelined config sst =
987987
m (RelayConsumerLocalState id header body n)
988988
acknowledgeIds lst idsSeq _ | Seq.null idsSeq = pure lst
989989
acknowledgeIds lst idsSeq idsMap = do
990-
isIgnored <- config.shouldIgnore
990+
isIgnored <- config.shouldNotRequest
991991
inFlight <- readTVarIO sst.inFlightVar
992992

993993
let lst1 =

simulation/src/LeiosProtocol/Short.hs

Lines changed: 85 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -467,21 +467,37 @@ isStage cfg stage slot = fromEnum slot >= cfg.sliceLength * fromEnum stage
467467
newtype PipelineNo = PipelineNo Word64
468468
deriving (Bounded, Enum, Show, Eq, Ord)
469469

470+
pipelineMonus :: PipelineNo -> Word64 -> PipelineNo
471+
pipelineMonus (PipelineNo w) i = PipelineNo $ w - min w i
472+
470473
stageRangeOf :: forall p. IsPipeline p => LeiosConfig -> PipelineNo -> Stage p -> (SlotNo, SlotNo)
471474
stageRangeOf cfg pl stage =
472475
fromMaybe
473476
undefined
474477
(stageRange cfg minBound (toEnum (fromEnum pl * cfg.sliceLength)) stage)
475478

479+
-- | WARNING This fails if the slot is earlier than the beginning of the stage
480+
-- in the first iteration (ie @'PipelineNo' 0@)
476481
pipelineOf :: forall p. IsPipeline p => LeiosConfig -> Stage p -> SlotNo -> PipelineNo
477482
pipelineOf cfg stage sl =
478-
toEnum $
479-
fromMaybe undefined (fromEnum <$> stageStart cfg stage sl minBound)
480-
`div` cfg.sliceLength
483+
maybe err cnv $ stageStart cfg stage sl minBound
484+
where
485+
cnv = toEnum . (`div` cfg.sliceLength) . fromEnum
486+
487+
err = error $ show (cfg.sliceLength, x, stage, sl)
488+
489+
x :: String
490+
x = case cfg of LeiosConfig{pipeline} -> case pipeline of
491+
SingSingleVote -> "SingleVote"
492+
SingSplitVote -> "SplitVote"
481493

482494
forEachPipeline :: (forall p. Stage p) -> (forall p. IsPipeline p => Stage p -> a) -> [a]
483495
forEachPipeline s k = [k @SingleVote s, k @SplitVote s]
484496

497+
lastEndorse :: LeiosConfig -> PipelineNo -> SlotNo
498+
lastEndorse leios@LeiosConfig{pipeline = _ :: SingPipeline p} pipelineNo =
499+
snd $ stageRangeOf @p leios pipelineNo Endorse
500+
485501
lastVoteSend :: LeiosConfig -> PipelineNo -> SlotNo
486502
lastVoteSend leios@LeiosConfig{pipeline} pipelineNo = case pipeline of
487503
SingSingleVote -> snd (stageRangeOf leios pipelineNo Vote)
@@ -663,48 +679,78 @@ data EndorseBlocksSnapshot = EndorseBlocksSnapshot
663679
, certifiedEndorseBlocks :: (PipelineNo, PipelineNo) -> [(PipelineNo, [(EndorseBlock, Certificate, UTCTime)])]
664680
}
665681

682+
-- | In which contemporary stage was an IB delivered
683+
--
684+
-- IBs cannot be deliver earlier than any of these options, due to the
685+
-- 'LeiosProtocol.Relay.shouldNotRequest' logic of the
686+
-- 'LeiosProtocol.Short.Node.relayIBState'.
687+
--
688+
-- IBs that are delivered later than any of these options are discarded,
689+
-- ignored.
690+
data IbDeliveryStage =
691+
IbDuringProposeOrDeliver1
692+
-- ^ The node will not vote for an EB that excludes IBs that arrived during
693+
-- Propose or Deliver1.
694+
--
695+
-- The node will include IBs that arrived during Propose or Deliver1 in an
696+
-- EB it makes.
697+
|
698+
IbDuringDeliver2
699+
-- ^ The node will include IBs that arrived during Deliver2 in an EB it makes.
700+
|
701+
IbDuringEndorse
702+
-- ^ The node will not vote for an EB that includes IBs that arrived later
703+
-- than Endorse.
704+
deriving (Bounded, Enum, Eq, Ord, Show)
705+
666706
-- | Both constraints are inclusive.
667707
data InputBlocksQuery = InputBlocksQuery
668-
{ generatedBetween :: (SlotNo, SlotNo)
669-
, receivedBy :: SlotNo
708+
{ generatedBetween :: (PipelineNo, PipelineNo)
709+
, receivedBy :: IbDeliveryStage
670710
-- ^ This is checked against time the body is downloaded, before validation.
671711
}
672712

673-
inputBlocksToEndorse1 ::
713+
ibWasDeliveredLate :: LeiosConfig -> SlotConfig -> SlotNo -> UTCTime -> Bool
714+
ibWasDeliveredLate cfg slotCfg sl deliveryTime =
715+
case ibDeliveryStage cfg slotCfg sl deliveryTime of
716+
Nothing -> True
717+
Just{} -> False
718+
719+
ibDeliveryStage :: LeiosConfig -> SlotConfig -> SlotNo -> UTCTime -> Maybe IbDeliveryStage
720+
ibDeliveryStage
721+
cfg@LeiosConfig {pipeline = _ :: SingPipeline p}
722+
slotCfg
723+
ibSlot
724+
deliveryTime
725+
| before loPropose = Nothing -- TODO future blocks?
726+
| before loDeliver2 = Just IbDuringProposeOrDeliver1
727+
| before loEndorse = Just IbDuringDeliver2
728+
| before (succ hiEndorse) = Just IbDuringEndorse
729+
| otherwise = Nothing -- TODO late blocks?
730+
where
731+
p = pipelineOf @p cfg Propose ibSlot
732+
733+
before sl = deliveryTime < slotTime slotCfg sl
734+
735+
(loPropose, _) = stageRangeOf @p cfg p Propose
736+
(loDeliver2, _) = stageRangeOf @p cfg p Deliver2
737+
(loEndorse, hiEndorse) = stageRangeOf @p cfg p Endorse
738+
739+
inputBlocksToEndorse ::
674740
LeiosConfig ->
675741
-- | current slot
676742
SlotNo ->
677743
InputBlocksSnapshot ->
678744
[InputBlockId]
679-
inputBlocksToEndorse1 cfg@LeiosConfig{pipeline = _ :: SingPipeline p} current buffer = fromMaybe [] $ do
680-
generatedBetween <- stageRange @p cfg Endorse current Propose
681-
receivedBy <- stageEnd @p cfg Endorse current Deliver2
682-
pure $
745+
inputBlocksToEndorse cfg@LeiosConfig{pipeline = _ :: SingPipeline p} current buffer =
683746
buffer.validInputBlocks
684747
InputBlocksQuery
685-
{ generatedBetween
686-
, receivedBy
748+
{ generatedBetween = (lo, hi)
749+
, receivedBy = IbDuringDeliver2
687750
}
688-
689-
-- | Invokes 'inputBlocksToEndorse1' as many times as 'lateIbInclusion'
690-
-- requires
691-
inputBlocksToEndorse ::
692-
LeiosConfig ->
693-
-- | current slot
694-
SlotNo ->
695-
InputBlocksSnapshot ->
696-
[InputBlockId]
697-
inputBlocksToEndorse cfg current buffer =
698-
concatMap each iterations
699-
where
700-
each sl = inputBlocksToEndorse1 cfg sl buffer
701-
capL = fromIntegral cfg.sliceLength
702-
iterations =
703-
if not cfg.lateIbInclusion
704-
then [current]
705-
else
706-
-- discard underflows
707-
dropWhile (> current) [current - 2 * capL, current - capL, current]
751+
where
752+
hi = pipelineOf @p cfg Endorse current
753+
lo = if cfg.lateIbInclusion then pipelineMonus hi 2 else hi
708754

709755
-- | Returns possible EBs to reference from current pipeline EB.
710756
endorseBlocksToReference ::
@@ -760,21 +806,24 @@ shouldVoteOnEB ::
760806
shouldVoteOnEB cfg@LeiosConfig{voteSendStage} _ slot _buffers _
761807
-- checks whether a pipeline has been started before.
762808
| Nothing <- stageRange cfg voteSendStage slot Propose = const False
763-
shouldVoteOnEB cfg@LeiosConfig{voteSendStage} slotConfig slot buffers ebuffers = cond
809+
shouldVoteOnEB cfg@LeiosConfig{voteSendStage = voteSendStage :: Stage p} slotConfig slot buffers ebuffers = cond
764810
where
765-
generatedBetween = fromMaybe (error "impossible") $ stageRange cfg voteSendStage slot Propose
811+
generatedBetween = (lo, hi)
812+
where
813+
hi = pipelineOf @p cfg voteSendStage slot
814+
lo = if cfg.lateIbInclusion then pipelineMonus hi 2 else hi
766815
receivedByEndorse =
767816
buffers.validInputBlocks
768817
InputBlocksQuery
769818
{ generatedBetween
770-
, receivedBy = fromMaybe (error "impossible") $ stageEnd cfg voteSendStage slot Endorse
819+
, receivedBy = IbDuringEndorse
771820
}
772821
receivedByDeliver1 = buffers.validInputBlocks q
773822
where
774823
q =
775824
InputBlocksQuery
776825
{ generatedBetween
777-
, receivedBy = fromMaybe (error "impossible") $ stageEnd cfg voteSendStage slot Deliver1
826+
, receivedBy = IbDuringProposeOrDeliver1
778827
}
779828
-- Order of references in EndorseBlock matters for ledger state, so we stick to lists.
780829
-- Note: maybe order on (slot, subSlot, vrf proof) should be used instead?

0 commit comments

Comments
 (0)