2022-08-28 06:33:49 +00:00
|
|
|
import RpcQueryBase from "./base.js";
|
|
|
|
import { flatten } from "../util.js";
|
|
|
|
import { Buffer } from "buffer";
|
|
|
|
import { blake2b } from "libskynet";
|
|
|
|
import { ERR_MAX_TRIES_HIT } from "../error.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 {
|
|
|
|
_maxTries = 3;
|
|
|
|
_tries = 0;
|
|
|
|
checkResponses() {
|
|
|
|
const responseStore = this._responses;
|
|
|
|
const responseStoreData = Object.values(responseStore);
|
|
|
|
const responseObjects = responseStoreData.reduce((output, item) => {
|
2022-08-29 03:19:45 +00:00
|
|
|
const hash = flatHash(item?.data);
|
2022-08-28 06:33:49 +00:00
|
|
|
output[hash] = item?.data;
|
|
|
|
return output;
|
|
|
|
}, {});
|
|
|
|
const responses = responseStoreData.reduce((output, item) => {
|
2022-08-29 03:19:45 +00:00
|
|
|
const hash = flatHash(item?.data);
|
2022-08-28 06:33:49 +00:00
|
|
|
output[hash] = output[hash] ?? 0;
|
|
|
|
output[hash]++;
|
|
|
|
return output;
|
|
|
|
}, {});
|
2022-09-09 10:05:13 +00:00
|
|
|
if (!Object.keys(responses).length) {
|
|
|
|
if (Object.keys(this._errors).length) {
|
|
|
|
this.resolve({ error: Object.values(this._errors).pop() });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this._tries <= this._maxTries) {
|
|
|
|
this._tries++;
|
|
|
|
this.retry();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.resolve({ data: { error: ERR_MAX_TRIES_HIT } });
|
|
|
|
return;
|
|
|
|
}
|
2022-08-28 06:33:49 +00:00
|
|
|
for (const responseHash in responses) {
|
|
|
|
if (responses[responseHash] / responseStoreData.length >=
|
|
|
|
this._network.majorityThreshold) {
|
|
|
|
let response = responseObjects[responseHash];
|
|
|
|
// @ts-ignore
|
|
|
|
if (null === response) {
|
|
|
|
if (this._tries <= this._maxTries) {
|
|
|
|
this._tries++;
|
|
|
|
this.retry();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
response = { error: ERR_MAX_TRIES_HIT };
|
|
|
|
}
|
2022-09-22 15:04:38 +00:00
|
|
|
else {
|
|
|
|
response = { data: response };
|
|
|
|
}
|
|
|
|
this.resolve(response);
|
2022-08-28 06:33:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
retry() {
|
|
|
|
this._responses = {};
|
|
|
|
this._errors = {};
|
|
|
|
if (this._completed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.run();
|
|
|
|
}
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|