1use alloc::vec::Vec;
23use core::fmt;
24use digest::Digest;
25use digest::typenum::U32;
26
27use crate::merkle::{ceil_log2, hash_pair, mix_in_length, zero_hash};
28use crate::missing::MissingOr;
29use crate::{BYTES_PER_LENGTH_OFFSET, Decode, DecodeError, Encode, HashTreeRoot};
30
31pub struct SparseList<T, const N: u64> {
38 len: u64,
39 entries: Vec<(u64, MissingOr<T>)>,
44 cached_subtree_roots: Vec<(u64, [u8; 32])>,
49}
50
51impl<T, const N: u64> SparseList<T, N> {
52 pub fn new() -> Self {
54 Self {
55 len: 0,
56 entries: Vec::new(),
57 cached_subtree_roots: Vec::new(),
58 }
59 }
60
61 pub fn len(&self) -> u64 {
63 self.len
64 }
65
66 pub fn is_empty(&self) -> bool {
68 self.len == 0
69 }
70
71 pub fn iter(&self) -> impl Iterator<Item = (u64, &MissingOr<T>)> {
73 self.entries.iter().map(|(k, v)| (*k, v))
74 }
75
76 pub fn iter_mut(&mut self) -> impl Iterator<Item = (u64, &mut MissingOr<T>)> {
80 self.entries.iter_mut().map(|(k, v)| (*k, v))
81 }
82
83 pub fn get(&self, idx: u64) -> Option<&MissingOr<T>> {
85 match self.entries.binary_search_by_key(&idx, |(k, _)| *k) {
86 Ok(pos) => Some(&self.entries[pos].1),
87 Err(_) => None,
88 }
89 }
90
91 pub fn insert(&mut self, idx: u64, value: MissingOr<T>) -> Result<(), DecodeError> {
95 if idx >= N {
96 return Err(DecodeError::BoundExceeded {
97 len: idx + 1,
98 bound: N,
99 });
100 }
101 self.len = self.len.max(idx + 1);
102 match self.entries.binary_search_by_key(&idx, |(k, _)| *k) {
103 Ok(pos) => {
104 self.entries[pos].1 = value;
105 }
106 Err(pos) => {
107 self.entries.insert(pos, (idx, value));
108 }
109 }
110 Ok(())
111 }
112
113 pub fn remove(&mut self, idx: u64) -> Option<MissingOr<T>> {
117 match self.entries.binary_search_by_key(&idx, |(k, _)| *k) {
118 Ok(pos) => Some(self.entries.remove(pos).1),
119 Err(_) => None,
120 }
121 }
122
123 pub fn set_len(&mut self, len: u64) -> Result<(), DecodeError> {
125 if len > N {
126 return Err(DecodeError::BoundExceeded { len, bound: N });
127 }
128 self.len = len;
129 Ok(())
130 }
131
132 pub fn cache_subtree_root(&mut self, depth: usize, idx: u64, root: [u8; 32]) {
136 let key = coord_to_key(depth, idx);
137 match self
138 .cached_subtree_roots
139 .binary_search_by_key(&key, |(k, _)| *k)
140 {
141 Ok(pos) => {
142 self.cached_subtree_roots[pos].1 = root;
143 }
144 Err(pos) => {
145 self.cached_subtree_roots.insert(pos, (key, root));
146 }
147 }
148 }
149
150 pub fn cached_subtree_roots_count(&self) -> usize {
152 self.cached_subtree_roots.len()
153 }
154
155 pub fn cached_subtree_roots(&self) -> impl Iterator<Item = (u64, &[u8; 32])> {
157 self.cached_subtree_roots.iter().map(|(k, v)| (*k, v))
158 }
159
160 fn cached_subtree_root(&self, key: u64) -> Option<&[u8; 32]> {
162 match self
163 .cached_subtree_roots
164 .binary_search_by_key(&key, |(k, _)| *k)
165 {
166 Ok(pos) => Some(&self.cached_subtree_roots[pos].1),
167 Err(_) => None,
168 }
169 }
170}
171
172impl<T, const N: u64> Default for SparseList<T, N> {
173 fn default() -> Self {
174 Self::new()
175 }
176}
177
178#[inline]
179fn coord_to_key(depth: usize, idx: u64) -> u64 {
180 (1u64 << depth) | idx
181}
182
183impl<T: fmt::Debug, const N: u64> fmt::Debug for SparseList<T, N> {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 f.debug_struct("SparseList")
186 .field("cap", &N)
187 .field("len", &self.len)
188 .field("materialized", &self.entries.len())
189 .field("cached_subtrees", &self.cached_subtree_roots.len())
190 .finish()
191 }
192}
193
194impl<T: Clone, const N: u64> Clone for SparseList<T, N> {
195 fn clone(&self) -> Self {
196 Self {
197 len: self.len,
198 entries: self.entries.clone(),
199 cached_subtree_roots: self.cached_subtree_roots.clone(),
200 }
201 }
202}
203
204impl<T: PartialEq, const N: u64> PartialEq for SparseList<T, N> {
205 fn eq(&self, other: &Self) -> bool {
206 if self.len != other.len
207 || self.entries.len() != other.entries.len()
208 || self.cached_subtree_roots.len() != other.cached_subtree_roots.len()
209 {
210 return false;
211 }
212 for ((ka, va), (kb, vb)) in self.entries.iter().zip(other.entries.iter()) {
215 if ka != kb || va != vb {
216 return false;
217 }
218 }
219 for ((ka, va), (kb, vb)) in self
220 .cached_subtree_roots
221 .iter()
222 .zip(other.cached_subtree_roots.iter())
223 {
224 if ka != kb || va != vb {
225 return false;
226 }
227 }
228 true
229 }
230}
231
232impl<T: Eq, const N: u64> Eq for SparseList<T, N> {}
233
234impl<T: Encode, const N: u64> Encode for SparseList<T, N> {
245 fn is_ssz_fixed_len() -> bool {
246 false
247 }
248 fn ssz_fixed_len() -> usize {
249 BYTES_PER_LENGTH_OFFSET
250 }
251 fn ssz_bytes_len(&self) -> usize {
252 let n_entries = self.entries.len();
254 let entry_var_size: usize = self
255 .entries
256 .iter()
257 .map(|(_, v)| v.ssz_bytes_len())
258 .sum::<usize>();
259 12 + n_entries * 12 + entry_var_size
272 }
273 fn ssz_append(&self, buf: &mut Vec<u8>) {
274 buf.extend_from_slice(&self.len.to_le_bytes());
276 buf.extend_from_slice(&12u32.to_le_bytes());
278 encode_sparse_entries_list(&self.entries, buf);
281 }
282}
283
284fn encode_sparse_entries_list<T: Encode>(entries: &[(u64, MissingOr<T>)], buf: &mut Vec<u8>) {
285 let n = entries.len();
286 let header_size = n * BYTES_PER_LENGTH_OFFSET;
299 let start = buf.len();
300 buf.resize(start + header_size, 0u8);
301
302 let mut running = header_size as u32;
303 for (i, (key, val)) in entries.iter().enumerate() {
304 let off_pos = start + i * BYTES_PER_LENGTH_OFFSET;
305 buf[off_pos..off_pos + 4].copy_from_slice(&running.to_le_bytes());
306
307 let entry_start = buf.len();
308 buf.extend_from_slice(&key.to_le_bytes());
310 buf.extend_from_slice(&12u32.to_le_bytes());
312 val.ssz_append(buf);
314
315 let entry_end = buf.len();
316 running = running
317 .checked_add((entry_end - entry_start) as u32)
318 .expect("ssz offset overflow");
319 }
320}
321
322impl<T: Decode, const N: u64> Decode for SparseList<T, N> {
323 fn is_ssz_fixed_len() -> bool {
324 false
325 }
326 fn ssz_fixed_len() -> usize {
327 BYTES_PER_LENGTH_OFFSET
328 }
329 fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
330 if bytes.len() < 12 {
331 return Err(DecodeError::UnexpectedEof {
332 expected: 12,
333 actual: bytes.len(),
334 });
335 }
336 let mut len_bytes = [0u8; 8];
337 len_bytes.copy_from_slice(&bytes[0..8]);
338 let len = u64::from_le_bytes(len_bytes);
339 if len > N {
340 return Err(DecodeError::BoundExceeded { len, bound: N });
341 }
342 let entries_offset = u32::from_le_bytes(bytes[8..12].try_into().unwrap()) as usize;
343 if entries_offset != 12 {
344 return Err(DecodeError::InvalidOffset {
345 offset: entries_offset,
346 len: bytes.len(),
347 fixed: 12,
348 });
349 }
350 let payload = &bytes[12..];
351 let entries_in = decode_sparse_entries_list::<T>(payload)?;
352 let mut entries: Vec<(u64, MissingOr<T>)> = Vec::with_capacity(entries_in.len());
353 let mut prev_key: Option<u64> = None;
354 for (k, v) in entries_in {
355 if k >= N {
356 return Err(DecodeError::BoundExceeded {
357 len: k + 1,
358 bound: N,
359 });
360 }
361 if let Some(p) = prev_key
362 && k <= p
363 {
364 return Err(DecodeError::NotSorted);
365 }
366 prev_key = Some(k);
367 entries.push((k, v));
368 }
369 Ok(Self {
370 len,
371 entries,
372 cached_subtree_roots: Vec::new(),
373 })
374 }
375}
376
377fn decode_sparse_entries_list<T: Decode>(
378 bytes: &[u8],
379) -> Result<Vec<(u64, MissingOr<T>)>, DecodeError> {
380 if bytes.is_empty() {
381 return Ok(Vec::new());
382 }
383 if bytes.len() < 4 {
384 return Err(DecodeError::UnexpectedEof {
385 expected: 4,
386 actual: bytes.len(),
387 });
388 }
389 let first = u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as usize;
390 if !first.is_multiple_of(BYTES_PER_LENGTH_OFFSET) || first > bytes.len() {
391 return Err(DecodeError::InvalidOffset {
392 offset: first,
393 len: bytes.len(),
394 fixed: 0,
395 });
396 }
397 let n = first / BYTES_PER_LENGTH_OFFSET;
398 let mut offsets = Vec::with_capacity(n + 1);
399 offsets.push(first);
400 for i in 1..n {
401 if bytes.len() < (i + 1) * BYTES_PER_LENGTH_OFFSET {
402 return Err(DecodeError::UnexpectedEof {
403 expected: (i + 1) * BYTES_PER_LENGTH_OFFSET,
404 actual: bytes.len(),
405 });
406 }
407 let off = u32::from_le_bytes(
408 bytes[i * BYTES_PER_LENGTH_OFFSET..(i + 1) * BYTES_PER_LENGTH_OFFSET]
409 .try_into()
410 .unwrap(),
411 ) as usize;
412 if off < *offsets.last().unwrap() {
413 return Err(DecodeError::OffsetsNotMonotonic {
414 prev: *offsets.last().unwrap(),
415 curr: off,
416 });
417 }
418 if off > bytes.len() {
419 return Err(DecodeError::InvalidOffset {
420 offset: off,
421 len: bytes.len(),
422 fixed: first,
423 });
424 }
425 offsets.push(off);
426 }
427 offsets.push(bytes.len());
428
429 let mut out = Vec::with_capacity(n);
430 for i in 0..n {
431 let entry_slice = &bytes[offsets[i]..offsets[i + 1]];
432 if entry_slice.len() < 12 {
434 return Err(DecodeError::UnexpectedEof {
435 expected: 12,
436 actual: entry_slice.len(),
437 });
438 }
439 let mut kbytes = [0u8; 8];
440 kbytes.copy_from_slice(&entry_slice[0..8]);
441 let key = u64::from_le_bytes(kbytes);
442 let value_offset = u32::from_le_bytes(entry_slice[8..12].try_into().unwrap()) as usize;
443 if value_offset != 12 {
444 return Err(DecodeError::InvalidOffset {
445 offset: value_offset,
446 len: entry_slice.len(),
447 fixed: 12,
448 });
449 }
450 let value = MissingOr::<T>::from_ssz_bytes(&entry_slice[12..])?;
451 out.push((key, value));
452 }
453 Ok(out)
454}
455
456#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
467pub struct SparseListRepr<T>
468where
469 T: rkyv::Archive,
470 MissingOr<T>: rkyv::Archive,
471{
472 pub len: u64,
473 pub entries: Vec<(u64, MissingOr<T>)>,
474}
475
476impl<T, const N: u64> rkyv::Archive for SparseList<T, N>
477where
478 T: rkyv::Archive + Clone,
479 MissingOr<T>: rkyv::Archive,
480{
481 type Archived = <SparseListRepr<T> as rkyv::Archive>::Archived;
482 type Resolver = <SparseListRepr<T> as rkyv::Archive>::Resolver;
483
484 fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
485 let repr = SparseListRepr {
486 len: self.len,
487 entries: self.entries.clone(),
488 };
489 <SparseListRepr<T> as rkyv::Archive>::resolve(&repr, resolver, out)
490 }
491}
492
493impl<T, S, const N: u64> rkyv::Serialize<S> for SparseList<T, N>
494where
495 T: rkyv::Archive + Clone,
496 MissingOr<T>: rkyv::Archive,
497 SparseListRepr<T>: rkyv::Serialize<S>,
498 S: rkyv::rancor::Fallible + ?Sized,
499{
500 fn serialize(
501 &self,
502 serializer: &mut S,
503 ) -> Result<Self::Resolver, <S as rkyv::rancor::Fallible>::Error> {
504 let repr = SparseListRepr {
505 len: self.len,
506 entries: self.entries.clone(),
507 };
508 <SparseListRepr<T> as rkyv::Serialize<S>>::serialize(&repr, serializer)
509 }
510}
511
512impl<T, D, const N: u64> rkyv::Deserialize<SparseList<T, N>, D>
513 for <SparseListRepr<T> as rkyv::Archive>::Archived
514where
515 T: rkyv::Archive + Clone,
516 MissingOr<T>: rkyv::Archive,
517 <SparseListRepr<T> as rkyv::Archive>::Archived: rkyv::Deserialize<SparseListRepr<T>, D>,
518 D: rkyv::rancor::Fallible + ?Sized,
519{
520 fn deserialize(
521 &self,
522 deserializer: &mut D,
523 ) -> Result<SparseList<T, N>, <D as rkyv::rancor::Fallible>::Error> {
524 let repr: SparseListRepr<T> =
525 rkyv::Deserialize::<SparseListRepr<T>, D>::deserialize(self, deserializer)?;
526 Ok(SparseList {
527 len: repr.len,
528 entries: repr.entries,
529 cached_subtree_roots: Vec::new(),
530 })
531 }
532}
533
534impl<T: HashTreeRoot + Encode, const N: u64> HashTreeRoot for SparseList<T, N> {
535 fn hash_tree_root<D: Digest<OutputSize = U32>>(&self) -> [u8; 32] {
536 let depth = ceil_log2(N);
542 let inner = self.compute_subtree_root::<D>(0, 0, depth);
543 mix_in_length::<D>(inner, self.len)
544 }
545}
546
547impl<T: HashTreeRoot, const N: u64> SparseList<T, N> {
548 fn compute_subtree_root<D: Digest<OutputSize = U32>>(
555 &self,
556 node_depth: usize,
557 node_index_at_depth: u64,
558 total_depth: usize,
559 ) -> [u8; 32] {
560 if let Some(cached) =
562 self.cached_subtree_root(coord_to_key(node_depth, node_index_at_depth))
563 {
564 return *cached;
565 }
566
567 if node_depth == total_depth {
569 return self
571 .get(node_index_at_depth)
572 .map(|e| e.hash_tree_root::<D>())
573 .unwrap_or([0u8; 32]);
574 }
575
576 let levels_below = total_depth - node_depth;
578 let leaves_per_subtree = 1u64 << levels_below;
579 let lo = node_index_at_depth * leaves_per_subtree;
580 let hi = lo + leaves_per_subtree; let pos = self.entries.partition_point(|(k, _)| *k < lo);
588 let has_entries = self.entries.get(pos).is_some_and(|(k, _)| *k < hi);
589 if !has_entries {
590 return zero_hash::<D>(levels_below);
591 }
592
593 let left =
595 self.compute_subtree_root::<D>(node_depth + 1, node_index_at_depth * 2, total_depth);
596 let right = self.compute_subtree_root::<D>(
597 node_depth + 1,
598 node_index_at_depth * 2 + 1,
599 total_depth,
600 );
601 hash_pair::<D>(&left, &right)
602 }
603}