17
17
module LeiosProtocol.Short (module LeiosProtocol.Short , DiffusionStrategy (.. )) where
18
18
19
19
import Chan (mkConnectionConfig )
20
+ import Control.DeepSeq
20
21
import Control.Exception (assert )
21
22
import Control.Monad (guard )
22
23
import Data.Kind
@@ -105,6 +106,11 @@ data LeiosConfig = forall p. IsPipeline p => LeiosConfig
105
106
-- ^ maximum age of an uncertified endorsement block before it expires
106
107
, cleanupPolicies :: CleanupPolicies
107
108
-- ^ 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`.
108
114
, votingFrequencyPerStage :: Double
109
115
, voteSendStage :: Stage p
110
116
, votesForCertificate :: Int
@@ -125,17 +131,25 @@ convertConfig disk =
125
131
else (\ x -> x)
126
132
)
127
133
$ case voting of
128
- SomeStage pipeline voteSendStage ->
134
+ SomeStage pipeline voteSendStage -> do
135
+ let sliceLength = fromIntegral disk. leiosStageLengthSlots
129
136
LeiosConfig
130
137
{ praos
131
138
, pipeline
132
139
, voteSendStage
133
- , sliceLength = fromIntegral disk . leiosStageLengthSlots
140
+ , sliceLength
134
141
, inputBlockFrequencyPerSlot = disk. ibGenerationProbability
135
142
, endorseBlockFrequencyPerStage = disk. ebGenerationProbability
136
143
, maxEndorseBlockAgeSlots = fromIntegral disk. ebMaxAgeSlots
137
144
, maxEndorseBlockAgeForRelaySlots = fromIntegral disk. ebMaxAgeForRelaySlots
138
145
, 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
139
153
, activeVotingStageLength = fromIntegral disk. leiosStageActiveVotingSlots
140
154
, votingFrequencyPerStage = disk. voteGenerationProbability
141
155
, votesForCertificate = fromIntegral disk. voteThreshold
@@ -210,6 +224,8 @@ convertConfig disk =
210
224
fromIntegral $
211
225
disk. ebSizeBytesConstant
212
226
+ disk. ebSizeBytesPerIb `forEach` eb. inputBlocks
227
+ -- TODO: make it a per-ref field.
228
+ + disk. ebSizeBytesPerIb `forEach` eb. endorseBlocksEarlierPipeline
213
229
, voteMsg = \ vt ->
214
230
fromIntegral $
215
231
disk. voteBundleSizeBytesConstant
@@ -265,6 +281,9 @@ delaysAndSizesAsFull cfg@LeiosConfig{pipeline, voteSendStage} =
265
281
, maxEndorseBlockAgeSlots = cfg. maxEndorseBlockAgeSlots
266
282
, maxEndorseBlockAgeForRelaySlots = fromIntegral cfg. maxEndorseBlockAgeForRelaySlots
267
283
, cleanupPolicies = cfg. cleanupPolicies
284
+ , variant = cfg. variant
285
+ , headerDiffusionTime = cfg. headerDiffusionTime
286
+ , pipelinesToReferenceFromEB = cfg. pipelinesToReferenceFromEB
268
287
, activeVotingStageLength = cfg. activeVotingStageLength
269
288
, votingFrequencyPerStage = cfg. votingFrequencyPerStage
270
289
, voteSendStage = voteSendStage
@@ -395,7 +414,7 @@ instance IsPipeline a => Bounded (Stage a) where
395
414
[] -> undefined
396
415
maxBound = last allStages
397
416
398
- inRange :: SlotNo -> (SlotNo , SlotNo ) -> Bool
417
+ inRange :: Ord a => a -> (a , a ) -> Bool
399
418
inRange s (a, b) = a <= s && s <= b
400
419
401
420
rangePrefix :: Int -> (SlotNo , SlotNo ) -> (SlotNo , SlotNo )
@@ -473,10 +492,16 @@ proposeRange :: LeiosConfig -> PipelineNo -> (SlotNo, SlotNo)
473
492
proposeRange cfg@ LeiosConfig {pipeline = (_ :: SingPipeline p )} p =
474
493
stageRangeOf @ p cfg p Propose
475
494
495
+ pipelineRange :: LeiosConfig -> PipelineNo -> (SlotNo , SlotNo )
496
+ pipelineRange cfg p = (fst $ proposeRange cfg p, lastVoteRecv cfg p)
497
+
476
498
lastUnadoptedEB :: LeiosConfig -> PipelineNo -> SlotNo
477
499
lastUnadoptedEB leios@ LeiosConfig {pipeline = (_ :: SingPipeline p ), maxEndorseBlockAgeSlots} pipelineNo =
478
500
lastVoteRecv leios pipelineNo + toEnum maxEndorseBlockAgeSlots
479
501
502
+ endorseBlockPipeline :: LeiosConfig -> EndorseBlock -> PipelineNo
503
+ endorseBlockPipeline cfg@ LeiosConfig {pipeline = _ :: SingPipeline p } eb = pipelineOf @ p cfg Endorse eb. slot
504
+
480
505
----------------------------------------------------------------------------------------------
481
506
---- Smart constructors
482
507
----------------------------------------------------------------------------------------------
@@ -510,21 +535,27 @@ mkInputBlock _cfg header bodySize = assert (messageSizeBytes ib >= segmentSize)
510
535
ib = InputBlock {header, body = InputBlockBody {id = header. id , size = bodySize, slot = header. slot}}
511
536
512
537
mkEndorseBlock ::
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 , .. }
519
548
520
549
mockEndorseBlock :: LeiosConfig -> Int -> EndorseBlock
521
550
mockEndorseBlock 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 ]]
528
559
529
560
mockFullEndorseBlock :: LeiosConfig -> EndorseBlock
530
561
mockFullEndorseBlock cfg = mockEndorseBlock cfg $ cfg. sliceLength * (ceiling cfg. inputBlockFrequencyPerSlot)
@@ -613,8 +644,10 @@ newtype InputBlocksSnapshot = InputBlocksSnapshot
613
644
{ validInputBlocks :: InputBlocksQuery -> [InputBlockId ]
614
645
}
615
646
616
- newtype EndorseBlocksSnapshot = EndorseBlocksSnapshot
647
+ data EndorseBlocksSnapshot = EndorseBlocksSnapshot
617
648
{ validEndorseBlocks :: (SlotNo , SlotNo ) -> [EndorseBlock ]
649
+ , -- , endorseBlocksInChain :: (SlotNo, SlotNo) -> [EndorseBlock]
650
+ certifiedEndorseBlocks :: (PipelineNo , PipelineNo ) -> [(PipelineNo , [(EndorseBlock , Certificate , UTCTime )])]
618
651
}
619
652
620
653
-- | Both constraints are inclusive.
@@ -640,16 +673,37 @@ inputBlocksToEndorse cfg@LeiosConfig{pipeline = _ :: SingPipeline p} current buf
640
673
, receivedBy
641
674
}
642
675
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
+
643
694
shouldVoteOnEB ::
644
695
LeiosConfig ->
696
+ SlotConfig ->
645
697
-- | current slot
646
698
SlotNo ->
647
699
InputBlocksSnapshot ->
700
+ EndorseBlocksSnapshot ->
648
701
EndorseBlock ->
649
702
Bool
650
- shouldVoteOnEB cfg@ LeiosConfig {voteSendStage} slot _buffers
703
+ shouldVoteOnEB cfg@ LeiosConfig {voteSendStage} _ slot _buffers _
704
+ -- checks whether a pipeline has been started before.
651
705
| 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
653
707
where
654
708
generatedBetween = fromMaybe (error " impossible" ) $ stageRange cfg voteSendStage slot Propose
655
709
receivedByEndorse =
@@ -669,35 +723,50 @@ shouldVoteOnEB cfg@LeiosConfig{voteSendStage} slot buffers = cond
669
723
-- Note: maybe order on (slot, subSlot, vrf proof) should be used instead?
670
724
subset xs ys = all (`elem` ys) xs
671
725
726
+ endOfPipelineTime p = slotTime slotConfig (snd (pipelineRange cfg p))
727
+
672
728
cond :: EndorseBlock -> Bool
673
- cond eb = assert assumptions $ acd && b
729
+ cond eb = assert assumptions $ acd && b && full
674
730
where
675
731
assumptions =
676
732
null eb. endorseBlocksEarlierStage
677
- && null eb. endorseBlocksEarlierPipeline
733
+ && ( null eb. endorseBlocksEarlierPipeline || cfg . variant == Full )
678
734
&& eb. slot `inRange` fromMaybe (error " impossible" ) (stageRange cfg voteSendStage slot Endorse )
679
735
-- A. all referenced IBs have been received by the end of the Endorse stage,
680
736
-- C. all referenced IBs validate (wrt. script execution), and,
681
737
-- D. only IBs from this pipeline’s Propose stage are referenced (and not from other pipelines).
682
738
acd = eb. inputBlocks `subset` receivedByEndorse
683
739
-- B. all IBs seen by the end of the Deliver 1 stage are referenced,
684
740
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
+ ]
685
756
686
757
endorseBlocksToVoteFor ::
687
758
LeiosConfig ->
759
+ SlotConfig ->
688
760
-- | current slot
689
761
SlotNo ->
690
762
InputBlocksSnapshot ->
691
763
EndorseBlocksSnapshot ->
692
764
[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
695
767
in filter cond $
696
768
maybe [] ebs. validEndorseBlocks (stageRange cfg voteSendStage slot Endorse )
697
769
698
- endorseBlockPipeline :: LeiosConfig -> EndorseBlock -> PipelineNo
699
- endorseBlockPipeline cfg@ LeiosConfig {pipeline = _ :: SingPipeline p } eb = pipelineOf @ p cfg Endorse eb. slot
700
-
701
770
-----------------------------------------------------------------
702
771
---- Expected generation rates in each slot.
703
772
-----------------------------------------------------------------
0 commit comments