Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 69 additions & 7 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
};
use alloy_primitives::{keccak256, Address, Bytes, B256, U256};
use alloy_provider::{network::AnyNetwork, Provider};
use alloy_rpc_types::{Block, BlockId, Transaction};
use alloy_rpc_types::{Account, Block, BlockId, Transaction};
use alloy_serde::WithOtherFields;
use alloy_transport::Transport;
use eyre::WrapErr;
Expand All @@ -31,7 +31,7 @@ use std::{
pin::Pin,
sync::{
mpsc::{channel as oneshot_channel, Sender as OneshotSender},
Arc,
Arc, OnceLock,
},
};

Expand Down Expand Up @@ -108,6 +108,15 @@ enum BackendRequest {
UpdateBlockHash(BlockHashData),
}

/// Serves as a marker to identify whether the RPC provider supports `eth_getAccount`
#[derive(PartialEq, Clone)]
enum GetAccountMode {
/// The provider supports `eth_getAccount`
EthGetAccount,
/// It doesn't support, and we have to fetch balance, nonce, and code concurrently
AccountCodeNonce,
}

/// Handles an internal provider and listens for requests.
///
/// This handler will remain active as long as it is reachable (request channel still open) and
Expand All @@ -133,6 +142,8 @@ pub struct BackendHandler<T, P> {
/// The block to fetch data from.
// This is an `Option` so that we can have less code churn in the functions below
block_id: Option<BlockId>,
/// Marker identifying whether the RPC provider supports `eth_getAccount`
get_account_mode: OnceLock<GetAccountMode>,
Comment on lines +145 to +146
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this have to be a oncelock?

Copy link
Contributor Author

@yash-atreya yash-atreya Sep 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only want to set it once on the first request, and we don't need to make get_account_req &mut self

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're also setting the value inside Box::pin async fut

}

impl<T, P> BackendHandler<T, P>
Expand All @@ -157,6 +168,7 @@ where
incoming: rx,
block_id,
transport: PhantomData,
get_account_mode: OnceLock::new(),
}
}

Expand Down Expand Up @@ -250,14 +262,64 @@ where
/// returns the future that fetches the account data
fn get_account_req(&self, address: Address) -> ProviderRequest<eyre::Report> {
trace!(target: "backendhandler", "preparing account request, address={:?}", address);

let provider = self.provider.clone();
let block_id = self.block_id.unwrap_or_default();
let get_acc_mode = self.get_account_mode.clone();
if get_acc_mode.get().is_none() {
let fut = Box::pin(async move {
let res = match provider.get_account(address).block_id(block_id).await {
Ok(Account { balance, nonce, code_hash, .. }) => {
let code = if code_hash != KECCAK_EMPTY {
provider
.get_code_at(address)
.block_id(block_id)
.await
.unwrap_or_default()
} else {
Bytes::default()
};

let _ = get_acc_mode.set(GetAccountMode::EthGetAccount);
Ok((balance, nonce, code))
}
Err(err) => {
let _ = get_acc_mode.set(GetAccountMode::AccountCodeNonce);
Err(err.into())
}
};

(res, address)
});
return ProviderRequest::Account(fut);
}

let fut = Box::pin(async move {
let balance = provider.get_balance(address).block_id(block_id).into_future();
let nonce = provider.get_transaction_count(address).block_id(block_id).into_future();
let code = provider.get_code_at(address).block_id(block_id).into_future();
let resp = tokio::try_join!(balance, nonce, code).map_err(Into::into);
(resp, address)
if let Some(GetAccountMode::EthGetAccount) = get_acc_mode.get() {
let res = match provider.get_account(address).block_id(block_id).await {
Ok(Account { balance, nonce, code_hash, .. }) => {
let code = if code_hash != KECCAK_EMPTY {
provider
.get_code_at(address)
.block_id(block_id)
.await
.unwrap_or_default()
} else {
Bytes::default()
};
Ok((balance, nonce, code))
}
Err(err) => Err(err.into()),
};
(res, address)
} else {
let balance = provider.get_balance(address).block_id(block_id).into_future();
let nonce =
provider.get_transaction_count(address).block_id(block_id).into_future();
let code = provider.get_code_at(address).block_id(block_id).into_future();
let resp = tokio::try_join!(balance, nonce, code).map_err(Into::into);
(resp, address)
}
});
ProviderRequest::Account(fut)
}
Expand Down
Loading