1717module LeiosProtocol.Short (module LeiosProtocol.Short , DiffusionStrategy (.. )) where
1818
1919import Chan (mkConnectionConfig )
20+ import Control.DeepSeq
2021import Control.Exception (assert )
2122import Control.Monad (guard )
2223import Data.Kind
@@ -105,6 +106,11 @@ data LeiosConfig = forall p. IsPipeline p => LeiosConfig
105106 -- ^ maximum age of an uncertified endorsement block before it expires
106107 , cleanupPolicies :: CleanupPolicies
107108 -- ^ active cleanup policies
109+ , variant :: LeiosVariant
110+ , headerDiffusionTime :: NominalDiffTime
111+ -- ^ Δ_{hdr}.
112+ , pipelinesToReferenceFromEB :: Int
113+ -- ^ how many older pipelines to reference from an EB when `variant = Full`.
108114 , votingFrequencyPerStage :: Double
109115 , voteSendStage :: Stage p
110116 , votesForCertificate :: Int
@@ -125,17 +131,25 @@ convertConfig disk =
125131 else (\ x -> x)
126132 )
127133 $ case voting of
128- SomeStage pipeline voteSendStage ->
134+ SomeStage pipeline voteSendStage -> do
135+ let sliceLength = fromIntegral disk. leiosStageLengthSlots
129136 LeiosConfig
130137 { praos
131138 , pipeline
132139 , voteSendStage
133- , sliceLength = fromIntegral disk . leiosStageLengthSlots
140+ , sliceLength
134141 , inputBlockFrequencyPerSlot = disk. ibGenerationProbability
135142 , endorseBlockFrequencyPerStage = disk. ebGenerationProbability
136143 , maxEndorseBlockAgeSlots = fromIntegral disk. ebMaxAgeSlots
137144 , maxEndorseBlockAgeForRelaySlots = fromIntegral disk. ebMaxAgeForRelaySlots
138145 , cleanupPolicies = disk. cleanupPolicies
146+ , variant = disk. leiosVariant
147+ , headerDiffusionTime = realToFrac $ durationMsToDiffTime disk. leiosHeaderDiffusionTimeMs
148+ , pipelinesToReferenceFromEB =
149+ if disk. leiosVariant == Full
150+ then
151+ ceiling ((3 * disk. praosChainQuality) / fromIntegral sliceLength) - 2
152+ else 0
139153 , activeVotingStageLength = fromIntegral disk. leiosStageActiveVotingSlots
140154 , votingFrequencyPerStage = disk. voteGenerationProbability
141155 , votesForCertificate = fromIntegral disk. voteThreshold
@@ -210,6 +224,8 @@ convertConfig disk =
210224 fromIntegral $
211225 disk. ebSizeBytesConstant
212226 + disk. ebSizeBytesPerIb `forEach` eb. inputBlocks
227+ -- TODO: make it a per-ref field.
228+ + disk. ebSizeBytesPerIb `forEach` eb. endorseBlocksEarlierPipeline
213229 , voteMsg = \ vt ->
214230 fromIntegral $
215231 disk. voteBundleSizeBytesConstant
@@ -265,6 +281,9 @@ delaysAndSizesAsFull cfg@LeiosConfig{pipeline, voteSendStage} =
265281 , maxEndorseBlockAgeSlots = cfg. maxEndorseBlockAgeSlots
266282 , maxEndorseBlockAgeForRelaySlots = fromIntegral cfg. maxEndorseBlockAgeForRelaySlots
267283 , cleanupPolicies = cfg. cleanupPolicies
284+ , variant = cfg. variant
285+ , headerDiffusionTime = cfg. headerDiffusionTime
286+ , pipelinesToReferenceFromEB = cfg. pipelinesToReferenceFromEB
268287 , activeVotingStageLength = cfg. activeVotingStageLength
269288 , votingFrequencyPerStage = cfg. votingFrequencyPerStage
270289 , voteSendStage = voteSendStage
@@ -395,7 +414,7 @@ instance IsPipeline a => Bounded (Stage a) where
395414 [] -> undefined
396415 maxBound = last allStages
397416
398- inRange :: SlotNo -> (SlotNo , SlotNo ) -> Bool
417+ inRange :: Ord a => a -> (a , a ) -> Bool
399418inRange s (a, b) = a <= s && s <= b
400419
401420rangePrefix :: Int -> (SlotNo , SlotNo ) -> (SlotNo , SlotNo )
@@ -473,10 +492,16 @@ proposeRange :: LeiosConfig -> PipelineNo -> (SlotNo, SlotNo)
473492proposeRange cfg@ LeiosConfig {pipeline = (_ :: SingPipeline p )} p =
474493 stageRangeOf @ p cfg p Propose
475494
495+ pipelineRange :: LeiosConfig -> PipelineNo -> (SlotNo , SlotNo )
496+ pipelineRange cfg p = (fst $ proposeRange cfg p, lastVoteRecv cfg p)
497+
476498lastUnadoptedEB :: LeiosConfig -> PipelineNo -> SlotNo
477499lastUnadoptedEB leios@ LeiosConfig {pipeline = (_ :: SingPipeline p ), maxEndorseBlockAgeSlots} pipelineNo =
478500 lastVoteRecv leios pipelineNo + toEnum maxEndorseBlockAgeSlots
479501
502+ endorseBlockPipeline :: LeiosConfig -> EndorseBlock -> PipelineNo
503+ endorseBlockPipeline cfg@ LeiosConfig {pipeline = _ :: SingPipeline p } eb = pipelineOf @ p cfg Endorse eb. slot
504+
480505----------------------------------------------------------------------------------------------
481506---- Smart constructors
482507----------------------------------------------------------------------------------------------
@@ -510,21 +535,27 @@ mkInputBlock _cfg header bodySize = assert (messageSizeBytes ib >= segmentSize)
510535 ib = InputBlock {header, body = InputBlockBody {id = header. id , size = bodySize, slot = header. slot}}
511536
512537mkEndorseBlock ::
513- LeiosConfig -> EndorseBlockId -> SlotNo -> NodeId -> [InputBlockId ] -> EndorseBlock
514- mkEndorseBlock cfg@ LeiosConfig {pipeline = _ :: SingPipeline p } id slot producer inputBlocks =
515- -- Endorse blocks are produced at the beginning of the stage.
516- assert (stageStart @ p cfg Endorse slot Endorse == Just slot) $
517- fixSize cfg $
518- EndorseBlock {endorseBlocksEarlierStage = [] , endorseBlocksEarlierPipeline = [] , size = 0 , .. }
538+ LeiosConfig -> EndorseBlockId -> SlotNo -> NodeId -> [EndorseBlockId ] -> [InputBlockId ] -> EndorseBlock
539+ mkEndorseBlock cfg@ LeiosConfig {pipeline = _ :: SingPipeline p } id slot producer endorseBlocksEarlierPipeline inputBlocks =
540+ assert (cfg. variant == Full || null endorseBlocksEarlierPipeline) $
541+ -- Endorse blocks are produced at the beginning of the stage.
542+ assert (stageStart @ p cfg Endorse slot Endorse == Just slot) $
543+ rnf endorseBlocksEarlierPipeline `seq`
544+ rnf inputBlocks `seq`
545+ fixSize
546+ cfg
547+ EndorseBlock {endorseBlocksEarlierStage = [] , size = 0 , .. }
519548
520549mockEndorseBlock :: LeiosConfig -> Int -> EndorseBlock
521550mockEndorseBlock cfg n =
522- mkEndorseBlock
523- cfg
524- (EndorseBlockId (NodeId 0 ) 0 )
525- 0
526- (NodeId 0 )
527- [InputBlockId (NodeId 0 ) i | i <- [0 .. n - 1 ]]
551+ assert (cfg. variant /= Full ) $
552+ mkEndorseBlock
553+ cfg
554+ (EndorseBlockId (NodeId 0 ) 0 )
555+ 0
556+ (NodeId 0 )
557+ []
558+ [InputBlockId (NodeId 0 ) i | i <- [0 .. n - 1 ]]
528559
529560mockFullEndorseBlock :: LeiosConfig -> EndorseBlock
530561mockFullEndorseBlock cfg = mockEndorseBlock cfg $ cfg. sliceLength * (ceiling cfg. inputBlockFrequencyPerSlot)
@@ -613,8 +644,10 @@ newtype InputBlocksSnapshot = InputBlocksSnapshot
613644 { validInputBlocks :: InputBlocksQuery -> [InputBlockId ]
614645 }
615646
616- newtype EndorseBlocksSnapshot = EndorseBlocksSnapshot
647+ data EndorseBlocksSnapshot = EndorseBlocksSnapshot
617648 { validEndorseBlocks :: (SlotNo , SlotNo ) -> [EndorseBlock ]
649+ , -- , endorseBlocksInChain :: (SlotNo, SlotNo) -> [EndorseBlock]
650+ certifiedEndorseBlocks :: (PipelineNo , PipelineNo ) -> [(PipelineNo , [(EndorseBlock , Certificate , UTCTime )])]
618651 }
619652
620653-- | Both constraints are inclusive.
@@ -640,16 +673,37 @@ inputBlocksToEndorse cfg@LeiosConfig{pipeline = _ :: SingPipeline p} current buf
640673 , receivedBy
641674 }
642675
676+ -- | Returns possible EBs to reference from current pipeline EB.
677+ endorseBlocksToReference ::
678+ LeiosConfig ->
679+ PipelineNo ->
680+ EndorseBlocksSnapshot ->
681+ (PipelineNo -> UTCTime -> Bool ) ->
682+ [(PipelineNo , [EndorseBlock ])]
683+ endorseBlocksToReference LeiosConfig {variant = Short } _ _ _ = []
684+ endorseBlocksToReference cfg@ LeiosConfig {variant = Full } pl EndorseBlocksSnapshot {.. } checkDeliveryTime =
685+ [ (p, [eb | (eb, _, _) <- es])
686+ | (p, es) <- ebs
687+ , or [checkDeliveryTime p t | (_, _, t) <- es]
688+ ]
689+ where
690+ newestPL = toEnum $ max 0 $ fromEnum pl - 2
691+ oldestPL = toEnum $ max 0 $ fromEnum newestPL - cfg. pipelinesToReferenceFromEB
692+ ebs = certifiedEndorseBlocks (oldestPL, newestPL)
693+
643694shouldVoteOnEB ::
644695 LeiosConfig ->
696+ SlotConfig ->
645697 -- | current slot
646698 SlotNo ->
647699 InputBlocksSnapshot ->
700+ EndorseBlocksSnapshot ->
648701 EndorseBlock ->
649702 Bool
650- shouldVoteOnEB cfg@ LeiosConfig {voteSendStage} slot _buffers
703+ shouldVoteOnEB cfg@ LeiosConfig {voteSendStage} _ slot _buffers _
704+ -- checks whether a pipeline has been started before.
651705 | Nothing <- stageRange cfg voteSendStage slot Propose = const False
652- shouldVoteOnEB cfg@ LeiosConfig {voteSendStage} slot buffers = cond
706+ shouldVoteOnEB cfg@ LeiosConfig {voteSendStage} slotConfig slot buffers ebuffers = cond
653707 where
654708 generatedBetween = fromMaybe (error " impossible" ) $ stageRange cfg voteSendStage slot Propose
655709 receivedByEndorse =
@@ -669,35 +723,50 @@ shouldVoteOnEB cfg@LeiosConfig{voteSendStage} slot buffers = cond
669723 -- Note: maybe order on (slot, subSlot, vrf proof) should be used instead?
670724 subset xs ys = all (`elem` ys) xs
671725
726+ endOfPipelineTime p = slotTime slotConfig (snd (pipelineRange cfg p))
727+
672728 cond :: EndorseBlock -> Bool
673- cond eb = assert assumptions $ acd && b
729+ cond eb = assert assumptions $ acd && b && full
674730 where
675731 assumptions =
676732 null eb. endorseBlocksEarlierStage
677- && null eb. endorseBlocksEarlierPipeline
733+ && ( null eb. endorseBlocksEarlierPipeline || cfg . variant == Full )
678734 && eb. slot `inRange` fromMaybe (error " impossible" ) (stageRange cfg voteSendStage slot Endorse )
679735 -- A. all referenced IBs have been received by the end of the Endorse stage,
680736 -- C. all referenced IBs validate (wrt. script execution), and,
681737 -- D. only IBs from this pipeline’s Propose stage are referenced (and not from other pipelines).
682738 acd = eb. inputBlocks `subset` receivedByEndorse
683739 -- B. all IBs seen by the end of the Deliver 1 stage are referenced,
684740 b = receivedByDeliver1 `subset` eb. inputBlocks
741+ -- assumes eb.endorseBlocksEarlierPipeline are in pipeline order.
742+ full =
743+ and $
744+ zipWith elem eb. endorseBlocksEarlierPipeline $
745+ [ map (. id ) es
746+ | (_, es) <-
747+ endorseBlocksToReference
748+ cfg
749+ (endorseBlockPipeline cfg eb)
750+ ebuffers
751+ ( \ p t ->
752+ addUTCTime cfg. headerDiffusionTime t < endOfPipelineTime p
753+ )
754+ , not (null es)
755+ ]
685756
686757endorseBlocksToVoteFor ::
687758 LeiosConfig ->
759+ SlotConfig ->
688760 -- | current slot
689761 SlotNo ->
690762 InputBlocksSnapshot ->
691763 EndorseBlocksSnapshot ->
692764 [EndorseBlock ]
693- endorseBlocksToVoteFor cfg@ LeiosConfig {voteSendStage} slot ibs ebs =
694- let cond = shouldVoteOnEB cfg slot ibs
765+ endorseBlocksToVoteFor cfg@ LeiosConfig {voteSendStage} slotConfig slot ibs ebs =
766+ let cond = shouldVoteOnEB cfg slotConfig slot ibs ebs
695767 in filter cond $
696768 maybe [] ebs. validEndorseBlocks (stageRange cfg voteSendStage slot Endorse )
697769
698- endorseBlockPipeline :: LeiosConfig -> EndorseBlock -> PipelineNo
699- endorseBlockPipeline cfg@ LeiosConfig {pipeline = _ :: SingPipeline p } eb = pipelineOf @ p cfg Endorse eb. slot
700-
701770-----------------------------------------------------------------
702771---- Expected generation rates in each slot.
703772-----------------------------------------------------------------
0 commit comments