/ node / router / messages / src / ping.rs
ping.rs
  1  // Copyright (c) 2025 ADnet Contributors
  2  // This file is part of the AlphaOS 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  
 16  use super::*;
 17  
 18  use alphaos_node_network::NodeType;
 19  use alphavm::prelude::{FromBytes, ToBytes};
 20  
 21  use std::borrow::Cow;
 22  
 23  #[derive(Clone, Debug, PartialEq, Eq)]
 24  pub struct Ping<N: Network> {
 25      pub version: u32,
 26      pub node_type: NodeType,
 27      pub block_locators: Option<BlockLocators<N>>,
 28  }
 29  
 30  impl<N: Network> MessageTrait for Ping<N> {
 31      /// Returns the message name.
 32      #[inline]
 33      fn name(&self) -> Cow<'static, str> {
 34          "Ping".into()
 35      }
 36  }
 37  
 38  impl<N: Network> ToBytes for Ping<N> {
 39      fn write_le<W: io::Write>(&self, mut writer: W) -> io::Result<()> {
 40          self.version.write_le(&mut writer)?;
 41          self.node_type.write_le(&mut writer)?;
 42          if let Some(locators) = &self.block_locators {
 43              1u8.write_le(&mut writer)?;
 44              locators.write_le(&mut writer)?;
 45          } else {
 46              0u8.write_le(&mut writer)?;
 47          }
 48  
 49          Ok(())
 50      }
 51  }
 52  
 53  impl<N: Network> FromBytes for Ping<N> {
 54      fn read_le<R: io::Read>(mut reader: R) -> io::Result<Self> {
 55          let version = u32::read_le(&mut reader)?;
 56          let node_type = NodeType::read_le(&mut reader)?;
 57  
 58          let selector = u8::read_le(&mut reader)?;
 59          let block_locators = match selector {
 60              0 => None,
 61              1 => Some(BlockLocators::read_le(&mut reader)?),
 62              _ => return Err(error("Invalid block locators marker")),
 63          };
 64  
 65          Ok(Self { version, node_type, block_locators })
 66      }
 67  }
 68  
 69  impl<N: Network> Ping<N> {
 70      pub fn new(node_type: NodeType, block_locators: Option<BlockLocators<N>>) -> Self {
 71          Self { version: <Message<N>>::latest_message_version(), node_type, block_locators }
 72      }
 73  }
 74  
 75  #[cfg(test)]
 76  pub mod prop_tests {
 77      use crate::{Ping, challenge_request::prop_tests::any_node_type};
 78      use alphaos_node_sync_locators::{BlockLocators, test_helpers::sample_block_locators};
 79      use alphavm::utilities::{FromBytes, ToBytes};
 80  
 81      use bytes::{Buf, BufMut, BytesMut};
 82      use proptest::prelude::{BoxedStrategy, Strategy, any};
 83      use test_strategy::proptest;
 84  
 85      type CurrentNetwork = alphavm::prelude::MainnetV0;
 86  
 87      pub fn any_block_locators() -> BoxedStrategy<BlockLocators<CurrentNetwork>> {
 88          any::<u32>().prop_map(sample_block_locators).boxed()
 89      }
 90  
 91      pub fn any_ping() -> BoxedStrategy<Ping<CurrentNetwork>> {
 92          (any::<u32>(), any_block_locators(), any_node_type())
 93              .prop_map(|(version, bls, node_type)| Ping { version, block_locators: Some(bls), node_type })
 94              .boxed()
 95      }
 96  
 97      #[proptest]
 98      fn ping_roundtrip(#[strategy(any_ping())] ping: Ping<CurrentNetwork>) {
 99          let mut bytes = BytesMut::default().writer();
100          ping.write_le(&mut bytes).unwrap();
101          let decoded = Ping::<CurrentNetwork>::read_le(&mut bytes.into_inner().reader()).unwrap();
102          assert_eq!(ping, decoded);
103      }
104  }