silence some warnings and make private rpcs an option
This commit is contained in:
parent
1d4d5844d0
commit
a5ccec76c7
@ -74,7 +74,7 @@ pub struct Web3ProxyApp {
|
|||||||
/// Send requests to the best server available
|
/// Send requests to the best server available
|
||||||
pub balanced_rpcs: Arc<Web3Connections>,
|
pub balanced_rpcs: Arc<Web3Connections>,
|
||||||
/// Send private requests (like eth_sendRawTransaction) to all these servers
|
/// Send private requests (like eth_sendRawTransaction) to all these servers
|
||||||
pub private_rpcs: Arc<Web3Connections>,
|
pub private_rpcs: Option<Arc<Web3Connections>>,
|
||||||
response_cache: ResponseCache,
|
response_cache: ResponseCache,
|
||||||
// don't drop this or the sender will stop working
|
// don't drop this or the sender will stop working
|
||||||
// TODO: broadcast channel instead?
|
// TODO: broadcast channel instead?
|
||||||
@ -280,7 +280,7 @@ impl Web3ProxyApp {
|
|||||||
let private_rpcs = if private_rpcs.is_empty() {
|
let private_rpcs = if private_rpcs.is_empty() {
|
||||||
// TODO: do None instead of clone?
|
// TODO: do None instead of clone?
|
||||||
warn!("No private relays configured. Any transactions will be broadcast to the public mempool!");
|
warn!("No private relays configured. Any transactions will be broadcast to the public mempool!");
|
||||||
balanced_rpcs.clone()
|
None
|
||||||
} else {
|
} else {
|
||||||
// TODO: attach context to this error
|
// TODO: attach context to this error
|
||||||
let (private_rpcs, private_handle) = Web3Connections::spawn(
|
let (private_rpcs, private_handle) = Web3Connections::spawn(
|
||||||
@ -304,7 +304,7 @@ impl Web3ProxyApp {
|
|||||||
|
|
||||||
handles.push(private_handle);
|
handles.push(private_handle);
|
||||||
|
|
||||||
private_rpcs
|
Some(private_rpcs)
|
||||||
};
|
};
|
||||||
|
|
||||||
let frontend_rate_limiter = redis_pool.as_ref().map(|redis_pool| {
|
let frontend_rate_limiter = redis_pool.as_ref().map(|redis_pool| {
|
||||||
@ -762,8 +762,9 @@ impl Web3ProxyApp {
|
|||||||
// broadcast transactions to all private rpcs at once
|
// broadcast transactions to all private rpcs at once
|
||||||
"eth_sendRawTransaction" => {
|
"eth_sendRawTransaction" => {
|
||||||
// emit stats
|
// emit stats
|
||||||
return self
|
let rpcs = self.private_rpcs.as_ref().unwrap_or(&self.balanced_rpcs);
|
||||||
.private_rpcs
|
|
||||||
|
return rpcs
|
||||||
.try_send_all_upstream_servers(request, None)
|
.try_send_all_upstream_servers(request, None)
|
||||||
.instrument(span)
|
.instrument(span)
|
||||||
.await;
|
.await;
|
||||||
@ -849,27 +850,11 @@ impl Web3ProxyApp {
|
|||||||
let mut response = self
|
let mut response = self
|
||||||
.response_cache
|
.response_cache
|
||||||
.try_get_with(cache_key, async move {
|
.try_get_with(cache_key, async move {
|
||||||
match method {
|
// TODO: retry some failures automatically!
|
||||||
"temporarily disabled" => {
|
// TODO: try private_rpcs if all the balanced_rpcs fail!
|
||||||
// "eth_getTransactionByHash" | "eth_getTransactionReceipt" => {
|
self.balanced_rpcs
|
||||||
// TODO: try_send_all serially with retries instead of parallel
|
.try_send_best_upstream_server(request, Some(&request_block_id.num))
|
||||||
self.private_rpcs
|
.await
|
||||||
.try_send_all_upstream_servers(
|
|
||||||
request,
|
|
||||||
Some(&request_block_id.num),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// TODO: retry some failures automatically!
|
|
||||||
self.balanced_rpcs
|
|
||||||
.try_send_best_upstream_server(
|
|
||||||
request,
|
|
||||||
Some(&request_block_id.num),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -120,7 +120,7 @@ impl Web3Connections {
|
|||||||
Some(rpc) => {
|
Some(rpc) => {
|
||||||
rpc.wait_for_request_handle()
|
rpc.wait_for_request_handle()
|
||||||
.await?
|
.await?
|
||||||
.request("eth_getBlockByHash", get_block_params)
|
.request("eth_getBlockByHash", get_block_params, false)
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -140,7 +140,8 @@ impl Web3Connections {
|
|||||||
let block = Arc::new(block);
|
let block = Arc::new(block);
|
||||||
|
|
||||||
// the block was fetched using eth_getBlockByHash, so it should have all fields
|
// the block was fetched using eth_getBlockByHash, so it should have all fields
|
||||||
self.save_block(&block, true).await?;
|
// TODO: fill in heaviest_chain!
|
||||||
|
self.save_block(&block, false).await?;
|
||||||
|
|
||||||
Ok(block)
|
Ok(block)
|
||||||
}
|
}
|
||||||
@ -256,6 +257,7 @@ impl Web3Connections {
|
|||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// we don't know if its on the heaviest chain yet
|
// we don't know if its on the heaviest chain yet
|
||||||
|
debug!(?rpc_head_hash, ?rpc_head_num, %rpc.name, "saving");
|
||||||
self.save_block(&rpc_head_block, false).await?;
|
self.save_block(&rpc_head_block, false).await?;
|
||||||
|
|
||||||
connection_heads.insert(rpc.name.to_owned(), rpc_head_hash);
|
connection_heads.insert(rpc.name.to_owned(), rpc_head_hash);
|
||||||
@ -290,7 +292,7 @@ impl Web3Connections {
|
|||||||
let conn_head_block = if let Some(x) = self.block_hashes.get(connection_head_hash) {
|
let conn_head_block = if let Some(x) = self.block_hashes.get(connection_head_hash) {
|
||||||
x
|
x
|
||||||
} else {
|
} else {
|
||||||
// TODO: why does this happen?
|
// TODO: why does this happen?!?! maybe we should do get_with?
|
||||||
warn!(%connection_head_hash, %conn_name, %rpc, "Missing connection_head_block in block_hashes");
|
warn!(%connection_head_hash, %conn_name, %rpc, "Missing connection_head_block in block_hashes");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@ -401,6 +403,8 @@ impl Web3Connections {
|
|||||||
// i think "conns" is somehow getting dupes
|
// i think "conns" is somehow getting dupes
|
||||||
trace!(?heavy_rpcs);
|
trace!(?heavy_rpcs);
|
||||||
|
|
||||||
|
// TODO: if maybe_head_block.time() is old, ignore it
|
||||||
|
|
||||||
// success! this block has enough soft limit and nodes on it (or on later blocks)
|
// success! this block has enough soft limit and nodes on it (or on later blocks)
|
||||||
let conns: Vec<Arc<Web3Connection>> = heavy_rpcs
|
let conns: Vec<Arc<Web3Connection>> = heavy_rpcs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -114,7 +114,7 @@ impl Web3Connection {
|
|||||||
let found_chain_id: Result<U64, _> = new_connection
|
let found_chain_id: Result<U64, _> = new_connection
|
||||||
.wait_for_request_handle()
|
.wait_for_request_handle()
|
||||||
.await?
|
.await?
|
||||||
.request("eth_chainId", Option::None::<()>)
|
.request("eth_chainId", Option::None::<()>, false)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
match found_chain_id {
|
match found_chain_id {
|
||||||
@ -206,6 +206,7 @@ impl Web3Connection {
|
|||||||
"0xdead00000000000000000000000000000000beef",
|
"0xdead00000000000000000000000000000000beef",
|
||||||
maybe_archive_block,
|
maybe_archive_block,
|
||||||
),
|
),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -295,31 +296,40 @@ impl Web3Connection {
|
|||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub async fn reconnect(
|
pub async fn reconnect(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
|
// websocket doesn't need the http client
|
||||||
block_sender: Option<&flume::Sender<BlockAndRpc>>,
|
block_sender: Option<&flume::Sender<BlockAndRpc>>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// TODO: no-op if this called on a http provider
|
|
||||||
// websocket doesn't need the http client
|
|
||||||
info!(rpc=%self, "connecting");
|
|
||||||
|
|
||||||
// since this lock is held open over an await, we use tokio's locking
|
// since this lock is held open over an await, we use tokio's locking
|
||||||
// TODO: timeout on this lock. if its slow, something is wrong
|
// TODO: timeout on this lock. if its slow, something is wrong
|
||||||
let mut provider = self.provider.write().await;
|
let mut provider = self.provider.write().await;
|
||||||
|
|
||||||
// our provider doesn't work anymore
|
if provider.is_some() {
|
||||||
*provider = None;
|
if self.http_client.is_some() {
|
||||||
|
// http clients don't need to do anything for reconnecting
|
||||||
|
// they *do* need to run this function to setup the first
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
// reset sync status
|
info!(rpc=%self, "reconnecting");
|
||||||
{
|
|
||||||
let mut head_block_id = self.head_block_id.write();
|
|
||||||
*head_block_id = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tell the block subscriber that we don't have any blocks
|
// disconnect the current provider
|
||||||
if let Some(block_sender) = &block_sender {
|
*provider = None;
|
||||||
block_sender
|
|
||||||
.send_async((None, self.clone()))
|
// reset sync status
|
||||||
.await
|
{
|
||||||
.context("block_sender during connect")?;
|
let mut head_block_id = self.head_block_id.write();
|
||||||
|
*head_block_id = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell the block subscriber that we don't have any blocks
|
||||||
|
if let Some(block_sender) = &block_sender {
|
||||||
|
block_sender
|
||||||
|
.send_async((None, self.clone()))
|
||||||
|
.await
|
||||||
|
.context("block_sender during connect")?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!(rpc=%self, "connecting");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: if this fails, keep retrying! otherwise it crashes and doesn't try again!
|
// TODO: if this fails, keep retrying! otherwise it crashes and doesn't try again!
|
||||||
@ -381,7 +391,7 @@ impl Web3Connection {
|
|||||||
let complete_head_block: Block<TxHash> = self
|
let complete_head_block: Block<TxHash> = self
|
||||||
.wait_for_request_handle()
|
.wait_for_request_handle()
|
||||||
.await?
|
.await?
|
||||||
.request("eth_getBlockByHash", (new_hash, false))
|
.request("eth_getBlockByHash", (new_hash, false), false)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
debug_assert!(complete_head_block.total_difficulty.is_some());
|
debug_assert!(complete_head_block.total_difficulty.is_some());
|
||||||
@ -549,7 +559,7 @@ impl Web3Connection {
|
|||||||
match self.wait_for_request_handle().await {
|
match self.wait_for_request_handle().await {
|
||||||
Ok(active_request_handle) => {
|
Ok(active_request_handle) => {
|
||||||
let block: Result<Block<TxHash>, _> = active_request_handle
|
let block: Result<Block<TxHash>, _> = active_request_handle
|
||||||
.request("eth_getBlockByNumber", ("latest", false))
|
.request("eth_getBlockByNumber", ("latest", false), false)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
match block {
|
match block {
|
||||||
@ -619,7 +629,7 @@ impl Web3Connection {
|
|||||||
let block: Result<Option<ArcBlock>, _> = self
|
let block: Result<Option<ArcBlock>, _> = self
|
||||||
.wait_for_request_handle()
|
.wait_for_request_handle()
|
||||||
.await?
|
.await?
|
||||||
.request("eth_getBlockByNumber", ("latest", false))
|
.request("eth_getBlockByNumber", ("latest", false), false)
|
||||||
.await
|
.await
|
||||||
.map(|x| Some(Arc::new(x)));
|
.map(|x| Some(Arc::new(x)));
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ impl Web3Connections {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|active_request_handle| async move {
|
.map(|active_request_handle| async move {
|
||||||
let result: Result<Box<RawValue>, _> =
|
let result: Result<Box<RawValue>, _> =
|
||||||
active_request_handle.request(method, params).await;
|
active_request_handle.request(method, params, false).await;
|
||||||
result
|
result
|
||||||
})
|
})
|
||||||
.collect::<FuturesUnordered<_>>()
|
.collect::<FuturesUnordered<_>>()
|
||||||
@ -500,7 +500,7 @@ impl Web3Connections {
|
|||||||
skip_rpcs.push(active_request_handle.clone_connection());
|
skip_rpcs.push(active_request_handle.clone_connection());
|
||||||
|
|
||||||
let response_result = active_request_handle
|
let response_result = active_request_handle
|
||||||
.request(&request.method, &request.params)
|
.request(&request.method, &request.params, false)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
match JsonRpcForwardedResponse::try_from_response_result(
|
match JsonRpcForwardedResponse::try_from_response_result(
|
||||||
|
@ -64,12 +64,14 @@ impl OpenRequestHandle {
|
|||||||
/// By having the request method here, we ensure that the rate limiter was called and connection counts were properly incremented
|
/// By having the request method here, we ensure that the rate limiter was called and connection counts were properly incremented
|
||||||
/// By taking self here, we ensure that this is dropped after the request is complete.
|
/// By taking self here, we ensure that this is dropped after the request is complete.
|
||||||
/// TODO: we no longer take self because metered doesn't like that
|
/// TODO: we no longer take self because metered doesn't like that
|
||||||
|
/// TODO: ErrorCount includes too many types of errors, such as transaction reverts
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
#[measure([ErrorCount, HitCount, InFlight, ResponseTime, Throughput])]
|
#[measure([ErrorCount, HitCount, InFlight, ResponseTime, Throughput])]
|
||||||
pub async fn request<T, R>(
|
pub async fn request<T, R>(
|
||||||
&self,
|
&self,
|
||||||
method: &str,
|
method: &str,
|
||||||
params: T,
|
params: T,
|
||||||
|
silent_errors: bool,
|
||||||
) -> Result<R, ethers::prelude::ProviderError>
|
) -> Result<R, ethers::prelude::ProviderError>
|
||||||
where
|
where
|
||||||
T: fmt::Debug + serde::Serialize + Send + Sync,
|
T: fmt::Debug + serde::Serialize + Send + Sync,
|
||||||
@ -107,7 +109,10 @@ impl OpenRequestHandle {
|
|||||||
|
|
||||||
// TODO: i think ethers already has trace logging (and does it much more fancy)
|
// TODO: i think ethers already has trace logging (and does it much more fancy)
|
||||||
if let Err(err) = &response {
|
if let Err(err) = &response {
|
||||||
warn!(?err, %method, rpc=%self.conn, "bad response!");
|
if !silent_errors {
|
||||||
|
// TODO: this isn't always bad. missing trie node while we are checking initial
|
||||||
|
warn!(?err, %method, rpc=%self.conn, "bad response!");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: opt-in response inspection to log reverts with their request. put into redis or what?
|
// TODO: opt-in response inspection to log reverts with their request. put into redis or what?
|
||||||
// trace!(rpc=%self.0, %method, ?response);
|
// trace!(rpc=%self.0, %method, ?response);
|
||||||
|
@ -27,7 +27,7 @@ impl Web3Connections {
|
|||||||
let tx: Transaction = match rpc.try_request_handle().await {
|
let tx: Transaction = match rpc.try_request_handle().await {
|
||||||
Ok(OpenRequestResult::Handle(handle)) => {
|
Ok(OpenRequestResult::Handle(handle)) => {
|
||||||
handle
|
handle
|
||||||
.request("eth_getTransactionByHash", (pending_tx_id,))
|
.request("eth_getTransactionByHash", (pending_tx_id,), false)
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user