rpc-client/dist/query/wisdom.js

123 lines
4.0 KiB
JavaScript
Raw Normal View History

2022-12-04 07:42:04 +00:00
import { clearTimeout } from "timers";
import b4a from "b4a";
2022-12-04 10:39:59 +00:00
import { flatten, validateResponse, validateTimestampedResponse, } from "../util.js";
2022-08-28 06:33:49 +00:00
import { blake2b } from "libskynet";
2022-12-04 07:42:04 +00:00
import { ERR_INVALID_SIGNATURE, ERR_NO_RELAYS } from "../error.js";
import RpcQueryBase from "./base.js";
2022-12-04 10:39:59 +00:00
import { getActiveRelay, setupRelay } from "../sharedRelay.js";
2022-08-29 03:19:45 +00:00
function flatHash(data) {
const flattenedData = flatten(data).sort();
return Buffer.from(blake2b(Buffer.from(JSON.stringify(flattenedData)))).toString("hex");
}
2022-08-28 06:33:49 +00:00
export default class WisdomRpcQuery extends RpcQueryBase {
2022-12-04 07:42:04 +00:00
get result() {
return this._promise;
}
async _run() {
2022-12-04 10:39:59 +00:00
await setupRelay(this._network);
2022-12-04 07:42:04 +00:00
await this.queryRelay();
await this.checkResponse();
}
resolve(data, timeout = false) {
clearTimeout(this._timeoutTimer);
this._timeout = timeout;
this._completed = true;
if (timeout) {
data = {
error: "timeout",
};
}
this._promiseResolve?.(data);
}
async queryRelay() {
2022-12-04 10:39:59 +00:00
let activeRelay = getActiveRelay();
2022-12-04 07:42:04 +00:00
let relays = this.getRelays();
if (!relays.length) {
throw new Error(ERR_NO_RELAYS);
}
2022-12-04 10:39:59 +00:00
if (this._query.bypassCache) {
delete this._query.bypassCache;
2022-12-04 11:37:24 +00:00
const clearCacheQuery = this._network.factory.clearCache({
relays,
query: this._query,
});
2022-12-04 10:39:59 +00:00
await clearCacheQuery.result;
}
if ("bypassCache" in this._query) {
delete this._query.bypassCache;
}
2022-12-04 07:42:04 +00:00
return this.queryRpc(activeRelay, {
module: "rpc",
method: "broadcast_request",
data: {
request: this._query,
relays,
},
});
}
async checkResponse() {
if (this._error) {
this.resolve({ error: this._error });
return;
}
2022-12-04 10:39:59 +00:00
if (!validateResponse(
// @ts-ignore
getActiveRelay().stream.remotePublicKey, this._response)) {
2022-12-04 07:42:04 +00:00
this.resolve({ error: ERR_INVALID_SIGNATURE });
return;
}
let relays = [];
for (const relay in this._response?.relays) {
const resp = this._response?.relays[relay];
2023-01-06 06:19:07 +00:00
if (resp?.error) {
continue;
}
2022-12-04 07:42:04 +00:00
if (validateTimestampedResponse(b4a.from(relay, "hex"), resp)) {
relays.push(resp);
}
}
if (!relays.length) {
this.resolve({ error: ERR_NO_RELAYS });
return;
}
const responseObjects = relays.reduce((output, item) => {
const field = item.signedField || "data";
// @ts-ignore
const hash = flatHash(item[field]);
2022-08-28 06:33:49 +00:00
output[hash] = item?.data;
return output;
}, {});
2022-12-04 07:42:04 +00:00
const responses = relays.reduce((output, item) => {
const field = item.signedField || "data";
// @ts-ignore
const hash = flatHash(item[field]);
2022-08-28 06:33:49 +00:00
output[hash] = output[hash] ?? 0;
output[hash]++;
return output;
}, {});
for (const responseHash in responses) {
2022-12-04 07:42:04 +00:00
if (responses[responseHash] / relays.length >=
2022-08-28 06:33:49 +00:00
this._network.majorityThreshold) {
let response = responseObjects[responseHash];
2022-12-04 07:42:04 +00:00
response = { data: response };
2022-09-22 15:04:38 +00:00
this.resolve(response);
2022-08-28 06:33:49 +00:00
break;
}
}
}
getRelays() {
2022-09-22 13:36:04 +00:00
if (this._network.maxRelays === 0 ||
this._network.relays.length <= this._network.maxRelays) {
return this._network.relays;
}
const list = [];
let available = this._network.relays;
2022-09-22 13:37:54 +00:00
while (list.length <= this._network.maxRelays) {
2022-09-22 13:36:04 +00:00
const item = Math.floor(Math.random() * available.length);
list.push(available[item]);
available.splice(item, 1);
}
return list;
2022-08-28 06:33:49 +00:00
}
}