snarkos_node_router_messages/
disconnect.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkOS library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18use snarkvm::prelude::{FromBytes, ToBytes};
19
20use std::borrow::Cow;
21
22#[derive(Copy, Clone, Debug, PartialEq, Eq)]
23pub struct Disconnect {
24    pub reason: DisconnectReason,
25}
26
27impl From<DisconnectReason> for Disconnect {
28    fn from(reason: DisconnectReason) -> Self {
29        Self { reason }
30    }
31}
32
33impl MessageTrait for Disconnect {
34    /// Returns the message name.
35    #[inline]
36    fn name(&self) -> Cow<'static, str> {
37        "Disconnect".into()
38    }
39}
40
41impl ToBytes for Disconnect {
42    fn write_le<W: io::Write>(&self, writer: W) -> io::Result<()> {
43        self.reason.write_le(writer)
44    }
45}
46
47impl FromBytes for Disconnect {
48    fn read_le<R: io::Read>(mut reader: R) -> io::Result<Self> {
49        Ok(Disconnect { reason: DisconnectReason::read_le(&mut reader)? })
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use crate::{Disconnect, DisconnectReason};
56    use snarkvm::{
57        console::prelude::{FromBytes, ToBytes},
58        prelude::{Rng, TestRng},
59    };
60
61    use bytes::{Buf, BufMut, BytesMut};
62
63    #[test]
64    fn disconnect_roundtrip() {
65        // TODO switch to an iteration method that doesn't require manually updating this vec if variants are added
66        let all_reasons = [
67            DisconnectReason::ExceededForkRange,
68            DisconnectReason::InvalidChallengeResponse,
69            DisconnectReason::InvalidForkDepth,
70            DisconnectReason::INeedToSyncFirst,
71            DisconnectReason::NoReasonGiven,
72            DisconnectReason::ProtocolViolation,
73            DisconnectReason::OutdatedClientVersion,
74            DisconnectReason::PeerHasDisconnected,
75            DisconnectReason::PeerRefresh,
76            DisconnectReason::ShuttingDown,
77            DisconnectReason::SyncComplete,
78            DisconnectReason::TooManyFailures,
79            DisconnectReason::TooManyPeers,
80            DisconnectReason::YouNeedToSyncFirst,
81            DisconnectReason::YourPortIsClosed(TestRng::default().r#gen()),
82        ];
83
84        for reason in all_reasons.iter() {
85            let disconnect = Disconnect::from(*reason);
86            let mut buf = BytesMut::default().writer();
87            Disconnect::write_le(&disconnect, &mut buf).unwrap();
88
89            let disconnect = Disconnect::read_le(buf.into_inner().reader()).unwrap();
90            assert_eq!(reason, &disconnect.reason);
91        }
92    }
93
94    #[test]
95    #[should_panic]
96    fn disconnect_invalid_data_panics() {
97        let mut buf = BytesMut::default().writer();
98        "not a DisconnectReason-value".as_bytes().write_le(&mut buf).unwrap();
99        let _disconnect = Disconnect::read_le(buf.into_inner().reader()).unwrap();
100    }
101}