Skip to main content

eth_state_diff/
types.rs

1use rkyv::{Archive, Deserialize, Serialize};
2
3/// Size, in bytes, of an SSZ-serialized validator record.
4pub const VALIDATOR_SSZ_SIZE: usize = 121;
5
6/// Protocol-defined withdrawability delay for non-slashed validators.
7pub const MIN_VALIDATOR_WITHDRAWABILITY_DELAY: u64 = 256;
8
9/// A field-level modification to a validator record.
10///
11/// Validator fields are diffed independently to avoid rewriting entire
12/// 121-byte SSZ validator records when only a small subset of fields change.
13#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
14pub enum ValidatorField {
15    WithdrawalCredentials,
16    EffectiveBalance,
17    Slashed,
18    ActivationEligibilityEpoch,
19    ActivationEpoch,
20    ExitEpoch,
21    WithdrawableEpochSlashed,
22}
23
24/// A modification to a single validator field.
25///
26/// Each patch identifies the validator index, the field being modified,
27/// and the replacement SSZ bytes for that field.
28#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
29pub struct ValidatorPatch {
30    pub index: u32,
31    pub field: ValidatorField,
32    pub value: Vec<u8>,
33}
34
35/// Compact representation of the difference between two validator registries.
36///
37/// Only modified validator fields are recorded. Newly appended validators are
38/// stored as raw SSZ bytes and appended during reconstruction.
39#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
40pub struct ValidatorsDiff {
41    pub patches: Vec<ValidatorPatch>,
42    pub appended_validators: Vec<u8>,
43}
44
45/// Compact representation of the difference between two balance snapshots.
46///
47/// A `BalanceDiffs` stores only the information required to transform one
48/// balance vector into another.
49///
50/// Small balance differences are encoded as mode-adjusted zig-zag varints,
51/// while values that can not be represented efficiently are stored explicitly.
52///
53/// This structure is intended to be serialized with `rkyv`.
54#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
55pub struct BalancesDiff {
56    pub tags: BitTagVec,
57
58    pub mode: i64,
59
60    pub varint_payload: Vec<u8>,
61    pub target_values: Vec<u64>,
62    pub appended_balances: Vec<u64>,
63}
64
65/// Compact delta encoding for participation flags.
66///
67/// A participation delta stores only the information required to transform one
68/// participation vector into another.
69///
70/// The encoder automatically selects the most compact representation:
71///
72/// - [`ParticipationDiff::AllZeros`] when the target vector contains only
73///   zero-valued flags.
74/// - [`ParticipationDiff::Sparse`] when only a subset of indices change.
75///
76/// This type is intended to be serialized using `rkyv`.
77#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
78pub enum ParticipationDiff {
79    /// Represents a participation vector consisting entirely of zeros.
80    ///
81    /// During reconstruction the destination vector is resized to `len`
82    /// and every entry is set to `0`.
83    AllZeros(usize),
84
85    /// Sparse delta representation.
86    ///
87    /// Only indices whose values differ from the base vector are stored.
88    ///
89    /// Changed indices are encoded as delta-varint gaps to reduce storage
90    /// requirements for sparsely changing participation flags.
91    Sparse {
92        /// Delta-varint encoded gaps between successive modified indices.
93        ///
94        /// Each decoded gap is added to the previous modified index to recover
95        /// the absolute index.
96        sparse_indices: Vec<u8>,
97
98        /// Replacement participation flags.
99        ///
100        /// Each entry corresponds one-to-one with a decoded index from
101        /// `sparse_indices`.
102        new_values: Vec<u8>,
103
104        /// Participation flags for validators that exist only in the target
105        /// vector.
106        extension: Vec<u8>,
107    },
108}
109
110/// Compact representation of the difference between two inactivity-score
111/// vectors.
112///
113/// The encoder automatically selects the most compact representation:
114///
115/// - [`InactivityDiff::AllZeros`] when the target vector contains only zero
116///   scores.
117/// - [`InactivityDiff::Sparse`] when only a subset of scores change.
118#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
119pub enum InactivityDiff {
120    /// Fast path for the 99.9% case where no scores change in the overlapping set.
121    AllZeros(u32),
122
123    /// Sparse inactivity-score updates.
124    ///
125    /// Only modified indices are stored.
126    Sparse {
127        /// Indices of modified inactivity scores.
128        indices: Vec<u32>,
129
130        /// Replacement scores corresponding one-to-one with `indices`.
131        new_values: Vec<u64>,
132
133        /// Scores for validators appended to the target vector.
134        extensions: Vec<u64>,
135    },
136}
137
138/// Sequence of roots written while advancing a circular root buffer.
139///
140/// Roots are stored in chronological slot order beginning at the supplied
141/// base slot used during reconstruction.
142///
143/// The buffer capacity is intentionally omitted from the encoding since it is
144/// determined by the destination buffer.
145#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
146pub struct RootsDiff {
147    /// Sequential list of 32-byte hashes added to the circular buffer
148    /// between the base slot and target slot.
149    pub roots: Vec<[u8; 32]>,
150}
151
152/// Sparse updates for a slashing ring buffer.
153///
154/// Each update stores the destination ring index together with its new slashing
155/// value.
156///
157/// Only epochs whose values changed are included.
158#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
159pub struct SlashingsDiff {
160    /// A sparse list of (index, new_slashing_amount).
161    /// Index fits in u16 (max size is 8192).
162    /// In a 32-epoch window, this Vec will have a length of 0 or 1.
163    pub updates: Vec<(u16, u64)>,
164}
165
166/// Sequence of RANDAO mixes written while advancing through epochs.
167///
168/// Mixes are stored in chronological epoch order beginning with the epoch
169/// containing the supplied base slot used during reconstruction.
170///
171/// The circular buffer capacity is intentionally omitted from the encoding, as
172/// it is determined by the destination buffer during application.
173#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
174pub struct RandaoDiff {
175    /// Sequential list of 32-byte randao reveals added during this window.
176    pub mixes: Vec<[u8; 32]>,
177}
178
179/// Delta representation of the Eth1 data vote list.
180///
181/// The encoder distinguishes between ordinary vote accumulation and the
182/// protocol-defined reset that occurs after an Eth1 voting period.
183#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
184pub enum Eth1DataVotesDiff {
185    /// Additional votes appended to the existing list.
186    Append(Vec<u8>),
187
188    /// The vote list was reset before appending new votes.
189    ResetAndAppend(Vec<u8>),
190}
191
192/// Delta representation for FIFO queues.
193///
194/// Rather than storing the full queue, the delta records how many items were
195/// consumed from the front and the newly appended items at the back.
196#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
197pub struct FifoQueueDiff {
198    /// The number of items consumed from the front of the base queue.
199    pub consumed_count: u32,
200
201    /// The raw SSZ bytes of *only* the newly appended items at the end.
202    pub appended_items: Vec<u8>,
203}
204
205#[derive(Eq, PartialEq, Debug, Clone, Default, Archive, Deserialize, Serialize)]
206pub struct BitTagVec {
207    /// Packed storage containing four 2-bit tags per byte.
208    pub data: Vec<u8>,
209    pub len: usize,
210}
211
212/// Balance is unchanged.
213pub const SET_NO_CHANGE: u8 = 0b00;
214
215/// Balance is replaced with zero.
216pub const SET_TO_ZERO: u8 = 0b10;
217
218/// Balance is reconstructed by applying a stored difference.
219pub const SET_TO_DIFF: u8 = 0b11;
220
221/// Balance is replaced with its absolute target value.
222pub const SET_TO_TARGET_VALUE: u8 = 0b01;
223
224/// Dense 2-bit tag vector.
225///
226/// Four entries are packed into each byte.
227///
228/// Each entry describes how the corresponding validator balance should be
229/// reconstructed.
230///
231/// Encoding:
232///
233/// - `00` — unchanged
234/// - `01` — absolute target value
235/// - `10` — set to zero
236/// - `11` — apply encoded difference
237impl BitTagVec {
238    pub fn new(len: usize) -> Self {
239        let bytes = len.div_ceil(4);
240        Self {
241            data: vec![0; bytes],
242            len,
243        }
244    }
245
246    /// Sets the tag at `idx`.
247    #[inline]
248    pub fn set(&mut self, idx: usize, tag: u8) {
249        let byte = idx / 4;
250        let shift = (idx % 4) * 2;
251
252        self.data[byte] |= (tag & 0b11) << shift;
253    }
254
255    /// Returns the tag stored at `idx`.
256    #[inline]
257    pub fn get(&self, idx: usize) -> u8 {
258        let byte = idx / 4;
259        let shift = (idx % 4) * 2;
260        (self.data[byte] >> shift) & 0b11
261    }
262}