Something went wrong. Try again.
STreaming ARchive format: simpler, stricter, smaller than CARs for a subset of use-cases. forked from microcosm.blue/star
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103use crate::error::{Result, StarError};use crate::types::{StarMstNode, calculate_height};
/// Validates the structure of a STAR MST node.////// Checks:/// - Key height consistency (all keys must have same height)/// - Height matching against expectation/// - Structural rules (Height 0 vs >0 constraints)/// - Implicit/Explicit V rules////// Returns (height, reconstructed_keys)pub fn validate_node_structure( node: &StarMstNode, expected: Option<u32>,) -> Result<(u32, Vec<Vec<u8>>)> { let mut node_height = None; let mut prev_key_bytes = Vec::new(); let mut entry_keys = Vec::new();
for e in &node.e { let mut key = if e.p as usize <= prev_key_bytes.len() { prev_key_bytes[..e.p as usize].to_vec() } else { prev_key_bytes.clone() }; key.extend_from_slice(&e.k);
let h = calculate_height(&key);
if let Some(existing) = node_height { if h != existing { return Err(StarError::InvalidStructure(format!( "Inconsistent key height in node: {} vs {}", h, existing ))); } } else { node_height = Some(h); }
entry_keys.push(key.clone()); prev_key_bytes = key; }
let height = match (node_height, expected) { (Some(h), Some(exp)) => { if h != exp { return Err(StarError::HeightMismatch { found: h, expected: exp, }); } h } (Some(h), None) => h, (None, Some(exp)) => { if exp == 0 { return Err(StarError::InvalidStructure( "Height 0 cannot be empty".into(), )); } exp } (None, None) => return Err(StarError::InvalidStructure("Root cannot be empty".into())), };
if height == 0 { if node.l.is_some() || node.l_archived.is_some() { return Err(StarError::InvalidStructure( "Height 0 node cannot have left child".into(), )); } for e in &node.e { if e.t.is_some() || e.t_archived.is_some() { return Err(StarError::InvalidStructure( "Height 0 entries cannot have subtrees".into(), )); } if e.v.is_some() { return Err(StarError::InvalidStructure( "Height 0 node must omit record CIDs".into(), )); } } } else { if node.e.is_empty() && node.l.is_none() { return Err(StarError::InvalidStructure( "Empty intermediate node must have left child".into(), )); } for e in &node.e { if e.v.is_none() { return Err(StarError::InvalidStructure( "Intermediate node must include record CIDs".into(), )); } } }
Ok((height, entry_keys))}