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

Optimize serialization for client parameters #864

Merged
merged 42 commits into from
Sep 6, 2022
Merged

Conversation

lexnv
Copy link
Contributor

@lexnv lexnv commented Aug 26, 2022

This PR adds a generic way of providing RPC parameters to the clients.

The previous method required the users to serialize their parameters
to a hardcoded serde_json::Value, which is allocation heavy, especially
when the valid parameters are already constructed.

To constrain users to correct parameter types, two alternative methods
are built upon the internal ParameterBuilder: the UnnamedParams and
NamedParams.

The former is the equivalent of the json array, while the latter represents a
json map key-value.

The ClientT interface has been updated to receive the ToRpcParams trait
as parameters, giving users an escape route that provides a raw constructed
value. This has the benefit of avoiding a Raw -> json::Value -> Raw
conversion.

To accommodate this change, the batch parameters need to receive Raw inputs.
This is because users wish to provide some methods without parameters
(deduced to the () empty tuple type), while some methods need to have named or
unnamed inputs (UnnamedParams and NamedParams).

For improving the user's experience, a batch parameter builder is introduced to
abstract the low-level interface required by submitting batch requests.

Closes #862.

lexnv added 10 commits August 26, 2022 15:56
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
@lexnv lexnv requested a review from a team as a code owner August 26, 2022 16:29
$(
__params.push($crate::client::__reexports::to_json_value($param).expect("json serialization is infallible; qed."));
__params.insert($param).expect("json serialization is infallible; qed.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just FYI, Json serialisation isn't infallible?

For example object keys just be strings, so trying to serialize eg a Map<bool, Foo> would fail.

Happy to sort this out in a future PR though to avoid bloating this one; I'd lean towards doing something like I did in subxt and having the macro return a Result, so that the caller can unwrap or "?" It.

Whatcha think @niklasad1 ?

Copy link
Member

Choose a reason for hiding this comment

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

yepp, you are correct @jsdw

as long as we document that it will panic if serialization fails I'm fine with it and remove the incorrect expect :)

it's intended to work as the serde_json::json! macro but we can do what you did in subxt here as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it makes sense. For this PR have changed the except message and added documentation. Will come up with a followup PR to return a Result here

Copy link
Collaborator

Choose a reason for hiding this comment

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

That makes sense @niklasad1! I pondered this and, indeed, it's only programmer error that can led to the panic (ie providing fallible things to the macro), so I'm ok with keeping the panic behaviour and not returning a result!

Maybe subxt's version should be the same..

types/src/params.rs Outdated Show resolved Hide resolved
lexnv added 6 commits August 29, 2022 14:36
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
@@ -225,10 +234,11 @@ impl ClientT for HttpClient {
.await
}

async fn batch_request<'a, R>(&self, batch: Vec<(&'a str, Option<ParamsSer<'a>>)>) -> Result<Vec<R>, Error>
async fn batch_request<'a, R>(&self, batch: BatchRequestBuilder<'a>) -> Result<Vec<R>, Error>
Copy link
Member

@niklasad1 niklasad1 Aug 31, 2022

Choose a reason for hiding this comment

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

yeah, this API is a bit different than the others i.e, takes the concrete type BatchRequestBuilder instead of ToRpcParams I think that makes sense as it supports both positional params (array) and named params (map) but not possible for folks to use there own impl of this.

Indeed it makes this API easier to understand and cleaner, cool

let (value, _value_type) = pair.1;
quote!(#name, #value)
});
quote!({
Copy link
Member

Choose a reason for hiding this comment

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

👍

types/src/params.rs Outdated Show resolved Hide resolved
types/src/params.rs Outdated Show resolved Hide resolved
core/src/client/mod.rs Outdated Show resolved Hide resolved
core/src/params.rs Outdated Show resolved Hide resolved
core/src/params.rs Outdated Show resolved Hide resolved
#[derive(Clone, Debug, Default)]
pub struct BatchRequestBuilder<'a>(Vec<(&'a str, Option<Box<RawValue>>)>);

impl<'a> BatchRequestBuilder<'a> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lovely :)

core/src/traits.rs Outdated Show resolved Hide resolved
core/src/traits.rs Outdated Show resolved Hide resolved
core/src/traits.rs Outdated Show resolved Hide resolved
/// }
/// }
/// ```
pub trait ToRpcParams {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Love the examples :)

@jsdw
Copy link
Collaborator

jsdw commented Sep 2, 2022

Left a few comments for small tweaks/reminders but overall love it!

lexnv and others added 7 commits September 2, 2022 14:38
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Co-authored-by: James Wilson <james@jsdw.me>
Co-authored-by: James Wilson <james@jsdw.me>
Comment on lines +212 to +220
impl ToRpcParams for ArrayParams {
fn to_rpc_params(self) -> Result<Option<Box<RawValue>>, Error> {
if let Some(json) = self.0.build() {
RawValue::from_string(json).map(Some).map_err(Error::ParseError)
} else {
Ok(None)
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lovely!

core/src/client/mod.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@jsdw jsdw left a comment

Choose a reason for hiding this comment

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

Amazing!

Left a couple of tiny nits but looks great :)

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
@niklasad1
Copy link
Member

@lexnv anything more to do before merging this one?

@lexnv
Copy link
Contributor Author

lexnv commented Sep 6, 2022

Nope, we can go ahead and merge this for now 😄

@lexnv lexnv merged commit 41b8a2c into master Sep 6, 2022
@lexnv lexnv deleted the 862_param_ser_v4 branch September 6, 2022 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Avoid mandatory encoding into serde_json::Value for parameters
3 participants