tiny.reticulum.node.transport.path
Defined in node.transport.
API (29)
Actions
Public operations.
Entry.announcePayload: Hands back the announce payload the path kept, and null when that payload came in above 465 bytes under a HEADER_1 header and was therefore never copied.Entry.holdsBlobEntry.timebase: Takes the newest emission time among the announces the path stores, following Reticulum@1.5.0 RNS/Transport.py:3654-3660.Table.activateTable.countTable.deinitTable.expire: Throws a path away, leaving its destination open to the next announce from any distance.Table.find: Looks a destination up and hands back a path only while that path sits inside the one-week age Reticulum@1.5.0 RNS/Transport.py:940-943 sets.Table.hopsTo: Reports the path hop count, or the pathfinder maximum when the table holds no live path, following Reticulum@1.5.0 RNS/Transport.py:3063-3070.Table.initTable.learn: Records an accepted announce, following Reticulum@1.5.0 RNS/Transport.py:2261-2265,2374-2375.Table.markUnresponsive: Notes that a link went unanswered over this path, as Reticulum@1.5.0 RNS/Transport.py:3157-3162 does.admits: Decides whether an announce replaces a path, following Reticulum@1.5.0 RNS/Transport.py:2137-2213.emission: Reads bytes 5 through 10 of the announce's random bytes as an emission time, following Reticulum@1.5.0 RNS/Transport.py:3650-3651.
Types and contracts
Public types and contracts.
BlobCandidate: One announce whose signature has checked out, put forward for the path store.Entry: One path the node worked out, holding the announces it has already taken and the payload of the latest one.SecondsState: Whether the last thing sent over a path got through.Table: Paths learned from announces, matching Reticulum@1.5.0 RNS/Transport.py:2374-2375.Table.CapacityTable.InitErrorTable.LimitsTable.Storage
Values and defaults
Public values and defaults.
Table.claimTable.storage_alignmentTable.work_limitslifetime: One week, the lifetime Reticulum@1.5.0 RNS/Transport.py:123,152 gives a path.random_blobs_max: Sixty-four, the number of recent random byte strings Reticulum@1.5.0 RNS/Transport.py:159 keeps per path.
Source
Source: lib/reticulum/src/node/transport/path.zig
zig
const std = @import("std");const alloc_phase = @import("alloc_phase");const carrier = @import("../../carrier/root.zig");const destination = @import("../../destination/root.zig");const packet = @import("../../packet/root.zig");const wire = @import("../../wire/root.zig");pub const Seconds = u64;pub const Blob = [10]u8;/// Sixty-four, the number of recent random byte strings Reticulum@1.5.0/// RNS/Transport.py:159 keeps per path.pub const random_blobs_max: u8 = 64;/// One week, the lifetime Reticulum@1.5.0 RNS/Transport.py:123,152 gives a/// path.pub const lifetime: Seconds = 60 * 60 * 24 * 7;/// Whether the last thing sent over a path got through. Reticulum@1.5.0/// RNS/Transport.py:145-147 draws the same three-way distinction.pub const State = enum(u2) { unknown, unresponsive, responsive,};/// One path the node worked out, holding the announces it has already taken and/// the payload of the latest one.pub const Entry = struct { destination: [16]u8, next_hop: [16]u8, announce_hash: packet.Hash, timestamp: Seconds, expires: Seconds, hops: u8, carrier: carrier.Index, state: State, context_flag: u1, blob_count: u8, blob_next: u8, payload_len: u16, blobs: [random_blobs_max]Blob, payload_bytes: [destination.announce.payload_bytes_max]u8, /// Hands back the announce payload the path kept, and null when that /// payload came in above 465 bytes under a HEADER_1 header and was /// therefore never copied. pub fn announcePayload(self: *const Entry) ?[]const u8 { std.debug.assert(self.payload_len <= self.payload_bytes.len); if (self.payload_len == 0) return null; return self.payload_bytes[0..self.payload_len]; } pub fn holdsBlob(self: *const Entry, blob: Blob) bool { std.debug.assert(self.blob_count <= random_blobs_max); for (self.blobs[0..self.blob_count]) |held| { if (std.mem.eql(u8, &held, &blob)) return true; } return false; } /// Takes the newest emission time among the announces the path stores, /// following Reticulum@1.5.0 RNS/Transport.py:3654-3660. pub fn timebase(self: *const Entry) Seconds { std.debug.assert(self.blob_count <= random_blobs_max); var newest: Seconds = 0; for (self.blobs[0..self.blob_count]) |held| newest = @max(newest, emission(held)); return newest; }};/// Reads bytes 5 through 10 of the announce's random bytes as an emission time,/// following Reticulum@1.5.0 RNS/Transport.py:3650-3651.pub fn emission(blob: Blob) Seconds { return std.mem.readInt(u40, blob[5..10], .big);}/// One announce whose signature has checked out, put forward for the path/// store.pub const Candidate = struct { destination: [16]u8, next_hop: [16]u8, announce_hash: packet.Hash, hops: u8, carrier: carrier.Index, context_flag: u1, blob: Blob, payload: []const u8,};/// Decides whether an announce replaces a path, following Reticulum@1.5.0/// RNS/Transport.py:2137-2213. A destination with no path admits any announce./// An announce at the path's hop count or nearer is taken when the path has not/// seen it before and it was emitted after the path's timebase. A farther/// announce is taken on a path past its week when the path has not seen it/// before. A farther announce emitted after the timebase is taken when the path/// has not seen it before. A farther announce emitted before the timebase is/// refused. On a path marked unresponsive, an announce it has already taken/// still wins the path back, provided that announce is stamped at the same/// instant as the newest one the path holds and comes from further off./// Reticulum@1.5.0 RNS/Transport.py:2208-2212 is the one place a repeat gets/// through.pub fn admits(known: ?*const Entry, candidate: Candidate, now: Seconds) bool { std.debug.assert(candidate.hops <= wire.pathfinder_hops); const entry = known orelse return true; std.debug.assert(std.mem.eql(u8, &entry.destination, &candidate.destination)); const unseen = !entry.holdsBlob(candidate.blob); const emitted = emission(candidate.blob); const base = entry.timebase(); if (candidate.hops <= entry.hops) return unseen and emitted > base; if (now >= entry.expires) return unseen; if (emitted > base) return unseen; if (emitted < base) return false; return entry.state == .unresponsive;}/// Reports whether a path entry still counts. A path stops counting one week/// past the second it was written, the age Reticulum@1.5.0/// RNS/Transport.py:940-943 sets. A zero expiry marks a path that `expire`/// dropped.fn live(entry: *const Entry, now: Seconds) bool { if (entry.expires == 0) return false; return now -| entry.timestamp <= lifetime;}const TableLimits = struct { paths_max: usize,};const TableCapacity = struct { paths_max: usize, storage_bytes: usize, pub const DeriveError = error{ InvalidLimit, CapacityOverflow }; pub fn derive(limits: TableLimits) DeriveError!TableCapacity { if (limits.paths_max == 0) return error.InvalidLimit; const storage_bytes = alloc_phase.capacity.mul( usize, limits.paths_max, @sizeOf(Entry), ) catch return error.CapacityOverflow; return .{ .paths_max = limits.paths_max, .storage_bytes = storage_bytes }; }};/// Paths learned from announces, matching Reticulum@1.5.0/// RNS/Transport.py:2374-2375.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.paths", .kind = .phase_static, .limit_source = .caller, .storage = .{ .covered = &.{.{ .id = "caller_path_table", .lifetime = .transferred, .detail = "caller storage for paths, random blobs, and announce payloads", }}, .excluded = &.{ "borrowed announce payload inputs", "persistent path records", }, }, .capacity = .{ .inputs = &.{alloc_phase.capacity.bindInput( Limits, "paths_max", "paths_max", )}, .type_selectors = &.{alloc_phase.capacity.bindType(Entry, "path")}, .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 path replaces a culled path, else the oldest timestamp", }, .risks = .{ .transitive = .{ .status = .excluded, .detail = "path operations call no allocating owner", }, .foreign = .{ .status = .excluded, .detail = "path storage crosses no foreign boundary", }, }, .work = .{ .equation = "operations scan at most paths_max entries and 64 blobs" }, .obligations = &.{ .{ .key = "reticulum_paths_capacity", .role = .capacity_model }, .{ .key = "reticulum_paths_replace", .role = .overload }, .{ .key = "reticulum_paths_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; } /// Looks a destination up and hands back a path only while that path sits /// inside the one-week age Reticulum@1.5.0 RNS/Transport.py:940-943 sets. pub fn find(self: *Table, hash: [16]u8, now: Seconds) ?*Entry { std.debug.assert(self.phase == .steady); const entry = self.slot(hash) orelse return null; if (!live(entry, now)) return null; return entry; } /// Reports the path hop count, or the pathfinder maximum when the table /// holds no live path, following Reticulum@1.5.0 /// RNS/Transport.py:3063-3070. pub fn hopsTo(self: *Table, hash: [16]u8, now: Seconds) u8 { const entry = self.find(hash, now) orelse return wire.pathfinder_hops; std.debug.assert(entry.hops <= wire.pathfinder_hops); return entry.hops; } /// Records an accepted announce, following Reticulum@1.5.0 /// RNS/Transport.py:2261-2265,2374-2375. An announce that wins back an /// unresponsive path at an emission time the path already holds leaves the /// unresponsive mark standing, so the next announce stamped at that instant /// wins the path in turn. Every other accepted announce clears the mark, /// following Reticulum@1.5.0 RNS/Transport.py:2155,2189,2200,2208-2212. pub fn learn(self: *Table, candidate: Candidate, now: Seconds) *Entry { std.debug.assert(self.phase == .steady); std.debug.assert(candidate.hops <= wire.pathfinder_hops); const previous = self.find(candidate.destination, now); const target = previous orelse self.reclaim(candidate.destination, now); if (previous == null) { target.blob_count = 0; target.blob_next = 0; } const repeats = previous != null and now < target.expires and emission(candidate.blob) == target.timebase(); if (!target.holdsBlob(candidate.blob)) { target.blobs[target.blob_next] = candidate.blob; target.blob_next = (target.blob_next + 1) % random_blobs_max; target.blob_count = @min(target.blob_count + 1, random_blobs_max); } if (!repeats) target.state = .unknown; target.destination = candidate.destination; target.next_hop = candidate.next_hop; target.announce_hash = candidate.announce_hash; target.timestamp = now; target.expires = now +| lifetime; target.hops = candidate.hops; target.carrier = candidate.carrier; target.context_flag = candidate.context_flag; const retained = candidate.payload.len <= target.payload_bytes.len; target.payload_len = if (retained) @intCast(candidate.payload.len) else 0; if (retained) @memcpy(target.payload_bytes[0..candidate.payload.len], candidate.payload); std.debug.assert(self.find(candidate.destination, now) == target); return target; } /// Notes that a link went unanswered over this path, as Reticulum@1.5.0 /// RNS/Transport.py:3157-3162 does. The answer says whether a path to that /// destination was still inside its week. pub fn markUnresponsive(self: *Table, hash: [16]u8, now: Seconds) bool { std.debug.assert(self.phase == .steady); const entry = self.find(hash, now) orelse return false; entry.state = .unresponsive; return true; } /// Throws a path away, leaving its destination open to the next announce /// from any distance. Reticulum@1.5.0 RNS/Transport.py:3146-3154 reaches /// the same end by zeroing the written-at second and running its removal /// pass at once. This port zeroes the expiry because it runs no cull pass. /// The call reports whether the table held a live path. pub fn expire(self: *Table, hash: [16]u8, now: Seconds) bool { std.debug.assert(self.phase == .steady); const entry = self.find(hash, now) orelse return false; entry.timestamp = 0; entry.expires = 0; 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 slot(self: *Table, hash: [16]u8) ?*Entry { var found: ?*Entry = null; for (self.entries[0..self.len]) |*entry| { if (!std.mem.eql(u8, &entry.destination, &hash)) continue; std.debug.assert(found == null); found = entry; } return found; } fn reclaim(self: *Table, hash: [16]u8, now: Seconds) *Entry { if (self.slot(hash)) |culled| return culled; for (self.entries[0..self.len]) |*entry| { if (!live(entry, now)) return entry; } if (self.len < self.capacity.paths_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 blobAt(salt: u8, emitted: Seconds) Blob { var blob: Blob = @splat(salt); std.mem.writeInt(u40, blob[5..10], @intCast(emitted), .big); return blob;}fn offer(destination_byte: u8, hops: u8, blob: Blob) Candidate { return .{ .destination = @splat(destination_byte), .next_hop = @splat(0xb0), .announce_hash = @splat(destination_byte), .hops = hops, .carrier = 1, .context_flag = 0, .blob = blob, .payload = "announce payload", };}test "paths admit maximum and replace the oldest at maximum plus one" { comptime { @stardustClaim(alloc_phase.capacity.witness( Table, "reticulum_paths_capacity", ), null, null, null, null, null, null); @stardustClaim(alloc_phase.capacity.witness( Table, "reticulum_paths_replace", ), null, null, null, null, null, null); @stardustClaim(alloc_phase.capacity.witness( Table, "reticulum_paths_work", ), null, null, null, null, null, null); } const capacity = comptime TableCapacity.derive(.{ .paths_max = 3 }) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, .{ .paths_max = 3 }); table.activate(); defer _ = table.deinit(); for (1..4) |value| { const byte: u8 = @intCast(value); _ = table.learn(offer(byte, 1, blobAt(byte, 100)), 100 + value); } try std.testing.expectEqual(@as(usize, 3), table.count()); _ = table.learn(offer(4, 1, blobAt(4, 200)), 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 "paths reclaim a culled slot before the oldest live path" { const capacity = comptime TableCapacity.derive(.{ .paths_max = 2 }) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, .{ .paths_max = 2 }); table.activate(); defer _ = table.deinit(); _ = table.learn(offer(1, 1, blobAt(1, 1)), 10); _ = table.learn(offer(2, 1, blobAt(2, 1)), 5); const later: Seconds = 10 + lifetime; try std.testing.expect(table.find(@splat(2), later) == null); _ = table.learn(offer(3, 1, blobAt(3, 1)), later); try std.testing.expect(table.find(@splat(1), later) != null); try std.testing.expect(table.find(@splat(3), later) != null); try std.testing.expectEqual(@as(usize, 2), table.count());}test "Reticulum@1.5.0 RNS/Transport.py:2137-2213 path add rules" { const capacity = comptime TableCapacity.derive(.{ .paths_max = 1 }) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, .{ .paths_max = 1 }); table.activate(); defer _ = table.deinit(); const accepted_at: Seconds = 1_000; try std.testing.expect(admits(null, offer(7, 3, blobAt(1, 500)), accepted_at)); const entry = table.learn(offer(7, 3, blobAt(1, 500)), accepted_at); try std.testing.expectEqual(accepted_at + lifetime, entry.expires); try std.testing.expect(admits(entry, offer(7, 3, blobAt(2, 501)), accepted_at)); try std.testing.expect(admits(entry, offer(7, 2, blobAt(2, 501)), accepted_at)); try std.testing.expect(!admits(entry, offer(7, 3, blobAt(1, 500)), accepted_at)); try std.testing.expect(!admits(entry, offer(7, 3, blobAt(2, 500)), accepted_at)); try std.testing.expect(!admits(entry, offer(7, 2, blobAt(2, 499)), accepted_at)); const before = entry.expires - 1; try std.testing.expect(admits(entry, offer(7, 4, blobAt(2, 501)), before)); try std.testing.expect(!admits(entry, offer(7, 4, blobAt(2, 500)), before)); try std.testing.expect(!admits(entry, offer(7, 4, blobAt(2, 499)), before)); try std.testing.expect(admits(entry, offer(7, 4, blobAt(2, 499)), entry.expires)); try std.testing.expect(!admits(entry, offer(7, 4, blobAt(1, 500)), entry.expires));}test "Reticulum@1.5.0 RNS/Transport.py:2263-2265 evicts the oldest of 65 blobs" { const capacity = comptime TableCapacity.derive(.{ .paths_max = 1 }) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, .{ .paths_max = 1 }); table.activate(); defer _ = table.deinit(); const now: Seconds = 5_000; for (0..65) |index| { const offered = offer(9, 1, blobAt(@intCast(index), 1_000 + index)); try std.testing.expect(admits(table.find(offered.destination, now), offered, now)); _ = table.learn(offered, now); } const entry = table.find(@splat(9), now).?; try std.testing.expectEqual(random_blobs_max, entry.blob_count); try std.testing.expect(!entry.holdsBlob(blobAt(0, 1_000))); try std.testing.expect(entry.holdsBlob(blobAt(1, 1_001))); try std.testing.expect(entry.holdsBlob(blobAt(64, 1_064))); try std.testing.expectEqual(@as(Seconds, 1_064), entry.timebase());}test "Reticulum@1.5.0 RNS/Transport.py:940-943 culls a path one second after a week" { const capacity = comptime TableCapacity.derive(.{ .paths_max = 1 }) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, .{ .paths_max = 1 }); table.activate(); defer _ = table.deinit(); _ = table.learn(offer(5, 2, blobAt(5, 10)), 100); try std.testing.expectEqual(@as(u8, 2), table.hopsTo(@splat(5), 100 + lifetime)); const culled_at: Seconds = 100 + lifetime + 1; try std.testing.expect(table.find(@splat(5), culled_at) == null); try std.testing.expectEqual(wire.pathfinder_hops, table.hopsTo(@splat(5), culled_at)); const replay = offer(5, 3, blobAt(5, 10)); try std.testing.expect(admits(table.find(replay.destination, culled_at), replay, culled_at)); const entry = table.learn(replay, culled_at); try std.testing.expectEqual(@as(u8, 1), entry.blob_count); try std.testing.expectEqual(@as(usize, 1), table.count());}test "Reticulum@1.5.0 RNS/Transport.py:2208-2212 an unresponsive path takes its announce again" { const capacity = comptime TableCapacity.derive(.{ .paths_max = 1 }) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, .{ .paths_max = 1 }); table.activate(); defer _ = table.deinit(); const now: Seconds = 1_000; const entry = table.learn(offer(7, 2, blobAt(1, 500)), now); const farther = offer(7, 3, blobAt(1, 500)); try std.testing.expectEqual(State.unknown, entry.state); try std.testing.expect(!admits(entry, farther, now)); try std.testing.expect(table.markUnresponsive(@splat(7), now)); try std.testing.expectEqual(State.unresponsive, entry.state); try std.testing.expect(admits(entry, farther, now)); try std.testing.expect(!admits(entry, offer(7, 2, blobAt(1, 500)), now)); try std.testing.expect(!admits(entry, offer(7, 3, blobAt(2, 499)), now)); try std.testing.expect(admits(entry, offer(7, 3, blobAt(2, 500)), now)); _ = table.learn(farther, now + 1); try std.testing.expectEqual(State.unresponsive, entry.state); try std.testing.expectEqual(@as(u8, 1), entry.blob_count); try std.testing.expectEqual(@as(u8, 3), entry.hops); try std.testing.expect(!admits(entry, farther, now + 1)); try std.testing.expect(admits(entry, offer(7, 4, blobAt(1, 500)), now + 1)); _ = table.learn(offer(7, 3, blobAt(2, 700)), now + 2); try std.testing.expectEqual(State.unknown, entry.state); try std.testing.expect(!admits(entry, offer(7, 4, blobAt(1, 500)), now + 2));}test "Reticulum@1.5.0 RNS/Transport.py:3146-3154 expires a path so any announce replaces it" { const capacity = comptime TableCapacity.derive(.{ .paths_max = 1 }) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, .{ .paths_max = 1 }); table.activate(); defer _ = table.deinit(); const now: Seconds = 1_000; _ = table.learn(offer(7, 1, blobAt(1, 500)), now); try std.testing.expect(table.expire(@splat(7), now)); try std.testing.expect(table.find(@splat(7), now) == null); try std.testing.expect(table.find(@splat(7), now + lifetime + 1) == null); try std.testing.expect(!table.expire(@splat(7), now)); try std.testing.expect(!table.markUnresponsive(@splat(7), now)); try std.testing.expectEqual(wire.pathfinder_hops, table.hopsTo(@splat(7), now)); const older = offer(7, 5, blobAt(2, 1)); try std.testing.expect(admits(table.find(older.destination, now), older, now)); const relearned = table.learn(older, now); try std.testing.expectEqual(@as(u8, 5), relearned.hops); try std.testing.expectEqual(@as(u8, 1), relearned.blob_count); try std.testing.expectEqual(@as(usize, 1), table.count());}test "paths copy announce payloads up to the HEADER_2 relay bound" { const capacity = comptime TableCapacity.derive(.{ .paths_max = 2 }) catch unreachable; var bytes: [capacity.storage_bytes]u8 align(Table.storage_alignment) = undefined; var table = try Table.init(&bytes, .{ .paths_max = 2 }); table.activate(); defer _ = table.deinit(); var long: [destination.announce.payload_bytes_max + 1]u8 = @splat(0x5a); var offered = offer(1, 1, blobAt(1, 1)); offered.payload = long[0..destination.announce.payload_bytes_max]; const kept = table.learn(offered, 1); long[0] = 0; try std.testing.expectEqual(@as(usize, long.len - 1), kept.announcePayload().?.len); try std.testing.expectEqual(@as(u8, 0x5a), kept.announcePayload().?[0]); offered = offer(2, 1, blobAt(2, 1)); offered.payload = &long; const skipped = table.learn(offered, 1); try std.testing.expect(skipped.announcePayload() == null); try std.testing.expectEqual(@as(u8, 1), skipped.hops);}Source: lib/reticulum/src/node/transport/root.zig:107
zig
pub const path = @import("path.zig");Complete caller list for node.transport.path.Table.activate
9 direct callers.
lib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2137-2213_path_add_rules[function] — test source atlib/reticulum/src/node/transport/path.zig:443in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2208-2212_an_unresponsive_path_takes_its_announce_again[function] — test source atlib/reticulum/src/node/transport/path.zig:504in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2263-2265_evicts_the_oldest_of_65_blobs[function] — test source atlib/reticulum/src/node/transport/path.zig:466in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:3146-3154_expires_a_path_so_any_announce_replaces_it[function] — test source atlib/reticulum/src/node/transport/path.zig:532in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:940-943_culls_a_path_one_second_after_a_week[function] — test source atlib/reticulum/src/node/transport/path.zig:486in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_admit_maximum_and_replace_the_oldest_at_maximum_plus_one[function] — test source atlib/reticulum/src/node/transport/path.zig:396in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_copy_announce_payloads_up_to_the_HEADER_2_relay_bound[function] — test source atlib/reticulum/src/node/transport/path.zig:554in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_reclaim_a_culled_slot_before_the_oldest_live_path[function] — test source atlib/reticulum/src/node/transport/path.zig:427in nearest public ownertiny.reticulum.node.transport.pathtiny.reticulum.node.transport.State.activate[method] atlib/reticulum/src/node/transport/state.zig:335
Complete caller list for node.transport.path.Table.deinit
9 direct callers.
lib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2137-2213_path_add_rules[function] — test source atlib/reticulum/src/node/transport/path.zig:443in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2208-2212_an_unresponsive_path_takes_its_announce_again[function] — test source atlib/reticulum/src/node/transport/path.zig:504in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2263-2265_evicts_the_oldest_of_65_blobs[function] — test source atlib/reticulum/src/node/transport/path.zig:466in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:3146-3154_expires_a_path_so_any_announce_replaces_it[function] — test source atlib/reticulum/src/node/transport/path.zig:532in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:940-943_culls_a_path_one_second_after_a_week[function] — test source atlib/reticulum/src/node/transport/path.zig:486in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_admit_maximum_and_replace_the_oldest_at_maximum_plus_one[function] — test source atlib/reticulum/src/node/transport/path.zig:396in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_copy_announce_payloads_up_to_the_HEADER_2_relay_bound[function] — test source atlib/reticulum/src/node/transport/path.zig:554in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_reclaim_a_culled_slot_before_the_oldest_live_path[function] — test source atlib/reticulum/src/node/transport/path.zig:427in nearest public ownertiny.reticulum.node.transport.pathtiny.reticulum.node.transport.State.deinit[method] atlib/reticulum/src/node/transport/state.zig:359
Complete caller list for node.transport.path.Table.find
9 direct callers.
tiny.reticulum.node.transport.path.Table.expire[method] atlib/reticulum/src/node/transport/path.zig:325tiny.reticulum.node.transport.path.Table.hopsTo[method] atlib/reticulum/src/node/transport/path.zig:265tiny.reticulum.node.transport.path.Table.learn[method] atlib/reticulum/src/node/transport/path.zig:277tiny.reticulum.node.transport.path.Table.markUnresponsive[method] atlib/reticulum/src/node/transport/path.zig:313lib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2263-2265_evicts_the_oldest_of_65_blobs[function] — test source atlib/reticulum/src/node/transport/path.zig:466in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:3146-3154_expires_a_path_so_any_announce_replaces_it[function] — test source atlib/reticulum/src/node/transport/path.zig:532in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:940-943_culls_a_path_one_second_after_a_week[function] — test source atlib/reticulum/src/node/transport/path.zig:486in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_admit_maximum_and_replace_the_oldest_at_maximum_plus_one[function] — test source atlib/reticulum/src/node/transport/path.zig:396in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_reclaim_a_culled_slot_before_the_oldest_live_path[function] — test source atlib/reticulum/src/node/transport/path.zig:427in nearest public ownertiny.reticulum.node.transport.path
Complete caller list for node.transport.path.Table.init
9 direct callers.
lib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2137-2213_path_add_rules[function] — test source atlib/reticulum/src/node/transport/path.zig:443in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2208-2212_an_unresponsive_path_takes_its_announce_again[function] — test source atlib/reticulum/src/node/transport/path.zig:504in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2263-2265_evicts_the_oldest_of_65_blobs[function] — test source atlib/reticulum/src/node/transport/path.zig:466in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:3146-3154_expires_a_path_so_any_announce_replaces_it[function] — test source atlib/reticulum/src/node/transport/path.zig:532in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:940-943_culls_a_path_one_second_after_a_week[function] — test source atlib/reticulum/src/node/transport/path.zig:486in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_admit_maximum_and_replace_the_oldest_at_maximum_plus_one[function] — test source atlib/reticulum/src/node/transport/path.zig:396in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_copy_announce_payloads_up_to_the_HEADER_2_relay_bound[function] — test source atlib/reticulum/src/node/transport/path.zig:554in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_reclaim_a_culled_slot_before_the_oldest_live_path[function] — test source atlib/reticulum/src/node/transport/path.zig:427in nearest public ownertiny.reticulum.node.transport.pathtiny.reticulum.node.transport.State.init[function] atlib/reticulum/src/node/transport/state.zig:281
Complete caller list for node.transport.path.Table.learn
8 direct callers.
lib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2137-2213_path_add_rules[function] — test source atlib/reticulum/src/node/transport/path.zig:443in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2208-2212_an_unresponsive_path_takes_its_announce_again[function] — test source atlib/reticulum/src/node/transport/path.zig:504in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:2263-2265_evicts_the_oldest_of_65_blobs[function] — test source atlib/reticulum/src/node/transport/path.zig:466in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:3146-3154_expires_a_path_so_any_announce_replaces_it[function] — test source atlib/reticulum/src/node/transport/path.zig:532in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_Reticulum@1.5.0_RNS/Transport.py:940-943_culls_a_path_one_second_after_a_week[function] — test source atlib/reticulum/src/node/transport/path.zig:486in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_admit_maximum_and_replace_the_oldest_at_maximum_plus_one[function] — test source atlib/reticulum/src/node/transport/path.zig:396in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_copy_announce_payloads_up_to_the_HEADER_2_relay_bound[function] — test source atlib/reticulum/src/node/transport/path.zig:554in nearest public ownertiny.reticulum.node.transport.pathlib.reticulum.src.node.transport.path.test_paths_reclaim_a_culled_slot_before_the_oldest_live_path[function] — test source atlib/reticulum/src/node/transport/path.zig:427in nearest public ownertiny.reticulum.node.transport.path
Audit
| Definitions | 30 |
|---|---|
| Public names | 30 |
| Members | 30 |
| Version | 26.7.0 |
| Revision | daab053ee433 |