Skip to main content

rns_hooks_abi/
context.rs

1/// Base address in WASM linear memory where the host writes context.
2pub const ARENA_BASE: usize = 0x1000;
3
4/// Context type discriminants.
5pub const CTX_TYPE_PACKET: u32 = 0;
6pub const CTX_TYPE_INTERFACE: u32 = 1;
7pub const CTX_TYPE_TICK: u32 = 2;
8pub const CTX_TYPE_ANNOUNCE: u32 = 3;
9pub const CTX_TYPE_LINK: u32 = 4;
10pub const CTX_TYPE_BACKBONE_PEER: u32 = 5;
11
12/// Read the context type discriminant from an arena pointer.
13///
14/// # Safety
15/// `ptr` must point to a valid arena context written by the host.
16pub unsafe fn context_type(ptr: *const u8) -> u32 {
17    (ptr as *const u32).read()
18}
19
20/// Packet context layout — matches host `ArenaPacket` byte-for-byte.
21#[repr(C)]
22pub struct PacketContext {
23    pub context_type: u32,
24    pub flags: u8,
25    pub hops: u8,
26    _pad: [u8; 2],
27    pub destination_hash: [u8; 16],
28    pub context: u8,
29    _pad2: [u8; 3],
30    pub packet_hash: [u8; 32],
31    _pad3: u32,
32    pub interface_id: u64,
33    pub data_offset: u32,
34    pub data_len: u32,
35}
36
37/// Interface context layout — matches host `ArenaInterface`.
38#[repr(C)]
39pub struct InterfaceContext {
40    pub context_type: u32,
41    _pad: u32,
42    pub interface_id: u64,
43}
44
45/// Tick context layout — matches host `ArenaTick`.
46#[repr(C)]
47pub struct TickContext {
48    pub context_type: u32,
49}
50
51/// Announce context layout — matches host `ArenaAnnounce`.
52#[repr(C)]
53pub struct AnnounceContext {
54    pub context_type: u32,
55    pub hops: u8,
56    _pad: [u8; 3],
57    pub destination_hash: [u8; 16],
58    pub interface_id: u64,
59}
60
61/// Link context layout — matches host `ArenaLink`.
62#[repr(C)]
63pub struct LinkContext {
64    pub context_type: u32,
65    _pad: u32,
66    pub link_id: [u8; 16],
67    pub interface_id: u64,
68}
69
70/// Backbone peer lifecycle context layout — matches host `ArenaBackbonePeer`.
71#[repr(C, packed)]
72#[derive(Clone, Copy)]
73pub struct BackbonePeerContext {
74    pub context_type: u32,
75    pub peer_ip_family: u8,
76    pub peer_port: u16,
77    pub had_received_data: u8,
78    pub server_interface_id: u64,
79    pub peer_interface_id: u64,
80    pub connected_for_secs: u64,
81    pub penalty_level: u8,
82    _pad: [u8; 7],
83    pub blacklist_for_secs: u64,
84    pub peer_ip: [u8; 16],
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    fn write_u16(data: &mut [u8], offset: usize, value: u16) {
92        data[offset..offset + 2].copy_from_slice(&value.to_le_bytes());
93    }
94
95    fn write_u32(data: &mut [u8], offset: usize, value: u32) {
96        data[offset..offset + 4].copy_from_slice(&value.to_le_bytes());
97    }
98
99    fn write_u64(data: &mut [u8], offset: usize, value: u64) {
100        data[offset..offset + 8].copy_from_slice(&value.to_le_bytes());
101    }
102
103    #[test]
104    fn backbone_peer_context_matches_host_layout() {
105        assert_eq!(core::mem::size_of::<BackbonePeerContext>(), 64);
106        let mut raw = [0u8; 64];
107        write_u32(&mut raw, 0, CTX_TYPE_BACKBONE_PEER);
108        raw[4] = 4;
109        write_u16(&mut raw, 5, 4242);
110        raw[7] = 1;
111        write_u64(&mut raw, 8, 11);
112        write_u64(&mut raw, 16, 22);
113        write_u64(&mut raw, 24, 33);
114        raw[32] = 4;
115        write_u64(&mut raw, 40, 44);
116        raw[48..64].copy_from_slice(&[172, 20, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
117
118        let ctx = unsafe { core::ptr::read_unaligned(raw.as_ptr() as *const BackbonePeerContext) };
119        let context_type = ctx.context_type;
120        let peer_ip_family = ctx.peer_ip_family;
121        let peer_port = ctx.peer_port;
122        let had_received_data = ctx.had_received_data;
123        let server_interface_id = ctx.server_interface_id;
124        let peer_interface_id = ctx.peer_interface_id;
125        let connected_for_secs = ctx.connected_for_secs;
126        let penalty_level = ctx.penalty_level;
127        let blacklist_for_secs = ctx.blacklist_for_secs;
128        let peer_ip = ctx.peer_ip;
129
130        assert_eq!(context_type, CTX_TYPE_BACKBONE_PEER);
131        assert_eq!(peer_ip_family, 4);
132        assert_eq!(peer_port, 4242);
133        assert_eq!(had_received_data, 1);
134        assert_eq!(server_interface_id, 11);
135        assert_eq!(peer_interface_id, 22);
136        assert_eq!(connected_for_secs, 33);
137        assert_eq!(penalty_level, 4);
138        assert_eq!(blacklist_for_secs, 44);
139        assert_eq!(peer_ip[0..4], [172, 20, 0, 3]);
140    }
141}