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!("Failed to parse the metadata as namespace table. Use a single namespace table instead.");
26        return vec![(0..payload_byte_len)];
27    }
28    let num_entries = u32::from_le_bytes(bytes[..NUM_NSS_BYTE_LEN].try_into().unwrap()) as usize;
29    if num_entries
30        != bytes.len().saturating_sub(NUM_NSS_BYTE_LEN)
31            / NS_ID_BYTE_LEN.saturating_add(NS_OFFSET_BYTE_LEN)
32        || (num_entries == 0 && payload_byte_len != 0)
33    {
34        tracing::warn!("Failed to parse the metadata as namespace table. Use a single namespace table instead.");
35        return vec![(0..payload_byte_len)];
36    }
37    // Early breaks for empty payload and namespace table
38    if num_entries == 0 {
39        return vec![(0..payload_byte_len)];
40    }
41    let mut l = 0;
42    for i in 0..num_entries {
43        let offset = NUM_NSS_BYTE_LEN + i * (NS_ID_BYTE_LEN + NS_OFFSET_BYTE_LEN) + NS_ID_BYTE_LEN;
44        let r = u32::from_le_bytes(
45            bytes[offset..offset + NS_OFFSET_BYTE_LEN]
46                .try_into()
47                .unwrap(),
48        ) as usize;
49        if r < l || r > payload_byte_len {
50            tracing::warn!("Failed to parse the metadata as namespace table. Use a single namespace table instead.");
51            return vec![(0..payload_byte_len)];
52        }
53        result.push(l..r);
54        l = r;
55    }
56    if l != payload_byte_len {
57        tracing::warn!("Failed to parse the metadata as namespace table. Use a single namespace table instead.");
58        return vec![(0..payload_byte_len)];
59    }
60    result
61}