Skip to content

Commit 4ef1db0

Browse files
committed
simulation: implemented --conformance-events
* emits Slot and No${LeiosBlockId}Generated events.
1 parent 00283ce commit 4ef1db0

File tree

10 files changed

+3379
-143
lines changed

10 files changed

+3379
-143
lines changed

data/simulation/example.haskell.jsonl

Lines changed: 3316 additions & 0 deletions
Large diffs are not rendered by default.

data/simulation/trace.haskell.d.ts

Lines changed: 4 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,7 @@
11
/** Haskell simulation trace format */
2-
export interface HaskellTraceEvent {
3-
time_s: number;
4-
message: HaskellEvent;
5-
}
62

7-
type LeiosBlockKind = "IB" | "EB" | "VTBundle"
8-
type BlockKind = LeiosBlockKind | "RB";
9-
type BlockAction = "Generated" | "EnteredState";
3+
import * as shared from "./trace.shared";
104

11-
type HaskellEvent =
12-
| HaskellCpuEvent
13-
| HaskellBlockEvent
14-
| HaskellNetworkEvent
15-
| HaskellSlotEvent
16-
| HaskellNoBlockEvent;
17-
18-
type HaskellEventType =
19-
| CpuEventType
20-
| BlockEventType
21-
| NetworkEventType
22-
| SlotEventType
23-
| NoBlockEventType;
24-
25-
type SlotEventType = "Slot"
26-
interface HaskellSlotEvent {
27-
type: SlotEventType;
28-
node: string;
29-
slot: number;
30-
}
31-
32-
type NoBlockEventType = `No${LeiosBlockKind}Generated`
33-
interface HaskellNoBlockEvent {
34-
type: NoBlockEventType;
35-
node: string;
36-
slot: number;
37-
}
38-
39-
40-
type CpuEventType = "Cpu"
41-
interface HaskellCpuEvent {
42-
type: CpuEventType;
43-
node: string;
44-
cpu_time_s: number;
45-
// CPU task types: Block validation (ValIB, ValEB, ValRB), Header validation (ValIH, ValRH), Vote validation (ValVote). Format: "<task_type>: <id>"
46-
task_label: string; // e.g., "ValIB: 6-29" or "ValRH: 6253064077348247640"
47-
}
48-
49-
type BlockEventType = `${BlockKind}${BlockAction}`
50-
// Base block event interface with just identification info
51-
interface BaseBlockEvent {
52-
type: BlockEventType;
53-
slot: number;
54-
}
55-
56-
// Additional fields for Generated events
57-
interface GeneratedBlockEvent extends BaseBlockEvent {
58-
size_bytes: number;
59-
producer: string;
60-
}
61-
62-
interface GeneratedInputBlock extends GeneratedBlockEvent {
63-
id: string;
64-
payload_bytes?: number|null;
65-
rb_ref?: string|null;
66-
}
67-
interface BlockRef {
68-
id : string;
69-
}
70-
interface Endorsement {
71-
eb : BlockRef;
72-
}
73-
74-
interface GeneratedEndorserBlock extends GeneratedBlockEvent {
75-
id: string;
76-
input_blocks: BlockRef[];
77-
}
78-
79-
interface GeneratedRankingBlock extends GeneratedBlockEvent {
80-
endorsement?: Endorsement|null;
81-
endorsements?: Endorsement[]|null;
82-
vrf? : number;
83-
id? : string;
84-
payload_bytes? : number|null;
85-
parent?: {
86-
id: string;
87-
}|null;
88-
}
89-
90-
interface GeneratedVote extends GeneratedBlockEvent {
91-
id: string;
92-
votes: Record<string, number>;
93-
}
94-
95-
// EnteredState events only need the base identification info
96-
interface EnteredStateBlock extends BaseBlockEvent {
97-
id: string;
98-
node: string;
99-
}
100-
101-
type HaskellBlockEvent =
102-
| GeneratedInputBlock
103-
| GeneratedEndorserBlock
104-
| GeneratedRankingBlock
105-
| GeneratedVote
106-
| EnteredStateBlock;
107-
108-
109-
type NetworkAction = "Sent" | "Received"
110-
type NetworkEventType = `${BlockKind}${NetworkAction}`
111-
112-
interface HaskellNetworkEvent {
113-
type: NetworkEventType;
114-
sender?: string|null;
115-
recipient: string;
116-
msg_size_bytes?: number|null;
117-
sending_s?: number|null;
118-
id: string;
119-
ids?: string[]|null;
120-
}
121-
122-
export interface UnknownEvent {
123-
time_s: number;
124-
message: UnknownMessage;
125-
}
126-
127-
export interface UnknownMessage {
128-
/** @$ref "#/definitions/UnknownType" */
129-
type;
130-
}
131-
132-
// Type to validate `jq '.' -cs` of a log.
133-
type TraceEvents = (HaskellTraceEvent|UnknownEvent)[]
134-
135-
type KnownType = HaskellEventType
5+
type HaskellTraceEvent = shared.TraceEvent;
6+
type KnownType = shared.KnownType;
7+
type TraceEvents = shared.TraceEvents;

simulation/src/LeiosProtocol/Short/DataSimP2P.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ data SimOutputConfig = SimOutputConfig
239239
, analize :: Bool
240240
, stop :: Time
241241
, logFormat :: LogFormat
242+
, conformanceEvents :: Bool
242243
}
243244

244245
rawDataFromState :: OnDisk.Config -> P2PNetwork -> LeiosSimState -> Time -> RawLeiosData
@@ -338,7 +339,7 @@ exampleSim seed cfg p2pNetwork@P2PNetwork{..} SimOutputConfig{..} = do
338339
runModel :: SampleModel LeiosEvent state -> IO ()
339340
runModel model =
340341
runSampleModel' logFile logEvent model stop $
341-
exampleTrace2 seed cfg p2pNetwork
342+
exampleTrace2 seed cfg p2pNetwork conformanceEvents
342343
logEvent = case logFormat of
343344
Legacy{..} -> jsonlLog $ logLeiosTraceEvent p2pNodeNames verbosity
344345
Shared{cbor}

simulation/src/LeiosProtocol/Short/Node.hs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{-# LANGUAGE BangPatterns #-}
2+
{-# LANGUAGE DuplicateRecordFields #-}
23
{-# LANGUAGE FlexibleContexts #-}
34
{-# LANGUAGE NamedFieldPuns #-}
45
{-# LANGUAGE NondecreasingIndentation #-}
@@ -73,11 +74,18 @@ data BlockEvent
7374
| Pruned
7475
deriving (Show)
7576

77+
data ConformanceEvent
78+
= Slot {slot :: !SlotNo}
79+
| NoIBGenerated {slot :: !SlotNo}
80+
| NoEBGenerated {slot :: !SlotNo}
81+
| NoVTGenerated {slot :: !SlotNo}
82+
deriving (Show)
7683
data LeiosNodeEvent
7784
= PraosNodeEvent !(PraosNode.PraosNodeEvent RankingBlockBody)
7885
| LeiosNodeEventCPU !CPUTask
7986
| LeiosNodeEvent !BlockEvent !LeiosEventBlock
8087
| LeiosNodeEventLedgerState !RankingBlockId
88+
| LeiosNodeEventConformance !ConformanceEvent
8189
deriving (Show)
8290

8391
--------------------------------------------------------------
@@ -103,6 +111,7 @@ data LeiosNodeConfig = LeiosNodeConfig
103111
, processingQueueBound :: !Natural
104112
, processingCores :: !NumCores
105113
, blockGeneration :: !BlockGeneration
114+
, conformanceEvents :: !Bool
106115
}
107116

108117
--------------------------------------------------------------
@@ -801,7 +810,7 @@ generator ::
801810
LeiosNodeState m ->
802811
m ()
803812
generator tracer cfg st = do
804-
schedule <- mkSchedule cfg
813+
schedule <- mkSchedule tracer cfg
805814
let buffers = mkBuffersView cfg st
806815
let
807816
withDelay d (lbl, m) = do
@@ -926,13 +935,14 @@ mkBuffersView cfg st = BuffersView{..}
926935
]
927936
return EndorseBlocksSnapshot{..}
928937

929-
mkSchedule :: MonadSTM m => LeiosNodeConfig -> m (SlotNo -> m [(SomeRole, Word64)])
930-
mkSchedule cfg = do
938+
mkSchedule :: MonadSTM m => Tracer m LeiosNodeEvent -> LeiosNodeConfig -> m (SlotNo -> m [(SomeRole, Word64)])
939+
mkSchedule tracer cfg = do
931940
-- For each pipeline, we want to deploy all our votes in a single
932941
-- message to cut down on traffic, so we pick one slot out of each
933942
-- active voting range (they are assumed not to overlap).
934943
votingSlots <- newTVarIO $ pickFromRanges rng1 $ votingRanges cfg.leios
935-
mkScheduler rng2 (rates votingSlots)
944+
sched <- mkScheduler' rng2 (rates votingSlots)
945+
pure $! if cfg.conformanceEvents then logMissedBlocks sched else fmap filterWins . sched
936946
where
937947
(rng1, rng2) = split cfg.rng
938948
calcWins rate = Just $ \sample ->
@@ -949,6 +959,7 @@ mkSchedule cfg = do
949959
, (SomeRole Generate.Base, const $ calcWins (NetworkRate cfg.leios.praos.blockFrequencyPerSlot))
950960
]
951961
rates votingSlots slot = do
962+
when cfg.conformanceEvents $ traceWith tracer $ LeiosNodeEventConformance Slot{..}
952963
vote <- atomically $ do
953964
vs <- readTVar votingSlots
954965
case vs of
@@ -966,7 +977,20 @@ mkSchedule cfg = do
966977
pickFromRanges rng0 rs = snd $ mapAccumL f rng0 rs
967978
where
968979
f rng r = coerce $ swap $ uniformR (coerce r :: (Word64, Word64)) rng
969-
980+
logMissedBlocks sched slot = do
981+
xs <- sched slot
982+
forM_ xs $ \(SomeRole role, wins) -> do
983+
when (wins == 0) $
984+
case role of
985+
Generate.Propose{} -> do
986+
traceWith tracer $ LeiosNodeEventConformance $ NoIBGenerated{..}
987+
Generate.Endorse{} -> do
988+
traceWith tracer $ LeiosNodeEventConformance $ NoEBGenerated{..}
989+
Generate.Vote{} -> do
990+
traceWith tracer $ LeiosNodeEventConformance $ NoVTGenerated{..}
991+
Generate.Base{} -> return ()
992+
return $ filterWins xs
993+
filterWins = filter ((>= 1) . snd)
970994
-- * Utils
971995

972996
partitionRBVar ::

simulation/src/LeiosProtocol/Short/Sim.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ logLeiosEvent nodeNames loudness e = case e of
168168
EventIB ib -> mconcat [ibKind, "id" .= ib.stringId]
169169
EventEB eb -> mconcat [ebKind, "id" .= eb.stringId]
170170
EventVote vt -> mconcat [vtKind, "id" .= vt.stringId]
171+
logNode _nid LeiosNodeEventConformance{} = Nothing
171172
logPraos nid (PraosNodeEventGenerate blk@(Block h b)) =
172173
Just $
173174
mconcat
@@ -312,6 +313,11 @@ sharedEvent leios nodeNames e = case e of
312313
_ -> Nothing
313314
where
314315
rbId blk = T.pack $ show (coerce @_ @Int (blockHash blk))
316+
sharedNode node (LeiosNodeEventConformance ev) = Just $ case ev of
317+
Slot{..} -> Shared.Slot{slot = coerce slot, ..}
318+
NoIBGenerated{..} -> Shared.NoIBGenerated{slot = coerce slot, ..}
319+
NoEBGenerated{..} -> Shared.NoEBGenerated{slot = coerce slot, ..}
320+
NoVTGenerated{..} -> Shared.NoVTBundleGenerated{slot = coerce slot, ..}
315321
sharedNode _ _ = Nothing
316322
headAndTail xs = case xs of
317323
[] -> (Nothing, Nothing)
@@ -470,6 +476,7 @@ traceRelayLink1 connectionOptions =
470476
processingQueueBound = 100
471477
, processingCores = Infinite
472478
, blockGeneration = Honest
479+
, conformanceEvents = False
473480
, ..
474481
}
475482
(pA, cB) <- newConnectionBundle (leiosTracer nodeA nodeB) (uncurry configureConnection connectionOptions)

simulation/src/LeiosProtocol/Short/SimP2P.hs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ traceLeiosP2P
8989
linkTracer nfrom nto =
9090
contramap (LeiosEventTcp . labelDirToLabelLink nfrom nto) tracer
9191

92-
exampleTrace2 :: StdGen -> OnDisk.Config -> P2PNetwork -> LeiosTrace
92+
exampleTrace2 :: StdGen -> OnDisk.Config -> P2PNetwork -> Bool -> LeiosTrace
9393
exampleTrace2 rng = exampleTrace2' rng . convertConfig
9494

95-
exampleTrace2' :: StdGen -> LeiosConfig -> P2PNetwork -> LeiosTrace
96-
exampleTrace2' rng0 leios@LeiosConfig{praos = PraosConfig{configureConnection}} p2pTopography@P2PNetwork{..} =
95+
exampleTrace2' :: StdGen -> LeiosConfig -> P2PNetwork -> Bool -> LeiosTrace
96+
exampleTrace2' rng0 leios@LeiosConfig{praos = PraosConfig{configureConnection}} p2pTopography@P2PNetwork{..} conformanceEvents =
9797
traceLeiosP2P
9898
rng0
9999
p2pTopography
@@ -118,6 +118,7 @@ exampleTrace2' rng0 leios@LeiosConfig{praos = PraosConfig{configureConnection}}
118118
, slotOfGeneratedIbs = SlotNo $ fromIntegral slotOfGeneratedIbs
119119
, ibsPerSlot = fromIntegral ibsPerSlot
120120
}
121+
, conformanceEvents
121122
}
122123
where
123124
processingCores = fromMaybe undefined $ Map.lookup nodeId p2pNodeCores

simulation/src/LeiosProtocol/Short/VizSim.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ leiosSimVizModel LeiosModelConfig{recentSpan} =
433433
vs{nodeCpuUsage = accumNodeCpuUsage now nid task (nodeCpuUsage vs)}
434434
accumEventVizState _now (LeiosEventNode (LabelNode _nid (LeiosNodeEventLedgerState{}))) vs =
435435
vs
436+
accumEventVizState _now (LeiosEventNode (LabelNode _nid (LeiosNodeEventConformance{}))) vs =
437+
vs
436438
accumEventVizState
437439
_now
438440
( LeiosEventNode

simulation/src/LeiosProtocol/Short/VizSimP2P.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,4 +785,4 @@ example2
785785
processingCores = maximum $ Map.elems p2pNodeCores
786786
config = defaultVizConfig voteSendStage 5 processingCores (10 * kilobytes 1000) -- TODO: calculate from p2pLinks
787787
modelConfig = config.model
788-
model = leiosSimVizModel modelConfig (exampleTrace2' rng leiosConfig p2pNetwork)
788+
model = leiosSimVizModel modelConfig (exampleTrace2' rng leiosConfig p2pNetwork False)

simulation/src/Main.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ runSimOptions SimOptions{..} = case simCommand of
385385
, logFormat = case sharedFormat of
386386
Just x -> DataShortLeiosP2P.Shared (x == CBOR)
387387
Nothing -> DataShortLeiosP2P.Legacy logVerbosity
388+
, conformanceEvents
388389
}
389390
DataShortLeiosP2P.exampleSim rng2 config p2pNetwork outputCfg
390391

@@ -421,6 +422,7 @@ data SimCommand
421422
, logVerbosity :: Int
422423
, analize :: Bool
423424
, sharedFormat :: Maybe OutputFormat
425+
, conformanceEvents :: Bool
424426
}
425427

426428
parserSimCommand :: Parser SimCommand
@@ -449,6 +451,7 @@ parserShortLeios =
449451
<*> logVerbosity
450452
<*> switch (long "analize" <> help "Calculate metrics and statistics.")
451453
<*> optional sharedLogFormat
454+
<*> switch (long "conformance-events" <> help "Emits `Slot` and `No*Generated` events in the shared log format.")
452455
where
453456
logVerbosity =
454457
option

simulation/src/PraosProtocol/Common.hs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ module PraosProtocol.Common (
4040
BlockGeneratorConfig (..),
4141
waitNextSlot,
4242
mkScheduler,
43+
mkScheduler',
4344
) where
4445

4546
import Chan (ConnectionConfig, mkConnectionConfig)
@@ -229,13 +230,22 @@ mkScheduler ::
229230
(SlotNo -> m [(a, Maybe (Double -> Word64))]) ->
230231
m (SlotNo -> m [(a, Word64)])
231232
mkScheduler rng0 rates = do
233+
sched <- mkScheduler rng0 rates
234+
pure $ \slot -> filter ((>= 1) . snd) <$> sched slot
235+
236+
mkScheduler' ::
237+
MonadSTM m =>
238+
StdGen ->
239+
(SlotNo -> m [(a, Maybe (Double -> Word64))]) ->
240+
m (SlotNo -> m [(a, Word64)])
241+
mkScheduler' rng0 rates = do
232242
let
233243
sampleRates (_role, Nothing) = return []
234244
sampleRates (role, Just f) = do
235245
(sample, rng') <- gets $ uniformR (0, 1)
236246
put $! rng'
237247
let wins = f sample
238-
return [(role, wins) | wins >= 1]
248+
return [(role, wins)]
239249
rngVar <- newTVarIO rng0
240250
let sched slot = do
241251
rs <- rates slot

0 commit comments

Comments
 (0)