db-16 — Observation
What does the simulator's output actually look like, and how do you read it by hand?
Header
offset 0x00 : 44 53 45 36 "DSE6" (magic)
offset 0x04 : 78 00 00 00 120 (event_count, u32 LE)
For --seed 42 --nodes 3 --rounds 20 the event count is 3 nodes × 20 rounds × 2 (send + recv) = 120.
A single Send event
Every Send is the start of a causal arc; every Recv is its endpoint. The first event in scenario A is a Send from node 0 at sim_time 0:
01 kind = 1 = Send
00 00 00 00 00 00 00 00 sim_time = 0
00 00 00 00 node = 0 (sender)
?? 00 00 00 peer = ? (destination, computed from PRNG)
01 00 00 00 00 00 00 00 lamport = 1 (Send rule: self += 1, then stamp)
01 00 00 00 vc_len = 1
00 00 00 00 01 00 00 00 00 00 00 00 (node=0, counter=1)
01 00 00 00 payload_len = 1
?? payload byte
Note the vector clock for a node that has only sent has a single entry (its own counter). Receivers' vector clocks grow as they merge incoming clocks.
A single Recv event
Recvs look identical except kind = 2 and peer is the source node:
02 kind = 2 = Recv
?? ?? ?? ?? ?? ?? ?? ?? sim_time = original send time + delay
01 00 00 00 node = 1 (receiver)
00 00 00 00 peer = 0 (sender of paired Send)
?? ?? ?? ?? ?? ?? ?? ?? lamport = max(self_before, incoming) + 1
02 00 00 00 vc_len = 2
00 00 00 00 01 00 00 00 00 00 00 00 merged entry for node 0
01 00 00 00 ?? 00 00 00 00 00 00 00 own counter, incremented
01 00 00 00 payload_len = 1
?? payload byte (copied from send)
The number of VC entries grows as a node hears from new peers; in a 3-node, 20-round run each receiver will eventually have all 3 entries.
Hex walkthrough
./simctl --seed 42 --nodes 3 --rounds 20 | xxd | head
Read column-by-column:
00000000: 4453 4536 7800 0000 DSE6 . . . . . . . . header
00000008: 01 00 00 00 00 00 00 00 00 first Send: kind=1, sim_time=0
00 00 00 00 node=0
00000014: ?? 00 00 00 peer
00000018: 01 00 00 00 00 00 00 00 lamport=1
00000020: 01 00 00 00 vc_len=1
00000024: 00 00 00 00 01 00 00 00 00 00 00 00 vc entry (0 → 1)
00000030: 01 00 00 00 payload_len=1
00000034: ?? payload byte
00000035: 02 ... next event (probably another Send at t=0)
The whole file for scenario A is 8156 bytes; scenario B is 45592 bytes.
What to learn from looking at it
- Lamport values are non-decreasing within a node but may regress between nodes — that is healthy: nodes 0 and 1 can be ahead of node 2 if 2 hasn't sent or received yet.
- The vector-clock entry for node
iin nodei's own events is strictly monotonic. - For any Send/Recv pair, the Recv's VC must dominate the Send's VC
(
>inVcOrd). This is exactly whatcheck_causalityasserts. - If you sort all events by
sim_timeyou get a globally consistent "tape" — but events at the same sim_time are concurrent and have no inherent ordering between nodes. Deliveries are scheduled before sends within a tick by simulator policy, not by physics.
Cross-language reading
scripts/cross_test.sh prints the hex of the first 8 bytes (44534536 7800 0000 for scenario A). If three implementations agree on those 8
bytes but disagree on the rest, the suspect is almost always either
(a) VC-entry order on the wire, or (b) heap tie-break by sender id.