Skip to content

Commit 9aca6be

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 9aca6be

File tree

5 files changed

+196
-113
lines changed

5 files changed

+196
-113
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: 79 additions & 37 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,71 @@ data EndorseBlocksSnapshot = EndorseBlocksSnapshot
663679
, certifiedEndorseBlocks :: (PipelineNo, PipelineNo) -> [(PipelineNo, [(EndorseBlock, Certificate, UTCTime)])]
664680
}
665681

682+
-- | In which contemporary stage was an IB delivered
683+
data IbDeliveryStage =
684+
IbDuringProposeOrDeliver1
685+
-- ^ The node will not vote for an EB that excludes IBs that arrived during
686+
-- Propose or Deliver1.
687+
--
688+
-- The node will include IBs that arrived during Propose or Deliver1 in an
689+
-- EB it makes.
690+
|
691+
IbDuringDeliver2
692+
-- ^ The node will include IBs that arrived during Deliver2 in an EB it makes.
693+
|
694+
IbDuringEndorse
695+
-- ^ The node will not vote for an EB that includes IBs that arrived later
696+
-- than Endorse.
697+
deriving (Bounded, Enum, Eq, Ord, Show)
698+
666699
-- | Both constraints are inclusive.
667700
data InputBlocksQuery = InputBlocksQuery
668-
{ generatedBetween :: (SlotNo, SlotNo)
669-
, receivedBy :: SlotNo
701+
{ generatedBetween :: (PipelineNo, PipelineNo)
702+
, receivedBy :: IbDeliveryStage
670703
-- ^ This is checked against time the body is downloaded, before validation.
671704
}
672705

673-
inputBlocksToEndorse1 ::
674-
LeiosConfig ->
675-
-- | current slot
676-
SlotNo ->
677-
InputBlocksSnapshot ->
678-
[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 $
683-
buffer.validInputBlocks
684-
InputBlocksQuery
685-
{ generatedBetween
686-
, receivedBy
687-
}
706+
ibWasDeliveredLate :: LeiosConfig -> SlotConfig -> SlotNo -> UTCTime -> Bool
707+
ibWasDeliveredLate cfg slotCfg sl deliveryTime =
708+
case ibDeliveryStage cfg slotCfg sl deliveryTime of
709+
Nothing -> True
710+
Just{} -> False
711+
712+
ibDeliveryStage :: LeiosConfig -> SlotConfig -> SlotNo -> UTCTime -> Maybe IbDeliveryStage
713+
ibDeliveryStage
714+
cfg@LeiosConfig {pipeline = _ :: SingPipeline p}
715+
slotCfg
716+
ibSlot
717+
deliveryTime
718+
| before loPropose = Nothing -- TODO future blocks?
719+
| before loDeliver2 = Just IbDuringProposeOrDeliver1
720+
| before loEndorse = Just IbDuringDeliver2
721+
| before (succ hiEndorse) = Just IbDuringEndorse
722+
| otherwise = Nothing -- TODO late blocks?
723+
where
724+
p = pipelineOf @p cfg Propose ibSlot
725+
726+
before sl = deliveryTime < slotTime slotCfg sl
727+
728+
(loPropose, _) = stageRangeOf @p cfg p Propose
729+
(loDeliver2, _) = stageRangeOf @p cfg p Deliver2
730+
(loEndorse, hiEndorse) = stageRangeOf @p cfg p Endorse
688731

689-
-- | Invokes 'inputBlocksToEndorse1' as many times as 'lateIbInclusion'
690-
-- requires
691732
inputBlocksToEndorse ::
692733
LeiosConfig ->
693734
-- | current slot
694735
SlotNo ->
695736
InputBlocksSnapshot ->
696737
[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]
738+
inputBlocksToEndorse cfg@LeiosConfig{pipeline = _ :: SingPipeline p} current buffer =
739+
let hi = pipelineOf @p cfg Endorse current in
740+
let lo = if cfg.lateIbInclusion then pipelineMonus hi 2 else hi
741+
in
742+
buffer.validInputBlocks
743+
InputBlocksQuery
744+
{ generatedBetween = (lo, hi)
745+
, receivedBy = IbDuringDeliver2
746+
}
708747

709748
-- | Returns possible EBs to reference from current pipeline EB.
710749
endorseBlocksToReference ::
@@ -760,21 +799,24 @@ shouldVoteOnEB ::
760799
shouldVoteOnEB cfg@LeiosConfig{voteSendStage} _ slot _buffers _
761800
-- checks whether a pipeline has been started before.
762801
| Nothing <- stageRange cfg voteSendStage slot Propose = const False
763-
shouldVoteOnEB cfg@LeiosConfig{voteSendStage} slotConfig slot buffers ebuffers = cond
802+
shouldVoteOnEB cfg@LeiosConfig{voteSendStage = voteSendStage :: Stage p} slotConfig slot buffers ebuffers = cond
764803
where
765-
generatedBetween = fromMaybe (error "impossible") $ stageRange cfg voteSendStage slot Propose
804+
generatedBetween = (lo, hi)
805+
where
806+
hi = pipelineOf @p cfg voteSendStage slot
807+
lo = if cfg.lateIbInclusion then pipelineMonus hi 2 else hi
766808
receivedByEndorse =
767809
buffers.validInputBlocks
768810
InputBlocksQuery
769811
{ generatedBetween
770-
, receivedBy = fromMaybe (error "impossible") $ stageEnd cfg voteSendStage slot Endorse
812+
, receivedBy = IbDuringEndorse
771813
}
772814
receivedByDeliver1 = buffers.validInputBlocks q
773815
where
774816
q =
775817
InputBlocksQuery
776818
{ generatedBetween
777-
, receivedBy = fromMaybe (error "impossible") $ stageEnd cfg voteSendStage slot Deliver1
819+
, receivedBy = IbDuringProposeOrDeliver1
778820
}
779821
-- Order of references in EndorseBlock matters for ledger state, so we stick to lists.
780822
-- Note: maybe order on (slot, subSlot, vrf proof) should be used instead?

0 commit comments

Comments
 (0)