• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tari-project / tari / 13391670077

18 Feb 2025 01:27PM UTC coverage: 74.078% (+0.02%) from 74.056%
13391670077

push

github

web-flow
chore: new release v1.11.5-pre.0 (#6804)

Description
---
new release esmeralda

83612 of 112870 relevant lines covered (74.08%)

273393.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.08
/base_layer/core/src/base_node/sync/sync_peer.rs
1
//  Copyright 2020, The Tari Project
2
//
3
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
4
//  following conditions are met:
5
//
6
//  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7
//  disclaimer.
8
//
9
//  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
10
//  following disclaimer in the documentation and/or other materials provided with the distribution.
11
//
12
//  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
13
//  products derived from this software without specific prior written permission.
14
//
15
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
//  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20
//  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
21
//  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22

23
use std::{
24
    cmp::Ordering,
25
    fmt::{Display, Formatter},
26
    time::Duration,
27
};
28

29
use primitive_types::U256;
30
use tari_common_types::chain_metadata::ChainMetadata;
31
use tari_comms::peer_manager::NodeId;
32

33
use crate::{base_node::chain_metadata_service::PeerChainMetadata, common::rolling_avg::RollingAverageTime};
34

35
#[derive(Debug, Clone)]
36
pub struct SyncPeer {
37
    peer_metadata: PeerChainMetadata,
38
    avg_latency: RollingAverageTime,
39
}
40

41
impl SyncPeer {
42
    pub fn node_id(&self) -> &NodeId {
332✔
43
        self.peer_metadata.node_id()
332✔
44
    }
332✔
45

46
    pub fn claimed_chain_metadata(&self) -> &ChainMetadata {
81✔
47
        self.peer_metadata.claimed_chain_metadata()
81✔
48
    }
81✔
49

50
    pub fn claimed_difficulty(&self) -> U256 {
×
51
        self.peer_metadata.claimed_chain_metadata().accumulated_difficulty()
×
52
    }
×
53

54
    pub fn latency(&self) -> Option<Duration> {
87✔
55
        self.peer_metadata.latency()
87✔
56
    }
87✔
57

58
    pub(super) fn set_latency(&mut self, latency: Duration) -> &mut Self {
387✔
59
        self.peer_metadata.set_latency(latency);
387✔
60
        self
387✔
61
    }
387✔
62

63
    pub fn items_per_second(&self) -> Option<f64> {
×
64
        self.avg_latency.calc_samples_per_second()
×
65
    }
×
66

67
    pub(super) fn add_sample(&mut self, time: Duration) -> &mut Self {
371✔
68
        self.avg_latency.add_sample(time);
371✔
69
        self
371✔
70
    }
371✔
71

72
    pub fn calc_avg_latency(&self) -> Option<Duration> {
×
73
        self.avg_latency.calculate_average()
×
74
    }
×
75
}
76

77
impl From<PeerChainMetadata> for SyncPeer {
78
    fn from(peer_metadata: PeerChainMetadata) -> Self {
67✔
79
        Self {
67✔
80
            peer_metadata,
67✔
81
            avg_latency: RollingAverageTime::new(20),
67✔
82
        }
67✔
83
    }
67✔
84
}
85

86
impl Display for SyncPeer {
87
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
×
88
        write!(
×
89
            f,
×
90
            "Node ID: {}, Chain metadata: {}, Latency: {}",
×
91
            self.node_id(),
×
92
            self.claimed_chain_metadata(),
×
93
            self.latency()
×
94
                .map(|d| format!("{:.2?}", d))
×
95
                .unwrap_or_else(|| "--".to_string())
×
96
        )
×
97
    }
×
98
}
99

100
impl PartialEq for SyncPeer {
101
    fn eq(&self, other: &Self) -> bool {
35✔
102
        self.node_id() == other.node_id()
35✔
103
    }
35✔
104
}
105
impl Eq for SyncPeer {}
106

107
impl Ord for SyncPeer {
108
    fn cmp(&self, other: &Self) -> Ordering {
37✔
109
        let mut result = self
37✔
110
            .peer_metadata
37✔
111
            .claimed_chain_metadata()
37✔
112
            .accumulated_difficulty()
37✔
113
            .cmp(&other.peer_metadata.claimed_chain_metadata().accumulated_difficulty());
37✔
114
        if result == Ordering::Equal {
37✔
115
            match (self.latency(), other.latency()) {
37✔
116
                (None, None) => result = Ordering::Equal,
2✔
117
                // No latency goes to the end
118
                (Some(_), None) => result = Ordering::Less,
16✔
119
                (None, Some(_)) => result = Ordering::Greater,
×
120
                (Some(la), Some(lb)) => result = la.cmp(&lb),
19✔
121
            }
122
        }
×
123
        result
37✔
124
    }
37✔
125
}
126

127
impl PartialOrd for SyncPeer {
128
    fn partial_cmp(&self, other: &SyncPeer) -> Option<Ordering> {
37✔
129
        Some(self.cmp(other))
37✔
130
    }
37✔
131
}
132

133
#[cfg(test)]
134
mod test {
135
    use std::time::Duration;
136

137
    use rand::rngs::OsRng;
138
    use tari_common_types::chain_metadata::ChainMetadata;
139

140
    use super::*;
141

142
    mod sort_by_latency {
143
        use tari_common_types::types::FixedHash;
144
        use tari_comms::types::{CommsPublicKey, CommsSecretKey};
145
        use tari_crypto::keys::SecretKey;
146

147
        use super::*;
148

149
        // Helper function to generate a peer with a given latency
150
        fn generate_peer(latency: Option<usize>) -> SyncPeer {
13✔
151
            let sk = CommsSecretKey::random(&mut OsRng);
13✔
152
            let pk = CommsPublicKey::from_secret_key(&sk);
13✔
153
            let node_id = NodeId::from_key(&pk);
13✔
154
            let latency_option = latency.map(|latency| Duration::from_millis(latency as u64));
13✔
155
            PeerChainMetadata::new(
13✔
156
                node_id,
13✔
157
                ChainMetadata::new(0, FixedHash::zero(), 0, 0, 1.into(), 0).unwrap(),
13✔
158
                latency_option,
13✔
159
            )
13✔
160
            .into()
13✔
161
        }
13✔
162

163
        #[test]
164
        fn it_sorts_by_latency() {
1✔
165
            const DISTINCT_LATENCY: usize = 5;
1✔
166

1✔
167
            // Generate a list of peers with latency, adding duplicates
1✔
168
            let mut peers = (0..2 * DISTINCT_LATENCY)
1✔
169
                .map(|latency| generate_peer(Some(latency % DISTINCT_LATENCY)))
10✔
170
                .collect::<Vec<SyncPeer>>();
1✔
171

1✔
172
            // Add peers with no latency in a few places
1✔
173
            peers.insert(0, generate_peer(None));
1✔
174
            peers.insert(DISTINCT_LATENCY, generate_peer(None));
1✔
175
            peers.push(generate_peer(None));
1✔
176

1✔
177
            // Sort the list; because difficulty is identical, it should sort by latency
1✔
178
            peers.sort();
1✔
179

180
            // Confirm that the sorted latency is correct: numerical ordering, then `None`
181
            for (i, peer) in peers[..2 * DISTINCT_LATENCY].iter().enumerate() {
10✔
182
                assert_eq!(peer.latency(), Some(Duration::from_millis((i as u64) / 2)));
10✔
183
            }
184
            for _ in 0..3 {
4✔
185
                assert_eq!(peers.pop().unwrap().latency(), None);
3✔
186
            }
187
        }
1✔
188
    }
189
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc