Skip to main content

eth_state_diff/
recent_roots.rs

1//! Delta encoding for fixed-size Ethereum consensus root buffers.
2//!
3//! Ethereum consensus stores historical roots (such as block roots and state
4//! roots) in fixed-capacity circular buffers. Advancing the chain overwrites
5//! the oldest entries once the buffer wraps.
6//!
7//! Rather than diffing the entire buffer, this module records only the sequence
8//! of newly written roots between two slots. Applying the delta replays those
9//! writes into another buffer using the same circular indexing logic.
10//!
11//! This representation is independent of the buffer capacity and works with
12//! any fixed-size root ring.
13
14use crate::types::{ArchivedRootsDiff, RootsDiff};
15
16/// Computes the sequence of newly written roots between two slots.
17///
18/// The returned delta contains every root written during the half-open slot
19/// range `[base_slot, target_slot)`.
20///
21/// The input `buffer` is treated as a circular buffer, with its length defining
22/// the modulo capacity.
23///
24/// # Arguments
25///
26/// * `base_slot` - First slot represented by the delta.
27/// * `target_slot` - Slot immediately following the final recorded root.
28/// * `buffer` - Circular root buffer.
29///
30/// # Complexity
31///
32/// O(target_slot - base_slot)
33pub fn diff_roots(base_slot: u64, target_slot: u64, buffer: &[[u8; 32]]) -> RootsDiff {
34    debug_assert!(
35        target_slot >= base_slot,
36        "target_slot must not precede base_slot"
37    );
38
39    let span = target_slot - base_slot;
40    let capacity = buffer.len() as u64;
41
42    let mut roots = Vec::with_capacity(span as usize);
43
44    for i in 0..span {
45        let slot = base_slot + i;
46        let idx = (slot % capacity) as usize;
47        roots.push(buffer[idx]);
48    }
49
50    RootsDiff { roots }
51}
52
53/// Applies a root delta to a circular root buffer.
54///
55/// Each stored root is written back into the destination buffer using the same
56/// slot-to-index mapping employed during diff generation.
57///
58/// After application, the destination buffer contains the same root values for
59/// every slot represented by the delta.
60///
61/// # Complexity
62///
63/// O(number of recorded roots)
64pub fn apply_roots(base_slot: u64, base_buffer: &mut [[u8; 32]], delta: &ArchivedRootsDiff) {
65    let capacity = base_buffer.len() as u64;
66
67    for (i, root) in delta.roots.iter().enumerate() {
68        let slot = base_slot + i as u64;
69        let idx = (slot % capacity) as usize;
70        base_buffer[idx] = *root;
71    }
72}