reth_transaction_pool/
identifier.rs

1//! Identifier types for transactions and senders.
2use alloy_primitives::{map::HashMap, Address};
3use rustc_hash::FxHashMap;
4
5/// An internal mapping of addresses.
6///
7/// This assigns a _unique_ [`SenderId`] for a new [`Address`].
8/// It has capacity for 2^64 unique addresses.
9#[derive(Debug, Default)]
10pub struct SenderIdentifiers {
11    /// The identifier to use next.
12    id: u64,
13    /// Assigned [`SenderId`] for an [`Address`].
14    address_to_id: HashMap<Address, SenderId>,
15    /// Reverse mapping of [`SenderId`] to [`Address`].
16    sender_to_address: FxHashMap<SenderId, Address>,
17}
18
19impl SenderIdentifiers {
20    /// Returns the address for the given identifier.
21    pub fn address(&self, id: &SenderId) -> Option<&Address> {
22        self.sender_to_address.get(id)
23    }
24
25    /// Returns the [`SenderId`] that belongs to the given address, if it exists
26    pub fn sender_id(&self, addr: &Address) -> Option<SenderId> {
27        self.address_to_id.get(addr).copied()
28    }
29
30    /// Returns the existing [`SenderId`] or assigns a new one if it's missing
31    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    /// Returns the existing [`SenderId`] or assigns a new one if it's missing
41    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    /// Returns the current identifier and increments the counter.
49    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/// A _unique_ identifier for a sender of an address.
57///
58/// This is the identifier of an internal `address` mapping that is valid in the context of this
59/// program.
60#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
61pub struct SenderId(u64);
62
63impl SenderId {
64    /// Returns a `Bound` for [`TransactionId`] starting with nonce `0`
65    pub const fn start_bound(self) -> std::ops::Bound<TransactionId> {
66        std::ops::Bound::Included(TransactionId::new(self, 0))
67    }
68
69    /// Returns a `Range` for [`TransactionId`] starting with nonce `0` and ending with nonce
70    /// `u64::MAX`
71    pub const fn range(self) -> std::ops::RangeInclusive<TransactionId> {
72        TransactionId::new(self, 0)..=TransactionId::new(self, u64::MAX)
73    }
74
75    /// Converts the sender to a [`TransactionId`] with the given nonce.
76    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/// A unique identifier of a transaction of a Sender.
88///
89/// This serves as an identifier for dependencies of a transaction:
90/// A transaction with a nonce higher than the current state nonce depends on `tx.nonce - 1`.
91#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
92pub struct TransactionId {
93    /// Sender of this transaction
94    pub sender: SenderId,
95    /// Nonce of this transaction
96    pub nonce: u64,
97}
98
99impl TransactionId {
100    /// Create a new identifier pair
101    pub const fn new(sender: SenderId, nonce: u64) -> Self {
102        Self { sender, nonce }
103    }
104
105    /// Returns the [`TransactionId`] this transaction depends on.
106    ///
107    /// This returns `transaction_nonce - 1` if `transaction_nonce` is higher than the
108    /// `on_chain_nonce`
109    pub fn ancestor(transaction_nonce: u64, on_chain_nonce: u64, sender: SenderId) -> Option<Self> {
110        // SAFETY: transaction_nonce > on_chain_nonce ⇒ transaction_nonce >= 1
111        (transaction_nonce > on_chain_nonce).then(|| Self::new(sender, transaction_nonce - 1))
112    }
113
114    /// Returns the [`TransactionId`] that would come before this transaction.
115    pub fn unchecked_ancestor(&self) -> Option<Self> {
116        // SAFETY: self.nonce != 0 ⇒ self.nonce >= 1
117        (self.nonce != 0).then(|| Self::new(self.sender, self.nonce - 1))
118    }
119
120    /// Returns the [`TransactionId`] that directly follows this transaction: `self.nonce + 1`
121    pub const fn descendant(&self) -> Self {
122        Self::new(self.sender, self.next_nonce())
123    }
124
125    /// Returns the nonce that follows immediately after this one.
126    #[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        // Special case with nonce 0 and higher on-chain nonce
150        let tx_id = TransactionId::ancestor(0, 1, sender);
151        assert_eq!(tx_id, None);
152
153        // Special case with nonce 0 and same on-chain nonce
154        let tx_id = TransactionId::ancestor(0, 0, sender);
155        assert_eq!(tx_id, None);
156
157        // Ancestor is the previous nonce if the transaction nonce is higher than the on-chain nonce
158        let tx_id = TransactionId::ancestor(5, 0, sender);
159        assert_eq!(tx_id, Some(TransactionId::new(sender, 4)));
160
161        // No ancestor if the transaction nonce is the same as the on-chain nonce
162        let tx_id = TransactionId::ancestor(5, 5, sender);
163        assert_eq!(tx_id, None);
164
165        // No ancestor if the transaction nonce is lower than the on-chain nonce
166        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        // Ancestor is the previous nonce if transaction nonce is higher than 0
175        let tx_id = TransactionId::new(sender, 5);
176        assert_eq!(tx_id.unchecked_ancestor(), Some(TransactionId::new(sender, 4)));
177
178        // No ancestor if transaction nonce is 0
179        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        // The current ID is `u64::MAX`, the next ID should wrap around to 0.
256        let id1 = identifiers.next_id();
257        assert_eq!(id1, SenderId(u64::MAX));
258
259        // The next ID should now be 0 because of wrapping.
260        let id2 = identifiers.next_id();
261        assert_eq!(id2, SenderId(0));
262
263        // And then 1, continuing incrementing.
264        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}