*Reformat

This commit is contained in:
Derrick Hammer 2022-07-19 18:31:15 -04:00
parent 070b7825e2
commit 20e9511eae
15 changed files with 768 additions and 769 deletions

View File

@ -1,36 +1,35 @@
// @ts-ignore // @ts-ignore
import BConfig from "bcfg"; import BConfig from "bcfg";
import {errorExit} from "./util.js"; import { errorExit } from "./util.js";
const config = new BConfig("lumeweb-relay"); const config = new BConfig("lumeweb-relay");
config.inject({ config.inject({
relayPort: 8080, relayPort: 8080,
}); });
config.load({ config.load({
env: true, env: true,
argv: true, argv: true,
}); });
try { try {
config.open("config.conf"); config.open("config.conf");
} catch (e) { } catch (e) {}
}
for (const setting of ["relay-domain", "afraid-username", "relay-seed"]) { for (const setting of ["relay-domain", "afraid-username", "relay-seed"]) {
if (!config.get(setting)) { if (!config.get(setting)) {
errorExit(`Required config option ${setting} not set`); errorExit(`Required config option ${setting} not set`);
} }
} }
let usingPocketGateway = true; let usingPocketGateway = true;
export function usePocketGateway() { export function usePocketGateway() {
return usingPocketGateway; return usingPocketGateway;
} }
export function updateUsePocketGateway(state: boolean): void { export function updateUsePocketGateway(state: boolean): void {
usingPocketGateway = state; usingPocketGateway = state;
} }
export default config; export default config;

View File

@ -1,57 +1,57 @@
import {createRequire} from "module"; import { createRequire } from "module";
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const DHT = require("@hyperswarm/dht"); const DHT = require("@hyperswarm/dht");
import {errorExit} from "./util.js"; import { errorExit } from "./util.js";
import { import {
deriveMyskyRootKeypair, deriveMyskyRootKeypair,
ed25519Keypair, ed25519Keypair,
seedPhraseToSeed, seedPhraseToSeed,
validSeedPhrase, validSeedPhrase,
} from "libskynet"; } from "libskynet";
import config from "./config.js"; import config from "./config.js";
let node: { let node: {
ready: () => any; ready: () => any;
createServer: () => any; createServer: () => any;
defaultKeyPair: any; defaultKeyPair: any;
on: any; on: any;
}; };
let server: { let server: {
listen: (arg0: ed25519Keypair) => any; listen: (arg0: ed25519Keypair) => any;
on: any; on: any;
}; };
async function start() { async function start() {
const seed = config.str("relay-seed"); const seed = config.str("relay-seed");
let [, err] = validSeedPhrase(seed); let [, err] = validSeedPhrase(seed);
if (err !== null) { if (err !== null) {
errorExit("RELAY_SEED is invalid. Aborting."); errorExit("RELAY_SEED is invalid. Aborting.");
} }
const keyPair = deriveMyskyRootKeypair(seedPhraseToSeed(seed)[0]); const keyPair = deriveMyskyRootKeypair(seedPhraseToSeed(seed)[0]);
node = new DHT({keyPair}); node = new DHT({ keyPair });
await node.ready(); await node.ready();
server = node.createServer(); server = node.createServer();
await server.listen(keyPair); await server.listen(keyPair);
return node; return node;
} }
export async function get( export async function get(
ret: "server" | "dht" = "dht" ret: "server" | "dht" = "dht"
): Promise<typeof server | typeof node> { ): Promise<typeof server | typeof node> {
if (!node) { if (!node) {
await start(); await start();
} }
if (ret == "server") { if (ret == "server") {
return server; return server;
} }
return node; return node;
} }

View File

@ -1,96 +1,96 @@
import cron from "node-cron"; import cron from "node-cron";
import fetch from "node-fetch"; import fetch from "node-fetch";
import {get as getDHT} from "./dht.js"; import { get as getDHT } from "./dht.js";
import {overwriteRegistryEntry} from "libskynetnode"; import { overwriteRegistryEntry } from "libskynetnode";
import {Buffer} from "buffer"; import { Buffer } from "buffer";
import {Parser} from "xml2js"; import { Parser } from "xml2js";
import {URL} from "url"; import { URL } from "url";
import {errorExit, hashDataKey} from "./util.js"; import { errorExit, hashDataKey } from "./util.js";
import {pack} from "msgpackr"; import { pack } from "msgpackr";
import config from "./config.js"; import config from "./config.js";
const {createHash} = await import("crypto"); const { createHash } = await import("crypto");
let activeIp: string; let activeIp: string;
const REGISTRY_NODE_KEY = "lumeweb-dht-node"; const REGISTRY_NODE_KEY = "lumeweb-dht-node";
async function ipUpdate() { async function ipUpdate() {
let currentIp = await getCurrentIp(); let currentIp = await getCurrentIp();
if (activeIp && currentIp === activeIp) { if (activeIp && currentIp === activeIp) {
return; return;
} }
let domain = await getDomainInfo(); let domain = await getDomainInfo();
await fetch(domain.url[0].toString()); await fetch(domain.url[0].toString());
activeIp = domain.address[0]; activeIp = domain.address[0];
} }
export async function start() { export async function start() {
const dht = (await getDHT()) as any; const dht = (await getDHT()) as any;
await ipUpdate(); await ipUpdate();
await overwriteRegistryEntry( await overwriteRegistryEntry(
dht.defaultKeyPair, dht.defaultKeyPair,
hashDataKey(REGISTRY_NODE_KEY), hashDataKey(REGISTRY_NODE_KEY),
pack(`${config.str("relay-domain")}:${config.uint("relay-port")}`) pack(`${config.str("relay-domain")}:${config.uint("relay-port")}`)
); );
console.log( console.log(
"node pubkey:", "node pubkey:",
Buffer.from(dht.defaultKeyPair.publicKey).toString("hex") Buffer.from(dht.defaultKeyPair.publicKey).toString("hex")
); );
cron.schedule("0 * * * *", ipUpdate); cron.schedule("0 * * * *", ipUpdate);
} }
async function getDomainInfo() { async function getDomainInfo() {
const relayDomain = config.str("relay-domain"); const relayDomain = config.str("relay-domain");
const parser = new Parser(); const parser = new Parser();
const url = new URL("https://freedns.afraid.org/api/"); const url = new URL("https://freedns.afraid.org/api/");
const params = url.searchParams; const params = url.searchParams;
params.append("action", "getdyndns"); params.append("action", "getdyndns");
params.append("v", "2"); params.append("v", "2");
params.append("style", "xml"); params.append("style", "xml");
const hash = createHash("sha1"); const hash = createHash("sha1");
hash.update( hash.update(
`${config.str("afraid-username")}|${config.str("afraid-password")}` `${config.str("afraid-username")}|${config.str("afraid-password")}`
); );
params.append("sha", hash.digest().toString("hex")); params.append("sha", hash.digest().toString("hex"));
const response = await (await fetch(url.toString())).text(); const response = await (await fetch(url.toString())).text();
if (/could not authenticate/i.test(response)) { if (/could not authenticate/i.test(response)) {
errorExit("Failed to authenticate to afraid.org"); errorExit("Failed to authenticate to afraid.org");
}
const json = await parser.parseStringPromise(response);
let domain = null;
for (const item of json.xml.item) {
if (item.host[0] === relayDomain) {
domain = item;
break;
} }
}
const json = await parser.parseStringPromise(response); if (!domain) {
errorExit(`Domain ${relayDomain} not found in afraid.org account`);
}
let domain = null; return domain;
for (const item of json.xml.item) {
if (item.host[0] === relayDomain) {
domain = item;
break;
}
}
if (!domain) {
errorExit(`Domain ${relayDomain} not found in afraid.org account`);
}
return domain;
} }
async function getCurrentIp(): Promise<string> { async function getCurrentIp(): Promise<string> {
return await (await fetch("http://ip1.dynupdate.no-ip.com/")).text(); return await (await fetch("http://ip1.dynupdate.no-ip.com/")).text();
} }

View File

@ -1,13 +1,13 @@
import {start as startDns} from "./dns.js"; import { start as startDns } from "./dns.js";
import {start as startRpc} from "./rpc.js"; import { start as startRpc } from "./rpc.js";
import {start as startRelay} from "./relay.js"; import { start as startRelay } from "./relay.js";
await startDns(); await startDns();
await startRpc(); await startRpc();
await startRelay(); await startRelay();
process.on("uncaughtException", function (err) { process.on("uncaughtException", function (err) {
console.log("Caught exception: " + err); console.log("Caught exception: " + err);
}); });
export {}; export {};

View File

@ -1,45 +1,45 @@
{ {
"algorand-mainnet": "29", "algorand-mainnet": "29",
"algorand-mainnet-indexer": "dummy", "algorand-mainnet-indexer": "dummy",
"algorand-archival": "000D", "algorand-archival": "000D",
"algorand-testnet": "45", "algorand-testnet": "45",
"algorand-testnet-archival": "0A45", "algorand-testnet-archival": "0A45",
"arweave-mainnet": "30", "arweave-mainnet": "30",
"avax-mainnet": "3", "avax-mainnet": "3",
"avax-archival": "00A3", "avax-archival": "00A3",
"avax-fuji": "000E", "avax-fuji": "000E",
"bsc-mainnet": "4", "bsc-mainnet": "4",
"bsc-archival": "10", "bsc-archival": "10",
"bsc-testnet": "11", "bsc-testnet": "11",
"bsc-testnet-archival": "12", "bsc-testnet-archival": "12",
"btc-mainnet": "2", "btc-mainnet": "2",
"eth-mainnet": "21", "eth-mainnet": "21",
"eth-archival": "22", "eth-archival": "22",
"eth-archival-trace": "28", "eth-archival-trace": "28",
"eth-goerli": "26", "eth-goerli": "26",
"poa-kovan": "24", "poa-kovan": "24",
"eth-rinkeby": "25", "eth-rinkeby": "25",
"eth-ropsten": "23", "eth-ropsten": "23",
"evmos-mainnet": "46", "evmos-mainnet": "46",
"fuse-mainnet": "5", "fuse-mainnet": "5",
"fuse-archival": "000A", "fuse-archival": "000A",
"gnosischain-mainnet": "27", "gnosischain-mainnet": "27",
"gnosischain-archival": "000C", "gnosischain-archival": "000C",
"harmony-0": "40", "harmony-0": "40",
"harmony-0-archival": "0A40", "harmony-0-archival": "0A40",
"harmony-1": "41", "harmony-1": "41",
"harmony-1-archival": "0A41", "harmony-1-archival": "0A41",
"harmony-2": "42", "harmony-2": "42",
"harmony-2-archival": "0A42", "harmony-2-archival": "0A42",
"harmony-3": "43", "harmony-3": "43",
"harmony-3-archival": "0A43", "harmony-3-archival": "0A43",
"iotex-mainnet": "44", "iotex-mainnet": "44",
"oec-mainnet": "47", "oec-mainnet": "47",
"mainnet": "1", "mainnet": "1",
"poly-mainnet": "9", "poly-mainnet": "9",
"poly-archival": "000B", "poly-archival": "000B",
"poly-mumbai": "000F", "poly-mumbai": "000F",
"poly-mumbai-archival": "00AF", "poly-mumbai-archival": "00AF",
"sol-mainnet": "6", "sol-mainnet": "6",
"sol-testnet": "31" "sol-testnet": "31"
} }

View File

@ -1,118 +1,118 @@
// @ts-ignore // @ts-ignore
import DHT from "@hyperswarm/dht"; import DHT from "@hyperswarm/dht";
// @ts-ignore // @ts-ignore
import {relay} from "@hyperswarm/dht-relay"; import { relay } from "@hyperswarm/dht-relay";
// @ts-ignore // @ts-ignore
import Stream from "@hyperswarm/dht-relay/ws"; import Stream from "@hyperswarm/dht-relay/ws";
import express, {Express} from "express"; import express, { Express } from "express";
import path from "path"; import path from "path";
import {fileURLToPath} from "url"; import { fileURLToPath } from "url";
import config from "./config.js"; import config from "./config.js";
import * as http from "http"; import * as http from "http";
import * as https from "https"; import * as https from "https";
import * as tls from "tls"; import * as tls from "tls";
import * as acme from "acme-client"; import * as acme from "acme-client";
import {Buffer} from "buffer"; import { Buffer } from "buffer";
import {intervalToDuration} from "date-fns"; import { intervalToDuration } from "date-fns";
import cron from "node-cron"; import cron from "node-cron";
import {get as getDHT} from "./dht.js"; import { get as getDHT } from "./dht.js";
import WS from "ws"; import WS from "ws";
// @ts-ignore // @ts-ignore
import DHT from "@hyperswarm/dht"; import DHT from "@hyperswarm/dht";
import {pack} from "msgpackr"; import { pack } from "msgpackr";
import {overwriteRegistryEntry} from "libskynetnode"; import { overwriteRegistryEntry } from "libskynetnode";
import {hashDataKey} from "./util.js"; import { hashDataKey } from "./util.js";
let sslCtx: tls.SecureContext = tls.createSecureContext(); let sslCtx: tls.SecureContext = tls.createSecureContext();
const sslParams: tls.SecureContextOptions = {}; const sslParams: tls.SecureContextOptions = {};
const sslPrivateKey = await acme.forge.createPrivateKey(); const sslPrivateKey = await acme.forge.createPrivateKey();
const acmeClient = new acme.Client({ const acmeClient = new acme.Client({
accountKey: sslPrivateKey, accountKey: sslPrivateKey,
directoryUrl: acme.directory.letsencrypt.production, directoryUrl: acme.directory.letsencrypt.production,
}); });
let app: Express; let app: Express;
let router = express.Router(); let router = express.Router();
export async function start() { export async function start() {
const relayPort = config.str("relay-port"); const relayPort = config.str("relay-port");
app = express(); app = express();
app.use(function (req, res, next) { app.use(function (req, res, next) {
router(req, res, next); router(req, res, next);
});
let httpsServer = https.createServer({
SNICallback(servername, cb) {
cb(null, sslCtx);
},
});
let httpServer = http.createServer(app);
cron.schedule("0 * * * *", createOrRenewSSl);
await new Promise((resolve) => {
httpServer.listen(80, "0.0.0.0", function () {
console.info("HTTP Listening on ", httpServer.address());
resolve(null);
}); });
});
const dht = await getDHT();
let httpsServer = https.createServer({ let wsServer = new WS.Server({ server: httpsServer });
SNICallback(servername, cb) {
cb(null, sslCtx); wsServer.on("connection", (socket: any) => {
}, relay(dht, new Stream(false, socket));
});
await new Promise((resolve) => {
httpsServer.listen(relayPort, "0.0.0.0", function () {
console.info("Relay started on ", httpsServer.address());
resolve(null);
}); });
});
let httpServer = http.createServer(app); await createOrRenewSSl();
cron.schedule("0 * * * *", createOrRenewSSl);
await new Promise((resolve) => {
httpServer.listen(80, "0.0.0.0", function () {
console.info("HTTP Listening on ", httpServer.address());
resolve(null);
});
});
const dht = await getDHT();
let wsServer = new WS.Server({server: httpsServer});
wsServer.on("connection", (socket: any) => {
relay(dht, new Stream(false, socket));
});
await new Promise((resolve) => {
httpsServer.listen(relayPort, "0.0.0.0", function () {
console.info("Relay started on ", httpsServer.address());
resolve(null);
});
});
await createOrRenewSSl();
} }
async function createOrRenewSSl() { async function createOrRenewSSl() {
if (sslParams.cert) { if (sslParams.cert) {
const expires = ( const expires = (
await acme.forge.readCertificateInfo(sslParams.cert as Buffer) await acme.forge.readCertificateInfo(sslParams.cert as Buffer)
).notAfter; ).notAfter;
let duration = intervalToDuration({start: new Date(), end: expires}); let duration = intervalToDuration({ start: new Date(), end: expires });
let daysLeft = (duration.months as number) * 30 + (duration.days as number); let daysLeft = (duration.months as number) * 30 + (duration.days as number);
if (daysLeft > 30) { if (daysLeft > 30) {
return; return;
}
} }
}
const [certificateKey, certificateRequest] = await acme.forge.createCsr({ const [certificateKey, certificateRequest] = await acme.forge.createCsr({
commonName: config.str("relay-domain"), commonName: config.str("relay-domain"),
}); });
sslParams.cert = await acmeClient.auto({ sslParams.cert = await acmeClient.auto({
csr: certificateRequest, csr: certificateRequest,
termsOfServiceAgreed: true, termsOfServiceAgreed: true,
challengeCreateFn: async (authz, challenge, keyAuthorization) => { challengeCreateFn: async (authz, challenge, keyAuthorization) => {
router.get( router.get(
`/.well-known/acme-challenge/${challenge.token}`, `/.well-known/acme-challenge/${challenge.token}`,
(req, res) => { (req, res) => {
res.send(keyAuthorization); res.send(keyAuthorization);
} }
); );
}, },
challengeRemoveFn: async () => { challengeRemoveFn: async () => {
router = express.Router(); router = express.Router();
}, },
challengePriority: ["http-01"], challengePriority: ["http-01"],
}); });
sslParams.key = certificateKey; sslParams.key = certificateKey;
sslCtx = tls.createSecureContext(sslParams); sslCtx = tls.createSecureContext(sslParams);
console.log("SSL Certificate Updated"); console.log("SSL Certificate Updated");
} }

View File

@ -1,28 +1,28 @@
import crypto from "crypto"; import crypto from "crypto";
import jayson from "jayson/promise/index.js"; import jayson from "jayson/promise/index.js";
import {pack, unpack} from "msgpackr"; import { pack, unpack } from "msgpackr";
import {Mutex} from "async-mutex"; import { Mutex } from "async-mutex";
import {createRequire} from "module"; import { createRequire } from "module";
import NodeCache from "node-cache"; import NodeCache from "node-cache";
import {get as getDHT} from "./dht.js"; import { get as getDHT } from "./dht.js";
import {rpcMethods} from "./rpc/index.js"; import { rpcMethods } from "./rpc/index.js";
import PocketPKG from "@pokt-network/pocket-js"; import PocketPKG from "@pokt-network/pocket-js";
const {Configuration, HttpRpcProvider, PocketAAT, Pocket} = PocketPKG; const { Configuration, HttpRpcProvider, PocketAAT, Pocket } = PocketPKG;
import { import {
JSONRPCRequest, JSONRPCRequest,
JSONRPCResponseWithError, JSONRPCResponseWithError,
JSONRPCResponseWithResult, JSONRPCResponseWithResult,
} from "jayson"; } from "jayson";
import config, {updateUsePocketGateway, usePocketGateway} from "./config.js"; import config, { updateUsePocketGateway, usePocketGateway } from "./config.js";
import {errorExit} from "./util.js"; import { errorExit } from "./util.js";
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const stringify = require("json-stable-stringify"); const stringify = require("json-stable-stringify");
const pendingRequests = new NodeCache(); const pendingRequests = new NodeCache();
const processedRequests = new NodeCache({ const processedRequests = new NodeCache({
stdTTL: 60 * 60 * 12, stdTTL: 60 * 60 * 12,
}); });
type PocketAATObject = typeof PocketAAT; type PocketAATObject = typeof PocketAAT;
@ -32,235 +32,235 @@ let _aat: PocketAATObject;
let jsonServer: jayson.Server; let jsonServer: jayson.Server;
interface RPCRequest { interface RPCRequest {
force: boolean; force: boolean;
chain: string; chain: string;
query: string; query: string;
data: string; data: string;
} }
interface RPCResponse { interface RPCResponse {
updated: number; updated: number;
data: data:
| any | any
| { | {
error: string | boolean; error: string | boolean;
}; };
} }
function hash(data: string): string { function hash(data: string): string {
return crypto.createHash("sha256").update(data).digest("hex"); return crypto.createHash("sha256").update(data).digest("hex");
} }
function getRequestId(request: RPCRequest) { function getRequestId(request: RPCRequest) {
const clonedRequest = Object.assign({}, request); const clonedRequest = Object.assign({}, request);
// @ts-ignore // @ts-ignore
delete clonedRequest.force; delete clonedRequest.force;
return hash(stringify(clonedRequest)); return hash(stringify(clonedRequest));
} }
function maybeProcessRequest(request: RPCRequest) { function maybeProcessRequest(request: RPCRequest) {
if (!request.chain) { if (!request.chain) {
throw new Error("RPC chain missing"); throw new Error("RPC chain missing");
} }
if (!request.data) { if (!request.data) {
throw new Error("RPC data missing"); throw new Error("RPC data missing");
} }
return processRequest(request); return processRequest(request);
} }
async function processRequest(request: RPCRequest): Promise<RPCResponse> { async function processRequest(request: RPCRequest): Promise<RPCResponse> {
const reqId = getRequestId(request); const reqId = getRequestId(request);
let lock: Mutex = pendingRequests.get(reqId) as Mutex; let lock: Mutex = pendingRequests.get(reqId) as Mutex;
const lockExists = !!lock; const lockExists = !!lock;
if (!lockExists) { if (!lockExists) {
lock = new Mutex(); lock = new Mutex();
pendingRequests.set(reqId, lock); pendingRequests.set(reqId, lock);
}
if (lock.isLocked()) {
await lock.waitForUnlock();
return processedRequests.get(reqId) as RPCResponse;
}
await lock.acquire();
if (!request.force && processedRequests.get(reqId)) {
return processedRequests.get(reqId) as RPCResponse;
}
let rpcResp;
let error;
try {
rpcResp = await processRpcRequest(
{
method: request.query,
jsonrpc: "2.0",
params: request.data,
id: 1,
} as unknown as JSONRPCRequest,
request.chain
);
} catch (e) {
error = (e as Error).message;
}
let dbData: RPCResponse = {
updated: Date.now(),
data: "",
};
if (rpcResp) {
rpcResp = rpcResp as JSONRPCResponseWithResult;
if (false === rpcResp.result) {
error = true;
} }
if (lock.isLocked()) { rpcResp = rpcResp as unknown as JSONRPCResponseWithError;
await lock.waitForUnlock();
return processedRequests.get(reqId) as RPCResponse; if (rpcResp.error) {
// @ts-ignore
error = rpcResp.error.message;
} }
await lock.acquire(); }
if (!request.force && processedRequests.get(reqId)) { dbData.data = error
return processedRequests.get(reqId) as RPCResponse; ? { error }
} : (rpcResp as unknown as JSONRPCResponseWithResult).result;
let rpcResp; if (!processedRequests.get(reqId) || request.force) {
processedRequests.set(reqId, dbData);
}
let error; await lock.release();
try {
rpcResp = await processRpcRequest(
{
method: request.query,
jsonrpc: "2.0",
params: request.data,
id: 1
} as unknown as JSONRPCRequest,
request.chain
);
} catch (e) {
error = (e as Error).message;
}
let dbData: RPCResponse = { return dbData;
updated: Date.now(),
data: "",
};
if (rpcResp) {
rpcResp = rpcResp as JSONRPCResponseWithResult;
if (false === rpcResp.result) {
error = true;
}
rpcResp = rpcResp as unknown as JSONRPCResponseWithError;
if (rpcResp.error) {
// @ts-ignore
error = rpcResp.error.message;
}
}
dbData.data = error
? {error}
: (rpcResp as unknown as JSONRPCResponseWithResult).result;
if (!processedRequests.get(reqId) || request.force) {
processedRequests.set(reqId, dbData);
}
await lock.release();
return dbData;
} }
export function updateAat(aat: PocketAATObject): void { export function updateAat(aat: PocketAATObject): void {
_aat = aat; _aat = aat;
} }
export function getAat(): PocketAATObject { export function getAat(): PocketAATObject {
return _aat; return _aat;
} }
export function getPocketServer(): typeof Pocket { export function getPocketServer(): typeof Pocket {
return pocketServer; return pocketServer;
} }
export async function unlockAccount( export async function unlockAccount(
accountPrivateKey: string, accountPrivateKey: string,
accountPublicKey: string, accountPublicKey: string,
accountPassphrase: string accountPassphrase: string
): Promise<PocketAATObject> { ): Promise<PocketAATObject> {
try { try {
// @ts-ignore // @ts-ignore
const account = await pocketServer.keybase.importAccount( const account = await pocketServer.keybase.importAccount(
Buffer.from(accountPrivateKey, "hex"), Buffer.from(accountPrivateKey, "hex"),
accountPassphrase accountPassphrase
); );
if (account instanceof Error) { if (account instanceof Error) {
// noinspection ExceptionCaughtLocallyJS // noinspection ExceptionCaughtLocallyJS
throw account; throw account;
}
// @ts-ignore
await pocketServer.keybase.unlockAccount(
account.addressHex,
accountPassphrase,
0
);
// @ts-ignore
return await PocketAAT.from(
"0.0.1",
accountPublicKey,
accountPublicKey,
accountPrivateKey
);
} catch (e) {
console.error(e);
process.exit(1);
} }
// @ts-ignore
await pocketServer.keybase.unlockAccount(
account.addressHex,
accountPassphrase,
0
);
// @ts-ignore
return await PocketAAT.from(
"0.0.1",
accountPublicKey,
accountPublicKey,
accountPrivateKey
);
} catch (e) {
console.error(e);
process.exit(1);
}
} }
export async function processRpcRequest( export async function processRpcRequest(
request: JSONRPCRequest, request: JSONRPCRequest,
chain: string chain: string
): Promise<JSONRPCResponseWithResult | JSONRPCResponseWithError | undefined> { ): Promise<JSONRPCResponseWithResult | JSONRPCResponseWithError | undefined> {
return new Promise((resolve) => { return new Promise((resolve) => {
jsonServer.call( jsonServer.call(
request, request,
{chain}, { chain },
( (
err?: JSONRPCResponseWithError | null, err?: JSONRPCResponseWithError | null,
result?: JSONRPCResponseWithResult result?: JSONRPCResponseWithResult
): void => { ): void => {
if (err) { if (err) {
return resolve(err); return resolve(err);
} }
resolve(result); resolve(result);
} }
); );
}); });
} }
export async function start() { export async function start() {
if (!config.str("pocket-app-id") || !config.str("pocket-app-key")) { if (!config.str("pocket-app-id") || !config.str("pocket-app-key")) {
const pocketHost = config.str("pocket-host"); const pocketHost = config.str("pocket-host");
const pocketPort = config.uint("pocket-port"); const pocketPort = config.uint("pocket-port");
if (!pocketHost || !pocketPort) { if (!pocketHost || !pocketPort) {
errorExit( errorExit(
"Please set pocket-host and pocket-port config options if you do not have an API key set" "Please set pocket-host and pocket-port config options if you do not have an API key set"
); );
}
const dispatchURL = new URL(
`http://${config.str("pocket-host")}:${config.uint("pocket-port")}`
);
const rpcProvider = new HttpRpcProvider(dispatchURL);
const configuration = new Configuration();
// @ts-ignore
pocketServer = new Pocket([dispatchURL], rpcProvider, configuration);
updateUsePocketGateway(false);
} }
if (!usePocketGateway()) { const dispatchURL = new URL(
updateAat( `http://${config.str("pocket-host")}:${config.uint("pocket-port")}`
await unlockAccount( );
<string>config.str("pocket-account-private-key"), const rpcProvider = new HttpRpcProvider(dispatchURL);
<string>config.str("pocket-account-public-key"), const configuration = new Configuration();
"0" // @ts-ignore
) pocketServer = new Pocket([dispatchURL], rpcProvider, configuration);
); updateUsePocketGateway(false);
} }
jsonServer = new jayson.Server(rpcMethods, {useContext: true}); if (!usePocketGateway()) {
updateAat(
await unlockAccount(
<string>config.str("pocket-account-private-key"),
<string>config.str("pocket-account-public-key"),
"0"
)
);
}
(await getDHT("server")).on("connection", (socket: any) => { jsonServer = new jayson.Server(rpcMethods, { useContext: true });
socket.rawStream._ondestroy = () => false;
socket.on("data", async (data: any) => {
let request: RPCRequest;
try {
request = unpack(data) as RPCRequest;
} catch (e) {
return;
}
try { (await getDHT("server")).on("connection", (socket: any) => {
socket.write(pack(await maybeProcessRequest(request))); socket.rawStream._ondestroy = () => false;
} catch (error) { socket.on("data", async (data: any) => {
console.trace(error); let request: RPCRequest;
socket.write(pack({error})); try {
} request = unpack(data) as RPCRequest;
socket.end(); } catch (e) {
}); return;
}
try {
socket.write(pack(await maybeProcessRequest(request)));
} catch (error) {
console.trace(error);
socket.write(pack({ error }));
}
socket.end();
}); });
});
} }

View File

@ -1,112 +1,112 @@
import {maybeMapChainId, reverseMapChainId} from "../util.js"; import { maybeMapChainId, reverseMapChainId } from "../util.js";
import minimatch from "minimatch"; import minimatch from "minimatch";
// @ts-ignore // @ts-ignore
import HTTPClient from "algosdk/dist/cjs/src/client/client.js"; import HTTPClient from "algosdk/dist/cjs/src/client/client.js";
import {sprintf} from "sprintf-js"; import { sprintf } from "sprintf-js";
import {RpcMethodList} from "./index.js"; import { RpcMethodList } from "./index.js";
import config from "../config.js"; import config from "../config.js";
const allowedEndpoints: { [endpoint: string]: ("GET" | "POST")[] } = { const allowedEndpoints: { [endpoint: string]: ("GET" | "POST")[] } = {
"/v2/teal/compile": ["POST"], "/v2/teal/compile": ["POST"],
"/v2/accounts/*": ["GET"], "/v2/accounts/*": ["GET"],
}; };
export function proxyRestMethod( export function proxyRestMethod(
apiServer: string, apiServer: string,
matchChainId: string matchChainId: string
): Function { ): Function {
return async function (args: any, context: object) { return async function (args: any, context: object) {
// @ts-ignore // @ts-ignore
let chain = context.chain; let chain = context.chain;
let chainId = maybeMapChainId(chain); let chainId = maybeMapChainId(chain);
if (!chainId) { if (!chainId) {
throw new Error("Invalid Chain"); throw new Error("Invalid Chain");
}
chainId = reverseMapChainId(chainId as string);
if (!chainId || chainId !== matchChainId) {
throw new Error("Invalid Chain");
}
let method = args.method ?? false;
let endpoint = args.endpoint ?? false;
let data = args.data ?? false;
let query = args.query ?? false;
let fullHeaders = args.fullHeaders ?? {};
fullHeaders = { ...fullHeaders, Referer: "lumeweb_dns_relay" };
if (method) {
method = method.toUpperCase();
}
if (!endpoint) {
throw new Error("Endpoint Missing");
}
let found = false;
for (const theEndpoint in allowedEndpoints) {
if (minimatch(endpoint, theEndpoint)) {
found = true;
break;
}
}
if (!found) {
throw new Error("Endpoint Invalid");
}
let apiUrl;
try {
apiUrl = sprintf(apiServer, chainId, config.str("pocket-app-id"));
} catch (e) {
apiUrl = apiServer;
}
const client = new HTTPClient({}, apiUrl);
let resp;
switch (method) {
case "GET":
resp = await client.get(endpoint, query, fullHeaders);
break;
case "POST":
if (Array.isArray(data?.data)) {
data = new Uint8Array(Buffer.from(data.data));
} }
chainId = reverseMapChainId(chainId as string); resp = await client.post(endpoint, data, { ...fullHeaders });
if (!chainId || chainId !== matchChainId) { break;
throw new Error("Invalid Chain"); default:
throw new Error("Method Invalid");
}
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key: string, value: any): any => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
} }
return value;
let method = args.method ?? false; };
let endpoint = args.endpoint ?? false;
let data = args.data ?? false;
let query = args.query ?? false;
let fullHeaders = args.fullHeaders ?? {};
fullHeaders = {...fullHeaders, Referer: "lumeweb_dns_relay"};
if (method) {
method = method.toUpperCase();
}
if (!endpoint) {
throw new Error("Endpoint Missing");
}
let found = false;
for (const theEndpoint in allowedEndpoints) {
if (minimatch(endpoint, theEndpoint)) {
found = true;
break;
}
}
if (!found) {
throw new Error("Endpoint Invalid");
}
let apiUrl;
try {
apiUrl = sprintf(apiServer, chainId, config.str("pocket-app-id"));
} catch (e) {
apiUrl = apiServer;
}
const client = new HTTPClient({}, apiUrl);
let resp;
switch (method) {
case "GET":
resp = await client.get(endpoint, query, fullHeaders);
break;
case "POST":
if (Array.isArray(data?.data)) {
data = new Uint8Array(Buffer.from(data.data));
}
resp = await client.post(endpoint, data, {...fullHeaders});
break;
default:
throw new Error("Method Invalid");
}
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key: string, value: any): any => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
return JSON.parse(JSON.stringify(resp, getCircularReplacer()));
}; };
return JSON.parse(JSON.stringify(resp, getCircularReplacer()));
};
} }
export default { export default {
algorand_rest_request: proxyRestMethod( algorand_rest_request: proxyRestMethod(
"http://mainnet-api.algonode.network", "http://mainnet-api.algonode.network",
"algorand-mainnet" "algorand-mainnet"
), ),
//'algorand_rest_request': proxyRestMethod("https://%s.gateway.pokt.network/v1/lb/%s", "algorand-mainnet"), //'algorand_rest_request': proxyRestMethod("https://%s.gateway.pokt.network/v1/lb/%s", "algorand-mainnet"),
algorand_rest_indexer_request: proxyRestMethod( algorand_rest_indexer_request: proxyRestMethod(
"http://mainnet-idx.algonode.network", "http://mainnet-idx.algonode.network",
"algorand-mainnet-indexer" "algorand-mainnet-indexer"
), ),
} as RpcMethodList; } as RpcMethodList;

View File

@ -1,106 +1,106 @@
import {ethers} from "ethers"; import { ethers } from "ethers";
import {Pocket, PocketAAT} from "@pokt-network/pocket-js"; import { Pocket, PocketAAT } from "@pokt-network/pocket-js";
import {maybeMapChainId, reverseMapChainId} from "../util.js"; import { maybeMapChainId, reverseMapChainId } from "../util.js";
import {Connection} from "@solana/web3.js"; import { Connection } from "@solana/web3.js";
import {getAat, getPocketServer} from "../rpc.js"; import { getAat, getPocketServer } from "../rpc.js";
import config, {usePocketGateway} from "../config.js"; import config, { usePocketGateway } from "../config.js";
type RpcProviderMethod = (method: string, params: Array<any>) => Promise<any>; type RpcProviderMethod = (method: string, params: Array<any>) => Promise<any>;
const gatewayProviders: { [name: string]: RpcProviderMethod } = {}; const gatewayProviders: { [name: string]: RpcProviderMethod } = {};
const gatewayMethods: { const gatewayMethods: {
[name: string]: (chainId: string) => RpcProviderMethod; [name: string]: (chainId: string) => RpcProviderMethod;
} = { } = {
default: (chainId: string): RpcProviderMethod => { default: (chainId: string): RpcProviderMethod => {
const provider = new ethers.providers.JsonRpcProvider({ const provider = new ethers.providers.JsonRpcProvider({
url: `https://${chainId}.gateway.pokt.network/v1/lb/${config.str( url: `https://${chainId}.gateway.pokt.network/v1/lb/${config.str(
"pocket-api-id" "pocket-api-id"
)}`, )}`,
password: config.str("pocket-api-key"), password: config.str("pocket-api-key"),
}); });
return provider.send.bind(provider); return provider.send.bind(provider);
}, },
"sol-mainnet": (chainId: string): RpcProviderMethod => { "sol-mainnet": (chainId: string): RpcProviderMethod => {
const provider = new Connection( const provider = new Connection(
`https://solana-mainnet.gateway.pokt.network/v1/lb/${config.str( `https://solana-mainnet.gateway.pokt.network/v1/lb/${config.str(
"pocket-api-id" "pocket-api-id"
)}` )}`
); );
// @ts-ignore // @ts-ignore
return provider._rpcRequest.bind(provider); return provider._rpcRequest.bind(provider);
}, },
}; };
export function proxyRpcMethod( export function proxyRpcMethod(
method: string, method: string,
chains: string[] = [] chains: string[] = []
): Function { ): Function {
return async function (args: any, context: object) { return async function (args: any, context: object) {
// @ts-ignore // @ts-ignore
let chain = context.chain; let chain = context.chain;
let chainId = maybeMapChainId(chain); let chainId = maybeMapChainId(chain);
let chainMatch = true; let chainMatch = true;
if ( if (
chains.length > 0 && chains.length > 0 &&
!chains.includes(chain) && !chains.includes(chain) &&
!chains.includes(chainId.toString()) !chains.includes(chainId.toString())
) { ) {
chainMatch = false; chainMatch = false;
} }
if (!chainId || !chainMatch) { if (!chainId || !chainMatch) {
throw new Error("Invalid Chain"); throw new Error("Invalid Chain");
} }
if (usePocketGateway()) { if (usePocketGateway()) {
chainId = reverseMapChainId(chainId as string); chainId = reverseMapChainId(chainId as string);
if (!chainId) { if (!chainId) {
throw new Error("Invalid Chain"); throw new Error("Invalid Chain");
} }
let provider: RpcProviderMethod | boolean = let provider: RpcProviderMethod | boolean =
gatewayProviders[chainId as string] || false; gatewayProviders[chainId as string] || false;
if (!provider) { if (!provider) {
provider = getRpcProvider(chainId as string); provider = getRpcProvider(chainId as string);
} }
gatewayProviders[chainId as string] = provider; gatewayProviders[chainId as string] = provider;
return await provider(method, args); return await provider(method, args);
} }
return await sendRelay( return await sendRelay(
JSON.stringify(args), JSON.stringify(args),
<string>chainId, <string>chainId,
getAat() as unknown as PocketAAT getAat() as unknown as PocketAAT
); );
}; };
} }
// Call this every time you want to fetch RPC data // Call this every time you want to fetch RPC data
async function sendRelay( async function sendRelay(
rpcQuery: string, rpcQuery: string,
blockchain: string, blockchain: string,
pocketAAT: PocketAAT pocketAAT: PocketAAT
) { ) {
try { try {
return await (getPocketServer() as unknown as Pocket).sendRelay( return await (getPocketServer() as unknown as Pocket).sendRelay(
rpcQuery, rpcQuery,
blockchain, blockchain,
pocketAAT pocketAAT
); );
} catch (e) { } catch (e) {
console.log(e); console.log(e);
throw e; throw e;
} }
} }
function getRpcProvider(chain: string): RpcProviderMethod { function getRpcProvider(chain: string): RpcProviderMethod {
if (chain in gatewayMethods) { if (chain in gatewayMethods) {
return gatewayMethods[chain](chain); return gatewayMethods[chain](chain);
} }
return gatewayMethods.default(chain); return gatewayMethods.default(chain);
} }

View File

@ -1,16 +1,16 @@
import {isIp} from "../util.js"; import { isIp } from "../util.js";
import {RpcMethodList} from "./index.js"; import { RpcMethodList } from "./index.js";
import {createRequire} from "module"; import { createRequire } from "module";
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const bns = require("bns"); const bns = require("bns");
const {StubResolver, RecursiveResolver} = bns; const { StubResolver, RecursiveResolver } = bns;
const resolverOpt = { const resolverOpt = {
tcp: true, tcp: true,
inet6: false, inet6: false,
edns: true, edns: true,
dnssec: true, dnssec: true,
}; };
const globalResolver = new RecursiveResolver(resolverOpt); const globalResolver = new RecursiveResolver(resolverOpt);
@ -18,90 +18,90 @@ globalResolver.hints.setDefault();
globalResolver.open(); globalResolver.open();
async function resolveNameServer(ns: string): Promise<string | boolean> { async function resolveNameServer(ns: string): Promise<string | boolean> {
if (isIp(ns)) { if (isIp(ns)) {
return ns; return ns;
} }
let result = await getDnsRecords(ns, "A"); let result = await getDnsRecords(ns, "A");
if (result.length) { if (result.length) {
return result[0]; return result[0];
} }
return false; return false;
} }
async function getDnsRecords( async function getDnsRecords(
domain: string, domain: string,
type: string, type: string,
authority: boolean = false, authority: boolean = false,
resolver = globalResolver resolver = globalResolver
): Promise<string[]> { ): Promise<string[]> {
let result; let result;
try { try {
result = await resolver.lookup(domain, type); result = await resolver.lookup(domain, type);
} catch (e) { } catch (e) {
return []; return [];
} }
let prop = authority ? "authority" : "answer"; let prop = authority ? "authority" : "answer";
if (!result || !result[prop].length) { if (!result || !result[prop].length) {
return []; return [];
} }
return result[prop].map( return result[prop].map(
(item: object) => (item: object) =>
// @ts-ignore // @ts-ignore
item.data.address ?? item.data.target ?? item.data.ns ?? null item.data.address ?? item.data.target ?? item.data.ns ?? null
); );
} }
export default { export default {
dnslookup: async function (args: any) { dnslookup: async function (args: any) {
let dnsResults: string[] = []; let dnsResults: string[] = [];
let domain = args.domain; let domain = args.domain;
let ns = args.nameserver; let ns = args.nameserver;
let dnsResolver = ns ? new StubResolver(resolverOpt) : globalResolver; let dnsResolver = ns ? new StubResolver(resolverOpt) : globalResolver;
await dnsResolver.open(); await dnsResolver.open();
if (ns) { if (ns) {
let nextNs = ns; let nextNs = ns;
let prevNs = null; let prevNs = null;
while (nextNs) { while (nextNs) {
nextNs = await resolveNameServer(nextNs); nextNs = await resolveNameServer(nextNs);
if (!nextNs) { if (!nextNs) {
nextNs = prevNs; nextNs = prevNs;
}
dnsResolver.setServers([nextNs]);
if (nextNs === prevNs) {
break;
}
let result = await getDnsRecords(domain, "NS", true, dnsResolver);
prevNs = nextNs;
nextNs = result.length ? result[0] : false;
}
} }
for (const queryType of ["CNAME", "A"]) { dnsResolver.setServers([nextNs]);
let result = await getDnsRecords(domain, queryType, false, dnsResolver);
if (result) { if (nextNs === prevNs) {
dnsResults = dnsResults.concat(result); break;
}
} }
let result = await getDnsRecords(domain, "NS", true, dnsResolver);
prevNs = nextNs;
nextNs = result.length ? result[0] : false;
}
}
await dnsResolver.close(); for (const queryType of ["CNAME", "A"]) {
let result = await getDnsRecords(domain, queryType, false, dnsResolver);
dnsResults = dnsResults.filter(Boolean); if (result) {
dnsResults = dnsResults.concat(result);
}
}
if (dnsResults.length) { await dnsResolver.close();
return dnsResults[0];
}
return false; dnsResults = dnsResults.filter(Boolean);
},
if (dnsResults.length) {
return dnsResults[0];
}
return false;
},
} as RpcMethodList; } as RpcMethodList;

View File

@ -1,14 +1,14 @@
import {proxyRpcMethod} from "./common.js"; import { proxyRpcMethod } from "./common.js";
import {RpcMethodList} from "./index.js"; import { RpcMethodList } from "./index.js";
const rpcMethods: RpcMethodList = {}; const rpcMethods: RpcMethodList = {};
function proxyEvmRpcMethod(method: string): Function { function proxyEvmRpcMethod(method: string): Function {
return proxyRpcMethod(method); return proxyRpcMethod(method);
} }
["eth_call", "eth_chainId", "net_version"].forEach((method) => { ["eth_call", "eth_chainId", "net_version"].forEach((method) => {
rpcMethods[method] = proxyEvmRpcMethod(method); rpcMethods[method] = proxyEvmRpcMethod(method);
}); });
export default rpcMethods; export default rpcMethods;

View File

@ -1,88 +1,88 @@
import {RpcMethodList} from "./index.js"; import { RpcMethodList } from "./index.js";
// @ts-ignore // @ts-ignore
import rand from "random-key"; import rand from "random-key";
// @ts-ignore // @ts-ignore
import SPVNode from "hsd/lib/node/spvnode.js"; import SPVNode from "hsd/lib/node/spvnode.js";
import config from "../config.js"; import config from "../config.js";
import {createRequire} from "module"; import { createRequire } from "module";
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const {NodeClient} = require("hs-client"); const { NodeClient } = require("hs-client");
let hsdServer: SPVNode; let hsdServer: SPVNode;
let clientArgs = { let clientArgs = {
network: "main", network: "main",
host: "127.0.0.1", host: "127.0.0.1",
port: 12037, port: 12037,
apiKey: rand.generate(), apiKey: rand.generate(),
}; };
if (!config.bool("hsd-use-external-node")) { if (!config.bool("hsd-use-external-node")) {
hsdServer = new SPVNode({ hsdServer = new SPVNode({
config: false, config: false,
argv: false, argv: false,
env: true, env: true,
noDns: true, noDns: true,
memory: false, memory: false,
httpHost: "127.0.0.1", httpHost: "127.0.0.1",
apiKey: clientArgs.apiKey, apiKey: clientArgs.apiKey,
logFile: false, logFile: false,
logConsole: true, logConsole: true,
logLevel: "info", logLevel: "info",
workers: true, workers: true,
network: "main", network: "main",
}); });
console.log(`HSD API KEY: ${clientArgs.apiKey}`); console.log(`HSD API KEY: ${clientArgs.apiKey}`);
hsdServer.on("abort", async (err: any) => { hsdServer.on("abort", async (err: any) => {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
console.error("Shutdown is taking a long time. Exiting."); console.error("Shutdown is taking a long time. Exiting.");
process.exit(3); process.exit(3);
}, 5000); }, 5000);
timeout.unref(); timeout.unref();
try {
console.error("Shutting down...");
await hsdServer.close();
clearTimeout(timeout);
console.error((err as Error).stack);
process.exit(2);
} catch (e: any) {
console.error(`Error occurred during shutdown: ${(e as Error).message}`);
process.exit(3);
}
});
try { try {
await hsdServer.ensure(); console.error("Shutting down...");
await hsdServer.open(); await hsdServer.close();
await hsdServer.connect(); clearTimeout(timeout);
console.error((err as Error).stack);
hsdServer.startSync(); process.exit(2);
} catch (e: any) { } catch (e: any) {
console.error((e as Error).stack); console.error(`Error occurred during shutdown: ${(e as Error).message}`);
process.exit(3);
} }
});
try {
await hsdServer.ensure();
await hsdServer.open();
await hsdServer.connect();
hsdServer.startSync();
} catch (e: any) {
console.error((e as Error).stack);
}
} else { } else {
clientArgs = { clientArgs = {
network: config.str("hsd-network-type"), network: config.str("hsd-network-type"),
host: config.str("hsd-host"), host: config.str("hsd-host"),
port: config.uint("hsd-port"), port: config.uint("hsd-port"),
apiKey: config.str("hsd-api-key"), apiKey: config.str("hsd-api-key"),
}; };
} }
const hnsClient = new NodeClient(clientArgs); const hnsClient = new NodeClient(clientArgs);
export default { export default {
getnameresource: async function (args: any, context: object) { getnameresource: async function (args: any, context: object) {
// @ts-ignore // @ts-ignore
if ("hns" !== context.chain) { if ("hns" !== context.chain) {
throw new Error("Invalid Chain"); throw new Error("Invalid Chain");
} }
return await hnsClient.execute("getnameresource", args); return await hnsClient.execute("getnameresource", args);
}, },
} as RpcMethodList; } as RpcMethodList;

View File

@ -2,17 +2,17 @@ export type RpcMethodList = { [name: string]: Function };
export * from "./common.js"; export * from "./common.js";
import {default as DnsMethods} from "./dns.js"; import { default as DnsMethods } from "./dns.js";
import {default as EvmMethods} from "./evm.js"; import { default as EvmMethods } from "./evm.js";
import {default as HnsMethods} from "./handshake.js"; import { default as HnsMethods } from "./handshake.js";
import {default as SolMethods} from "./solana.js"; import { default as SolMethods } from "./solana.js";
import {default as AlgoMethods} from "./algorand.js"; import { default as AlgoMethods } from "./algorand.js";
export const rpcMethods: RpcMethodList = Object.assign( export const rpcMethods: RpcMethodList = Object.assign(
{}, {},
DnsMethods, DnsMethods,
EvmMethods, EvmMethods,
HnsMethods, HnsMethods,
SolMethods, SolMethods,
AlgoMethods AlgoMethods
); );

View File

@ -1,9 +1,9 @@
import {proxyRpcMethod} from "./common.js"; import { proxyRpcMethod } from "./common.js";
import {RpcMethodList} from "./index.js"; import { RpcMethodList } from "./index.js";
import * as chainNetworks from "../networks.json" assert {type: "json"}; import * as chainNetworks from "../networks.json" assert { type: "json" };
export default { export default {
getAccountInfo: proxyRpcMethod("getAccountInfo", [ getAccountInfo: proxyRpcMethod("getAccountInfo", [
chainNetworks["sol-mainnet"], chainNetworks["sol-mainnet"],
]), ]),
} as RpcMethodList; } as RpcMethodList;

View File

@ -1,66 +1,66 @@
import * as chainNetworks from "./networks.json" assert {type: "json"}; import * as chainNetworks from "./networks.json" assert { type: "json" };
import {Buffer} from "buffer"; import { Buffer } from "buffer";
import {blake2b} from "libskynet"; import { blake2b } from "libskynet";
type networks = { [net: string]: string }; type networks = { [net: string]: string };
export function errorExit(msg: string): void { export function errorExit(msg: string): void {
console.error(msg); console.error(msg);
process.exit(1); process.exit(1);
} }
export function maybeMapChainId(chain: string): string | boolean { export function maybeMapChainId(chain: string): string | boolean {
if (chain in chainNetworks) { if (chain in chainNetworks) {
return (chainNetworks as networks)[chain]; return (chainNetworks as networks)[chain];
} }
if ( if (
[parseInt(chain, 16).toString(), parseInt(chain, 10).toString()].includes( [parseInt(chain, 16).toString(), parseInt(chain, 10).toString()].includes(
chain.toLowerCase() chain.toLowerCase()
) )
) { ) {
return chain; return chain;
} }
return false; return false;
} }
export function reverseMapChainId(chainId: string): string | boolean { export function reverseMapChainId(chainId: string): string | boolean {
let vals = Object.values(chainNetworks); let vals = Object.values(chainNetworks);
if (!vals.includes(chainId)) { if (!vals.includes(chainId)) {
return false; return false;
} }
return Object.keys(chainNetworks)[vals.indexOf(chainId)]; return Object.keys(chainNetworks)[vals.indexOf(chainId)];
} }
export function isIp(ip: string) { export function isIp(ip: string) {
return /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test( return /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(
ip ip
); );
} }
export function hashDataKey(dataKey: string): Uint8Array { export function hashDataKey(dataKey: string): Uint8Array {
return blake2b(encodeUtf8String(dataKey)); return blake2b(encodeUtf8String(dataKey));
} }
function encodeUtf8String(str: string): Uint8Array { function encodeUtf8String(str: string): Uint8Array {
const byteArray = stringToUint8ArrayUtf8(str); const byteArray = stringToUint8ArrayUtf8(str);
const encoded = new Uint8Array(8 + byteArray.length); const encoded = new Uint8Array(8 + byteArray.length);
encoded.set(encodeNumber(byteArray.length)); encoded.set(encodeNumber(byteArray.length));
encoded.set(byteArray, 8); encoded.set(byteArray, 8);
return encoded; return encoded;
} }
function stringToUint8ArrayUtf8(str: string): Uint8Array { function stringToUint8ArrayUtf8(str: string): Uint8Array {
return Uint8Array.from(Buffer.from(str, "utf-8")); return Uint8Array.from(Buffer.from(str, "utf-8"));
} }
function encodeNumber(num: number): Uint8Array { function encodeNumber(num: number): Uint8Array {
const encoded = new Uint8Array(8); const encoded = new Uint8Array(8);
for (let index = 0; index < encoded.length; index++) { for (let index = 0; index < encoded.length; index++) {
encoded[index] = num & 0xff; encoded[index] = num & 0xff;
num = num >> 8; num = num >> 8;
} }
return encoded; return encoded;
} }