1//! Commonly used code snippets
23use super::{EthApiError, EthResult};
4use reth_primitives_traits::{Recovered, SignedTransaction};
5use std::future::Future;
67/// Recovers a [`SignedTransaction`] from an enveloped encoded byte stream.
8///
9/// This is a helper function that returns the appropriate RPC-specific error if the input data is
10/// malformed.
11///
12/// See [`alloy_eips::eip2718::Decodable2718::decode_2718`]
13pub fn recover_raw_transaction<T: SignedTransaction>(mut data: &[u8]) -> EthResult<Recovered<T>> {
14if data.is_empty() {
15return Err(EthApiError::EmptyRawTransactionData)
16 }
1718let transaction =
19 T::decode_2718(&mut data).map_err(|_| EthApiError::FailedToDecodeSignedTransaction)?;
2021transaction.try_into_recovered().or(Err(EthApiError::InvalidTransactionSignature))
22}
2324/// Performs a binary search within a given block range to find the desired block number.
25///
26/// The binary search is performed by calling the provided asynchronous `check` closure on the
27/// blocks of the range. The closure should return a future representing the result of performing
28/// the desired logic at a given block. The future resolves to an `bool` where:
29/// - `true` indicates that the condition has been matched, but we can try to find a lower block to
30/// make the condition more matchable.
31/// - `false` indicates that the condition not matched, so the target is not present in the current
32/// block and should continue searching in a higher range.
33///
34/// Args:
35/// - `low`: The lower bound of the block range (inclusive).
36/// - `high`: The upper bound of the block range (inclusive).
37/// - `check`: A closure that performs the desired logic at a given block.
38pub async fn binary_search<F, Fut, E>(low: u64, high: u64, check: F) -> Result<u64, E>
39where
40F: Fn(u64) -> Fut,
41 Fut: Future<Output = Result<bool, E>>,
42{
43let mut low = low;
44let mut high = high;
45let mut num = high;
4647while low <= high {
48let mid = (low + high) / 2;
49if check(mid).await? {
50 high = mid - 1;
51 num = mid;
52 } else {
53 low = mid + 1
54}
55 }
5657Ok(num)
58}
5960#[cfg(test)]
61mod tests {
62use super::*;
6364#[tokio::test]
65async fn test_binary_search() {
66// in the middle
67let num: Result<_, ()> =
68 binary_search(1, 10, |mid| Box::pin(async move { Ok(mid >= 5) })).await;
69assert_eq!(num, Ok(5));
7071// in the upper
72let num: Result<_, ()> =
73 binary_search(1, 10, |mid| Box::pin(async move { Ok(mid >= 7) })).await;
74assert_eq!(num, Ok(7));
7576// in the lower
77let num: Result<_, ()> =
78 binary_search(1, 10, |mid| Box::pin(async move { Ok(mid >= 1) })).await;
79assert_eq!(num, Ok(1));
8081// higher than the upper
82let num: Result<_, ()> =
83 binary_search(1, 10, |mid| Box::pin(async move { Ok(mid >= 11) })).await;
84assert_eq!(num, Ok(10));
85 }
86}