1use alloy_primitives::Address;
3use rustc_hash::FxHashMap;
4use std::collections::HashMap;
5
6#[derive(Debug, Default)]
11pub struct SenderIdentifiers {
12 id: u64,
14 address_to_id: HashMap<Address, SenderId>,
16 sender_to_address: FxHashMap<SenderId, Address>,
18}
19
20impl SenderIdentifiers {
21 pub fn address(&self, id: &SenderId) -> Option<&Address> {
23 self.sender_to_address.get(id)
24 }
25
26 pub fn sender_id(&self, addr: &Address) -> Option<SenderId> {
28 self.address_to_id.get(addr).copied()
29 }
30
31 pub fn sender_id_or_create(&mut self, addr: Address) -> SenderId {
33 self.sender_id(&addr).unwrap_or_else(|| {
34 let id = self.next_id();
35 self.address_to_id.insert(addr, id);
36 self.sender_to_address.insert(id, addr);
37 id
38 })
39 }
40
41 fn next_id(&mut self) -> SenderId {
43 let id = self.id;
44 self.id = self.id.wrapping_add(1);
45 id.into()
46 }
47}
48
49#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
54pub struct SenderId(u64);
55
56impl SenderId {
57 pub const fn start_bound(self) -> std::ops::Bound<TransactionId> {
59 std::ops::Bound::Included(TransactionId::new(self, 0))
60 }
61
62 pub const fn into_transaction_id(self, nonce: u64) -> TransactionId {
64 TransactionId::new(self, nonce)
65 }
66}
67
68impl From<u64> for SenderId {
69 fn from(value: u64) -> Self {
70 Self(value)
71 }
72}
73
74#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
79pub struct TransactionId {
80 pub sender: SenderId,
82 pub nonce: u64,
84}
85
86impl TransactionId {
87 pub const fn new(sender: SenderId, nonce: u64) -> Self {
89 Self { sender, nonce }
90 }
91
92 pub fn ancestor(transaction_nonce: u64, on_chain_nonce: u64, sender: SenderId) -> Option<Self> {
97 (transaction_nonce > on_chain_nonce)
98 .then(|| Self::new(sender, transaction_nonce.saturating_sub(1)))
99 }
100
101 pub fn unchecked_ancestor(&self) -> Option<Self> {
103 (self.nonce != 0).then(|| Self::new(self.sender, self.nonce - 1))
104 }
105
106 pub const fn descendant(&self) -> Self {
108 Self::new(self.sender, self.next_nonce())
109 }
110
111 #[inline]
113 pub const fn next_nonce(&self) -> u64 {
114 self.nonce + 1
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use std::collections::BTreeSet;
122
123 #[test]
124 fn test_transaction_id_new() {
125 let sender = SenderId(1);
126 let tx_id = TransactionId::new(sender, 5);
127 assert_eq!(tx_id.sender, sender);
128 assert_eq!(tx_id.nonce, 5);
129 }
130
131 #[test]
132 fn test_transaction_id_ancestor() {
133 let sender = SenderId(1);
134
135 let tx_id = TransactionId::ancestor(0, 1, sender);
137 assert_eq!(tx_id, None);
138
139 let tx_id = TransactionId::ancestor(0, 0, sender);
141 assert_eq!(tx_id, None);
142
143 let tx_id = TransactionId::ancestor(5, 0, sender);
145 assert_eq!(tx_id, Some(TransactionId::new(sender, 4)));
146
147 let tx_id = TransactionId::ancestor(5, 5, sender);
149 assert_eq!(tx_id, None);
150
151 let tx_id = TransactionId::ancestor(5, 15, sender);
153 assert_eq!(tx_id, None);
154 }
155
156 #[test]
157 fn test_transaction_id_unchecked_ancestor() {
158 let sender = SenderId(1);
159
160 let tx_id = TransactionId::new(sender, 5);
162 assert_eq!(tx_id.unchecked_ancestor(), Some(TransactionId::new(sender, 4)));
163
164 let tx_id = TransactionId::new(sender, 0);
166 assert_eq!(tx_id.unchecked_ancestor(), None);
167 }
168
169 #[test]
170 fn test_transaction_id_descendant() {
171 let sender = SenderId(1);
172 let tx_id = TransactionId::new(sender, 5);
173 let descendant = tx_id.descendant();
174 assert_eq!(descendant, TransactionId::new(sender, 6));
175 }
176
177 #[test]
178 fn test_transaction_id_next_nonce() {
179 let sender = SenderId(1);
180 let tx_id = TransactionId::new(sender, 5);
181 assert_eq!(tx_id.next_nonce(), 6);
182 }
183
184 #[test]
185 fn test_transaction_id_ord_eq_sender() {
186 let tx1 = TransactionId::new(100u64.into(), 0u64);
187 let tx2 = TransactionId::new(100u64.into(), 1u64);
188 assert!(tx2 > tx1);
189 let set = BTreeSet::from([tx1, tx2]);
190 assert_eq!(set.into_iter().collect::<Vec<_>>(), vec![tx1, tx2]);
191 }
192
193 #[test]
194 fn test_transaction_id_ord() {
195 let tx1 = TransactionId::new(99u64.into(), 0u64);
196 let tx2 = TransactionId::new(100u64.into(), 1u64);
197 assert!(tx2 > tx1);
198 let set = BTreeSet::from([tx1, tx2]);
199 assert_eq!(set.into_iter().collect::<Vec<_>>(), vec![tx1, tx2]);
200 }
201
202 #[test]
203 fn test_address_retrieval() {
204 let mut identifiers = SenderIdentifiers::default();
205 let address = Address::new([1; 20]);
206 let id = identifiers.sender_id_or_create(address);
207 assert_eq!(identifiers.address(&id), Some(&address));
208 }
209
210 #[test]
211 fn test_sender_id_retrieval() {
212 let mut identifiers = SenderIdentifiers::default();
213 let address = Address::new([1; 20]);
214 let id = identifiers.sender_id_or_create(address);
215 assert_eq!(identifiers.sender_id(&address), Some(id));
216 }
217
218 #[test]
219 fn test_sender_id_or_create_existing() {
220 let mut identifiers = SenderIdentifiers::default();
221 let address = Address::new([1; 20]);
222 let id1 = identifiers.sender_id_or_create(address);
223 let id2 = identifiers.sender_id_or_create(address);
224 assert_eq!(id1, id2);
225 }
226
227 #[test]
228 fn test_sender_id_or_create_new() {
229 let mut identifiers = SenderIdentifiers::default();
230 let address1 = Address::new([1; 20]);
231 let address2 = Address::new([2; 20]);
232 let id1 = identifiers.sender_id_or_create(address1);
233 let id2 = identifiers.sender_id_or_create(address2);
234 assert_ne!(id1, id2);
235 }
236
237 #[test]
238 fn test_next_id_wrapping() {
239 let mut identifiers = SenderIdentifiers { id: u64::MAX, ..Default::default() };
240
241 let id1 = identifiers.next_id();
243 assert_eq!(id1, SenderId(u64::MAX));
244
245 let id2 = identifiers.next_id();
247 assert_eq!(id2, SenderId(0));
248
249 let id3 = identifiers.next_id();
251 assert_eq!(id3, SenderId(1));
252 }
253
254 #[test]
255 fn test_sender_id_start_bound() {
256 let sender = SenderId(1);
257 let start_bound = sender.start_bound();
258 if let std::ops::Bound::Included(tx_id) = start_bound {
259 assert_eq!(tx_id, TransactionId::new(sender, 0));
260 } else {
261 panic!("Expected included bound");
262 }
263 }
264}