UNPKG

deth

Version:

Ethereum node focused on Developer Experience

68 lines (67 loc) 2.44 kB
import { assert } from 'ts-essentials'; import { Mutex } from 'async-mutex'; import * as t from 'io-ts'; import { isRight, isLeft } from 'fp-ts/lib/Either'; import { responseOf } from '@restless/restless'; import { IOTSError, NotFoundHttpError } from '../errorHandler'; import debug from 'debug'; const d = debug('deth:rpc'); const executionMutex = new Mutex(); const jsonRpcEnvelope = t.type({ jsonrpc: t.literal('2.0'), id: t.union([t.number, t.string]), method: t.string, params: t.any, }); export function sanitizeRPCEnvelope() { return (_data, req) => { const result = jsonRpcEnvelope.decode(req.body); if (isLeft(result)) { throw new IOTSError(result); } }; } export function sanitizeRPC(schema) { return (_data, req) => { const m = req.body.method; const rpcDescription = schema[m]; d(`--> RPC call ${m}`); d(`--> RPC call data ${JSON.stringify(req.body.params)}`); if (!rpcDescription) { throw new NotFoundHttpError([`RPC method: ${m} called with ${JSON.stringify(req.body.params)} not found`]); } const params = req.body.params; // we need to normalize empty arrays to undefineds const normalizedParams = Array.isArray(params) && params.length === 0 ? undefined : params; const res = rpcDescription.parameters.decode(normalizedParams); if (isRight(res)) { return res.right; } throw new IOTSError(res); }; } export function executeRPC(executors) { return async (data, req) => { const method = req.body.method; const executor = executors[method]; assert(executor, `Couldn't find executor for ${method}`); // @todo: NOTE currently we run RPC calls sequentially. This limits performance but solves concurrency issues. return executionMutex.runExclusive(async () => { return executor(data); }); }; } export function respondRPC(schema) { return (data, req) => { const method = req.body.method; const rpcDescription = schema[method]; d(`<-- RES: ${JSON.stringify(data)}`); assert(rpcDescription, `Couldn't find rpc description for ${method}`); const result = rpcDescription.returns.encode(data); return responseOf({ jsonrpc: '2.0', id: req.body.id, result: result, }); }; }