reth_trie_common/
target_v2.rs1use crate::Nibbles;
4use alloc::vec::Vec;
5use alloy_primitives::{map::B256Map, B256};
6
7#[derive(Debug, Copy, Clone)]
10pub struct ProofV2Target {
11 pub key_nibbles: Nibbles,
13 pub min_len: u8,
15}
16
17impl ProofV2Target {
18 pub fn new(key: B256) -> Self {
21 let key_nibbles = unsafe { Nibbles::unpack_unchecked(key.as_slice()) };
23 Self { key_nibbles, min_len: 0 }
24 }
25
26 pub fn key(&self) -> B256 {
28 B256::from_slice(&self.key_nibbles.pack())
29 }
30
31 pub fn with_min_len(mut self, min_len: u8) -> Self {
37 debug_assert!(min_len <= 64);
38 self.min_len = min_len;
39 self
40 }
41}
42
43impl From<B256> for ProofV2Target {
44 fn from(key: B256) -> Self {
45 Self::new(key)
46 }
47}
48
49#[derive(Debug, Default)]
52pub struct MultiProofTargetsV2 {
53 pub account_targets: Vec<ProofV2Target>,
55 pub storage_targets: B256Map<Vec<ProofV2Target>>,
57}
58
59impl MultiProofTargetsV2 {
60 pub fn is_empty(&self) -> bool {
62 self.account_targets.is_empty() && self.storage_targets.is_empty()
63 }
64
65 pub fn chunking_length(&self) -> usize {
67 self.account_targets.len() +
68 self.storage_targets.values().map(|slots| slots.len()).sum::<usize>()
69 }
70
71 pub fn chunks(self, chunk_size: usize) -> impl Iterator<Item = Self> {
73 ChunkedMultiProofTargetsV2::new(self, chunk_size)
74 }
75}
76
77#[derive(Debug)]
85pub struct ChunkedMultiProofTargetsV2 {
86 account_targets: alloc::vec::IntoIter<ProofV2Target>,
88 storage_targets: B256Map<Vec<ProofV2Target>>,
90 current_account_storage: Option<(B256, alloc::vec::IntoIter<ProofV2Target>)>,
92 size: usize,
94}
95
96impl ChunkedMultiProofTargetsV2 {
97 pub fn new(targets: MultiProofTargetsV2, size: usize) -> Self {
99 Self {
100 account_targets: targets.account_targets.into_iter(),
101 storage_targets: targets.storage_targets,
102 current_account_storage: None,
103 size,
104 }
105 }
106}
107
108impl Iterator for ChunkedMultiProofTargetsV2 {
109 type Item = MultiProofTargetsV2;
110
111 fn next(&mut self) -> Option<Self::Item> {
112 let mut chunk = MultiProofTargetsV2::default();
113 let mut count = 0;
114
115 if let Some((account_addr, ref mut storage_iter)) = self.current_account_storage {
117 let remaining_capacity = self.size - count;
118 let slots: Vec<_> = storage_iter.by_ref().take(remaining_capacity).collect();
119
120 count += slots.len();
121 chunk.storage_targets.insert(account_addr, slots);
122
123 if storage_iter.len() == 0 {
125 self.current_account_storage = None;
126 }
127 }
128
129 while count < self.size {
131 let Some(account_target) = self.account_targets.next() else {
132 break;
133 };
134
135 chunk.account_targets.push(account_target);
137 count += 1;
138
139 let account_addr = account_target.key();
141 if let Some(storage_slots) = self.storage_targets.remove(&account_addr) {
142 let remaining_capacity = self.size - count;
143
144 if storage_slots.len() <= remaining_capacity {
145 count += storage_slots.len();
147 chunk.storage_targets.insert(account_addr, storage_slots);
148 } else {
149 let mut storage_iter = storage_slots.into_iter();
151 let slots_in_chunk: Vec<_> =
152 storage_iter.by_ref().take(remaining_capacity).collect();
153 count += slots_in_chunk.len();
154
155 chunk.storage_targets.insert(account_addr, slots_in_chunk);
156
157 self.current_account_storage = Some((account_addr, storage_iter));
159 break;
160 }
161 }
162 }
163
164 while let Some((account_addr, storage_slots)) = self.storage_targets.iter_mut().next() &&
166 count < self.size
167 {
168 let account_addr = *account_addr;
169 let storage_slots = core::mem::take(storage_slots);
170 let remaining_capacity = self.size - count;
171
172 self.storage_targets.remove(&account_addr);
175
176 if storage_slots.len() <= remaining_capacity {
177 count += storage_slots.len();
179 chunk.storage_targets.insert(account_addr, storage_slots);
180 } else {
181 let mut storage_iter = storage_slots.into_iter();
183 let slots_in_chunk: Vec<_> =
184 storage_iter.by_ref().take(remaining_capacity).collect();
185
186 chunk.storage_targets.insert(account_addr, slots_in_chunk);
187
188 if storage_iter.len() > 0 {
190 self.current_account_storage = Some((account_addr, storage_iter));
191 }
192 break;
193 }
194 }
195
196 if chunk.account_targets.is_empty() && chunk.storage_targets.is_empty() {
197 None
198 } else {
199 Some(chunk)
200 }
201 }
202}