decrement even if error
This commit is contained in:
parent
a870dfa63a
commit
4d3b851b2c
52
src/main.rs
52
src/main.rs
@ -26,13 +26,22 @@ static APP_USER_AGENT: &str = concat!(
|
|||||||
env!("CARGO_PKG_VERSION"),
|
env!("CARGO_PKG_VERSION"),
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: i tried to use Box<dyn Provider>, but hit https://github.com/gakonst/ethers-rs/issues/592
|
type RpcRateLimiter =
|
||||||
|
RateLimiter<NotKeyed, InMemoryState, QuantaClock, NoOpMiddleware<QuantaInstant>>;
|
||||||
|
|
||||||
|
type BlockMap = RwLock<HashMap<String, Block<TxHash>>>;
|
||||||
|
type RateLimiterMap = RwLock<HashMap<String, RpcRateLimiter>>;
|
||||||
|
// TODO: include the ethers client on this map
|
||||||
|
type ConnectionsMap = RwLock<HashMap<String, EthersConnection>>;
|
||||||
|
|
||||||
|
// TODO: instead of an enum, I tried to use Box<dyn Provider>, but hit https://github.com/gakonst/ethers-rs/issues/592
|
||||||
#[derive(From)]
|
#[derive(From)]
|
||||||
enum EthersProvider {
|
enum EthersProvider {
|
||||||
Http(ethers::providers::Provider<ethers::providers::Http>),
|
Http(ethers::providers::Provider<ethers::providers::Http>),
|
||||||
Ws(ethers::providers::Provider<ethers::providers::Ws>),
|
Ws(ethers::providers::Provider<ethers::providers::Ws>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Forward functions to the inner ethers::providers::Provider
|
||||||
impl EthersProvider {
|
impl EthersProvider {
|
||||||
/// Send a web3 request
|
/// Send a web3 request
|
||||||
pub async fn request(
|
pub async fn request(
|
||||||
@ -91,6 +100,7 @@ impl EthersProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An active connection to a Web3Rpc
|
||||||
struct EthersConnection {
|
struct EthersConnection {
|
||||||
/// keep track of currently open requests. We sort on this
|
/// keep track of currently open requests. We sort on this
|
||||||
active_requests: u32,
|
active_requests: u32,
|
||||||
@ -98,6 +108,7 @@ struct EthersConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EthersConnection {
|
impl EthersConnection {
|
||||||
|
/// Connect to a web3 rpc and subscribe to new heads
|
||||||
async fn try_new(
|
async fn try_new(
|
||||||
url_str: String,
|
url_str: String,
|
||||||
http_client: Option<reqwest::Client>,
|
http_client: Option<reqwest::Client>,
|
||||||
@ -141,11 +152,11 @@ impl EthersConnection {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inc(&mut self) {
|
fn inc_active_requests(&mut self) {
|
||||||
self.active_requests += 1;
|
self.active_requests += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dec(&mut self) {
|
fn dec_active_requests(&mut self) {
|
||||||
self.active_requests -= 1;
|
self.active_requests -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,22 +175,17 @@ impl PartialOrd for EthersConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// note that this is just comparing the active requests. two providers with different rpc urls are equal!
|
||||||
impl PartialEq for EthersConnection {
|
impl PartialEq for EthersConnection {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.active_requests == other.active_requests
|
self.active_requests == other.active_requests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockMap = RwLock<HashMap<String, Block<TxHash>>>;
|
/// Load balance to the rpc
|
||||||
type RateLimiterMap = RwLock<HashMap<String, RpcRateLimiter>>;
|
|
||||||
// TODO: include the ethers client on this map
|
|
||||||
type ConnectionsMap = RwLock<HashMap<String, EthersConnection>>;
|
|
||||||
|
|
||||||
type RpcRateLimiter =
|
|
||||||
RateLimiter<NotKeyed, InMemoryState, QuantaClock, NoOpMiddleware<QuantaInstant>>;
|
|
||||||
|
|
||||||
/// Load balance to the least-connection rpc
|
|
||||||
struct RpcTier {
|
struct RpcTier {
|
||||||
|
/// RPC urls sorted by
|
||||||
|
/// TODO: what type?
|
||||||
rpcs: RwLock<Vec<String>>,
|
rpcs: RwLock<Vec<String>>,
|
||||||
connections: Arc<ConnectionsMap>,
|
connections: Arc<ConnectionsMap>,
|
||||||
ratelimits: RateLimiterMap,
|
ratelimits: RateLimiterMap,
|
||||||
@ -325,7 +331,7 @@ impl RpcTier {
|
|||||||
.await
|
.await
|
||||||
.get_mut(selected_rpc)
|
.get_mut(selected_rpc)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.inc();
|
.inc_active_requests();
|
||||||
|
|
||||||
// return the selected RPC
|
// return the selected RPC
|
||||||
return Ok(selected_rpc.clone());
|
return Ok(selected_rpc.clone());
|
||||||
@ -382,7 +388,7 @@ impl RpcTier {
|
|||||||
.await
|
.await
|
||||||
.get_mut(selected_rpc)
|
.get_mut(selected_rpc)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.inc();
|
.inc_active_requests();
|
||||||
|
|
||||||
// this is rpc should work
|
// this is rpc should work
|
||||||
selected_rpcs.push(selected_rpc.clone());
|
selected_rpcs.push(selected_rpc.clone());
|
||||||
@ -402,9 +408,14 @@ impl RpcTier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Application state
|
||||||
struct Web3ProxyState {
|
struct Web3ProxyState {
|
||||||
|
/// clock used for rate limiting
|
||||||
|
/// TODO: use tokio's clock (will require a different ratelimiting crate)
|
||||||
clock: QuantaClock,
|
clock: QuantaClock,
|
||||||
|
/// Send requests to the best server available
|
||||||
balanced_rpc_tiers: Arc<Vec<RpcTier>>,
|
balanced_rpc_tiers: Arc<Vec<RpcTier>>,
|
||||||
|
/// Send private requests (like eth_sendRawTransaction) to all these servers
|
||||||
private_rpcs: Option<Arc<RpcTier>>,
|
private_rpcs: Option<Arc<RpcTier>>,
|
||||||
/// write lock on these when all rate limits are hit
|
/// write lock on these when all rate limits are hit
|
||||||
balanced_rpc_ratelimiter_lock: RwLock<()>,
|
balanced_rpc_ratelimiter_lock: RwLock<()>,
|
||||||
@ -518,6 +529,7 @@ impl Web3ProxyState {
|
|||||||
// this is not a private transaction (or no private relays are configured)
|
// this is not a private transaction (or no private relays are configured)
|
||||||
// try to send to each tier, stopping at the first success
|
// try to send to each tier, stopping at the first success
|
||||||
loop {
|
loop {
|
||||||
|
// TODO: i'm not positive that this locking is correct
|
||||||
let read_lock = self.balanced_rpc_ratelimiter_lock.read().await;
|
let read_lock = self.balanced_rpc_ratelimiter_lock.read().await;
|
||||||
|
|
||||||
// there are multiple tiers. save the earliest not_until (if any). if we don't return, we will sleep until then and then try again
|
// there are multiple tiers. save the earliest not_until (if any). if we don't return, we will sleep until then and then try again
|
||||||
@ -625,10 +637,16 @@ impl Web3ProxyState {
|
|||||||
// get the client for this rpc server
|
// get the client for this rpc server
|
||||||
let provider = connections.read().await.get(&rpc).unwrap().provider.clone();
|
let provider = connections.read().await.get(&rpc).unwrap().provider.clone();
|
||||||
|
|
||||||
// TODO: there has to be a better way to attach the url to the result
|
let response = provider.request(&method, params).await;
|
||||||
let mut response = provider.request(&method, params).await?;
|
|
||||||
|
|
||||||
connections.write().await.get_mut(&rpc).unwrap().dec();
|
connections
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.get_mut(&rpc)
|
||||||
|
.unwrap()
|
||||||
|
.dec_active_requests();
|
||||||
|
|
||||||
|
let mut response = response?;
|
||||||
|
|
||||||
if let Some(response_id) = response.get_mut("id") {
|
if let Some(response_id) = response.get_mut("id") {
|
||||||
*response_id = incoming_id;
|
*response_id = incoming_id;
|
||||||
|
Loading…
Reference in New Issue
Block a user