Skip to content

Commit 8b08341

Browse files
committed
Support leios-late-ib-inclusion
1 parent b20de35 commit 8b08341

File tree

8 files changed

+121
-8
lines changed

8 files changed

+121
-8
lines changed

data/simulation/config.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ export interface Config {
3939
* Only supported by Haskell simulation. */
4040
"leios-vote-send-recv-stages": boolean;
4141
/**
42-
* Extends Leios so that EB producers include IBs directly from previous pipelines
43-
* where no certified EB was observed.
44-
*
45-
* Only supported by Rust simulation. */
42+
* Extends Leios so that EB producers include IBs directly from previous pipelines.
43+
* Due to casuality, the EB must always include them, even if those IBs end up being
44+
* certified in their own pipeline.
45+
*/
4646
"leios-late-ib-inclusion": boolean;
4747
/**
4848
* The expected time it takes a header to fully diffuse across the network.

leios-trace-hs/src/LeiosConfig.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ data Config = Config
9999
, leiosStageActiveVotingSlots :: Word
100100
, leiosVoteSendRecvStages :: Bool
101101
, leiosVariant :: LeiosVariant
102+
, leiosLateIbInclusion :: Bool
102103
, leiosHeaderDiffusionTimeMs :: DurationMs
103104
, praosChainQuality :: Double
104105
, txGenerationDistribution :: Distribution
@@ -171,6 +172,7 @@ instance Default Config where
171172
, leiosStageActiveVotingSlots = 1
172173
, leiosVoteSendRecvStages = False
173174
, leiosVariant = Short
175+
, leiosLateIbInclusion = True
174176
, leiosHeaderDiffusionTimeMs = 1000
175177
, praosChainQuality = 40
176178
, txGenerationDistribution = Exp{lambda = 0.85, scale = Just 1000}
@@ -243,6 +245,7 @@ configToKVsWith getter cfg =
243245
, get @"treatBlocksAsFull" getter cfg
244246
, get @"cleanupPolicies" getter cfg
245247
, get @"leiosVariant" getter cfg
248+
, get @"leiosLateIbInclusion" getter cfg
246249
, get @"leiosHeaderDiffusionTimeMs" getter cfg
247250
, get @"praosChainQuality" getter cfg
248251
, get @"simulateTransactions" getter cfg
@@ -329,6 +332,7 @@ instance FromJSON Config where
329332
treatBlocksAsFull <- parseFieldOrDefault @Config @"treatBlocksAsFull" obj
330333
cleanupPolicies <- parseFieldOrDefault @Config @"cleanupPolicies" obj
331334
leiosVariant <- parseFieldOrDefault @Config @"leiosVariant" obj
335+
leiosLateIbInclusion <- parseFieldOrDefault @Config @"leiosLateIbInclusion" obj
332336
leiosHeaderDiffusionTimeMs <- parseFieldOrDefault @Config @"leiosHeaderDiffusionTimeMs" obj
333337
praosChainQuality <- parseFieldOrDefault @Config @"praosChainQuality" obj
334338
simulateTransactions <- parseFieldOrDefault @Config @"simulateTransactions" obj

leios-trace-verifier/hs-src/test/Spec/Scenario.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import qualified Data.Map.Strict as M
1919
import qualified Data.Set as S
2020

2121
config :: Config
22-
config = Config{relayStrategy = RequestFromFirst, tcpCongestionControl = True, multiplexMiniProtocols = True, treatBlocksAsFull = False, cleanupPolicies = CleanupPolicies (S.fromList [CleanupExpiredVote]), simulateTransactions = True, leiosStageLengthSlots = 2, leiosStageActiveVotingSlots = 1, leiosVoteSendRecvStages = False, leiosVariant = Short, leiosHeaderDiffusionTimeMs = 1000.0, praosChainQuality = 20.0, txGenerationDistribution = Exp{lambda = 0.85, scale = pure 1000.0}, txSizeBytesDistribution = LogNormal{mu = 6.833, sigma = 1.127}, txValidationCpuTimeMs = 1.5, txMaxSizeBytes = 16384, rbGenerationProbability = 5.0e-2, rbGenerationCpuTimeMs = 1.0, rbHeadValidationCpuTimeMs = 1.0, rbHeadSizeBytes = 1024, rbBodyMaxSizeBytes = 90112, rbBodyLegacyPraosPayloadValidationCpuTimeMsConstant = 50.0, rbBodyLegacyPraosPayloadValidationCpuTimeMsPerByte = 5.0e-4, rbBodyLegacyPraosPayloadAvgSizeBytes = 0, ibGenerationProbability = 5.0, ibGenerationCpuTimeMs = 130.0, ibHeadSizeBytes = 304, ibHeadValidationCpuTimeMs = 1.0, ibBodyValidationCpuTimeMsConstant = 50.0, ibBodyValidationCpuTimeMsPerByte = 5.0e-4, ibBodyMaxSizeBytes = 327680, ibBodyAvgSizeBytes = 98304, ibDiffusionStrategy = FreshestFirst, ibDiffusionMaxWindowSize = 100, ibDiffusionMaxHeadersToRequest = 100, ibDiffusionMaxBodiesToRequest = 1, ibShards = 50, ebGenerationProbability = 1.5, ebGenerationCpuTimeMs = 75.0, ebValidationCpuTimeMs = 1.0, ebSizeBytesConstant = 240, ebSizeBytesPerIb = 32, ebDiffusionStrategy = PeerOrder, ebDiffusionMaxWindowSize = 100, ebDiffusionMaxHeadersToRequest = 100, ebDiffusionMaxBodiesToRequest = 1, ebMaxAgeSlots = 100, ebMaxAgeForRelaySlots = 40, voteGenerationProbability = 500.0, voteGenerationCpuTimeMsConstant = 0.164, voteGenerationCpuTimeMsPerIb = 0.0, voteValidationCpuTimeMs = 0.816, voteThreshold = 300, voteBundleSizeBytesConstant = 0, voteBundleSizeBytesPerEb = 105, voteDiffusionStrategy = PeerOrder, voteDiffusionMaxWindowSize = 100, voteDiffusionMaxHeadersToRequest = 100, voteDiffusionMaxBodiesToRequest = 1, certGenerationCpuTimeMsConstant = 90.0, certGenerationCpuTimeMsPerNode = 0.0, certValidationCpuTimeMsConstant = 130.0, certValidationCpuTimeMsPerNode = 0.0, certSizeBytesConstant = 7168, certSizeBytesPerNode = 0}
22+
config = Config{relayStrategy = RequestFromFirst, tcpCongestionControl = True, multiplexMiniProtocols = True, treatBlocksAsFull = False, cleanupPolicies = CleanupPolicies (S.fromList [CleanupExpiredVote]), simulateTransactions = True, leiosStageLengthSlots = 2, leiosStageActiveVotingSlots = 1, leiosVoteSendRecvStages = False, leiosVariant = Short, leiosLateIbInclusion = False, leiosHeaderDiffusionTimeMs = 1000.0, praosChainQuality = 20.0, txGenerationDistribution = Exp{lambda = 0.85, scale = pure 1000.0}, txSizeBytesDistribution = LogNormal{mu = 6.833, sigma = 1.127}, txValidationCpuTimeMs = 1.5, txMaxSizeBytes = 16384, rbGenerationProbability = 5.0e-2, rbGenerationCpuTimeMs = 1.0, rbHeadValidationCpuTimeMs = 1.0, rbHeadSizeBytes = 1024, rbBodyMaxSizeBytes = 90112, rbBodyLegacyPraosPayloadValidationCpuTimeMsConstant = 50.0, rbBodyLegacyPraosPayloadValidationCpuTimeMsPerByte = 5.0e-4, rbBodyLegacyPraosPayloadAvgSizeBytes = 0, ibGenerationProbability = 5.0, ibGenerationCpuTimeMs = 130.0, ibHeadSizeBytes = 304, ibHeadValidationCpuTimeMs = 1.0, ibBodyValidationCpuTimeMsConstant = 50.0, ibBodyValidationCpuTimeMsPerByte = 5.0e-4, ibBodyMaxSizeBytes = 327680, ibBodyAvgSizeBytes = 98304, ibDiffusionStrategy = FreshestFirst, ibDiffusionMaxWindowSize = 100, ibDiffusionMaxHeadersToRequest = 100, ibDiffusionMaxBodiesToRequest = 1, ibShards = 50, ebGenerationProbability = 1.5, ebGenerationCpuTimeMs = 75.0, ebValidationCpuTimeMs = 1.0, ebSizeBytesConstant = 240, ebSizeBytesPerIb = 32, ebDiffusionStrategy = PeerOrder, ebDiffusionMaxWindowSize = 100, ebDiffusionMaxHeadersToRequest = 100, ebDiffusionMaxBodiesToRequest = 1, ebMaxAgeSlots = 100, ebMaxAgeForRelaySlots = 40, voteGenerationProbability = 500.0, voteGenerationCpuTimeMsConstant = 0.164, voteGenerationCpuTimeMsPerIb = 0.0, voteValidationCpuTimeMs = 0.816, voteThreshold = 300, voteBundleSizeBytesConstant = 0, voteBundleSizeBytesPerEb = 105, voteDiffusionStrategy = PeerOrder, voteDiffusionMaxWindowSize = 100, voteDiffusionMaxHeadersToRequest = 100, voteDiffusionMaxBodiesToRequest = 1, certGenerationCpuTimeMsConstant = 90.0, certGenerationCpuTimeMsPerNode = 0.0, certValidationCpuTimeMsConstant = 130.0, certValidationCpuTimeMsPerNode = 0.0, certSizeBytesConstant = 7168, certSizeBytesPerNode = 0}
2323

2424
topology :: Topology 'COORD2D
2525
topology = Topology{nodes = M.fromList [(NodeName "node-0", Node{nodeInfo = NodeInfo{stake = 500, cpuCoreCount = CpuCoreCount mzero, location = LocCoord2D{coord2D = Point{_1 = 0.12000040231003672, _2 = 0.1631004621065356}}, adversarial = mzero}, producers = M.fromList [(NodeName "node-1", LinkInfo{latencyMs = 141.01364015418432, bandwidthBytesPerSecond = BandwidthBps $ pure 1024000}), (NodeName "node-2", LinkInfo{latencyMs = 254.6249782835189, bandwidthBytesPerSecond = BandwidthBps $ pure 1024000})]}), (NodeName "node-1", Node{nodeInfo = NodeInfo{stake = 200, cpuCoreCount = CpuCoreCount mzero, location = LocCoord2D{coord2D = Point{_1 = 0.34276660615051174, _2 = 0.2636899791034371}}, adversarial = mzero}, producers = M.fromList [(NodeName "node-2", LinkInfo{latencyMs = 175.32530255486685, bandwidthBytesPerSecond = BandwidthBps $ pure 1024000}), (NodeName "node-3", LinkInfo{latencyMs = 379.1167948193313, bandwidthBytesPerSecond = BandwidthBps $ pure 1024000})]}), (NodeName "node-2", Node{nodeInfo = NodeInfo{stake = 100, cpuCoreCount = CpuCoreCount mzero, location = LocCoord2D{coord2D = Point{_1 = 0.5150493264153491, _2 = 0.27873594531347595}}, adversarial = mzero}, producers = M.fromList [(NodeName "node-3", LinkInfo{latencyMs = 248.31457793649423, bandwidthBytesPerSecond = BandwidthBps $ pure 1024000})]}), (NodeName "node-3", Node{nodeInfo = NodeInfo{stake = 0, cpuCoreCount = CpuCoreCount mzero, location = LocCoord2D{coord2D = Point{_1 = 0.3503537969220088, _2 = 0.13879558055660354}}, adversarial = mzero}, producers = M.fromList [(NodeName "node-0", LinkInfo{latencyMs = 140.19739576271448, bandwidthBytesPerSecond = BandwidthBps $ pure 1024000})]})]}

simulation/ouroboros-leios-sim.cabal

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ test-suite ols-test
218218
, bytestring
219219
other-modules:
220220
Paths_ouroboros_leios_sim
221-
Test.Topology
222221
Test.Config
222+
Test.ShortToFull
223+
Test.Topology
223224
default-language: Haskell2010

simulation/src/LeiosProtocol/Short.hs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ data LeiosConfig = forall p. IsPipeline p => LeiosConfig
111111
, variant :: LeiosVariant
112112
, headerDiffusionTime :: NominalDiffTime
113113
-- ^ Δ_{hdr}.
114+
, lateIbInclusion :: Bool
115+
-- ^ Whether an EB also includes IBs from the two previous iterations.
116+
--
117+
-- TODO Merely one previous iteration if 'pipeline' is 'SingleVote'?
114118
, pipelinesToReferenceFromEB :: Int
115119
-- ^ how many older pipelines to reference from an EB when `variant = Full`.
116120
, votingFrequencyPerStage :: Double
@@ -147,6 +151,7 @@ convertConfig disk =
147151
, cleanupPolicies = disk.cleanupPolicies
148152
, variant = disk.leiosVariant
149153
, headerDiffusionTime = realToFrac $ durationMsToDiffTime disk.leiosHeaderDiffusionTimeMs
154+
, lateIbInclusion = disk.leiosLateIbInclusion
150155
, pipelinesToReferenceFromEB =
151156
if disk.leiosVariant == Full
152157
then
@@ -285,6 +290,7 @@ delaysAndSizesAsFull cfg@LeiosConfig{pipeline, voteSendStage} =
285290
, cleanupPolicies = cfg.cleanupPolicies
286291
, variant = cfg.variant
287292
, headerDiffusionTime = cfg.headerDiffusionTime
293+
, lateIbInclusion = cfg.lateIbInclusion
288294
, pipelinesToReferenceFromEB = cfg.pipelinesToReferenceFromEB
289295
, activeVotingStageLength = cfg.activeVotingStageLength
290296
, votingFrequencyPerStage = cfg.votingFrequencyPerStage
@@ -664,13 +670,13 @@ data InputBlocksQuery = InputBlocksQuery
664670
-- ^ This is checked against time the body is downloaded, before validation.
665671
}
666672

667-
inputBlocksToEndorse ::
673+
inputBlocksToEndorse1 ::
668674
LeiosConfig ->
669675
-- | current slot
670676
SlotNo ->
671677
InputBlocksSnapshot ->
672678
[InputBlockId]
673-
inputBlocksToEndorse cfg@LeiosConfig{pipeline = _ :: SingPipeline p} current buffer = fromMaybe [] $ do
679+
inputBlocksToEndorse1 cfg@LeiosConfig{pipeline = _ :: SingPipeline p} current buffer = fromMaybe [] $ do
674680
generatedBetween <- stageRange @p cfg Endorse current Propose
675681
receivedBy <- stageEnd @p cfg Endorse current Deliver2
676682
pure $
@@ -680,6 +686,26 @@ inputBlocksToEndorse cfg@LeiosConfig{pipeline = _ :: SingPipeline p} current buf
680686
, receivedBy
681687
}
682688

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]
708+
683709
-- | Returns possible EBs to reference from current pipeline EB.
684710
endorseBlocksToReference ::
685711
LeiosConfig ->

simulation/src/LeiosProtocol/Short/Sim.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ traceRelayLink1 connectionOptions =
426426
, cleanupPolicies = def
427427
, variant = Short
428428
, headerDiffusionTime = 1
429+
, lateIbInclusion = False
429430
, pipelinesToReferenceFromEB = 0
430431
, activeVotingStageLength = 1
431432
, pipeline = SingSingleVote

simulation/test/Main.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Main where
22

33
import qualified Test.Config
4+
import qualified Test.ShortToFull
45
import Test.Tasty (defaultMain, testGroup)
56
import qualified Test.Topology
67

@@ -9,4 +10,5 @@ main =
910
defaultMain . testGroup "ouroboros-leios-sim" $
1011
[ Test.Topology.tests
1112
, Test.Config.tests
13+
, Test.ShortToFull.tests
1214
]
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
{-# LANGUAGE OverloadedRecordDot #-}
2+
{-# LANGUAGE RecordWildCards #-}
3+
4+
module Test.ShortToFull where
5+
6+
import Data.Default (def)
7+
import LeiosProtocol.Common (InputBlockId (..), NodeId (..), SlotNo)
8+
import LeiosProtocol.Config (Config)
9+
import qualified LeiosProtocol.Short as Short
10+
import Test.QuickCheck as Q
11+
import Test.Tasty (TestTree, testGroup)
12+
import Test.Tasty.QuickCheck (testProperty)
13+
14+
tests :: TestTree
15+
tests =
16+
testGroup
17+
"ShortToFull"
18+
[ testProperty "test_leiosLateIbInclusion" test_leiosLateIbInclusion
19+
]
20+
21+
data Test_leiosLateIbInclusion = Test_leiosLateIbInclusion
22+
{ ibTable :: [(Int, SlotNo, SlotNo)] -- the Int is @zip [0..]@, /before shrinking/
23+
, current :: SlotNo
24+
}
25+
deriving (Show)
26+
27+
instance Q.Arbitrary Test_leiosLateIbInclusion where
28+
arbitrary = do
29+
let cfg = Short.convertConfig def
30+
let arbSlot = Q.choose (0, 10 * cfg.sliceLength)
31+
let toSlot :: Int -> SlotNo
32+
toSlot = toEnum
33+
current <- toSlot <$> arbSlot
34+
ibTable <- do
35+
n <- Q.choose (0, 1000)
36+
flip mapM [0 .. n - 1] $ \i -> do
37+
gen <- Q.choose (0, fromEnum current)
38+
delay <- Q.choose (0, 3 * cfg.sliceLength)
39+
pure (i, toSlot gen, toSlot (gen + delay))
40+
pure Test_leiosLateIbInclusion{..}
41+
42+
shrink testSetup =
43+
[ testSetup{ibTable = ibTable'}
44+
| ibTable' <- shrinkList (const []) testSetup.ibTable
45+
]
46+
47+
test_leiosLateIbInclusion :: Test_leiosLateIbInclusion -> Property
48+
test_leiosLateIbInclusion testSetup =
49+
Q.counterexample (show (cfg.sliceLength, iterations))
50+
$ Q.counterexample ("on " <> show (map (.num) on))
51+
$ Q.counterexample
52+
(unlines $ ("off" :) $ map (show . map (.num) . off) $ iterations)
53+
$ on Q.=== concatMap off iterations
54+
where
55+
Test_leiosLateIbInclusion{..} = testSetup
56+
cfg = Short.convertConfig def
57+
ibSnapshot =
58+
Short.InputBlocksSnapshot
59+
{ validInputBlocks = \q ->
60+
[ InputBlockId{node = NodeId 0, num = i}
61+
| (i, gen, recv) <- ibTable
62+
, gen `Short.inRange` q.generatedBetween
63+
, recv <= q.receivedBy
64+
]
65+
}
66+
on =
67+
Short.inputBlocksToEndorse
68+
cfg{Short.lateIbInclusion = True}
69+
current
70+
ibSnapshot
71+
off sl =
72+
Short.inputBlocksToEndorse
73+
cfg{Short.lateIbInclusion = False}
74+
sl
75+
ibSnapshot
76+
iterations =
77+
let capL = fromIntegral cfg.sliceLength
78+
in -- detect underflow
79+
dropWhile (> current) [current - 2 * capL, current - capL, current]

0 commit comments

Comments
 (0)