diff --git a/.gitignore b/.gitignore index be72117326..78f95e223b 100644 --- a/.gitignore +++ b/.gitignore @@ -115,3 +115,6 @@ data* # VS code files .vscode/launch.json + +# KAs Distribution Simulation Script Plots +tools/knowledge-assets-distribution-simulation/plots/**/*jpg diff --git a/installer/data/otnode.service b/installer/data/otnode.service index 1d2168c8f8..92fbc8d5ed 100755 --- a/installer/data/otnode.service +++ b/installer/data/otnode.service @@ -1,7 +1,7 @@ #/lib/systemd/system/otnode.service [Unit] -Description=OriginTrail V6 Stage 1 Beta Node +Description=OriginTrail V6 Node Documentation=https://github.com/OriginTrail/ot-node/ After=network.target graphdb.service blazegraph.service diff --git a/ot-node.js b/ot-node.js index 6bdcf4fa9b..7a64c5f38c 100644 --- a/ot-node.js +++ b/ot-node.js @@ -49,6 +49,12 @@ class OTNode { await this.initializeModules(); + await MigrationExecutor.executeRemoveServiceAgreementsForChiadoMigration( + this.container, + this.logger, + this.config, + ); + await this.createProfiles(); await this.initializeCommandExecutor(); diff --git a/package-lock.json b/package-lock.json index 8e19c69950..9d3780f6a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "origintrail_node", - "version": "6.1.3", + "version": "6.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "origintrail_node", - "version": "6.1.3", + "version": "6.2.0", "license": "ISC", "dependencies": { "@comunica/query-sparql": "^2.4.3", @@ -25,7 +25,7 @@ "axios": "^1.6.0", "cors": "^2.8.5", "deep-extend": "^0.6.0", - "dkg-evm-module": "^4.1.0", + "dkg-evm-module": "github:OriginTrail/dkg-evm-module#release/delegations", "dotenv": "^16.0.1", "ethers": "^5.7.2", "express": "^4.18.1", @@ -66,7 +66,9 @@ "devDependencies": { "@cucumber/cucumber": "^8.5.2", "chai": "^4.3.6", - "dkg.js": "^6.0.2", + "d3": "^7.8.5", + "d3-node": "^3.0.0", + "dkg.js": "^6.1.2", "eslint": "^8.23.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", @@ -75,6 +77,7 @@ "mocha": "^10.0.0", "nyc": "^15.1.0", "prettier": "^2.7.1", + "sharp": "^0.32.6", "sinon": "^14.0.0", "slugify": "^1.6.5" }, @@ -5396,6 +5399,15 @@ "node": ">=10.17" } }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -5650,6 +5662,13 @@ "resolved": "https://registry.npmjs.org/@vascosantos/moving-average/-/moving-average-1.1.0.tgz", "integrity": "sha512-MVEJ4vWAPNbrGLjz7ITnHYg+YXZ6ijAqtH5/cHwSoCpbvuJ98aLXwFfPKAUfZpJMQR5uXB58UJajbY130IRF/w==" }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -5715,6 +5734,37 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals/node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -6061,9 +6111,9 @@ } }, "node_modules/assertion-tools": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/assertion-tools/-/assertion-tools-2.0.2.tgz", - "integrity": "sha512-wntV3+hNWfd0vAs1vaBsSBEaa7W7Qs3Wbu9Sh0WeZEr+RZ55ImjFICh1Bfi1ArGTXYgjd/zQa5YSSOFvs18UGQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assertion-tools/-/assertion-tools-2.1.0.tgz", + "integrity": "sha512-HCI/K2G9x/PlTpj0XuB2K3gR09C5VSXfqOfhzeqONC1x3WHRlUOIZmSSodaA5uLamUE45x8pnHjJxSyqxOI7tA==", "dependencies": { "ethers": "^5.7.2", "jsonld": "^8.1.0", @@ -6228,6 +6278,12 @@ "deep-equal": "^2.0.5" } }, + "node_modules/b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "dev": true + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -6450,6 +6506,12 @@ "run-parallel-limit": "^1.1.0" } }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -7402,6 +7464,30 @@ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, "node_modules/d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -7411,6 +7497,751 @@ "type": "^1.0.1" } }, + "node_modules/d3": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", + "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "dev": true, + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dev": true, + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dev": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dev": true, + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==", + "dev": true + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dev": true, + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dev": true, + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dev": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dev": true, + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dev": true, + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dev": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dev": true, + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dev": true, + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-node/-/d3-node-3.0.0.tgz", + "integrity": "sha512-JuuBToljSQBo+KHSuPVOEdKawsxuLDlrB8TZY8AkPkpvyKaGgX+g0ksgjRg+Mgat9fB77qFQrk09j72cD0yk7w==", + "dev": true, + "dependencies": { + "d3": "^5.16.0", + "jsdom": "^16.7.0" + } + }, + "node_modules/d3-node/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", + "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", + "dev": true, + "dependencies": { + "d3-array": "1", + "d3-axis": "1", + "d3-brush": "1", + "d3-chord": "1", + "d3-collection": "1", + "d3-color": "1", + "d3-contour": "1", + "d3-dispatch": "1", + "d3-drag": "1", + "d3-dsv": "1", + "d3-ease": "1", + "d3-fetch": "1", + "d3-force": "1", + "d3-format": "1", + "d3-geo": "1", + "d3-hierarchy": "1", + "d3-interpolate": "1", + "d3-path": "1", + "d3-polygon": "1", + "d3-quadtree": "1", + "d3-random": "1", + "d3-scale": "2", + "d3-scale-chromatic": "1", + "d3-selection": "1", + "d3-shape": "1", + "d3-time": "1", + "d3-time-format": "2", + "d3-timer": "1", + "d3-transition": "1", + "d3-voronoi": "1", + "d3-zoom": "1" + } + }, + "node_modules/d3-node/node_modules/d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-axis": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz", + "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-brush": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz", + "integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==", + "dev": true, + "dependencies": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "node_modules/d3-node/node_modules/d3-chord": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz", + "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==", + "dev": true, + "dependencies": { + "d3-array": "1", + "d3-path": "1" + } + }, + "node_modules/d3-node/node_modules/d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-contour": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", + "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", + "dev": true, + "dependencies": { + "d3-array": "^1.1.1" + } + }, + "node_modules/d3-node/node_modules/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-drag": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", + "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", + "dev": true, + "dependencies": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "node_modules/d3-node/node_modules/d3-dsv": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz", + "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", + "dev": true, + "dependencies": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json", + "csv2tsv": "bin/dsv2dsv", + "dsv2dsv": "bin/dsv2dsv", + "dsv2json": "bin/dsv2json", + "json2csv": "bin/json2dsv", + "json2dsv": "bin/json2dsv", + "json2tsv": "bin/json2dsv", + "tsv2csv": "bin/dsv2dsv", + "tsv2json": "bin/dsv2json" + } + }, + "node_modules/d3-node/node_modules/d3-ease": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", + "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-fetch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", + "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", + "dev": true, + "dependencies": { + "d3-dsv": "1" + } + }, + "node_modules/d3-node/node_modules/d3-force": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", + "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", + "dev": true, + "dependencies": { + "d3-collection": "1", + "d3-dispatch": "1", + "d3-quadtree": "1", + "d3-timer": "1" + } + }, + "node_modules/d3-node/node_modules/d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-geo": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", + "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", + "dev": true, + "dependencies": { + "d3-array": "1" + } + }, + "node_modules/d3-node/node_modules/d3-hierarchy": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", + "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "dev": true, + "dependencies": { + "d3-color": "1" + } + }, + "node_modules/d3-node/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-polygon": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz", + "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-quadtree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", + "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-random": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz", + "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "dev": true, + "dependencies": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "node_modules/d3-node/node_modules/d3-scale-chromatic": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", + "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", + "dev": true, + "dependencies": { + "d3-color": "1", + "d3-interpolate": "1" + } + }, + "node_modules/d3-node/node_modules/d3-selection": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", + "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dev": true, + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-node/node_modules/d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-time-format": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", + "dev": true, + "dependencies": { + "d3-time": "1" + } + }, + "node_modules/d3-node/node_modules/d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==", + "dev": true + }, + "node_modules/d3-node/node_modules/d3-transition": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", + "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", + "dev": true, + "dependencies": { + "d3-color": "1", + "d3-dispatch": "1", + "d3-ease": "1", + "d3-interpolate": "1", + "d3-selection": "^1.1.0", + "d3-timer": "1" + } + }, + "node_modules/d3-node/node_modules/d3-zoom": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz", + "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==", + "dev": true, + "dependencies": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dev": true, + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dev": true, + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dev": true, + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dev": true, + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dev": true, + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dev": true, + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-voronoi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", + "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==", + "dev": true + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dev": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -7438,6 +8269,55 @@ "node": ">= 12" } }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/dateformat": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", @@ -7622,6 +8502,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dev": true, + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -7655,6 +8544,15 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -7664,9 +8562,9 @@ } }, "node_modules/dkg-evm-module": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/dkg-evm-module/-/dkg-evm-module-4.1.0.tgz", - "integrity": "sha512-80l9dIjUchBk5SOx6+hdo/I1+r1hUpxHmz3fwQuLISvof4aLSVZ2oqvkEdMPtkvBOjgT3F7uKnHSu6SanBa40A==", + "version": "4.2.0", + "resolved": "git+ssh://git@github.com/OriginTrail/dkg-evm-module.git#5fcbdfba99d8b8b9d23d9e2277f73a1bfa70c50c", + "license": "Apache-2.0", "dependencies": { "@openzeppelin/contracts": "^4.9.3", "@polkadot/api": "^10.1.4", @@ -8183,14 +9081,14 @@ "optional": true }, "node_modules/dkg.js": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/dkg.js/-/dkg.js-6.0.2.tgz", - "integrity": "sha512-F1+XGbOTQh//n5fOLpPJCZLNMlTl9Q//A5dAAdBxhA/cXjDWnMJOX2w98Fd2b2/Q4ZsWGuLnwdILqO8GmhG9bw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/dkg.js/-/dkg.js-6.1.2.tgz", + "integrity": "sha512-flqu4wEDEVcMQnnO8WkuAUzeiEn/6wyTIDkRe72j8mwtClVHvA0+QGWrvuv2zfJJuDHx6e3wjrzhkuMdxjez9g==", "dev": true, "dependencies": { - "assertion-tools": "^2.0.2", + "assertion-tools": "^2.1.0", "axios": "^0.27.2", - "dkg-evm-module": "^4.0.4", + "dkg-evm-module": "^4.1.0", "ethers": "^6.1.0", "jsonld": "^8.1.0", "web3": "^1.7.3" @@ -8343,6 +9241,28 @@ } ] }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -8800,6 +9720,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, "node_modules/eslint": { "version": "8.36.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", @@ -9537,6 +10478,15 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -9652,9 +10602,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-fifo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.1.0.tgz", - "integrity": "sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g==" + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" }, "node_modules/fast-glob": { "version": "3.2.12", @@ -10058,6 +11008,12 @@ } ] }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -10315,6 +11271,12 @@ "assert-plus": "^1.0.0" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -11203,6 +12165,18 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -11262,6 +12236,20 @@ "node": ">=6.0.0" } }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -11494,6 +12482,15 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/io-ts": { "version": "1.10.4", "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", @@ -11858,6 +12855,12 @@ "node": ">=8" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", @@ -12395,6 +13398,144 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsdom/node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jsdom/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -13850,6 +14991,12 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "node_modules/mkdirp-promise": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", @@ -14318,6 +15465,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, "node_modules/napi-macros": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", @@ -14442,6 +15595,18 @@ "node": ">= 10.13" } }, + "node_modules/node-abi": { + "version": "3.54.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", + "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-addon-api": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", @@ -14567,6 +15732,12 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==" }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, "node_modules/nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -15235,6 +16406,12 @@ "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", "dev": true }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -15535,6 +16712,134 @@ "node": ">=12.0.0" } }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/prebuild-install/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/prebuild-install/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prebuild-install/node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -15740,6 +17045,12 @@ "node": ">=0.10.0" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -15759,6 +17070,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "node_modules/quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", @@ -16259,6 +17576,12 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -16432,6 +17755,12 @@ "rlp": "bin/rlp" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "dev": true + }, "node_modules/rolling-rate-limiter": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/rolling-rate-limiter/-/rolling-rate-limiter-0.2.13.tgz", @@ -16493,6 +17822,12 @@ "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==" }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "dev": true + }, "node_modules/rxjs": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", @@ -16629,9 +17964,9 @@ "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" }, "node_modules/semver": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", - "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -16858,6 +18193,73 @@ "rdf-string-ttl": "^1.3.2" } }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/sharp/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true + }, + "node_modules/sharp/node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -17445,6 +18847,16 @@ "node": ">=10.0.0" } }, + "node_modules/streamx": { + "version": "2.15.6", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", + "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "node_modules/strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -17793,6 +19205,12 @@ "node": ">= 4.0.0" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/tar": { "version": "4.4.19", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", @@ -17811,6 +19229,28 @@ "node": ">=4.5" } }, + "node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -18439,6 +19879,16 @@ "resolved": "https://registry.npmjs.org/uritemplate/-/uritemplate-0.3.4.tgz", "integrity": "sha512-enADBvHfhjrwxFMTVWeIIYz51SZ91uC6o2MR/NQTVljJB6HTZ8eQL3Q7JBj3RxNISA14MOwJaU3vpf5R6dyxHA==" }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/url-set-query": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", @@ -18565,6 +20015,28 @@ "node": ">=0.6.0" } }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/web-streams-polyfill": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", @@ -19010,6 +20482,21 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -19268,6 +20755,12 @@ "xhr-request": "^1.1.0" } }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, "node_modules/xml2js": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", @@ -23922,6 +25415,12 @@ "integrity": "sha512-TL1adzq1HdxUf9WYduLcQ/DNGYiz71U31QRgbnr0Ef1cPyOUOsBojxHVWpFeOSUucB6Lrs0LxFRA14ntgtkc9w==", "dev": true }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, "@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -24177,6 +25676,12 @@ "resolved": "https://registry.npmjs.org/@vascosantos/moving-average/-/moving-average-1.1.0.tgz", "integrity": "sha512-MVEJ4vWAPNbrGLjz7ITnHYg+YXZ6ijAqtH5/cHwSoCpbvuJ98aLXwFfPKAUfZpJMQR5uXB58UJajbY130IRF/w==" }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -24227,6 +25732,30 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==" }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + } + } + }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -24499,9 +26028,9 @@ } }, "assertion-tools": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/assertion-tools/-/assertion-tools-2.0.2.tgz", - "integrity": "sha512-wntV3+hNWfd0vAs1vaBsSBEaa7W7Qs3Wbu9Sh0WeZEr+RZ55ImjFICh1Bfi1ArGTXYgjd/zQa5YSSOFvs18UGQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assertion-tools/-/assertion-tools-2.1.0.tgz", + "integrity": "sha512-HCI/K2G9x/PlTpj0XuB2K3gR09C5VSXfqOfhzeqONC1x3WHRlUOIZmSSodaA5uLamUE45x8pnHjJxSyqxOI7tA==", "requires": { "ethers": "^5.7.2", "jsonld": "^8.1.0", @@ -24643,6 +26172,12 @@ "deep-equal": "^2.0.5" } }, + "b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -24829,6 +26364,12 @@ "run-parallel-limit": "^1.1.0" } }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -25554,6 +27095,29 @@ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -25563,6 +27127,631 @@ "type": "^1.0.1" } }, + "d3": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", + "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "dev": true, + "requires": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + } + }, + "d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dev": true, + "requires": { + "internmap": "1 - 2" + } + }, + "d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "dev": true + }, + "d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dev": true, + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + } + }, + "d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dev": true, + "requires": { + "d3-path": "1 - 3" + } + }, + "d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==", + "dev": true + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "dev": true + }, + "d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dev": true, + "requires": { + "d3-array": "^3.2.0" + } + }, + "d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dev": true, + "requires": { + "delaunator": "5" + } + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "dev": true + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dev": true, + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + } + }, + "d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dev": true, + "requires": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "dev": true + }, + "d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dev": true, + "requires": { + "d3-dsv": "1 - 3" + } + }, + "d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dev": true, + "requires": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "dev": true + }, + "d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dev": true, + "requires": { + "d3-array": "2.5.0 - 3" + } + }, + "d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "dev": true + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dev": true, + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-node/-/d3-node-3.0.0.tgz", + "integrity": "sha512-JuuBToljSQBo+KHSuPVOEdKawsxuLDlrB8TZY8AkPkpvyKaGgX+g0ksgjRg+Mgat9fB77qFQrk09j72cD0yk7w==", + "dev": true, + "requires": { + "d3": "^5.16.0", + "jsdom": "^16.7.0" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "d3": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", + "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", + "dev": true, + "requires": { + "d3-array": "1", + "d3-axis": "1", + "d3-brush": "1", + "d3-chord": "1", + "d3-collection": "1", + "d3-color": "1", + "d3-contour": "1", + "d3-dispatch": "1", + "d3-drag": "1", + "d3-dsv": "1", + "d3-ease": "1", + "d3-fetch": "1", + "d3-force": "1", + "d3-format": "1", + "d3-geo": "1", + "d3-hierarchy": "1", + "d3-interpolate": "1", + "d3-path": "1", + "d3-polygon": "1", + "d3-quadtree": "1", + "d3-random": "1", + "d3-scale": "2", + "d3-scale-chromatic": "1", + "d3-selection": "1", + "d3-shape": "1", + "d3-time": "1", + "d3-time-format": "2", + "d3-timer": "1", + "d3-transition": "1", + "d3-voronoi": "1", + "d3-zoom": "1" + } + }, + "d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", + "dev": true + }, + "d3-axis": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz", + "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==", + "dev": true + }, + "d3-brush": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz", + "integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==", + "dev": true, + "requires": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "d3-chord": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz", + "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==", + "dev": true, + "requires": { + "d3-array": "1", + "d3-path": "1" + } + }, + "d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==", + "dev": true + }, + "d3-contour": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", + "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", + "dev": true, + "requires": { + "d3-array": "^1.1.1" + } + }, + "d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", + "dev": true + }, + "d3-drag": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", + "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", + "dev": true, + "requires": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "d3-dsv": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz", + "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", + "dev": true, + "requires": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + } + }, + "d3-ease": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", + "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==", + "dev": true + }, + "d3-fetch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", + "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", + "dev": true, + "requires": { + "d3-dsv": "1" + } + }, + "d3-force": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", + "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", + "dev": true, + "requires": { + "d3-collection": "1", + "d3-dispatch": "1", + "d3-quadtree": "1", + "d3-timer": "1" + } + }, + "d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==", + "dev": true + }, + "d3-geo": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", + "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", + "dev": true, + "requires": { + "d3-array": "1" + } + }, + "d3-hierarchy": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", + "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==", + "dev": true + }, + "d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "dev": true, + "requires": { + "d3-color": "1" + } + }, + "d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "dev": true + }, + "d3-polygon": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz", + "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==", + "dev": true + }, + "d3-quadtree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", + "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==", + "dev": true + }, + "d3-random": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz", + "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ==", + "dev": true + }, + "d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "dev": true, + "requires": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "d3-scale-chromatic": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", + "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", + "dev": true, + "requires": { + "d3-color": "1", + "d3-interpolate": "1" + } + }, + "d3-selection": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", + "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==", + "dev": true + }, + "d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dev": true, + "requires": { + "d3-path": "1" + } + }, + "d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==", + "dev": true + }, + "d3-time-format": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", + "dev": true, + "requires": { + "d3-time": "1" + } + }, + "d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==", + "dev": true + }, + "d3-transition": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", + "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", + "dev": true, + "requires": { + "d3-color": "1", + "d3-dispatch": "1", + "d3-ease": "1", + "d3-interpolate": "1", + "d3-selection": "^1.1.0", + "d3-timer": "1" + } + }, + "d3-zoom": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz", + "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==", + "dev": true, + "requires": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + } + } + }, + "d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "dev": true + }, + "d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "dev": true + }, + "d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "dev": true + }, + "d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "dev": true + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dev": true, + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dev": true, + "requires": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + } + }, + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "dev": true + }, + "d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dev": true, + "requires": { + "d3-path": "^3.1.0" + } + }, + "d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dev": true, + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dev": true, + "requires": { + "d3-time": "1 - 3" + } + }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "dev": true + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dev": true, + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-voronoi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", + "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==", + "dev": true + }, + "d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dev": true, + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + } + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -25584,6 +27773,45 @@ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "dependencies": { + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + } + } + }, "dateformat": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", @@ -25716,6 +27944,15 @@ "object-keys": "^1.1.1" } }, + "delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dev": true, + "requires": { + "robust-predicates": "^3.0.0" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -25736,15 +27973,20 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "dev": true + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" }, "dkg-evm-module": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/dkg-evm-module/-/dkg-evm-module-4.1.0.tgz", - "integrity": "sha512-80l9dIjUchBk5SOx6+hdo/I1+r1hUpxHmz3fwQuLISvof4aLSVZ2oqvkEdMPtkvBOjgT3F7uKnHSu6SanBa40A==", + "version": "git+ssh://git@github.com/OriginTrail/dkg-evm-module.git#5fcbdfba99d8b8b9d23d9e2277f73a1bfa70c50c", + "from": "dkg-evm-module@github:OriginTrail/dkg-evm-module#release/delegations", "requires": { "@openzeppelin/contracts": "^4.9.3", "@polkadot/api": "^10.1.4", @@ -26139,14 +28381,14 @@ } }, "dkg.js": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/dkg.js/-/dkg.js-6.0.2.tgz", - "integrity": "sha512-F1+XGbOTQh//n5fOLpPJCZLNMlTl9Q//A5dAAdBxhA/cXjDWnMJOX2w98Fd2b2/Q4ZsWGuLnwdILqO8GmhG9bw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/dkg.js/-/dkg.js-6.1.2.tgz", + "integrity": "sha512-flqu4wEDEVcMQnnO8WkuAUzeiEn/6wyTIDkRe72j8mwtClVHvA0+QGWrvuv2zfJJuDHx6e3wjrzhkuMdxjez9g==", "dev": true, "requires": { - "assertion-tools": "^2.0.2", + "assertion-tools": "^2.1.0", "axios": "^0.27.2", - "dkg-evm-module": "^4.0.4", + "dkg-evm-module": "^4.1.0", "ethers": "^6.1.0", "jsonld": "^8.1.0", "web3": "^1.7.3" @@ -26253,6 +28495,23 @@ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, "domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", @@ -26645,6 +28904,18 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, + "escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "source-map": "~0.6.1" + } + }, "eslint": { "version": "8.36.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", @@ -27241,6 +29512,12 @@ "strip-final-newline": "^2.0.0" } }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true + }, "express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -27346,9 +29623,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-fifo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.1.0.tgz", - "integrity": "sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g==" + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" }, "fast-glob": { "version": "3.2.12", @@ -27644,6 +29921,12 @@ "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", "dev": true }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, "fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -27838,6 +30121,12 @@ "assert-plus": "^1.0.0" } }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true + }, "glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -28532,6 +30821,15 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -28578,6 +30876,17 @@ "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.1.0.tgz", "integrity": "sha512-pj6N1yxOz/ANO8HHsWGg/OoIL1kmRYvQnXQ7PIRpgp+15AnEsRH8fmIJE6D1OdWG2Bov+BJHVla1fFXxg1JbbA==" }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -28740,6 +31049,12 @@ "side-channel": "^1.0.4" } }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "dev": true + }, "io-ts": { "version": "1.10.4", "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", @@ -28983,6 +31298,12 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", @@ -29424,6 +31745,103 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, + "tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + } + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -30582,6 +33000,12 @@ "minimist": "^1.2.6" } }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "mkdirp-promise": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", @@ -30956,6 +33380,12 @@ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, "napi-macros": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", @@ -31067,6 +33497,15 @@ "propagate": "^2.0.0" } }, + "node-abi": { + "version": "3.54.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", + "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, "node-addon-api": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", @@ -31147,6 +33586,12 @@ } } }, + "nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, "nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -31641,6 +34086,12 @@ "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", "dev": true }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -31873,6 +34324,96 @@ "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.8.tgz", "integrity": "sha512-c4E5sVlX+npoRiKb72SkMOYMZ/c+jehaKAytybykhh49tEQYkjHxKSZ3YHUyH1v3oEL+wl3aXtkyYhJp+cNXDg==" }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + } + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -32033,11 +34574,23 @@ "strict-uri-encode": "^1.0.0" } }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, + "queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", @@ -32469,6 +35022,12 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -32602,6 +35161,12 @@ "bn.js": "^5.2.0" } }, + "robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "dev": true + }, "rolling-rate-limiter": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/rolling-rate-limiter/-/rolling-rate-limiter-0.2.13.tgz", @@ -32632,6 +35197,12 @@ "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==" }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "dev": true + }, "rxjs": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", @@ -32743,9 +35314,9 @@ "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" }, "semver": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", - "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" }, @@ -32916,6 +35487,51 @@ "rdf-string-ttl": "^1.3.2" } }, + "sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "dev": true, + "requires": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + } + }, + "node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + } + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -33391,6 +36007,16 @@ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" }, + "streamx": { + "version": "2.15.6", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", + "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "dev": true, + "requires": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -33649,6 +36275,12 @@ } } }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "tar": { "version": "4.4.19", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", @@ -33664,6 +36296,28 @@ "yallist": "^3.1.1" } }, + "tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "requires": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dev": true, + "requires": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -34156,6 +36810,16 @@ "resolved": "https://registry.npmjs.org/uritemplate/-/uritemplate-0.3.4.tgz", "integrity": "sha512-enADBvHfhjrwxFMTVWeIIYz51SZ91uC6o2MR/NQTVljJB6HTZ8eQL3Q7JBj3RxNISA14MOwJaU3vpf5R6dyxHA==" }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "url-set-query": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", @@ -34259,6 +36923,24 @@ "extsprintf": "^1.2.0" } }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, "web-streams-polyfill": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", @@ -34645,6 +37327,21 @@ } } }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -34850,6 +37547,12 @@ "xhr-request": "^1.1.0" } }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, "xml2js": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", diff --git a/package.json b/package.json index a47456623b..4e6c99b95e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "origintrail_node", - "version": "6.1.3", + "version": "6.2.0", "description": "OTNode V6", "main": "index.js", "type": "module", @@ -48,7 +48,9 @@ "devDependencies": { "@cucumber/cucumber": "^8.5.2", "chai": "^4.3.6", - "dkg.js": "^6.0.2", + "d3": "^7.8.5", + "d3-node": "^3.0.0", + "dkg.js": "^6.1.2", "eslint": "^8.23.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", @@ -57,6 +59,7 @@ "mocha": "^10.0.0", "nyc": "^15.1.0", "prettier": "^2.7.1", + "sharp": "^0.32.6", "sinon": "^14.0.0", "slugify": "^1.6.5" }, @@ -77,7 +80,7 @@ "axios": "^1.6.0", "cors": "^2.8.5", "deep-extend": "^0.6.0", - "dkg-evm-module": "^4.1.0", + "dkg-evm-module": "github:OriginTrail/dkg-evm-module#release/delegations", "dotenv": "^16.0.1", "ethers": "^5.7.2", "express": "^4.18.1", diff --git a/scripts/set-stake.js b/scripts/set-stake.js index 4db4be7fb0..01f01f76a0 100644 --- a/scripts/set-stake.js +++ b/scripts/set-stake.js @@ -95,7 +95,7 @@ async function setStake( // TODO: Add ABI instead of hard-coded function definition tx = await stakingContract['addStake(uint72,uint96)'](identityId, stakeWei, { gasPrice: gasPrice ? gasPrice * 100 : undefined, - gasLimit: 500_000, + gasLimit: 3_000_000, }); await provider.waitForTransaction( tx.hash, diff --git a/src/commands/protocols/common/epoch-check-command.js b/src/commands/protocols/common/epoch-check-command.js index d8da892f21..0b144995a5 100644 --- a/src/commands/protocols/common/epoch-check-command.js +++ b/src/commands/protocols/common/epoch-check-command.js @@ -20,6 +20,8 @@ class EpochCheckCommand extends Command { this.blockchainModuleManager = ctx.blockchainModuleManager; this.serviceAgreementService = ctx.serviceAgreementService; this.fileService = ctx.fileService; + this.proximityScoringService = ctx.proximityScoringService; + this.hashingService = ctx.hashingService; this.errorType = ERROR_TYPE.COMMIT_PROOF.EPOCH_CHECK_ERROR; } @@ -35,11 +37,11 @@ class EpochCheckCommand extends Command { !migrationExecuted ) { this.logger.info( - 'Epoch check command will be postponed until ual extension triple store migration is completed', + 'Epoch check: command will be postponed until ual extension triple store migration is completed', ); return Command.repeat(); } - this.logger.info('Starting epoch check command'); + this.logger.info('Epoch check: Starting epoch check command'); const operationId = this.operationIdService.generateId(); await Promise.all( @@ -72,9 +74,12 @@ class EpochCheckCommand extends Command { totalTransactions -= transactionQueueLength; - const [r0, r2] = await Promise.all([ + const [r0, r2, totalNodesNumber, minStake, maxStake] = await Promise.all([ this.blockchainModuleManager.getR0(blockchain), this.blockchainModuleManager.getR2(blockchain), + this.repositoryModuleManager.getPeersCount(blockchain), + this.blockchainModuleManager.getMinimumStake(blockchain), + this.blockchainModuleManager.getMaximumStake(blockchain), ]); await Promise.all([ @@ -84,6 +89,9 @@ class EpochCheckCommand extends Command { commitWindowDurationPerc, r0, r2, + totalNodesNumber, + minStake, + maxStake, ), this.scheduleCalculateProofsCommands( blockchain, @@ -110,6 +118,9 @@ class EpochCheckCommand extends Command { commitWindowDurationPerc, r0, r2, + totalNodesNumber, + minStake, + maxStake, ) { const timestamp = await this.blockchainModuleManager.getBlockchainTimestamp(blockchain); const eligibleAgreementForSubmitCommit = @@ -118,18 +129,58 @@ class EpochCheckCommand extends Command { blockchain, commitWindowDurationPerc, ); - + this.logger.info( + `Epoch check: Found ${eligibleAgreementForSubmitCommit.length} eligible agreements for submit commit for blockchain: ${blockchain}`, + ); const scheduleSubmitCommitCommands = []; const updateServiceAgreementsLastCommitEpoch = []; for (const serviceAgreement of eligibleAgreementForSubmitCommit) { - if (scheduleSubmitCommitCommands.length >= maxTransactions) break; + if (scheduleSubmitCommitCommands.length >= maxTransactions) { + this.logger.warn( + `Epoch check: not scheduling new commits. Submit commit command length: ${scheduleSubmitCommitCommands.length}, max number of transactions: ${maxTransactions} for blockchain: ${blockchain}`, + ); + break; + } + + const neighbourhood = await this.shardingTableService.findNeighbourhood( + blockchain, + serviceAgreement.keyword, + r2, + serviceAgreement.hashFunctionId, + serviceAgreement.scoreFunctionId, + true, + ); + + let neighbourhoodEdges = null; + if (serviceAgreement.scoreFunctionId === 2) { + neighbourhoodEdges = await this.shardingTableService.getNeighboorhoodEdgeNodes( + neighbourhood, + blockchain, + serviceAgreement.hashFunctionId, + serviceAgreement.scoreFunctionId, + serviceAgreement.keyword, + ); + } + + if (!neighbourhoodEdges && serviceAgreement.scoreFunctionId === 2) { + this.logger.warn( + `Epoch check: unable to find neighbourhood edges for agreement id: ${serviceAgreement.agreementId} for blockchain: ${blockchain}`, + ); + continue; + } try { - const rank = await this.calculateRank( + const rank = await this.serviceAgreementService.calculateRank( blockchain, serviceAgreement.keyword, serviceAgreement.hashFunctionId, + serviceAgreement.scoreFunctionId, r2, + neighbourhood, + neighbourhoodEdges, + totalNodesNumber, + minStake, + maxStake, ); updateServiceAgreementsLastCommitEpoch.push( @@ -141,36 +192,40 @@ class EpochCheckCommand extends Command { if (rank == null) { this.logger.trace( - `Node not in R2: ${r2} for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Skipping scheduling submitCommitCommand.`, + `Epoch check: Node not in R2: ${r2} for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Skipping scheduling submitCommitCommand for blockchain: ${blockchain}`, ); continue; } if (rank >= r0) { this.logger.trace( - `Calculated rank: ${ + `Epoch check: Calculated rank: ${ rank + 1 }. Node not in R0: ${r0} for the Service Agreement with the ID: ${ serviceAgreement.agreementId - }. Skipping scheduling submitCommitCommand.`, + }. Skipping scheduling submitCommitCommand for blockchain: ${blockchain}`, ); continue; } this.logger.trace( - `Calculated rank: ${ + `Epoch check: Calculated rank: ${ rank + 1 }. Node in R0: ${r0} for the Service Agreement with the ID: ${ serviceAgreement.agreementId - }. Scheduling submitCommitCommand.`, + }. Scheduling submitCommitCommand for blockchain: ${blockchain}`, ); - + const closestNode = neighbourhood[0]; scheduleSubmitCommitCommands.push( - this.scheduleSubmitCommitCommand(serviceAgreement), + this.scheduleSubmitCommitCommand( + serviceAgreement, + neighbourhoodEdges, + closestNode, + ), ); } catch (error) { this.logger.warn( - `Failed to schedule submitCommitCommand for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Error message: ${error.message}.`, + `Epoch check: Failed to schedule submitCommitCommand for the Service Agreement with the ID: ${serviceAgreement.agreementId} for blockchain: ${blockchain}. Error message: ${error.message}.`, ); continue; } @@ -194,10 +249,18 @@ class EpochCheckCommand extends Command { blockchain, proofWindowDurationPerc, ); + this.logger.info( + `Epoch check: Found ${eligibleAgreementsForSubmitProofs.length} eligible agreements for submit proof for blockchain: ${blockchain}`, + ); const scheduleSubmitProofCommands = []; const updateServiceAgreementsLastProofEpoch = []; for (const serviceAgreement of eligibleAgreementsForSubmitProofs) { - if (scheduleSubmitProofCommands.length >= maxTransactions) break; + if (scheduleSubmitProofCommands.length >= maxTransactions) { + this.logger.warn( + `Epoch check: not scheduling new proofs. Submit proofs command length: ${scheduleSubmitProofCommands.length}, max number of transactions: ${maxTransactions} for blockchain: ${blockchain}`, + ); + break; + } try { const eligibleForReward = await this.isEligibleForRewards( @@ -209,7 +272,7 @@ class EpochCheckCommand extends Command { ); if (eligibleForReward) { this.logger.trace( - `Node is eligible for rewards for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Scheduling submitProofsCommand.`, + `Epoch check: Node is eligible for rewards for the Service Agreement with the ID: ${serviceAgreement.agreementId} for blockchain: ${blockchain}. Scheduling submitProofsCommand.`, ); scheduleSubmitProofCommands.push( @@ -217,7 +280,7 @@ class EpochCheckCommand extends Command { ); } else { this.logger.trace( - `Node is not eligible for rewards for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Skipping scheduling submitProofsCommand.`, + `Epoch check: Node is not eligible for rewards for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Skipping scheduling submitProofsCommand for blockchain: ${blockchain}`, ); } updateServiceAgreementsLastProofEpoch.push( @@ -228,7 +291,7 @@ class EpochCheckCommand extends Command { ); } catch (error) { this.logger.warn( - `Failed to schedule submitProofsCommand for the Service Agreement with the ID: ${serviceAgreement.agreementId}. Error message: ${error.message}.`, + `Epoch check: Failed to schedule submitProofsCommand for the Service Agreement with the ID: ${serviceAgreement.agreementId} for blockchain: ${blockchain}. Error message: ${error.message}.`, ); continue; } @@ -239,37 +302,6 @@ class EpochCheckCommand extends Command { ]); } - async calculateRank(blockchain, keyword, hashFunctionId, r2) { - const neighbourhood = await this.shardingTableService.findNeighbourhood( - blockchain, - keyword, - r2, - hashFunctionId, - true, - ); - - const peerId = this.networkModuleManager.getPeerId().toB58String(); - if (!neighbourhood.some((node) => node.peerId === peerId)) { - return; - } - - const scores = await Promise.all( - neighbourhood.map(async (node) => ({ - score: await this.serviceAgreementService.calculateScore( - node.peerId, - blockchain, - keyword, - hashFunctionId, - ), - peerId: node.peerId, - })), - ); - - scores.sort((a, b) => b.score - a.score); - - return scores.findIndex((node) => node.peerId === peerId); - } - async isEligibleForRewards(blockchain, agreementId, epoch, stateIndex, r0) { const identityId = await this.blockchainModuleManager.getIdentityId(blockchain); const commits = await this.blockchainModuleManager.getTopCommitSubmissions( @@ -288,7 +320,7 @@ class EpochCheckCommand extends Command { return false; } - async scheduleSubmitCommitCommand(agreement) { + async scheduleSubmitCommitCommand(agreement, neighbourhoodEdges, closestNode) { const commandData = { operationId: this.operationIdService.generateId(), blockchain: agreement.blockchainId, @@ -299,6 +331,9 @@ class EpochCheckCommand extends Command { epoch: agreement.currentEpoch, agreementId: agreement.agreementId, stateIndex: agreement.stateIndex, + closestNode: closestNode.index, + leftNeighborhoodEdge: neighbourhoodEdges?.leftEdge.index, + rightNeighborhoodEdge: neighbourhoodEdges?.rightEdge.index, }; await this.commandExecutor.add({ diff --git a/src/commands/protocols/common/find-nodes-command.js b/src/commands/protocols/common/find-nodes-command.js index bf9e204301..a3f6e19e0c 100644 --- a/src/commands/protocols/common/find-nodes-command.js +++ b/src/commands/protocols/common/find-nodes-command.js @@ -22,6 +22,7 @@ class FindNodesCommand extends Command { networkProtocols, hashFunctionId, minAckResponses, + proximityScoreFunctionsPairId, } = command.data; this.errorType = errorType; @@ -29,7 +30,13 @@ class FindNodesCommand extends Command { // TODO: protocol selection const closestNodes = []; - const foundNodes = await this.findNodes(blockchain, keyword, operationId, hashFunctionId); + const foundNodes = await this.findNodes( + blockchain, + keyword, + operationId, + hashFunctionId, + proximityScoreFunctionsPairId, + ); for (const node of foundNodes) { if (node.id !== this.networkModuleManager.getPeerId().toB58String()) { closestNodes.push({ id: node.id, protocol: networkProtocols[0] }); @@ -66,7 +73,13 @@ class FindNodesCommand extends Command { ); } - async findNodes(blockchainId, keyword, operationId, hashFunctionId) { + async findNodes( + blockchainId, + keyword, + operationId, + hashFunctionId, + proximityScoreFunctionsPairId, + ) { await this.operationIdService.updateOperationIdStatus( operationId, blockchainId, @@ -78,6 +91,7 @@ class FindNodesCommand extends Command { keyword, r2, hashFunctionId, + proximityScoreFunctionsPairId, true, ); diff --git a/src/commands/protocols/common/handle-protocol-message-command.js b/src/commands/protocols/common/handle-protocol-message-command.js index 92b7966697..1da17dcbcc 100644 --- a/src/commands/protocols/common/handle-protocol-message-command.js +++ b/src/commands/protocols/common/handle-protocol-message-command.js @@ -47,12 +47,19 @@ class HandleProtocolMessageCommand extends Command { throw Error('prepareMessage not implemented'); } - async validateNeighborhood(blockchain, keyword, hashFunctionId, ual) { + async validateNeighborhood( + blockchain, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + ual, + ) { const closestNodes = await this.shardingTableService.findNeighbourhood( blockchain, keyword, await this.blockchainModuleManager.getR2(blockchain), hashFunctionId, + proximityScoreFunctionsPairId, true, ); const peerId = this.networkModuleManager.getPeerId().toB58String(); @@ -179,11 +186,20 @@ class HandleProtocolMessageCommand extends Command { tokenId, keyword, hashFunctionId, + proximityScoreFunctionsPairId, ) { const ual = this.ualService.deriveUAL(blockchain, contract, tokenId); this.logger.trace(`Validating neighborhood for ual: ${ual}`); - if (!(await this.validateNeighborhood(blockchain, keyword, hashFunctionId, ual))) { + if ( + !(await this.validateNeighborhood( + blockchain, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + ual, + )) + ) { return { messageType: NETWORK_MESSAGE_TYPES.RESPONSES.NACK, messageData: { errorMessage: 'Invalid neighbourhood' }, diff --git a/src/commands/protocols/common/network-protocol-command.js b/src/commands/protocols/common/network-protocol-command.js index fb10f1d3b3..8bbf2affbc 100644 --- a/src/commands/protocols/common/network-protocol-command.js +++ b/src/commands/protocols/common/network-protocol-command.js @@ -4,6 +4,8 @@ class NetworkProtocolCommand extends Command { constructor(ctx) { super(ctx); this.commandExecutor = ctx.commandExecutor; + this.blockchainModuleManager = ctx.blockchainModuleManager; + this.serviceAgreementService = ctx.serviceAgreementService; } /** @@ -11,12 +13,25 @@ class NetworkProtocolCommand extends Command { * @param command */ async execute(command) { - const { blockchain } = command.data; + const { blockchain, contract, tokenId, hashFunctionId } = command.data; const keywords = await this.getKeywords(command); const batchSize = await this.getBatchSize(blockchain); const minAckResponses = await this.getMinAckResponses(blockchain); + const serviceAgreementId = await this.serviceAgreementService.generateId( + blockchain, + contract, + tokenId, + keywords[0], + hashFunctionId, + ); + const proximityScoreFunctionsPairId = + await this.blockchainModuleManager.getAgreementScoreFunctionId( + blockchain, + serviceAgreementId, + ); + const commandSequence = [ 'findNodesCommand', `${this.operationService.getOperationName()}ScheduleMessagesCommand`, @@ -34,6 +49,7 @@ class NetworkProtocolCommand extends Command { minAckResponses, errorType: this.errorType, networkProtocols: this.operationService.getNetworkProtocols(), + proximityScoreFunctionsPairId, }, transactional: false, }), diff --git a/src/commands/protocols/common/protocol-init-command.js b/src/commands/protocols/common/protocol-init-command.js index 6a76e0318b..df324248fa 100644 --- a/src/commands/protocols/common/protocol-init-command.js +++ b/src/commands/protocols/common/protocol-init-command.js @@ -3,12 +3,27 @@ import { NETWORK_MESSAGE_TYPES } from '../../../constants/constants.js'; class ProtocolInitCommand extends ProtocolMessageCommand { async prepareMessage(command) { - const { assertionId, contract, tokenId, keyword, hashFunctionId } = command.data; + const { + assertionId, + contract, + tokenId, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + } = command.data; // TODO: Backwards compatibility, send blockchain without chainId const blockchain = command.data.blockchain.split(':')[0]; - return { assertionId, blockchain, contract, tokenId, keyword, hashFunctionId }; + return { + assertionId, + blockchain, + contract, + tokenId, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + }; } async execute(command) { diff --git a/src/commands/protocols/common/protocol-schedule-messages-command.js b/src/commands/protocols/common/protocol-schedule-messages-command.js index c29b66559d..6d2022d71b 100644 --- a/src/commands/protocols/common/protocol-schedule-messages-command.js +++ b/src/commands/protocols/common/protocol-schedule-messages-command.js @@ -69,8 +69,22 @@ class ProtocolScheduleMessagesCommand extends Command { } getNextCommandData(command) { - const { assertionId, blockchain, contract, tokenId, hashFunctionId } = command.data; - return { assertionId, blockchain, contract, tokenId, hashFunctionId }; + const { + assertionId, + blockchain, + contract, + tokenId, + hashFunctionId, + proximityScoreFunctionsPairId, + } = command.data; + return { + assertionId, + blockchain, + contract, + tokenId, + hashFunctionId, + proximityScoreFunctionsPairId, + }; } /** diff --git a/src/commands/protocols/common/submit-commit-command.js b/src/commands/protocols/common/submit-commit-command.js index d7a703d95e..12277e803d 100644 --- a/src/commands/protocols/common/submit-commit-command.js +++ b/src/commands/protocols/common/submit-commit-command.js @@ -28,6 +28,9 @@ class SubmitCommitCommand extends Command { agreementId, stateIndex, gasPrice, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, } = command.data; this.logger.trace( @@ -35,6 +38,8 @@ class SubmitCommitCommand extends Command { `Blockchain: ${blockchain}, Contract: ${contract}, Token ID: ${tokenId}, ` + `Keyword: ${keyword}, Hash function ID: ${hashFunctionId}, Epoch: ${epoch}, ` + `State Index: ${stateIndex}, Operation ID: ${operationId}, ` + + `Clossest Node: ${closestNode}, Left neighborhood edge: ${leftNeighborhoodEdge}, ` + + `Right neighborhood edge: ${rightNeighborhoodEdge}` + `Retry number: ${COMMAND_RETRIES.SUBMIT_COMMIT - command.retries + 1}`, ); @@ -60,7 +65,9 @@ class SubmitCommitCommand extends Command { `Knowledge Asset was updated, not sending Commit for the Service Agreement with the ID: ${agreementId}, ` + `Blockchain: ${blockchain}, Contract: ${contract}, Token ID: ${tokenId}, ` + `Keyword: ${keyword}, Hash function ID: ${hashFunctionId}, Epoch: ${epoch}, ` + - `State Index: ${stateIndex}, Operation ID: ${operationId}`, + `State Index: ${stateIndex}, Operation ID: ${operationId}` + + `Clossest Node: ${closestNode}, Left neighborhood edge: ${leftNeighborhoodEdge}, ` + + `Right neighborhood edge: ${rightNeighborhoodEdge}`, ); return Command.empty(); @@ -78,7 +85,9 @@ class SubmitCommitCommand extends Command { `Commit has already been submitted for the Service Agreement with the ID: ${agreementId}, ` + `Blockchain: ${blockchain}, Contract: ${contract}, Token ID: ${tokenId}, ` + `Keyword: ${keyword}, Hash function ID: ${hashFunctionId}, Epoch: ${epoch}, ` + - `State Index: ${stateIndex}, Operation ID: ${operationId}`, + `State Index: ${stateIndex}, Operation ID: ${operationId}` + + `Clossest Node: ${closestNode}, Left neighborhood edge: ${leftNeighborhoodEdge}, ` + + `Right neighborhood edge: ${rightNeighborhoodEdge}`, ); return Command.empty(); @@ -93,6 +102,9 @@ class SubmitCommitCommand extends Command { tokenId, keyword, hashFunctionId, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, epoch, stateIndex, (result) => { @@ -128,6 +140,8 @@ class SubmitCommitCommand extends Command { `with the ID: ${agreementId}, Blockchain: ${blockchain}, Contract: ${contract}, ` + `Token ID: ${tokenId}, Keyword: ${keyword}, Hash function ID: ${hashFunctionId}, ` + `Epoch: ${epoch}, State Index: ${stateIndex}, Operation ID: ${operationId}, ` + + `Clossest Node: ${closestNode}, Left neighborhood edge: ${leftNeighborhoodEdge}, ` + + `Right neighborhood edge: ${rightNeighborhoodEdge}, ` + `Retry number: ${COMMAND_RETRIES.SUBMIT_COMMIT - command.retries + 1}.`, ); this.operationIdService.emitChangeEvent( @@ -190,6 +204,8 @@ class SubmitCommitCommand extends Command { `Blockchain: ${blockchain}, Contract: ${contract}, Token ID: ${tokenId}, ` + `Keyword: ${keyword}, Hash function ID: ${hashFunctionId}, Epoch: ${epoch}, ` + `State Index: ${stateIndex}, Operation ID: ${operationId}, ` + + `Clossest Node: ${closestNode}, Left neighborhood edge: ${leftNeighborhoodEdge}, ` + + `Right neighborhood edge: ${rightNeighborhoodEdge}` + `Retry number: ${COMMAND_RETRIES.SUBMIT_COMMIT - command.retries + 1}`, ); diff --git a/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-init-command.js b/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-init-command.js index 2c366cd952..f0ccabe408 100644 --- a/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-init-command.js +++ b/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-init-command.js @@ -10,7 +10,8 @@ class GetInitCommand extends ProtocolInitCommand { } async prepareMessage(command) { - const { contract, tokenId, keyword, assertionId, state } = command.data; + const { contract, tokenId, keyword, assertionId, state, proximityScoreFunctionsPairId } = + command.data; // TODO: Backwards compatibility, send blockchain without chainId const blockchain = command.data.blockchain.split(':')[0]; @@ -22,6 +23,7 @@ class GetInitCommand extends ProtocolInitCommand { keyword, assertionId, state, + proximityScoreFunctionsPairId, }; } diff --git a/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-request-command.js b/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-request-command.js index 6780a99871..82ec902859 100644 --- a/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-request-command.js +++ b/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-request-command.js @@ -31,7 +31,14 @@ class GetRequestCommand extends ProtocolRequestCommand { } async prepareMessage(command) { - const { contract, tokenId, assertionId, state, hashFunctionId } = command.data; + const { + contract, + tokenId, + assertionId, + state, + hashFunctionId, + proximityScoreFunctionsPairId, + } = command.data; // TODO: Backwards compatibility, send blockchain without chainId const blockchain = command.data.blockchain.split(':')[0]; @@ -43,6 +50,7 @@ class GetRequestCommand extends ProtocolRequestCommand { assertionId, state, hashFunctionId, + proximityScoreFunctionsPairId, }; } diff --git a/src/commands/protocols/publish/receiver/v1.0.0/v1-0-0-handle-store-init-command.js b/src/commands/protocols/publish/receiver/v1.0.0/v1-0-0-handle-store-init-command.js index d9c529ffe8..77e3bd36c4 100644 --- a/src/commands/protocols/publish/receiver/v1.0.0/v1-0-0-handle-store-init-command.js +++ b/src/commands/protocols/publish/receiver/v1.0.0/v1-0-0-handle-store-init-command.js @@ -11,8 +11,16 @@ class HandleStoreInitCommand extends HandleProtocolMessageCommand { } async prepareMessage(commandData) { - const { operationId, assertionId, blockchain, contract, tokenId, keyword, hashFunctionId } = - commandData; + const { + operationId, + assertionId, + blockchain, + contract, + tokenId, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + } = commandData; await this.operationIdService.updateOperationIdStatus( operationId, @@ -28,6 +36,7 @@ class HandleStoreInitCommand extends HandleProtocolMessageCommand { tokenId, keyword, hashFunctionId, + proximityScoreFunctionsPairId, ); this.operationIdService.updateOperationIdStatus( diff --git a/src/commands/protocols/update/receiver/submit-update-commit-command.js b/src/commands/protocols/update/receiver/submit-update-commit-command.js index 64d81de6d2..b89a600441 100644 --- a/src/commands/protocols/update/receiver/submit-update-commit-command.js +++ b/src/commands/protocols/update/receiver/submit-update-commit-command.js @@ -27,13 +27,18 @@ class SubmitUpdateCommitCommand extends Command { agreementId, operationId, gasPrice, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, } = command.data; this.logger.trace( `Started ${command.name} for the Service Agreement with the ID: ${agreementId}, ` + `Blockchain: ${blockchain}, Contract: ${contract}, Token ID: ${tokenId}, ` + `Keyword: ${keyword}, Hash function ID: ${hashFunctionId}, Operation ID: ${operationId}, ` + - `Retry number: ${COMMAND_RETRIES.SUBMIT_UPDATE_COMMIT - command.retries + 1}`, + `Clossest Node: ${closestNode}, Left neighborhood edge: ${leftNeighborhoodEdge}, ` + + `Right neighborhood edge: ${rightNeighborhoodEdge}, `, + `Retry number: ${COMMAND_RETRIES.SUBMIT_UPDATE_COMMIT - command.retries + 1}`, ); const epoch = await this.calculateCurrentEpoch( @@ -62,7 +67,9 @@ class SubmitUpdateCommitCommand extends Command { `Not submitting update commit as state has been already finalized for the Service Agreement ` + `with the ID: ${agreementId}, Blockchain: ${blockchain}, Contract: ${contract}, ` + `Token ID: ${tokenId}, Keyword: ${keyword}, Hash function ID: ${hashFunctionId}, ` + - `Epoch: ${epoch}, Operation ID: ${operationId}`, + `Clossest Node: ${closestNode}, Left neighborhood edge: ${leftNeighborhoodEdge}, ` + + `Right neighborhood edge: ${rightNeighborhoodEdge}, `, + +`Epoch: ${epoch}, Operation ID: ${operationId}`, ); return Command.empty(); @@ -77,6 +84,9 @@ class SubmitUpdateCommitCommand extends Command { tokenId, keyword, hashFunctionId, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, epoch, (result) => { if (result?.error) { @@ -111,9 +121,11 @@ class SubmitUpdateCommitCommand extends Command { `Failed to execute ${command.name}, Error Message: ${error.message} for the Service Agreement ` + `with the ID: ${agreementId}, Blockchain: ${blockchain}, Contract: ${contract}, ` + `Token ID: ${tokenId}, Keyword: ${keyword}, Hash function ID: ${hashFunctionId}, ` + - `Epoch: ${epoch}, Operation ID: ${operationId}, Retry number: ${ - COMMAND_RETRIES.SUBMIT_UPDATE_COMMIT - command.retries + 1 - }.`, + `Clossest Node: ${closestNode}, Left neighborhood edge: ${leftNeighborhoodEdge}, ` + + `Right neighborhood edge: ${rightNeighborhoodEdge}, `, + +`Epoch: ${epoch}, Operation ID: ${operationId}, Retry number: ${ + COMMAND_RETRIES.SUBMIT_UPDATE_COMMIT - command.retries + 1 + }.`, ); this.operationIdService.emitChangeEvent( OPERATION_ID_STATUS.FAILED, @@ -146,9 +158,11 @@ class SubmitUpdateCommitCommand extends Command { `Successfully executed ${command.name} for the Service Agreement with the ID: ${agreementId}, ` + `Blockchain: ${blockchain}, Contract: ${contract}, Token ID: ${tokenId}, ` + `Keyword: ${keyword}, Hash function ID: ${hashFunctionId}, Epoch: ${epoch}, ` + - `Operation ID: ${operationId}, Retry number: ${ - COMMAND_RETRIES.SUBMIT_UPDATE_COMMIT - command.retries + 1 - }`, + `Clossest Node: ${closestNode}, Left neighborhood edge: ${leftNeighborhoodEdge}, ` + + `Right neighborhood edge: ${rightNeighborhoodEdge}, `, + +`Operation ID: ${operationId}, Retry number: ${ + COMMAND_RETRIES.SUBMIT_UPDATE_COMMIT - command.retries + 1 + }`, ); this.operationIdService.emitChangeEvent( diff --git a/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-init-command.js b/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-init-command.js index ca0c1720ab..d0c814cecb 100644 --- a/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-init-command.js +++ b/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-init-command.js @@ -14,8 +14,16 @@ class HandleUpdateInitCommand extends HandleProtocolMessageCommand { } async prepareMessage(commandData) { - const { operationId, assertionId, blockchain, contract, tokenId, keyword, hashFunctionId } = - commandData; + const { + operationId, + assertionId, + blockchain, + contract, + tokenId, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + } = commandData; await this.operationIdService.updateOperationIdStatus( operationId, blockchain, @@ -39,6 +47,7 @@ class HandleUpdateInitCommand extends HandleProtocolMessageCommand { tokenId, keyword, hashFunctionId, + proximityScoreFunctionsPairId, ); await this.operationIdService.updateOperationIdStatus( diff --git a/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-request-command.js b/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-request-command.js index 3f82ad11df..4a2ab745c1 100644 --- a/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-request-command.js +++ b/src/commands/protocols/update/receiver/v1.0.0/v1-0-0-handle-update-request-command.js @@ -21,6 +21,9 @@ class HandleUpdateRequestCommand extends HandleProtocolMessageCommand { this.tripleStoreService = ctx.tripleStoreService; this.ualService = ctx.ualService; this.pendingStorageService = ctx.pendingStorageService; + this.shardingTableService = ctx.shardingTableService; + this.hashingService = ctx.hashingService; + this.proximityScoringService = ctx.proximityScoringService; this.errorType = ERROR_TYPE.UPDATE.UPDATE_LOCAL_STORE_REMOTE_ERROR; } @@ -34,6 +37,7 @@ class HandleUpdateRequestCommand extends HandleProtocolMessageCommand { agreementId, keyword, hashFunctionId, + proximityScoreFunctionsPairId, agreementData, } = commandData; @@ -66,7 +70,48 @@ class HandleUpdateRequestCommand extends HandleProtocolMessageCommand { const r2 = await this.blockchainModuleManager.getR2(blockchain); const scheduleCommandsPromises = []; - const rank = await this.calculateRank(blockchain, keyword, hashFunctionId, r2); + const neighbourhood = await this.shardingTableService.findNeighbourhood( + blockchain, + keyword, + r2, + hashFunctionId, + proximityScoreFunctionsPairId, + true, + ); + + const closestNode = neighbourhood[0]; + + let neighbourhoodEdges = null; + if (proximityScoreFunctionsPairId === 2) { + neighbourhoodEdges = await this.shardingTableService.getNeighboorhoodEdgeNodes( + neighbourhood, + blockchain, + hashFunctionId, + proximityScoreFunctionsPairId, + keyword, + ); + } + + if (!neighbourhoodEdges && proximityScoreFunctionsPairId === 2) { + throw Error('Unable to find neighbourhood edges for asset'); + } + + const totalNodesNumber = await this.repositoryModuleManager.getPeersCount(blockchain); + const minStake = await this.blockchainModuleManager.getMinimumStake(blockchain); + const maxStake = await this.blockchainModuleManager.getMaximumStake(blockchain); + + const rank = await this.serviceAgreementService.calculateRank( + blockchain, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + r2, + neighbourhood, + neighbourhoodEdges, + totalNodesNumber, + minStake, + maxStake, + ); if (rank != null) { this.logger.trace(`Calculated rank: ${rank + 1} for agreement id: ${agreementId}`); const finalizationCommitsNumber = @@ -91,6 +136,10 @@ class HandleUpdateRequestCommand extends HandleProtocolMessageCommand { r0, r2, updateCommitWindowDuration, + proximityScoreFunctionsPairId, + closestNode: closestNode?.index, + leftNeighborhoodEdge: neighbourhoodEdges?.leftEdge?.index, + rightNeighborhoodEdge: neighbourhoodEdges?.rightEdge?.index, }, transactional: false, }), @@ -148,37 +197,6 @@ class HandleUpdateRequestCommand extends HandleProtocolMessageCommand { return delay; } - async calculateRank(blockchain, keyword, hashFunctionId, r2) { - const neighbourhood = await this.shardingTableService.findNeighbourhood( - blockchain, - keyword, - r2, - hashFunctionId, - true, - ); - - const peerId = this.networkModuleManager.getPeerId().toB58String(); - if (!neighbourhood.some((node) => node.peerId === peerId)) { - return; - } - - const scores = await Promise.all( - neighbourhood.map(async (node) => ({ - score: await this.serviceAgreementService.calculateScore( - node.peerId, - blockchain, - keyword, - hashFunctionId, - ), - peerId: node.peerId, - })), - ); - - scores.sort((a, b) => b.score - a.score); - - return scores.findIndex((node) => node.peerId === peerId); - } - /** * Builds default HandleUpdateRequestCommand * @param map diff --git a/src/constants/constants.js b/src/constants/constants.js index 9afa6ed6b9..c12e3f5482 100644 --- a/src/constants/constants.js +++ b/src/constants/constants.js @@ -8,10 +8,18 @@ export const FALLBACK_PROVIDER_QUORUM = 1; export const RPC_PROVIDER_STALL_TIMEOUT = 60 * 1000; -export const UINT256_MAX_BN = BigNumber.from(2).pow(256).sub(1); +export const UINT256_MAX_BN = ethers.constants.MaxUint256; + +export const UINT128_MAX_BN = BigNumber.from(2).pow(128).sub(1); + +export const UINT64_MAX_BN = BigNumber.from(2).pow(64).sub(1); + +export const UINT40_MAX_BN = BigNumber.from(2).pow(40).sub(1); export const UINT32_MAX_BN = BigNumber.from(2).pow(32).sub(1); +export const HASH_RING_SIZE = ethers.constants.MaxUint256; + export const STAKE_UINT256_MULTIPLIER_BN = UINT256_MAX_BN.div(500000000); export const UINT256_UINT32_DIVISOR_BN = UINT256_MAX_BN.div(UINT32_MAX_BN); @@ -563,10 +571,13 @@ export const CONTRACTS = { STAKING_CONTRACT: 'StakingContract', PROFILE_CONTRACT: 'ProfileContract', HUB_CONTRACT: 'HubContract', + // TODO: Update with new commit Managers COMMIT_MANAGER_V1_U1_CONTRACT: 'CommitManagerV1U1Contract', SERVICE_AGREEMENT_V1_CONTRACT: 'ServiceAgreementV1Contract', PARAMETERS_STORAGE_CONTRACT: 'ParametersStorageContract', IDENTITY_STORAGE_CONTRACT: 'IdentityStorageContract', + Log2PLDSF_CONTRACT: 'Log2PLDSFContract', + LINEAR_SUM_CONTRACT: 'LinearSumContract', }; export const CONTRACT_EVENTS = { @@ -577,6 +588,8 @@ export const CONTRACT_EVENTS = { COMMIT_MANAGER_V1: ['StateFinalized'], SERVICE_AGREEMENT_V1: ['ServiceAgreementV1Extended', 'ServiceAgreementV1Terminated'], PARAMETERS_STORAGE: ['ParameterChanged'], + Log2PLDSF: ['ParameterChanged'], + LINEAR_SUM: ['ParameterChanged'], }; export const NODE_ENVIRONMENTS = { @@ -607,6 +620,7 @@ export const TRANSACTION_CONFIRMATIONS = 1; export const CACHE_DATA_TYPES = { NUMBER: 'number', + ANY: 'any', }; /** @@ -626,8 +640,16 @@ export const CACHED_FUNCTIONS = { commitWindowDurationPerc: CACHE_DATA_TYPES.NUMBER, proofWindowDurationPerc: CACHE_DATA_TYPES.NUMBER, epochLength: CACHE_DATA_TYPES.NUMBER, + minimumStake: CACHE_DATA_TYPES.ANY, + maximumStake: CACHE_DATA_TYPES.ANY, }, IdentityStorageContract: { getIdentityId: CACHE_DATA_TYPES.NUMBER, }, + Log2PLDSFContract: { + getParameters: CACHE_DATA_TYPES.ANY, + }, + LinearSumContract: { + getParameters: CACHE_DATA_TYPES.ANY, + }, }; diff --git a/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js b/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js index 4d711228fa..ce397f483d 100644 --- a/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js +++ b/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js @@ -6,6 +6,7 @@ class BidSuggestionController extends BaseController { this.repositoryModuleManager = ctx.repositoryModuleManager; this.blockchainModuleManager = ctx.blockchainModuleManager; this.shardingTableService = ctx.shardingTableService; + this.serviceAgreementService = ctx.serviceAgreementService; } async handleRequest(req, res) { @@ -49,7 +50,16 @@ class BidSuggestionController extends BaseController { firstAssertionId, hashFunctionId, } = req.query; + let { proximityScoreFunctionsPairId } = req.query; try { + // TODO: ADD-DOCS + if (!proximityScoreFunctionsPairId) { + if (blockchain.startsWith('otp') || blockchain.startsWith('hardhat1')) + proximityScoreFunctionsPairId = 1; + else if (blockchain.startsWith('gnosis') || blockchain.startsWith('hardhat2')) + proximityScoreFunctionsPairId = 2; + } + const bidSuggestion = await this.shardingTableService.getBidSuggestion( blockchain, epochsNumber, @@ -57,6 +67,7 @@ class BidSuggestionController extends BaseController { contentAssetStorageAddress, firstAssertionId, hashFunctionId, + proximityScoreFunctionsPairId, ); this.returnResponse(res, 200, { bidSuggestion }); diff --git a/src/controllers/http-api/v0/publish-http-api-controller-v0.js b/src/controllers/http-api/v0/publish-http-api-controller-v0.js index dd132f8eac..f3de5c7c4b 100644 --- a/src/controllers/http-api/v0/publish-http-api-controller-v0.js +++ b/src/controllers/http-api/v0/publish-http-api-controller-v0.js @@ -14,6 +14,9 @@ class PublishController extends BaseController { this.commandExecutor = ctx.commandExecutor; this.operationIdService = ctx.operationIdService; this.repositoryModuleManager = ctx.repositoryModuleManager; + this.ualService = ctx.ualService; + this.serviceAgreementService = ctx.serviceAgreementService; + this.blockchainModuleManager = ctx.blockchainModuleManager; } async handleRequest(req, res) { diff --git a/src/controllers/http-api/v0/request-schema/bid-suggestion-schema-v0.js b/src/controllers/http-api/v0/request-schema/bid-suggestion-schema-v0.js index f9259aa3ef..715b37ce60 100644 --- a/src/controllers/http-api/v0/request-schema/bid-suggestion-schema-v0.js +++ b/src/controllers/http-api/v0/request-schema/bid-suggestion-schema-v0.js @@ -35,5 +35,10 @@ export default (argumentsObject) => ({ minimum: 1, maximum: 1, }, + proximityScoreFunctionsPairId: { + type: 'number', + minimum: 1, + maximum: 2, + }, }, }); diff --git a/src/controllers/rpc/publish-rpc-controller.js b/src/controllers/rpc/publish-rpc-controller.js index 84010abb3c..c435b58dc8 100644 --- a/src/controllers/rpc/publish-rpc-controller.js +++ b/src/controllers/rpc/publish-rpc-controller.js @@ -54,6 +54,7 @@ class PublishController extends BaseController { tokenId: dataSource.tokenId, keyword: dataSource.keyword, hashFunctionId: message.data.hashFunctionId ?? CONTENT_ASSET_HASH_FUNCTION_ID, + proximityScoreFunctionsPairId: dataSource.proximityScoreFunctionsPairId, }; await this.commandExecutor.add(command); diff --git a/src/controllers/rpc/update-rpc-controller.js b/src/controllers/rpc/update-rpc-controller.js index f9fd8764d5..355723ef42 100644 --- a/src/controllers/rpc/update-rpc-controller.js +++ b/src/controllers/rpc/update-rpc-controller.js @@ -24,7 +24,8 @@ class UpdateController extends BaseController { command.name = handleInitCommand; command.period = 5000; command.retries = 3; - + command.data.proximityScoreFunctionsPairId = + dataSource.proximityScoreFunctionsPairId; break; case NETWORK_MESSAGE_TYPES.REQUESTS.PROTOCOL_REQUEST: // eslint-disable-next-line no-case-declarations @@ -37,6 +38,8 @@ class UpdateController extends BaseController { command.data.keyword = message.data.keyword; command.data.agreementId = dataSource.agreementId; command.data.agreementData = dataSource.agreementData; + command.data.proximityScoreFunctionsPairId = + dataSource.agreementData.scoreFunctionId; break; default: throw Error('unknown message type'); diff --git a/src/migration/migration-executor.js b/src/migration/migration-executor.js index 847a9308cf..5a5559f777 100644 --- a/src/migration/migration-executor.js +++ b/src/migration/migration-executor.js @@ -15,6 +15,7 @@ import ServiceAgreementsInvalidDataMigration from './service-agreements-invalid- import UalExtensionUserConfigurationMigration from './ual-extension-user-configuration-migration.js'; import UalExtensionTripleStoreMigration from './ual-extension-triple-store-migration.js'; import MarkStakingEventsAsProcessedMigration from './mark-staking-events-as-processed-migration.js'; +import RemoveServiceAgreementsForChiadoMigration from './remove-service-agreements-for-chiado-migration.js'; class MigrationExecutor { static async executePullShardingTableMigration(container, logger, config) { @@ -29,7 +30,7 @@ class MigrationExecutor { const validationModuleManager = container.resolve('validationModuleManager'); const migration = new PullBlockchainShardingTableMigration( - 'pullShardingTableMigrationV611', + 'pullShardingTableMigrationV620', logger, config, repositoryModuleManager, @@ -364,6 +365,32 @@ class MigrationExecutor { } } + static async executeRemoveServiceAgreementsForChiadoMigration(container, logger, config) { + if ( + process.env.NODE_ENV === NODE_ENVIRONMENTS.DEVNET || + process.env.NODE_ENV === NODE_ENVIRONMENTS.TESTNET + ) { + const repositoryModuleManager = container.resolve('repositoryModuleManager'); + + const migration = new RemoveServiceAgreementsForChiadoMigration( + 'removeServiceAgreementsForChiadoMigrationV2', + logger, + config, + repositoryModuleManager, + ); + if (!(await migration.migrationAlreadyExecuted())) { + try { + await migration.migrate(); + } catch (error) { + logger.error( + `Unable to execute remove service agreements for Chiado migration. Error: ${error.message}`, + ); + this.exitNode(1); + } + } + } + } + static exitNode(code = 0) { process.exit(code); } diff --git a/src/migration/pull-sharding-table-migration.js b/src/migration/pull-sharding-table-migration.js index 6a02e219fa..6455a88dc2 100644 --- a/src/migration/pull-sharding-table-migration.js +++ b/src/migration/pull-sharding-table-migration.js @@ -7,12 +7,12 @@ class PullBlockchainShardingTableMigration extends BaseMigration { config, repositoryModuleManager, blockchainModuleManager, - validationModuleManager, + hashingService, ) { super(migrationName, logger, config); this.repositoryModuleManager = repositoryModuleManager; this.blockchainModuleManager = blockchainModuleManager; - this.validationModuleManager = validationModuleManager; + this.hashingService = hashingService; } async executeMigration() { @@ -49,6 +49,7 @@ class PullBlockchainShardingTableMigration extends BaseMigration { ...nodes.slice(sliceIndex).filter((node) => node.nodeId !== '0x'), ); sliceIndex = 1; + // TODO: Should we fix it here also startingIdentityId = nodes[nodes.length - 1].identityId; } @@ -64,6 +65,8 @@ class PullBlockchainShardingTableMigration extends BaseMigration { peer.nodeId, ); + const sha256 = await this.hashingService.callHashFunction(1, nodeId); + return { peerId: nodeId, blockchainId, @@ -77,10 +80,7 @@ class PullBlockchainShardingTableMigration extends BaseMigration { peer.stake, 'ether', ), - sha256: await this.validationModuleManager.callHashFunction( - 1, - nodeId, - ), + sha256, }; }), ), diff --git a/src/migration/remove-service-agreements-for-chiado-migration.js b/src/migration/remove-service-agreements-for-chiado-migration.js new file mode 100644 index 0000000000..680931b4f2 --- /dev/null +++ b/src/migration/remove-service-agreements-for-chiado-migration.js @@ -0,0 +1,18 @@ +import BaseMigration from './base-migration.js'; + +const GNOSIS_DEVNET_CHAIN_ID = 'gnosis:10200'; + +class RemoveServiceAgreementsForChiadoMigration extends BaseMigration { + constructor(migrationName, logger, config, repositoryModuleManager) { + super(migrationName, logger, config); + this.repositoryModuleManager = repositoryModuleManager; + } + + async executeMigration() { + await this.repositoryModuleManager.removeServiceAgreementsForBlockchain( + GNOSIS_DEVNET_CHAIN_ID, + ); + } +} + +export default RemoveServiceAgreementsForChiadoMigration; diff --git a/src/modules/blockchain/blockchain-module-manager.js b/src/modules/blockchain/blockchain-module-manager.js index 3cc9055ee2..18995d74d0 100644 --- a/src/modules/blockchain/blockchain-module-manager.js +++ b/src/modules/blockchain/blockchain-module-manager.js @@ -248,6 +248,9 @@ class BlockchainModuleManager extends BaseModuleManager { tokenId, keyword, hashFunctionId, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, epoch, latestStateIndex, callback, @@ -258,6 +261,9 @@ class BlockchainModuleManager extends BaseModuleManager { tokenId, keyword, hashFunctionId, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, epoch, latestStateIndex, callback, @@ -271,6 +277,9 @@ class BlockchainModuleManager extends BaseModuleManager { tokenId, keyword, hashFunctionId, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, epoch, callback, gasPrice, @@ -280,6 +289,9 @@ class BlockchainModuleManager extends BaseModuleManager { tokenId, keyword, hashFunctionId, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, epoch, callback, gasPrice, @@ -330,6 +342,14 @@ class BlockchainModuleManager extends BaseModuleManager { ]); } + async getMinimumStake(blockchain) { + return this.callImplementationFunction(blockchain, 'getMinimumStake'); + } + + async getMaximumStake(blockchain) { + return this.callImplementationFunction(blockchain, 'getMaximumStake'); + } + async getR2(blockchain) { return this.callImplementationFunction(blockchain, 'getR2'); } @@ -395,6 +415,20 @@ class BlockchainModuleManager extends BaseModuleManager { async hasPendingUpdate(blockchain, tokenId) { return this.callImplementationFunction(blockchain, 'hasPendingUpdate', [tokenId]); } + + async getAgreementScoreFunctionId(blockchain, agreementId) { + return this.callImplementationFunction(blockchain, 'getAgreementScoreFunctionId', [ + agreementId, + ]); + } + + convertUint8ArrayToHex(blockchain, uint8Array) { + return this.callImplementationFunction(blockchain, 'convertUint8ArrayToHex', [uint8Array]); + } + + getLinearSumParams(blockchain) { + return this.callImplementationFunction(blockchain, 'getLinearSumParams'); + } } export default BlockchainModuleManager; diff --git a/src/modules/blockchain/implementation/web3-service.js b/src/modules/blockchain/implementation/web3-service.js index 89f74acfa1..e33a0657b8 100644 --- a/src/modules/blockchain/implementation/web3-service.js +++ b/src/modules/blockchain/implementation/web3-service.js @@ -41,18 +41,20 @@ const ABIs = { ProfileStorage: require('dkg-evm-module/abi/ProfileStorage.json'), ScoringProxy: require('dkg-evm-module/abi/ScoringProxy.json'), ServiceAgreementV1: require('dkg-evm-module/abi/ServiceAgreementV1.json'), - CommitManagerV1: require('dkg-evm-module/abi/CommitManagerV1.json'), - CommitManagerV1U1: require('dkg-evm-module/abi/CommitManagerV1U1.json'), + CommitManagerV1: require('dkg-evm-module/abi/CommitManagerV2.json'), + CommitManagerV1U1: require('dkg-evm-module/abi/CommitManagerV2U1.json'), ProofManagerV1: require('dkg-evm-module/abi/ProofManagerV1.json'), ProofManagerV1U1: require('dkg-evm-module/abi/ProofManagerV1U1.json'), - ShardingTable: require('dkg-evm-module/abi/ShardingTable.json'), - ShardingTableStorage: require('dkg-evm-module/abi/ShardingTableStorage.json'), + ShardingTable: require('dkg-evm-module/abi/ShardingTableV2.json'), + ShardingTableStorage: require('dkg-evm-module/abi/ShardingTableStorageV2.json'), ServiceAgreementStorageProxy: require('dkg-evm-module/abi/ServiceAgreementStorageProxy.json'), UnfinalizedStateStorage: require('dkg-evm-module/abi/UnfinalizedStateStorage.json'), + LinearSum: require('dkg-evm-module/abi/LinearSum.json'), }; const SCORING_FUNCTIONS = { 1: 'Log2PLDSF', + 2: 'LinearSum', }; class Web3Service { @@ -480,6 +482,12 @@ class Web3Service { } catch (error) { const decodedErrorData = this._decodeErrorData(error, contractInstance.interface); + if (error.transaction === undefined) { + throw new Error( + `Gas estimation for ${functionName} has failed, reason: ${decodedErrorData}`, + ); + } + const functionFragment = contractInstance.interface.getFunction( error.transaction.data.slice(0, 10), ); @@ -702,9 +710,10 @@ class Web3Service { ) { const contract = this[contractName]; if (!contract) { - throw new Error( - `Error while getting all past events. Unknown contract: ${contractName}`, - ); + // this will happen when we have different set of contracts on different blockchains + // eg LinearSum contract is available on gnosis but not on NeuroWeb, so the node should not fetch events + // from LinearSum contract on NeuroWeb blockchain + return []; } let fromBlock; @@ -927,6 +936,28 @@ class Web3Service { })); } + async getMinimumStake() { + const minimumStake = await this.callContractFunction( + this.ParametersStorageContract, + 'minimumStake', + [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, + ); + + return Number(ethers.utils.formatEther(minimumStake)); + } + + async getMaximumStake() { + const maximumStake = await this.callContractFunction( + this.ParametersStorageContract, + 'maximumStake', + [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, + ); + + return Number(ethers.utils.formatEther(maximumStake)); + } + async getR2() { const r2 = await this.callContractFunction( this.ParametersStorageContract, @@ -972,15 +1003,29 @@ class Web3Service { tokenId, keyword, hashFunctionId, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, epoch, latestStateIndex, callback, gasPrice, ) { + const submitCommitArgs = [assetContractAddress, tokenId, keyword, hashFunctionId, epoch]; + let functionName = 'submitCommit((address,uint256,bytes,uint8,uint16))'; + if ( + closestNode !== undefined && + leftNeighborhoodEdge !== undefined && + rightNeighborhoodEdge !== undefined + ) { + submitCommitArgs.push(closestNode, leftNeighborhoodEdge, rightNeighborhoodEdge); + functionName = + 'submitCommit((address,uint256,bytes,uint8,uint16,uint72,uint72,uint72))'; + } return this.queueTransaction( this.selectCommitManagerContract(latestStateIndex), - 'submitCommit', - [[assetContractAddress, tokenId, keyword, hashFunctionId, epoch]], + functionName, + [submitCommitArgs], callback, gasPrice, ); @@ -991,14 +1036,28 @@ class Web3Service { tokenId, keyword, hashFunctionId, + closestNode, + leftNeighborhoodEdge, + rightNeighborhoodEdge, epoch, callback, gasPrice, ) { + const submitCommitArgs = [assetContractAddress, tokenId, keyword, hashFunctionId, epoch]; + let functionName = 'submitUpdateCommit((address,uint256,bytes,uint8,uint16))'; + if ( + closestNode !== undefined && + leftNeighborhoodEdge !== undefined && + rightNeighborhoodEdge !== undefined + ) { + submitCommitArgs.push(closestNode, leftNeighborhoodEdge, rightNeighborhoodEdge); + functionName = + 'submitUpdateCommit((address,uint256,bytes,uint8,uint16,uint72,uint72,uint72))'; + } return this.queueTransaction( this.CommitManagerV1U1Contract, - 'submitUpdateCommit', - [[assetContractAddress, tokenId, keyword, hashFunctionId, epoch]], + functionName, + [submitCommitArgs], callback, gasPrice, ); @@ -1093,8 +1152,12 @@ class Web3Service { return ethers.utils.solidityPack(types, values); } + convertUint8ArrayToHex(uint8Array) { + return ethers.utils.hexlify(uint8Array); + } + convertAsciiToHex(string) { - return ethers.utils.hexlify(ethers.utils.toUtf8Bytes(string)); + return this.convertUint8ArrayToHex(ethers.utils.toUtf8Bytes(string)); } convertHexToAscii(hexString) { @@ -1179,6 +1242,7 @@ class Web3Service { this.scoringFunctionsContracts[1], 'getParameters', [], + CONTRACTS.Log2PLDSF_CONTRACT, ); const params = {}; @@ -1217,6 +1281,29 @@ class Web3Service { tokenId, ]); } + + async getAgreementScoreFunctionId(agreementId) { + return this.callContractFunction( + this.ServiceAgreementStorageProxyContract, + 'getAgreementScoreFunctionId', + [agreementId], + ); + } + + async getLinearSumParams() { + const linearSumParams = await this.callContractFunction( + this.scoringFunctionsContracts[2], + 'getParameters', + [], + CONTRACTS.LINEAR_SUM_CONTRACT, + ); + return { + distanceScaleFactor: BigNumber.from(linearSumParams[0]), + stakeScaleFactor: BigNumber.from(linearSumParams[1]), + w1: Number(linearSumParams[2]), + w2: Number(linearSumParams[3]), + }; + } } export default Web3Service; diff --git a/src/modules/repository/implementation/sequelize/migrations/20240126120000-shard-add-sha256blobl.js b/src/modules/repository/implementation/sequelize/migrations/20240126120000-shard-add-sha256blobl.js new file mode 100644 index 0000000000..45da4b3837 --- /dev/null +++ b/src/modules/repository/implementation/sequelize/migrations/20240126120000-shard-add-sha256blobl.js @@ -0,0 +1,13 @@ +export async function up({ context: { queryInterface, Sequelize } }) { + const tableInfo = await queryInterface.describeTable('shard'); + + if (!tableInfo.sha256_blob) { + await queryInterface.addColumn('shard', 'sha256_blob', { + type: Sequelize.BLOB, + }); + } +} + +export async function down({ context: { queryInterface } }) { + await queryInterface.removeColumn('shard', 'sha256_blob'); +} diff --git a/src/modules/repository/implementation/sequelize/migrations/20240201100000-remove-sha256Blob.js b/src/modules/repository/implementation/sequelize/migrations/20240201100000-remove-sha256Blob.js new file mode 100644 index 0000000000..25618e1d51 --- /dev/null +++ b/src/modules/repository/implementation/sequelize/migrations/20240201100000-remove-sha256Blob.js @@ -0,0 +1,17 @@ +export async function up({ context: { queryInterface } }) { + const tableInfo = await queryInterface.describeTable('shard'); + + if (tableInfo.sha256_blob) { + await queryInterface.removeColumn('shard', 'sha256_blob'); + } +} + +export async function down({ context: { queryInterface, Sequelize } }) { + const tableInfo = await queryInterface.describeTable('shard'); + + if (!tableInfo.sha256_blob) { + await queryInterface.addColumn('shard', 'sha256_blob', { + type: Sequelize.BLOB, + }); + } +} diff --git a/src/modules/repository/implementation/sequelize/repositories/service-agreement-repository.js b/src/modules/repository/implementation/sequelize/repositories/service-agreement-repository.js index deec201839..1e8124f3cf 100644 --- a/src/modules/repository/implementation/sequelize/repositories/service-agreement-repository.js +++ b/src/modules/repository/implementation/sequelize/repositories/service-agreement-repository.js @@ -21,6 +21,14 @@ class ServiceAgreementRepository { }); } + async removeServiceAgreementsForBlockchain(blockchainId) { + await this.model.destroy({ + where: { + blockchainId, + }, + }); + } + async updateServiceAgreementRecord( blockchainId, assetStorageContractAddress, diff --git a/src/modules/repository/implementation/sequelize/repositories/shard-repository.js b/src/modules/repository/implementation/sequelize/repositories/shard-repository.js index 08dc04df82..2b66f77b84 100644 --- a/src/modules/repository/implementation/sequelize/repositories/shard-repository.js +++ b/src/modules/repository/implementation/sequelize/repositories/shard-repository.js @@ -40,6 +40,8 @@ class ShardRepository { where: { blockchainId, }, + attributes: ['peerId', 'blockchainId', 'ask', 'stake', 'lastSeen', 'sha256'], + order: [['sha256', 'asc']], }; if (filterLastSeen) { diff --git a/src/modules/repository/implementation/sequelize/sequelize-repository.js b/src/modules/repository/implementation/sequelize/sequelize-repository.js index f232c34f8d..aae1f1c648 100644 --- a/src/modules/repository/implementation/sequelize/sequelize-repository.js +++ b/src/modules/repository/implementation/sequelize/sequelize-repository.js @@ -94,7 +94,13 @@ class SequelizeRepository { async runMigrations() { const migrator = createMigrator(this.models.sequelize, this.config, this.logger); - await migrator.up(); + try { + await migrator.up(); + } catch (error) { + this.logger.error(`Failed to execute ${migrator.name} migration: ${error.message}.`); + await migrator.down(); + throw error; + } } async loadModels() { diff --git a/src/modules/repository/repository-module-manager.js b/src/modules/repository/repository-module-manager.js index 0a58b7570a..11e610d824 100644 --- a/src/modules/repository/repository-module-manager.js +++ b/src/modules/repository/repository-module-manager.js @@ -416,6 +416,12 @@ class RepositoryModuleManager extends BaseModuleManager { return this.getRepository('service_agreement').removeServiceAgreements(agreementIds); } + async removeServiceAgreementsForBlockchain(blockchainId) { + return this.getRepository('service_agreement').removeServiceAgreementsForBlockchain( + blockchainId, + ); + } + async updateServiceAgreementEpochsNumber(agreementId, epochsNumber) { return this.getRepository('service_agreement').updateServiceAgreementEpochsNumber( agreementId, diff --git a/src/service/blockchain-event-listener-service.js b/src/service/blockchain-event-listener-service.js index c406e34b91..d49436ae87 100644 --- a/src/service/blockchain-event-listener-service.js +++ b/src/service/blockchain-event-listener-service.js @@ -20,10 +20,10 @@ class BlockchainEventListenerService { this.logger = ctx.logger; this.blockchainModuleManager = ctx.blockchainModuleManager; this.repositoryModuleManager = ctx.repositoryModuleManager; - this.validationModuleManager = ctx.validationModuleManager; this.tripleStoreService = ctx.tripleStoreService; this.pendingStorageService = ctx.pendingStorageService; this.ualService = ctx.ualService; + this.hashingService = ctx.hashingService; } async initialize() { @@ -69,6 +69,7 @@ class BlockchainEventListenerService { currentBlock, CONTRACT_EVENTS.PROFILE, ), + // TODO: Update with new commit managers this.getContractEvents( blockchainId, CONTRACTS.COMMIT_MANAGER_V1_U1_CONTRACT, @@ -87,6 +88,18 @@ class BlockchainEventListenerService { currentBlock, CONTRACT_EVENTS.PARAMETERS_STORAGE, ), + this.getContractEvents( + blockchainId, + CONTRACTS.Log2PLDSF_CONTRACT, + currentBlock, + CONTRACT_EVENTS.Log2PLDSF, + ), + this.getContractEvents( + blockchainId, + CONTRACTS.LINEAR_SUM_CONTRACT, + currentBlock, + CONTRACT_EVENTS.LINEAR_SUM, + ), ]; if (!devEnvironment) { @@ -238,13 +251,40 @@ class BlockchainEventListenerService { async handleParameterChangedEvents(blockEvents) { for (const event of blockEvents) { - const { parameterName, parameterValue } = JSON.parse(event.data); - this.blockchainModuleManager.setContractCallCache( - event.blockchainId, - CONTRACTS.PARAMETERS_STORAGE_CONTRACT, - parameterName, - parameterValue, - ); + const { blockchainId, contract, data } = event; + const { parameterName, parameterValue } = JSON.parse(data); + switch (contract) { + case CONTRACTS.Log2PLDSF_CONTRACT: + // This invalidates contracts parameter + // TODO: Create function for contract call cache invalidation + this.blockchainModuleManager.setContractCallCache( + blockchainId, + CONTRACTS.Log2PLDSF_CONTRACT, + parameterName, + null, + ); + break; + case CONTRACTS.LINEAR_SUM_CONTRACT: + this.blockchainModuleManager.setContractCallCache( + blockchainId, + CONTRACTS.LINEAR_SUM_CONTRACT, + parameterName, + null, + ); + break; + case CONTRACTS.PARAMETERS_STORAGE_CONTRACT: + this.blockchainModuleManager.setContractCallCache( + blockchainId, + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, + parameterName, + parameterValue, + ); + break; + default: + this.logger.warn( + `Unable to handle parameter changed event. Unknown contract name ${event.contract}`, + ); + } } } @@ -306,8 +346,7 @@ class BlockchainEventListenerService { eventData.nodeId, ); - const nodeIdSha256 = await this.validationModuleManager.callHashFunction( - // TODO: How to add more hashes? + const sha256 = await this.hashingService.callHashFunction( CONTENT_ASSET_HASH_FUNCTION_ID, nodeId, ); @@ -325,7 +364,7 @@ class BlockchainEventListenerService { eventData.stake, ), lastSeen: new Date(0), - sha256: nodeIdSha256, + sha256, }; }), ); diff --git a/src/service/hashing-service.js b/src/service/hashing-service.js new file mode 100644 index 0000000000..0a0da3fab5 --- /dev/null +++ b/src/service/hashing-service.js @@ -0,0 +1,31 @@ +import { ethers } from 'ethers'; + +class HashingService { + constructor(ctx) { + this.config = ctx.config; + this.logger = ctx.logger; + + this.hashFunctions = { + 1: 'sha256', + }; + } + + async callHashFunction(hashFunctionId, data) { + const hashFunctionName = this.getHashFunctionName(hashFunctionId); + return this[hashFunctionName](data); + } + + getHashFunctionName(hashFunctionId) { + return this.hashFunctions[hashFunctionId]; + } + + async sha256(data) { + if (!ethers.utils.isBytesLike(data)) { + const bytesLikeData = ethers.utils.toUtf8Bytes(data); + return ethers.utils.sha256(bytesLikeData); + } + return ethers.utils.sha256(data); + } +} + +export default HashingService; diff --git a/src/service/proximity-scoring-service.js b/src/service/proximity-scoring-service.js new file mode 100644 index 0000000000..3dd72c7317 --- /dev/null +++ b/src/service/proximity-scoring-service.js @@ -0,0 +1,198 @@ +import { xor as uint8ArrayXor } from 'uint8arrays/xor'; +import { + HASH_RING_SIZE, + UINT40_MAX_BN, + UINT64_MAX_BN, + UINT256_MAX_BN, +} from '../constants/constants.js'; + +class ProximityScoringService { + constructor(ctx) { + this.config = ctx.config; + this.logger = ctx.logger; + + this.blockchainModuleManager = ctx.blockchainModuleManager; + + this.proximityScoreFunctionsPairs = { + 1: [this.calculateBinaryXOR.bind(this), this.log2PLDSF.bind(this)], + 2: [ + this.calculateBidirectionalProximityOnHashRing.bind(this), + this.linearSum.bind(this), + ], + }; + } + + async callProximityFunction( + blockchain, + proximityFunctionId, + peerHash, + keyHash, + ...additionalArgs + ) { + return this.proximityScoreFunctionsPairs[proximityFunctionId][0]( + blockchain, + peerHash, + keyHash, + ...additionalArgs, + ); + } + + async callScoreFunction(blockchain, scoreFunctionId, distance, stake, ...additionalArgs) { + return this.proximityScoreFunctionsPairs[scoreFunctionId][1]( + blockchain, + distance, + stake, + ...additionalArgs, + ); + } + + async calculateBinaryXOR(blockchain, peerHash, keyHash) { + const distance = uint8ArrayXor( + this.blockchainModuleManager.convertBytesToUint8Array(blockchain, peerHash), + this.blockchainModuleManager.convertBytesToUint8Array(blockchain, keyHash), + ); + + const distanceHex = await this.blockchainModuleManager.convertUint8ArrayToHex( + blockchain, + distance, + ); + + return this.blockchainModuleManager.toBigNumber(blockchain, distanceHex); + } + + async calculateBidirectionalProximityOnHashRing(blockchain, peerHash, keyHash) { + const peerPositionOnHashRing = await this.blockchainModuleManager.toBigNumber( + blockchain, + peerHash, + ); + const keyPositionOnHashRing = await this.blockchainModuleManager.toBigNumber( + blockchain, + keyHash, + ); + + const directDistance = peerPositionOnHashRing.gt(keyPositionOnHashRing) + ? peerPositionOnHashRing.sub(keyPositionOnHashRing) + : keyPositionOnHashRing.sub(peerPositionOnHashRing); + const wraparoundDistance = HASH_RING_SIZE.sub(directDistance); + + return directDistance.lt(wraparoundDistance) ? directDistance : wraparoundDistance; + } + + async log2PLDSF(blockchain, distance, stake) { + const log2PLDSFParams = await this.blockchainModuleManager.getLog2PLDSFParams(blockchain); + + const { + distanceMappingCoefficient, + stakeMappingCoefficient, + multiplier, + logArgumentConstant, + a, + stakeExponent, + b, + c, + distanceExponent, + d, + } = log2PLDSFParams; + + const mappedStake = this.blockchainModuleManager + .toBigNumber(blockchain, this.blockchainModuleManager.convertToWei(blockchain, stake)) + .div(stakeMappingCoefficient); + + const mappedDistance = distance.div(distanceMappingCoefficient); + + const dividend = mappedStake.pow(stakeExponent).mul(a).add(b); + const divisor = mappedDistance.pow(distanceExponent).mul(c).add(d); + + return Math.floor( + Number(multiplier) * + Math.log2(Number(logArgumentConstant) + dividend.toNumber() / divisor.toNumber()), + ); + } + + async linearSum( + blockchain, + distance, + stake, + maxNeighborhoodDistance, + r2, + nodesNumber, + minStake, + maxStake, + ) { + const linearSumParams = await this.blockchainModuleManager.getLinearSumParams(blockchain); + const { distanceScaleFactor, stakeScaleFactor, w1, w2 } = linearSumParams; + const mappedStake = this.blockchainModuleManager.toBigNumber( + blockchain, + this.blockchainModuleManager.convertToWei(blockchain, stake), + ); + const mappedMinStake = this.blockchainModuleManager.toBigNumber( + blockchain, + this.blockchainModuleManager.convertToWei(blockchain, minStake), + ); + const mappedMaxStake = this.blockchainModuleManager.toBigNumber( + blockchain, + this.blockchainModuleManager.convertToWei(blockchain, maxStake), + ); + + const idealMaxDistanceInNeighborhood = HASH_RING_SIZE.div(nodesNumber).mul( + Math.ceil(r2 / 2), + ); + const divisor = maxNeighborhoodDistance.lte(idealMaxDistanceInNeighborhood) + ? maxNeighborhoodDistance + : idealMaxDistanceInNeighborhood; + + const maxMultiplier = UINT256_MAX_BN.div(distance); + + let scaledDistanceScaleFactor = distanceScaleFactor; + let compensationFactor = 1; + + if (scaledDistanceScaleFactor.gt(maxMultiplier)) { + compensationFactor = scaledDistanceScaleFactor.div(maxMultiplier); + scaledDistanceScaleFactor = maxMultiplier; + } + + const scaledDistance = distance.mul(scaledDistanceScaleFactor); + const adjustedDivisor = divisor.div(compensationFactor); + + let normalizedDistance = scaledDistance.div(adjustedDivisor); + if (normalizedDistance.gt(UINT64_MAX_BN)) { + normalizedDistance = normalizedDistance.mod(UINT64_MAX_BN.add(1)); + } + + let normalizedStake = stakeScaleFactor + .mul(mappedStake.sub(mappedMinStake)) + .div(mappedMaxStake.sub(mappedMinStake)); + if (normalizedStake.gt(UINT64_MAX_BN)) { + normalizedStake = normalizedStake.mod(UINT64_MAX_BN.add(1)); + } + + const oneEther = await this.blockchainModuleManager.toBigNumber( + blockchain, + '1000000000000000000', + ); + + const isProximityScorePositive = oneEther.gte(normalizedDistance); + + const proximityScore = isProximityScorePositive + ? oneEther.sub(normalizedDistance).mul(w1) + : normalizedDistance.sub(oneEther).mul(w1); + const stakeScore = normalizedStake.mul(w2); + + let finalScore; + if (isProximityScorePositive) { + finalScore = proximityScore.add(stakeScore); + } else if (stakeScore.gte(proximityScore)) { + finalScore = stakeScore.sub(proximityScore); + } else { + finalScore = await this.blockchainModuleManager.toBigNumber(blockchain, 0); + } + + if (finalScore.gt(UINT40_MAX_BN)) { + finalScore = finalScore.mod(UINT40_MAX_BN.add(1)); + } + + return finalScore.toNumber(); + } +} + +export default ProximityScoringService; diff --git a/src/service/service-agreement-service.js b/src/service/service-agreement-service.js index d1f0f17ca1..de4ecd9076 100644 --- a/src/service/service-agreement-service.js +++ b/src/service/service-agreement-service.js @@ -2,15 +2,16 @@ class ServiceAgreementService { constructor(ctx) { this.logger = ctx.logger; - this.validationModuleManager = ctx.validationModuleManager; this.blockchainModuleManager = ctx.blockchainModuleManager; this.repositoryModuleManager = ctx.repositoryModuleManager; this.shardingTableService = ctx.shardingTableService; this.networkModuleManager = ctx.networkModuleManager; + this.hashingService = ctx.hashingService; + this.proximityScoringService = ctx.proximityScoringService; } async generateId(blockchain, assetTypeContract, tokenId, keyword, hashFunctionId) { - return this.validationModuleManager.callHashFunction( + return this.hashingService.callHashFunction( hashFunctionId, this.blockchainModuleManager.encodePacked( blockchain, @@ -24,60 +25,89 @@ class ServiceAgreementService { return Math.floor(Math.random() * (max - min + 1) + min); } - async calculateScore(peerId, blockchainId, keyword, hashFunctionId) { - const peerRecord = await this.repositoryModuleManager.getPeerRecord(peerId, blockchainId); - const keyHash = await this.validationModuleManager.callHashFunction( - hashFunctionId, - keyword, + async calculateRank( + blockchain, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + r2, + neighbourhood, + neighbourhoodEdges, + totalNodesNumber, + minStake, + maxStake, + ) { + const peerId = this.networkModuleManager.getPeerId().toB58String(); + if (!neighbourhood.some((node) => node.peerId === peerId)) { + return; + } + + const scores = await Promise.all( + neighbourhood.map(async (node) => ({ + score: await this.calculateScore( + node.peerId, + blockchain, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + neighbourhoodEdges, + r2, + totalNodesNumber, + minStake, + maxStake, + ), + peerId: node.peerId, + })), ); - const hashFunctionName = this.validationModuleManager.getHashFunctionName(hashFunctionId); + scores.sort((a, b) => b.score - a.score); + + return scores.findIndex((node) => node.peerId === peerId); + } + + async calculateScore( + peerId, + blockchainId, + keyword, + hashFunctionId, + proximityScoreFunctionsPairId, + neighbourhoodEdges, + r2, + totalNodesNumber, + minStake, + maxStake, + ) { + const peerRecord = await this.repositoryModuleManager.getPeerRecord(peerId, blockchainId); + const keyHash = await this.hashingService.callHashFunction(hashFunctionId, keyword); + + const hashFunctionName = this.hashingService.getHashFunctionName(hashFunctionId); - const distanceUint8Array = this.shardingTableService.calculateDistance( + const distance = await this.proximityScoringService.callProximityFunction( blockchainId, + proximityScoreFunctionsPairId, peerRecord[hashFunctionName], keyHash, ); - - // todo: store this in a more appropriate way - if (!this.log2PLDSFParams) { - this.log2PLDSFParams = await this.blockchainModuleManager.getLog2PLDSFParams( + let maxNeighborhoodDistance; + if (neighbourhoodEdges) { + maxNeighborhoodDistance = await this.proximityScoringService.callProximityFunction( blockchainId, + proximityScoreFunctionsPairId, + neighbourhoodEdges.leftEdge[hashFunctionName], + neighbourhoodEdges.rightEdge[hashFunctionName], ); } - const { - distanceMappingCoefficient, - stakeMappingCoefficient, - multiplier, - logArgumentConstant, - a, - stakeExponent, - b, - c, - distanceExponent, - d, - } = this.log2PLDSFParams; - - const distanceUint256BN = this.blockchainModuleManager.toBigNumber( + return this.proximityScoringService.callScoreFunction( blockchainId, - distanceUint8Array, - ); - - const mappedStake = this.blockchainModuleManager - .toBigNumber( - blockchainId, - this.blockchainModuleManager.convertToWei(blockchainId, peerRecord.stake), - ) - .div(stakeMappingCoefficient); - const mappedDistance = distanceUint256BN.div(distanceMappingCoefficient); - - const dividend = mappedStake.pow(stakeExponent).mul(a).add(b); - const divisor = mappedDistance.pow(distanceExponent).mul(c).add(d); - - return Math.floor( - Number(multiplier) * - Math.log2(Number(logArgumentConstant) + dividend.toNumber() / divisor.toNumber()), + proximityScoreFunctionsPairId, + distance, + peerRecord.stake, + maxNeighborhoodDistance, + r2, + totalNodesNumber, + minStake, + maxStake, ); } } diff --git a/src/service/sharding-table-service.js b/src/service/sharding-table-service.js index 87688c0a42..4a5a3ff8cf 100644 --- a/src/service/sharding-table-service.js +++ b/src/service/sharding-table-service.js @@ -1,6 +1,3 @@ -import { xor as uint8ArrayXor } from 'uint8arrays/xor'; -import { compare as uint8ArrayCompare } from 'uint8arrays/compare'; - import { BYTES_IN_KILOBYTE, CONTRACTS, @@ -14,7 +11,8 @@ class ShardingTableService { this.blockchainModuleManager = ctx.blockchainModuleManager; this.repositoryModuleManager = ctx.repositoryModuleManager; this.networkModuleManager = ctx.networkModuleManager; - this.validationModuleManager = ctx.validationModuleManager; + this.hashingService = ctx.hashingService; + this.proximityScoringService = ctx.proximityScoringService; this.memoryCachedPeerIds = {}; } @@ -93,6 +91,7 @@ class ShardingTableService { blockchainId, peer.nodeId, ); + const sha256 = await this.hashingService.callHashFunction(1, nodeId); return { peerId: nodeId, @@ -107,41 +106,70 @@ class ShardingTableService { peer.stake, 'ether', ), - sha256: await this.validationModuleManager.callHashFunction(1, nodeId), + sha256, }; }), ), ); } - async findNeighbourhood(blockchainId, key, r2, hashFunctionId, filterLastSeen) { - const peers = await this.repositoryModuleManager.getAllPeerRecords( + async findNeighbourhood( + blockchainId, + key, + r2, + hashFunctionId, + proximityScoreFunctionsPairId, + filterLastSeen, + ) { + let peers = await this.repositoryModuleManager.getAllPeerRecords( blockchainId, filterLastSeen, ); - const keyHash = await this.validationModuleManager.callHashFunction(hashFunctionId, key); + peers = peers.map((peer, index) => ({ ...peer.dataValues, index })); + const keyHash = await this.hashingService.callHashFunction(hashFunctionId, key); - return this.sortPeers(blockchainId, keyHash, peers, r2, hashFunctionId); + const soretedPeers = this.sortPeers( + blockchainId, + keyHash, + peers, + r2, + hashFunctionId, + proximityScoreFunctionsPairId, + ); + return soretedPeers; } - async sortPeers(blockchainId, keyHash, peers, count, hashFunctionId) { - const hashFunctionName = this.validationModuleManager.getHashFunctionName(hashFunctionId); - - return peers - .map((peer) => ({ + async sortPeers( + blockchainId, + keyHash, + peers, + count, + hashFunctionId, + proximityScoreFunctionsPairId, + ) { + const hashFunctionName = this.hashingService.getHashFunctionName(hashFunctionId); + const peersWithDistance = await Promise.all( + peers.map(async (peer) => ({ peer, - distance: this.calculateDistance(blockchainId, keyHash, peer[hashFunctionName]), - })) - .sort((a, b) => uint8ArrayCompare(a.distance, b.distance)) - .slice(0, count) - .map((pd) => pd.peer); - } - - calculateDistance(blockchain, peerHash, keyHash) { - return uint8ArrayXor( - this.blockchainModuleManager.convertBytesToUint8Array(blockchain, peerHash), - this.blockchainModuleManager.convertBytesToUint8Array(blockchain, keyHash), + distance: await this.proximityScoringService.callProximityFunction( + blockchainId, + proximityScoreFunctionsPairId, + peer[hashFunctionName], + keyHash, + ), + })), ); + peersWithDistance.sort((a, b) => { + if (a.distance.lt(b.distance)) { + return -1; + } + if (a.distance.gt(b.distance)) { + return 1; + } + return 0; + }); + const result = peersWithDistance.slice(0, count).map((pd) => pd.peer); + return result; } async getBidSuggestion( @@ -151,6 +179,7 @@ class ShardingTableService { contentAssetStorageAddress, firstAssertionId, hashFunctionId, + proximityScoreFunctionsPairId, ) { const kbSize = assertionSize < BYTES_IN_KILOBYTE ? BYTES_IN_KILOBYTE : assertionSize; const peerRecords = await this.findNeighbourhood( @@ -162,6 +191,7 @@ class ShardingTableService { ), await this.blockchainModuleManager.getR2(blockchainId), hashFunctionId, + proximityScoreFunctionsPairId, true, ); const r1 = await this.blockchainModuleManager.getR1(blockchainId); @@ -278,6 +308,56 @@ class ShardingTableService { protocols: peerInfo?.protocols ?? [], }; } + + async getNeighboorhoodEdgeNodes( + neighbourhood, + blockchainId, + hashFunctionId, + proximityScoreFunctionsPairId, + key, + ) { + const keyHash = await this.hashingService.callHashFunction(hashFunctionId, key); + + const hashFunctionName = this.hashingService.getHashFunctionName(hashFunctionId); + const assetPositionOnHashRing = await this.blockchainModuleManager.toBigNumber( + blockchainId, + keyHash, + ); + const hashRing = []; + + const maxDistance = await this.proximityScoringService.callProximityFunction( + blockchainId, + proximityScoreFunctionsPairId, + neighbourhood[neighbourhood.length - 1][hashFunctionName], + keyHash, + ); + + for (const neighbour of neighbourhood) { + // eslint-disable-next-line no-await-in-loop + const neighbourPositionOnHashRing = await this.blockchainModuleManager.toBigNumber( + blockchainId, + neighbour[hashFunctionName], + ); + if (assetPositionOnHashRing.lte(neighbourPositionOnHashRing)) { + if (neighbourPositionOnHashRing.sub(assetPositionOnHashRing).lte(maxDistance)) { + hashRing.push(neighbour); + } else { + hashRing.unshift(neighbour); + } + } else if (assetPositionOnHashRing.gt(neighbourPositionOnHashRing)) { + if (assetPositionOnHashRing.sub(neighbourPositionOnHashRing).lte(maxDistance)) { + hashRing.unshift(neighbour); + } else { + hashRing.push(neighbour); + } + } + } + + return { + leftEdge: hashRing[0], + rightEdge: hashRing[hashRing.length - 1], + }; + } } export default ShardingTableService; diff --git a/test/bdd/features/bid-suggestion.feature b/test/bdd/features/bid-suggestion.feature new file mode 100644 index 0000000000..544ec47240 --- /dev/null +++ b/test/bdd/features/bid-suggestion.feature @@ -0,0 +1,37 @@ +Feature: Release related tests + Background: Setup local blockchain, bootstraps and nodes + Given the blockchains are set up + And 1 bootstrap is running + + @release + Scenario: Get bid suggestion with a valid assertion and valid hashFunctionId and scoreFunctionId on both blockchains + Given I set R0 to be 1 on blockchain hardhat1:31337 + And I set R1 to be 2 on blockchain hardhat1:31337 + And I set R0 to be 1 on blockchain hardhat2:31337 + And I set R1 to be 2 on blockchain hardhat2:31337 + And I setup 4 nodes + And I wait for 5 seconds + + When I call Get Bid Suggestion on the node 2 with validPublish_1ForValidUpdate_1 on blockchain hardhat1:31337 + Then I call Info route on the node 2 + + When I call Get Bid Suggestion on the node 2 with validPublish_1ForValidUpdate_1 on blockchain hardhat2:31337 + Then I call Info route on the node 2 + + When I call Get Bid Suggestion on node 2 using parameters validPublish_1ForValidUpdate_1, hashFunctionId 1, scoreFunctionId 1, within blockchain hardhat1:31337 + Then I call Info route on the node 2 + + When I call Get Bid Suggestion on node 2 using parameters validPublish_1ForValidUpdate_1, hashFunctionId 1, scoreFunctionId 1, within blockchain hardhat2:31337 + Then I call Info route on the node 2 + + When I call Get Bid Suggestion on node 2 using parameters validPublish_1ForValidUpdate_1, hashFunctionId 1, scoreFunctionId 2, within blockchain hardhat1:31337 + Then I call Info route on the node 2 + + When I call Get Bid Suggestion on node 2 using parameters validPublish_1ForValidUpdate_1, hashFunctionId 1, scoreFunctionId 2, within blockchain hardhat2:31337 + Then I call Info route on the node 2 + + When I call Get Bid Suggestion on node 2 using parameters validPublish_1ForValidUpdate_1, hashFunctionId 1, scoreFunctionId 4, within blockchain hardhat1:31337 + Then I call Info route on the node 2 + + When I call Get Bid Suggestion on node 2 using parameters validPublish_1ForValidUpdate_1, hashFunctionId 1, scoreFunctionId 4, within blockchain hardhat2:31337 + Then I call Info route on the node 2 diff --git a/test/bdd/steps/api/bid-suggestion.mjs b/test/bdd/steps/api/bid-suggestion.mjs new file mode 100644 index 0000000000..72d27845e5 --- /dev/null +++ b/test/bdd/steps/api/bid-suggestion.mjs @@ -0,0 +1,125 @@ +import { When } from '@cucumber/cucumber'; +import { expect, assert } from 'chai'; +import { readFile } from 'fs/promises'; + +const assertions = JSON.parse(await readFile('test/bdd/steps/api/datasets/assertions.json')); + +When( + /^I call Get Bid Suggestion on node (\d+) using parameters ([^"]*), hashFunctionId (\d+), scoreFunctionId (\d+), within blockchain ([^"]*)/, + { timeout: 300000 }, + async function getBidSuggestionWithHashAndScore( + node, + assertionName, + hashFunctionId, + scoreFunctionId, + blockchain, + ) { + this.logger.log( + `I call get bid suggestion route on the node ${node} on blockchain ${blockchain} with hashFunctionId ${hashFunctionId} and scoreFunctionId ${scoreFunctionId}`, + ); + + expect( + !!this.state.localBlockchains[blockchain], + `Blockchain with name ${blockchain} not found`, + ).to.be.equal(true); + + expect( + !!assertions[assertionName], + `Assertion with name: ${assertionName} not found!`, + ).to.be.equal(true); + + expect( + Number.isInteger(hashFunctionId), + `hashFunctionId value: ${hashFunctionId} is not an integer!`, + ).to.be.equal(true); + + expect( + Number.isInteger(scoreFunctionId), + `scoreFunctionId value: ${scoreFunctionId} is not an integer!`, + ).to.be.equal(true); + + const assertion = assertions[assertionName]; + const publicAssertionId = await this.state.nodes[node - 1].client + .getPublicAssertionId(assertion) + .catch((error) => { + assert.fail(`Error while trying to get public assertion id. ${error}`); + }); + + const sizeInBytes = await this.state.nodes[node - 1].client + .getSizeInBytes(assertion) + .catch((error) => { + assert.fail(`Error while trying to get size in bytes. ${error}`); + }); + + const options = { + ...this.state.nodes[node - 1].clientBlockchainOptions[blockchain], + hashFunctionId: hashFunctionId, + scoreFunctionId: scoreFunctionId, + }; + let getBidSuggestionError; + const result = await this.state.nodes[node - 1].client + .getBidSuggestion(publicAssertionId, sizeInBytes, options) + .catch((error) => { + getBidSuggestionError = error; + assert.fail(`Error while trying to get bid suggestion. ${error}`); + }); + this.state.latestBidSuggestionResult = { + nodeId: node - 1, + publicAssertionId, + sizeInBytes, + assertion: assertions[assertionName], + result, + getBidSuggestionError, + }; + }, +); + +When( + /^I call Get Bid Suggestion on the node (\d+) with ([^"]*) on blockchain ([^"]*)/, + { timeout: 300000 }, + async function getBidSuggestion(node, assertionName, blockchain) { + this.logger.log( + `I call get bid suggestion route on the node ${node} on blockchain ${blockchain}`, + ); + + expect( + !!this.state.localBlockchains[blockchain], + `Blockchain with name ${blockchain} not found`, + ).to.be.equal(true); + + expect( + !!assertions[assertionName], + `Assertion with name: ${assertionName} not found!`, + ).to.be.equal(true); + + const assertion = assertions[assertionName]; + const publicAssertionId = await this.state.nodes[node - 1].client + .getPublicAssertionId(assertion) + .catch((error) => { + assert.fail(`Error while trying to get public assertion id. ${error}`); + }); + + const sizeInBytes = await this.state.nodes[node - 1].client + .getSizeInBytes(assertion) + .catch((error) => { + assert.fail(`Error while trying to get size in bytes. ${error}`); + }); + + const options = this.state.nodes[node - 1].clientBlockchainOptions[blockchain]; + let getBidSuggestionError; + const result = await this.state.nodes[node - 1].client + .getBidSuggestion(publicAssertionId, sizeInBytes, options) + .catch((error) => { + getBidSuggestionError = error; + assert.fail(`Error while trying to get bid suggestion. ${error}`); + }); + this.state.latestBidSuggestionResult = { + nodeId: node - 1, + publicAssertionId, + sizeInBytes, + assertion: assertions[assertionName], + result, + getBidSuggestionError, + }; + }, +); diff --git a/test/bdd/steps/api/datasets/requests.json b/test/bdd/steps/api/datasets/requests.json index ac5eefe732..d0ca535d19 100644 --- a/test/bdd/steps/api/datasets/requests.json +++ b/test/bdd/steps/api/datasets/requests.json @@ -9,26 +9,26 @@ "_:c14n0 ." ], "blockchain": "hardhat1:31337", - "contract": "0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07", + "contract": "0x0aec7c174554af8aec3680bb58431f6618311510", "tokenId": 0 }, "validGetFirstStateRequestBody": { - "id": "did:dkg:blockchain/0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07/0", + "id": "did:dkg:blockchain/0x0aec7c174554af8aec3680bb58431f6618311510/0", "state": "0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf" }, "validGetUpdatedStateRequestBody": { - "id": "did:dkg:blockchain/0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07/0" + "id": "did:dkg:blockchain/0x0aec7c174554af8aec3680bb58431f6618311510/0" }, "getFirstStateRequestBody": { - "id": "did:dkg:blockchain/0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07/0", + "id": "did:dkg:blockchain/0x0aec7c174554af8aec3680bb58431f6618311510/0", "state": "0xe3a6733d7b999ca6f0d141afe3e38ac59223a4dfde7a5458932d2094ed4193cf" }, "getSecondStateRequestBody": { - "id": "did:dkg:blockchain/0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07/0", + "id": "did:dkg:blockchain/0x0aec7c174554af8aec3680bb58431f6618311510/0", "state": "0x591503a1c8ba4667dd7afd203025c1bf594d817d8eec71274fe960d69fb8584f" }, "getThirdStateRequestBody": { - "id": "did:dkg:blockchain/0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07/0", + "id": "did:dkg:blockchain/0x0aec7c174554af8aec3680bb58431f6618311510/0", "state": "0x759c285786b95622dad67a6be857a4eec3d9ba0caec991ed4297629ae6abbc0d" }, "blockchainNotDefinedRequestBody": { @@ -42,21 +42,21 @@ "_:c14n0 ." ], "blockchain": null, - "contract": "0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07", + "contract": "0x0aec7c174554af8aec3680bb58431f6618311510", "tokenId": 0 }, "nonExistentUAL": { - "id": "did:dkg:hardhat1:31337/0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07/1" + "id": "did:dkg:hardhat1:31337/0x0aec7c174554af8aec3680bb58431f6618311510/1" }, "invalidUAL": { "id": "did:dkg:hardhat1:31337/0xB0D4afd8879eD9F/52b28595d31B441D079B2Ca07/1" }, "nonExistentState": { - "id": "did:dkg:hardhat1:31337/0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07/0", + "id": "did:dkg:hardhat1:31337/0x0aec7c174554af8aec3680bb58431f6618311510/0", "state": -1 }, "invalidStateHash": { - "id": "did:dkg:hardhat1:31337/0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07/0", + "id": "did:dkg:hardhat1:31337/0x0aec7c174554af8aec3680bb58431f6618311510/0", "state": "0x591503a1c8ba4667dd7afd203025c1bf594d817d8eec71274fe960d69fb8584e" }, "validUpdateRequestBody": { @@ -67,7 +67,7 @@ " ." ], "blockchain": "hardhat1:31337", - "contract": "0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07", + "contract": "0x0aec7c174554af8aec3680bb58431f6618311510", "tokenId": 0 } } diff --git a/test/bdd/steps/api/get.mjs b/test/bdd/steps/api/get.mjs index 7b49dfd543..0331785678 100644 --- a/test/bdd/steps/api/get.mjs +++ b/test/bdd/steps/api/get.mjs @@ -105,3 +105,44 @@ When('I wait for latest Get to finalize', { timeout: 80000 }, async function get await setTimeout(4000); } }); + +When( + /^I call Get directly on the node (\d+) with ([^"]*) on blockchain ([^"]*) with hashFunctionId (\d+)/, + { timeout: 30000 }, + async function getFromNode(node, requestName, blockchain, hashFunctionId) { + this.logger.log(`I call get directly on the node ${node} on blockchain ${blockchain}`); + + expect( + !!this.state.localBlockchains[blockchain], + `Blockchain with name ${blockchain} not found`, + ).to.be.equal(true); + + expect( + !!requests[requestName], + `Request body with name: ${requestName} not found!`, + ).to.be.equal(true); + + expect( + !Number.isInteger(hashFunctionId), + `hashFunctionId value: ${hashFunctionId} is not an integer!`, + ).to.be.equal(true); + + const requestBody = JSON.parse(JSON.stringify(requests[requestName])); + requestBody.id = requestBody.id.replace('blockchain', blockchain); + requestBody.hashFunctionId = hashFunctionId; + + try { + const result = await httpApiHelper.get( + this.state.nodes[node - 1].nodeRpcUrl, + requestBody, + ); + const { operationId } = result.data; + this.state.latestGetData = { + nodeId: node - 1, + operationId, + }; + } catch (error) { + this.state.latestError = error; + } + }, +); diff --git a/test/bdd/steps/api/publish.mjs b/test/bdd/steps/api/publish.mjs index 18b6bf3bb3..8e46ab9a48 100644 --- a/test/bdd/steps/api/publish.mjs +++ b/test/bdd/steps/api/publish.mjs @@ -124,3 +124,54 @@ When( ); }, ); + +When( + /^I call Publish on the node (\d+) with ([^"]*) on blockchain ([^"]*) with hashFunctionId (\d+) and scoreFunctionId (\d+)/, + { timeout: 120000 }, + async function publish(node, assertionName, blockchain, hashFunctionId, scoreFunctionId) { + this.logger.log(`I call publish route on the node ${node} on blockchain ${blockchain}`); + + expect( + !!this.state.localBlockchains[blockchain], + `Blockchain with name ${blockchain} not found`, + ).to.be.equal(true); + + expect( + !!assertions[assertionName], + `Assertion with name: ${assertionName} not found!`, + ).to.be.equal(true); + + expect( + !Number.isInteger(hashFunctionId), + `hashFunctionId value: ${hashFunctionId} is not an integer!`, + ).to.be.equal(true); + + expect( + !Number.isInteger(scoreFunctionId), + `scoreFunctionId value: ${scoreFunctionId} not an integer!`, + ).to.be.equal(true); + + const assertion = assertions[assertionName]; + const options = { + blockchain: this.state.nodes[node - 1].clientBlockchainOptions[blockchain], + hashFunctionId, + scoreFunctionId, + }; + const result = await this.state.nodes[node - 1].client + .publish(assertion, options) + .catch((error) => { + assert.fail(`Error while trying to publish assertion. ${error}`); + }); + const { operationId } = result.operation; + this.state.latestPublishData = { + nodeId: node - 1, + UAL: result.UAL, + assertionId: result.assertionId, + operationId, + assertion: assertions[assertionName], + status: result.operation.status, + errorType: result.operation.errorType, + result, + }; + }, +); diff --git a/test/bdd/steps/api/update.mjs b/test/bdd/steps/api/update.mjs index 4740083d75..d1eca6a678 100644 --- a/test/bdd/steps/api/update.mjs +++ b/test/bdd/steps/api/update.mjs @@ -102,3 +102,55 @@ When('I wait for latest Update to finalize', { timeout: 80000 }, async function await setTimeout(4000); } }); + +When( + /^I call Update on the node (\d+) for the latest published UAL with ([^"]*) on blockchain ([^"]*) with hashFunctionId (\d+) and scoreFunctionId (\d+)/, + { timeout: 120000 }, + async function update(node, assertionName, blockchain, hashFunctionId, scoreFunctionId) { + this.logger.log(`I call update route on the node ${node} on blockchain ${blockchain}`); + + expect( + !!this.state.localBlockchains[blockchain], + `Blockchain with name ${blockchain} not found`, + ).to.be.equal(true); + + expect( + !!assertions[assertionName], + `Assertion with name: ${assertionName} not found!`, + ).to.be.equal(true); + + expect( + !Number.isInteger(hashFunctionId), + `hashFunctionId value: ${hashFunctionId} is not an integer!`, + ).to.be.equal(true); + + expect( + !Number.isInteger(scoreFunctionId), + `scoreFunctionId value: ${scoreFunctionId} is not an integer!`, + ).to.be.equal(true); + + const assertion = assertions[assertionName]; + const { UAL } = this.state.latestPublishData; + const options = { + blockchain: this.state.nodes[node - 1].clientBlockchainOptions[blockchain], + hashFunctionId, + scoreFunctionId, + }; + const result = await this.state.nodes[node - 1].client + .update(UAL, assertion, options) + .catch((error) => { + assert.fail(`Error while trying to update assertion. ${error}`); + }); + const { operationId } = result.operation; + this.state.latestUpdateData = { + nodeId: node - 1, + UAL, + assertionId: result.assertionId, + operationId, + assertion: assertions[assertionName], + status: result.operation.status, + errorType: result.operation.errorType, + result, + }; + }, +); diff --git a/test/bdd/steps/lib/local-blockchain.mjs b/test/bdd/steps/lib/local-blockchain.mjs index 19410f9504..b686cec378 100644 --- a/test/bdd/steps/lib/local-blockchain.mjs +++ b/test/bdd/steps/lib/local-blockchain.mjs @@ -22,6 +22,9 @@ const testParametersStorageParams = { proofWindowDurationPerc: 33, // 2 minutes updateCommitWindowDuration: 60, // 1 minute finalizationCommitsNumber: 3, + r0: 3, + r1: 5, + r2: 6, }; /** * LocalBlockchain represent small wrapper around the Ganache. diff --git a/test/utilities/dkg-client-helper.mjs b/test/utilities/dkg-client-helper.mjs index 6b41114a0a..2e216a3dd6 100644 --- a/test/utilities/dkg-client-helper.mjs +++ b/test/utilities/dkg-client-helper.mjs @@ -46,6 +46,24 @@ class DkgClientHelper { async query(query) { return this.client.query(query); } + + async getBidSuggestion(publicAssertionId, sizeInBytes, userOptions = {}) { + const defaultOptions = { + epochsNum: 2, + }; + + const options = { ...defaultOptions, ...userOptions }; + + return this.client.network.getBidSuggestion(publicAssertionId, sizeInBytes, options); + } + + async getPublicAssertionId(content) { + return this.client.assertion.getPublicAssertionId(content); + } + + async getSizeInBytes(content) { + return this.client.assertion.getSizeInBytes(content); + } } export default DkgClientHelper; diff --git a/tools/knowledge-assets-distribution-simulation/mocks/blockchain-module-manager-mock.js b/tools/knowledge-assets-distribution-simulation/mocks/blockchain-module-manager-mock.js new file mode 100644 index 0000000000..5651dddee7 --- /dev/null +++ b/tools/knowledge-assets-distribution-simulation/mocks/blockchain-module-manager-mock.js @@ -0,0 +1,57 @@ +import { ethers } from 'ethers'; + +class BlockchainModuleManagerMock { + convertBytesToUint8Array(blockchain, bytesLikeData) { + return ethers.utils.arrayify(bytesLikeData); + } + + convertUint8ArrayToHex(blockchain, uint8Array) { + return ethers.utils.hexlify(uint8Array); + } + + convertFromWei(value, toUnit = 'ether') { + return ethers.utils.formatUnits(value, toUnit); + } + + convertToWei(blockchain, value, fromUnit = 'ether') { + return ethers.utils.parseUnits(value.toString(), fromUnit).toString(); + } + + toBigNumber(blockchain, value) { + return ethers.BigNumber.from(value); + } + + getMinimumStake(blockchain) { + return 50000; + } + + getMaximumStake(blockchain) { + return 1000000; + } + + getLog2PLDSFParams(blockchain) { + return { + distanceMappingCoefficient: + '115792089237316195423570985008687907853269984665640564039457584007913129639', + stakeMappingCoefficient: `${Math.floor(5000000 / 200000)}000000000000000000`, + multiplier: 10000, + logArgumentConstant: 1, + a: 1, + stakeExponent: 1, + b: 0, + c: 1, + distanceExponent: 2, + d: 1, + }; + } + + getLinearSumParams(blockchain) { + return { + distanceScaleFactor: '1000000000000000000', + w1: 1, + w2: 1, + }; + } +} + +export default BlockchainModuleManagerMock; diff --git a/tools/knowledge-assets-distribution-simulation/plots/.gitkeep b/tools/knowledge-assets-distribution-simulation/plots/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/knowledge-assets-distribution-simulation/simulation.js b/tools/knowledge-assets-distribution-simulation/simulation.js new file mode 100644 index 0000000000..60b3cd9593 --- /dev/null +++ b/tools/knowledge-assets-distribution-simulation/simulation.js @@ -0,0 +1,574 @@ +/* eslint-disable import/no-extraneous-dependencies */ +/* eslint-disable no-await-in-loop */ +import 'dotenv/config'; +import crypto from 'crypto'; +import DeepExtend from 'deep-extend'; +import rc from 'rc'; +import fs from 'fs-extra'; +import D3Node from 'd3-node'; +import * as d3 from 'd3'; +import sharp from 'sharp'; +import { readFile } from 'fs/promises'; +import { createRequire } from 'module'; +import { create as createLibP2PKey, createFromPrivKey } from 'peer-id'; +import { HASH_RING_SIZE, UINT128_MAX_BN } from '../../src/constants/constants.js'; +import BlockchainModuleManagerMock from './mocks/blockchain-module-manager-mock.js'; +import HashingService from '../../src/service/hashing-service.js'; +import ProximityScoringService from '../../src/service/proximity-scoring-service.js'; +import Logger from '../../src/logger/logger.js'; + +const require = createRequire(import.meta.url); +const configjson = require('../../config/config.json'); +const pjson = require('../../package.json'); + +function getConfig() { + let config; + let userConfig; + + if (process.env.USER_CONFIG_PATH) { + const configurationFilename = process.env.USER_CONFIG_PATH; + const pathSplit = configurationFilename.split('/'); + userConfig = JSON.parse(fs.readFileSync(configurationFilename)); + userConfig.configFilename = pathSplit[pathSplit.length - 1]; + } + + const defaultConfig = JSON.parse(JSON.stringify(configjson[process.env.NODE_ENV])); + + if (userConfig) { + config = DeepExtend(defaultConfig, userConfig); + } else { + config = rc(pjson.name, defaultConfig); + } + + if (!config.configFilename) { + config.configFilename = '.origintrail_noderc'; + } + return config; +} + +function getLogger() { + return new Logger('debug'); +} + +const config = getConfig(); +const logger = getLogger(); +const blockchain = 'hardhat1:31337'; +const blockchainModuleManagerMock = new BlockchainModuleManagerMock(); +const hashingService = new HashingService({ config, logger }); +const proximityScoringService = new ProximityScoringService({ + config, + logger, + blockchainModuleManager: blockchainModuleManagerMock, +}); + +function generateRandomNumber(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +function generateRandomHashes(numberOfHashes) { + const hashes = []; + + for (let i = 0; i < numberOfHashes; i += 1) { + const randomString = crypto.randomBytes(20).toString('hex'); + const hash = `0x${crypto.createHash('sha256').update(randomString).digest('hex')}`; + hashes.push(hash); + } + + return numberOfHashes === 1 ? hashes[0] : hashes; +} + +async function generateRandomNodes( + numberOfNodes, + stakeMin = 50000, + stakeMax = 1000000, + hashFunctionId = 1, +) { + const nodes = []; + + for (let i = 0; i < numberOfNodes; i += 1) { + const libp2pPrivKey = (await createLibP2PKey({ bits: 1024, keyType: 'RSA' })).toJSON() + .privKey; + const nodeId = (await createFromPrivKey(libp2pPrivKey)).toB58String(); + const sha256 = await hashingService.callHashFunction(hashFunctionId, nodeId); + const stake = String(generateRandomNumber(stakeMin, stakeMax)); + + nodes.push({ nodeId, sha256, stake }); + } + + return nodes; +} + +async function readJsonFromFile(filePath) { + try { + const data = await readFile(filePath, 'utf8'); + return JSON.parse(data); + } catch (error) { + logger.error(`Error reading file: ${error.stack}`); + throw error; + } +} + +function convertSvgToJpg(svgString, outputImageName) { + sharp(Buffer.from(svgString)) + .flatten({ background: '#FFFFFF' }) + .jpeg({ quality: 100 }) + .toBuffer() + .then((buffer) => { + fs.writeFile( + `tools/knowledge-assets-distribution-simulation/plots/${outputImageName}.jpg`, + buffer, + (err) => { + if (err) { + logger.error(`Error saving the JPG file: ${err.stack}`); + } else { + logger.info( + `Plot saved as "tools/knowledge-assets-distribution-simulation/plots/${outputImageName}.jpg"`, + ); + } + }, + ); + }) + .catch((error) => { + logger.error('Error converting SVG to JPG:', error); + }); +} + +function generateStakeDistributionPlot(data, outputImageName) { + logger.info('Generating Node-Stake Distribution Plot.'); + + const d3n = new D3Node(); + const margin = { top: 60, right: 30, bottom: 60, left: 90 }; + const width = 2000 - margin.left - margin.right; + const height = 1000 - margin.top - margin.bottom; + + data.sort((a, b) => d3.descending(a.stake, b.stake)); + + const svg = d3n + .createSVG(width + margin.left + margin.right, height + margin.top + margin.bottom) + .append('g') + .attr('transform', `translate(${margin.left},${margin.top})`); + + svg.append('text') + .attr('x', width / 2) + .attr('y', 0 - margin.top / 2) + .attr('text-anchor', 'middle') + .style('font-size', '20px') + .style('text-decoration', 'underline') + .text('Node-Stake Distribution Plot'); + + const x = d3 + .scaleBand() + .range([0, width]) + .domain(data.map((_, i) => i + 1)) + .padding(0.2); + + svg.append('text') + .attr('transform', `translate(${width / 2}, ${height + margin.top - 20})`) + .style('text-anchor', 'middle') + .text('Node Index'); + + const y = d3 + .scaleLinear() + .domain([0, Math.round(d3.max(data.map((node) => node.stake)) * 1.1)]) + .range([height, 0]); + + svg.append('text') + .attr('transform', 'rotate(-90)') + .attr('y', 0 - margin.left) + .attr('x', 0 - height / 2) + .attr('dy', '1em') + .style('text-anchor', 'middle') + .text('Stake'); + + svg.selectAll('rect') + .data(data) + .enter() + .append('rect') + .attr('x', (_, i) => x(i + 1)) + .attr('width', x.bandwidth()) + .attr('y', (d) => y(d.stake)) + .attr('height', (d) => height - y(d.stake)) + .attr('fill', 'steelblue'); + + svg.append('g') + .attr('transform', `translate(0, ${height})`) + .call(d3.axisBottom(x)) + .selectAll('text') + .style('text-anchor', 'end') + .attr('dx', '-.8em') + .attr('dy', '.15em') + .attr('transform', 'rotate(-65)'); + + svg.append('g').call(d3.axisLeft(y)); + + convertSvgToJpg(d3n.svgString(), outputImageName); +} + +function generateScatterPlot(data, metric, outputImageName) { + const d3n = new D3Node(); + const margin = { top: 60, right: 30, bottom: 60, left: 60 }; + const width = 2000 - margin.left - margin.right; + const height = 1000 - margin.top - margin.bottom; + + const svg = d3n + .createSVG(width + margin.left + margin.right, height + margin.top + margin.bottom) + .append('g') + .attr('transform', `translate(${margin.left},${margin.top})`); + + svg.append('text') + .attr('x', width / 2) + .attr('y', 0 - margin.top / 2) + .attr('text-anchor', 'middle') + .style('font-size', '20px') + .style('text-decoration', 'underline') + .text(`Stake / KAs ${metric[0].toUpperCase() + metric.slice(1)} Relation Plot`); + + const minStake = d3.min(data.map((node) => node.stake)); + const maxStake = d3.max(data.map((node) => node.stake)); + + const x = d3 + .scaleLinear() + .domain([Math.round(minStake * 0.9), Math.round(maxStake * 1.1)]) + .range([0, width]); + + svg.append('text') + .attr('transform', `translate(${width / 2}, ${height + margin.top - 20})`) + .style('text-anchor', 'middle') + .text('Stake'); + + const minKAsNum = d3.min(data.map((node) => node[metric])); + const maxKAsNum = d3.max(data.map((node) => node[metric])); + + const y = d3 + .scaleLinear() + .domain([Math.round(minKAsNum * 0.9), Math.round(maxKAsNum * 1.1)]) + .range([height, 0]); + + svg.append('text') + .attr('transform', 'rotate(-90)') + .attr('y', 0 - margin.left) + .attr('x', 0 - height / 2) + .attr('dy', '1em') + .style('text-anchor', 'middle') + .text(`Knowledge Assets ${metric}`); + + svg.append('g').attr('transform', `translate(0, ${height})`).call(d3.axisBottom(x).ticks(15)); + + svg.append('g').call(d3.axisLeft(y).ticks(30)); + + svg.append('g') + .selectAll('dot') + .data(data) + .enter() + .append('circle') + .attr('cx', (d) => x(d.stake)) + .attr('cy', (d) => y(d[metric])) + .attr('r', 5) + .style('fill', '#69b3a2'); + + svg.append('line') + .style('stroke', 'red') + .style('stroke-width', 2) + .style('stroke-dasharray', '3, 3') + .attr('x1', 0) + .attr('y1', y(minKAsNum)) + .attr('x2', width) + .attr('y2', y(minKAsNum)); + + svg.append('line') + .style('stroke', 'red') + .style('stroke-width', 2) + .style('stroke-dasharray', '3, 3') + .attr('x1', 0) + .attr('y1', y(maxKAsNum)) + .attr('x2', width) + .attr('y2', y(maxKAsNum)); + + convertSvgToJpg(d3n.svgString(), outputImageName); +} + +function generateBoxPlot(data, metric, outputImageName) { + const d3n = new D3Node(); + const margin = { top: 60, right: 30, bottom: 60, left: 60 }; + const width = 2000 - margin.left - margin.right; + const height = 1000 - margin.top - margin.bottom; + + const svg = d3n + .createSVG(width + margin.left + margin.right, height + margin.top + margin.bottom) + .append('g') + .attr('transform', `translate(${margin.left},${margin.top})`); + + svg.append('text') + .attr('x', width / 2) + .attr('y', 0 - margin.top / 2) + .attr('text-anchor', 'middle') + .style('font-size', '20px') + .style('text-decoration', 'underline') + .text(`${metric[0].toUpperCase() + metric.slice(1)} Distribution Plot`); + + const groupedData = d3.group(data, (d) => d.nodeId); + const valuesPerNode = Array.from(groupedData.values(), (d) => d.map((item) => item[metric])); + + const x = d3 + .scaleBand() + .domain(valuesPerNode.map((_, i) => i)) + .range([0, width]); + + svg.append('text') + .attr('transform', `translate(${width / 2}, ${height + margin.top - 20})`) + .style('text-anchor', 'middle') + .text('Node Index'); + + const y = d3 + .scaleLinear() + .domain([0, d3.max(data, (d) => d[metric])]) + .nice() + .range([height, 0]); + + svg.append('text') + .attr('transform', 'rotate(-90)') + .attr('y', 0 - margin.left) + .attr('x', 0 - height / 2) + .attr('dy', '1em') + .style('text-anchor', 'middle') + .text(metric[0].toUpperCase() + metric.slice(1)); + + svg.append('g') + .attr('transform', `translate(0, ${height})`) + .call(d3.axisBottom(x)) + .selectAll('text') + .style('text-anchor', 'end') + .attr('dx', '-.8em') + .attr('dy', '.15em') + .attr('transform', 'rotate(-65)'); + + svg.append('g').call(d3.axisLeft(y).ticks(30)); + + const boxWidth = x.bandwidth() - 3; + + valuesPerNode.forEach((d, i) => { + const box = svg + .append('g') + .attr('transform', `translate(${x(i) + (x.bandwidth() - boxWidth) / 2},0)`); + + const q1 = d3.quantile(d, 0.25); + const median = d3.quantile(d, 0.5); + const q3 = d3.quantile(d, 0.75); + const iqr = q3 - q1; + const lowerLimit = q1 - 1.5 * iqr; + const upperLimit = q3 + 1.5 * iqr; + + const lowerWhisker = d3.max([d3.min(data, (n) => n[metric]), lowerLimit]); + const upperWhisker = d3.min([d3.max(data, (n) => n[metric]), upperLimit]); + + box.append('rect') + .attr('y', y(q3)) + .attr('height', y(q1) - y(q3)) + .attr('width', boxWidth) + .style('fill', '#69b3a2'); + + box.append('line') + .attr('y1', y(median)) + .attr('y2', y(median)) + .attr('x1', 0) + .attr('x2', boxWidth) + .style('stroke', 'black') + .style('width', 80); + + box.append('line') + .attr('y1', y(lowerWhisker)) + .attr('y2', y(upperWhisker)) + .attr('x1', boxWidth / 2) + .attr('x2', boxWidth / 2) + .style('stroke', 'black'); + + box.append('line') + .attr('y1', y(lowerWhisker)) + .attr('y2', y(lowerWhisker)) + .attr('x1', boxWidth * 0.25) + .attr('x2', boxWidth * 0.75) + .style('stroke', 'black'); + + box.append('line') + .attr('y1', y(upperWhisker)) + .attr('y2', y(upperWhisker)) + .attr('x1', boxWidth * 0.25) + .attr('x2', boxWidth * 0.75) + .style('stroke', 'black'); + }); + + convertSvgToJpg(d3n.svgString(), outputImageName); +} + +async function runSimulation( + mode, + filePath, + numberOfNodes, + numberOfKAs, + proximityScoreFunctionsPairId, + r0 = 3, + r2 = 20, +) { + let nodes = []; + + if (mode === 'load') { + nodes = await readJsonFromFile(filePath); + } else if (mode === 'generate') { + nodes = await generateRandomNodes(numberOfNodes); + } else { + logger.error(`Invalid mode: ${mode}. Use "load" or "generate".`); + return; + } + + logger.info( + `Running simulation in '${mode}' mode with ${nodes.length} nodes and ${numberOfKAs} KAs.`, + ); + + generateStakeDistributionPlot( + nodes.map((node) => ({ ...node, stake: Number(node.stake) })), + `${mode}-${nodes.length}-${numberOfKAs}-${proximityScoreFunctionsPairId}-nodes-stake-distribution`, + ); + + const knowledgeAssets = await generateRandomHashes(numberOfKAs); + const metrics = []; + const replicas = {}; + + for (const node of nodes) { + replicas[node.nodeId] = { + stake: Number(node.stake), + replicated: 0, + won: 0, + }; + } + + const nodesNumber = nodes.length; + let IDEAL_MAX_DISTANCE_IN_NEIGHBORHOOD; + + if (proximityScoreFunctionsPairId === 2) { + IDEAL_MAX_DISTANCE_IN_NEIGHBORHOOD = HASH_RING_SIZE.div(nodesNumber).mul(20); + } else if (proximityScoreFunctionsPairId === 3) { + IDEAL_MAX_DISTANCE_IN_NEIGHBORHOOD = HASH_RING_SIZE.div(nodesNumber).mul(10); + } + + const linearSumParams = await blockchainModuleManagerMock.getLinearSumParams(blockchain); + const { distanceScaleFactor } = linearSumParams; + const minimumStake = await blockchainModuleManagerMock.getMinimumStake(blockchain); + const maximumStake = await blockchainModuleManagerMock.getMaximumStake(blockchain); + + for (const key of knowledgeAssets) { + const nodesWithDistances = await Promise.all( + nodes.map(async (node) => { + const distance = await proximityScoringService.callProximityFunction( + blockchain, + proximityScoreFunctionsPairId, + node.sha256, + key, + ); + + return { ...node, distance }; + }), + ); + + const nodesSortedByDistance = nodesWithDistances + .sort((a, b) => a.distance.sub(b.distance)) + .slice(0, r2); + + const maxDistanceInNeighborhood = + nodesSortedByDistance[nodesSortedByDistance.length - 1].distance; + const maxDistance = + maxDistanceInNeighborhood > IDEAL_MAX_DISTANCE_IN_NEIGHBORHOOD + ? IDEAL_MAX_DISTANCE_IN_NEIGHBORHOOD + : maxDistanceInNeighborhood; + + for (const node of nodesSortedByDistance) { + replicas[node.nodeId].replicated += 1; + } + + const nodesWithScores = await Promise.all( + nodesSortedByDistance.map(async (node) => { + const score = await proximityScoringService.callScoreFunction( + blockchain, + proximityScoreFunctionsPairId, + node.distance, + node.stake, + maxDistance, + ); + + let dividend = node.distance; + let divisor = maxDistance; + if (dividend.gt(UINT128_MAX_BN) || divisor.gt(UINT128_MAX_BN)) { + dividend = dividend.div(distanceScaleFactor); + divisor = divisor.div(distanceScaleFactor); + } + + const divResult = dividend.mul(distanceScaleFactor).div(divisor); + + const mappedDistance = + parseFloat(divResult.toString()) / parseFloat(distanceScaleFactor.toString()); + const mappedStake = (node.stake - minimumStake) / (maximumStake - minimumStake); + + metrics.push({ nodeId: node.nodeId, mappedDistance, mappedStake, score }); + + return { ...node, score }; + }), + ); + + const nodesSortedByScore = nodesWithScores.sort((a, b) => b.score - a.score); + + for (const [index, node] of nodesSortedByScore.entries()) { + if (index < r0) { + replicas[node.nodeId].won += 1; + } else { + break; + } + } + } + + generateScatterPlot( + Object.values(replicas), + 'replicated', + `${mode}-${nodes.length}-${numberOfKAs}-${proximityScoreFunctionsPairId}-stake-replications-relation`, + ); + generateScatterPlot( + Object.values(replicas), + 'won', + `${mode}-${nodes.length}-${numberOfKAs}-${proximityScoreFunctionsPairId}-stake-wins-relation`, + ); + + generateBoxPlot( + metrics, + 'mappedDistance', + `${mode}-${nodes.length}-${numberOfKAs}-${proximityScoreFunctionsPairId}-mapped-distances-distribution`, + ); + generateBoxPlot( + metrics, + 'score', + `${mode}-${nodes.length}-${numberOfKAs}-${proximityScoreFunctionsPairId}-scores-distribution`, + ); +} + +const args = process.argv.slice(2); +const mode = args[0]; +const filePath = mode === 'load' ? args[1] : undefined; +const numberOfNodes = mode === 'generate' ? parseInt(args[1], 10) : undefined; +const numberOfKAs = parseInt(args[2], 10); +const proximityScoreFunctionsPairId = parseInt(args[3], 10); + +if ( + (mode === 'load' && !filePath) || + (mode === 'generate' && numberOfNodes === undefined) || + numberOfKAs === undefined || + proximityScoreFunctionsPairId === undefined +) { + logger.error('Incorrect arguments. Please provide the correct format.'); + logger.error( + 'To load nodes list from the JSON file: node simulate.js load ', + ); + logger.error( + 'To generate random nodes: node simulate.js generate ', + ); +} else { + runSimulation(mode, filePath, numberOfNodes, numberOfKAs, proximityScoreFunctionsPairId).catch( + (error) => logger.error(`Simulation error: ${error.stack}`), + ); +}