From cd22619dc4d30ff1b19f10c6960020b645cedbda Mon Sep 17 00:00:00 2001 From: Victor Oliva Date: Fri, 23 Aug 2024 10:15:53 +0200 Subject: [PATCH 1/3] make json-rpc server id handling spec-compliant --- packages/chopsticks/src/server.ts | 36 +++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/chopsticks/src/server.ts b/packages/chopsticks/src/server.ts index f57e49bc..3a6b8d23 100644 --- a/packages/chopsticks/src/server.ts +++ b/packages/chopsticks/src/server.ts @@ -9,7 +9,7 @@ const httpLogger = defaultLogger.child({ name: 'http' }) const wsLogger = defaultLogger.child({ name: 'ws' }) const singleRequest = z.object({ - id: z.number(), + id: z.optional(z.union([z.number().int(), z.string(), z.null()])), jsonrpc: z.literal('2.0'), method: z.string(), params: z.array(z.any()).default([]), @@ -91,6 +91,22 @@ export const createServer = async (handler: Handler, port: number) => { }, } + const safeHandleRequest = async (request: z.infer) => { + try { + const result = handler(request, emptySubscriptionManager) + return request.id === undefined ? undefined : { id: request.id, jsonrpc: '2.0', result } + } catch (err: any) { + return { + jsonrpc: '2.0', + id: request.id, + error: { + code: -32603, + message: err.message, + }, + } + } + } + const server = http.createServer(async (req, res) => { if (req.method === 'OPTIONS') { return respond(res) @@ -112,25 +128,23 @@ export const createServer = async (handler: Handler, port: number) => { let response: any if (Array.isArray(parsed.data)) { - response = await Promise.all( - parsed.data.map((req) => { - const result = handler(req, emptySubscriptionManager) - return { id: req.id, jsonrpc: '2.0', result } - }), - ) + response = await Promise.all(parsed.data.map(safeHandleRequest)) + response = response.filter((r) => r !== undefined) } else { - const result = await handler(parsed.data, emptySubscriptionManager) - response = { id: parsed.data.id, jsonrpc: '2.0', result } + response = await safeHandleRequest(parsed.data) } - respond(res, JSON.stringify(response)) + if (response !== undefined) { + respond(res, JSON.stringify(response)) + } } catch (err: any) { respond( res, JSON.stringify({ jsonrpc: '2.0', - id: 1, + id: null, error: { + code: -32700, message: err.message, }, }), From b3bc81ff67e0e214cf0bdba5971be3adaaeb42f8 Mon Sep 17 00:00:00 2001 From: Victor Oliva Date: Fri, 23 Aug 2024 12:32:14 +0200 Subject: [PATCH 2/3] await response, remove error code --- packages/chopsticks/src/server.ts | 4 +--- packages/e2e/src/http.test.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/chopsticks/src/server.ts b/packages/chopsticks/src/server.ts index 3a6b8d23..8dcda116 100644 --- a/packages/chopsticks/src/server.ts +++ b/packages/chopsticks/src/server.ts @@ -93,14 +93,13 @@ export const createServer = async (handler: Handler, port: number) => { const safeHandleRequest = async (request: z.infer) => { try { - const result = handler(request, emptySubscriptionManager) + const result = await handler(request, emptySubscriptionManager) return request.id === undefined ? undefined : { id: request.id, jsonrpc: '2.0', result } } catch (err: any) { return { jsonrpc: '2.0', id: request.id, error: { - code: -32603, message: err.message, }, } @@ -144,7 +143,6 @@ export const createServer = async (handler: Handler, port: number) => { jsonrpc: '2.0', id: null, error: { - code: -32700, message: err.message, }, }), diff --git a/packages/e2e/src/http.test.ts b/packages/e2e/src/http.test.ts index ac4c0e2a..af079d5d 100644 --- a/packages/e2e/src/http.test.ts +++ b/packages/e2e/src/http.test.ts @@ -106,7 +106,7 @@ describe('http.server', () => { "error": { "message": "Only POST method is supported", }, - "id": 1, + "id": null, "jsonrpc": "2.0", } `, From c9c249f9f0b75a008ae0a13ce3c451aaa1ddebc4 Mon Sep 17 00:00:00 2001 From: Victor Oliva Date: Fri, 23 Aug 2024 12:42:55 +0200 Subject: [PATCH 3/3] add string id tests for json rpc server --- packages/e2e/src/http.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/e2e/src/http.test.ts b/packages/e2e/src/http.test.ts index af079d5d..263d108e 100644 --- a/packages/e2e/src/http.test.ts +++ b/packages/e2e/src/http.test.ts @@ -115,5 +115,23 @@ describe('http.server', () => { }, ).end(body) } + + { + // Accepts string ids + const id = 'lorem ipsum dolor sit amet' + const res = await fetch(`http://localhost:${port}`, { + method: 'POST', + body: JSON.stringify({ id, jsonrpc: '2.0', method: 'chain_getBlockHash', params: [] }), + }) + expect(await res.json()).toMatchInlineSnapshot( + ` + { + "id": "${id}", + "jsonrpc": "2.0", + "result": "0x0df086f32a9c3399f7fa158d3d77a1790830bd309134c5853718141c969299c7", + } + `, + ) + } }) })