reth_rpc_eth_types/
id_provider.rs

1//! Helper type for `reth_rpc_eth_api::EthPubSubApiServer` implementation.
2//!
3//! Generates IDs for tracking subscriptions.
4
5use std::fmt::Write;
6
7use jsonrpsee_types::SubscriptionId;
8
9/// An [`IdProvider`](jsonrpsee_core::traits::IdProvider) for ethereum subscription ids.
10///
11/// Returns new hex-string [QUANTITY](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding) ids
12#[derive(Debug, Clone, Copy, Default)]
13#[non_exhaustive]
14pub struct EthSubscriptionIdProvider;
15
16impl jsonrpsee_core::traits::IdProvider for EthSubscriptionIdProvider {
17    fn next_id(&self) -> SubscriptionId<'static> {
18        to_quantity(rand::random::<u128>())
19    }
20}
21
22/// Returns a hex quantity string for the given value
23///
24/// Strips all leading zeros, `0` is returned as `0x0`
25#[inline(always)]
26fn to_quantity(val: u128) -> SubscriptionId<'static> {
27    let bytes = val.to_be_bytes();
28    let b = bytes.as_slice();
29    let non_zero = b.iter().take_while(|b| **b == 0).count();
30    let b = &b[non_zero..];
31    if b.is_empty() {
32        return SubscriptionId::Str("0x0".into())
33    }
34
35    let mut id = String::with_capacity(2 * b.len() + 2);
36    id.push_str("0x");
37    let first_byte = b[0];
38    write!(id, "{first_byte:x}").unwrap();
39
40    for byte in &b[1..] {
41        write!(id, "{byte:02x}").unwrap();
42    }
43    id.into()
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use alloy_primitives::U128;
50
51    #[test]
52    fn test_id_provider_quantity() {
53        let id = to_quantity(0);
54        assert_eq!(id, SubscriptionId::Str("0x0".into()));
55        let id = to_quantity(1);
56        assert_eq!(id, SubscriptionId::Str("0x1".into()));
57
58        for _ in 0..1000 {
59            let val = rand::random::<u128>();
60            let id = to_quantity(val);
61            match id {
62                SubscriptionId::Str(id) => {
63                    let from_hex: U128 = id.parse().unwrap();
64                    assert_eq!(from_hex, U128::from(val));
65                }
66                SubscriptionId::Num(_) => {
67                    unreachable!()
68                }
69            }
70        }
71    }
72}