1use alloy_primitives::{map::HashMap, Address};
3use rustc_hash::FxHashMap;
4
5#[derive(Debug, Default)]
10pub struct SenderIdentifiers {
11 id: u64,
13 address_to_id: HashMap<Address, SenderId>,
15 sender_to_address: FxHashMap<SenderId, Address>,
17}
18
19impl SenderIdentifiers {
20 pub fn address(&self, id: &SenderId) -> Option<&Address> {
22 self.sender_to_address.get(id)
23 }
24
25 pub fn sender_id(&self, addr: &Address) -> Option<SenderId> {
27 self.address_to_id.get(addr).copied()
28 }
29
30 pub fn sender_id_or_create(&mut self, addr: Address) -> SenderId {
32 self.sender_id(&addr).unwrap_or_else(|| {
33 let id = self.next_id();
34 self.address_to_id.insert(addr, id);
35 self.sender_to_address.insert(id, addr);
36 id
37 })
38 }
39
40 pub fn sender_ids_or_create(
42 &mut self,
43 addrs: impl IntoIterator<Item = Address>,
44 ) -> Vec<SenderId> {
45 addrs.into_iter().map(|addr| self.sender_id_or_create(addr)).collect()
46 }
47
48 fn next_id(&mut self) -> SenderId {
50 let id = self.id;
51 self.id = self.id.wrapping_add(1);
52 id.into()
53 }
54}
55
56#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
61pub struct SenderId(u64);
62
63impl SenderId {
64 pub const fn start_bound(self) -> std::ops::Bound<TransactionId> {
66 std::ops::Bound::Included(TransactionId::new(self, 0))
67 }
68
69 pub const fn range(self) -> std::ops::RangeInclusive<TransactionId> {
72 TransactionId::new(self, 0)..=TransactionId::new(self, u64::MAX)
73 }
74
75 pub const fn into_transaction_id(self, nonce: u64) -> TransactionId {
77 TransactionId::new(self, nonce)
78 }
79}
80
81impl From<u64> for SenderId {
82 fn from(value: u64) -> Self {
83 Self(value)
84 }
85}
86
87#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
92pub struct TransactionId {
93 pub sender: SenderId,
95 pub nonce: u64,
97}
98
99impl TransactionId {
100 pub const fn new(sender: SenderId, nonce: u64) -> Self {
102 Self { sender, nonce }
103 }
104
105 pub fn ancestor(transaction_nonce: u64, on_chain_nonce: u64, sender: SenderId) -> Option<Self> {
110 (transaction_nonce > on_chain_nonce).then(|| Self::new(sender, transaction_nonce - 1))
112 }
113
114 pub fn unchecked_ancestor(&self) -> Option<Self> {
116 (self.nonce != 0).then(|| Self::new(self.sender, self.nonce - 1))
118 }
119
120 pub const fn descendant(&self) -> Self {
122 Self::new(self.sender, self.next_nonce())
123 }
124
125 #[inline]
127 pub const fn next_nonce(&self) -> u64 {
128 self.nonce + 1
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use std::collections::BTreeSet;
136
137 #[test]
138 fn test_transaction_id_new() {
139 let sender = SenderId(1);
140 let tx_id = TransactionId::new(sender, 5);
141 assert_eq!(tx_id.sender, sender);
142 assert_eq!(tx_id.nonce, 5);
143 }
144
145 #[test]
146 fn test_transaction_id_ancestor() {
147 let sender = SenderId(1);
148
149 let tx_id = TransactionId::ancestor(0, 1, sender);
151 assert_eq!(tx_id, None);
152
153 let tx_id = TransactionId::ancestor(0, 0, sender);
155 assert_eq!(tx_id, None);
156
157 let tx_id = TransactionId::ancestor(5, 0, sender);
159 assert_eq!(tx_id, Some(TransactionId::new(sender, 4)));
160
161 let tx_id = TransactionId::ancestor(5, 5, sender);
163 assert_eq!(tx_id, None);
164
165 let tx_id = TransactionId::ancestor(5, 15, sender);
167 assert_eq!(tx_id, None);
168 }
169
170 #[test]
171 fn test_transaction_id_unchecked_ancestor() {
172 let sender = SenderId(1);
173
174 let tx_id = TransactionId::new(sender, 5);
176 assert_eq!(tx_id.unchecked_ancestor(), Some(TransactionId::new(sender, 4)));
177
178 let tx_id = TransactionId::new(sender, 0);
180 assert_eq!(tx_id.unchecked_ancestor(), None);
181 }
182
183 #[test]
184 fn test_transaction_id_descendant() {
185 let sender = SenderId(1);
186 let tx_id = TransactionId::new(sender, 5);
187 let descendant = tx_id.descendant();
188 assert_eq!(descendant, TransactionId::new(sender, 6));
189 }
190
191 #[test]
192 fn test_transaction_id_next_nonce() {
193 let sender = SenderId(1);
194 let tx_id = TransactionId::new(sender, 5);
195 assert_eq!(tx_id.next_nonce(), 6);
196 }
197
198 #[test]
199 fn test_transaction_id_ord_eq_sender() {
200 let tx1 = TransactionId::new(100u64.into(), 0u64);
201 let tx2 = TransactionId::new(100u64.into(), 1u64);
202 assert!(tx2 > tx1);
203 let set = BTreeSet::from([tx1, tx2]);
204 assert_eq!(set.into_iter().collect::<Vec<_>>(), vec![tx1, tx2]);
205 }
206
207 #[test]
208 fn test_transaction_id_ord() {
209 let tx1 = TransactionId::new(99u64.into(), 0u64);
210 let tx2 = TransactionId::new(100u64.into(), 1u64);
211 assert!(tx2 > tx1);
212 let set = BTreeSet::from([tx1, tx2]);
213 assert_eq!(set.into_iter().collect::<Vec<_>>(), vec![tx1, tx2]);
214 }
215
216 #[test]
217 fn test_address_retrieval() {
218 let mut identifiers = SenderIdentifiers::default();
219 let address = Address::new([1; 20]);
220 let id = identifiers.sender_id_or_create(address);
221 assert_eq!(identifiers.address(&id), Some(&address));
222 }
223
224 #[test]
225 fn test_sender_id_retrieval() {
226 let mut identifiers = SenderIdentifiers::default();
227 let address = Address::new([1; 20]);
228 let id = identifiers.sender_id_or_create(address);
229 assert_eq!(identifiers.sender_id(&address), Some(id));
230 }
231
232 #[test]
233 fn test_sender_id_or_create_existing() {
234 let mut identifiers = SenderIdentifiers::default();
235 let address = Address::new([1; 20]);
236 let id1 = identifiers.sender_id_or_create(address);
237 let id2 = identifiers.sender_id_or_create(address);
238 assert_eq!(id1, id2);
239 }
240
241 #[test]
242 fn test_sender_id_or_create_new() {
243 let mut identifiers = SenderIdentifiers::default();
244 let address1 = Address::new([1; 20]);
245 let address2 = Address::new([2; 20]);
246 let id1 = identifiers.sender_id_or_create(address1);
247 let id2 = identifiers.sender_id_or_create(address2);
248 assert_ne!(id1, id2);
249 }
250
251 #[test]
252 fn test_next_id_wrapping() {
253 let mut identifiers = SenderIdentifiers { id: u64::MAX, ..Default::default() };
254
255 let id1 = identifiers.next_id();
257 assert_eq!(id1, SenderId(u64::MAX));
258
259 let id2 = identifiers.next_id();
261 assert_eq!(id2, SenderId(0));
262
263 let id3 = identifiers.next_id();
265 assert_eq!(id3, SenderId(1));
266 }
267
268 #[test]
269 fn test_sender_id_start_bound() {
270 let sender = SenderId(1);
271 let start_bound = sender.start_bound();
272 if let std::ops::Bound::Included(tx_id) = start_bound {
273 assert_eq!(tx_id, TransactionId::new(sender, 0));
274 } else {
275 panic!("Expected included bound");
276 }
277 }
278}