Skip to documentation
SLOP

tiny.reticulum.node.transport.reverse

Reference tiny.reticulum node transport reverse

Defined in node.transport.

API (18)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callsnode.transportreverse
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callstest sourcelib.reticulum.src.node.transport.reverse.test...py:834-841 expires a reverse entry at...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries admit maximum a...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries replace their k...node.transport.Stateactivatenode.transport.reverse.Tableactivate
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.reticulum.src.node.transport.reverse.test...py:834-841 expires a reverse entry at...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries admit maximum a...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries replace their k...node.transport.reverse.Tablecount
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.reticulum.src.node.transport.reverse.test...py:834-841 expires a reverse entry at...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries admit maximum a...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries replace their k...node.transport.Statedeinitnode.transport.reverse.Tabledeinit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.reticulum.src.node.transport.reverse.test...py:834-841 expires a reverse entry at...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries admit maximum a...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries replace their k...private sourcelib.reticulum.src.node.transport.reverse.TableindexOfprivate sourcelib.reticulum.src.node.transport.reverselivenode.transport.reverse.Tablefind
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.reticulum.src.node.transport.reverse.test...py:834-841 expires a reverse entry at...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries admit maximum a...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries replace their k...node.transport.Stateinitnode.transport.reverse.Tableinit
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest sourcelib.reticulum.src.node.transport.reverse.test...py:834-841 expires a reverse entry at...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries admit maximum a...test sourcelib.reticulum.src.node.transport.reversetest: reverse entries replace their k...private sourcelib.reticulum.src.node.transport.reverse.Tablereclaimnode.transport.reverse.Tableinsert
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.reticulum.src.node.transport.reversetest: reverse entries replace their k...private sourcelib.reticulum.src.node.transport.reverse.TableindexOfnode.transport.reverse.Tableremove
Static calls · unresolved targets: 0 · external targets: 0.

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

Definitions19
Public names19
Members9
Version26.7.0
Revisiondaab053ee433