Skip to main content

evmlib/
quoting_metrics.rs

1// Copyright 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9use crate::common::U256;
10use serde::{Deserialize, Serialize};
11use std::fmt::{Debug, Formatter, Result as FmtResult};
12
13/// Quoting metrics used to generate a quote, or to track peer's status.
14#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
15pub struct QuotingMetrics {
16    /// DataTypes presented as its `index`
17    pub data_type: u32,
18    /// data size of the record
19    pub data_size: usize,
20    /// the records stored
21    pub close_records_stored: usize,
22    /// each entry to be `(data_type_index, num_of_records_of_that_type)`
23    pub records_per_type: Vec<(u32, u32)>,
24    /// number of times that got paid
25    pub received_payment_count: usize,
26    /// the duration that node keeps connected to the network, measured in hours
27    pub live_time: u64,
28    /// network density from this node's perspective, which is the responsible_range as well
29    /// This could be calculated via sampling, or equation calculation.
30    pub network_density: Option<[u8; 32]>,
31    /// estimated network size
32    pub network_size: Option<u64>,
33}
34
35impl Debug for QuotingMetrics {
36    fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
37        let density_u256 = self.network_density.map(U256::from_be_bytes);
38
39        write!(
40            formatter,
41            "QuotingMetrics {{ data_type: {}, data_size: {}, close_records_stored: {}, records_per_type {:?}, received_payment_count: {}, live_time: {}, network_density: {density_u256:?}, network_size: {:?} }}",
42            self.data_type,
43            self.data_size,
44            self.close_records_stored,
45            self.records_per_type,
46            self.received_payment_count,
47            self.live_time,
48            self.network_size
49        )
50    }
51}
52
53impl QuotingMetrics {
54    /// Convert to deterministic byte representation for hashing
55    ///
56    /// Uses fixed-width encoding (u64) for all numeric fields to ensure
57    /// architecture-independent serialization across 32-bit and 64-bit platforms.
58    pub fn to_bytes(&self) -> Vec<u8> {
59        let mut bytes = Vec::new();
60
61        bytes.extend_from_slice(&self.data_type.to_le_bytes());
62        bytes.extend_from_slice(&(self.data_size as u64).to_le_bytes());
63        bytes.extend_from_slice(&(self.close_records_stored as u64).to_le_bytes());
64        bytes.extend_from_slice(&(self.records_per_type.len() as u32).to_le_bytes());
65        for (dtype, count) in &self.records_per_type {
66            bytes.extend_from_slice(&dtype.to_le_bytes());
67            bytes.extend_from_slice(&count.to_le_bytes());
68        }
69        bytes.extend_from_slice(&(self.received_payment_count as u64).to_le_bytes());
70        bytes.extend_from_slice(&self.live_time.to_le_bytes());
71        if let Some(density) = &self.network_density {
72            bytes.push(1); // Option::Some marker
73            bytes.extend_from_slice(density);
74        } else {
75            bytes.push(0); // Option::None marker
76        }
77        if let Some(size) = self.network_size {
78            bytes.push(1); // Option::Some marker
79            bytes.extend_from_slice(&size.to_le_bytes());
80        } else {
81            bytes.push(0); // Option::None marker
82        }
83
84        bytes
85    }
86}