1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! Delta encoding for Phase 0 pending attestation lists.
//!
//! Phase 0 maintains two attestation lists with different update semantics:
//!
//! - `current_epoch_attestations` grows by appending new attestations during an
//! epoch.
//! - `previous_epoch_attestations` is replaced when the epoch transitions.
//!
//! This module provides a single diff function that selects the most compact
//! supported representation for both cases. If the target list starts with the
//! exact byte sequence of the base list, only the appended bytes are stored.
//! Otherwise, the complete target list is stored as a full replacement.
//!
//! Both representations use [`AttestationsDiff`] and can be applied with
//! [`apply_attestations`] without deserializing individual attestations.
use crate;
/// Computes a compact delta between two serialized SSZ attestation lists.
///
/// The function automatically selects between the supported delta
/// representations:
///
/// - If the lists are identical, [`AttestationsDiff::Unchanged`] is returned.
/// - If the target list starts with the exact byte sequence of the base list,
/// only the trailing bytes are stored in [`AttestationsDiff::Append`].
/// - Otherwise, the complete target list is stored in
/// [`AttestationsDiff::FullReplacement`].
///
/// This covers both append-only updates, such as growth of
/// `current_epoch_attestations`, and epoch-boundary replacement of
/// `previous_epoch_attestations`.
///
/// An empty base list is naturally represented as an append of the complete
/// target list.
///
/// # Arguments
///
/// * `base_ssz` - Serialized SSZ representation of the base attestation list.
/// * `target_ssz` - Serialized SSZ representation of the target attestation list.
///
/// # Returns
///
/// A compact [`AttestationsDiff`] representing the transition from `base_ssz`
/// to `target_ssz`.
///
/// # Complexity
///
/// The prefix comparison takes O(min(n, m)) time, where *n* and *m* are the
/// lengths of `base_ssz` and `target_ssz`, respectively. Additional space is
/// proportional to the selected delta payload.
///
/// # Example
///
/// ```
/// # use eth_state_diff::attestations::diff_attestations;
/// # use eth_state_diff::types::AttestationsDiff;
///
/// let base = b"AAAA";
///
/// // Append case.
/// let target = b"AAAABBBB";
/// assert_eq!(
/// diff_attestations(base, target),
/// AttestationsDiff::Append(b"BBBB".to_vec())
/// );
///
/// // Replacement case.
/// let target = b"CCCC";
/// assert_eq!(
/// diff_attestations(base, target),
/// AttestationsDiff::FullReplacement(b"CCCC".to_vec())
/// );
/// ```
/// Applies an attestation delta to a serialized SSZ list in place.
///
/// [`AttestationsDiff::Unchanged`] leaves the base buffer untouched.
///
/// [`AttestationsDiff::Append`] appends the serialized bytes stored in the
/// delta to the existing buffer.
///
/// [`AttestationsDiff::FullReplacement`] clears the existing buffer and
/// replaces it with the serialized target bytes.
///
/// # Complexity
///
/// - [`AttestationsDiff::Unchanged`][]: O(1).
/// - [`AttestationsDiff::Append`]: O(k), where *k* is the number of appended
/// bytes.
/// - [`AttestationsDiff::FullReplacement`]: O(n), where *n* is the size of the
/// replacement list.
///
/// # Example
///
/// ```
/// # use eth_state_diff::attestations::{apply_attestations, diff_attestations};
/// # use eth_state_diff::types::AttestationsDiff;
///
/// let mut base = b"AAAA".to_vec();
/// let delta = diff_attestations(&base, b"AAAABBBB");
///
/// match delta {
/// AttestationsDiff::Unchanged => {}
/// AttestationsDiff::Append(bytes) => base.extend_from_slice(&bytes),
/// AttestationsDiff::FullReplacement(bytes) => {
/// base.clear();
/// base.extend_from_slice(&bytes);
/// }
/// }
///
/// assert_eq!(base, b"AAAABBBB");
/// ```