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

Accept JSON-RPC requests without a params field #3090

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixed

- JSON-RPC requests without a `params` field are no longer invalid. ([#3090](https://github.com/paritytech/smoldot/pull/3090))
- Fix Merkle proofs whose trie root node has a size inferior to 32 bytes being considered as invalid. ([#3046](https://github.com/paritytech/smoldot/pull/3046))

## 0.7.9 - 2022-11-28
Expand Down
10 changes: 6 additions & 4 deletions src/json_rpc/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,13 @@ macro_rules! define_methods {
parse::build_call(parse::Call {
id_json,
method: self.name(),
params_json: &self.params_to_json_object(),
// Note that we never skip the `params` field, even if empty. This is an
// arbitrary choice.
params_json: Some(&self.params_to_json_object()),
})
}

fn from_defs(name: &'a str, params: &'a str) -> Result<Self, MethodError<'a>> {
fn from_defs(name: &'a str, params: Option<&'a str>) -> Result<Self, MethodError<'a>> {
#![allow(unused, unused_mut)]

$(
Expand All @@ -243,7 +245,7 @@ macro_rules! define_methods {
#[serde(borrow, skip)]
_dummy: core::marker::PhantomData<&'a ()>,
}
if let Ok(params) = serde_json::from_str(params) {
if let Some(Ok(params)) = params.as_ref().map(|p| serde_json::from_str(p)) {
let Params { _dummy: _, $($p_name),* } = params;
return Ok($rq_name::$name {
$($p_name,)*
Expand All @@ -257,7 +259,7 @@ macro_rules! define_methods {
//
// The code below allocates a `Vec`, but at the time of writing there is
// no way to ask `serde_json` to parse an array without doing so.
if let Ok(params) = serde_json::from_str::<Vec<&'a serde_json::value::RawValue>>(params) {
if let Some(Ok(params)) = params.as_ref().map(|p| serde_json::from_str::<Vec<&'a serde_json::value::RawValue>>(p)) {
let mut n = 0;
$(
// Missing parameters are implicitly equal to null.
Expand Down
26 changes: 17 additions & 9 deletions src/json_rpc/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub fn parse_call(call_json: &str) -> Result<Call, ParseError> {
Ok(Call {
id_json: serde_call.id.map(|v| v.get()),
method: serde_call.method,
params_json: serde_call.params.get(),
params_json: serde_call.params.map(|p| p.get()),
})
}

Expand All @@ -59,7 +59,7 @@ pub fn build_call(call: Call) -> String {
jsonrpc: SerdeVersion::V2,
id: call.id_json.map(|id| serde_json::from_str(id).unwrap()),
method: call.method,
params: serde_json::from_str(call.params_json).unwrap(),
params: call.params_json.map(|p| serde_json::from_str(p).unwrap()),
})
.unwrap()
}
Expand All @@ -71,8 +71,8 @@ pub struct Call<'a> {
pub id_json: Option<&'a str>,
/// Name of the method that is being called.
pub method: &'a str,
/// JSON-formatted list of parameters.
pub params_json: &'a str,
/// JSON-formatted list of parameters. `None` iff the `params` field is missing.
pub params_json: Option<&'a str>,
}

/// Error while parsing a call.
Expand Down Expand Up @@ -206,7 +206,7 @@ struct SerdeCall<'a> {
#[serde(borrow)]
method: &'a str,
#[serde(borrow)]
params: &'a serde_json::value::RawValue,
params: Option<&'a serde_json::value::RawValue>,
}

#[derive(Debug, PartialEq, Clone, Copy, Hash, Eq)]
Expand Down Expand Up @@ -335,15 +335,15 @@ mod tests {
.unwrap();
assert_eq!(call.id_json.unwrap(), "5");
assert_eq!(call.method, "foo");
assert_eq!(call.params_json, "[5,true, \"hello\"]");
assert_eq!(call.params_json, Some("[5,true, \"hello\"]"));
}

#[test]
fn parse_missing_id() {
let call = super::parse_call(r#"{"jsonrpc":"2.0","method":"foo","params":[]}"#).unwrap();
assert!(call.id_json.is_none());
assert_eq!(call.method, "foo");
assert_eq!(call.params_json, "[]");
assert_eq!(call.params_json, Some("[]"));
}

#[test]
Expand All @@ -353,7 +353,7 @@ mod tests {
.unwrap();
assert_eq!(call.id_json.unwrap(), "\"hello\"");
assert_eq!(call.method, "foo");
assert_eq!(call.params_json, "[]");
assert_eq!(call.params_json, Some("[]"));
}

#[test]
Expand All @@ -363,7 +363,15 @@ mod tests {
.unwrap();
assert_eq!(call.id_json.unwrap(), r#""extern:\"health-checker:0\"""#);
assert_eq!(call.method, "system_health");
assert_eq!(call.params_json, "[]");
assert_eq!(call.params_json, Some("[]"));
}

#[test]
fn missing_params() {
let call = super::parse_call(r#"{"jsonrpc":"2.0","id":2,"method":"foo"}"#).unwrap();
assert_eq!(call.id_json.unwrap(), r#"2"#);
assert_eq!(call.method, "foo");
assert_eq!(call.params_json, None);
}

#[test]
Expand Down