reth_trie_common/
target_v2.rs1use crate::Nibbles;
4use alloc::vec::Vec;
5use alloy_primitives::{keccak256, map::B256Map, B256};
6use revm_state::EvmState;
7
8#[derive(Debug, Copy, Clone)]
11pub struct ProofV2Target {
12 pub key_nibbles: Nibbles,
14 pub min_len: u8,
16}
17
18impl ProofV2Target {
19 pub fn new(key: B256) -> Self {
22 let key_nibbles = unsafe { Nibbles::unpack_unchecked(key.as_slice()) };
24 Self { key_nibbles, min_len: 0 }
25 }
26
27 pub fn key(&self) -> B256 {
29 B256::from_slice(&self.key_nibbles.pack())
30 }
31
32 pub fn with_min_len(mut self, min_len: u8) -> Self {
38 debug_assert!(min_len <= 64);
39 self.min_len = min_len;
40 self
41 }
42}
43
44impl From<B256> for ProofV2Target {
45 fn from(key: B256) -> Self {
46 Self::new(key)
47 }
48}
49
50#[derive(Debug, Default)]
53pub struct MultiProofTargetsV2 {
54 pub account_targets: Vec<ProofV2Target>,
56 pub storage_targets: B256Map<Vec<ProofV2Target>>,
58}
59
60impl MultiProofTargetsV2 {
61 pub fn is_empty(&self) -> bool {
63 self.account_targets.is_empty() && self.storage_targets.is_empty()
64 }
65
66 pub fn chunking_length(&self) -> usize {
68 self.account_targets.len() +
69 self.storage_targets.values().map(|slots| slots.len()).sum::<usize>()
70 }
71
72 pub fn chunks(self, chunk_size: usize) -> impl Iterator<Item = Self> {
74 ChunkedMultiProofTargetsV2::new(self, chunk_size)
75 }
76
77 pub fn from_state(state: EvmState) -> (Self, usize) {
80 let mut targets = Self::default();
81 targets.account_targets.reserve(state.len());
82 targets.storage_targets.reserve(state.len());
83 let mut storage_target_count = 0;
84 for (addr, account) in state {
85 if !account.is_touched() || account.is_selfdestructed() {
93 continue
94 }
95
96 let hashed_address = keccak256(addr);
97
98 if account.info != account.original_info() {
99 targets.account_targets.push(hashed_address.into());
100 }
101
102 let mut storage_slots = Vec::with_capacity(account.storage.len());
103 for (key, slot) in account.storage {
104 if !slot.is_changed() {
106 continue
107 }
108
109 let hashed_slot = keccak256(B256::new(key.to_be_bytes()));
110 storage_slots.push(ProofV2Target::from(hashed_slot));
111 }
112
113 storage_target_count += storage_slots.len();
114 if !storage_slots.is_empty() {
115 targets.storage_targets.insert(hashed_address, storage_slots);
116 }
117 }
118
119 (targets, storage_target_count)
120 }
121}
122
123#[derive(Debug)]
131pub struct ChunkedMultiProofTargetsV2 {
132 account_targets: alloc::vec::IntoIter<ProofV2Target>,
134 storage_targets: B256Map<Vec<ProofV2Target>>,
136 current_account_storage: Option<(B256, alloc::vec::IntoIter<ProofV2Target>)>,
138 size: usize,
140}
141
142impl ChunkedMultiProofTargetsV2 {
143 pub fn new(targets: MultiProofTargetsV2, size: usize) -> Self {
145 Self {
146 account_targets: targets.account_targets.into_iter(),
147 storage_targets: targets.storage_targets,
148 current_account_storage: None,
149 size,
150 }
151 }
152}
153
154impl Iterator for ChunkedMultiProofTargetsV2 {
155 type Item = MultiProofTargetsV2;
156
157 fn next(&mut self) -> Option<Self::Item> {
158 let mut chunk = MultiProofTargetsV2::default();
159 let mut count = 0;
160
161 if let Some((account_addr, ref mut storage_iter)) = self.current_account_storage {
163 let remaining_capacity = self.size - count;
164 let slots: Vec<_> = storage_iter.by_ref().take(remaining_capacity).collect();
165
166 count += slots.len();
167 chunk.storage_targets.insert(account_addr, slots);
168
169 if storage_iter.len() == 0 {
171 self.current_account_storage = None;
172 }
173 }
174
175 while count < self.size {
177 let Some(account_target) = self.account_targets.next() else {
178 break;
179 };
180
181 chunk.account_targets.push(account_target);
183 count += 1;
184
185 let account_addr = account_target.key();
187 if let Some(storage_slots) = self.storage_targets.remove(&account_addr) {
188 let remaining_capacity = self.size - count;
189
190 if storage_slots.len() <= remaining_capacity {
191 count += storage_slots.len();
193 chunk.storage_targets.insert(account_addr, storage_slots);
194 } else {
195 let mut storage_iter = storage_slots.into_iter();
197 let slots_in_chunk: Vec<_> =
198 storage_iter.by_ref().take(remaining_capacity).collect();
199 count += slots_in_chunk.len();
200
201 chunk.storage_targets.insert(account_addr, slots_in_chunk);
202
203 self.current_account_storage = Some((account_addr, storage_iter));
205 break;
206 }
207 }
208 }
209
210 while let Some((account_addr, storage_slots)) = self.storage_targets.iter_mut().next() &&
212 count < self.size
213 {
214 let account_addr = *account_addr;
215 let storage_slots = core::mem::take(storage_slots);
216 let remaining_capacity = self.size - count;
217
218 self.storage_targets.remove(&account_addr);
221
222 if storage_slots.len() <= remaining_capacity {
223 count += storage_slots.len();
225 chunk.storage_targets.insert(account_addr, storage_slots);
226 } else {
227 let mut storage_iter = storage_slots.into_iter();
229 let slots_in_chunk: Vec<_> =
230 storage_iter.by_ref().take(remaining_capacity).collect();
231
232 chunk.storage_targets.insert(account_addr, slots_in_chunk);
233
234 if storage_iter.len() > 0 {
236 self.current_account_storage = Some((account_addr, storage_iter));
237 }
238 break;
239 }
240 }
241
242 if chunk.account_targets.is_empty() && chunk.storage_targets.is_empty() {
243 None
244 } else {
245 Some(chunk)
246 }
247 }
248}