Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
40 changes: 30 additions & 10 deletions light-base/src/json_rpc_service/background.rs
Original file line number Diff line number Diff line change
Expand Up @@ -704,16 +704,36 @@ pub(super) async fn run<TPlat: PlatformRef>(

WakeUpReason::IncomingJsonRpcRequest(request_json) => {
// New JSON-RPC request pulled from the channel.
let Ok((request_id_json, request_parsed)) =
methods::parse_jsonrpc_client_to_server(&request_json)
else {
// Request has failed to parse. Immediately return an answer.
let _ = me
.responses_tx
.send(parse::build_parse_error_response())
.await;
continue;
};

let (request_id_json, request_parsed) =
match methods::parse_jsonrpc_client_to_server(&request_json) {
Ok(r) => r,
Err(methods::ParseClientToServerError::JsonRpcParse(_)) => {
// Request has failed to parse. Immediately return an answer.
let _ = me
.responses_tx
.send(parse::build_parse_error_response())
.await;
continue;
}
Err(methods::ParseClientToServerError::Method { request_id, error }) => {
// Invalid method or parameters. Immediately return an answer.
let _ = me.responses_tx.send(error.to_json_error(request_id)).await;
continue;
}
Err(methods::ParseClientToServerError::UnknownNotification { .. }) => {
// Invalid method. Immediately return an answer.
let _ = me
.responses_tx
.send(parse::build_error_response(
"null",
parse::ErrorResponse::InvalidRequest,
None,
))
.await;
continue;
}
};

// Print a warning for legacy JSON-RPC API functions.
match request_parsed {
Expand Down
4 changes: 4 additions & 0 deletions wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Fixed

- A "parse error" JSON-RPC response is no longer erroneously sent back in case of an unrecognized JSON-RPC function name or wrong parameter types. ([#2138](https://github.com/smol-dot/smoldot/pull/2138))

## 2.0.35 - 2025-05-27

### Changed
Expand Down
23 changes: 21 additions & 2 deletions wasm-node/javascript/test/misc.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,33 @@ test('malformed JSON-RPC request generates an error', async t => {
.then(() => client.terminate());
});

test('invalid JSON-RPC method generates an error', async t => {
const client = start({ logCallback: () => { } });
await client
.addChain({ chainSpec: westendSpec })
.then((chain) => {
chain.sendJsonRpc('{"jsonrpc":"2.0","id":1,"method":"this method doesnt exist","params":[]}');
return chain;
})
.then(async (chain) => {
const response = await chain.nextJsonRpcResponse();
const parsed = JSON.parse(response);
if (parsed.id === null && parsed.error)

Choose a reason for hiding this comment

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

Actually, this shouldn't be null, right? It should be the id sent.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed. The tests take a very long time to run for me locally (several minutes), and I ran out of patience before it hit the new test.

Choose a reason for hiding this comment

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

I understand the feeling, our zombienet tests have the same problem :)

t.pass();
else
t.fail(response);
})
.then(() => client.terminate());
});

test('disableJsonRpc option forbids sendJsonRpc', async t => {
const client = start({ logCallback: () => { } });
await client
.addChain({ chainSpec: westendSpec, disableJsonRpc: true })
.then((chain) => {
try {
chain.sendJsonRpc('{"jsonrpc":"2.0","id":1,"method":"system_name","params":[]}');
} catch(error) {
} catch (error) {
t.assert(error instanceof JsonRpcDisabledError);
t.pass();
}
Expand All @@ -62,7 +81,7 @@ test('disableJsonRpc option forbids nextJsonRpcResponse', async t => {
.then(async (chain) => {
try {
await chain.nextJsonRpcResponse();
} catch(error) {
} catch (error) {
t.assert(error instanceof JsonRpcDisabledError);
t.pass();
}
Expand Down
Loading