deth
Version:
Ethereum node focused on Developer Experience
84 lines (83 loc) • 3.23 kB
JavaScript
;
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ts_essentials_1 = require("ts-essentials");
const async_mutex_1 = require("async-mutex");
const t = __importStar(require("io-ts"));
const Either_1 = require("fp-ts/lib/Either");
const restless_1 = require("@restless/restless");
const errorHandler_1 = require("../errorHandler");
const debug_1 = __importDefault(require("debug"));
const d = debug_1.default('deth:rpc');
const executionMutex = new async_mutex_1.Mutex();
const jsonRpcEnvelope = t.type({
jsonrpc: t.literal('2.0'),
id: t.union([t.number, t.string]),
method: t.string,
params: t.any,
});
function sanitizeRPCEnvelope() {
return (_data, req) => {
const result = jsonRpcEnvelope.decode(req.body);
if (Either_1.isLeft(result)) {
throw new errorHandler_1.IOTSError(result);
}
};
}
exports.sanitizeRPCEnvelope = sanitizeRPCEnvelope;
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 errorHandler_1.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 (Either_1.isRight(res)) {
return res.right;
}
throw new errorHandler_1.IOTSError(res);
};
}
exports.sanitizeRPC = sanitizeRPC;
function executeRPC(executors) {
return async (data, req) => {
const method = req.body.method;
const executor = executors[method];
ts_essentials_1.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);
});
};
}
exports.executeRPC = executeRPC;
function respondRPC(schema) {
return (data, req) => {
const method = req.body.method;
const rpcDescription = schema[method];
d(`<-- RES: ${JSON.stringify(data)}`);
ts_essentials_1.assert(rpcDescription, `Couldn't find rpc description for ${method}`);
const result = rpcDescription.returns.encode(data);
return restless_1.responseOf({
jsonrpc: '2.0',
id: req.body.id,
result: result,
});
};
}
exports.respondRPC = respondRPC;