UNPKG

@lodestar/prover

Version:

A Typescript implementation of the Ethereum Consensus light client

136 lines 5.22 kB
import http from "node:http"; import https from "node:https"; import url from "node:url"; import { LogLevel } from "@lodestar/logger"; import { getNodeLogger } from "@lodestar/logger/node"; import httpProxy from "http-proxy"; import { ProofProvider } from "./proof_provider/proof_provider.js"; import { getResponseForRequest, isBatchRequest } from "./utils/json_rpc.js"; import { processAndVerifyRequest } from "./utils/process.js"; import { fetchRequestPayload, fetchResponseBody } from "./utils/req_resp.js"; import { ELRpcProvider } from "./utils/rpc_provider.js"; function createHttpHandler({ info, signal, }) { return function handler(payload) { return new Promise((resolve, reject) => { const serverInfo = info(); if (typeof serverInfo === "string") { return reject(new Error(serverInfo)); } const req = http.request({ method: "POST", path: "/proxy", port: serverInfo.port, host: serverInfo.host, timeout: serverInfo.timeout, signal, headers: { "Content-Type": "application/json", }, }, (res) => { fetchResponseBody(res) .then((response) => { resolve(response); }) .catch(reject); }); req.on("timeout", () => { req.destroy(); reject(new Error("Request timeout")); }); req.write(JSON.stringify(payload)); req.end(); }); }; } export function createVerifiedExecutionProxy(opts) { const { executionRpcUrl, requestTimeout } = opts; const signal = opts.signal ?? new AbortController().signal; const logger = opts.logger ?? getNodeLogger({ level: opts.logLevel ?? LogLevel.info, module: "prover" }); const proofProvider = ProofProvider.init({ ...opts, signal, logger, }); logger.info("Creating http proxy", { url: executionRpcUrl }); const proxy = httpProxy.createProxy({ target: executionRpcUrl, ws: executionRpcUrl.startsWith("ws"), agent: executionRpcUrl.startsWith("https") ? https.globalAgent : http.globalAgent, xfwd: true, ignorePath: true, changeOrigin: true, }); let proxyServerListeningAddress; const rpc = new ELRpcProvider(createHttpHandler({ signal, info: () => { if (!proxyServerListeningAddress) { return "Proxy server not listening"; } return { port: proxyServerListeningAddress.port, host: proxyServerListeningAddress.host, timeout: requestTimeout, }; }, }), logger); logger.info("Creating http server"); const proxyServer = http.createServer(function proxyRequestHandler(req, res) { if (req.url === "/proxy") { logger.debug("Forwarding request to execution layer"); proxy.web(req, res); return; } let payload; fetchRequestPayload(req) .then((data) => { payload = data; return processAndVerifyRequest({ payload, proofProvider, rpc, logger }); }) .then((response) => { res.write(JSON.stringify(response)); res.end(); }) .catch((err) => { logger.error("Error processing request", err); const message = err.message; if (isBatchRequest(payload)) { res.write(JSON.stringify(payload.map((req) => getResponseForRequest(req, { message })))); } else { res.write(JSON.stringify(getResponseForRequest(payload, undefined, { message }))); } res.end(); }); }); proxyServer.on("listening", () => { const address = proxyServer.address(); if (address === null) { throw new Error("Invalid proxy server address"); } if (typeof address === "string") { const rawUrl = url.parse(address); if (!rawUrl.host || !rawUrl.port || !rawUrl.protocol) { throw new Error(`Invalid proxy server address: ${address}`); } proxyServerListeningAddress = { host: rawUrl.host, port: parseInt(rawUrl.port) }; } else { proxyServerListeningAddress = { host: address.address, port: address.port }; } logger.info(`Lodestar Prover Proxy listening on ${proxyServerListeningAddress.host}:${proxyServerListeningAddress.port}`); rpc.verifyCompatibility().catch((err) => { logger.error(err); process.exit(1); }); }); proxyServer.on("upgrade", function proxyRequestUpgrade(req, socket, head) { logger.debug("Upgrading the ws connection"); proxy.ws(req, socket, head); }); signal.addEventListener("abort", () => { proxyServer.close(); }); return { server: proxyServer, proofProvider }; } //# sourceMappingURL=web3_proxy.js.map