eth_state_diff/
balances.rs1use rustc_hash::FxHashMap;
22
23use crate::types::{
24 ArchivedBalancesDiff, BalancesDiff, BitTagVec, SET_NO_CHANGE, SET_TO_DIFF, SET_TO_TARGET_VALUE,
25 SET_TO_ZERO,
26};
27
28#[inline]
29fn zigzag_encode(n: i64) -> u64 {
30 ((n << 1) ^ (n >> 63)) as u64
31}
32
33pub(super) fn write_varint(mut val: u64, buf: &mut Vec<u8>) {
34 loop {
35 if val < 0x80 {
36 buf.push(val as u8);
37 break;
38 }
39 buf.push((val as u8) | 0x80);
40 val >>= 7;
41 }
42}
43
44pub fn diff_balances(base: &[u64], target: &[u64]) -> BalancesDiff {
63 let common_len = base.len().min(target.len());
64
65 let mut freq_map = FxHashMap::default();
66 freq_map.reserve(1024);
67
68 for i in 0..common_len {
69 let v1 = base[i];
70 let v2 = target[i];
71 if v1 != v2 {
72 let diff = v2 as i64 - v1 as i64;
73 *freq_map.entry(diff).or_insert(0usize) += 1;
74 }
75 }
76
77 let mode = freq_map
78 .into_iter()
79 .max_by_key(|&(_, count)| count)
80 .map(|(val, _)| val)
81 .unwrap_or(0);
82
83 let mut tags = BitTagVec::new(common_len);
84
85 let mut varint_payload = Vec::with_capacity(common_len / 2);
86 let mut target_values = Vec::new();
87
88 for i in 0..common_len {
89 let v1 = base[i];
90 let v2 = target[i];
91
92 if v1 == v2 {
93 continue; }
95
96 if v2 == 0 {
97 tags.set(i, SET_TO_ZERO);
98 } else if v1 == 0 {
99 tags.set(i, SET_TO_TARGET_VALUE);
100 target_values.push(v2);
101 } else {
102 let diff = v2 as i64 - v1 as i64;
103
104 if let Ok(_diff_i32) = i32::try_from(diff) {
105 tags.set(i, SET_TO_DIFF);
106 let corrected = diff - mode;
107 let encoded = zigzag_encode(corrected);
108 write_varint(encoded, &mut varint_payload);
109 } else {
110 tags.set(i, SET_TO_TARGET_VALUE);
111 target_values.push(v2);
112 }
113 }
114 }
115
116 let appended_balances = if target.len() > base.len() {
117 target[base.len()..].to_vec()
118 } else {
119 Vec::new()
120 };
121
122 BalancesDiff {
123 tags,
124 mode,
125 varint_payload,
126 target_values,
127 appended_balances,
128 }
129}
130
131#[inline]
132fn zigzag_decode(n: u64) -> i64 {
133 ((n >> 1) as i64) ^ -((n & 1) as i64)
134}
135
136#[inline]
137pub(super) fn read_varint(buf: &[u8], cursor: &mut usize) -> u64 {
138 let mut val = 0u64;
139 let mut shift = 0u32;
140
141 loop {
142 let byte = buf[*cursor];
145 *cursor += 1;
146
147 val |= ((byte & 0x7F) as u64) << shift;
148
149 if (byte & 0x80) == 0 {
151 break;
152 }
153 shift += 7;
154 }
155
156 val
157}
158
159pub fn apply_balances(base: &mut Vec<u64>, delta: &ArchivedBalancesDiff) {
171 let mode = delta.mode.to_native();
172
173 let tag_len = delta.tags.len.to_native() as usize;
174
175 debug_assert_eq!(
176 base.len(),
177 tag_len,
178 "Base balance length does not match delta tag length"
179 );
180
181 let mut target_iter = delta.target_values.iter();
182 let payload = delta.varint_payload.as_slice();
183 let mut payload_cursor = 0usize;
184
185 let mut base_idx = 0usize;
186
187 for &tag_byte in delta.tags.data.iter() {
188 if base_idx >= tag_len {
189 break;
190 }
191
192 if tag_byte == 0 {
194 base_idx = (base_idx + 4).min(tag_len);
195 continue;
196 }
197
198 for bit in 0..4 {
199 if base_idx >= tag_len {
200 break;
201 }
202
203 let tag = (tag_byte >> (bit * 2)) & 0b11;
204
205 match tag {
206 SET_NO_CHANGE => {}
207 SET_TO_ZERO => {
208 base[base_idx] = 0;
209 }
210 SET_TO_TARGET_VALUE => {
211 base[base_idx] = target_iter.next().unwrap().to_native();
212 }
213 SET_TO_DIFF => {
214 let encoded = read_varint(payload, &mut payload_cursor);
215 let corrected = zigzag_decode(encoded);
216 let diff = corrected + mode;
217 base[base_idx] = (base[base_idx] as i64 + diff) as u64;
218 }
219 _ => unreachable!("Invalid 2-bit tag state encountered during apply"),
220 }
221
222 base_idx += 1;
223 }
224 }
225
226 if !delta.appended_balances.is_empty() {
227 base.extend(delta.appended_balances.iter().map(|v| v.to_native()));
228 }
229}