-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix batched reqs #315
Fix batched reqs #315
Changes from all commits
0135dcb
2003682
94008b6
e7f0148
77f7542
e719650
7772e09
57eba3a
1c39f2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -170,8 +170,6 @@ enum VersionMiddlewareError { | |
BodyReadError(#[from] hyper::Error), | ||
#[error("Failed to parse JSON: {0}")] | ||
JsonParseError(#[from] serde_json::Error), | ||
#[error("Invalid request format")] | ||
InvalidRequestFormat, | ||
#[error("Invalid URL format")] | ||
InvalidUrlFormat, | ||
#[error("Invalid version specified")] | ||
|
@@ -236,9 +234,6 @@ where | |
VersionMiddlewareError::InvalidVersion => { | ||
ErrorObject::owned(-32600, "Invalid RPC version specified", None::<()>) | ||
} | ||
VersionMiddlewareError::InvalidRequestFormat => { | ||
ErrorObject::owned(-32600, "Invalid JSON-RPC request format", None::<()>) | ||
} | ||
VersionMiddlewareError::UnsupportedVersion => { | ||
ErrorObject::owned(-32601, "Unsupported RPC version specified", None::<()>) | ||
} | ||
|
@@ -248,7 +243,7 @@ where | |
let body = json!({ | ||
"jsonrpc": "2.0", | ||
"error": error, | ||
"id": 0 | ||
"id": null | ||
}) | ||
.to_string(); | ||
|
||
|
@@ -267,18 +262,29 @@ async fn add_rpc_version_to_method(req: &mut hyper::Request<Body>) -> Result<(), | |
let version = RpcVersion::from_request_path(&path)?; | ||
|
||
let whole_body = hyper::body::to_bytes(req.body_mut()).await?; | ||
let mut json: Value = serde_json::from_slice(&whole_body)?; | ||
|
||
if let Some(method) = json.get_mut("method").as_deref().and_then(Value::as_str) { | ||
let new_method = format!("starknet_{}_{}", version.name(), method.strip_prefix("starknet_").unwrap_or(method)); | ||
let json: Value = serde_json::from_slice(&whole_body)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i really don't like the fact that we're deserializing and reserializing the body like that 😔 this has a perf cost, especially with serde_json::Value There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ya we can do that in a new PR probably, I can create an issue if you like. Do you've any specific suggestions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think it would require us to handle versions very differently the problem i have with parsing requests to a serde_json::Value is that it looks like this https://docs.rs/serde_json/latest/serde_json/enum.Value.html parsing a concrete struct is much cheaper since nested structs and enums only require one allocation as a whole unless there's a Box or Vec or such in between, so it's not that we're deserializing it twice for nothing, we're actually deserializing it first in the most inefficient way first and then deserializing it again in an okay form (it's not a problem of the serde_json library, their serde_json::Value type is very sensible, it's just that we should avoid it in such a critical path) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's make an issue, right There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done #322 |
||
|
||
json["method"] = Value::String(new_method); | ||
// in case of batched requests, the request is an array of JSON-RPC requests | ||
let mut batched_request = false; | ||
let mut items = if let Value::Array(items) = json { | ||
batched_request = true; | ||
items | ||
} else { | ||
return Err(VersionMiddlewareError::InvalidRequestFormat); | ||
vec![json] | ||
}; | ||
Comment on lines
+268
to
+274
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we do an helper function for batched_request like: fn is_batched_request(json: &Value) -> Option<&Vec<Value>> {
match json {
Value::Array(items) => Some(items),
_ => None,
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not mandatory but it would be cleaner There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, although making |
||
|
||
for item in items.iter_mut() { | ||
if let Some(method) = item.get_mut("method").as_deref().and_then(Value::as_str) { | ||
let new_method = | ||
format!("starknet_{}_{}", version.name(), method.strip_prefix("starknet_").unwrap_or(method)); | ||
|
||
item["method"] = Value::String(new_method); | ||
} | ||
// we don't need to throw an error here, the request will be rejected later if the method is not supported | ||
} | ||
|
||
let new_body = Body::from(serde_json::to_vec(&json)?); | ||
*req.body_mut() = new_body; | ||
let response = if batched_request { serde_json::to_vec(&items)? } else { serde_json::to_vec(&items[0])? }; | ||
*req.body_mut() = Body::from(response); | ||
|
||
Ok(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah so we can just null out that field, okay
i guess that makes sense