Skip to main content

amaru_protocols/handshake/
mod.rs

1// Copyright 2025 PRAGMA
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod initiator;
16mod messages;
17mod responder;
18#[cfg(test)]
19mod tests;
20
21use amaru_kernel::NetworkMagic;
22pub use messages::Message;
23
24use crate::{
25    protocol::{ProtoSpec, ProtocolState, Role, RoleT},
26    protocol_messages::{
27        handshake::{HandshakeResult, RefuseReason},
28        version_data::{PEER_SHARING_DISABLED, VersionData},
29        version_number::VersionNumber,
30        version_table::VersionTable,
31    },
32};
33
34pub fn register_deserializers() -> pure_stage::DeserializerGuards {
35    vec![initiator::register_deserializers(), responder::register_deserializers()].into_iter().flatten().collect()
36}
37
38#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
39pub enum State {
40    Propose,
41    Confirm,
42    Done,
43}
44
45// Re-export types
46pub use initiator::{HandshakeInitiator, initiator};
47pub use responder::{HandshakeResponder, responder};
48
49// FIXME: proper implementation of network spec needed
50pub fn compute_negotiation_result(
51    _role: Role,
52    ours: VersionTable<VersionData>,
53    theirs: VersionTable<VersionData>,
54) -> HandshakeResult {
55    use crate::protocol_messages::handshake::RefuseReason;
56    let mut their_versions = theirs.values.keys().collect::<Vec<_>>();
57    their_versions.sort();
58    their_versions.reverse();
59    for their_version in their_versions {
60        if let Some(our_version) = ours.values.get(their_version) {
61            return HandshakeResult::Accepted(*their_version, our_version.clone());
62        }
63    }
64    HandshakeResult::Refused(RefuseReason::VersionMismatch(ours.values.keys().copied().collect()))
65}
66
67pub fn spec<R: RoleT>() -> ProtoSpec<State, Message<VersionData>, R>
68where
69    State: ProtocolState<R, WireMsg = Message<VersionData>>,
70{
71    use State::*;
72
73    let mut spec = ProtoSpec::default();
74
75    let propose = || Message::Propose(VersionTable::empty());
76    let accept = || {
77        Message::Accept(
78            VersionNumber::V14,
79            VersionData::new(NetworkMagic::MAINNET, false, PEER_SHARING_DISABLED, false),
80        )
81    };
82    let refuse = || Message::Refuse(RefuseReason::VersionMismatch(vec![VersionNumber::V14]));
83    let query_reply = || Message::QueryReply(VersionTable::empty());
84
85    spec.init(Propose, propose(), Confirm);
86    spec.sim_open(Confirm, propose(), Done);
87    spec.resp(Confirm, accept(), Done);
88    spec.resp(Confirm, refuse(), Done);
89    spec.resp(Confirm, query_reply(), Done);
90    spec
91}