tiny.machine.Fabric
Defined in tiny.machine.
API (22)
Actions
Public operations.
advanceTimeapplyFaultchooseEntropychooseServicecutinitinjectEntropynodeAvailablepacketpacketCountpartitionedpendingDeliveryreceiveNextPacketreceivePacketreplayrootsendPacketsettlesettleServiceterminalturnPending
Fields and members
Public fields and members.
Source
Source: lib/machine/src/fabric/owner.zig:43
zig
pub const Fabric = struct { state: types.State, pub fn init(input: types.Input) Error!Fabric { try profile.validate(input.profile); if (input.nodes.len == 0 or input.nodes.len > types.node_limit or input.nodes.len > input.profile.contract.instance_limit) { return error.NodeCapacityExceeded; } if (os.abi.wire.allZero(&input.world)) return error.InvalidWorld; const contract = try profile.contractFingerprint(input.profile); var state: types.State = .{ .contract = contract, .world = input.world, .node_count = @intCast(input.nodes.len), .nodes = undefined, .virtual_time_tick = input.virtual_time_tick, .entropy_frontier = 0, .entropy_bytes = 0, .packet_next_id = 0, .packet_count = 0, .packets = undefined, .partition_bits = 0, .capacity_bits = 0, .pending = null, .entry_frontier = 0, .admission_frontier = 0, .fault_frontier = 0, .admission_limit = types.admission_limit, .ledger_digest = @splat(0), .fault_digest = @splat(1), .root = .{ .digest = @splat(1), .dialect = .ordered_effect_fabric_v3, .machine_contract = contract, .entry_frontier = 0, .admission_frontier = 0, .fault_frontier = 0, }, }; for (input.nodes, 0..) |node, index| { state.nodes[index] = .{ .id = node.id, .basis = node.basis, .machine = .{ .kind = .basis, .digest = canon.basisDigest(node.basis), }, .available = true, }; } try canon.initialize(&state); return .{ .state = state }; } pub fn root(self: *const Fabric) types.Root { return self.state.root; } pub fn cut(self: *const Fabric) Error!types.Cut { try canon.validate(self.state); if (self.state.pending != null) return error.TurnPending; var result: types.Cut = .{ .root = self.state.root, .node_count = self.state.node_count, .nodes = @splat(emptyNodeBoundary()), }; for (self.state.nodes[0..self.state.node_count], 0..) |node, index| { result.nodes[index] = .{ .id = node.id, .available = node.available, .machine = node.machine, }; } return result; } pub fn turnPending(self: *const Fabric) bool { return self.state.pending != null; } pub fn packetCount(self: *const Fabric) u8 { return self.state.packet_count; } pub fn packet(self: *const Fabric, id: u64) Error!types.Packet { try canon.validate(self.state); const index = packetIndex(self.state, id) orelse return error.PacketUnknown; return self.state.packets[index].packet; } pub fn nodeAvailable(self: *const Fabric, node: types.NodeId) Error!bool { try canon.validate(self.state); const index = nodeIndex(self.state, node) orelse return error.UnknownNode; return self.state.nodes[index].available; } pub fn partitioned( self: *const Fabric, first: types.NodeId, second: types.NodeId, ) Error!bool { try canon.validate(self.state); return linkPartitioned(self.state, first, second); } pub fn applyFault( self: *Fabric, input: types.FaultInput, ) Error!types.Faulted { try canon.validate(self.state); if (self.state.pending != null) return error.TurnPending; if (self.state.admission_frontier == self.state.admission_limit) { return error.AdmissionCapacityExceeded; } try validateDirectFault(self.state, input.effect); const point = try canon.faultPoint(self.state.root, input.effect); const decision = try fault.decide(point, input.choice); const entry = try nextEntry(self.state, .{ .fault = .{ .effect = input.effect, .decision = decision, } }); var candidate = self.*; try applyEntry(&candidate.state, entry); self.* = candidate; return .{ .entry = entry, .root = self.state.root, .decision = decision, }; } pub fn terminal( self: *Fabric, node: types.NodeId, machine: *const instance.Instance, fence: os.abi.ActivationFence, bytes: []const u8, ) Error!types.Admitted { const basis = try self.liveBasis(node, machine); const record = try admission.terminal( basis.frontiers.terminal_input_offset, bytes, ); return self.admit(node, basis, fence, record, .direct); } pub fn advanceTime( self: *Fabric, node: types.NodeId, machine: *const instance.Instance, fence: os.abi.ActivationFence, to_tick: u64, ) Error!types.Admitted { const basis = try self.liveBasis(node, machine); if (to_tick < self.state.virtual_time_tick) { return error.VirtualTimeRegression; } const record = try admission.virtualTime( basis.frontiers.virtual_time_tick, to_tick, ); return self.admit(node, basis, fence, record, .direct); } pub fn injectEntropy( self: *Fabric, node: types.NodeId, machine: *const instance.Instance, fence: os.abi.ActivationFence, bytes: []const u8, ) Error!types.Admitted { const basis = try self.liveBasis(node, machine); const generation = std.math.add( u64, basis.frontiers.entropy_generation, 1, ) catch return error.EntropyCapacityExceeded; const record = try admission.entropy(generation, bytes); return self.admit(node, basis, fence, record, .direct); } pub fn chooseEntropy( self: *Fabric, node: types.NodeId, machine: *const instance.Instance, fence: os.abi.ActivationFence, bypass_bytes: []const u8, inject_bytes: []const u8, choice: fault.Choice, ) Error!types.Admitted { const basis = try self.liveBasis(node, machine); const generation = std.math.add( u64, basis.frontiers.entropy_generation, 1, ) catch return error.EntropyCapacityExceeded; const bypass_record = try admission.entropy(generation, bypass_bytes); const inject_record = try admission.entropy(generation, inject_bytes); return self.admitAlternatives( node, basis, fence, bypass_record, inject_record, .entropy_choice, choice, ); } pub fn settleService( self: *Fabric, node: types.NodeId, machine: *const instance.Instance, fence: os.abi.ActivationFence, result: types.ServiceResult, ) Error!types.Admitted { const basis = try self.liveBasis(node, machine); const request = basis.outstanding_effect orelse return error.EffectRequestRequired; const record = try admission.effectResult( request.receipt.digest, request.correlation, result.status, result.output_root, result.bytes, ); return self.admit(node, basis, fence, record, .direct); } pub fn chooseService( self: *Fabric, node: types.NodeId, machine: *const instance.Instance, fence: os.abi.ActivationFence, kind: fault.Kind, bypass: types.ServiceResult, injected: types.ServiceResult, choice: fault.Choice, ) Error!types.Admitted { const basis = try self.liveBasis(node, machine); const request = basis.outstanding_effect orelse return error.EffectRequestRequired; try validateServiceFault(kind, injected.status); const bypass_record = try serviceRecord(request, bypass); const inject_record = try serviceRecord(request, injected); return self.admitAlternatives( node, basis, fence, bypass_record, inject_record, kind, choice, ); } pub fn sendPacket( self: *Fabric, node: types.NodeId, machine: *const instance.Instance, fence: os.abi.ActivationFence, input: types.PacketInput, ) Error!types.Admitted { const basis = try self.liveBasis(node, machine); const request = basis.outstanding_effect orelse return error.EffectRequestRequired; if (self.state.packet_count == types.packet_limit or capacityActive(self.state, .packet)) { return error.PacketCapacityExceeded; } _ = try availableNodeIndex(self.state, input.destination); if (try linkPartitioned(self.state, node, input.destination)) { return error.LinkPartitioned; } const packet_id = std.math.add( u64, self.state.packet_next_id, 1, ) catch return error.PacketIdExhausted; const packet_value = try canon.makePacket(packet_id, node, request, input); const record = try admission.effectResult( request.receipt.digest, request.correlation, .ok, packet_value.digest, "", ); return self.admit( node, basis, fence, record, .{ .packet_send = packet_value }, ); } pub fn receivePacket( self: *Fabric, node: types.NodeId, machine: *const instance.Instance, fence: os.abi.ActivationFence, packet_id: u64, ) Error!types.Admitted { const basis = try self.liveBasis(node, machine); const request = basis.outstanding_effect orelse return error.EffectRequestRequired; const index = packetIndex(self.state, packet_id) orelse return error.PacketUnknown; const queued = self.state.packets[index]; if (!queued.ready) return error.PacketNotReady; if (queued.ready_at_tick > self.state.virtual_time_tick) { return error.PacketDelayed; } if (!canon.sameNode(queued.packet.destination, node)) { return error.PacketDestinationMismatch; } if (try linkPartitioned(self.state, queued.packet.source, node)) { return error.LinkPartitioned; } const record = try admission.effectResult( request.receipt.digest, request.correlation, .ok, queued.packet.digest, queued.packet.bytes(), ); return self.admit( node, basis, fence, record, .{ .packet_delivery = packet_id }, ); } pub fn receiveNextPacket( self: *Fabric, node: types.NodeId, machine: *const instance.Instance, fence: os.abi.ActivationFence, ) Error!types.Admitted { try canon.validate(self.state); const packet_id = (try nextPacketId(self.state, node)) orelse return error.PacketUnknown; return self.receivePacket(node, machine, fence, packet_id); } pub fn pendingDelivery( self: *const Fabric, node: types.NodeId, fence: os.abi.ActivationFence, ) Error!admission.Delivery { try canon.validate(self.state); const pending = self.state.pending orelse return error.NoTurnPending; if (!canon.sameNode(pending.node, node)) return error.UnknownNode; try validateFence(self.state.world, fence); return admission.bindDelivery( pending.admission, pending.delivery_root, fence, ); } pub fn settle( self: *Fabric, node: types.NodeId, receipt: instance.QuiescenceReceipt, ) Error!types.Settled { try canon.validate(self.state); const pending = self.state.pending orelse return error.NoTurnPending; if (!canon.sameNode(pending.node, node)) return error.UnknownNode; try instance.verifyQuiescenceReceipt(receipt, receipt.fence); try validateFence(self.state.world, receipt.fence); const delivery = try admission.bindDelivery( pending.admission, pending.delivery_root, receipt.fence, ); if (!std.meta.eql(delivery.receipt, receipt.delivery)) { return error.ReceiptMismatch; } const semantic = try instance.projectSemanticReceipt(receipt); const entry = try nextEntry(self.state, .{ .settlement = .{ .node = node, .receipt = semantic, } }); var candidate = self.*; try applyEntry(&candidate.state, entry); self.* = candidate; return .{ .entry = entry, .root = self.state.root }; } pub fn replay(self: *Fabric, entry: types.Entry) Error!types.Root { var candidate = self.*; try applyEntry(&candidate.state, entry); self.* = candidate; return self.state.root; } fn liveBasis( self: *const Fabric, node: types.NodeId, machine: *const instance.Instance, ) Error!admission.Basis { try canon.validate(self.state); if (self.state.pending != null) return error.TurnPending; const index = nodeIndex(self.state, node) orelse return error.UnknownNode; if (!self.state.nodes[index].available) return error.NodeUnavailable; if (capacityActive(self.state, .admission)) { return error.AdmissionCapacityExceeded; } const basis = try machine.admissionBasis(); if (!std.meta.eql(basis, self.state.nodes[index].basis)) { return error.MachineBasisMismatch; } return basis; } fn admit( self: *Fabric, node: types.NodeId, basis: admission.Basis, fence: os.abi.ActivationFence, record: admission.Record, effect: types.AdmissionEffect, ) Error!types.Admitted { const prepared = try admission.prepare(basis, record); return self.admitPrepared(node, fence, prepared, effect, null); } fn admitAlternatives( self: *Fabric, node: types.NodeId, basis: admission.Basis, fence: os.abi.ActivationFence, bypass_record: admission.Record, inject_record: admission.Record, kind: fault.Kind, choice: fault.Choice, ) Error!types.Admitted { const bypassed = try admission.prepare(basis, bypass_record); const injected = try admission.prepare(basis, inject_record); if (std.meta.eql(bypassed.receipt, injected.receipt)) { return error.FaultAlternativesEqual; } const alternatives: types.FaultAlternatives = .{ .node = node, .bypass = bypassed.receipt.digest, .inject = injected.receipt.digest, }; const effect: types.FaultEffect = switch (kind) { .entropy_choice => .{ .entropy_choice = alternatives }, .io_error => .{ .io_error = alternatives }, .host_service_failure => .{ .host_service_failure = alternatives }, else => return error.FaultEffectMismatch, }; const point = try canon.faultPoint(self.state.root, effect); const decision = try fault.decide(point, choice); const selected = switch (choice) { .bypass => bypassed, .inject => injected, }; return self.admitPrepared(node, fence, selected, .direct, .{ .effect = effect, .decision = decision, }); } fn admitPrepared( self: *Fabric, node: types.NodeId, fence: os.abi.ActivationFence, prepared: admission.Admission, effect: types.AdmissionEffect, admission_fault: ?types.AdmissionFault, ) Error!types.Admitted { try validateFence(self.state.world, fence); const entry = try nextEntry(self.state, .{ .admission = .{ .node = node, .admission = prepared, .effect = effect, .fault = admission_fault, } }); var candidate = self.*; try applyEntry(&candidate.state, entry); const delivery = try candidate.pendingDelivery(node, fence); self.* = candidate; return .{ .entry = entry, .root = self.state.root, .delivery = delivery, }; }};Source: lib/machine/src/root.zig:85
zig
pub const Fabric = fabric.Fabric;Also reachable as
Audit
| Definitions | 22 |
|---|---|
| Public names | 44 |
| Members | 1 |
| Version | 26.7.0 |
| Revision | daab053ee433 |