Skip to content
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

Merged
merged 9 commits into from
Oct 14, 2024
Merged

Fix batched reqs #315

merged 9 commits into from
Oct 14, 2024

Conversation

apoorvsadana
Copy link
Contributor

@apoorvsadana apoorvsadana commented Oct 7, 2024

The version middleware doesn't handle batched requests (i.e. array of JSON RPC reuqests). This fixes that.

Resolves #313

Copy link
Member

@antiyro antiyro left a comment

Choose a reason for hiding this comment

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

lgtm

Comment on lines +273 to +279
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]
};
Copy link
Member

Choose a reason for hiding this comment

The 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,
    }
}

Copy link
Member

Choose a reason for hiding this comment

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

Not mandatory but it would be cleaner

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, although making is_batched_request return a optional vector looks non intuitive. I can maybe change it to get_items_from_request but then I would need to return a tuple - (items, is_batched_request)

@cchudant
Copy link
Member

cchudant commented Oct 8, 2024

Oh, thank you i've thought about this problem
Also, while you're at it, there was something else i've noticed. This looks wrong, right? the index should not be 0, it should match the one from the request..? @apoorvsadana

i believe this is also wrong in the case of batched requests

@apoorvsadana
Copy link
Contributor Author

Also, while you're at it, there was something else i've noticed. This looks wrong, right? the index should not be 0, it should match the one from the request..? @apoorvsadana

You're right! Thanks for pointing it out. I have changed the code now so that requests without method are sent directly to the node and the errors of each request are returned respectively.

@@ -248,7 +243,7 @@ where
let body = json!({
"jsonrpc": "2.0",
"error": error,
"id": 0
"id": null
Copy link
Member

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


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)?;
Copy link
Member

Choose a reason for hiding this comment

The 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
but that isnt the scope of this PR i guess..

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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?

Copy link
Member

@cchudant cchudant Oct 9, 2024

Choose a reason for hiding this comment

The 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
it does one heap allocation per object, string and array, recursively for the whole request and it's really unnecessary
also, their Object(Map<... variant is a BTreeMap, which is really really pushing it - it does a ton of allocs, as you would expect

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)

Copy link
Member

Choose a reason for hiding this comment

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

let's make an issue, right

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done #322

@antiyro antiyro merged commit b79390b into main Oct 14, 2024
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

feat: support batched requests (needed for voyager)
4 participants