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

oasisprotocol / oasis-core / #6697

26 Nov 2025 11:20AM UTC coverage: 48.351% (-0.01%) from 48.362%
#6697

Pull #6412

peternose
go/worker/compute/executor: Remove epoch check

The epoch check is incorrect because the group’s epoch
denotes the epoch in which the committee is valid, while
the block epoch represents the epoch in which the consensus
block was produced. When scheduling the first block of a new
epoch, these two epochs should differ by one.

Additionally, the check was optional because if the worker is
behind, a new block will cancel the ongoing round, resulting in
the same effect as the check itself.
Pull Request #6412: go/worker/client/committee: Refactor code

4678 of 9675 relevant lines covered (48.35%)

1.12 hits per line

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

90.57
/runtime/src/common/key_format.rs
1
use std::{convert::TryInto, mem::size_of};
2

3
use impl_trait_for_tuples::impl_for_tuples;
4

5
/// Size of the KeyFormat prefix.
6
const KEY_FORMAT_PREFIX_SIZE: usize = size_of::<u8>();
7

8
/// A key formatting helper trait to be used together with key-value
9
/// backends for constructing keys.
10
pub trait KeyFormat {
11
    /// The prefix that identifies the key format.
12
    fn prefix() -> u8;
13

14
    /// The minimum size of the encoded key.
15
    fn size() -> usize;
16

17
    /// Encode the given key format into a set of atoms.
18
    fn encode_atoms(self, atoms: &mut Vec<Vec<u8>>);
19

20
    /// Decode the given key format from data (without prefix).
21
    ///
22
    /// The caller must ensure that the size of the passed data is at
23
    /// least the minimum size returned by `size`.
24
    fn decode_atoms(data: &[u8]) -> Self
25
    where
26
        Self: Sized;
27

28
    /// Encode the first few atoms in the key format.
29
    ///
30
    /// This method can be used to construct key prefixes for iteration.
31
    /// Specifying a zero count will only generate the prefix.
32
    fn encode_partial(self, count: usize) -> Vec<u8>
21✔
33
    where
34
        Self: Sized,
35
    {
36
        let mut v = Vec::with_capacity(KEY_FORMAT_PREFIX_SIZE + Self::size());
42✔
37
        v.push(Self::prefix());
42✔
38

39
        if count == 0 {
21✔
40
            return v;
6✔
41
        }
42

43
        let mut atoms = Vec::new();
21✔
44
        self.encode_atoms(&mut atoms);
21✔
45
        for (included, mut atom) in atoms.into_iter().enumerate() {
42✔
46
            if included >= count {
21✔
47
                break;
×
48
            }
49
            v.append(&mut atom);
21✔
50
        }
51

52
        v
21✔
53
    }
54

55
    /// Encode the given key format.
56
    fn encode(self) -> Vec<u8>
21✔
57
    where
58
        Self: Sized,
59
    {
60
        self.encode_partial(usize::MAX)
21✔
61
    }
62

63
    /// Decode the given key format from data.
64
    ///
65
    /// The method may return `None` in case the key is of a different
66
    /// type as indicated by the prefix byte.
67
    fn decode(data: &[u8]) -> Option<Self>
8✔
68
    where
69
        Self: Sized,
70
    {
71
        assert!(!data.is_empty(), "key format: malformed input (empty data)");
8✔
72
        if data[0] != Self::prefix() {
16✔
73
            return None;
7✔
74
        }
75
        assert!(
8✔
76
            data.len() >= Self::size() + KEY_FORMAT_PREFIX_SIZE,
×
77
            "key format: malformed input"
×
78
        );
79

80
        Some(Self::decode_atoms(&data[1..]))
8✔
81
    }
82
}
83

84
/// Part of the KeyFormat to be used with key-value backends for constructing keys.
85
pub trait KeyFormatAtom {
86
    fn size() -> usize;
87

88
    fn encode_atom(self) -> Vec<u8>;
89

90
    fn decode_atom(data: &[u8]) -> Self
91
    where
92
        Self: Sized;
93
}
94

95
impl KeyFormatAtom for u64 {
96
    fn size() -> usize {
97
        8
98
    }
99

100
    fn encode_atom(self) -> Vec<u8> {
1✔
101
        self.to_be_bytes().to_vec()
1✔
102
    }
103

104
    fn decode_atom(data: &[u8]) -> Self
1✔
105
    where
106
        Self: Sized,
107
    {
108
        u64::from_be_bytes(data.try_into().expect("key_format: malformed u64 input"))
1✔
109
    }
110
}
111

112
impl KeyFormatAtom for u8 {
113
    fn size() -> usize {
114
        1
115
    }
116

117
    fn encode_atom(self) -> Vec<u8> {
1✔
118
        vec![self]
1✔
119
    }
120

121
    fn decode_atom(data: &[u8]) -> Self
1✔
122
    where
123
        Self: Sized,
124
    {
125
        assert!(!data.is_empty(), "key_format: malformed: u8 input");
1✔
126
        data[0]
2✔
127
    }
128
}
129

130
impl KeyFormatAtom for () {
131
    fn size() -> usize {
132
        0
133
    }
134

135
    fn encode_atom(self) -> Vec<u8> {
1✔
136
        Vec::new()
1✔
137
    }
138

139
    fn decode_atom(_: &[u8]) {}
×
140
}
141

142
#[impl_for_tuples(2, 10)]
143
impl KeyFormatAtom for Tuple {
144
    fn size() -> usize {
5✔
145
        for_tuples!( #( Tuple::size() )+* );
146
    }
147

148
    fn encode_atom(self) -> Vec<u8> {
5✔
149
        let mut atoms: Vec<Vec<u8>> = [for_tuples!( #( self.Tuple.encode_atom() ),* )].to_vec();
18✔
150

151
        atoms.into_iter().flatten().collect()
5✔
152
    }
153

154
    fn decode_atom(data: &[u8]) -> for_tuples!( ( #( Tuple ),* ) ) {
4✔
155
        assert!(
×
156
            data.len() >= Self::size(),
157
            "key format atom: malformed input"
158
        );
159

160
        let mut sizes: Vec<usize> = [for_tuples!( #( Tuple::size() ),* )].to_vec();
4✔
161
        sizes.reverse();
8✔
162
        let mut data = data.to_vec();
4✔
163

164
        /*
165
            (
166
                {
167
                    let x = T1::decode_atom(data.drain(0..T1::size()));
168
                    x
169
                },
170
                {
171
                    let x = T2::decode_atom(data.drain(0..T2::size()));
172
                    x
173
                }
174
                ...
175
            )
176
        */
177
        for_tuples!(
178
            (
179
                #(
180
                    {
181
                        let x = Tuple::decode_atom(data.drain(0..sizes.pop().unwrap()).as_slice());
36✔
182
                        x
5✔
183
                    }
184
                ),*
185
            )
186
        )
187
    }
188
}
189

190
/// Define a KeyFormat from KeyFormatAtom and a prefix.
191
///
192
/// # Examples
193
///
194
/// ```rust,ignore
195
/// key_format!(NewKeyFormatName, 0x01, InnerType);
196
/// ```
197
#[macro_export]
198
macro_rules! key_format {
199
    ($name:ident, $prefix:expr, $inner:ty) => {
200
        #[derive(Debug, Default, PartialEq, Eq, Clone)]
14✔
201
        struct $name($inner);
7✔
202

203
        impl KeyFormat for $name {
204
            fn prefix() -> u8 {
205
                $prefix
206
            }
207

208
            fn size() -> usize {
18✔
209
                <$inner>::size()
18✔
210
            }
211

212
            fn encode_atoms(self, atoms: &mut Vec<Vec<u8>>) {
18✔
213
                atoms.push(self.0.encode_atom());
18✔
214
            }
215

216
            fn decode_atoms(data: &[u8]) -> Self {
7✔
217
                Self(<$inner>::decode_atom(data))
7✔
218
            }
219
        }
220
    };
221
}
222

223
#[cfg(test)]
224
mod test {
225
    use rustc_hex::ToHex;
226

227
    use crate::common::crypto::hash::Hash;
228

229
    use super::*;
230

231
    #[derive(Debug, PartialEq)]
232
    struct Test1KeyFormat {
233
        h: Hash,
234
    }
235

236
    impl KeyFormat for Test1KeyFormat {
237
        fn prefix() -> u8 {
238
            b'T'
239
        }
240

241
        fn size() -> usize {
242
            32
243
        }
244

245
        fn encode_atoms(self, atoms: &mut Vec<Vec<u8>>) {
246
            atoms.push(self.h.as_ref().to_vec());
247
        }
248

249
        fn decode_atoms(data: &[u8]) -> Self {
250
            Self { h: data.into() }
251
        }
252
    }
253

254
    #[test]
255
    fn test_key_format() {
256
        let mut enc = Test1KeyFormat {
257
            h: Hash::empty_hash(),
258
        }
259
        .encode();
260
        assert_eq!(
261
            enc.to_hex::<String>(),
262
            "54c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"
263
        );
264

265
        let dec = Test1KeyFormat::decode(&enc);
266
        assert_eq!(
267
            dec,
268
            Some(Test1KeyFormat {
269
                h: Hash::empty_hash()
270
            })
271
        );
272

273
        // Clear type.
274
        enc[0] = 0x00;
275
        let dec = Test1KeyFormat::decode(&enc);
276
        assert_eq!(dec, None);
277

278
        // Partial encoding.
279
        let enc = Test1KeyFormat {
280
            h: Hash::empty_hash(),
281
        }
282
        .encode_partial(0);
283
        assert_eq!(enc.to_hex::<String>(), "54");
284
    }
285

286
    #[test]
287
    fn test_key_format_atom() {
288
        key_format!(TestKeyFormat, 0x01, (u8, u64, u8, u64, u64));
289

290
        let key = TestKeyFormat((1, 2, 3, 4, 5));
291
        let enc = key.clone().encode();
292
        let dec = TestKeyFormat::decode(&enc);
293

294
        assert_eq!(dec, Some(key),)
295
    }
296
}
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