hotshot_types/data/
ns_table.rs

1// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
2// This file is part of the HotShot repository.
3
4// You should have received a copy of the MIT License
5// along with the HotShot repository. If not, see <https://mit-license.org/>.
6
7//! This module provides helpers for namespace table.
8
9use std::ops::Range;
10
11/// Byte lengths for the different items that could appear in a namespace table.
12const NUM_NSS_BYTE_LEN: usize = 4;
13const NS_OFFSET_BYTE_LEN: usize = 4;
14const NS_ID_BYTE_LEN: usize = 4;
15
16/// Helper function for AvidM scheme to parse a namespace table.
17/// If the namespace table is invalid, it returns a default single entry namespace table.
18/// For details, please refer to `block/full_payload/ns_table.rs` in the `sequencer` crate.
19#[allow(clippy::single_range_in_vec_init)]
20pub fn parse_ns_table(payload_byte_len: usize, bytes: &[u8]) -> Vec<Range<usize>> {
21    let mut result = vec![];
22    if bytes.len() < NUM_NSS_BYTE_LEN
23        || (bytes.len() - NUM_NSS_BYTE_LEN) % (NS_OFFSET_BYTE_LEN + NS_ID_BYTE_LEN) != 0
24    {
25        tracing::warn!(
26            "Failed to parse the metadata as namespace table. Use a single namespace table \
27             instead."
28        );
29        return vec![(0..payload_byte_len)];
30    }
31    let num_entries = u32::from_le_bytes(bytes[..NUM_NSS_BYTE_LEN].try_into().unwrap()) as usize;
32    if num_entries
33        != bytes.len().saturating_sub(NUM_NSS_BYTE_LEN)
34            / NS_ID_BYTE_LEN.saturating_add(NS_OFFSET_BYTE_LEN)
35        || (num_entries == 0 && payload_byte_len != 0)
36    {
37        tracing::warn!(
38            "Failed to parse the metadata as namespace table. Use a single namespace table \
39             instead."
40        );
41        return vec![(0..payload_byte_len)];
42    }
43    // Early breaks for empty payload and namespace table
44    if num_entries == 0 {
45        return vec![(0..payload_byte_len)];
46    }
47    let mut l = 0;
48    for i in 0..num_entries {
49        let offset = NUM_NSS_BYTE_LEN + i * (NS_ID_BYTE_LEN + NS_OFFSET_BYTE_LEN) + NS_ID_BYTE_LEN;
50        let r = u32::from_le_bytes(
51            bytes[offset..offset + NS_OFFSET_BYTE_LEN]
52                .try_into()
53                .unwrap(),
54        ) as usize;
55        if r < l || r > payload_byte_len {
56            tracing::warn!(
57                "Failed to parse the metadata as namespace table. Use a single namespace table \
58                 instead."
59            );
60            return vec![(0..payload_byte_len)];
61        }
62        result.push(l..r);
63        l = r;
64    }
65    if l != payload_byte_len {
66        tracing::warn!(
67            "Failed to parse the metadata as namespace table. Use a single namespace table \
68             instead."
69        );
70        return vec![(0..payload_byte_len)];
71    }
72    result
73}