Skip to documentation
SLOP

tiny.reticulum.node.transport.announces

Reference tiny.reticulum node transport announces

Defined in node.transport.

API (31)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

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

Source

Called byCallsNo direct callsprivate sourcelib.reticulum.src.node.transport.announcespendingprivate sourcelib.reticulum.src.node.transport.requestsanswerKnownnode.transport.retransmitenternode.transport.announces.Recordinit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.reticulum.src.node.transport.announces.te...py:791-794 releases a held record for...test sourcelib.reticulum.src.node.transport.announcestest: announces admit maximum and rej...test sourcelib.reticulum.src.node.transport.announcestest: announces replace the oldest re...node.transport.Stateactivatenode.transport.announces.Tableactivate
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.reticulum.src.node.transport.announcestest: announces admit maximum and rej...test sourcelib.reticulum.src.node.transport.announcestest: announces replace the oldest re...private sourcelib.reticulum.src.node.transport.announces.TableindexOfprivate sourcelib.reticulum.src.node.transport.announces.TableoldestRebroadcastnode.transport.announces.Tableadmits
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.reticulum.src.node.transport.announces.te...py:791-794 releases a held record for...test sourcelib.reticulum.src.node.transport.announcestest: announces admit maximum and rej...test sourcelib.reticulum.src.node.transport.announcestest: announces replace the oldest re...node.transport.announces.Tablecount
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.reticulum.src.node.transport.announces.te...py:791-794 releases a held record for...test sourcelib.reticulum.src.node.transport.announcestest: announces admit maximum and rej...test sourcelib.reticulum.src.node.transport.announcestest: announces replace the oldest re...node.transport.Statedeinitnode.transport.announces.Tabledeinit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.reticulum.src.node.transport.announcestest: announces replace the oldest re...node.transport.announces.TableearliestDue
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.reticulum.src.node.transport.announces.te...py:791-794 releases a held record for...test sourcelib.reticulum.src.node.transport.announcestest: announces admit maximum and rej...test sourcelib.reticulum.src.node.transport.announcestest: announces replace the oldest re...private sourcelib.reticulum.src.node.transport.announces.TableindexOfnode.transport.announces.Tablefind
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.reticulum.src.node.transport.announces.te...py:791-794 releases a held record for...test sourcelib.reticulum.src.node.transport.announcestest: announces admit maximum and rej...test sourcelib.reticulum.src.node.transport.announcestest: announces replace the oldest re...node.transport.Stateinitnode.transport.announces.Tableinit
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest sourcelib.reticulum.src.node.transport.announces.te...py:791-794 releases a held record for...test sourcelib.reticulum.src.node.transport.announcestest: announces admit maximum and rej...test sourcelib.reticulum.src.node.transport.announcestest: announces replace the oldest re...private sourcelib.reticulum.src.node.transport.announces.TableindexOfprivate sourcelib.reticulum.src.node.transport.announces.TableoldestRebroadcastnode.transport.announces.Tableinsert
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.reticulum.src.node.transport.announces.te...py:791-794 releases a held record for...private sourcelib.reticulum.src.node.transport.announces.TableindexOfnode.transport.announces.TableremoveAtnode.transport.announces.Tableremove
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsnode.transport.announces.Tableremovenode.transport.announces.TableremoveAt
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/reticulum/src/node/transport/announces.zig

zig
const std = @import("std");const alloc_phase = @import("alloc_phase");const carrier = @import("../../carrier/root.zig");const destination = @import("../../destination/root.zig");pub const Seconds = u64;/// Two rebroadcasts heard from neighbors finish a pending entry, the count/// Reticulum@1.5.0 RNS/Transport.py:129 fixes.pub const local_rebroadcasts_max: u8 = 2;/// One retry follows the first rebroadcast, the allowance Reticulum@1.5.0/// RNS/Transport.py:120 sets.pub const retries_max: u8 = 1;/// The whole second this port waits before a first rebroadcast, standing in for/// the wait of up to half a second at Reticulum@1.5.0 RNS/Transport.py:2254.pub const first_delay: Seconds = 1;/// The whole second this port waits before a retry, standing in for the 5.5/// second wait at Reticulum@1.5.0 RNS/Transport.py:751.pub const retry_delay: Seconds = 6;/// The values that describe one new pending rebroadcast.pub const Fields = struct {    destination: [16]u8,    due: Seconds,    timestamp: Seconds,    retries: u8,    hops: u8,    block_rebroadcasts: bool,    attached: ?carrier.Index,    context_flag: u1,    payload: []const u8,};/// One pending rebroadcast, matching the record at Reticulum@1.5.0/// RNS/Transport.py:4061-4069.pub const Record = struct {    destination: [16]u8,    due: Seconds,    timestamp: Seconds,    retries: u8,    hops: u8,    local_rebroadcasts: u8,    block_rebroadcasts: bool,    attached: ?carrier.Index,    context_flag: u1,    payload_len: u16,    payload_bytes: [destination.announce.payload_bytes_max]u8,    /// Builds a record carrying its own copy of the announce payload, which    /// runs to 465 bytes at most.    pub fn init(fields: Fields) Record {        std.debug.assert(fields.payload.len <= destination.announce.payload_bytes_max);        std.debug.assert(fields.retries <= retries_max);        var record = Record{            .destination = fields.destination,            .due = fields.due,            .timestamp = fields.timestamp,            .retries = fields.retries,            .hops = fields.hops,            .local_rebroadcasts = 0,            .block_rebroadcasts = fields.block_rebroadcasts,            .attached = fields.attached,            .context_flag = fields.context_flag,            .payload_len = @intCast(fields.payload.len),            .payload_bytes = @splat(0),        };        @memcpy(record.payload_bytes[0..fields.payload.len], fields.payload);        return record;    }    pub fn payload(self: *const Record) []const u8 {        std.debug.assert(self.payload_len <= self.payload_bytes.len);        return self.payload_bytes[0..self.payload_len];    }};/// One destination with the rebroadcast queued for it and any second record/// waiting its turn.pub const Entry = struct {    record: Record,    held: ?Record,    /// Puts the entry's current record behind a new one, following    /// Reticulum@1.5.0 RNS/Transport.py:3438-3444.    pub fn hold(self: *Entry, record: Record) void {        std.debug.assert(std.mem.eql(u8, &self.record.destination, &record.destination));        self.held = self.record;        self.record = record;    }    /// Returns a held record to the front and gives it a due second later than    /// `now`, following Reticulum@1.5.0 RNS/Transport.py:791-794. The call    /// reports whether a held record was there.    pub fn release(self: *Entry, now: Seconds) bool {        const held = self.held orelse return false;        std.debug.assert(std.mem.eql(u8, &self.record.destination, &held.destination));        self.record = held;        self.record.due = @max(held.due, now +| 1);        self.held = null;        return true;    }};const TableLimits = struct {    announces_max: usize,};const TableCapacity = struct {    announces_max: usize,    storage_bytes: usize,    pub const DeriveError = error{ InvalidLimit, CapacityOverflow };    pub fn derive(limits: TableLimits) DeriveError!TableCapacity {        if (limits.announces_max == 0) return error.InvalidLimit;        const storage_bytes = alloc_phase.capacity.mul(            usize,            limits.announces_max,            @sizeOf(Entry),        ) catch return error.CapacityOverflow;        return .{ .announces_max = limits.announces_max, .storage_bytes = storage_bytes };    }};/// Pending announce rebroadcasts, matching Reticulum@1.5.0/// RNS/Transport.py:2279-2289.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 Exhaustion = error{Full};    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.announces",            .kind = .phase_static,            .limit_source = .caller,            .storage = .{                .covered = &.{.{                    .id = "caller_announce_table",                    .lifetime = .transferred,                    .detail = "caller storage for pending and held announce rebroadcasts",                }},                .excluded = &.{                    "borrowed announce payload inputs",                    "rebroadcast frames in effect storage",                },            },            .capacity = .{                .inputs = &.{alloc_phase.capacity.bindInput(                    Limits,                    "announces_max",                    "announces_max",                )},                .type_selectors = &.{alloc_phase.capacity.bindType(Entry, "announce")},                .nodes = &.{                    .{ .input = 0 },                    .{ .scale = .{                        .node = 0,                        .coefficient = .{ .size_of_concrete_type = 0 },                    } },                },                .assertions = &.{.{                    .scope = .closure_total,                    .measure = .retained,                    .relation = .exact,                    .expression = 1,                }},            },            .overload = .{                .kind = .reject_before_mutation,                .detail = "a new destination replaces the oldest rebroadcast entry, else rejects",            },            .risks = .{                .transitive = .{                    .status = .excluded,                    .detail = "announce operations call no allocating owner",                },                .foreign = .{                    .status = .excluded,                    .detail = "announce storage crosses no foreign boundary",                },            },            .work = .{ .equation = "operations scan at most announces_max entries" },            .obligations = &.{                .{ .key = "reticulum_announces_capacity", .role = .capacity_model },                .{ .key = "reticulum_announces_overload", .role = .overload },                .{ .key = "reticulum_announces_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;    }    pub fn find(self: *Table, hash: [16]u8) ?*Entry {        std.debug.assert(self.phase == .steady);        const index = self.indexOf(hash) orelse return null;        return &self.entries[index];    }    /// Answers whether `insert` would take a record for this destination.    pub fn admits(self: *const Table, hash: [16]u8) bool {        std.debug.assert(self.phase == .steady);        if (self.indexOf(hash) != null) return true;        if (self.len < self.capacity.announces_max) return true;        return self.oldestRebroadcast() != null;    }    /// Writes the entry for one destination, following Reticulum@1.5.0    /// RNS/Transport.py:2279-2289. A destination already in the table keeps its    /// slot and the record held behind it. With every place taken, the one    /// given up is the longest-standing entry the node has already sent at    /// least once. A full table with no such entry returns `error.Full` and    /// leaves every entry as it was.    pub fn insert(self: *Table, record: Record) Exhaustion!*Entry {        std.debug.assert(self.phase == .steady);        if (self.indexOf(record.destination)) |index| {            self.entries[index].record = record;            return &self.entries[index];        }        if (self.len < self.capacity.announces_max) {            self.entries[self.len] = .{ .record = record, .held = null };            self.len += 1;            return &self.entries[self.len - 1];        }        const index = self.oldestRebroadcast() orelse return error.Full;        self.entries[index] = .{ .record = record, .held = null };        return &self.entries[index];    }    /// Takes the entry at one position out, leaving the rest in the order they    /// were written.    pub fn removeAt(self: *Table, index: usize) void {        std.debug.assert(self.phase == .steady);        std.debug.assert(index < self.len);        std.mem.copyForwards(            Entry,            self.entries[index .. self.len - 1],            self.entries[index + 1 .. self.len],        );        self.len -= 1;    }    pub fn remove(self: *Table, hash: [16]u8) bool {        const index = self.indexOf(hash) orelse return false;        self.removeAt(index);        return true;    }    /// Returns the earliest due second among the pending records. An empty    /// table gives null.    pub fn earliestDue(self: *const Table) ?Seconds {        std.debug.assert(self.phase == .steady);        var earliest: ?Seconds = null;        for (self.entries[0..self.len]) |*entry| {            const due = entry.record.due;            if (earliest) |selected| {                if (due >= selected) continue;            }            earliest = due;        }        return earliest;    }    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, hash: [16]u8) ?usize {        std.debug.assert(self.len <= self.capacity.announces_max);        for (self.entries[0..self.len], 0..) |*entry, index| {            if (std.mem.eql(u8, &entry.record.destination, &hash)) return index;        }        return null;    }    fn oldestRebroadcast(self: *const Table) ?usize {        var oldest: ?usize = null;        for (self.entries[0..self.len], 0..) |*entry, index| {            if (entry.record.retries == 0) continue;            if (oldest) |selected| {                if (entry.record.timestamp >= self.entries[selected].record.timestamp) continue;            }            oldest = index;        }        return oldest;    }};comptime {    alloc_phase.capacity.requireProvisionedRejectingOwnerShape(Table);}fn pending(byte: u8, timestamp: Seconds, retries: u8) Record {    return Record.init(.{        .destination = @splat(byte),        .due = timestamp + first_delay,        .timestamp = timestamp,        .retries = retries,        .hops = 1,        .block_rebroadcasts = false,        .attached = null,        .context_flag = 0,        .payload = "announce payload",    });}test "announces admit maximum and reject a new destination before any rebroadcast" {    comptime {        @stardustClaim(alloc_phase.capacity.witness(            Table,            "reticulum_announces_capacity",        ), null, null, null, null, null, null);        @stardustClaim(alloc_phase.capacity.witness(            Table,            "reticulum_announces_overload",        ), null, null, null, null, null, null);        @stardustClaim(alloc_phase.capacity.witness(            Table,            "reticulum_announces_work",        ), null, null, null, null, null, null);    }    const capacity = comptime TableCapacity.derive(.{ .announces_max = 3 }) catch unreachable;    var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined;    var table = try Table.init(&bytes, .{ .announces_max = 3 });    table.activate();    defer _ = table.deinit();    for (1..4) |value| _ = try table.insert(pending(@intCast(value), 100, 0));    try std.testing.expectEqual(@as(usize, 3), table.count());    try std.testing.expect(!table.admits(@splat(4)));    try std.testing.expectError(error.Full, table.insert(pending(4, 101, 0)));    try std.testing.expectEqual(@as(usize, 3), table.count());    try std.testing.expect(table.admits(@splat(2)));    for (1..4) |value| try std.testing.expect(table.find(@splat(@intCast(value))) != null);}test "announces replace the oldest rebroadcast entry at maximum plus one" {    const capacity = comptime TableCapacity.derive(.{ .announces_max = 3 }) catch unreachable;    var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined;    var table = try Table.init(&bytes, .{ .announces_max = 3 });    table.activate();    defer _ = table.deinit();    _ = try table.insert(pending(1, 10, 1));    _ = try table.insert(pending(2, 5, 0));    _ = try table.insert(pending(3, 7, 1));    try std.testing.expect(table.admits(@splat(4)));    _ = try table.insert(pending(4, 20, 0));    try std.testing.expectEqual(@as(usize, 3), table.count());    try std.testing.expect(table.find(@splat(3)) == null);    for ([_]u8{ 1, 2, 4 }) |byte| try std.testing.expect(table.find(@splat(byte)) != null);    try std.testing.expectEqual(@as(Seconds, 6), table.earliestDue().?);}test "Reticulum@1.5.0 RNS/Transport.py:791-794 releases a held record for the next sweep" {    const capacity = comptime TableCapacity.derive(.{ .announces_max = 1 }) catch unreachable;    var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined;    var table = try Table.init(&bytes, .{ .announces_max = 1 });    table.activate();    defer _ = table.deinit();    const entry = try table.insert(pending(9, 10, 0));    var response = pending(9, 12, 1);    response.block_rebroadcasts = true;    entry.hold(response);    try std.testing.expect(entry.record.block_rebroadcasts);    _ = try table.insert(response);    try std.testing.expect(table.find(@splat(9)).?.held != null);    try std.testing.expect(entry.release(40));    try std.testing.expect(!entry.record.block_rebroadcasts);    try std.testing.expectEqual(@as(Seconds, 41), entry.record.due);    try std.testing.expect(entry.held == null);    try std.testing.expect(!entry.release(41));    try std.testing.expect(table.remove(@splat(9)));    try std.testing.expectEqual(@as(usize, 0), table.count());}

Source: lib/reticulum/src/node/transport/root.zig:102

zig
pub const announces = @import("announces.zig");

Audit

Definitions32
Public names32
Members28
Version26.7.0
Revisiondaab053ee433