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

tari-project / tari / 17033178607

18 Aug 2025 06:45AM UTC coverage: 54.49% (-0.007%) from 54.497%
17033178607

push

github

stringhandler
Merge branch 'development' of github.com:tari-project/tari into odev

971 of 2923 new or added lines in 369 files covered. (33.22%)

5804 existing lines in 173 files now uncovered.

76688 of 140739 relevant lines covered (54.49%)

193850.18 hits per line

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

86.36
/base_layer/core/src/proof_of_work/monero_rx/fixed_array.rs
1
//  Copyright 2021, 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::{convert::TryFrom, io, io::Write, ops::Deref};
24

25
use borsh::{BorshDeserialize, BorshSerialize};
26
use tari_utilities::{ByteArray, ByteArrayError};
27

28
const MAX_ARR_SIZE: usize = 60;
29

30
/// A fixed size byte array for RandomX that can be serialized and deserialized using Borsh.
31
#[derive(Clone, Debug, PartialEq, Eq)]
32
pub struct FixedByteArray {
33
    elems: [u8; MAX_ARR_SIZE],
34
    len: u8,
35
}
36

37
impl BorshSerialize for FixedByteArray {
38
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
33✔
39
        self.len.serialize(writer)?;
33✔
40
        let data = self.as_slice();
33✔
41
        for item in data.iter().take(self.len as usize) {
454✔
42
            item.serialize(writer)?;
454✔
43
        }
44
        Ok(())
33✔
45
    }
33✔
46
}
47

48
impl BorshDeserialize for FixedByteArray {
49
    fn deserialize_reader<R>(reader: &mut R) -> Result<Self, io::Error>
14✔
50
    where R: io::Read {
14✔
51
        let len = u8::deserialize_reader(reader)? as usize;
14✔
52
        if len > MAX_ARR_SIZE {
14✔
53
            return Err(io::Error::new(
2✔
54
                io::ErrorKind::InvalidInput,
2✔
55
                format!("length exceeded maximum of 60-bytes for FixedByteArray: {len}"),
2✔
56
            ));
2✔
57
        }
12✔
58
        let mut bytes = Vec::with_capacity(len);
12✔
59
        for _ in 0..len {
12✔
60
            bytes.push(u8::deserialize_reader(reader)?);
293✔
61
        }
62
        // This unwrap should never fail, the len is checked above.
63
        Ok(Self::from_canonical_bytes(bytes.as_bytes()).unwrap())
11✔
64
    }
14✔
65
}
66

67
impl FixedByteArray {
68
    /// Create a new FixedByteArray with the preset length. The array will be zeroed.
69
    pub fn new() -> Self {
×
70
        Default::default()
×
71
    }
×
72

73
    /// Returns the array as a slice of bytes.
74
    pub fn as_slice(&self) -> &[u8] {
33✔
75
        self.get(..self.len()).expect("Cannot fail")
33✔
76
    }
33✔
77

78
    /// Returns true if the array is full.
79
    #[inline]
80
    pub fn is_full(&self) -> bool {
×
81
        self.len() == MAX_ARR_SIZE
×
82
    }
×
83

84
    /// Returns the length of the array.
85
    #[inline]
86
    pub fn len(&self) -> usize {
37✔
87
        self.len as usize
37✔
88
    }
37✔
89

90
    /// Returns true if the array is empty.
91
    #[inline]
92
    pub fn is_empty(&self) -> bool {
×
93
        self.len == 0
×
94
    }
×
95

96
    pub fn to_vec(&self) -> Vec<u8> {
×
97
        self.as_slice().to_vec()
×
98
    }
×
99
}
100

101
impl Deref for FixedByteArray {
102
    type Target = [u8];
103

104
    fn deref(&self) -> &Self::Target {
36✔
105
        self.elems.get(..self.len as usize).expect("Cannot fail")
36✔
106
    }
36✔
107
}
108

109
#[allow(clippy::derivable_impls)]
110
impl Default for FixedByteArray {
111
    fn default() -> Self {
16✔
112
        Self {
16✔
113
            elems: [0u8; MAX_ARR_SIZE],
16✔
114
            len: 0,
16✔
115
        }
16✔
116
    }
16✔
117
}
118

119
impl ByteArray for FixedByteArray {
120
    fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, ByteArrayError> {
24✔
121
        if bytes.len() > MAX_ARR_SIZE {
24✔
122
            return Err(ByteArrayError::IncorrectLength {});
1✔
123
        }
23✔
124

125
        let len = u8::try_from(bytes.len()).map_err(|_| ByteArrayError::IncorrectLength {})?;
23✔
126

127
        let mut elems = [0u8; MAX_ARR_SIZE];
23✔
128
        elems
23✔
129
            .get_mut(..len as usize)
23✔
130
            .expect("Cannot fail")
23✔
131
            .copy_from_slice(bytes.get(..len as usize).expect("Cannot fail"));
23✔
132
        Ok(Self { elems, len })
23✔
133
    }
24✔
134

UNCOV
135
    fn as_bytes(&self) -> &[u8] {
×
UNCOV
136
        self.as_slice()
×
UNCOV
137
    }
×
138
}
139

140
#[cfg(test)]
141
mod test {
142
    use super::*;
143

144
    #[test]
145
    fn assert_size() {
1✔
146
        assert_eq!(std::mem::size_of::<FixedByteArray>(), MAX_ARR_SIZE + 1);
1✔
147
    }
1✔
148

149
    #[test]
150
    fn from_bytes() {
1✔
151
        let empty = FixedByteArray::from_canonical_bytes(&[]).unwrap();
1✔
152
        assert_eq!(empty.len(), 0);
1✔
153
        let arr = FixedByteArray::from_canonical_bytes(&[1u8][..]).unwrap();
1✔
154
        assert_eq!(arr.len(), 1);
1✔
155
        assert!(arr.iter().all(|b| *b == 1));
1✔
156
        // Iterates only up to len
157
        let mut used = false;
1✔
158
        for _ in arr.iter() {
1✔
159
            assert!(!used);
1✔
160
            used = true;
1✔
161
        }
162
        assert!(used);
1✔
163

164
        let arr = FixedByteArray::from_canonical_bytes(&[1u8; 60][..]).unwrap();
1✔
165
        assert_eq!(arr.len(), 60);
1✔
166
        assert!(arr.iter().all(|b| *b == 1));
60✔
167

168
        FixedByteArray::from_canonical_bytes(&[1u8; 64][..]).unwrap_err();
1✔
169
    }
1✔
170

171
    #[test]
172
    fn capacity_overflow_does_not_panic() {
1✔
173
        let data = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f];
1✔
174
        let _result = FixedByteArray::deserialize(&mut data.as_slice()).unwrap_err();
1✔
175
    }
1✔
176

177
    #[test]
178
    fn length_check() {
1✔
179
        let mut buf = [u8::try_from(MAX_ARR_SIZE).unwrap(); MAX_ARR_SIZE + 1];
1✔
180
        let fixed_byte_array = FixedByteArray::deserialize(&mut buf.as_slice()).unwrap();
1✔
181
        assert_eq!(fixed_byte_array.len(), MAX_ARR_SIZE);
1✔
182
        buf[0] += 1;
1✔
183
        FixedByteArray::deserialize(&mut buf.as_slice()).unwrap_err();
1✔
184
    }
1✔
185

186
    #[test]
187
    fn test_borsh_de_serialization() {
1✔
188
        let fixed_byte_array = FixedByteArray::from_canonical_bytes(&[5, 6, 7]).unwrap();
1✔
189
        let mut buf = Vec::new();
1✔
190
        fixed_byte_array.serialize(&mut buf).unwrap();
1✔
191
        buf.extend_from_slice(&[1, 2, 3]);
1✔
192
        let buf = &mut buf.as_slice();
1✔
193
        assert_eq!(fixed_byte_array, FixedByteArray::deserialize(buf).unwrap());
1✔
194
        assert_eq!(buf, &[1, 2, 3]);
1✔
195
    }
1✔
196

197
    #[test]
198
    fn test_borsh_deserialize_wrong_length() {
1✔
199
        let mut buf = Vec::new();
1✔
200
        buf.extend_from_slice(&[3, 1, 1]);
1✔
201
        let buf = &mut buf.as_slice();
1✔
202
        let result = FixedByteArray::deserialize(buf);
1✔
203
        assert!(result.is_err());
1✔
204
        assert_eq!(buf, &[1u8; 0]);
1✔
205
    }
1✔
206
}
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