Skip to main content

signet_sim/cache/
state.rs

1use alloy::{
2    primitives::{Address, U256},
3    providers::Provider,
4    transports::TransportError,
5};
6use core::future::Future;
7use trevm::revm::database_interface::async_db::DatabaseAsyncRef;
8
9/// Account information including nonce and balance. This is partially modeled
10/// after [`revm::AccountInfo`], but only includes the fields we care about.
11///
12/// [`revm::AccountInfo`]: trevm::revm::state::AccountInfo
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct AcctInfo {
15    /// The account nonce.
16    pub nonce: u64,
17    /// The account balance.
18    pub balance: U256,
19    /// Whether the account has deployed code.
20    pub has_code: bool,
21}
22
23/// A source for nonce and balance information. Exists to simplify type bounds
24/// in various places.
25pub trait StateSource: Send + Sync {
26    /// The error type for state lookups.
27    type Error: core::error::Error + Send + 'static;
28
29    /// Get account details for an address.
30    fn account_details(
31        &self,
32        address: &Address,
33    ) -> impl Future<Output = Result<AcctInfo, Self::Error>> + Send;
34
35    /// Get the nonce for an address. Returns the NEXT EXPECTED nonce, i.e. `0` for an address that
36    /// has never sent a transaction, 1 for an address that has sent exactly one transaction, etc.
37    fn nonce(&self, address: &Address) -> impl Future<Output = Result<u64, Self::Error>> + Send {
38        async { self.account_details(address).await.map(|info| info.nonce) }
39    }
40
41    /// Get the balance for an address.
42    fn balance(&self, address: &Address) -> impl Future<Output = Result<U256, Self::Error>> + Send {
43        async { self.account_details(address).await.map(|info| info.balance) }
44    }
45
46    /// Run an arbitrary check on the account details for an address.
47    fn map<T: Send, F: FnOnce(&AcctInfo) -> T + Send>(
48        &self,
49        address: &Address,
50        f: F,
51    ) -> impl Future<Output = Result<T, Self::Error>> + Send {
52        async { self.account_details(address).await.map(|info| f(&info)) }
53    }
54}
55
56impl<Db> StateSource for Db
57where
58    Db: DatabaseAsyncRef + Send + Sync,
59    Db::Error: Send + 'static,
60{
61    type Error = Db::Error;
62
63    async fn account_details(&self, address: &Address) -> Result<AcctInfo, Self::Error> {
64        let info = self.basic_async_ref(*address).await?.unwrap_or_default();
65        let has_code = info.code_hash() != trevm::revm::primitives::KECCAK_EMPTY;
66        Ok(AcctInfo { nonce: info.nonce, balance: info.balance, has_code })
67    }
68}
69
70/// A wrapper that implements [`StateSource`] for any alloy [`Provider`].
71///
72/// This allows using an alloy provider as a state source for bundle tx list
73/// validation via [`check_bundle_tx_list`].
74///
75/// [`check_bundle_tx_list`]: crate::check_bundle_tx_list
76#[derive(Debug, Clone)]
77pub struct ProviderStateSource<P>(pub P);
78
79impl<P: Provider> StateSource for ProviderStateSource<P> {
80    type Error = TransportError;
81
82    async fn account_details(&self, address: &Address) -> Result<AcctInfo, Self::Error> {
83        let (nonce, balance, code) = tokio::join!(
84            self.0.get_transaction_count(*address),
85            self.0.get_balance(*address),
86            self.0.get_code_at(*address),
87        );
88        Ok(AcctInfo { nonce: nonce?, balance: balance?, has_code: !code?.is_empty() })
89    }
90}