Skip to main content

rings_node/onion/circuit/
protocol.rs

1use super::codec::decode_event;
2use super::codec::OnionCircuitEvent;
3use super::reducer::OnionCircuitEffect;
4use super::reducer::OnionCircuitReducer;
5use super::reducer::OnionCircuitState;
6use super::ONION_CIRCUIT_NAMESPACE;
7use crate::extension::ext::Ctx;
8use crate::extension::ext::Protocol;
9use crate::extension::ext::Reject;
10use crate::extension::ext::Transition;
11use crate::extension::ext::Wire;
12
13/// Capabilities this node enables for the onion circuit data plane.
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub enum OnionCircuitCapabilities {
16    /// This node only creates client circuits.
17    Client,
18    /// This node forwards relay layers but does not execute exit payloads.
19    Relay,
20    /// This node executes exit payloads but does not forward relay layers.
21    Exit,
22    /// This node can both relay and execute exit payloads.
23    RelayAndExit,
24}
25
26impl OnionCircuitCapabilities {
27    /// Build capabilities from the node's advertised relay flag and installed exit service.
28    pub const fn from_registration(relay: bool, exit: bool) -> Self {
29        match (relay, exit) {
30            (false, false) => Self::Client,
31            (true, false) => Self::Relay,
32            (false, true) => Self::Exit,
33            (true, true) => Self::RelayAndExit,
34        }
35    }
36
37    /// Build capabilities for a client-only node.
38    pub const fn client() -> Self {
39        Self::Client
40    }
41
42    /// Build capabilities for a relay-only node.
43    pub const fn relay() -> Self {
44        Self::Relay
45    }
46
47    /// Build capabilities for an exit-only node.
48    pub const fn exit() -> Self {
49        Self::Exit
50    }
51
52    pub(super) const fn accepts_forward_layers(self) -> bool {
53        matches!(self, Self::Relay | Self::Exit | Self::RelayAndExit)
54    }
55
56    pub(super) const fn permits_relay_layer(self) -> bool {
57        matches!(self, Self::Relay | Self::RelayAndExit)
58    }
59
60    pub(super) const fn permits_exit_layer(self) -> bool {
61        matches!(self, Self::Exit | Self::RelayAndExit)
62    }
63}
64
65/// Encrypted onion circuit protocol.
66#[derive(Clone, Debug)]
67pub struct OnionCircuitProtocol {
68    reducer: OnionCircuitReducer,
69}
70
71impl OnionCircuitProtocol {
72    /// Create a protocol instance over explicit onion circuit capabilities.
73    pub fn new(capabilities: OnionCircuitCapabilities) -> Self {
74        Self {
75            reducer: OnionCircuitReducer::new(capabilities),
76        }
77    }
78}
79
80impl Protocol for OnionCircuitProtocol {
81    type State = OnionCircuitState;
82    type Event = OnionCircuitEvent;
83    type Effect = OnionCircuitEffect;
84
85    fn namespace(&self) -> &str {
86        ONION_CIRCUIT_NAMESPACE
87    }
88
89    fn init(&self) -> Self::State {
90        OnionCircuitState::default()
91    }
92
93    fn decode(&self, wire: Wire<'_>) -> std::result::Result<Self::Event, Reject> {
94        decode_event(wire)
95    }
96
97    fn step(
98        &self,
99        ctx: Ctx<'_, Self::State>,
100        event: Self::Event,
101    ) -> Transition<Self::State, Self::Effect> {
102        self.reducer.apply(ctx.state, event.input)
103    }
104}