diff --git a/src/fetch.ts b/src/fetch.ts index 09ccb80d..28127532 100644 --- a/src/fetch.ts +++ b/src/fetch.ts @@ -1,5 +1,13 @@ -import { createAsyncMiddleware, JsonRpcMiddleware } from 'json-rpc-engine'; -import { EthereumRpcError, ethErrors } from 'eth-rpc-errors'; +import { + createAsyncMiddleware, + JsonRpcMiddleware, + JsonRpcRequest, +} from 'json-rpc-engine'; +import { + EthereumRpcError, + ethErrors, + getMessageFromCode, +} from 'eth-rpc-errors'; import { Payload, Block } from './utils/cache'; /* eslint-disable node/global-require,@typescript-eslint/no-require-imports */ @@ -68,7 +76,7 @@ export function createFetchMiddleware({ `FetchMiddleware - failed to parse response body: "${rawBody}"`, ); } - const result: Block = parseResponse(fetchRes, fetchBody); + const result: Block = parseResponse(fetchRes, fetchBody, req); // set result and exit retry loop res.result = result; return; @@ -106,7 +114,11 @@ function checkForHttpErrors(fetchRes: Response): void { } } -function parseResponse(fetchRes: Response, body: Record): Block { +function parseResponse( + fetchRes: Response, + body: Record, + req: JsonRpcRequest, +): Block { // check for error code if (fetchRes.status !== 200) { throw ethErrors.rpc.internal({ @@ -117,9 +129,21 @@ function parseResponse(fetchRes: Response, body: Record): Block { // check for rpc error if (body.error) { - throw ethErrors.rpc.internal({ - data: body.error, - }); + console.log('body.error', body.error) + const reqData = { req, res: body }; + if (body.error.code) { + throw new EthereumRpcError( + Number(body.error.code), + String(body.error.message) || + getMessageFromCode(Number(body.error.code)), + reqData, + ); + } else { + throw new Error('yabdab') + throw ethErrors.rpc.internal({ + data: reqData, + }); + } } // return successful result return body.result; diff --git a/test/fetch.js b/test/fetch.js index b07272cb..72f6aa82 100644 --- a/test/fetch.js +++ b/test/fetch.js @@ -81,65 +81,141 @@ test('fetch - auth in url', (t) => { t.end(); }); -test('fetch - server test', (t) => { - const rpcUrl = 'http://localhost:3000/abc/xyz'; - - const req = { - method: 'eth_getBalance', - params: ['0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', 'latest'], - }; +serverTest('fetch - server test', { + createReq() { + return { + id: 1, + json_rpc: '2.0', + method: 'eth_getBalance', + params: ['0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', 'latest'], + }; + }, + handleReq() { + return { + id: 1, + result: 42, + }; + }, + afternFn(t, res) { + t.deepEquals(res, { + id: 1, + result: 42, + }); + }, +}); - const rpcRes = { id: 1 }; - let server; - let serverSideRequest; - let serverSidePayload; - - series([createServer, makeRequest, closeServer], (err) => { - t.ifError(err, 'should not error'); - // validate request - t.equals(serverSideRequest.headers.accept, 'application/json'); - t.equals(serverSideRequest.headers['content-type'], 'application/json'); - t.equals(serverSideRequest.method, 'POST'); - // eslint-disable-next-line node/no-deprecated-api - t.equals(serverSideRequest.url, url.parse(rpcUrl).path); - t.deepEquals(serverSidePayload, req); - // validate response - t.deepEquals(rpcRes, { id: 1, result: 42 }); - t.end(); - }); +serverTest('fetch - server with error code', { + createReq() { + return { + id: 1, + json_rpc: '2.0', + method: 'eth_getBalance', + params: ['0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', 'latest'], + }; + }, + handleReq() { + return { + id: 1, + error: { + code: 42, + message: 'dank', + }, + }; + }, + afternFn(t, res) { + t.deepEquals(res, { + id: 1, + error: { + code: 42, + message: 'dank', + }, + }); + }, +}); - function requestHandler(request, response) { - request.pipe( - concat((rawRequestBody) => { - const payload = JSON.parse(rawRequestBody.toString()); - // save request details - serverSideRequest = request; - serverSidePayload = payload; - // send response - const responseBody = JSON.stringify({ - id: 1, - result: 42, - }); - response.end(responseBody); - }), - ); - } - - function createServer(cb) { - server = http.createServer(requestHandler); - server.listen(3000, cb); - } - - function closeServer(cb) { - server.close(cb); - } - - function makeRequest(cb) { - const middleware = createFetchMiddleware({ rpcUrl }); - middleware(req, rpcRes, failTest, cb); - } - - function failTest() { - t.fail('something broke'); - } +serverTest('fetch - server with NO error code', { + createReq() { + return { + id: 1, + json_rpc: '2.0', + method: 'eth_getBalance', + params: ['0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', 'latest'], + }; + }, + handleReq() { + return { + id: 1, + error: { + message: 'big baloo', + }, + }; + }, + afternFn(t, res) { + t.deepEquals(res, { + id: 1, + error: { + message: 'big baloo', + }, + }); + }, }); + +function serverTest(label, { createReq, handleReq, afternFn }) { + test(label, (t) => { + const rpcUrl = 'http://localhost:3000/abc/xyz'; + const clientReq = createReq(); + const clientRes = { id: clientReq.id }; + + let server; + let serverSideNetworkRequest; + let serverSideReq; + let serverSideRes; + + series([createServer, makeRequest, closeServer], (err) => { + t.ifError(err, 'should not error'); + // validate request + t.equals(serverSideNetworkRequest.headers.accept, 'application/json'); + t.equals( + serverSideNetworkRequest.headers['content-type'], + 'application/json', + ); + t.equals(serverSideNetworkRequest.method, 'POST'); + // eslint-disable-next-line node/no-deprecated-api + t.equals(serverSideNetworkRequest.url, url.parse(rpcUrl).path); + afternFn(t, serverSideRes); + t.end(); + }); + + function requestHandler(request, response) { + request.pipe( + concat((rawRequestBody) => { + // save request details + serverSideNetworkRequest = request; + serverSideReq = JSON.parse(rawRequestBody.toString()); + serverSideRes = handleReq(serverSideReq); + // send response + const responseBody = JSON.stringify(serverSideRes); + response.end(responseBody); + }), + ); + } + + function createServer(cb) { + server = http.createServer(requestHandler); + server.listen(3000, cb); + } + + function closeServer(cb) { + server.close(cb); + } + + function makeRequest(cb) { + const middleware = createFetchMiddleware({ rpcUrl }); + middleware(clientReq, clientRes, failTest, (err) => cb()); + } + + function failTest() { + t.fail('something broke'); + } + }); +}