lib/machine/src/world/owner.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const canon = @import("canon.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 types = @import("types.zig");
 9 
10 const SealError = error{
11     MachineBoundaryUnavailable,
12     MachineSourceMismatch,
13     NodeCountMismatch,
14     NodeMismatch,
15     ProfileMismatch,
16     SemanticBoundaryMismatch,
17 };
18 
19 pub const Error = canon.Error ||
20     checkpoint.Error ||
21     fabric.Error ||
22     instance.QuiescenceReceiptError ||
23     profile.Error ||
24     SealError;
25 
26 /// Proves that the caller's checkpoints sit at the semantic boundaries the ledger
27 /// currently holds, then joins them into a single cut so a caller can store the
28 /// boundary now and restore it later. A live binding has to carry the semantic digest
29 /// that its instance's quiescence receipt carries. A retained binding has to name
30 /// a node that the ledger already marks unavailable. The ledger's machine contract
31 /// has to appear in every binding. The binding count must equal the ledger's node
32 /// count, and each binding must name the ledger's node at the same index. Each binding's
33 /// profile fingerprint must equal the one recorded in its checkpoint root.
34 pub fn seal(
35     fabric_owner: *const fabric.Fabric,
36     bindings: []const types.Binding,
37 ) Error!types.Cut {
38     const fabric_cut = try fabric_owner.cut();
39     if (bindings.len != fabric_cut.node_count) {
40         return error.NodeCountMismatch;
41     }
42     var nodes: [types.node_limit]types.Node = @splat(canon.emptyNode());
43     for (bindings, 0..) |binding, index| {
44         const boundary = fabric_cut.nodes[index];
45         if (!std.meta.eql(binding.node, boundary.id)) {
46             return error.NodeMismatch;
47         }
48         if (boundary.machine.kind != .semantic) {
49             return error.MachineBoundaryUnavailable;
50         }
51         const live_semantic: ?os.abi.Digest = switch (binding.source) {
52             .live => |machine| live: {
53                 if (!boundary.available) return error.MachineSourceMismatch;
54                 const receipt = try machine.quiescenceReceipt();
55                 const semantic = try instance.projectSemanticReceipt(receipt);
56                 break :live try instance.semanticReceiptDigest(semantic);
57             },
58             .retained => retained: {
59                 if (boundary.available) return error.MachineSourceMismatch;
60                 break :retained null;
61             },
62         };
63         try profile.validate(binding.execution_profile);
64         const contract = try profile.contractFingerprint(binding.execution_profile);
65         if (!std.meta.eql(contract, fabric_cut.root.machine_contract)) {
66             return error.ContractMismatch;
67         }
68         const identity = try binding.checkpoint.identity();
69         const profile_fingerprint = try profile.profileFingerprint(
70             binding.execution_profile,
71         );
72         if (!std.meta.eql(profile_fingerprint, identity.root.profile)) {
73             return error.ProfileMismatch;
74         }
75         if (!std.mem.eql(
76             u8,
77             &identity.semantic,
78             &boundary.machine.digest,
79         )) {
80             return error.SemanticBoundaryMismatch;
81         }
82         if (live_semantic) |semantic| {
83             if (!std.mem.eql(u8, &semantic, &identity.semantic)) {
84                 return error.SemanticBoundaryMismatch;
85             }
86         }
87         nodes[index] = .{ .id = binding.node, .machine = identity.root };
88     }
89     return canon.prepare(
90         fabric_cut.root,
91         nodes[0..fabric_cut.node_count],
92     );
93 }
94 
95 /// Hashes a cut's material again and refuses the cut when the result differs from
96 /// the stored root. A node slot holding no node carries the empty padding value.
97 /// The cut's own contract must equal the contract its ledger root carries.
98 pub const verify = canon.verify;