lib/machine/src/world/test.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const admission = @import("../admission/root.zig");
2 const checkpoint = @import("../checkpoint/root.zig");
3 const fabric = @import("../fabric/root.zig");
4 const instance = @import("../instance/root.zig");
5 const os = @import("os");
6 const profile = @import("../profile/root.zig");
7 const std = @import("std");
8 const world = @import("root.zig");
9 const world_moment = @import("moment.zig");
10
11 const k0_elf = @embedFile("machine-k0-elf");
12 const k0_manifest = @embedFile("machine-k0-manifest");
13 const world_id: [16]u8 = @splat(0x44);
14 const first_id: fabric.NodeId = .{ .bytes = @splat(0x11) };
15 const second_id: fabric.NodeId = .{ .bytes = @splat(0x22) };
16
17 const ManifestMutation = struct {
18 offset: usize,
19 mask: u8,
20 expected: anyerror,
21 };
22
23 const ReopenedWorld = struct {
24 cut: world.Cut,
25 fabric: fabric.Fabric,
26 checkpoints: [2]checkpoint.Checkpoint,
27 };
28
29 var first_live_ram: [instance.ram_bytes]u8 align(instance.ram_alignment) = undefined;
30 var second_live_ram: [instance.ram_bytes]u8 align(instance.ram_alignment) = undefined;
31 var first_checkpoint_ram: [checkpoint.ram_bytes]u8 align(checkpoint.ram_alignment) = undefined;
32 var second_checkpoint_ram: [checkpoint.ram_bytes]u8 align(checkpoint.ram_alignment) = undefined;
33 var first_restore_ram: [instance.ram_bytes]u8 align(instance.ram_alignment) = undefined;
34 var second_restore_ram: [instance.ram_bytes]u8 align(instance.ram_alignment) = undefined;
35 var checkpoint_stream: [checkpoint.stream.stream_bytes]u8 = undefined;
36 var fabric_stream: [fabric.snapshot.stream_bytes]u8 = undefined;
37 var manifest_stream: [world.manifest.stream_bytes + 1]u8 = undefined;
38 var replay_admission_stream: [fabric.transition.stream_bytes]u8 = undefined;
39 var replay_settlement_stream: [fabric.transition.stream_bytes]u8 = undefined;
40 var replay_next_admission_stream: [fabric.transition.stream_bytes]u8 = undefined;
41 var replay_next_settlement_stream: [fabric.transition.stream_bytes]u8 = undefined;
42 var replay_divergent_stream: [fabric.transition.stream_bytes]u8 = undefined;
43 var fault_bypass_stream: [fabric.transition.stream_bytes]u8 = undefined;
44 var fault_inject_stream: [fabric.transition.stream_bytes]u8 = undefined;
45 var fault_process_stream: [fabric.transition.stream_bytes]u8 = undefined;
46 var fault_admission_stream: [fabric.transition.stream_bytes]u8 = undefined;
47 var fault_clock_stream: [fabric.transition.stream_bytes]u8 = undefined;
48 const hot_page_limit: usize = 64;
49 var first_hot_a_indices: [hot_page_limit]u16 = undefined;
50 var first_hot_a_pages: [hot_page_limit * checkpoint.hot.page_bytes]u8 align(checkpoint.hot.page_bytes) = undefined;
51 var second_hot_a_indices: [hot_page_limit]u16 = undefined;
52 var second_hot_a_pages: [hot_page_limit * checkpoint.hot.page_bytes]u8 align(checkpoint.hot.page_bytes) = undefined;
53 var first_hot_b_indices: [hot_page_limit]u16 = undefined;
54 var first_hot_b_pages: [hot_page_limit * checkpoint.hot.page_bytes]u8 align(checkpoint.hot.page_bytes) = undefined;
55 var second_hot_b_indices: [hot_page_limit]u16 = undefined;
56 var second_hot_b_pages: [hot_page_limit * checkpoint.hot.page_bytes]u8 align(checkpoint.hot.page_bytes) = undefined;
57 var hot_probe_ram: [checkpoint.ram_bytes]u8 align(checkpoint.ram_alignment) = undefined;
58
59 const UnavailableWorld = struct {
60 fabric: fabric.Fabric,
61 cut: world.Cut,
62 };
63
64 test "world manifest reopens independent streams into connected restore" {
65 const execution = try os.boot.kernel.manifest.parse(k0_manifest);
66 const first_fence = activationFence(0xc1);
67 const second_fence = activationFence(0xc2);
68 var first_storage = instance.Storage.init();
69 var first = try start(
70 &first_storage,
71 &first_live_ram,
72 machineInput(execution, first_fence, 0x71),
73 );
74 var first_open = true;
75 defer if (first_open) first.deinit();
76 var second_storage = instance.Storage.init();
77 var second = try start(
78 &second_storage,
79 &second_live_ram,
80 machineInput(execution, second_fence, 0x81),
81 );
82 var second_open = true;
83 defer if (second_open) second.deinit();
84 var connected = try connectedFabric(&first, &second);
85 var first_checkpoint_storage = checkpoint.Storage.init();
86 const first_checkpoint = try captureBoundary(
87 &connected,
88 first_id,
89 &first,
90 first_fence,
91 0xd1,
92 &first_checkpoint_storage,
93 &first_checkpoint_ram,
94 false,
95 );
96 var second_checkpoint_storage = checkpoint.Storage.init();
97 const second_checkpoint = try captureBoundary(
98 &connected,
99 second_id,
100 &second,
101 second_fence,
102 0xd2,
103 &second_checkpoint_storage,
104 &second_checkpoint_ram,
105 false,
106 );
107 const bindings = [_]world.Binding{
108 binding(first_id, &first, &first_checkpoint),
109 binding(second_id, &second, &second_checkpoint),
110 };
111 const cut = try world.seal(&connected, &bindings);
112 try expectManifestCodec(cut);
113 var first_reopened_storage = checkpoint.Storage.init();
114 var second_reopened_storage = checkpoint.Storage.init();
115 var reopened = try reopenWorldStreams(
116 &connected,
117 cut,
118 &first_checkpoint,
119 &second_checkpoint,
120 &first_reopened_storage,
121 &second_reopened_storage,
122 );
123 first.deinit();
124 first_open = false;
125 second.deinit();
126 second_open = false;
127 try restoreReopenedWorld(&reopened);
128 }
129
130 test "connected world root authenticates one exact canonical machine cut" {
131 const execution = try os.boot.kernel.manifest.parse(k0_manifest);
132 const first_fence = activationFence(0x51);
133 const second_fence = activationFence(0x52);
134 var first_storage = instance.Storage.init();
135 var first = try start(
136 &first_storage,
137 &first_live_ram,
138 machineInput(execution, first_fence, 0x31),
139 );
140 defer first.deinit();
141 var second_storage = instance.Storage.init();
142 var second = try start(
143 &second_storage,
144 &second_live_ram,
145 machineInput(execution, second_fence, 0x41),
146 );
147 defer second.deinit();
148 var connected = try connectedFabric(&first, &second);
149 try expectInitialBoundary(&connected);
150
151 var first_checkpoint_storage = checkpoint.Storage.init();
152 const first_checkpoint = try captureBoundary(
153 &connected,
154 first_id,
155 &first,
156 first_fence,
157 0xa1,
158 &first_checkpoint_storage,
159 &first_checkpoint_ram,
160 true,
161 );
162 try expectIncompleteWorld(
163 &connected,
164 &first,
165 &second,
166 &first_checkpoint,
167 );
168
169 var second_checkpoint_storage = checkpoint.Storage.init();
170 const second_checkpoint = try captureBoundary(
171 &connected,
172 second_id,
173 &second,
174 second_fence,
175 0xb2,
176 &second_checkpoint_storage,
177 &second_checkpoint_ram,
178 false,
179 );
180 try exerciseConnectedWorld(
181 &first,
182 &second,
183 &connected,
184 &first_checkpoint,
185 &second_checkpoint,
186 );
187 }
188
189 test "sibling worlds share parent roots and restore dirty pages" {
190 const execution = try os.boot.kernel.manifest.parse(k0_manifest);
191 const first_fence = activationFence(0x55);
192 const second_fence = activationFence(0x56);
193 var first_storage = instance.Storage.init();
194 var first = try start(
195 &first_storage,
196 &first_live_ram,
197 machineInput(execution, first_fence, 0x35),
198 );
199 var second_storage = instance.Storage.init();
200 var second = try start(
201 &second_storage,
202 &second_live_ram,
203 machineInput(execution, second_fence, 0x45),
204 );
205 var connected = try connectedFabric(&first, &second);
206 var first_checkpoint_storage = checkpoint.Storage.init();
207 const first_checkpoint = try captureBoundary(
208 &connected,
209 first_id,
210 &first,
211 first_fence,
212 0x91,
213 &first_checkpoint_storage,
214 &first_checkpoint_ram,
215 false,
216 );
217 var second_checkpoint_storage = checkpoint.Storage.init();
218 const second_checkpoint = try captureBoundary(
219 &connected,
220 second_id,
221 &second,
222 second_fence,
223 0x92,
224 &second_checkpoint_storage,
225 &second_checkpoint_ram,
226 false,
227 );
228 const parent_bindings = [_]world.Binding{
229 binding(first_id, &first, &first_checkpoint),
230 binding(second_id, &second, &second_checkpoint),
231 };
232 const parent = try world.seal(&connected, &parent_bindings);
233 first.deinit();
234 second.deinit();
235 const first_branch = try captureHotBranch(
236 parent,
237 connected,
238 &first_checkpoint,
239 &second_checkpoint,
240 .{ 0xa1, 0xa2 },
241 hotStorageA(),
242 true,
243 );
244 const second_branch = try captureHotBranch(
245 parent,
246 connected,
247 &first_checkpoint,
248 &second_checkpoint,
249 .{ 0xb1, 0xb2 },
250 hotStorageB(),
251 false,
252 );
253 try expectSiblingDivergence(parent, first_branch, second_branch);
254 try expectSparseMaterialization(first_branch, &first_checkpoint, &second_checkpoint);
255 try expectHotRestoreAndReplay(first_branch);
256 try expectHotRestore(second_branch);
257 }
258
259 const HotBranch = struct {
260 cut: world.Cut,
261 fabric: fabric.Fabric,
262 after_replay: fabric.Fabric,
263 snapshots: [2]checkpoint.hot.Snapshot,
264 admission: ?fabric.Transition,
265 settlement: ?fabric.Transition,
266 };
267
268 const RecordedTurn = struct {
269 admission: fabric.Transition,
270 settlement: fabric.Transition,
271 };
272
273 fn hotStorageA() [2]checkpoint.hot.Storage {
274 return .{
275 checkpoint.hot.Storage.init(
276 &first_hot_a_indices,
277 &first_hot_a_pages,
278 ) catch unreachable,
279 checkpoint.hot.Storage.init(
280 &second_hot_a_indices,
281 &second_hot_a_pages,
282 ) catch unreachable,
283 };
284 }
285
286 fn hotStorageB() [2]checkpoint.hot.Storage {
287 return .{
288 checkpoint.hot.Storage.init(
289 &first_hot_b_indices,
290 &first_hot_b_pages,
291 ) catch unreachable,
292 checkpoint.hot.Storage.init(
293 &second_hot_b_indices,
294 &second_hot_b_pages,
295 ) catch unreachable,
296 };
297 }
298
299 fn captureHotBranch(
300 parent: world.Cut,
301 initial: fabric.Fabric,
302 first_parent: *const checkpoint.Checkpoint,
303 second_parent: *const checkpoint.Checkpoint,
304 entropy: [2]u8,
305 storage: [2]checkpoint.hot.Storage,
306 record_replay: bool,
307 ) !HotBranch {
308 var branch_fabric = initial;
309 var first_storage = instance.Storage.init();
310 var second_storage = instance.Storage.init();
311 const restore_bindings = restoreBindings(
312 first_parent,
313 second_parent,
314 &first_storage,
315 &second_storage,
316 );
317 var restored = try requireRestored(world.restore(
318 parent,
319 &branch_fabric,
320 &restore_bindings,
321 ));
322 defer restored.deinit();
323 try settleRestoredEntropy(&restored, 0, activationFence(0x71), entropy[0]);
324 try settleRestoredEntropy(&restored, 1, activationFence(0x72), entropy[1]);
325 const first_machine = if (restored.nodes[0].machine) |*value|
326 value
327 else
328 return error.TestExpectedLiveMachine;
329 const second_machine = if (restored.nodes[1].machine) |*value|
330 value
331 else
332 return error.TestExpectedLiveMachine;
333 markBranchPage(first_machine, entropy[0]);
334 markBranchPage(second_machine, entropy[1]);
335 const snapshots = [2]checkpoint.hot.Snapshot{
336 try first_machine.captureHot(first_parent, storage[0]),
337 try second_machine.captureHot(second_parent, storage[1]),
338 };
339 const bindings = [_]world.Binding{
340 hotBinding(first_id, first_machine, &snapshots[0]),
341 hotBinding(second_id, second_machine, &snapshots[1]),
342 };
343 const cut = try world.seal(restored.fabric, &bindings);
344 const at_cut = restored.fabric.*;
345 const recorded = if (record_replay)
346 try recordHotSuffix(&restored)
347 else
348 null;
349 return .{
350 .cut = cut,
351 .fabric = at_cut,
352 .after_replay = restored.fabric.*,
353 .snapshots = snapshots,
354 .admission = if (recorded) |value| value.admission else null,
355 .settlement = if (recorded) |value| value.settlement else null,
356 };
357 }
358
359 fn markBranchPage(machine: *instance.Instance, value: u8) void {
360 machine.ram[machine.ram.len - 1] = value;
361 }
362
363 fn settleRestoredEntropy(
364 restored: *world.Restored,
365 index: usize,
366 fence: os.abi.ActivationFence,
367 entropy: u8,
368 ) !void {
369 const machine = if (restored.nodes[index].machine) |*value|
370 value
371 else
372 return error.TestExpectedLiveMachine;
373 try activate(machine);
374 const admitted = try restored.fabric.injectEntropy(
375 restored.nodes[index].id,
376 machine,
377 fence,
378 &.{entropy},
379 );
380 const receipt = try completeTurn(machine, admitted.delivery);
381 _ = try restored.fabric.settle(restored.nodes[index].id, receipt);
382 }
383
384 fn recordHotSuffix(restored: *world.Restored) !RecordedTurn {
385 const machine = if (restored.nodes[0].machine) |*value|
386 value
387 else
388 return error.TestExpectedLiveMachine;
389 const fence = activationFenceAt(0xc1, 2);
390 try machine.reactivate(fence);
391 try activate(machine);
392 const before_admission = restored.fabric.*;
393 const admitted = try restored.fabric.injectEntropy(first_id, machine, fence, &.{0xdd});
394 const admission_transition: fabric.Transition = .{
395 .entry = admitted.entry,
396 .root = admitted.root,
397 };
398 try encodeTransition(
399 &before_admission,
400 &admission_transition,
401 &replay_admission_stream,
402 );
403 const receipt = try completeTurn(machine, admitted.delivery);
404 const before_settlement = restored.fabric.*;
405 const settled = try restored.fabric.settle(first_id, receipt);
406 const settlement_transition: fabric.Transition = .{
407 .entry = settled.entry,
408 .root = settled.root,
409 };
410 try encodeTransition(
411 &before_settlement,
412 &settlement_transition,
413 &replay_settlement_stream,
414 );
415 return .{ .admission = admission_transition, .settlement = settlement_transition };
416 }
417
418 fn hotBinding(
419 node: fabric.NodeId,
420 machine: *const instance.Instance,
421 snapshot: *const checkpoint.hot.Snapshot,
422 ) world.Binding {
423 return .{
424 .node = node,
425 .execution_profile = profile.interpretedContinuationTestV1(),
426 .checkpoint = .{ .hot = snapshot },
427 .source = .{ .live = machine },
428 };
429 }
430
431 fn expectSiblingDivergence(
432 parent: world.Cut,
433 first_branch: HotBranch,
434 second_branch: HotBranch,
435 ) !void {
436 try std.testing.expect(!std.meta.eql(first_branch.cut.root, parent.root));
437 try std.testing.expect(!std.meta.eql(second_branch.cut.root, parent.root));
438 try std.testing.expect(!std.meta.eql(first_branch.cut.root, second_branch.cut.root));
439 for (first_branch.snapshots, second_branch.snapshots) |first_hot, second_hot| {
440 try std.testing.expect(first_hot.parent == second_hot.parent);
441 try std.testing.expect(first_hot.dirtyPageCount() > 0);
442 try std.testing.expect(second_hot.dirtyPageCount() > 0);
443 try std.testing.expect(first_hot.dirtyPageCount() < checkpoint.page_count);
444 try std.testing.expect(second_hot.dirtyPageCount() < checkpoint.page_count);
445 try std.testing.expectEqualSlices(u16, first_hot.indices, second_hot.indices);
446 try std.testing.expect(!std.mem.eql(u8, first_hot.pages, second_hot.pages));
447 try std.testing.expect(!std.meta.eql(
448 first_hot.identity_value.root,
449 second_hot.identity_value.root,
450 ));
451 }
452 }
453
454 fn expectSparseMaterialization(
455 branch: HotBranch,
456 first_parent: *const checkpoint.Checkpoint,
457 second_parent: *const checkpoint.Checkpoint,
458 ) !void {
459 const parents = [_]*const checkpoint.Checkpoint{ first_parent, second_parent };
460 for (branch.snapshots, parents, 0..) |snapshot, parent, index| {
461 @memcpy(&hot_probe_ram, parent.ram);
462 const restored = try snapshot.materializeForRestore(
463 branch.cut.nodes[index].machine,
464 &hot_probe_ram,
465 );
466 try std.testing.expectEqual(snapshot.dirtyPageCount(), restored.copied_pages);
467 try std.testing.expect(restored.copied_pages < checkpoint.page_count);
468 }
469 }
470
471 fn expectHotRestoreAndReplay(branch: HotBranch) !void {
472 var restored_fabric = branch.fabric;
473 var first_storage = instance.Storage.init();
474 var second_storage = instance.Storage.init();
475 const bindings = hotRestoreBindings(&branch, &first_storage, &second_storage);
476 var restored = try requireRestored(world.restore(
477 branch.cut,
478 &restored_fabric,
479 &bindings,
480 ));
481 defer restored.deinit();
482 const advanced = try replayRecorded(
483 &restored,
484 &replay_admission_stream,
485 branch.admission orelse return error.TestExpectedRecordedTurn,
486 &replay_settlement_stream,
487 branch.settlement orelse return error.TestExpectedRecordedTurn,
488 activationFence(0xd1),
489 );
490 try std.testing.expect(advanced.events.count > 0);
491 try std.testing.expectEqualDeep(branch.after_replay, restored.fabric.*);
492 }
493
494 fn expectHotRestore(branch: HotBranch) !void {
495 var restored_fabric = branch.fabric;
496 var first_storage = instance.Storage.init();
497 var second_storage = instance.Storage.init();
498 const bindings = hotRestoreBindings(&branch, &first_storage, &second_storage);
499 var restored = try requireRestored(world.restore(
500 branch.cut,
501 &restored_fabric,
502 &bindings,
503 ));
504 defer restored.deinit();
505 try std.testing.expectEqualDeep(branch.cut.root, restored.root);
506 try expectRestoredBooting(&restored.nodes[0], first_id);
507 try expectRestoredBooting(&restored.nodes[1], second_id);
508 }
509
510 fn hotRestoreBindings(
511 branch: *const HotBranch,
512 first_storage: *instance.Storage,
513 second_storage: *instance.Storage,
514 ) [2]world.RestoreBinding {
515 @memcpy(&first_restore_ram, branch.snapshots[0].parent.ram);
516 @memcpy(&second_restore_ram, branch.snapshots[1].parent.ram);
517 return .{
518 .{
519 .node = first_id,
520 .checkpoint = .{ .hot = &branch.snapshots[0] },
521 .mode = .{ .live = restoreTarget(first_storage, &first_restore_ram, 0xd1) },
522 },
523 .{
524 .node = second_id,
525 .checkpoint = .{ .hot = &branch.snapshots[1] },
526 .mode = .{ .live = restoreTarget(second_storage, &second_restore_ram, 0xd2) },
527 },
528 };
529 }
530
531 test "recorded settlement is verified by restored guest execution" {
532 const execution = try os.boot.kernel.manifest.parse(k0_manifest);
533 const first_fence = activationFence(0x91);
534 const second_fence = activationFence(0x92);
535 var first_storage = instance.Storage.init();
536 var first = try start(
537 &first_storage,
538 &first_live_ram,
539 machineInput(execution, first_fence, 0x61),
540 );
541 var first_open = true;
542 defer if (first_open) first.deinit();
543 var second_storage = instance.Storage.init();
544 var second = try start(
545 &second_storage,
546 &second_live_ram,
547 machineInput(execution, second_fence, 0x71),
548 );
549 var second_open = true;
550 defer if (second_open) second.deinit();
551 var connected = try connectedFabric(&first, &second);
552 var first_checkpoint_storage = checkpoint.Storage.init();
553 const first_checkpoint = try captureBoundary(
554 &connected,
555 first_id,
556 &first,
557 first_fence,
558 0xa1,
559 &first_checkpoint_storage,
560 &first_checkpoint_ram,
561 false,
562 );
563 var second_checkpoint_storage = checkpoint.Storage.init();
564 const second_checkpoint = try captureBoundary(
565 &connected,
566 second_id,
567 &second,
568 second_fence,
569 0xa2,
570 &second_checkpoint_storage,
571 &second_checkpoint_ram,
572 false,
573 );
574 const bindings = [_]world.Binding{
575 binding(first_id, &first, &first_checkpoint),
576 binding(second_id, &second, &second_checkpoint),
577 };
578 const cut = try world.seal(&connected, &bindings);
579 const before_turn = connected;
580 const recording_fence = activationFenceAt(0xb1, 2);
581 try first.reactivate(recording_fence);
582 try activate(&first);
583 const admitted = try connected.injectEntropy(
584 first_id,
585 &first,
586 recording_fence,
587 &.{0xc1},
588 );
589 const admission_transition: fabric.Transition = .{
590 .entry = admitted.entry,
591 .root = admitted.root,
592 };
593 try encodeTransition(
594 &before_turn,
595 &admission_transition,
596 &replay_admission_stream,
597 );
598 const receipt = try completeTurn(&first, admitted.delivery);
599 const before_settlement = connected;
600 const settled = try connected.settle(first_id, receipt);
601 const settlement_transition: fabric.Transition = .{
602 .entry = settled.entry,
603 .root = settled.root,
604 };
605 try encodeTransition(
606 &before_settlement,
607 &settlement_transition,
608 &replay_settlement_stream,
609 );
610 var divergent_entry = settled.entry;
611 divergent_entry.value.settlement.receipt.semantic_transcript_digest[0] ^= 1;
612 var divergent_fabric = before_settlement;
613 const divergent_transition: fabric.Transition = .{
614 .entry = divergent_entry,
615 .root = try divergent_fabric.replay(divergent_entry),
616 };
617 try encodeTransition(
618 &before_settlement,
619 &divergent_transition,
620 &replay_divergent_stream,
621 );
622 try std.testing.expect(!std.meta.eql(
623 settlement_transition.root,
624 divergent_transition.root,
625 ));
626 const next_recording_fence = activationFenceAt(0xb2, 3);
627 try first.reactivate(next_recording_fence);
628 try activate(&first);
629 const before_next_turn = connected;
630 const next_admitted = try connected.injectEntropy(
631 first_id,
632 &first,
633 next_recording_fence,
634 &.{0xc2},
635 );
636 const next_admission_transition: fabric.Transition = .{
637 .entry = next_admitted.entry,
638 .root = next_admitted.root,
639 };
640 try encodeTransition(
641 &before_next_turn,
642 &next_admission_transition,
643 &replay_next_admission_stream,
644 );
645 const next_receipt = try completeTurn(&first, next_admitted.delivery);
646 const before_next_settlement = connected;
647 const next_settled = try connected.settle(first_id, next_receipt);
648 const next_settlement_transition: fabric.Transition = .{
649 .entry = next_settled.entry,
650 .root = next_settled.root,
651 };
652 try encodeTransition(
653 &before_next_settlement,
654 &next_settlement_transition,
655 &replay_next_settlement_stream,
656 );
657 first.deinit();
658 first_open = false;
659 second.deinit();
660 second_open = false;
661 const replayed = try expectVerifiedReplay(
662 cut,
663 before_turn,
664 connected,
665 &first_checkpoint,
666 &second_checkpoint,
667 admission_transition,
668 settlement_transition,
669 next_admission_transition,
670 next_settlement_transition,
671 );
672 try expectTurnPrefixReplay(
673 cut,
674 before_turn,
675 connected,
676 &first_checkpoint,
677 &second_checkpoint,
678 admission_transition,
679 settlement_transition,
680 next_admission_transition,
681 next_settlement_transition,
682 replayed,
683 );
684 try expectDivergentReplayInvalidation(
685 cut,
686 before_turn,
687 &first_checkpoint,
688 &second_checkpoint,
689 admission_transition,
690 divergent_transition,
691 );
692 }
693
694 const ReplayedMoments = struct {
695 first: world.Moment,
696 second: world.Moment,
697 };
698
699 fn expectVerifiedReplay(
700 cut: world.Cut,
701 initial: fabric.Fabric,
702 expected: fabric.Fabric,
703 first_checkpoint: *const checkpoint.Checkpoint,
704 second_checkpoint: *const checkpoint.Checkpoint,
705 admission_transition: fabric.Transition,
706 settlement_transition: fabric.Transition,
707 next_admission_transition: fabric.Transition,
708 next_settlement_transition: fabric.Transition,
709 ) !ReplayedMoments {
710 var restored_fabric = initial;
711 var first_storage = instance.Storage.init();
712 var second_storage = instance.Storage.init();
713 const bindings = restoreBindings(
714 first_checkpoint,
715 second_checkpoint,
716 &first_storage,
717 &second_storage,
718 );
719 var restored = try requireRestored(world.restore(
720 cut,
721 &restored_fabric,
722 &bindings,
723 ));
724 defer restored.deinit();
725 const initial_moment = try restored.currentMoment();
726 try std.testing.expectEqualDeep(cut.root, initial_moment.origin);
727 try std.testing.expectEqualDeep(initial.root(), initial_moment.fabric);
728 const first_advanced = try replayRecorded(
729 &restored,
730 &replay_admission_stream,
731 admission_transition,
732 &replay_settlement_stream,
733 settlement_transition,
734 activationFence(0x71),
735 );
736 try std.testing.expectEqualDeep(
737 admission_transition,
738 first_advanced.admission,
739 );
740 try std.testing.expectEqualDeep(
741 settlement_transition,
742 first_advanced.settlement,
743 );
744 try std.testing.expect(first_advanced.events.count > 0);
745 try std.testing.expectEqualDeep(
746 settlement_transition.root,
747 restored.fabric.root(),
748 );
749 try std.testing.expectEqualDeep(
750 first_advanced.moment,
751 try restored.currentMoment(),
752 );
753 try std.testing.expectEqualDeep(
754 settlement_transition.root,
755 first_advanced.moment.fabric,
756 );
757 try std.testing.expect(!std.meta.eql(
758 initial_moment,
759 first_advanced.moment,
760 ));
761 try std.testing.expect(restored.nodes[0].machine != null);
762 try std.testing.expect(restored.nodes[1].machine != null);
763 try std.testing.expectEqual(
764 instance.RunPhase.awaiting_reactivation,
765 restored.nodes[0].machine.?.phase(),
766 );
767 try std.testing.expectEqual(
768 instance.RunPhase.booting,
769 restored.nodes[1].machine.?.phase(),
770 );
771 const next_advanced = try replayRecorded(
772 &restored,
773 &replay_next_admission_stream,
774 next_admission_transition,
775 &replay_next_settlement_stream,
776 next_settlement_transition,
777 activationFenceAt(0x73, 2),
778 );
779 try std.testing.expectEqualDeep(
780 next_admission_transition,
781 next_advanced.admission,
782 );
783 try std.testing.expectEqualDeep(
784 next_settlement_transition,
785 next_advanced.settlement,
786 );
787 try std.testing.expect(next_advanced.events.count > 0);
788 try std.testing.expectEqualDeep(
789 next_advanced.moment,
790 try restored.currentMoment(),
791 );
792 try std.testing.expectEqualDeep(
793 next_settlement_transition.root,
794 next_advanced.moment.fabric,
795 );
796 try std.testing.expect(!std.meta.eql(
797 first_advanced.moment,
798 next_advanced.moment,
799 ));
800 try std.testing.expectEqualDeep(expected, restored.fabric.*);
801 try std.testing.expect(restored.nodes[0].machine != null);
802 try std.testing.expect(restored.nodes[1].machine != null);
803 try std.testing.expectEqual(
804 instance.RunPhase.awaiting_reactivation,
805 restored.nodes[0].machine.?.phase(),
806 );
807 try std.testing.expectEqual(
808 instance.RunPhase.booting,
809 restored.nodes[1].machine.?.phase(),
810 );
811 return .{
812 .first = first_advanced.moment,
813 .second = next_advanced.moment,
814 };
815 }
816
817 fn expectTurnPrefixReplay(
818 cut: world.Cut,
819 initial: fabric.Fabric,
820 expected: fabric.Fabric,
821 first_checkpoint: *const checkpoint.Checkpoint,
822 second_checkpoint: *const checkpoint.Checkpoint,
823 admission_transition: fabric.Transition,
824 settlement_transition: fabric.Transition,
825 next_admission_transition: fabric.Transition,
826 next_settlement_transition: fabric.Transition,
827 moments: ReplayedMoments,
828 ) !void {
829 {
830 var restored_fabric = initial;
831 var first_storage = instance.Storage.init();
832 var second_storage = instance.Storage.init();
833 var restored = try restoreFaultWorld(
834 cut,
835 &restored_fabric,
836 first_checkpoint,
837 second_checkpoint,
838 &first_storage,
839 &second_storage,
840 );
841 defer restored.deinit();
842 const start_moment = try restored.currentMoment();
843 var admission_reader = std.Io.Reader.fixed(&replay_admission_stream);
844 var settlement_reader = std.Io.Reader.fixed(&replay_settlement_stream);
845 var next_admission_reader = std.Io.Reader.fixed(
846 &replay_next_admission_stream,
847 );
848 var next_settlement_reader = std.Io.Reader.fixed(
849 &replay_next_settlement_stream,
850 );
851 const steps = [_]world.PrefixStep{
852 turnPrefixStep(
853 &admission_reader,
854 admission_transition,
855 &settlement_reader,
856 settlement_transition,
857 activationFence(0x71),
858 moments.first,
859 ),
860 turnPrefixStep(
861 &next_admission_reader,
862 next_admission_transition,
863 &next_settlement_reader,
864 next_settlement_transition,
865 activationFenceAt(0x73, 2),
866 moments.second,
867 ),
868 };
869 const progress = try requirePrefixReached(world.replayPrefix(
870 &restored,
871 .{ .start = start_moment, .steps = &steps, .end = moments.second },
872 ));
873 try std.testing.expectEqual(@as(u8, 2), progress.step_count);
874 try std.testing.expectEqual(@as(u8, 2), progress.turn_count);
875 try std.testing.expectEqualSlices(u8, &.{ 0, 1 }, progress.eventSteps());
876 try std.testing.expectEqual(@as(usize, 2), progress.eventBatches().len);
877 try std.testing.expect(progress.eventBatches()[0].count > 0);
878 try std.testing.expect(progress.eventBatches()[1].count > 0);
879 try std.testing.expectEqualDeep(moments.second, progress.moment);
880 try std.testing.expectEqualDeep(moments.second, restored.moment);
881 try std.testing.expectEqualDeep(expected, restored.fabric.*);
882 }
883 try expectMixedPrefixReplay(
884 cut,
885 initial,
886 first_checkpoint,
887 second_checkpoint,
888 admission_transition,
889 settlement_transition,
890 moments.first,
891 );
892 try expectPrefixPlanRejections(
893 cut,
894 initial,
895 first_checkpoint,
896 second_checkpoint,
897 admission_transition,
898 settlement_transition,
899 moments,
900 );
901 try expectPartialPrefixRejection(
902 cut,
903 initial,
904 first_checkpoint,
905 second_checkpoint,
906 admission_transition,
907 settlement_transition,
908 next_admission_transition,
909 next_settlement_transition,
910 moments,
911 );
912 }
913
914 fn expectMixedPrefixReplay(
915 cut: world.Cut,
916 initial: fabric.Fabric,
917 first_checkpoint: *const checkpoint.Checkpoint,
918 second_checkpoint: *const checkpoint.Checkpoint,
919 admission_transition: fabric.Transition,
920 settlement_transition: fabric.Transition,
921 first_moment: world.Moment,
922 ) !void {
923 var fault_transition: fabric.Transition = undefined;
924 var fault_moment: world.Moment = undefined;
925 var expected: fabric.Fabric = undefined;
926 var fault_stream: [fabric.transition.stream_bytes]u8 = undefined;
927 {
928 var recorded_fabric = initial;
929 var first_storage = instance.Storage.init();
930 var second_storage = instance.Storage.init();
931 var restored = try restoreFaultWorld(
932 cut,
933 &recorded_fabric,
934 first_checkpoint,
935 second_checkpoint,
936 &first_storage,
937 &second_storage,
938 );
939 defer restored.deinit();
940 const advanced = try replayRecorded(
941 &restored,
942 &replay_admission_stream,
943 admission_transition,
944 &replay_settlement_stream,
945 settlement_transition,
946 activationFence(0x71),
947 );
948 try std.testing.expectEqualDeep(first_moment, advanced.moment);
949 const before_fault = restored.fabric.*;
950 const applied = try requireFaultApplied(world.applyFault(
951 &restored,
952 .{
953 .effect = .{ .clock_jump = 31 },
954 .choice = .inject,
955 },
956 ));
957 fault_transition = applied.transition;
958 fault_moment = applied.moment;
959 expected = restored.fabric.*;
960 try encodeTransition(
961 &before_fault,
962 &fault_transition,
963 &fault_stream,
964 );
965 }
966 var replayed_fabric = initial;
967 var first_storage = instance.Storage.init();
968 var second_storage = instance.Storage.init();
969 var restored = try restoreFaultWorld(
970 cut,
971 &replayed_fabric,
972 first_checkpoint,
973 second_checkpoint,
974 &first_storage,
975 &second_storage,
976 );
977 defer restored.deinit();
978 const start_moment = try restored.currentMoment();
979 var admission_reader = std.Io.Reader.fixed(&replay_admission_stream);
980 var settlement_reader = std.Io.Reader.fixed(&replay_settlement_stream);
981 var fault_reader = std.Io.Reader.fixed(&fault_stream);
982 const steps = [_]world.PrefixStep{
983 turnPrefixStep(
984 &admission_reader,
985 admission_transition,
986 &settlement_reader,
987 settlement_transition,
988 activationFence(0x71),
989 first_moment,
990 ),
991 .{ .fault = .{
992 .reader = &fault_reader,
993 .expected_root = fault_transition.root,
994 .expected_moment = fault_moment,
995 } },
996 };
997 const progress = try requirePrefixReached(world.replayPrefix(
998 &restored,
999 .{ .start = start_moment, .steps = &steps, .end = fault_moment },
1000 ));
1001 try std.testing.expectEqual(@as(u8, 2), progress.step_count);
1002 try std.testing.expectEqual(@as(u8, 1), progress.turn_count);
1003 try std.testing.expectEqualSlices(u8, &.{0}, progress.eventSteps());
1004 try std.testing.expectEqual(@as(usize, 1), progress.eventBatches().len);
1005 try std.testing.expect(progress.eventBatches()[0].count > 0);
1006 try std.testing.expectEqualDeep(fault_moment, progress.moment);
1007 try std.testing.expectEqualDeep(expected, restored.fabric.*);
1008 }
1009
1010 fn expectPrefixPlanRejections(
1011 cut: world.Cut,
1012 initial: fabric.Fabric,
1013 first_checkpoint: *const checkpoint.Checkpoint,
1014 second_checkpoint: *const checkpoint.Checkpoint,
1015 admission_transition: fabric.Transition,
1016 settlement_transition: fabric.Transition,
1017 moments: ReplayedMoments,
1018 ) !void {
1019 var restored_fabric = initial;
1020 var first_storage = instance.Storage.init();
1021 var second_storage = instance.Storage.init();
1022 var restored = try restoreFaultWorld(
1023 cut,
1024 &restored_fabric,
1025 first_checkpoint,
1026 second_checkpoint,
1027 &first_storage,
1028 &second_storage,
1029 );
1030 defer restored.deinit();
1031 const start_moment = try restored.currentMoment();
1032 const identity = try requirePrefixReached(world.replayPrefix(
1033 &restored,
1034 .{ .start = start_moment, .steps = &.{}, .end = start_moment },
1035 ));
1036 try std.testing.expectEqual(@as(u8, 0), identity.step_count);
1037 try std.testing.expectEqual(@as(u8, 0), identity.turn_count);
1038 try std.testing.expectEqual(@as(usize, 0), identity.eventBatches().len);
1039 try std.testing.expectEqualDeep(start_moment, identity.moment);
1040 var wrong_start = start_moment;
1041 wrong_start.digest[0] ^= 1;
1042 try expectPrefixRejected(
1043 world.replayPrefix(
1044 &restored,
1045 .{ .start = wrong_start, .steps = &.{}, .end = wrong_start },
1046 ),
1047 0,
1048 error.PrefixStartMismatch,
1049 start_moment,
1050 );
1051 try expectPrefixRejected(
1052 world.replayPrefix(
1053 &restored,
1054 .{ .start = start_moment, .steps = &.{}, .end = moments.first },
1055 ),
1056 0,
1057 error.PrefixEndMismatch,
1058 start_moment,
1059 );
1060 const restored_bytes = std.mem.asBytes(&restored);
1061 const aliased_steps = std.mem.bytesAsSlice(
1062 world.PrefixStep,
1063 restored_bytes[0..@sizeOf(world.PrefixStep)],
1064 );
1065 try expectPrefixRejected(
1066 world.replayPrefix(
1067 &restored,
1068 .{ .start = start_moment, .steps = aliased_steps, .end = start_moment },
1069 ),
1070 0,
1071 error.SourceAlias,
1072 start_moment,
1073 );
1074 var admission_reader = std.Io.Reader.fixed(&replay_admission_stream);
1075 var settlement_reader = std.Io.Reader.fixed(&replay_settlement_stream);
1076 var sequenced_step = turnPrefixStep(
1077 &admission_reader,
1078 admission_transition,
1079 &settlement_reader,
1080 settlement_transition,
1081 activationFence(0x71),
1082 moments.first,
1083 );
1084 sequenced_step.turn.replay.admission.expected_root.entry_frontier += 1;
1085 try expectPrefixRejected(
1086 world.replayPrefix(
1087 &restored,
1088 .{
1089 .start = start_moment,
1090 .steps = &.{sequenced_step},
1091 .end = moments.first,
1092 },
1093 ),
1094 0,
1095 error.PrefixStepSequenceMismatch,
1096 start_moment,
1097 );
1098 var tampered = moments.first;
1099 tampered.digest[0] ^= 1;
1100 const tampered_step = turnPrefixStep(
1101 &admission_reader,
1102 admission_transition,
1103 &settlement_reader,
1104 settlement_transition,
1105 activationFence(0x71),
1106 tampered,
1107 );
1108 try expectPrefixRejected(
1109 world.replayPrefix(
1110 &restored,
1111 .{
1112 .start = start_moment,
1113 .steps = &.{tampered_step},
1114 .end = tampered,
1115 },
1116 ),
1117 0,
1118 error.MomentMismatch,
1119 start_moment,
1120 );
1121 const oversized: [world.prefix_step_limit + 1]world.PrefixStep =
1122 @splat(tampered_step);
1123 try expectPrefixRejected(
1124 world.replayPrefix(
1125 &restored,
1126 .{ .start = start_moment, .steps = &oversized, .end = tampered },
1127 ),
1128 0,
1129 error.PrefixStepCapacityExceeded,
1130 start_moment,
1131 );
1132 try std.testing.expectEqualDeep(initial, restored.fabric.*);
1133 try std.testing.expect(restored.nodes[0].machine != null);
1134 try std.testing.expect(restored.nodes[1].machine != null);
1135 }
1136
1137 fn expectPartialPrefixRejection(
1138 cut: world.Cut,
1139 initial: fabric.Fabric,
1140 first_checkpoint: *const checkpoint.Checkpoint,
1141 second_checkpoint: *const checkpoint.Checkpoint,
1142 admission_transition: fabric.Transition,
1143 settlement_transition: fabric.Transition,
1144 next_admission_transition: fabric.Transition,
1145 next_settlement_transition: fabric.Transition,
1146 moments: ReplayedMoments,
1147 ) !void {
1148 var restored_fabric = initial;
1149 var first_storage = instance.Storage.init();
1150 var second_storage = instance.Storage.init();
1151 var restored = try restoreFaultWorld(
1152 cut,
1153 &restored_fabric,
1154 first_checkpoint,
1155 second_checkpoint,
1156 &first_storage,
1157 &second_storage,
1158 );
1159 defer restored.deinit();
1160 const start_moment = try restored.currentMoment();
1161 var malformed = replay_next_admission_stream;
1162 malformed[0] ^= 1;
1163 var admission_reader = std.Io.Reader.fixed(&replay_admission_stream);
1164 var settlement_reader = std.Io.Reader.fixed(&replay_settlement_stream);
1165 var next_admission_reader = std.Io.Reader.fixed(&malformed);
1166 var next_settlement_reader = std.Io.Reader.fixed(
1167 &replay_next_settlement_stream,
1168 );
1169 const steps = [_]world.PrefixStep{
1170 turnPrefixStep(
1171 &admission_reader,
1172 admission_transition,
1173 &settlement_reader,
1174 settlement_transition,
1175 activationFence(0x71),
1176 moments.first,
1177 ),
1178 turnPrefixStep(
1179 &next_admission_reader,
1180 next_admission_transition,
1181 &next_settlement_reader,
1182 next_settlement_transition,
1183 activationFenceAt(0x73, 2),
1184 moments.second,
1185 ),
1186 };
1187 const stopped = try requirePrefixRejected(
1188 world.replayPrefix(
1189 &restored,
1190 .{ .start = start_moment, .steps = &steps, .end = moments.second },
1191 ),
1192 error.BadMagic,
1193 );
1194 const progress = stopped.progress.?;
1195 try std.testing.expectEqual(@as(u8, 1), stopped.step);
1196 try std.testing.expectEqual(@as(u8, 1), progress.step_count);
1197 try std.testing.expectEqual(@as(u8, 1), progress.turn_count);
1198 try std.testing.expectEqualSlices(u8, &.{0}, progress.eventSteps());
1199 try std.testing.expectEqual(@as(usize, 1), progress.eventBatches().len);
1200 try std.testing.expectEqualDeep(moments.first, progress.moment);
1201 try std.testing.expectEqualDeep(moments.first, restored.moment);
1202 try std.testing.expectEqualDeep(
1203 settlement_transition.root,
1204 restored.fabric.root(),
1205 );
1206 try std.testing.expect(restored.nodes[0].machine != null);
1207 try std.testing.expect(restored.nodes[1].machine != null);
1208 }
1209
1210 fn turnPrefixStep(
1211 admission_reader: *std.Io.Reader,
1212 admission_transition: fabric.Transition,
1213 settlement_reader: *std.Io.Reader,
1214 settlement_transition: fabric.Transition,
1215 fence: os.abi.ActivationFence,
1216 expected_moment: world.Moment,
1217 ) world.PrefixStep {
1218 return .{ .turn = .{
1219 .replay = .{
1220 .admission = .{
1221 .reader = admission_reader,
1222 .expected_root = admission_transition.root,
1223 },
1224 .settlement = .{
1225 .reader = settlement_reader,
1226 .expected_root = settlement_transition.root,
1227 },
1228 .fence = fence,
1229 },
1230 .expected_moment = expected_moment,
1231 } };
1232 }
1233
1234 fn requirePrefixReached(
1235 result: world.PrefixResult,
1236 ) !world.PrefixProgress {
1237 return switch (result) {
1238 .reached => |progress| progress,
1239 .rejected => |stopped| stopped.failure,
1240 .invalidated => |stopped| stopped.failure,
1241 };
1242 }
1243
1244 fn requirePrefixRejected(
1245 result: world.PrefixResult,
1246 expected_failure: world.PrefixError,
1247 ) !world.PrefixStopped {
1248 return switch (result) {
1249 .rejected => |stopped| value: {
1250 try std.testing.expectEqual(expected_failure, stopped.failure);
1251 break :value stopped;
1252 },
1253 .reached => error.TestExpectedPrefixRejection,
1254 .invalidated => error.TestExpectedPrefixRejection,
1255 };
1256 }
1257
1258 fn requirePrefixInvalidated(
1259 result: world.PrefixResult,
1260 expected_failure: world.PrefixError,
1261 ) !world.PrefixStopped {
1262 return switch (result) {
1263 .invalidated => |stopped| value: {
1264 try std.testing.expectEqual(expected_failure, stopped.failure);
1265 break :value stopped;
1266 },
1267 .reached => error.TestExpectedPrefixInvalidation,
1268 .rejected => error.TestExpectedPrefixInvalidation,
1269 };
1270 }
1271
1272 fn expectPrefixRejected(
1273 result: world.PrefixResult,
1274 expected_step: u8,
1275 expected_failure: world.PrefixError,
1276 expected_moment: world.Moment,
1277 ) !void {
1278 const stopped = try requirePrefixRejected(result, expected_failure);
1279 try std.testing.expectEqual(expected_step, stopped.step);
1280 try std.testing.expect(stopped.node == null);
1281 const progress = stopped.progress.?;
1282 try std.testing.expectEqual(@as(u8, 0), progress.step_count);
1283 try std.testing.expectEqual(@as(u8, 0), progress.turn_count);
1284 try std.testing.expectEqual(@as(usize, 0), progress.eventSteps().len);
1285 try std.testing.expectEqualDeep(expected_moment, progress.moment);
1286 }
1287
1288 fn replayRecorded(
1289 restored: *world.Restored,
1290 admission_bytes: []const u8,
1291 admission_transition: fabric.Transition,
1292 settlement_bytes: []const u8,
1293 settlement_transition: fabric.Transition,
1294 fence: os.abi.ActivationFence,
1295 ) !world.ReplayAdvanced {
1296 var admission_reader = std.Io.Reader.fixed(admission_bytes);
1297 var settlement_reader = std.Io.Reader.fixed(settlement_bytes);
1298 return switch (world.replayTurn(restored, .{
1299 .admission = .{
1300 .reader = &admission_reader,
1301 .expected_root = admission_transition.root,
1302 },
1303 .settlement = .{
1304 .reader = &settlement_reader,
1305 .expected_root = settlement_transition.root,
1306 },
1307 .fence = fence,
1308 })) {
1309 .advanced => |advanced| advanced,
1310 .rejected => |rejection| rejection.failure,
1311 .invalidated => |rejection| rejection.failure,
1312 };
1313 }
1314
1315 fn expectDivergentReplayInvalidation(
1316 cut: world.Cut,
1317 initial: fabric.Fabric,
1318 first_checkpoint: *const checkpoint.Checkpoint,
1319 second_checkpoint: *const checkpoint.Checkpoint,
1320 admission_transition: fabric.Transition,
1321 divergent_transition: fabric.Transition,
1322 ) !void {
1323 var restored_fabric = initial;
1324 var first_storage = instance.Storage.init();
1325 var second_storage = instance.Storage.init();
1326 const bindings = restoreBindings(
1327 first_checkpoint,
1328 second_checkpoint,
1329 &first_storage,
1330 &second_storage,
1331 );
1332 var restored = try requireRestored(world.restore(
1333 cut,
1334 &restored_fabric,
1335 &bindings,
1336 ));
1337 defer restored.deinit();
1338 const initial_moment = try restored.currentMoment();
1339 try expectReplayMomentRejection(&restored, admission_transition);
1340 try expectReplayCapabilityRejection(&restored, admission_transition);
1341 try expectReplayPreflightRejection(&restored, admission_transition);
1342 try expectReplayAliasRejection(&restored, admission_transition);
1343 var admission_reader = std.Io.Reader.fixed(&replay_admission_stream);
1344 var divergent_reader = std.Io.Reader.fixed(&replay_divergent_stream);
1345 const result = world.replayTurn(&restored, .{
1346 .admission = .{
1347 .reader = &admission_reader,
1348 .expected_root = admission_transition.root,
1349 },
1350 .settlement = .{
1351 .reader = &divergent_reader,
1352 .expected_root = divergent_transition.root,
1353 },
1354 .fence = activationFence(0x71),
1355 });
1356 try expectReplayInvalidated(
1357 result,
1358 first_id,
1359 error.SettlementTransitionMismatch,
1360 );
1361 try std.testing.expect(restored.nodes[0].machine == null);
1362 try std.testing.expect(restored.nodes[1].machine == null);
1363 try std.testing.expectEqualDeep(initial, restored.fabric.*);
1364 try std.testing.expectEqualDeep(initial_moment, restored.moment);
1365 try std.testing.expectEqualDeep(
1366 initial_moment,
1367 try restored.currentMoment(),
1368 );
1369 try expectPrefixDivergentInvalidation(
1370 cut,
1371 initial,
1372 first_checkpoint,
1373 second_checkpoint,
1374 admission_transition,
1375 divergent_transition,
1376 );
1377 }
1378
1379 fn expectPrefixDivergentInvalidation(
1380 cut: world.Cut,
1381 initial: fabric.Fabric,
1382 first_checkpoint: *const checkpoint.Checkpoint,
1383 second_checkpoint: *const checkpoint.Checkpoint,
1384 admission_transition: fabric.Transition,
1385 divergent_transition: fabric.Transition,
1386 ) !void {
1387 var restored_fabric = initial;
1388 var first_storage = instance.Storage.init();
1389 var second_storage = instance.Storage.init();
1390 var restored = try restoreFaultWorld(
1391 cut,
1392 &restored_fabric,
1393 first_checkpoint,
1394 second_checkpoint,
1395 &first_storage,
1396 &second_storage,
1397 );
1398 defer restored.deinit();
1399 const start_moment = try restored.currentMoment();
1400 const expected = try world_moment.prepare(
1401 cut.root,
1402 divergent_transition.root,
1403 );
1404 var admission_reader = std.Io.Reader.fixed(&replay_admission_stream);
1405 var divergent_reader = std.Io.Reader.fixed(&replay_divergent_stream);
1406 const steps = [_]world.PrefixStep{turnPrefixStep(
1407 &admission_reader,
1408 admission_transition,
1409 &divergent_reader,
1410 divergent_transition,
1411 activationFence(0x71),
1412 expected,
1413 )};
1414 const stopped = try requirePrefixInvalidated(
1415 world.replayPrefix(
1416 &restored,
1417 .{ .start = start_moment, .steps = &steps, .end = expected },
1418 ),
1419 error.SettlementTransitionMismatch,
1420 );
1421 const progress = stopped.progress.?;
1422 try std.testing.expectEqual(@as(u8, 0), stopped.step);
1423 try std.testing.expectEqualDeep(first_id, stopped.node.?);
1424 try std.testing.expectEqual(@as(u8, 0), progress.step_count);
1425 try std.testing.expectEqual(@as(u8, 0), progress.turn_count);
1426 try std.testing.expectEqualDeep(start_moment, progress.moment);
1427 try std.testing.expectEqualDeep(start_moment, restored.moment);
1428 try std.testing.expectEqualDeep(initial, restored.fabric.*);
1429 try std.testing.expect(restored.nodes[0].machine == null);
1430 try std.testing.expect(restored.nodes[1].machine == null);
1431 }
1432
1433 fn expectReplayCapabilityRejection(
1434 restored: *world.Restored,
1435 admission_transition: fabric.Transition,
1436 ) !void {
1437 const before_fabric = restored.fabric.*;
1438 const before_moment = try restored.currentMoment();
1439 const second = restored.nodes[1].machine.?;
1440 restored.nodes[1].machine = null;
1441 defer restored.nodes[1].machine = second;
1442 var admission_reader = std.Io.Reader.fixed(&replay_admission_stream);
1443 var settlement_reader = std.Io.Reader.fixed(&replay_settlement_stream);
1444 const result = world.replayTurn(restored, .{
1445 .admission = .{
1446 .reader = &admission_reader,
1447 .expected_root = admission_transition.root,
1448 },
1449 .settlement = .{
1450 .reader = &settlement_reader,
1451 .expected_root = admission_transition.root,
1452 },
1453 .fence = activationFence(0x71),
1454 });
1455 try expectReplayRejected(result, null, error.CapabilitySetMismatch);
1456 try std.testing.expectEqualDeep(before_fabric, restored.fabric.*);
1457 try std.testing.expectEqualDeep(before_moment, restored.moment);
1458 try std.testing.expect(restored.nodes[0].machine != null);
1459 try std.testing.expect(second.active());
1460 }
1461
1462 fn expectReplayMomentRejection(
1463 restored: *world.Restored,
1464 admission_transition: fabric.Transition,
1465 ) !void {
1466 const before_fabric = restored.fabric.*;
1467 const before_moment = restored.moment;
1468 restored.moment.digest[0] ^= 1;
1469 defer restored.moment = before_moment;
1470 var admission_reader = std.Io.Reader.fixed(&replay_admission_stream);
1471 var settlement_reader = std.Io.Reader.fixed(&replay_settlement_stream);
1472 const result = world.replayTurn(restored, .{
1473 .admission = .{
1474 .reader = &admission_reader,
1475 .expected_root = admission_transition.root,
1476 },
1477 .settlement = .{
1478 .reader = &settlement_reader,
1479 .expected_root = admission_transition.root,
1480 },
1481 .fence = activationFence(0x71),
1482 });
1483 try expectReplayRejected(result, null, error.MomentMismatch);
1484 try std.testing.expectEqualDeep(before_fabric, restored.fabric.*);
1485 try std.testing.expect(restored.nodes[0].machine != null);
1486 try std.testing.expect(restored.nodes[1].machine != null);
1487 }
1488
1489 fn expectReplayPreflightRejection(
1490 restored: *world.Restored,
1491 admission_transition: fabric.Transition,
1492 ) !void {
1493 const before = restored.fabric.*;
1494 const before_moment = try restored.currentMoment();
1495 var wrong_root = admission_transition.root;
1496 wrong_root.digest[0] ^= 1;
1497 var admission_reader = std.Io.Reader.fixed(&replay_admission_stream);
1498 var settlement_reader = std.Io.Reader.fixed(&replay_settlement_stream);
1499 const result = world.replayTurn(restored, .{
1500 .admission = .{
1501 .reader = &admission_reader,
1502 .expected_root = wrong_root,
1503 },
1504 .settlement = .{
1505 .reader = &settlement_reader,
1506 .expected_root = admission_transition.root,
1507 },
1508 .fence = activationFence(0x71),
1509 });
1510 try expectReplayRejected(result, null, error.ResultRootMismatch);
1511 try std.testing.expect(restored.nodes[0].machine != null);
1512 try std.testing.expect(restored.nodes[1].machine != null);
1513 try std.testing.expectEqualDeep(before, restored.fabric.*);
1514 try std.testing.expectEqualDeep(before_moment, restored.moment);
1515 }
1516
1517 fn expectReplayAliasRejection(
1518 restored: *world.Restored,
1519 admission_transition: fabric.Transition,
1520 ) !void {
1521 const before = restored.fabric.*;
1522 const before_moment = try restored.currentMoment();
1523 var admission_reader = std.Io.Reader.fixed(std.mem.asBytes(restored.fabric));
1524 var settlement_reader = std.Io.Reader.fixed(&replay_settlement_stream);
1525 const result = world.replayTurn(restored, .{
1526 .admission = .{
1527 .reader = &admission_reader,
1528 .expected_root = admission_transition.root,
1529 },
1530 .settlement = .{
1531 .reader = &settlement_reader,
1532 .expected_root = admission_transition.root,
1533 },
1534 .fence = activationFence(0x71),
1535 });
1536 try expectReplayRejected(result, null, error.SourceAlias);
1537 try std.testing.expect(restored.nodes[0].machine != null);
1538 try std.testing.expect(restored.nodes[1].machine != null);
1539 try std.testing.expectEqualDeep(before, restored.fabric.*);
1540 try std.testing.expectEqualDeep(before_moment, restored.moment);
1541 }
1542
1543 fn expectReplayRejected(
1544 result: world.ReplayResult,
1545 expected_node: ?fabric.NodeId,
1546 expected_failure: world.ReplayError,
1547 ) !void {
1548 switch (result) {
1549 .rejected => |rejection| {
1550 try std.testing.expectEqualDeep(expected_node, rejection.node);
1551 try std.testing.expectEqual(expected_failure, rejection.failure);
1552 },
1553 .advanced => return error.TestExpectedReplayRejection,
1554 .invalidated => return error.TestExpectedReplayRejection,
1555 }
1556 }
1557
1558 fn expectReplayInvalidated(
1559 result: world.ReplayResult,
1560 expected_node: fabric.NodeId,
1561 expected_failure: world.ReplayError,
1562 ) !void {
1563 switch (result) {
1564 .invalidated => |rejection| {
1565 try std.testing.expectEqualDeep(expected_node, rejection.node.?);
1566 try std.testing.expectEqual(expected_failure, rejection.failure);
1567 },
1568 .advanced => return error.TestExpectedReplayInvalidation,
1569 .rejected => return error.TestExpectedReplayInvalidation,
1570 }
1571 }
1572
1573 test "rooted machine crashes update restored capability topology" {
1574 const execution = try os.boot.kernel.manifest.parse(k0_manifest);
1575 const first_fence = activationFence(0xd1);
1576 const second_fence = activationFence(0xd2);
1577 var first_storage = instance.Storage.init();
1578 var first = try start(
1579 &first_storage,
1580 &first_live_ram,
1581 machineInput(execution, first_fence, 0x81),
1582 );
1583 var first_open = true;
1584 defer if (first_open) first.deinit();
1585 var second_storage = instance.Storage.init();
1586 var second = try start(
1587 &second_storage,
1588 &second_live_ram,
1589 machineInput(execution, second_fence, 0x91),
1590 );
1591 var second_open = true;
1592 defer if (second_open) second.deinit();
1593 var connected = try connectedFabric(&first, &second);
1594 var first_checkpoint_storage = checkpoint.Storage.init();
1595 const first_checkpoint = try captureBoundary(
1596 &connected,
1597 first_id,
1598 &first,
1599 first_fence,
1600 0xe1,
1601 &first_checkpoint_storage,
1602 &first_checkpoint_ram,
1603 false,
1604 );
1605 var second_checkpoint_storage = checkpoint.Storage.init();
1606 const second_checkpoint = try captureBoundary(
1607 &connected,
1608 second_id,
1609 &second,
1610 second_fence,
1611 0xe2,
1612 &second_checkpoint_storage,
1613 &second_checkpoint_ram,
1614 false,
1615 );
1616 const bindings = [_]world.Binding{
1617 binding(first_id, &first, &first_checkpoint),
1618 binding(second_id, &second, &second_checkpoint),
1619 };
1620 const cut = try world.seal(&connected, &bindings);
1621 const initial = connected;
1622 const bypass_input: fabric.FaultInput = .{
1623 .effect = .{ .machine_crash = first_id },
1624 .choice = .bypass,
1625 };
1626 var bypass_fabric = initial;
1627 const bypassed = try bypass_fabric.applyFault(bypass_input);
1628 try encodeTransition(
1629 &initial,
1630 &.{ .entry = bypassed.entry, .root = bypassed.root },
1631 &fault_bypass_stream,
1632 );
1633 const clock_input: fabric.FaultInput = .{
1634 .effect = .{ .clock_jump = 23 },
1635 .choice = .inject,
1636 };
1637 var clock_fabric = bypass_fabric;
1638 const clocked = try clock_fabric.applyFault(clock_input);
1639 try encodeTransition(
1640 &bypass_fabric,
1641 &.{ .entry = clocked.entry, .root = clocked.root },
1642 &fault_clock_stream,
1643 );
1644 const inject_input: fabric.FaultInput = .{
1645 .effect = .{ .machine_crash = first_id },
1646 .choice = .inject,
1647 };
1648 var inject_fabric = initial;
1649 const injected = try inject_fabric.applyFault(inject_input);
1650 try encodeTransition(
1651 &initial,
1652 &.{ .entry = injected.entry, .root = injected.root },
1653 &fault_inject_stream,
1654 );
1655 const process_input: fabric.FaultInput = .{
1656 .effect = .{ .process_crash = .{
1657 .node = first_id,
1658 .process = 7,
1659 } },
1660 .choice = .inject,
1661 };
1662 var process_fabric = initial;
1663 const process = try process_fabric.applyFault(process_input);
1664 try encodeTransition(
1665 &initial,
1666 &.{ .entry = process.entry, .root = process.root },
1667 &fault_process_stream,
1668 );
1669 const admission_fence = activationFenceAt(0xd3, 2);
1670 try first.reactivate(admission_fence);
1671 try activate(&first);
1672 var admission_fabric = initial;
1673 const admitted = try admission_fabric.injectEntropy(
1674 first_id,
1675 &first,
1676 admission_fence,
1677 &.{0xe3},
1678 );
1679 try encodeTransition(
1680 &initial,
1681 &.{ .entry = admitted.entry, .root = admitted.root },
1682 &fault_admission_stream,
1683 );
1684 first.deinit();
1685 first_open = false;
1686 second.deinit();
1687 second_open = false;
1688 const bypass_apply_moment = try expectMachineFaultApply(
1689 cut,
1690 initial,
1691 &first_checkpoint,
1692 &second_checkpoint,
1693 bypass_input,
1694 bypass_fabric,
1695 bypassed,
1696 );
1697 const inject_apply_moment = try expectMachineFaultApply(
1698 cut,
1699 initial,
1700 &first_checkpoint,
1701 &second_checkpoint,
1702 inject_input,
1703 inject_fabric,
1704 injected,
1705 );
1706 const bypass_replay_moment = try expectMachineFaultReplay(
1707 cut,
1708 initial,
1709 &first_checkpoint,
1710 &second_checkpoint,
1711 &fault_bypass_stream,
1712 bypass_fabric,
1713 bypassed,
1714 );
1715 const inject_replay_moment = try expectMachineFaultReplay(
1716 cut,
1717 initial,
1718 &first_checkpoint,
1719 &second_checkpoint,
1720 &fault_inject_stream,
1721 inject_fabric,
1722 injected,
1723 );
1724 try std.testing.expectEqualDeep(
1725 bypass_apply_moment,
1726 bypass_replay_moment,
1727 );
1728 try std.testing.expectEqualDeep(
1729 inject_apply_moment,
1730 inject_replay_moment,
1731 );
1732 try std.testing.expect(!std.meta.eql(
1733 bypass_apply_moment,
1734 inject_apply_moment,
1735 ));
1736 try expectFaultPrefixReplay(
1737 cut,
1738 initial,
1739 &first_checkpoint,
1740 &second_checkpoint,
1741 bypass_input,
1742 bypassed,
1743 clock_input,
1744 clocked,
1745 clock_fabric,
1746 );
1747 try expectFaultRejectionsAndFabricEffect(
1748 cut,
1749 initial,
1750 &first_checkpoint,
1751 &second_checkpoint,
1752 process_input,
1753 process,
1754 admitted,
1755 injected,
1756 );
1757 }
1758
1759 fn expectFaultPrefixReplay(
1760 cut: world.Cut,
1761 initial: fabric.Fabric,
1762 first_checkpoint: *const checkpoint.Checkpoint,
1763 second_checkpoint: *const checkpoint.Checkpoint,
1764 bypass_input: fabric.FaultInput,
1765 bypassed: fabric.Faulted,
1766 clock_input: fabric.FaultInput,
1767 clocked: fabric.Faulted,
1768 expected: fabric.Fabric,
1769 ) !void {
1770 var bypass_moment: world.Moment = undefined;
1771 var clock_moment: world.Moment = undefined;
1772 {
1773 var applied_fabric = initial;
1774 var first_storage = instance.Storage.init();
1775 var second_storage = instance.Storage.init();
1776 var restored = try restoreFaultWorld(
1777 cut,
1778 &applied_fabric,
1779 first_checkpoint,
1780 second_checkpoint,
1781 &first_storage,
1782 &second_storage,
1783 );
1784 defer restored.deinit();
1785 const first = try requireFaultApplied(world.applyFault(
1786 &restored,
1787 bypass_input,
1788 ));
1789 const second = try requireFaultApplied(world.applyFault(
1790 &restored,
1791 clock_input,
1792 ));
1793 bypass_moment = first.moment;
1794 clock_moment = second.moment;
1795 try std.testing.expectEqualDeep(expected, restored.fabric.*);
1796 }
1797 var replayed_fabric = initial;
1798 var first_storage = instance.Storage.init();
1799 var second_storage = instance.Storage.init();
1800 var restored = try restoreFaultWorld(
1801 cut,
1802 &replayed_fabric,
1803 first_checkpoint,
1804 second_checkpoint,
1805 &first_storage,
1806 &second_storage,
1807 );
1808 defer restored.deinit();
1809 const start_moment = try restored.currentMoment();
1810 var bypass_reader = std.Io.Reader.fixed(&fault_bypass_stream);
1811 var clock_reader = std.Io.Reader.fixed(&fault_clock_stream);
1812 const steps = [_]world.PrefixStep{
1813 .{ .fault = .{
1814 .reader = &bypass_reader,
1815 .expected_root = bypassed.root,
1816 .expected_moment = bypass_moment,
1817 } },
1818 .{ .fault = .{
1819 .reader = &clock_reader,
1820 .expected_root = clocked.root,
1821 .expected_moment = clock_moment,
1822 } },
1823 };
1824 const progress = try requirePrefixReached(world.replayPrefix(
1825 &restored,
1826 .{ .start = start_moment, .steps = &steps, .end = clock_moment },
1827 ));
1828 try std.testing.expectEqual(@as(u8, 2), progress.step_count);
1829 try std.testing.expectEqual(@as(u8, 0), progress.turn_count);
1830 try std.testing.expectEqual(@as(usize, 0), progress.eventBatches().len);
1831 try std.testing.expectEqualDeep(clock_moment, progress.moment);
1832 try std.testing.expectEqualDeep(expected, restored.fabric.*);
1833 try std.testing.expect(restored.nodes[0].machine != null);
1834 try std.testing.expect(restored.nodes[1].machine != null);
1835 }
1836
1837 fn expectMachineFaultApply(
1838 cut: world.Cut,
1839 initial: fabric.Fabric,
1840 first_checkpoint: *const checkpoint.Checkpoint,
1841 second_checkpoint: *const checkpoint.Checkpoint,
1842 input: fabric.FaultInput,
1843 expected_fabric: fabric.Fabric,
1844 expected: fabric.Faulted,
1845 ) !world.Moment {
1846 var restored_fabric = initial;
1847 var first_storage = instance.Storage.init();
1848 var second_storage = instance.Storage.init();
1849 var restored = try restoreFaultWorld(
1850 cut,
1851 &restored_fabric,
1852 first_checkpoint,
1853 second_checkpoint,
1854 &first_storage,
1855 &second_storage,
1856 );
1857 defer restored.deinit();
1858 const first_handle = restored.nodes[0].machine.?;
1859 const applied = try requireFaultApplied(world.applyFault(&restored, input));
1860 try expectFaultApplied(applied, expected);
1861 try std.testing.expectEqualDeep(applied.moment, try restored.currentMoment());
1862 try std.testing.expectEqualDeep(cut.root, applied.moment.origin);
1863 try std.testing.expectEqualDeep(expected_fabric, restored.fabric.*);
1864 const injected = input.choice == .inject;
1865 try std.testing.expectEqual(!injected, restored.nodes[0].machine != null);
1866 try std.testing.expectEqual(!injected, first_handle.active());
1867 try std.testing.expect(restored.nodes[1].machine != null);
1868 try std.testing.expect(restored.nodes[1].machine.?.active());
1869 return applied.moment;
1870 }
1871
1872 fn expectMachineFaultReplay(
1873 cut: world.Cut,
1874 initial: fabric.Fabric,
1875 first_checkpoint: *const checkpoint.Checkpoint,
1876 second_checkpoint: *const checkpoint.Checkpoint,
1877 bytes: []const u8,
1878 expected_fabric: fabric.Fabric,
1879 expected: fabric.Faulted,
1880 ) !world.Moment {
1881 var restored_fabric = initial;
1882 var first_storage = instance.Storage.init();
1883 var second_storage = instance.Storage.init();
1884 var restored = try restoreFaultWorld(
1885 cut,
1886 &restored_fabric,
1887 first_checkpoint,
1888 second_checkpoint,
1889 &first_storage,
1890 &second_storage,
1891 );
1892 defer restored.deinit();
1893 const first_handle = restored.nodes[0].machine.?;
1894 var reader = std.Io.Reader.fixed(bytes);
1895 const applied = try requireFaultApplied(world.replayFault(
1896 &restored,
1897 &reader,
1898 expected.root,
1899 ));
1900 try expectFaultApplied(applied, expected);
1901 try std.testing.expectEqualDeep(applied.moment, try restored.currentMoment());
1902 try std.testing.expectEqualDeep(cut.root, applied.moment.origin);
1903 try std.testing.expectEqualDeep(expected_fabric, restored.fabric.*);
1904 const injected = expected.decision.choice == .inject;
1905 try std.testing.expectEqual(!injected, restored.nodes[0].machine != null);
1906 try std.testing.expectEqual(!injected, first_handle.active());
1907 try std.testing.expect(restored.nodes[1].machine != null);
1908 try std.testing.expect(restored.nodes[1].machine.?.active());
1909 return applied.moment;
1910 }
1911
1912 fn expectFaultRejectionsAndFabricEffect(
1913 cut: world.Cut,
1914 initial: fabric.Fabric,
1915 first_checkpoint: *const checkpoint.Checkpoint,
1916 second_checkpoint: *const checkpoint.Checkpoint,
1917 process_input: fabric.FaultInput,
1918 process: fabric.Faulted,
1919 admitted: fabric.Admitted,
1920 injected: fabric.Faulted,
1921 ) !void {
1922 var restored_fabric = initial;
1923 var first_storage = instance.Storage.init();
1924 var second_storage = instance.Storage.init();
1925 var restored = try restoreFaultWorld(
1926 cut,
1927 &restored_fabric,
1928 first_checkpoint,
1929 second_checkpoint,
1930 &first_storage,
1931 &second_storage,
1932 );
1933 defer restored.deinit();
1934 const first_handle = restored.nodes[0].machine.?;
1935 const second_handle = restored.nodes[1].machine.?;
1936 const initial_moment = try restored.currentMoment();
1937 try expectFaultRejected(
1938 world.applyFault(&restored, process_input),
1939 first_id,
1940 error.ProcessFaultProviderUnavailable,
1941 );
1942 try expectFaultWorldUnchanged(
1943 &restored,
1944 initial,
1945 initial_moment,
1946 first_handle,
1947 second_handle,
1948 );
1949 var process_reader = std.Io.Reader.fixed(&fault_process_stream);
1950 try expectFaultRejected(
1951 world.replayFault(&restored, &process_reader, process.root),
1952 first_id,
1953 error.ProcessFaultProviderUnavailable,
1954 );
1955 try expectFaultWorldUnchanged(
1956 &restored,
1957 initial,
1958 initial_moment,
1959 first_handle,
1960 second_handle,
1961 );
1962 var admission_reader = std.Io.Reader.fixed(&fault_admission_stream);
1963 try expectFaultRejected(
1964 world.replayFault(&restored, &admission_reader, admitted.root),
1965 null,
1966 error.FaultTransitionExpected,
1967 );
1968 try expectFaultWorldUnchanged(
1969 &restored,
1970 initial,
1971 initial_moment,
1972 first_handle,
1973 second_handle,
1974 );
1975 var wrong_root = injected.root;
1976 wrong_root.digest[0] ^= 1;
1977 var wrong_reader = std.Io.Reader.fixed(&fault_inject_stream);
1978 try expectFaultRejected(
1979 world.replayFault(&restored, &wrong_reader, wrong_root),
1980 null,
1981 error.ResultRootMismatch,
1982 );
1983 try expectFaultWorldUnchanged(
1984 &restored,
1985 initial,
1986 initial_moment,
1987 first_handle,
1988 second_handle,
1989 );
1990 var alias_reader = std.Io.Reader.fixed(std.mem.asBytes(restored.fabric));
1991 try expectFaultRejected(
1992 world.replayFault(&restored, &alias_reader, injected.root),
1993 null,
1994 error.SourceAlias,
1995 );
1996 try expectFaultWorldUnchanged(
1997 &restored,
1998 initial,
1999 initial_moment,
2000 first_handle,
2001 second_handle,
2002 );
2003 restored.moment.digest[0] ^= 1;
2004 try expectFaultRejected(
2005 world.applyFault(&restored, .{
2006 .effect = .{ .clock_jump = 23 },
2007 .choice = .inject,
2008 }),
2009 null,
2010 error.MomentMismatch,
2011 );
2012 try std.testing.expectEqualDeep(initial, restored.fabric.*);
2013 try std.testing.expect(first_handle.active());
2014 try std.testing.expect(second_handle.active());
2015 restored.moment = initial_moment;
2016 const clock = try requireFaultApplied(world.applyFault(&restored, .{
2017 .effect = .{ .clock_jump = 23 },
2018 .choice = .inject,
2019 }));
2020 try std.testing.expectEqualDeep(clock.transition.root, restored.fabric.root());
2021 try std.testing.expectEqualDeep(clock.moment, try restored.currentMoment());
2022 try std.testing.expect(!std.meta.eql(initial_moment, clock.moment));
2023 try std.testing.expect(!std.meta.eql(initial.root(), restored.fabric.root()));
2024 try std.testing.expect(first_handle.active());
2025 try std.testing.expect(second_handle.active());
2026 }
2027
2028 fn restoreFaultWorld(
2029 cut: world.Cut,
2030 fabric_owner: *fabric.Fabric,
2031 first_checkpoint: *const checkpoint.Checkpoint,
2032 second_checkpoint: *const checkpoint.Checkpoint,
2033 first_storage: *instance.Storage,
2034 second_storage: *instance.Storage,
2035 ) !world.Restored {
2036 const bindings = restoreBindings(
2037 first_checkpoint,
2038 second_checkpoint,
2039 first_storage,
2040 second_storage,
2041 );
2042 return requireRestored(world.restore(cut, fabric_owner, &bindings));
2043 }
2044
2045 fn requireFaultApplied(result: world.FaultResult) !world.FaultApplied {
2046 return switch (result) {
2047 .applied => |applied| applied,
2048 .rejected => |rejection| rejection.failure,
2049 };
2050 }
2051
2052 fn expectFaultApplied(
2053 actual: world.FaultApplied,
2054 expected: fabric.Faulted,
2055 ) !void {
2056 try std.testing.expectEqualDeep(expected.entry, actual.transition.entry);
2057 try std.testing.expectEqualDeep(expected.root, actual.transition.root);
2058 try std.testing.expectEqualDeep(expected.decision, actual.decision);
2059 try std.testing.expectEqualDeep(expected.root, actual.moment.fabric);
2060 }
2061
2062 fn expectFaultRejected(
2063 result: world.FaultResult,
2064 expected_node: ?fabric.NodeId,
2065 expected_failure: world.FaultError,
2066 ) !void {
2067 switch (result) {
2068 .rejected => |rejection| {
2069 try std.testing.expectEqualDeep(expected_node, rejection.node);
2070 try std.testing.expectEqual(expected_failure, rejection.failure);
2071 },
2072 .applied => return error.TestExpectedFaultRejection,
2073 }
2074 }
2075
2076 fn expectFaultWorldUnchanged(
2077 restored: *world.Restored,
2078 expected: fabric.Fabric,
2079 expected_moment: world.Moment,
2080 first: instance.Instance,
2081 second: instance.Instance,
2082 ) !void {
2083 try std.testing.expectEqualDeep(expected, restored.fabric.*);
2084 try std.testing.expectEqualDeep(expected_moment, restored.moment);
2085 try std.testing.expectEqualDeep(expected_moment, try restored.currentMoment());
2086 try std.testing.expect(restored.nodes[0].machine != null);
2087 try std.testing.expect(restored.nodes[1].machine != null);
2088 try std.testing.expect(first.active());
2089 try std.testing.expect(second.active());
2090 }
2091
2092 fn exerciseConnectedWorld(
2093 first: *instance.Instance,
2094 second: *instance.Instance,
2095 connected: *const fabric.Fabric,
2096 first_checkpoint: *const checkpoint.Checkpoint,
2097 second_checkpoint: *const checkpoint.Checkpoint,
2098 ) !void {
2099 const bindings = [_]world.Binding{
2100 binding(first_id, first, first_checkpoint),
2101 binding(second_id, second, second_checkpoint),
2102 };
2103 const sealed = try expectSealedWorld(connected, bindings, first_checkpoint);
2104 try expectSealRejections(
2105 connected,
2106 bindings,
2107 first_checkpoint,
2108 second_checkpoint,
2109 );
2110 try expectCutMutationRejections(sealed);
2111 try expectRestoreCapabilityAtomicity(
2112 connected.*,
2113 sealed,
2114 first_checkpoint,
2115 second_checkpoint,
2116 );
2117 const unavailable = try expectUnavailableNodeRetainsRoot(
2118 connected.*,
2119 bindings,
2120 sealed,
2121 );
2122 try expectRetainedRestore(
2123 unavailable,
2124 first_checkpoint,
2125 second_checkpoint,
2126 );
2127 try expectActiveNodeRejected(first, connected, bindings);
2128 }
2129
2130 fn expectInitialBoundary(connected: *const fabric.Fabric) !void {
2131 const initial_cut = try connected.cut();
2132 try std.testing.expectEqual(
2133 fabric.MachineBoundaryKind.basis,
2134 initial_cut.nodes[0].machine.kind,
2135 );
2136 }
2137
2138 fn expectSealedWorld(
2139 connected: *const fabric.Fabric,
2140 bindings: [2]world.Binding,
2141 first_checkpoint: *const checkpoint.Checkpoint,
2142 ) !world.Cut {
2143 const sealed = try world.seal(connected, &bindings);
2144 try world.verify(sealed);
2145 try std.testing.expectEqual(@as(u8, 2), sealed.root.node_count);
2146 try std.testing.expectEqualDeep(connected.root(), sealed.root.fabric);
2147 try std.testing.expectEqualDeep(
2148 try first_checkpoint.root(),
2149 sealed.nodes[0].machine,
2150 );
2151 try std.testing.expectEqualDeep(sealed, try world.seal(connected, &bindings));
2152 try expectRootHex(
2153 sealed.root,
2154 "e859110745ba21acbcf5556e72bb1bfe364fc23ceb06e85cec9515d223cd584e",
2155 );
2156 return sealed;
2157 }
2158
2159 fn connectedFabric(
2160 first: *const instance.Instance,
2161 second: *const instance.Instance,
2162 ) !fabric.Fabric {
2163 const nodes = [_]fabric.Node{
2164 .{ .id = first_id, .basis = try first.admissionBasis() },
2165 .{ .id = second_id, .basis = try second.admissionBasis() },
2166 };
2167 return fabric.Fabric.init(.{
2168 .profile = profile.interpretedContinuationTestV1(),
2169 .world = world_id,
2170 .virtual_time_tick = 7,
2171 .nodes = &nodes,
2172 });
2173 }
2174
2175 fn captureBoundary(
2176 connected: *fabric.Fabric,
2177 node: fabric.NodeId,
2178 machine: *instance.Instance,
2179 fence: os.abi.ActivationFence,
2180 entropy: u8,
2181 storage: *checkpoint.Storage,
2182 ram: []align(checkpoint.ram_alignment) u8,
2183 probe_pending: bool,
2184 ) !checkpoint.Checkpoint {
2185 const admitted = try connected.injectEntropy(
2186 node,
2187 machine,
2188 fence,
2189 &.{entropy},
2190 );
2191 if (probe_pending) {
2192 try std.testing.expectError(error.TurnPending, world.seal(connected, &.{}));
2193 }
2194 const receipt = try completeTurn(machine, admitted.delivery);
2195 _ = try connected.settle(node, receipt);
2196 return machine.captureCheckpoint(storage, ram);
2197 }
2198
2199 fn expectIncompleteWorld(
2200 connected: *const fabric.Fabric,
2201 first: *const instance.Instance,
2202 second: *const instance.Instance,
2203 first_checkpoint: *const checkpoint.Checkpoint,
2204 ) !void {
2205 const bindings = [_]world.Binding{
2206 binding(first_id, first, first_checkpoint),
2207 binding(second_id, second, first_checkpoint),
2208 };
2209 try std.testing.expectError(
2210 error.MachineBoundaryUnavailable,
2211 world.seal(connected, &bindings),
2212 );
2213 }
2214
2215 fn expectUnavailableNodeRetainsRoot(
2216 connected: fabric.Fabric,
2217 bindings: [2]world.Binding,
2218 before: world.Cut,
2219 ) !UnavailableWorld {
2220 var crashed = connected;
2221 _ = try crashed.applyFault(.{
2222 .effect = .{ .machine_crash = second_id },
2223 .choice = .inject,
2224 });
2225 const fabric_cut = try crashed.cut();
2226 try std.testing.expect(!fabric_cut.nodes[1].available);
2227 try std.testing.expectError(
2228 error.MachineSourceMismatch,
2229 world.seal(&crashed, &bindings),
2230 );
2231 var retained = bindings;
2232 retained[1].source = .retained;
2233 const after = try world.seal(&crashed, &retained);
2234 try world.verify(after);
2235 try std.testing.expectEqualDeep(
2236 before.nodes[1].machine,
2237 after.nodes[1].machine,
2238 );
2239 try std.testing.expect(!std.meta.eql(before.root, after.root));
2240 return .{ .fabric = crashed, .cut = after };
2241 }
2242
2243 fn expectRestoreCapabilityAtomicity(
2244 connected: fabric.Fabric,
2245 cut: world.Cut,
2246 first_checkpoint: *const checkpoint.Checkpoint,
2247 second_checkpoint: *const checkpoint.Checkpoint,
2248 ) !void {
2249 var restored_fabric = connected;
2250 var first_storage = instance.Storage.init();
2251 var second_storage = instance.Storage.init();
2252 @memset(&first_restore_ram, 0xa5);
2253 @memset(&second_restore_ram, 0xa5);
2254 var bindings = restoreBindings(
2255 first_checkpoint,
2256 second_checkpoint,
2257 &first_storage,
2258 &second_storage,
2259 );
2260 try expectRestoreStructuralRejections(&restored_fabric, cut, &bindings);
2261
2262 bindings[1].mode.live.execution_manifest = k0_manifest[0 .. k0_manifest.len - 1];
2263 const rejected = world.restore(cut, &restored_fabric, &bindings);
2264 try expectRestoreRejectedNode(rejected, second_id);
2265 try std.testing.expectEqual(@as(u8, 0xa5), first_restore_ram[0]);
2266 try std.testing.expectEqual(@as(u8, 0xa5), second_restore_ram[0]);
2267
2268 bindings[1].mode.live.execution_manifest = k0_manifest;
2269 var restored = try requireRestored(world.restore(
2270 cut,
2271 &restored_fabric,
2272 &bindings,
2273 ));
2274 try std.testing.expectEqualDeep(cut.root, restored.root);
2275 try std.testing.expect(restored.fabric == &restored_fabric);
2276 const initial_moment = try restored.currentMoment();
2277 try std.testing.expectEqualDeep(cut.root, initial_moment.origin);
2278 try std.testing.expectEqualDeep(cut.root.fabric, initial_moment.fabric);
2279 try std.testing.expectEqual(
2280 world.MomentDialect.stable_world_v1,
2281 initial_moment.dialect,
2282 );
2283 try std.testing.expectEqual(@as(u8, 2), restored.node_count);
2284 try expectRestoredBooting(&restored.nodes[0], first_id);
2285 try expectRestoredBooting(&restored.nodes[1], second_id);
2286 try expectPendingRestoreRejected(&restored, cut, &bindings);
2287 restored.deinit();
2288 try std.testing.expect(restored.nodes[0].machine == null);
2289 try std.testing.expect(restored.nodes[1].machine == null);
2290 }
2291
2292 fn expectPendingRestoreRejected(
2293 restored: *world.Restored,
2294 cut: world.Cut,
2295 bindings: *const [2]world.RestoreBinding,
2296 ) !void {
2297 const machine = if (restored.nodes[0].machine) |*value|
2298 value
2299 else
2300 return error.TestExpectedLiveMachine;
2301 try activate(machine);
2302 _ = try restored.fabric.injectEntropy(
2303 first_id,
2304 machine,
2305 activationFence(0x71),
2306 &.{0xcc},
2307 );
2308 try expectRestoreRejected(
2309 world.restore(cut, restored.fabric, bindings),
2310 null,
2311 error.TurnPending,
2312 );
2313 }
2314
2315 fn expectRestoreStructuralRejections(
2316 connected: *fabric.Fabric,
2317 cut: world.Cut,
2318 bindings: *[2]world.RestoreBinding,
2319 ) !void {
2320 try expectRestoreRejected(
2321 world.restore(cut, connected, bindings[0..1]),
2322 null,
2323 error.NodeCountMismatch,
2324 );
2325 const reversed = [_]world.RestoreBinding{ bindings[1], bindings[0] };
2326 try expectRestoreRejected(
2327 world.restore(cut, connected, &reversed),
2328 second_id,
2329 error.NodeMismatch,
2330 );
2331 var retained = bindings.*;
2332 retained[0].mode = .retained;
2333 try expectRestoreRejected(
2334 world.restore(cut, connected, &retained),
2335 first_id,
2336 error.MachineModeMismatch,
2337 );
2338 var aliased = bindings.*;
2339 aliased[0].mode.live.ram = &second_checkpoint_ram;
2340 try expectRestoreRejected(
2341 world.restore(cut, connected, &aliased),
2342 null,
2343 error.RestoreAlias,
2344 );
2345 aliased = bindings.*;
2346 aliased[1].mode.live.storage = aliased[0].mode.live.storage;
2347 try expectRestoreRejected(
2348 world.restore(cut, connected, &aliased),
2349 null,
2350 error.RestoreAlias,
2351 );
2352 aliased = bindings.*;
2353 aliased[1].mode.live.execution_manifest = first_restore_ram[0..k0_manifest.len];
2354 try expectRestoreRejected(
2355 world.restore(cut, connected, &aliased),
2356 null,
2357 error.RestoreAlias,
2358 );
2359 var different = connected.*;
2360 _ = try different.applyFault(.{
2361 .effect = .{ .machine_crash = second_id },
2362 .choice = .inject,
2363 });
2364 try expectRestoreRejected(
2365 world.restore(cut, &different, bindings),
2366 null,
2367 error.FabricMismatch,
2368 );
2369 }
2370
2371 fn expectRetainedRestore(
2372 unavailable: UnavailableWorld,
2373 first_checkpoint: *const checkpoint.Checkpoint,
2374 second_checkpoint: *const checkpoint.Checkpoint,
2375 ) !void {
2376 var restored_fabric = unavailable.fabric;
2377 var storage = instance.Storage.init();
2378 const bindings = [_]world.RestoreBinding{
2379 restoreBinding(
2380 first_id,
2381 first_checkpoint,
2382 restoreTarget(&storage, &first_restore_ram, 0x81),
2383 ),
2384 .{
2385 .node = second_id,
2386 .checkpoint = .{ .durable = second_checkpoint },
2387 .mode = .retained,
2388 },
2389 };
2390 var restored = try requireRestored(world.restore(
2391 unavailable.cut,
2392 &restored_fabric,
2393 &bindings,
2394 ));
2395 try expectRestoredBooting(&restored.nodes[0], first_id);
2396 try std.testing.expectEqualDeep(second_id, restored.nodes[1].id);
2397 try std.testing.expect(restored.nodes[1].machine == null);
2398 restored.deinit();
2399 }
2400
2401 fn restoreBindings(
2402 first_checkpoint: *const checkpoint.Checkpoint,
2403 second_checkpoint: *const checkpoint.Checkpoint,
2404 first_storage: *instance.Storage,
2405 second_storage: *instance.Storage,
2406 ) [2]world.RestoreBinding {
2407 return .{
2408 restoreBinding(
2409 first_id,
2410 first_checkpoint,
2411 restoreTarget(first_storage, &first_restore_ram, 0x71),
2412 ),
2413 restoreBinding(
2414 second_id,
2415 second_checkpoint,
2416 restoreTarget(second_storage, &second_restore_ram, 0x72),
2417 ),
2418 };
2419 }
2420
2421 fn restoreBinding(
2422 node: fabric.NodeId,
2423 value: *const checkpoint.Checkpoint,
2424 target: world.RestoreTarget,
2425 ) world.RestoreBinding {
2426 return .{
2427 .node = node,
2428 .checkpoint = .{ .durable = value },
2429 .mode = .{ .live = target },
2430 };
2431 }
2432
2433 fn restoreTarget(
2434 storage: *instance.Storage,
2435 ram: []align(instance.ram_alignment) u8,
2436 token: u8,
2437 ) world.RestoreTarget {
2438 return .{
2439 .profile = profile.interpretedContinuationTestV1(),
2440 .execution_manifest = k0_manifest,
2441 .fence = activationFence(token),
2442 .storage = storage,
2443 .ram = ram,
2444 };
2445 }
2446
2447 fn requireRestored(result: world.RestoreResult) !world.Restored {
2448 return switch (result) {
2449 .ready => |restored| restored,
2450 .unavailable => error.UnexpectedBackendUnavailable,
2451 .rejected => |rejection| rejection.failure,
2452 };
2453 }
2454
2455 fn expectRestoredBooting(
2456 node: *world.RestoredNode,
2457 expected: fabric.NodeId,
2458 ) !void {
2459 try std.testing.expectEqualDeep(expected, node.id);
2460 if (node.machine) |*machine| {
2461 try std.testing.expectEqual(instance.RunPhase.booting, machine.phase());
2462 } else {
2463 return error.TestExpectedLiveMachine;
2464 }
2465 }
2466
2467 fn expectRestoreRejectedNode(
2468 result: world.RestoreResult,
2469 expected: fabric.NodeId,
2470 ) !void {
2471 switch (result) {
2472 .rejected => |rejection| try std.testing.expectEqualDeep(
2473 expected,
2474 rejection.node orelse return error.TestExpectedNode,
2475 ),
2476 .ready => |value| {
2477 var restored = value;
2478 restored.deinit();
2479 return error.TestExpectedRestoreRejection;
2480 },
2481 .unavailable => return error.TestExpectedRestoreRejection,
2482 }
2483 }
2484
2485 fn expectRestoreRejected(
2486 result: world.RestoreResult,
2487 expected_node: ?fabric.NodeId,
2488 expected_failure: world.RestoreError,
2489 ) !void {
2490 switch (result) {
2491 .rejected => |rejection| {
2492 try std.testing.expectEqualDeep(expected_node, rejection.node);
2493 try std.testing.expectEqual(expected_failure, rejection.failure);
2494 },
2495 .ready => |value| {
2496 var restored = value;
2497 restored.deinit();
2498 return error.TestExpectedRestoreRejection;
2499 },
2500 .unavailable => return error.TestExpectedRestoreRejection,
2501 }
2502 }
2503
2504 fn expectActiveNodeRejected(
2505 first: *instance.Instance,
2506 connected: *const fabric.Fabric,
2507 bindings: [2]world.Binding,
2508 ) !void {
2509 try first.reactivate(.{
2510 .world = world_id,
2511 .generation = 2,
2512 .token = @splat(0x61),
2513 });
2514 try activate(first);
2515 try std.testing.expectError(
2516 error.QuiescenceUnavailable,
2517 world.seal(connected, &bindings),
2518 );
2519 }
2520
2521 fn expectSealRejections(
2522 connected: *const fabric.Fabric,
2523 bindings: [2]world.Binding,
2524 first_checkpoint: *const checkpoint.Checkpoint,
2525 second_checkpoint: *const checkpoint.Checkpoint,
2526 ) !void {
2527 try std.testing.expectError(
2528 error.NodeCountMismatch,
2529 world.seal(connected, bindings[0..1]),
2530 );
2531 const reversed = [_]world.Binding{ bindings[1], bindings[0] };
2532 try std.testing.expectError(
2533 error.NodeMismatch,
2534 world.seal(connected, &reversed),
2535 );
2536 var substituted = bindings;
2537 substituted[0].checkpoint = .{ .durable = second_checkpoint };
2538 substituted[1].checkpoint = .{ .durable = first_checkpoint };
2539 try std.testing.expectError(
2540 error.SemanticBoundaryMismatch,
2541 world.seal(connected, &substituted),
2542 );
2543 var wrong_profile = bindings;
2544 wrong_profile[0].execution_profile = profile.kvmContinuationTestV1();
2545 try std.testing.expectError(
2546 error.ProfileMismatch,
2547 world.seal(connected, &wrong_profile),
2548 );
2549 wrong_profile[0].execution_profile = profile.interpretedReconstructV1();
2550 try std.testing.expectError(
2551 error.ContractMismatch,
2552 world.seal(connected, &wrong_profile),
2553 );
2554 }
2555
2556 fn expectCutMutationRejections(sealed: world.Cut) !void {
2557 var changed = sealed;
2558 changed.nodes[0].machine.digest[0] ^= 1;
2559 try std.testing.expectError(error.RootMismatch, world.verify(changed));
2560 changed = sealed;
2561 const first = changed.nodes[0];
2562 changed.nodes[0] = changed.nodes[1];
2563 changed.nodes[1] = first;
2564 try std.testing.expectError(error.NodesNotCanonical, world.verify(changed));
2565 changed = sealed;
2566 changed.nodes[1] = changed.nodes[0];
2567 try std.testing.expectError(error.NodesNotCanonical, world.verify(changed));
2568 changed = sealed;
2569 changed.nodes[2] = changed.nodes[0];
2570 try std.testing.expectError(error.CutInvalid, world.verify(changed));
2571 changed = sealed;
2572 changed.root.fabric.fault_frontier =
2573 changed.root.fabric.admission_frontier + 1;
2574 try std.testing.expectError(error.CutInvalid, world.verify(changed));
2575 }
2576
2577 fn expectManifestCodec(cut: world.Cut) !void {
2578 try encodeManifest(&cut);
2579 try std.testing.expectEqualSlices(u8, &.{
2580 'M', 'C', 'H', 'W', 'R', 'L', '1', 0,
2581 1, 0, 0, 4, 0, 0, 1, 0,
2582 1, 0, 3, 0, 4, 0, 128, 0,
2583 32, 0, 192, 0,
2584 }, manifest_stream[0..28]);
2585 var reader = std.Io.Reader.fixed(
2586 manifest_stream[0..world.manifest.stream_bytes],
2587 );
2588 const reopened = try world.manifest.decodeDisjoint(&reader, cut.root);
2589 try std.testing.expectEqualDeep(cut, reopened);
2590 var repeated: [world.manifest.stream_bytes]u8 = undefined;
2591 var writer = std.Io.Writer.fixed(&repeated);
2592 try world.manifest.encodeDisjoint(&reopened, &writer);
2593 try std.testing.expectEqual(world.manifest.stream_bytes, writer.end);
2594 try std.testing.expectEqualSlices(
2595 u8,
2596 manifest_stream[0..world.manifest.stream_bytes],
2597 &repeated,
2598 );
2599 try expectManifestFraming(cut);
2600 try expectManifestMutations(cut.root);
2601 }
2602
2603 fn expectManifestFraming(cut: world.Cut) !void {
2604 var short_writer = std.Io.Writer.fixed(
2605 manifest_stream[0 .. world.manifest.stream_bytes - 1],
2606 );
2607 try std.testing.expectError(
2608 error.WriteFailed,
2609 world.manifest.encodeDisjoint(&cut, &short_writer),
2610 );
2611 try expectManifestDecodeFailure(
2612 error.TruncatedStream,
2613 manifest_stream[0 .. world.manifest.stream_bytes - 1],
2614 cut.root,
2615 );
2616 manifest_stream[world.manifest.stream_bytes] = 0xa5;
2617 try expectManifestDecodeFailure(error.TrailingData, &manifest_stream, cut.root);
2618 var wrong_root = cut.root;
2619 wrong_root.digest[0] ^= 1;
2620 try expectManifestDecodeFailure(
2621 error.WorldRootMismatch,
2622 manifest_stream[0..world.manifest.stream_bytes],
2623 wrong_root,
2624 );
2625 var aliased = cut;
2626 var alias_writer = std.Io.Writer.fixed(std.mem.asBytes(&aliased));
2627 try std.testing.expectError(
2628 error.SinkAliasesCut,
2629 world.manifest.encodeDisjoint(&aliased, &alias_writer),
2630 );
2631 }
2632
2633 fn expectManifestMutations(expected_root: world.Root) !void {
2634 const mutations = [_]ManifestMutation{
2635 .{ .offset = 0, .mask = 1, .expected = error.BadMagic },
2636 .{ .offset = 8, .mask = 1, .expected = error.UnsupportedVersion },
2637 .{ .offset = 10, .mask = 1, .expected = error.StreamBytesMismatch },
2638 .{ .offset = 12, .mask = 1, .expected = error.UnsupportedFlags },
2639 .{ .offset = 14, .mask = 1, .expected = error.ManifestFormatMismatch },
2640 .{ .offset = 16, .mask = 1, .expected = error.UnknownManifestField },
2641 .{ .offset = 18, .mask = 1, .expected = error.UnknownManifestField },
2642 .{ .offset = 20, .mask = 1, .expected = error.MetadataShapeMismatch },
2643 .{ .offset = 28, .mask = 1, .expected = error.ReservedNonzero },
2644 .{ .offset = 99, .mask = 1, .expected = error.ReservedNonzero },
2645 .{ .offset = 170, .mask = 1, .expected = error.ReservedNonzero },
2646 .{ .offset = 232, .mask = 1, .expected = error.ReservedNonzero },
2647 .{ .offset = 368, .mask = 1, .expected = error.ReservedNonzero },
2648 .{ .offset = 512, .mask = 1, .expected = error.ReservedNonzero },
2649 .{ .offset = 768, .mask = 1, .expected = error.ReservedNonzero },
2650 .{ .offset = 64, .mask = 1, .expected = error.WorldRootMismatch },
2651 .{ .offset = 256, .mask = 1, .expected = error.RootMismatch },
2652 };
2653 for (mutations) |mutation| {
2654 manifest_stream[mutation.offset] ^= mutation.mask;
2655 try expectManifestDecodeFailure(
2656 mutation.expected,
2657 manifest_stream[0..world.manifest.stream_bytes],
2658 expected_root,
2659 );
2660 manifest_stream[mutation.offset] ^= mutation.mask;
2661 }
2662 try expectEveryManifestByteBound(expected_root);
2663 }
2664
2665 fn expectEveryManifestByteBound(expected_root: world.Root) !void {
2666 for (0..world.manifest.stream_bytes) |offset| {
2667 manifest_stream[offset] ^= 1;
2668 var reader = std.Io.Reader.fixed(
2669 manifest_stream[0..world.manifest.stream_bytes],
2670 );
2671 if (world.manifest.decodeDisjoint(&reader, expected_root)) |_| {
2672 manifest_stream[offset] ^= 1;
2673 return error.TestAcceptedManifestMutation;
2674 } else |_| {}
2675 manifest_stream[offset] ^= 1;
2676 }
2677 }
2678
2679 fn reopenWorldStreams(
2680 connected: *const fabric.Fabric,
2681 cut: world.Cut,
2682 first: *const checkpoint.Checkpoint,
2683 second: *const checkpoint.Checkpoint,
2684 first_storage: *checkpoint.Storage,
2685 second_storage: *checkpoint.Storage,
2686 ) !ReopenedWorld {
2687 try encodeManifest(&cut);
2688 var manifest_reader = std.Io.Reader.fixed(
2689 manifest_stream[0..world.manifest.stream_bytes],
2690 );
2691 const reopened_cut = try world.manifest.decodeDisjoint(
2692 &manifest_reader,
2693 cut.root,
2694 );
2695 try encodeFabric(connected);
2696 var fabric_reader = std.Io.Reader.fixed(&fabric_stream);
2697 const reopened_fabric = try fabric.snapshot.decodeDisjoint(
2698 &fabric_reader,
2699 reopened_cut.root.fabric,
2700 );
2701 const first_reopened = try reopenCheckpoint(
2702 first,
2703 reopened_cut.nodes[0].machine,
2704 first_storage,
2705 &first_restore_ram,
2706 );
2707 try encodeCheckpoint(second);
2708 var wrong_reader = std.Io.Reader.fixed(&checkpoint_stream);
2709 try std.testing.expectError(
2710 error.CheckpointRootMismatch,
2711 checkpoint.stream.decodeDisjoint(
2712 &wrong_reader,
2713 reopened_cut.nodes[0].machine,
2714 second_storage,
2715 &second_restore_ram,
2716 ),
2717 );
2718 var second_reader = std.Io.Reader.fixed(&checkpoint_stream);
2719 const second_reopened = try checkpoint.stream.decodeDisjoint(
2720 &second_reader,
2721 reopened_cut.nodes[1].machine,
2722 second_storage,
2723 &second_restore_ram,
2724 );
2725 return .{
2726 .cut = reopened_cut,
2727 .fabric = reopened_fabric,
2728 .checkpoints = .{ first_reopened, second_reopened },
2729 };
2730 }
2731
2732 fn restoreReopenedWorld(reopened: *ReopenedWorld) !void {
2733 var first_storage = instance.Storage.init();
2734 var second_storage = instance.Storage.init();
2735 const bindings = [_]world.RestoreBinding{
2736 restoreBinding(
2737 first_id,
2738 &reopened.checkpoints[0],
2739 restoreTarget(&first_storage, &first_live_ram, 0xe1),
2740 ),
2741 restoreBinding(
2742 second_id,
2743 &reopened.checkpoints[1],
2744 restoreTarget(&second_storage, &second_live_ram, 0xe2),
2745 ),
2746 };
2747 var restored = try requireRestored(world.restore(
2748 reopened.cut,
2749 &reopened.fabric,
2750 &bindings,
2751 ));
2752 try std.testing.expectEqualDeep(reopened.cut.root, restored.root);
2753 try std.testing.expectEqualDeep(
2754 reopened.cut.root.fabric,
2755 restored.fabric.root(),
2756 );
2757 try expectRestoredBooting(&restored.nodes[0], first_id);
2758 try expectRestoredBooting(&restored.nodes[1], second_id);
2759 restored.deinit();
2760 }
2761
2762 fn encodeManifest(value: *const world.Cut) !void {
2763 var writer = std.Io.Writer.fixed(
2764 manifest_stream[0..world.manifest.stream_bytes],
2765 );
2766 try world.manifest.encodeDisjoint(value, &writer);
2767 try std.testing.expectEqual(world.manifest.stream_bytes, writer.end);
2768 }
2769
2770 fn encodeFabric(value: *const fabric.Fabric) !void {
2771 var writer = std.Io.Writer.fixed(&fabric_stream);
2772 try fabric.snapshot.encodeDisjoint(value, &writer);
2773 try std.testing.expectEqual(fabric.snapshot.stream_bytes, writer.end);
2774 }
2775
2776 fn encodeCheckpoint(value: *const checkpoint.Checkpoint) !void {
2777 var writer = std.Io.Writer.fixed(&checkpoint_stream);
2778 try checkpoint.stream.encodeDisjoint(value, &writer);
2779 try std.testing.expectEqual(checkpoint.stream.stream_bytes, writer.end);
2780 }
2781
2782 fn encodeTransition(
2783 before: *const fabric.Fabric,
2784 value: *const fabric.Transition,
2785 output: *[fabric.transition.stream_bytes]u8,
2786 ) !void {
2787 var writer = std.Io.Writer.fixed(output);
2788 try fabric.transition.encodeDisjoint(before, value, &writer);
2789 try std.testing.expectEqual(fabric.transition.stream_bytes, writer.end);
2790 }
2791
2792 fn reopenCheckpoint(
2793 source: *const checkpoint.Checkpoint,
2794 expected: checkpoint.Root,
2795 storage: *checkpoint.Storage,
2796 ram: []align(checkpoint.ram_alignment) u8,
2797 ) !checkpoint.Checkpoint {
2798 try encodeCheckpoint(source);
2799 var reader = std.Io.Reader.fixed(&checkpoint_stream);
2800 return checkpoint.stream.decodeDisjoint(&reader, expected, storage, ram);
2801 }
2802
2803 fn expectManifestDecodeFailure(
2804 expected: anyerror,
2805 bytes: []const u8,
2806 root: world.Root,
2807 ) !void {
2808 var reader = std.Io.Reader.fixed(bytes);
2809 try std.testing.expectError(
2810 expected,
2811 world.manifest.decodeDisjoint(&reader, root),
2812 );
2813 }
2814
2815 fn binding(
2816 node: fabric.NodeId,
2817 machine: *const instance.Instance,
2818 value: *const checkpoint.Checkpoint,
2819 ) world.Binding {
2820 return .{
2821 .node = node,
2822 .execution_profile = profile.interpretedContinuationTestV1(),
2823 .checkpoint = .{ .durable = value },
2824 .source = .{ .live = machine },
2825 };
2826 }
2827
2828 fn start(
2829 storage: *instance.Storage,
2830 ram: []align(instance.ram_alignment) u8,
2831 input: instance.Input,
2832 ) !instance.Instance {
2833 var machine = switch (instance.Instance.init(storage, ram, input)) {
2834 .ready => |value| value,
2835 .unavailable => return error.UnexpectedBackendUnavailable,
2836 .rejected => |failure| return failure,
2837 };
2838 try activate(&machine);
2839 return machine;
2840 }
2841
2842 fn activate(machine: *instance.Instance) !void {
2843 try std.testing.expectEqualDeep(
2844 instance.Exit{ .doorbell = .{ .code = .ready } },
2845 try machine.run(),
2846 );
2847 var events: instance.EventBatch = undefined;
2848 try machine.takeEvents(&events);
2849 }
2850
2851 fn completeTurn(
2852 machine: *instance.Instance,
2853 delivery: admission.Delivery,
2854 ) !instance.QuiescenceReceipt {
2855 try machine.deliverAdmitted(&delivery);
2856 try std.testing.expectEqualDeep(
2857 instance.Exit{ .doorbell = .{ .code = .quiescent } },
2858 try machine.run(),
2859 );
2860 var events: instance.EventBatch = undefined;
2861 try machine.takeEvents(&events);
2862 try machine.acknowledge(delivery.receipt);
2863 return machine.quiescenceReceipt();
2864 }
2865
2866 fn machineInput(
2867 execution: os.boot.kernel.manifest.View,
2868 fence: os.abi.ActivationFence,
2869 root_byte: u8,
2870 ) instance.Input {
2871 return .{
2872 .profile = profile.interpretedContinuationTestV1(),
2873 .elf = k0_elf,
2874 .execution_manifest = k0_manifest,
2875 .expected_execution_fingerprint = execution.header.fingerprint,
2876 .fence = fence,
2877 .initial_time_tick = 7,
2878 .entropy_generation = 1,
2879 .terminal_offset = 0,
2880 .effect_frontier = 0,
2881 .block_root = @splat(root_byte),
2882 .source_root = @splat(root_byte + 1),
2883 .input_frontier = 0,
2884 .terminal_input_offset = 0,
2885 .outstanding_effect = null,
2886 };
2887 }
2888
2889 fn activationFence(token: u8) os.abi.ActivationFence {
2890 return activationFenceAt(token, 1);
2891 }
2892
2893 fn activationFenceAt(token: u8, generation: u64) os.abi.ActivationFence {
2894 return .{ .world = world_id, .generation = generation, .token = @splat(token) };
2895 }
2896
2897 fn expectRootHex(root: world.Root, expected: []const u8) !void {
2898 const actual = std.fmt.bytesToHex(root.digest, .lower);
2899 try std.testing.expectEqualStrings(expected, &actual);
2900 }