tiny.reticulum.node.transport.reverse
Defined in node.transport.
API (18)
Actions
Public operations.
Table.activateTable.countTable.deinitTable.find: Hands back the entry for one proof destination while that entry sits inside its age, and the store keeps it.Table.initTable.insert: Records the carriers of one relayed packet, following Reticulum@1.5.0 RNS/Transport.py:2012-2018.Table.remove: Removes the entry for one proof, following Reticulum@1.5.0 RNS/Transport.py:2669-2671.
Types and contracts
Public types and contracts.
Entry: One packet this node moved onward, held until its proof comes back.SecondsTable: Relayed packet carriers, matching Reticulum@1.5.0 RNS/Transport.py:2012-2018.Table.CapacityTable.InitErrorTable.LimitsTable.Storage
Values and defaults
Public values and defaults.
Table.claimTable.storage_alignmentTable.work_limitstimeout: Four hundred and eighty seconds, the lifetime Reticulum@1.5.0 RNS/Transport.py:151 gives a reverse entry.
Source
Source: lib/reticulum/src/node/transport/reverse.zig
zig
const std = @import("std");const alloc_phase = @import("alloc_phase");const carrier = @import("../../carrier/root.zig");pub const Seconds = u64;/// Four hundred and eighty seconds, the lifetime Reticulum@1.5.0/// RNS/Transport.py:151 gives a reverse entry.pub const timeout: Seconds = 480;/// One packet this node moved onward, held until its proof comes back.pub const Entry = struct { truncated: [16]u8, timestamp: Seconds, receiving: carrier.Index, outbound: carrier.Index,};/// Reports whether an entry still counts. An entry stops counting 480 seconds/// past the second it was written, the age Reticulum@1.5.0/// RNS/Transport.py:834-841 sets.fn live(entry: *const Entry, now: Seconds) bool { return now -| entry.timestamp <= timeout;}const TableLimits = struct { reverse_entries_max: usize,};const TableCapacity = struct { reverse_entries_max: usize, storage_bytes: usize, pub const DeriveError = error{ InvalidLimit, CapacityOverflow }; pub fn derive(limits: TableLimits) DeriveError!TableCapacity { if (limits.reverse_entries_max == 0) return error.InvalidLimit; const storage_bytes = alloc_phase.capacity.mul( usize, limits.reverse_entries_max, @sizeOf(Entry), ) catch return error.CapacityOverflow; return .{ .reverse_entries_max = limits.reverse_entries_max, .storage_bytes = storage_bytes, }; }};/// Relayed packet carriers, matching Reticulum@1.5.0/// RNS/Transport.py:2012-2018.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.reverse_entries", .kind = .phase_static, .limit_source = .caller, .storage = .{ .covered = &.{.{ .id = "caller_reverse_table", .lifetime = .transferred, .detail = "caller storage for relayed packet hashes and carriers", }}, .excluded = &.{"relayed frames in effect storage"}, }, .capacity = .{ .inputs = &.{alloc_phase.capacity.bindInput( Limits, "reverse_entries_max", "reverse_entries_max", )}, .type_selectors = &.{alloc_phase.capacity.bindType(Entry, "reverse_entry")}, .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 = "reverse operations call no allocating owner", }, .foreign = .{ .status = .excluded, .detail = "reverse storage crosses no foreign boundary", }, }, .work = .{ .equation = "operations scan at most reverse_entries_max entries" }, .obligations = &.{ .{ .key = "reticulum_reverse_entries_capacity", .role = .capacity_model }, .{ .key = "reticulum_reverse_entries_replace", .role = .overload }, .{ .key = "reticulum_reverse_entries_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; } /// Records the carriers of one relayed packet, following Reticulum@1.5.0 /// RNS/Transport.py:2012-2018. A full table gives the slot to the packet's /// own entry, else to an entry past its wait, else to the oldest. pub fn insert(self: *Table, value: Entry) void { std.debug.assert(self.phase == .steady); const target = self.reclaim(value.truncated, value.timestamp); target.* = value; std.debug.assert(self.len <= self.capacity.reverse_entries_max); } /// Hands back the entry for one proof destination while that entry sits /// inside its age, and the store keeps it. pub fn find(self: *const Table, truncated: [16]u8, now: Seconds) ?Entry { std.debug.assert(self.phase == .steady); const index = self.indexOf(truncated) orelse return null; const entry = self.entries[index]; if (!live(&entry, now)) return null; return entry; } /// Removes the entry for one proof, following Reticulum@1.5.0 /// RNS/Transport.py:2669-2671. The call reports whether an entry was there. pub fn remove(self: *Table, truncated: [16]u8) bool { std.debug.assert(self.phase == .steady); const index = self.indexOf(truncated) 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, truncated: [16]u8) ?usize { std.debug.assert(self.len <= self.capacity.reverse_entries_max); for (self.entries[0..self.len], 0..) |*entry, index| { if (std.mem.eql(u8, &entry.truncated, &truncated)) return index; } return null; } fn reclaim(self: *Table, truncated: [16]u8, now: Seconds) *Entry { if (self.indexOf(truncated)) |index| return &self.entries[index]; for (self.entries[0..self.len]) |*entry| { if (!live(entry, now)) return entry; } if (self.len < self.capacity.reverse_entries_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);}fn relayed(byte: u8, timestamp: Seconds) Entry { return .{ .truncated = @splat(byte), .timestamp = timestamp, .receiving = 0, .outbound = 1, };}test "reverse entries admit maximum and replace the oldest at maximum plus one" { comptime { @stardustClaim(alloc_phase.capacity.witness( Table, "reticulum_reverse_entries_capacity", ), null, null, null, null, null, null); @stardustClaim(alloc_phase.capacity.witness( Table, "reticulum_reverse_entries_replace", ), null, null, null, null, null, null); @stardustClaim(alloc_phase.capacity.witness( Table, "reticulum_reverse_entries_work", ), null, null, null, null, null, null); } const limits = TableLimits{ .reverse_entries_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(relayed(@intCast(value), 100 + value)); try std.testing.expectEqual(@as(usize, 3), table.count()); table.insert(relayed(4, 200)); try std.testing.expectEqual(@as(usize, 3), table.count()); try std.testing.expect(table.find(@splat(1), 200) == null); for (2..5) |value| try std.testing.expect(table.find(@splat(@intCast(value)), 200) != null);}test "Reticulum@1.5.0 RNS/Transport.py:834-841 expires a reverse entry at plus 481" { const limits = TableLimits{ .reverse_entries_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(relayed(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(relayed(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 "reverse entries replace their key and remove one proof destination" { const limits = TableLimits{ .reverse_entries_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(relayed(5, 10)); var moved = relayed(5, 11); moved.receiving = 2; table.insert(moved); try std.testing.expectEqual(@as(usize, 1), table.count()); try std.testing.expectEqual(@as(carrier.Index, 2), table.find(@splat(5), 11).?.receiving); 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:111
zig
pub const reverse = @import("reverse.zig");Audit
| Definitions | 19 |
|---|---|
| Public names | 19 |
| Members | 9 |
| Version | 26.7.0 |
| Revision | daab053ee433 |