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

ergoplatform / sigma-rust / 16405540612

20 Jul 2025 11:50PM UTC coverage: 78.438% (-0.01%) from 78.451%
16405540612

Pull #790

github

web-flow
Merge 7bd76aff4 into 2725f402c
Pull Request #790: Use precomputed tables

62 of 69 new or added lines in 16 files covered. (89.86%)

10 existing lines in 5 files now uncovered.

11961 of 15249 relevant lines covered (78.44%)

2.94 hits per line

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

78.13
/ergo-p2p/src/peer_spec.rs
1
//! PeerSpec types
2
use std::io;
3

4
use bounded_vec::BoundedVec;
5
use ergo_chain_types::PeerAddr;
6
use sigma_ser::vlq_encode::VlqEncodingError;
7
use sigma_ser::{ScorexParsingError, ScorexSerializable, ScorexSerializeResult};
8

9
use crate::{peer_feature::PeerFeature, protocol_version::ProtocolVersion};
10

11
type PeerFeatures = BoundedVec<PeerFeature, 1, { u8::MAX as usize }>;
12

13
/// PeerSpec
14
#[derive(PartialEq, Eq, Debug, Clone, Hash)]
15
pub struct PeerSpec {
16
    agent_name: String,
17
    protocol_version: ProtocolVersion,
18
    node_name: String,
19
    declared_addr: Option<PeerAddr>,
20
    features: Option<PeerFeatures>,
21
}
22

23
impl PeerSpec {
24
    /// Create new PeerSpec instance
25
    pub fn new(
3✔
26
        agent_name: &str,
27
        protocol_version: ProtocolVersion,
28
        node_name: &str,
29
        declared_addr: Option<PeerAddr>,
30
        features: Option<PeerFeatures>,
31
    ) -> Self {
32
        Self {
33
            agent_name: agent_name.into(),
1✔
34
            protocol_version,
35
            node_name: node_name.into(),
3✔
36
            declared_addr,
37
            features,
38
        }
39
    }
40

41
    /// Local address of the peer if the peer is using the LocalAddress feature
42
    pub fn local_addr(&self) -> Option<PeerAddr> {
1✔
43
        Some(PeerAddr::from(
1✔
44
            self.features
2✔
45
                .as_ref()?
46
                .iter()
47
                .find_map(PeerFeature::as_local_addr)?
48
                .to_owned(),
49
        ))
50
    }
51

52
    /// Returns true if the peer is reachable
53
    pub fn reachable_peer(&self) -> bool {
×
54
        self.addr().is_some()
×
55
    }
56

57
    /// The address of the peer
58
    /// Returns either the declared address or local address if either are valid
59
    pub fn addr(&self) -> Option<PeerAddr> {
3✔
60
        self.declared_addr.or_else(|| self.local_addr())
6✔
61
    }
62
}
63

64
impl ScorexSerializable for PeerSpec {
65
    fn scorex_serialize<W: sigma_ser::vlq_encode::WriteSigmaVlqExt>(
1✔
66
        &self,
67
        w: &mut W,
68
    ) -> ScorexSerializeResult {
69
        w.put_short_string(&self.agent_name)?;
1✔
70
        self.protocol_version.scorex_serialize(w)?;
1✔
71
        w.put_short_string(&self.node_name)?;
1✔
72

73
        w.put_option(
1✔
74
            self.declared_addr,
1✔
75
            |w: &mut W, addr: PeerAddr| -> io::Result<()> {
1✔
76
                w.put_u8(addr.ip_size() as u8)?;
1✔
77
                addr.scorex_serialize(w)?;
1✔
78

79
                Ok(())
1✔
80
            },
81
        )?;
82

83
        if let Some(feats) = &self.features {
1✔
84
            w.put_u8(feats.len() as u8)?;
1✔
85
            feats.iter().try_for_each(|f| f.scorex_serialize(w))?;
3✔
86
        } else {
87
            w.put_u8(0)?;
1✔
88
        }
89

90
        Ok(())
1✔
91
    }
92

93
    fn scorex_parse<R: sigma_ser::vlq_encode::ReadSigmaVlqExt>(
1✔
94
        r: &mut R,
95
    ) -> Result<Self, ScorexParsingError> {
96
        let agent_name = r.get_short_string()?;
1✔
97

98
        if agent_name.is_empty() {
2✔
99
            return Err(ScorexParsingError::Io("agent name cannot be empty".into()));
×
100
        }
101

102
        let version = ProtocolVersion::scorex_parse(r)?;
2✔
103
        let node_name = r.get_short_string()?;
1✔
104
        let declared_addr: Option<PeerAddr> =
3✔
105
            r.get_option(|r: &mut R| -> Result<_, ScorexParsingError> {
×
106
                // read the size bytes
107
                // not used at the moment because PeerAddr is currently ipv4/4 bytes
108
                r.get_u8()?;
1✔
109
                let addr =
×
110
                    PeerAddr::scorex_parse(r).map_err(|_| VlqEncodingError::VlqDecodingFailed)?;
1✔
111

112
                Ok(addr)
1✔
113
            })?;
114

115
        let feat_len = r.get_u8()?;
1✔
116
        let features = match feat_len {
1✔
117
            0 => None,
1✔
118
            n => {
×
119
                let mut f: Vec<PeerFeature> = Vec::with_capacity(n as usize);
2✔
120
                for _ in 0..n {
2✔
121
                    f.push(PeerFeature::scorex_parse(r)?);
2✔
122
                }
123
                Some(BoundedVec::from_vec(f)?)
1✔
124
            }
125
        };
126

127
        Ok(PeerSpec::new(
1✔
128
            &agent_name,
1✔
129
            version,
×
130
            &node_name,
1✔
131
            declared_addr,
×
132
            features,
1✔
133
        ))
134
    }
135
}
136

137
/// Arbitrary
138
#[cfg(feature = "arbitrary")]
139
#[allow(clippy::unwrap_used, clippy::panic)]
140
pub mod arbitrary {
141
    use super::*;
142
    use proptest::prelude::{Arbitrary, BoxedStrategy};
143
    use proptest::test_runner::TestRunner;
144
    use proptest::{collection::vec, option, prelude::*};
145

146
    impl Arbitrary for PeerSpec {
147
        type Parameters = ();
148
        type Strategy = BoxedStrategy<Self>;
149

150
        fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
4✔
151
            (
152
                any::<ProtocolVersion>(),
4✔
153
                option::of(any::<PeerAddr>()),
8✔
154
                option::of(vec(any::<PeerFeature>(), 1..4)),
8✔
155
            )
156
                .prop_map(|(version, declared_addr, features)| {
4✔
157
                    let feats = features.map(|f| BoundedVec::from_vec(f).unwrap());
3✔
158

159
                    PeerSpec::new(
2✔
160
                        "/Ergo-Scala-client:2.0.0(iPad; U; CPU OS 3_2_1)/AndroidBuild:0.8/",
161
                        version,
162
                        "Testing node",
163
                        declared_addr,
164
                        feats,
165
                    )
166
                })
167
                .boxed()
168
        }
169
    }
170

171
    impl PeerSpec {
172
        /// Ensure the PeerSpec has a valid addr
173
        /// This can happen if declared_addr is none and there is no LocalAddressPeerFeature in features
UNCOV
174
        pub fn with_ensured_addr(mut self) -> Self {
×
UNCOV
175
            if self.addr().is_none() {
×
UNCOV
176
                let mut runner = TestRunner::default();
×
UNCOV
177
                self.declared_addr =
×
UNCOV
178
                    Some(any::<PeerAddr>().new_tree(&mut runner).unwrap().current());
×
179
            }
UNCOV
180
            self
×
181
        }
182
    }
183
}
184

185
#[allow(clippy::panic)]
186
#[allow(clippy::unwrap_used)]
187
#[cfg(test)]
188
#[cfg(feature = "arbitrary")]
189
mod tests {
190
    use super::*;
191
    use proptest::prelude::*;
192
    use sigma_ser::scorex_serialize_roundtrip;
193

194
    proptest! {
195
        #![proptest_config(ProptestConfig::with_cases(64))]
196

197
        #[test]
198
        fn ser_roundtrip(v in any::<PeerSpec>()) {
199
            assert_eq![scorex_serialize_roundtrip(&v), v]
200
        }
201
    }
202
}
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

© 2025 Coveralls, Inc