add bundler_4337_rpcs
This commit is contained in:
parent
d035049c8f
commit
f3435bc6e0
@ -202,6 +202,8 @@ impl DatabaseReplica {
|
|||||||
pub struct Web3ProxyApp {
|
pub struct Web3ProxyApp {
|
||||||
/// Send requests to the best server available
|
/// Send requests to the best server available
|
||||||
pub balanced_rpcs: Arc<Web3Rpcs>,
|
pub balanced_rpcs: Arc<Web3Rpcs>,
|
||||||
|
/// Send 4337 Abstraction Bundler requests to one of these servers
|
||||||
|
pub bundler_4337_rpcs: Option<Arc<Web3Rpcs>>,
|
||||||
pub http_client: Option<reqwest::Client>,
|
pub http_client: Option<reqwest::Client>,
|
||||||
/// Send private requests (like eth_sendRawTransaction) to all these servers
|
/// Send private requests (like eth_sendRawTransaction) to all these servers
|
||||||
pub private_rpcs: Option<Arc<Web3Rpcs>>,
|
pub private_rpcs: Option<Arc<Web3Rpcs>>,
|
||||||
@ -695,11 +697,46 @@ impl Web3ProxyApp {
|
|||||||
Some(private_rpcs)
|
Some(private_rpcs)
|
||||||
};
|
};
|
||||||
|
|
||||||
let hostname = hostname::get().ok().and_then(|x| x.to_str().map(|x| x.to_string()));
|
// prepare a Web3Rpcs to hold all our 4337 Abstraction Bundler connections
|
||||||
|
// only some chains have this, so this is optional
|
||||||
|
let bundler_4337_rpcs = if top_config.bundler_4337_rpcs.is_none() {
|
||||||
|
warn!("No bundler_4337_rpcs configured");
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// TODO: do something with the spawn handle
|
||||||
|
let (bundler_4337_rpcs, bundler_4337_rpcs_handle) = Web3Rpcs::spawn(
|
||||||
|
top_config.app.chain_id,
|
||||||
|
db_conn.clone(),
|
||||||
|
http_client.clone(),
|
||||||
|
// bundler_4337_rpcs don't get subscriptions, so no need for max_block_age or max_block_lag
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
pending_transactions.clone(),
|
||||||
|
None,
|
||||||
|
// subscribing to new heads here won't work well. if they are fast, they might be ahead of balanced_rpcs
|
||||||
|
// they also often have low rate limits
|
||||||
|
// however, they are well connected to miners/validators. so maybe using them as a safety check would be good
|
||||||
|
// TODO: but maybe we could include privates in the "backup" tier
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.context("spawning bundler_4337_rpcs")?;
|
||||||
|
|
||||||
|
app_handles.push(bundler_4337_rpcs_handle);
|
||||||
|
|
||||||
|
Some(bundler_4337_rpcs)
|
||||||
|
};
|
||||||
|
|
||||||
|
let hostname = hostname::get()
|
||||||
|
.ok()
|
||||||
|
.and_then(|x| x.to_str().map(|x| x.to_string()));
|
||||||
|
|
||||||
let app = Self {
|
let app = Self {
|
||||||
config: top_config.app.clone(),
|
config: top_config.app.clone(),
|
||||||
balanced_rpcs,
|
balanced_rpcs,
|
||||||
|
bundler_4337_rpcs,
|
||||||
http_client,
|
http_client,
|
||||||
kafka_producer,
|
kafka_producer,
|
||||||
private_rpcs,
|
private_rpcs,
|
||||||
@ -778,6 +815,17 @@ impl Web3ProxyApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(bundler_4337_rpc_configs) = new_top_config.bundler_4337_rpcs {
|
||||||
|
if let Some(bundler_4337_rpcs) = self.bundler_4337_rpcs.as_ref() {
|
||||||
|
bundler_4337_rpcs
|
||||||
|
.apply_server_configs(self, bundler_4337_rpc_configs)
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
// TODO: maybe we should have bundler_4337_rpcs just be empty instead of being None
|
||||||
|
todo!("handle toggling bundler_4337_rpcs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1074,6 +1122,7 @@ impl Web3ProxyApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// #[measure([ErrorCount, HitCount, ResponseTime, Throughput])]
|
// #[measure([ErrorCount, HitCount, ResponseTime, Throughput])]
|
||||||
|
// TODO: more robust stats and kafka logic! if we use the try operator, they aren't saved!
|
||||||
async fn proxy_cached_request(
|
async fn proxy_cached_request(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
authorization: &Arc<Authorization>,
|
authorization: &Arc<Authorization>,
|
||||||
@ -1250,6 +1299,59 @@ impl Web3ProxyApp {
|
|||||||
vec![],
|
vec![],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
method @ ("debug_bundler_sendBundleNow"
|
||||||
|
| "debug_bundler_clearState"
|
||||||
|
| "debug_bundler_dumpMempool") => {
|
||||||
|
return Ok((
|
||||||
|
JsonRpcForwardedResponse::from_string(
|
||||||
|
// TODO: we should probably have some escaping on this. but maybe serde will protect us enough
|
||||||
|
format!("method unsupported: {}", method),
|
||||||
|
None,
|
||||||
|
Some(request_id),
|
||||||
|
),
|
||||||
|
vec![],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_method @ ("eth_sendUserOperation"
|
||||||
|
| "eth_estimateUserOperationGas"
|
||||||
|
| "eth_getUserOperationByHash"
|
||||||
|
| "eth_getUserOperationReceipt"
|
||||||
|
| "eth_supportedEntryPoints") => match self.bundler_4337_rpcs.as_ref() {
|
||||||
|
Some(bundler_4337_rpcs) => {
|
||||||
|
let response = bundler_4337_rpcs
|
||||||
|
.try_proxy_connection(
|
||||||
|
authorization,
|
||||||
|
request,
|
||||||
|
Some(&request_metadata),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// TODO: DRY
|
||||||
|
let rpcs = request_metadata.backend_requests.lock().clone();
|
||||||
|
|
||||||
|
if let Some(stat_sender) = self.stat_sender.as_ref() {
|
||||||
|
let response_stat = ProxyResponseStat::new(
|
||||||
|
request_method,
|
||||||
|
authorization.clone(),
|
||||||
|
request_metadata,
|
||||||
|
response.num_bytes(),
|
||||||
|
);
|
||||||
|
|
||||||
|
stat_sender
|
||||||
|
.send_async(response_stat.into())
|
||||||
|
.await
|
||||||
|
.context("stat_sender sending bundler_4337 response stat")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok((response, rpcs));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// TODO: stats!
|
||||||
|
return Err(anyhow::anyhow!("no bundler_4337_rpcs available").into());
|
||||||
|
}
|
||||||
|
},
|
||||||
// some commands can use local data or caches
|
// some commands can use local data or caches
|
||||||
"eth_accounts" => {
|
"eth_accounts" => {
|
||||||
// no stats on this. its cheap
|
// no stats on this. its cheap
|
||||||
@ -1297,6 +1399,8 @@ impl Web3ProxyApp {
|
|||||||
// i think this is always an error response
|
// i think this is always an error response
|
||||||
let rpcs = request_metadata.backend_requests.lock().clone();
|
let rpcs = request_metadata.backend_requests.lock().clone();
|
||||||
|
|
||||||
|
// TODO! save stats
|
||||||
|
|
||||||
return Ok((response, rpcs));
|
return Ok((response, rpcs));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1492,7 +1596,6 @@ impl Web3ProxyApp {
|
|||||||
serde_json::Value::String(APP_USER_AGENT.to_string())
|
serde_json::Value::String(APP_USER_AGENT.to_string())
|
||||||
}
|
}
|
||||||
"web3_sha3" => {
|
"web3_sha3" => {
|
||||||
// emit stats
|
|
||||||
// returns Keccak-256 (not the standardized SHA3-256) of the given data.
|
// returns Keccak-256 (not the standardized SHA3-256) of the given data.
|
||||||
match &request.params {
|
match &request.params {
|
||||||
Some(serde_json::Value::Array(params)) => {
|
Some(serde_json::Value::Array(params)) => {
|
||||||
@ -1558,8 +1661,6 @@ impl Web3ProxyApp {
|
|||||||
return Err(FrontendErrorResponse::AccessDenied);
|
return Err(FrontendErrorResponse::AccessDenied);
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit stats
|
|
||||||
|
|
||||||
// TODO: if no servers synced, wait for them to be synced? probably better to error and let haproxy retry another server
|
// TODO: if no servers synced, wait for them to be synced? probably better to error and let haproxy retry another server
|
||||||
let head_block_num = head_block_num
|
let head_block_num = head_block_num
|
||||||
.or(self.balanced_rpcs.head_block_num())
|
.or(self.balanced_rpcs.head_block_num())
|
||||||
|
@ -316,6 +316,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
private_rpcs: None,
|
private_rpcs: None,
|
||||||
|
bundler_4337_rpcs: None,
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ pub struct CliConfig {
|
|||||||
pub struct TopConfig {
|
pub struct TopConfig {
|
||||||
pub app: AppConfig,
|
pub app: AppConfig,
|
||||||
pub balanced_rpcs: HashMap<String, Web3RpcConfig>,
|
pub balanced_rpcs: HashMap<String, Web3RpcConfig>,
|
||||||
// TODO: instead of an option, give it a default
|
|
||||||
pub private_rpcs: Option<HashMap<String, Web3RpcConfig>>,
|
pub private_rpcs: Option<HashMap<String, Web3RpcConfig>>,
|
||||||
|
pub bundler_4337_rpcs: Option<HashMap<String, Web3RpcConfig>>,
|
||||||
/// unknown config options get put here
|
/// unknown config options get put here
|
||||||
#[serde(flatten, default = "HashMap::default")]
|
#[serde(flatten, default = "HashMap::default")]
|
||||||
pub extra: HashMap<String, serde_json::Value>,
|
pub extra: HashMap<String, serde_json::Value>,
|
||||||
|
Loading…
Reference in New Issue
Block a user