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    /// the max_records configured
25    pub max_records: usize,
26    /// number of times that got paid
27    pub received_payment_count: usize,
28    /// the duration that node keeps connected to the network, measured in hours
29    pub live_time: u64,
30    /// network density from this node's perspective, which is the responsible_range as well
31    /// This could be calculated via sampling, or equation calculation.
32    pub network_density: Option<[u8; 32]>,
33    /// estimated network size
34    pub network_size: Option<u64>,
35}
36
37impl Debug for QuotingMetrics {
38    fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
39        let density_u256 = self.network_density.map(U256::from_be_bytes);
40
41        write!(
42            formatter,
43            "QuotingMetrics {{ data_type: {}, data_size: {}, close_records_stored: {}, records_per_type {:?}, max_records: {}, received_payment_count: {}, live_time: {}, network_density: {density_u256:?}, network_size: {:?} }}",
44            self.data_type,
45            self.data_size,
46            self.close_records_stored,
47            self.records_per_type,
48            self.max_records,
49            self.received_payment_count,
50            self.live_time,
51            self.network_size
52        )
53    }
54}
55
56impl QuotingMetrics {
57    /// Convert to deterministic byte representation for hashing
58    ///
59    /// Uses fixed-width encoding (u64) for all numeric fields to ensure
60    /// architecture-independent serialization across 32-bit and 64-bit platforms.
61    pub fn to_bytes(&self) -> Vec<u8> {
62        let mut bytes = Vec::new();
63
64        bytes.extend_from_slice(&self.data_type.to_le_bytes());
65        bytes.extend_from_slice(&(self.data_size as u64).to_le_bytes());
66        bytes.extend_from_slice(&(self.close_records_stored as u64).to_le_bytes());
67        bytes.extend_from_slice(&(self.records_per_type.len() as u32).to_le_bytes());
68        for (dtype, count) in &self.records_per_type {
69            bytes.extend_from_slice(&dtype.to_le_bytes());
70            bytes.extend_from_slice(&count.to_le_bytes());
71        }
72        bytes.extend_from_slice(&(self.max_records as u64).to_le_bytes());
73        bytes.extend_from_slice(&(self.received_payment_count as u64).to_le_bytes());
74        bytes.extend_from_slice(&self.live_time.to_le_bytes());
75        if let Some(density) = &self.network_density {
76            bytes.push(1); // Option::Some marker
77            bytes.extend_from_slice(density);
78        } else {
79            bytes.push(0); // Option::None marker
80        }
81        if let Some(size) = self.network_size {
82            bytes.push(1); // Option::Some marker
83            bytes.extend_from_slice(&size.to_le_bytes());
84        } else {
85            bytes.push(0); // Option::None marker
86        }
87
88        bytes
89    }
90}