tiny.machine.world
Defined in tiny.machine.
Machines that talk to each other advance separately, so stopping them all at one instant, storing that instant, and bringing it back later takes a definition of what one instant is, and this namespace supplies it.
API (62)
Actions
Public operations.
PrefixProgress.eventBatches: The accessor returns each applied turn's event batch, kept in application order, so a caller reads the guest's output for the whole plan.PrefixProgress.eventSteps: The accessor returns each applied turn's step index, kept in application order, so a caller pairs event batches with their steps.Restored.currentMoment: Checks a stored moment against both the origin and the position the ledger holds, then hands it back.Restored.deinitactivate: Brings one restored node up and carries it as far as its ready point, so a caller activates a node once after restore, before it can take turns.applyFault: Applies one fault input to a candidate ledger, then commits that ledger and the moment together.prepareMoment: Produces the moment that belongs to a given origin world root and current ledger root, so a caller records where the world now stands after every ledger change.replayFault: Reads one recorded fault transition back from its wire bytes so a caller proves the recording reproduces the same ledger position, and demands that the replay land on the root the record declares.replayPrefix: Replays a plan of recorded steps on a restored world, bounded in length, beginning at a verified start and finishing at the declared end, so a caller replays a stretch of recorded history in one call with the plan proved consistent before the guest runs at all.replayTurn: Runs one recorded turn again on a restored world so a caller proves the recording and the guest still agree.restore: Brings a world back from a sealed cut so a caller brings a stored boundary back as running machines.seal: Proves that the caller's checkpoints sit at the semantic boundaries the ledger currently holds, then joins them into a single cut so a caller can store the boundary now and restore it later.terminal: Carries one connected terminal turn from end to end, so a caller feeds one node input and lets the guest settle it: the call admits the bytes into a candidate ledger, hands them to the node, runs the guest until it quiesces, checks the events it produced against the quiescence receipt and the fence, settles the ledg…verify: Hashes a cut's material again and refuses the cut when the result differs from the stored root.verifyMoment: Derives the moment the material should yield and refuses a value that has drifted from it, so a reader who holds a stored moment proves it belongs to this origin and this position.
Types and contracts
Public types and contracts.
Binding: The binding holds whatsealneeds from one node: its identity, its profile, the checkpoint it seals from, and the authority proving it live or retained.Cut: A cut is a boundary complete enough to restore from, made of one root and the checkpoint root of each node.Dialect: The encoding version names the version number a world root is written under, and a reader rejects a root written under a version it does not speak.ErrorFaultApplied: The record left behind by an applied fault: the ledger transition holding its record, the decision that was taken, and the moment the world reaches afterwards.FaultErrorFaultRejection: A named failure carrying the node involved whenever the code can name one.FaultResult: The fault outcome.LiveActivateResult: The activation outcome, so a caller switches on this to decide whether the world can keep going.LiveActivated: What an activation yields: the node now awake and every event it emitted on the way to its ready point.LiveAdvanced: What a settled turn yields: two ledger transitions record the admission and the settlement, a moment marks where the world stands once both are in, the guest events travel with them, and a quiescence receipt shows that the guest came to its cooperative stop.LiveErrorLiveRejection: A named failure, carrying the node involved whenever the code can name one.LiveTurnResult: The outcome of a turn obeys the contractActivateResultobeys, so a caller switches on this the same way it switches on an activation outcome.Moment: A place in one world's history, fixed by the origin cut it started from together with the ledger root it stands at now.MomentDialect: The encoding version for moments.MomentErrorNode: A node once sealed is named by its identity and by the checkpoint root of its machine.PrefixErrorPrefixFault: A step that replays a fault, holding the recorded transition together with the root and the moment the replay has to land on, so a caller builds one for every recorded fault in a plan.PrefixInput: A plan for replaying a prefix, holding a start moment already verified, no more thanstep_limitrecorded steps, and the end moment it declares, so a caller hands one toreplayPrefix.PrefixProgress: The running total of a prefix replay, counting steps and turns applied, naming the moment reached, and keeping each applied turn's step index and event batch, so a caller reads this to see how far a replay got and what the guest said along the way.PrefixResult: The prefix outcome, so a caller switches on this to learn whether the plan proved what it claimed.PrefixStepPrefixStopped: The record of a halted prefix, holding the progress reached, the step that failed, the failure itself, and the node involved whenever the code can name one, so a caller reads this to learn exactly where a plan stopped and why.PrefixTurn: A step that replays a turn, holding the recorded input and the moment the replay has to land on, so a caller builds one for every recorded turn in a plan.ReplayAdvanced: The yield of a replayed turn, namely the pair of ledger transitions, the moment reached once both are in, and the guest events.ReplayErrorReplayFrame: A recorded transition offered for replay, holding a reader over its wire bytes and the ledger root the replay has to reproduce.ReplayInput: A recorded turn, holding the frame for the admission, the frame for the settlement, and the activation fence the delivery was bound to.ReplayRejection: A named failure, carrying the node involved whenever the code can name one.ReplayResult: The outcome of a replay, which obeys the contract a live turn obeys.RestoreBinding: What one node brings to a restore: its identity, the checkpoint it restores from, and its mode.RestoreErrorRestoreMode: The form a node takes when it comes back.RestoreRejection: A named failure, carrying the node involved whenever the code can name one, so a caller reads the value to learn which node a failure concerns.RestoreResult: The restore outcome, switched on by a caller so the caller takes ownership of the live machines in exactly one arm.RestoreTarget: What restoring one live node requires: the activation fence, the K0 execution manifest, the execution profile, instance storage, and aligned guest RAM.RestoreUnavailable: A node whose backend is missing on this host, together with the reason that backend gives, so a caller tells a host that lacks the backend apart from a world that failed to check out.Restored: A world rebuilt out of a cut, holding the origin root, the ledger the caller supplied, the moment it stands at, and an entry for every node.RestoredNode: A node after restore, naming itself and carrying a live instance if live was the mode asked for.Root: A world root is one world state folded into a single digest, covering the contract that binds every node, the ledger root, and the node count.Source: The union names the origin of one node's sealed state.
Namespaces
Public namespaces.
Values and defaults
Public values and defaults.
determinism_sourcesnode_limitprefix_step_limit: The maximum number of steps one prefix replays, for a caller sizing its plan before calling.
Source
Source: lib/machine/src/world/fault.zig:26
/// The record left behind by an applied fault: the ledger transition holding its/// record, the decision that was taken, and the moment the world reaches afterwards./// A caller reads this to see what the fault did to the ledger and where the world/// now stands.pub const Applied = struct { transition: fabric.Transition, decision: fault.Decision, moment: moment.Moment,};Source: lib/machine/src/world/fault.zig:34
/// A named failure carrying the node involved whenever the code can name one. A/// caller reads this to learn which node the failure concerns.pub const Rejection = struct { node: ?fabric.NodeId, failure: Error,};Source: lib/machine/src/world/fault.zig:41
/// The fault outcome. A world that rejected the call still holds the state it had/// before and stays usable.pub const Result = union(enum) { applied: Applied, rejected: Rejection,};Source: lib/machine/src/world/live.zig:59
/// The activation outcome, so a caller switches on this to decide whether the world/// can keep going. A world that rejected the call still holds the state it had before/// and stays usable. A world marked invalid failed once mutation was already under/// way, so its live instances were destroyed and it cannot continue.pub const ActivateResult = union(enum) { activated: Activated, rejected: Rejection, invalidated: Rejection,};Source: lib/machine/src/world/live.zig:31
/// What an activation yields: the node now awake and every event it emitted on the/// way to its ready point. A caller reads this to see which node woke and what it/// said on the way up.pub const Activated = struct { node: fabric.NodeId, events: instance.EventBatch,};Source: lib/machine/src/world/live.zig:41
/// What a settled turn yields: two ledger transitions record the admission and the/// settlement, a moment marks where the world stands once both are in, the guest/// events travel with them, and a quiescence receipt shows that the guest came to/// its cooperative stop. A caller reads this to see everything one settled turn/// produced.pub const Advanced = struct { admission: fabric.Transition, settlement: fabric.Transition, moment: moment.Moment, events: instance.EventBatch, receipt: instance.QuiescenceReceipt,};Source: lib/machine/src/world/live.zig:50
/// A named failure, carrying the node involved whenever the code can name one.pub const Rejection = struct { node: ?fabric.NodeId, failure: Error,};Source: lib/machine/src/world/live.zig:68
/// The outcome of a turn obeys the contract `ActivateResult` obeys, so a caller/// switches on this the same way it switches on an activation outcome. Rejected/// worlds continue, and invalidated worlds are gone.pub const TurnResult = union(enum) { advanced: Advanced, rejected: Rejection, invalidated: Rejection,};Source: lib/machine/src/world/moment.zig:12
/// The encoding version for moments. A reader checks this version before trusting/// a stored moment, and rejects a moment written under a version it does not speak./// One version exists today: `stable_world_v1`.pub const Dialect = enum(u16) { stable_world_v1 = 1,};Source: lib/machine/src/world/moment.zig:29
pub const Error = error{ ContractMismatch, FabricFrontierRegression, InvalidFabricRoot, InvalidWorldRoot, MomentMismatch,};Source: lib/machine/src/world/moment.zig:22
/// A place in one world's history, fixed by the origin cut it started from together/// with the ledger root it stands at now. A caller compares moments to know whether/// two worlds stand at the same place in the same history. Two moments match when/// both the origin and the position match, and the digest covers the pair, so two/// worlds that reached the same ledger position from different origins produce different/// moments.pub const Moment = struct { digest: os.abi.Digest, dialect: Dialect, origin: types.Root, fabric: fabric.Root,};Source: lib/machine/src/world/prefix.zig:40
/// A step that replays a fault, holding the recorded transition together with the/// root and the moment the replay has to land on, so a caller builds one for every/// recorded fault in a plan.pub const Fault = struct { reader: *std.Io.Reader, expected_root: fabric.Root, expected_moment: moment.Moment,};Source: lib/machine/src/world/prefix.zig:54
/// A plan for replaying a prefix, holding a start moment already verified, no more/// than `step_limit` recorded steps, and the end moment it declares, so a caller/// hands one to `replayPrefix`.pub const Input = struct { start: moment.Moment, steps: []const Step, end: moment.Moment,};Source: lib/machine/src/world/prefix.zig:66
/// The running total of a prefix replay, counting steps and turns applied, naming/// the moment reached, and keeping each applied turn's step index and event batch,/// so a caller reads this to see how far a replay got and what the guest said along/// the way./// The event arrays are fixed at the step limit, and only the first `turn_count`/// entries of each are populated.pub const Progress = struct { step_count: u8, turn_count: u8, moment: moment.Moment, turn_steps: [step_limit]u8, turn_events: [step_limit]instance.EventBatch, /// The accessor returns each applied turn's step index, kept in application /// order, so a caller pairs event batches with their steps. pub fn eventSteps(self: *const @This()) []const u8 { std.debug.assert(self.turn_count <= self.turn_steps.len); return self.turn_steps[0..self.turn_count]; } /// The accessor returns each applied turn's event batch, kept in application /// order, so a caller reads the guest's output for the whole plan. pub fn eventBatches(self: *const @This()) []const instance.EventBatch { std.debug.assert(self.turn_count <= self.turn_events.len); return self.turn_events[0..self.turn_count]; }};Source: lib/machine/src/world/prefix.zig:102
/// The prefix outcome, so a caller switches on this to learn whether the plan proved/// what it claimed./// `reached` establishes that the replay finished on the end moment the plan declared./// Rejected worlds continue, and invalidated worlds are gone.pub const Result = union(enum) { reached: Progress, rejected: Stopped, invalidated: Stopped,};Source: lib/machine/src/world/prefix.zig:46
Source: lib/machine/src/world/prefix.zig:91
/// The record of a halted prefix, holding the progress reached, the step that failed,/// the failure itself, and the node involved whenever the code can name one, so/// a caller reads this to learn exactly where a plan stopped and why.pub const Stopped = struct { progress: ?Progress, step: u8, node: ?fabric.NodeId, failure: Error,};Source: lib/machine/src/world/prefix.zig:32
/// A step that replays a turn, holding the recorded input and the moment the replay/// has to land on, so a caller builds one for every recorded turn in a plan.pub const Turn = struct { replay: replay_owner.Input, expected_moment: moment.Moment,};Source: lib/machine/src/world/replay.zig:54
/// The yield of a replayed turn, namely the pair of ledger transitions, the moment/// reached once both are in, and the guest events. A caller reads this to see what/// the replayed turn produced.pub const Advanced = struct { admission: fabric.Transition, settlement: fabric.Transition, moment: moment.Moment, events: instance.EventBatch,};Source: lib/machine/src/world/replay.zig:37
/// A recorded transition offered for replay, holding a reader over its wire bytes/// and the ledger root the replay has to reproduce. A caller pairs each recorded/// transition with the root it is supposed to reproduce.pub const Frame = struct { reader: *std.Io.Reader, expected_root: fabric.Root,};Source: lib/machine/src/world/replay.zig:45
/// A recorded turn, holding the frame for the admission, the frame for the settlement,/// and the activation fence the delivery was bound to. A caller assembles one of/// these per recorded turn.pub const Input = struct { admission: Frame, settlement: Frame, fence: os.abi.ActivationFence,};Source: lib/machine/src/world/replay.zig:63
/// A named failure, carrying the node involved whenever the code can name one. A/// caller reads this to learn which node a failure concerns.pub const Rejection = struct { node: ?fabric.NodeId, failure: Error,};Source: lib/machine/src/world/replay.zig:71
/// The outcome of a replay, which obeys the contract a live turn obeys. A caller/// switches on this exactly as it does for a live turn. Rejected worlds continue,/// and invalidated worlds are gone.pub const Result = union(enum) { advanced: Advanced, rejected: Rejection, invalidated: Rejection,};Source: lib/machine/src/world/restore.zig:58
/// What one node brings to a restore: its identity, the checkpoint it restores from,/// and its mode. A caller builds one of these per node and hands the array to `restore`.pub const Binding = struct { node: fabric.NodeId, checkpoint: checkpoint.Source, mode: Mode,};Source: lib/machine/src/world/restore.zig:51
/// The form a node takes when it comes back. A caller sets this per node to say/// whether that node comes back running. Live rebuilds an instance from caller storage,/// and retained constructs no instance.pub const Mode = union(enum) { live: Target, retained,};Source: lib/machine/src/world/restore.zig:67
/// A node after restore, naming itself and carrying a live instance if live was/// the mode asked for. A caller reaches through these to drive one machine of a/// restored world.pub const Node = struct { id: fabric.NodeId, machine: ?instance.Instance,};Source: lib/machine/src/world/restore.zig:109
/// A named failure, carrying the node involved whenever the code can name one, so/// a caller reads the value to learn which node a failure concerns.pub const Rejection = struct { node: ?fabric.NodeId, failure: Error,};Source: lib/machine/src/world/restore.zig:76
/// A world rebuilt out of a cut, holding the origin root, the ledger the caller/// supplied, the moment it stands at, and an entry for every node. Every turn owner/// takes this value to own the live machines. Turn owners mutate a restored world/// in place. `deinit` tears down every live instance and clears each entry.pub const Restored = struct { root: types.Root, fabric: *fabric.Fabric, moment: moment.Moment, node_count: u8, nodes: [types.node_limit]Node, /// Checks a stored moment against both the origin and the position the ledger /// holds, then hands it back. A caller reads the world's position through this, /// because the read verifies before it returns. pub fn currentMoment(self: *const @This()) moment.Error!moment.Moment { try moment.verify(self.moment, self.root, self.fabric.root()); return self.moment; } pub fn deinit(self: *@This()) void { for (&self.nodes) |*node| { if (node.machine) |*machine| machine.deinit(); node.machine = null; } }};Source: lib/machine/src/world/restore.zig:119
/// The restore outcome, switched on by a caller so the caller takes ownership of/// the live machines in exactly one arm. Ownership of the live instances passes/// to the caller under `ready` and under no other outcome. The other two arms leave/// nothing constructed, because construction tears down what it built before returning/// them.pub const Result = union(enum) { ready: Restored, unavailable: Unavailable, rejected: Rejection,};Source: lib/machine/src/world/restore.zig:40
/// What restoring one live node requires: the activation fence, the K0 execution/// manifest, the execution profile, instance storage, and aligned guest RAM. A caller/// fills one of these in for every node it wants running again. The caller owns/// the storage and the RAM, and both are borrowed for the life of the instance.pub const Target = struct { profile: profile.Profile, execution_manifest: []const u8, fence: os.abi.ActivationFence, storage: *instance.Storage, ram: []align(instance.ram_alignment) u8,};Source: lib/machine/src/world/restore.zig:102
/// A node whose backend is missing on this host, together with the reason that backend/// gives, so a caller tells a host that lacks the backend apart from a world that/// failed to check out.pub const Unavailable = struct { node: fabric.NodeId, backend: instance.Unavailable,};Source: lib/machine/src/world/types.zig:33
/// The binding holds what `seal` needs from one node: its identity, its profile,/// the checkpoint it seals from, and the authority proving it live or retained./// A caller builds one binding per node and hands the array to `seal`.pub const Binding = struct { node: fabric.NodeId, execution_profile: profile.Profile, checkpoint: checkpoint.Source, source: Source,};Source: lib/machine/src/world/types.zig:64
/// A cut is a boundary complete enough to restore from, made of one root and the/// checkpoint root of each node. A caller stores one cut as the boundary it can/// come back to. A cut carries no live state. The node array is fixed at the node/// limit, and every slot past the node count holds the padding value.pub const Cut = struct { root: Root, nodes: [node_limit]Node,};Source: lib/machine/src/world/types.zig:16
/// The encoding version names the version number a world root is written under,/// and a reader rejects a root written under a version it does not speak. A reader/// checks this value before trusting a stored world root. One version exists today,/// `connected_world_v1`.pub const Dialect = enum(u16) { connected_world_v1 = 1,};Source: lib/machine/src/world/types.zig:42
/// A node once sealed is named by its identity and by the checkpoint root of its/// machine. A caller reads these nodes out of a cut to know what each node was holding.pub const Node = struct { id: fabric.NodeId, machine: checkpoint.Root,};Source: lib/machine/src/world/types.zig:52
/// A world root is one world state folded into a single digest, covering the contract/// that binds every node, the ledger root, and the node count. A caller compares/// this digest to know whether two worlds are at the same state. The digest commits/// the encoding version, the contract, the whole ledger root, and every node in/// order.pub const Root = struct { digest: os.abi.Digest, dialect: Dialect, machine_contract: profile.ContractFingerprint, fabric: fabric.Root, node_count: u8,};Source: lib/machine/src/world/types.zig:25
/// The union names the origin of one node's sealed state. A caller sets this per/// node to say whether a live instance stands behind the checkpoint it is sealing./// A live source carries the instance, whose current receipt must agree with the/// checkpoint. A retained source carries no instance, and the ledger must already/// mark that node unavailable.pub const Source = union(enum) { live: *const instance.Instance, retained,};Source: lib/machine/src/world/canon.zig:45
/// Hashes a cut's material again and refuses the cut when the result differs from/// the stored root. A node slot holding no node carries the empty padding value./// The cut's own contract must equal the contract its ledger root carries.pub fn verify(cut: types.Cut) Error!void { const count = cut.root.node_count; if (count == 0 or count > types.node_limit) { return error.NodeCountMismatch; } for (cut.nodes[count..]) |node| { if (!std.meta.eql(node, emptyNode())) return error.CutInvalid; } const nodes = cut.nodes[0..count]; try validateMaterial(cut.root.fabric, nodes); if (cut.root.dialect != .connected_world_v1 or !std.meta.eql( cut.root.machine_contract, cut.root.fabric.machine_contract, )) { return error.CutInvalid; } const expected = rootFor(cut.root.fabric, nodes); if (!std.meta.eql(expected, cut.root)) return error.RootMismatch;}Source: lib/machine/src/world/fault.zig:16
pub const Error = fabric.Error || fabric.transition.Error || restore.StableError || source.Error || FaultOwnerError;Source: lib/machine/src/world/fault.zig:57
/// Applies one fault input to a candidate ledger, then commits that ledger and the/// moment together. Injecting a machine crash destroys the live instance on that/// node and marks the node unavailable. A process fault requires a provider that/// this owner never holds, so the call rejects it. The candidate's node set must/// match the restored world's, node for node, before it commits.pub fn applyFault( restored: *restore.Restored, input: fabric.FaultInput,) Result { validateCapabilities(restored) catch |failure| return reject(null, failure); if (std.meta.activeTag(input.effect) == .process_crash) { return reject( input.effect.process_crash.node, error.ProcessFaultProviderUnavailable, ); } var candidate = restored.fabric.*; const faulted = candidate.applyFault(input) catch |failure| return reject(faultNode(input.effect), failure); return commit( restored, candidate, .{ .entry = faulted.entry, .root = faulted.root }, );}Source: lib/machine/src/world/fault.zig:84
/// Reads one recorded fault transition back from its wire bytes so a caller proves/// the recording reproduces the same ledger position, and demands that the replay/// land on the root the record declares. The reader is checked against the world's/// live memory before anything is read. The call accepts a fault entry alone, and/// it rejects a recorded process crash. The call commits exactly like `applyFault`.pub fn replayFault( restored: *restore.Restored, reader: *std.Io.Reader, expected_root: fabric.Root,) Result { source.validate(restored, &.{reader}) catch |failure| return reject(null, failure); validateCapabilities(restored) catch |failure| return reject(null, failure); var candidate = restored.fabric.*; const transition = fabric.transition.replayDisjoint( &candidate, reader, expected_root, ) catch |failure| return reject(null, failure); const entry = switch (transition.entry.value) { .fault => |value| value, else => return reject(null, error.FaultTransitionExpected), }; if (std.meta.activeTag(entry.effect) == .process_crash) { return reject( entry.effect.process_crash.node, error.ProcessFaultProviderUnavailable, ); } return commit(restored, candidate, transition);}Source: lib/machine/src/world/live.zig:15
pub const Error = fabric.Error || instance.AcknowledgeError || instance.DeliveryError || instance.EventBatchError || instance.EventError || instance.QuiescenceReceiptError || instance.ReactivateError || instance.RunError || moment.Error || os.abi.wire.FenceError || restore.StableError || LiveOwnerError;Source: lib/machine/src/world/live.zig:81
/// Brings one restored node up and carries it as far as its ready point, so a caller/// activates a node once after restore, before it can take turns. The fence carries/// the authority for this activation, so a machine waiting to be reactivated takes/// the fence as its own, and the batch of events it emits has to verify under that/// same fence. The call demands a stable world, and the node's machine has to be/// either booting or waiting to be reactivated. An exit other than a ready doorbell/// invalidates the world.pub fn activate( restored: *restore.Restored, node: fabric.NodeId, fence: os.abi.ActivationFence,) ActivateResult { _ = restore.validateStable(restored) catch |failure| return activationReject(node, failure); os.abi.wire.validateFence(fence) catch |failure| return activationReject(node, failure); const machine = findMachine(restored, node) orelse return activationReject(node, error.MachineNodeUnavailable); switch (machine.phase()) { .booting => {}, .awaiting_reactivation => machine.reactivate(fence) catch |failure| return activationInvalidate(restored, node, failure), else => return activationReject(node, error.MachinePhaseMismatch), } const exit_value = machine.run() catch |failure| return activationInvalidate(restored, node, failure); if (!std.meta.eql( exit_value, instance.Exit{ .doorbell = .{ .code = .ready } }, )) { return activationInvalidate( restored, node, error.ActivationExitMismatch, ); } var events: instance.EventBatch = undefined; machine.takeEvents(&events) catch |failure| return activationInvalidate(restored, node, failure); instance.verifyEventBatch(&events, fence) catch |failure| return activationInvalidate(restored, node, failure); return .{ .activated = .{ .node = node, .events = events } };}Source: lib/machine/src/world/live.zig:126
/// Carries one connected terminal turn from end to end, so a caller feeds one node/// input and lets the guest settle it: the call admits the bytes into a candidate/// ledger, hands them to the node, runs the guest until it quiesces, checks the/// events it produced against the quiescence receipt and the fence, settles the/// ledger, and moves the moment forward. The call commits the candidate ledger once/// every check has passed. The call requires a stable world, a valid fence, and/// a node awaiting input. A failure before delivery rejects, and a failure from/// delivery onward invalidates.pub fn terminal( restored: *restore.Restored, node: fabric.NodeId, fence: os.abi.ActivationFence, bytes: []const u8,) TurnResult { _ = restore.validateStable(restored) catch |failure| return turnReject(node, failure); os.abi.wire.validateFence(fence) catch |failure| return turnReject(node, failure); const machine = findMachine(restored, node) orelse return turnReject(node, error.MachineNodeUnavailable); if (machine.phase() != .awaiting_input) { return turnReject(node, error.MachinePhaseMismatch); } var candidate = restored.fabric.*; const admitted = candidate.terminal( node, machine, fence, bytes, ) catch |failure| return turnReject(node, failure); machine.deliverAdmitted(&admitted.delivery) catch |failure| return turnInvalidate(restored, node, failure); const exit_value = machine.run() catch |failure| return turnInvalidate(restored, node, failure); if (!std.meta.eql( exit_value, instance.Exit{ .doorbell = .{ .code = .quiescent } }, )) { return turnInvalidate( restored, node, error.QuiescenceExitMismatch, ); } var events: instance.EventBatch = undefined; machine.takeEvents(&events) catch |failure| return turnInvalidate(restored, node, failure); machine.acknowledge(admitted.delivery.receipt) catch |failure| return turnInvalidate(restored, node, failure); const receipt = machine.quiescenceReceipt() catch |failure| return turnInvalidate(restored, node, failure); instance.verifyEventBatchReceipt( &events, receipt, fence, ) catch |failure| return turnInvalidate(restored, node, failure); const settled = candidate.settle(node, receipt) catch |failure| return turnInvalidate(restored, node, failure); const next_moment = moment.prepare( restored.root, candidate.root(), ) catch |failure| return turnInvalidate(restored, node, failure); restored.fabric.* = candidate; restored.moment = next_moment; return .{ .advanced = .{ .admission = .{ .entry = admitted.entry, .root = admitted.root }, .settlement = .{ .entry = settled.entry, .root = settled.root }, .moment = next_moment, .events = events, .receipt = receipt, } };}Source: lib/machine/src/world/moment.zig:42
/// Produces the moment that belongs to a given origin world root and current ledger/// root, so a caller records where the world now stands after every ledger change./// A contract mismatch between the origin and the current position rejects. Any/// ledger counter that moved backward relative to the origin rejects: the entry,/// admission, and fault frontiers are each checked.pub fn prepare(origin: types.Root, current: fabric.Root) Error!Moment { try validateMaterial(origin, current); return rootFor(origin, current);}Source: lib/machine/src/world/moment.zig:50
/// Derives the moment the material should yield and refuses a value that has drifted/// from it, so a reader who holds a stored moment proves it belongs to this origin/// and this position. The comparison covers every field, digest included.pub fn verify( value: Moment, origin: types.Root, current: fabric.Root,) Error!void { const expected = try prepare(origin, current); if (!std.meta.eql(value, expected)) return error.MomentMismatch;}Source: lib/machine/src/world/owner.zig:19
pub const Error = canon.Error || checkpoint.Error || fabric.Error || instance.QuiescenceReceiptError || profile.Error || SealError;Source: lib/machine/src/world/owner.zig:34
/// Proves that the caller's checkpoints sit at the semantic boundaries the ledger/// currently holds, then joins them into a single cut so a caller can store the/// boundary now and restore it later. A live binding has to carry the semantic digest/// that its instance's quiescence receipt carries. A retained binding has to name/// a node that the ledger already marks unavailable. The ledger's machine contract/// has to appear in every binding. The binding count must equal the ledger's node/// count, and each binding must name the ledger's node at the same index. Each binding's/// profile fingerprint must equal the one recorded in its checkpoint root.pub fn seal( fabric_owner: *const fabric.Fabric, bindings: []const types.Binding,) Error!types.Cut { const fabric_cut = try fabric_owner.cut(); if (bindings.len != fabric_cut.node_count) { return error.NodeCountMismatch; } var nodes: [types.node_limit]types.Node = @splat(canon.emptyNode()); for (bindings, 0..) |binding, index| { const boundary = fabric_cut.nodes[index]; if (!std.meta.eql(binding.node, boundary.id)) { return error.NodeMismatch; } if (boundary.machine.kind != .semantic) { return error.MachineBoundaryUnavailable; } const live_semantic: ?os.abi.Digest = switch (binding.source) { .live => |machine| live: { if (!boundary.available) return error.MachineSourceMismatch; const receipt = try machine.quiescenceReceipt(); const semantic = try instance.projectSemanticReceipt(receipt); break :live try instance.semanticReceiptDigest(semantic); }, .retained => retained: { if (boundary.available) return error.MachineSourceMismatch; break :retained null; }, }; try profile.validate(binding.execution_profile); const contract = try profile.contractFingerprint(binding.execution_profile); if (!std.meta.eql(contract, fabric_cut.root.machine_contract)) { return error.ContractMismatch; } const identity = try binding.checkpoint.identity(); const profile_fingerprint = try profile.profileFingerprint( binding.execution_profile, ); if (!std.meta.eql(profile_fingerprint, identity.root.profile)) { return error.ProfileMismatch; } if (!std.mem.eql( u8, &identity.semantic, &boundary.machine.digest, )) { return error.SemanticBoundaryMismatch; } if (live_semantic) |semantic| { if (!std.mem.eql(u8, &semantic, &identity.semantic)) { return error.SemanticBoundaryMismatch; } } nodes[index] = .{ .id = binding.node, .machine = identity.root }; } return canon.prepare( fabric_cut.root, nodes[0..fabric_cut.node_count], );}Source: lib/machine/src/world/prefix.zig:23
pub const Error = fault_owner.Error || moment.Error || replay_owner.Error || restore.StableError || source.Error || PrefixOwnerError;Source: lib/machine/src/world/prefix.zig:120
/// Replays a plan of recorded steps on a restored world, bounded in length, beginning/// at a verified start and finishing at the declared end, so a caller replays a/// stretch of recorded history in one call with the plan proved consistent before/// the guest runs at all./// Validation covers the entire plan before the first step runs./// A turn moves the entry frontiers forward by two and a fault moves them forward/// by one, and any other advance is rejected./// Each moment a step expects has to verify under the world's origin./// The first failing step halts the replay./// The start moment must equal the world's verified current moment./// The plan's step array is checked against the world's live memory before it is/// copied.pub fn replayPrefix(restored: *restore.Restored, input: Input) Result { const current = restore.validateStable(restored) catch |failure| return rejected(null, 0, null, failure); var progress = initialProgress(current); if (!std.meta.eql(current, input.start)) { return rejected(progress, 0, null, error.PrefixStartMismatch); } if (input.steps.len > step_limit) { return rejected( progress, 0, null, error.PrefixStepCapacityExceeded, ); } source.validateMemory(restored, std.mem.sliceAsBytes(input.steps)) catch |failure| return rejected(progress, 0, null, failure); var steps: [step_limit]Step = undefined; @memcpy(steps[0..input.steps.len], input.steps); validatePlan( restored.root, current, steps[0..input.steps.len], input.end, ) catch |failure| return rejected(progress, 0, null, failure); for (steps[0..input.steps.len], 0..) |*step, index| { switch (step.*) { .turn => |turn| switch (replay_owner.replayTurn( restored, turn.replay, )) { .advanced => |advanced| { std.debug.assert(std.meta.eql( advanced.moment, turn.expected_moment, )); std.debug.assert(progress.turn_count < step_limit); progress.turn_steps[progress.turn_count] = @intCast(index); progress.turn_events[progress.turn_count] = advanced.events; progress.turn_count += 1; progress.step_count += 1; progress.moment = advanced.moment; }, .rejected => |failure| return rejected( progress, index, failure.node, failure.failure, ), .invalidated => |failure| return invalidated( progress, index, failure.node, failure.failure, ), }, .fault => |fault| switch (fault_owner.replayFault( restored, fault.reader, fault.expected_root, )) { .applied => |applied| { std.debug.assert(std.meta.eql( applied.moment, fault.expected_moment, )); progress.step_count += 1; progress.moment = applied.moment; }, .rejected => |failure| return rejected( progress, index, failure.node, failure.failure, ), }, } } std.debug.assert(std.meta.eql(progress.moment, input.end)); return .{ .reached = progress };}Source: lib/machine/src/world/prefix.zig:14
/// The maximum number of steps one prefix replays, for a caller sizing its plan/// before calling./// A plan longer than this rejects before any step runs.pub const step_limit: usize = 16;Source: lib/machine/src/world/replay.zig:21
pub const Error = fabric.transition.Error || fabric.Error || instance.AcknowledgeError || instance.DeliveryError || instance.EventError || instance.QuiescenceReceiptError || instance.ReactivateError || instance.RunError || os.abi.wire.FenceError || restore.StableError || source.Error || ReplayOwnerError;Source: lib/machine/src/world/replay.zig:95
/// Runs one recorded turn again on a restored world so a caller proves the recording/// and the guest still agree. Both recorded transitions replay against candidate/// ledgers before the guest runs. The guest executes the delivery as recorded, and/// the settlement it produces has to come out identical to the recorded transition./// Ledger and moment commit together on agreement. Both readers are checked against/// the world's live memory before anything is read. The two recorded transitions/// must name the same node, and that node must have a live instance.pub fn replayTurn(restored: *restore.Restored, input: Input) Result { const prepared = preflight(restored, input) catch |failure| return reject(null, failure); const phase = prepared.machine.phase(); switch (phase) { .booting, .awaiting_input, .awaiting_reactivation => {}, else => return reject(prepared.node, error.MachinePhaseMismatch), } switch (phase) { .booting => activate(prepared.machine) catch |failure| return invalidate(restored, prepared.node, failure), .awaiting_reactivation => { prepared.machine.reactivate(input.fence) catch |failure| return invalidate(restored, prepared.node, failure); activate(prepared.machine) catch |failure| return invalidate(restored, prepared.node, failure); }, .awaiting_input => {}, else => unreachable, } prepared.machine.deliverAdmitted(&prepared.delivery) catch |failure| return invalidate(restored, prepared.node, failure); const exit_value = prepared.machine.run() catch |failure| return invalidate(restored, prepared.node, failure); if (!std.meta.eql( exit_value, instance.Exit{ .doorbell = .{ .code = .quiescent } }, )) return invalidate(restored, prepared.node, error.QuiescenceExitMismatch); var events: instance.EventBatch = undefined; prepared.machine.takeEvents(&events) catch |failure| return invalidate(restored, prepared.node, failure); prepared.machine.acknowledge(prepared.delivery.receipt) catch |failure| return invalidate(restored, prepared.node, failure); const receipt = prepared.machine.quiescenceReceipt() catch |failure| return invalidate(restored, prepared.node, failure); var actual_fabric = prepared.after_admission; const settled = actual_fabric.settle(prepared.node, receipt) catch |failure| return invalidate(restored, prepared.node, failure); const actual: fabric.Transition = .{ .entry = settled.entry, .root = settled.root, }; if (!std.meta.eql(actual, prepared.settlement) or !std.meta.eql(actual_fabric, prepared.after_settlement)) { return invalidate( restored, prepared.node, error.SettlementTransitionMismatch, ); } restored.fabric.* = actual_fabric; restored.moment = prepared.next_moment; return .{ .advanced = .{ .admission = prepared.admission, .settlement = actual, .moment = prepared.next_moment, .events = events, } };}Source: lib/machine/src/world/restore.zig:26
pub const Error = canon.Error || checkpoint.Error || fabric.Error || instance.RestoreError || moment.Error || profile.Error || RestoreOwnerError;Source: lib/machine/src/world/restore.zig:174
/// Brings a world back from a sealed cut so a caller brings a stored boundary back/// as running machines. The ledger has to sit at precisely the position the cut/// recorded. Each binding is checked against both the cut and the ledger boundary,/// covering the identity, the checkpoint root, the semantic digest, the contract/// fingerprint, the profile fingerprint, and the fence. Live storage buffers must/// not overlap each other, the ledger, or any checkpoint. The first backend missing/// on this host halts construction, and everything built so far is torn down.pub fn restore( cut: types.Cut, fabric_owner: *fabric.Fabric, bindings: []const Binding,) Result { canon.verify(cut) catch |failure| return reject(null, failure); const fabric_cut = fabric_owner.cut() catch |failure| return reject(null, failure); if (!std.meta.eql(fabric_cut.root, cut.root.fabric)) { return reject(null, error.FabricMismatch); } if (bindings.len != cut.root.node_count or bindings.len != fabric_cut.node_count) { return reject(null, error.NodeCountMismatch); } var owned: [types.node_limit]Binding = undefined; @memcpy(owned[0..bindings.len], bindings); validateAliases(fabric_owner, owned[0..bindings.len]) catch |failure| return reject(null, failure); for (owned[0..bindings.len], 0..) |binding, index| { const boundary = fabric_cut.nodes[index]; const node = cut.nodes[index]; if (!std.meta.eql(binding.node, node.id) or !std.meta.eql(binding.node, boundary.id)) { return reject(binding.node, error.NodeMismatch); } if (boundary.machine.kind != .semantic) { return reject(binding.node, error.MachineBoundaryUnavailable); } const identity = switch (binding.mode) { .live => |target| live: { if (!boundary.available) { return reject(binding.node, error.MachineModeMismatch); } validateTarget(cut.root, node.machine, target) catch |failure| return reject(binding.node, failure); break :live instance.validateRestore( target.storage, target.ram, .{ .checkpoint = binding.checkpoint, .expected_root = node.machine, .profile = target.profile, .execution_manifest = target.execution_manifest, .fence = target.fence, }, ) catch |failure| return reject(binding.node, failure); }, .retained => retained: { if (boundary.available) { return reject(binding.node, error.MachineModeMismatch); } break :retained binding.checkpoint.identity() catch |failure| return reject(binding.node, failure); }, }; if (!std.meta.eql(identity.root, node.machine)) { return reject(binding.node, error.CheckpointRootMismatch); } if (!std.mem.eql(u8, &identity.semantic, &boundary.machine.digest)) { return reject(binding.node, error.SemanticBoundaryMismatch); } } const initial_moment = moment.prepare(cut.root, fabric_cut.root) catch |failure| return reject(null, failure); return construct( cut, fabric_owner, initial_moment, owned[0..bindings.len], );}Source: lib/machine/src/root.zig:72
pub const world = @import("world/root.zig");Source: lib/machine/src/world/root.zig
//! Machines that talk to each other advance separately, so stopping them all at//! one instant, storing that instant, and bringing it back later takes a definition//! of what one instant is, and this namespace supplies it. The namespace folds the//! state of every running machine, every machine's saved state, and the order of//! everything that passed between the machines into one identity, and a caller seals,//! restores, and replays that identity. The execution cycle runs seal, then restore,//! then activate, then advance, and seal again.//!//! A step of the machines can fail its checks before it changes anything, or after//! its changes have begun. Running machines together adds places where two runs//! of the same program could differ, beyond the places each machine has alone.//!//! The order of everything that passed between the machines lives in one record//! of every admitted input, packet, settlement, and fault decision across them,//! the *ledger*. The namespace runs one deterministic execution across up to four//! machines, together with the ledger (a *world*). The instant is a complete restorable//! boundary holding one digest of the whole world state together with the checkpoint//! root of each machine, and carrying no live state (a *cut*).//!//! A step is an input delivered to a machine together with the guest work that settles//! it (a *turn*). Each turn runs under the world, generation, and token authorized//! for it (its *activation fence*). Every mutation works on a copy of the ledger//! (a *candidate ledger*), verifies the result on that copy, then commits the record//! and the world's new position in its history together, once every verification//! passes. A turn that fails before changing anything leaves the world usable (*rejected*).//! A turn that fails after mutation began tears down every running machine and ends//! the world (*invalidated*).//!//! The namespace answers for exactly three named places where two runs of the same//! program could differ (each a *divergence source*): the activation fence, turn//! selection, and the replay source.//!//! - *node*: one participant in a world, named by a 16-byte identity.//! - *world root*: one world state folded into a single digest, covering the contract//! that binds every node, the ledger root, and the node count.//! - *moment*: a position in one world's history, pairing the world root the world//! grew from with the ledger root it has reached since.//! - *instance*: one live K0 execution that borrows caller-owned storage and guest-memory//! backing until `deinit`.//! - *checkpoint*: captured machine execution state carrying an identity that any//! holder of the bytes can recompute.const fault_owner = @import("fault.zig");const live_owner = @import("live.zig");const moment_owner = @import("moment.zig");const owner = @import("owner.zig");const prefix_owner = @import("prefix.zig");const profile = @import("../profile/root.zig");const replay_owner = @import("replay.zig");const restore_owner = @import("restore.zig");const types = @import("types.zig");pub const manifest = @import("manifest/root.zig");pub const Binding = types.Binding;pub const Cut = types.Cut;pub const Dialect = types.Dialect;pub const Error = owner.Error;pub const FaultApplied = fault_owner.Applied;pub const FaultError = fault_owner.Error;pub const FaultRejection = fault_owner.Rejection;pub const FaultResult = fault_owner.Result;pub const LiveActivated = live_owner.Activated;pub const LiveActivateResult = live_owner.ActivateResult;pub const LiveAdvanced = live_owner.Advanced;pub const LiveError = live_owner.Error;pub const LiveRejection = live_owner.Rejection;pub const LiveTurnResult = live_owner.TurnResult;pub const Moment = moment_owner.Moment;pub const MomentDialect = moment_owner.Dialect;pub const MomentError = moment_owner.Error;pub const Node = types.Node;pub const PrefixError = prefix_owner.Error;pub const PrefixFault = prefix_owner.Fault;pub const PrefixInput = prefix_owner.Input;pub const PrefixProgress = prefix_owner.Progress;pub const PrefixResult = prefix_owner.Result;pub const PrefixStep = prefix_owner.Step;pub const PrefixStopped = prefix_owner.Stopped;pub const PrefixTurn = prefix_owner.Turn;pub const Root = types.Root;pub const RestoreBinding = restore_owner.Binding;pub const RestoreError = restore_owner.Error;pub const RestoreMode = restore_owner.Mode;pub const RestoreRejection = restore_owner.Rejection;pub const RestoreResult = restore_owner.Result;pub const RestoreTarget = restore_owner.Target;pub const RestoreUnavailable = restore_owner.Unavailable;pub const Restored = restore_owner.Restored;pub const RestoredNode = restore_owner.Node;pub const ReplayAdvanced = replay_owner.Advanced;pub const ReplayError = replay_owner.Error;pub const ReplayFrame = replay_owner.Frame;pub const ReplayInput = replay_owner.Input;pub const ReplayRejection = replay_owner.Rejection;pub const ReplayResult = replay_owner.Result;pub const Source = types.Source;pub const node_limit = types.node_limit;pub const prefix_step_limit = prefix_owner.step_limit;pub const applyFault = fault_owner.applyFault;pub const activate = live_owner.activate;pub const prepareMoment = moment_owner.prepare;pub const replayFault = fault_owner.replayFault;pub const replayPrefix = prefix_owner.replayPrefix;pub const seal = owner.seal;pub const restore = restore_owner.restore;pub const replayTurn = replay_owner.replayTurn;pub const terminal = live_owner.terminal;pub const verify = owner.verify;pub const verifyMoment = moment_owner.verify;pub const determinism_sources = [_]profile.DeterminismSource{ .activation_fence, .turn_selection, .replay_source,};Audit
| Definitions | 61 |
|---|---|
| Public names | 61 |
| Members | 108 |
| Version | 26.7.0 |
| Revision | daab053ee433 |