tiny.reticulum.node.transport.inflight
Defined in node.transport.
API (18)
Actions
Public operations.
Table.activateTable.countTable.deinitTable.find: Reports the live gate for one destination, following Reticulum@1.5.0 RNS/Transport.py:1770-1772.Table.initTable.insert: Opens a gate at the second of the request, following Reticulum@1.5.0 RNS/Transport.py:1774-1776.Table.remove: Closes the gate for one destination, following Reticulum@1.5.0 RNS/Transport.py:2395-2397,3520-3524.
Types and contracts
Public types and contracts.
Entry: One destination the node has asked after and has yet to hear back on.SecondsTable: In-flight path request gates, matching Reticulum@1.5.0 RNS/Transport.py:1770-1776.Table.CapacityTable.InitErrorTable.LimitsTable.Storage
Values and defaults
Public values and defaults.
Table.claimTable.storage_alignmentTable.work_limitstimeout: Forty-five seconds, after which Reticulum@1.5.0 RNS/Transport.py:132,968 clears a gate.
Source
Source: lib/reticulum/src/node/transport/inflight.zig
zig
const std = @import("std");const alloc_phase = @import("alloc_phase");pub const Seconds = u64;/// Forty-five seconds, after which Reticulum@1.5.0 RNS/Transport.py:132,968/// clears a gate.pub const timeout: Seconds = 45;/// One destination the node has asked after and has yet to hear back on.pub const Entry = struct { destination: [16]u8, timestamp: Seconds,};/// Reports whether a gate still counts. This port keeps a gate through the/// second it was stamped plus forty-five and clears it at plus forty-six.fn live(entry: *const Entry, now: Seconds) bool { return now -| entry.timestamp <= timeout;}const TableLimits = struct { inflight_requests_max: usize,};const TableCapacity = struct { inflight_requests_max: usize, storage_bytes: usize, pub const DeriveError = error{ InvalidLimit, CapacityOverflow }; pub fn derive(limits: TableLimits) DeriveError!TableCapacity { if (limits.inflight_requests_max == 0) return error.InvalidLimit; const storage_bytes = alloc_phase.capacity.mul( usize, limits.inflight_requests_max, @sizeOf(Entry), ) catch return error.CapacityOverflow; return .{ .inflight_requests_max = limits.inflight_requests_max, .storage_bytes = storage_bytes, }; }};/// In-flight path request gates, matching Reticulum@1.5.0/// RNS/Transport.py:1770-1776.pub const Table = struct { phase: alloc_phase.capacity.Phase, capacity: Capacity, storage: Storage, entries: []Entry, len: usize = 0, pub const storage_alignment: usize = 8; pub const Storage = []align(storage_alignment) u8; pub const Limits: type = TableLimits; pub const Capacity: type = TableCapacity; pub const InitError = Capacity.DeriveError || error{StorageLengthMismatch}; pub const work_limits: alloc_phase.capacity.WorkLimits = .{ .transition_steps_max = 65_536, .cleanup_steps_per_call_max = 0, .cleanup_calls_at_capacity_max = 0, }; pub const claim: alloc_phase.capacity.Declaration = .{ .source = .{ .id = "reticulum.inflight_requests", .kind = .phase_static, .limit_source = .caller, .storage = .{ .covered = &.{.{ .id = "caller_inflight_request_table", .lifetime = .transferred, .detail = "caller storage for in-flight path request destinations", }}, .excluded = &.{"path request frames in effect storage"}, }, .capacity = .{ .inputs = &.{alloc_phase.capacity.bindInput( Limits, "inflight_requests_max", "inflight_requests_max", )}, .type_selectors = &.{alloc_phase.capacity.bindType(Entry, "inflight_request")}, .nodes = &.{ .{ .input = 0 }, .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 0 }, } }, }, .assertions = &.{.{ .scope = .closure_total, .measure = .retained, .relation = .exact, .expression = 1, }}, }, .overload = .{ .kind = .not_applicable, .detail = "a new entry replaces its key, an expired entry, else the oldest", }, .risks = .{ .transitive = .{ .status = .excluded, .detail = "in-flight operations call no allocating owner", }, .foreign = .{ .status = .excluded, .detail = "in-flight storage crosses no foreign boundary", }, }, .work = .{ .equation = "operations scan at most inflight_requests_max entries" }, .obligations = &.{ .{ .key = "reticulum_inflight_requests_capacity", .role = .capacity_model }, .{ .key = "reticulum_inflight_requests_replace", .role = .overload }, .{ .key = "reticulum_inflight_requests_work", .role = .work_bound }, }, }, .bindings = .{ .owner = @This(), .seal = .{ .family = alloc_phase.capacity.selector(@This().activate), .premise = .{ .class = .checked_semantic_fact, .authority = .checker }, }, .teardown = .{ .family = alloc_phase.capacity.selector(@This().deinit), .premise = .{ .class = .checked_semantic_fact, .authority = .checker }, }, }, }; pub fn init(storage: Storage, limits: Limits) InitError!Table { const capacity = try Capacity.derive(limits); if (storage.len != capacity.storage_bytes) return error.StorageLengthMismatch; return .{ .phase = .initialization, .capacity = capacity, .storage = storage, .entries = std.mem.bytesAsSlice(Entry, storage), }; } pub fn activate(self: *Table) void { std.debug.assert(self.phase == .initialization); std.debug.assert(self.len == 0); self.phase = .steady; } /// Reports the live gate for one destination, following Reticulum@1.5.0 /// RNS/Transport.py:1770-1772. pub fn find(self: *const Table, destination: [16]u8, now: Seconds) ?Entry { std.debug.assert(self.phase == .steady); const index = self.indexOf(destination) orelse return null; const entry = self.entries[index]; if (!live(&entry, now)) return null; return entry; } /// Opens a gate at the second of the request, following Reticulum@1.5.0 /// RNS/Transport.py:1774-1776. A full table gives the slot to the /// destination's own gate, else to a gate past its wait, else to the /// oldest. pub fn insert(self: *Table, destination: [16]u8, now: Seconds) void { std.debug.assert(self.phase == .steady); const target = self.reclaim(destination, now); target.* = .{ .destination = destination, .timestamp = now }; std.debug.assert(self.len <= self.capacity.inflight_requests_max); } /// Closes the gate for one destination, following Reticulum@1.5.0 /// RNS/Transport.py:2395-2397,3520-3524. The call reports whether a gate /// was there. pub fn remove(self: *Table, destination: [16]u8) bool { std.debug.assert(self.phase == .steady); const index = self.indexOf(destination) orelse return false; self.len -= 1; self.entries[index] = self.entries[self.len]; return true; } pub fn count(self: *const Table) usize { std.debug.assert(self.phase == .steady); return self.len; } pub fn deinit(self: *Table) Storage { std.debug.assert(self.phase == .steady); self.phase = .teardown; const storage = self.storage; self.* = undefined; return storage; } fn indexOf(self: *const Table, destination: [16]u8) ?usize { std.debug.assert(self.len <= self.capacity.inflight_requests_max); for (self.entries[0..self.len], 0..) |*entry, index| { if (std.mem.eql(u8, &entry.destination, &destination)) return index; } return null; } fn reclaim(self: *Table, destination: [16]u8, now: Seconds) *Entry { if (self.indexOf(destination)) |index| return &self.entries[index]; for (self.entries[0..self.len]) |*entry| { if (!live(entry, now)) return entry; } if (self.len < self.capacity.inflight_requests_max) { self.len += 1; return &self.entries[self.len - 1]; } var oldest = &self.entries[0]; for (self.entries[1..self.len]) |*entry| { if (entry.timestamp < oldest.timestamp) oldest = entry; } return oldest; }};comptime { alloc_phase.capacity.requireProvisionedExactOwnerShape(Table);}test "inflight requests admit maximum and replace the oldest at maximum plus one" { comptime { @stardustClaim(alloc_phase.capacity.witness( Table, "reticulum_inflight_requests_capacity", ), null, null, null, null, null, null); @stardustClaim(alloc_phase.capacity.witness( Table, "reticulum_inflight_requests_replace", ), null, null, null, null, null, null); @stardustClaim(alloc_phase.capacity.witness( Table, "reticulum_inflight_requests_work", ), null, null, null, null, null, null); } const limits = TableLimits{ .inflight_requests_max = 3 }; const capacity = comptime TableCapacity.derive(limits) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, limits); table.activate(); defer _ = table.deinit(); for (1..4) |value| table.insert(@splat(@intCast(value)), 100 + value); try std.testing.expectEqual(@as(usize, 3), table.count()); table.insert(@splat(4), 110); try std.testing.expectEqual(@as(usize, 3), table.count()); try std.testing.expect(table.find(@splat(1), 110) == null); for (2..5) |value| try std.testing.expect(table.find(@splat(@intCast(value)), 110) != null);}test "Reticulum@1.5.0 RNS/Transport.py:968 keeps a gate through plus 45 and clears it at plus 46" { const limits = TableLimits{ .inflight_requests_max = 2 }; const capacity = comptime TableCapacity.derive(limits) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, limits); table.activate(); defer _ = table.deinit(); table.insert(@splat(7), 1_000); try std.testing.expect(table.find(@splat(7), 1_000 + timeout) != null); try std.testing.expect(table.find(@splat(7), 1_000 + timeout + 1) == null); table.insert(@splat(8), 1_000 + timeout + 1); try std.testing.expectEqual(@as(usize, 1), table.count()); try std.testing.expect(table.find(@splat(8), 1_000 + timeout + 1) != null);}test "inflight requests reopen their key and remove one destination" { const limits = TableLimits{ .inflight_requests_max = 2 }; const capacity = comptime TableCapacity.derive(limits) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, limits); table.activate(); defer _ = table.deinit(); table.insert(@splat(5), 10); table.insert(@splat(5), 20); try std.testing.expectEqual(@as(usize, 1), table.count()); try std.testing.expect(table.find(@splat(5), 20 + timeout) != null); try std.testing.expect(table.remove(@splat(5))); try std.testing.expect(!table.remove(@splat(5))); try std.testing.expectEqual(@as(usize, 0), table.count());}Source: lib/reticulum/src/node/transport/root.zig:104
zig
pub const inflight = @import("inflight.zig");Audit
| Definitions | 19 |
|---|---|
| Public names | 19 |
| Members | 7 |
| Version | 26.7.0 |
| Revision | daab053ee433 |