diff --git a/README.md b/README.md index 1036589..a21fa17 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,13 @@ yarn run start # You can change the host of CodeChain and DB host on the config/dev.json ``` +### Check CCCChanges + +If you run the Indexer with the environment `ENABLE_CCC_CHANGES_CHECK` variable, +the Indexer checks to see if CCCChanges is well calculated. +If you want to receive an email when an error is found, please set the `SENDGRID_API_KEY` and `SENDGRID_TO` variables. +If you want to receive a slack notification, please set the `SLACK_WEBHOOK` variable. + ## Run (for production) ``` diff --git a/package.json b/package.json index e69c5a4..141b0f6 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "yarn": "^1.10.0" }, "dependencies": { + "@sendgrid/mail": "^6.4.0", + "@slack/client": "^5.0.1", "async-lock": "^1.1.4", "bignumber.js": "^7.2.1", "buffer": "^5.2.1", diff --git a/src/checker/email.ts b/src/checker/email.ts new file mode 100644 index 0000000..4c46b63 --- /dev/null +++ b/src/checker/email.ts @@ -0,0 +1,99 @@ +import * as sendgrid from "@sendgrid/mail"; + +export interface Email { + sendError(msg: string): void; + sendWarning(text: string): void; + sendInfo(title: string, msg: string): void; +} + +class NullEmail implements Email { + public sendError(_: string): void { + // empty + } + public sendWarning(_: string): void { + // empty + } + public sendInfo(_: string, __: string): void { + // empty + } +} + +const from = "no-reply+indexer-CCCChanges-checker@devop.codechain.io"; + +function createTitle(params: { + title: string; + tag: string; + level: string; +}): string { + const { title, tag, level } = params; + return `[${level}]${tag} ${title}`; +} + +// tslint:disable-next-line:max-classes-per-file +class Sendgrid implements Email { + private readonly tag: string; + private readonly to: string; + + public constructor(params: { + tag: string; + sendgridApiKey: string; + to: string; + }) { + const { tag, sendgridApiKey, to } = params; + this.tag = tag; + sendgrid.setApiKey(sendgridApiKey); + this.to = to; + } + + public sendError(text: string): void { + const subject = createTitle({ + tag: this.tag, + title: "has a problem.", + level: "error" + }); + this.send(subject, text); + } + + public sendWarning(text: string): void { + const subject = createTitle({ + tag: this.tag, + title: "finds a problem.", + level: "warn" + }); + this.send(subject, text); + } + + public sendInfo(title: string, text: string): void { + const subject = createTitle({ tag: this.tag, title, level: "info" }); + this.send(subject, text); + } + + private send(subject: string, value: string): void { + sendgrid + .send({ + subject, + from, + to: this.to, + content: [{ type: "text/html", value }] + }) + .catch(console.error); + } +} + +export function createEmail(params: { + tag: string; + to?: string; + sendgridApiKey?: string; +}): Email { + const { tag, to, sendgridApiKey } = params; + if (sendgridApiKey != null) { + if (to == null) { + throw Error("The email destination is not set"); + } + console.log("Sendgrid key is set"); + return new Sendgrid({ tag, sendgridApiKey, to }); + } else { + console.log("Donot use sendgrid"); + return new NullEmail(); + } +} diff --git a/src/checker/index.ts b/src/checker/index.ts new file mode 100644 index 0000000..35bd418 --- /dev/null +++ b/src/checker/index.ts @@ -0,0 +1,184 @@ +import { SDK } from "codechain-sdk"; +import { IndexerConfig } from "../config"; +import * as BlockModel from "../models/logic/block"; +import * as CCCChangeModel from "../models/logic/cccChange"; +import { createEmail, Email } from "./email"; +import { createSlack, Slack } from "./slack"; + +export async function run(sdk: SDK, options: IndexerConfig) { + console.log("Start to check CCCChanges"); + const prevBlockInstance = await BlockModel.getLatestBlock(); + let lastCheckedBlockNumber: number | "NotExist"; + + const email = createEmail({ + tag: `[${options.codechain.networkId}][indexer-cccchanges-checker]`, + sendgridApiKey: process.env.SENDGRID_API_KEY, + to: process.env.SENDGRID_TO + }); + + const slack = createSlack( + `[${options.codechain.networkId}][indexer-cccchanges-checker]`, + process.env.SLACK_WEBHOOK + ); + + if (prevBlockInstance) { + lastCheckedBlockNumber = prevBlockInstance.get({ plain: true }).number; + } else { + lastCheckedBlockNumber = "NotExist"; + } + for (;;) { + await new Promise(resolve => setTimeout(resolve, 5 * 1000)); + if (lastCheckedBlockNumber === "NotExist") { + const blockInstance = await BlockModel.getByNumber(0); + if (blockInstance === null) { + continue; + } else { + lastCheckedBlockNumber = -1; + continue; + } + } + + const latestBlock = (await BlockModel.getLatestBlock())!; + const latestBlockNumber: number = latestBlock.get("number"); + + const checkFrom = lastCheckedBlockNumber + 1; + const checkTo = latestBlockNumber - 1; + if (checkTo > checkFrom) { + await checkBlocks(checkFrom, checkTo, sdk, email, slack); + lastCheckedBlockNumber = checkTo; + } else { + continue; + } + } +} + +async function checkBlocks( + fromBlockNumber: number, + toBlockNumber: number, + sdk: SDK, + email: Email, + slack: Slack +) { + if (fromBlockNumber >= toBlockNumber) { + throw new Error( + `Invalid fromBlockNumber(${fromBlockNumber}) and toBlockNumber(${toBlockNumber})` + ); + } + + let beforeBlockNumber = fromBlockNumber; + let afterBlockNumber = fromBlockNumber + 1; + + for (;;) { + const cccChanges = (await CCCChangeModel.getByBlockNumber( + afterBlockNumber + )).map(instance => instance.get({ plain: true })); + + const balanceChangeMap: Map = new Map(); + cccChanges.forEach(cccChange => { + /// Total CCC does not exceed Number.MAX_SAFE_INTEGER; + const change = parseInt(cccChange.change, 10); + const address = cccChange.address; + + if (balanceChangeMap.has(cccChange.address)) { + balanceChangeMap.set( + address, + balanceChangeMap.get(address)! + change + ); + } else { + balanceChangeMap.set(address, change); + } + }); + + const promises = Array.from(balanceChangeMap).map( + async ([address, change]) => { + const beforeBalanceUInt = await sdk.rpc.chain.getBalance( + address, + beforeBlockNumber + ); + const afterBalanceUInt = await sdk.rpc.chain.getBalance( + address, + afterBlockNumber + ); + + const beforeBalance = parseInt( + beforeBalanceUInt.toString(10), + 10 + ); + const afterBalance = parseInt( + afterBalanceUInt.toString(10), + 10 + ); + const expected = afterBalance - beforeBalance; + const actual = change; + + if (actual !== expected) { + sendAlarm({ + address, + beforeBlockNumber, + afterBlockNumber, + beforeBalance, + afterBalance, + actual, + expected, + email, + slack + }); + } + } + ); + + await Promise.all(promises); + if (afterBlockNumber === toBlockNumber) { + return; + } + beforeBlockNumber += 1; + afterBlockNumber += 1; + } +} + +function sendAlarm({ + address, + beforeBlockNumber, + afterBlockNumber, + actual, + expected, + beforeBalance, + afterBalance, + email, + slack +}: { + address: string; + beforeBlockNumber: number; + afterBlockNumber: number; + actual: number; + expected: number; + beforeBalance: number; + afterBalance: number; + email: Email; + slack: Slack; +}) { + /// TODO Send an email. + const firstLine = "Mismatch found"; + console.group(firstLine); + + const lines = [ + `Address: ${address}`, + `Balance at ${beforeBlockNumber}: ${beforeBalance}`, + `Balance at ${afterBlockNumber}: ${afterBalance}`, + `Actual CCCChanges: ${actual}`, + `Exepcted CCCChanges: ${expected}` + ]; + lines.forEach(line => { + console.error(line); + }); + console.groupEnd(); + + email.sendError(` +

${firstLine}

+ + `); + + slack.sendError([firstLine, ...lines].join("\n")); +} diff --git a/src/checker/slack.ts b/src/checker/slack.ts new file mode 100644 index 0000000..4e5543e --- /dev/null +++ b/src/checker/slack.ts @@ -0,0 +1,85 @@ +import { IncomingWebhook, MessageAttachment } from "@slack/client"; +import * as _ from "lodash"; + +export interface Slack { + sendError(msg: string): void; + sendWarning(text: string): void; + sendInfo(title: string, text: string): void; +} + +class NullSlack implements Slack { + public sendError(__: string) { + // empty + } + public sendWarning(__: string) { + // empty + } + public sendInfo(__: string, ___: string) { + // empty + } +} + +// tslint:disable-next-line:max-classes-per-file +class SlackWebhook implements Slack { + private readonly tag: string; + private readonly webhook: IncomingWebhook; + private unsentAttachments: MessageAttachment[] = []; + + public constructor(tag: string, slackWebhookUrl: string) { + this.tag = tag; + this.webhook = new IncomingWebhook(slackWebhookUrl, {}); + } + + public sendError(text: string) { + const title = `[error]${this.tag} has a problem`; + this.unsentAttachments.push({ title, text, color: "danger" }); + this.send(); + } + + public sendWarning(text: string) { + console.log(`Warning: ${text}`); + this.unsentAttachments.push({ + title: `[warn]${this.tag} finds a problem`, + text, + color: "warning" + }); + this.send(); + } + + public sendInfo(title: string, text: string) { + console.log(`Info: ${text}`); + this.unsentAttachments.push({ + title: `[info]${this.tag} ${title}`, + text, + color: "good" + }); + this.send(); + } + + private send() { + this.webhook + .send({ + attachments: this.unsentAttachments + }) + .catch((err: Error) => { + if (err) { + console.error("IncomingWebhook failed!", err); + return; + } + }); + this.unsentAttachments = []; + } +} + +export function createSlack( + tag: string, + slackWebhookUrl: string | undefined +): Slack { + if (slackWebhookUrl) { + console.log("Slack connected"); + return new SlackWebhook(tag, slackWebhookUrl); + } else { + console.log("Slack not connected"); + return new NullSlack(); + } +} diff --git a/src/index.ts b/src/index.ts index 64a42a8..176575f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import * as http from "http"; +import { run as runChecker } from "./checker"; import { IndexerConfig } from "./config"; import { IndexerContext } from "./context"; import log from "./log"; @@ -38,6 +39,10 @@ async function runServer() { ); }); context.worker.run(); + + if (process.env.ENABLE_CCC_CHANGES_CHECK) { + runChecker(context.sdk, context.options).catch(console.error); + } } runServer(); diff --git a/src/models/logic/block.ts b/src/models/logic/block.ts index ba58e4a..b2f10ef 100644 --- a/src/models/logic/block.ts +++ b/src/models/logic/block.ts @@ -327,6 +327,13 @@ async function parseSigners({ [parentBlockNumber] ); + // PoW or Solo consensus + if (validatorAddresses === null) { + return { + missedSigners: [] + }; + } + const missedValidatorIndices: number[] = unsetBitIndices( precommitBitset, validatorAddresses.length diff --git a/src/models/logic/cccChange.ts b/src/models/logic/cccChange.ts index 38590ec..ab0f4cd 100644 --- a/src/models/logic/cccChange.ts +++ b/src/models/logic/cccChange.ts @@ -245,3 +245,25 @@ export async function getCountByAddress( throw Exception.DBError(); } } + +export async function getByBlockNumber( + blockNumber: number +): Promise { + try { + return await models.CCCChange.findAll({ + attributes: [ + "address", + "change", + "blockNumber", + "reason", + "transactionHash" + ], + where: { + blockNumber + } + }); + } catch (err) { + console.error(err); + throw Exception.DBError(); + } +} diff --git a/yarn.lock b/yarn.lock index 0f7f9f8..f9ab330 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,31 @@ # yarn lockfile v1 +"@sendgrid/client@^6.4.0": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-6.4.0.tgz#d58df30adea5d7d09e747e2b61f9f859deeda798" + integrity sha512-GcO+hKXMQiwN0xMGfPITArlj4Nab1vZsrsRLmsJlcXGZV1V1zQC6XuAWJv6MGDd0hr/jKaXmCJ1XMYkxIRQHFw== + dependencies: + "@sendgrid/helpers" "^6.4.0" + "@types/request" "^2.0.3" + request "^2.88.0" + +"@sendgrid/helpers@^6.4.0": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@sendgrid/helpers/-/helpers-6.4.0.tgz#f9001cbe2f34e2c264d30fcf71aa5b9c3cde49aa" + integrity sha512-1dDDXauArHyxwTKFFfWvQpsijmwalyLgwoQJ3FRCssFq1RfqYDgFhRg0Xs3v/IXS2jkKWePSWiPORSR4Sysdpw== + dependencies: + chalk "^2.0.1" + deepmerge "^2.1.1" + +"@sendgrid/mail@^6.4.0": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@sendgrid/mail/-/mail-6.4.0.tgz#21d022f7fae57dcdc5910eeca5ed318df21e5f51" + integrity sha512-pVzbqbxhZ4FUN6iSIksRLtyXRPurrcee1i0noPDStDCLlHVwUR+TofeeKIFWGpIvbbk5UR6S6iV/U5ie8Kdblw== + dependencies: + "@sendgrid/client" "^6.4.0" + "@sendgrid/helpers" "^6.4.0" + "@sinonjs/commons@^1", "@sinonjs/commons@^1.0.2", "@sinonjs/commons@^1.3.1": version "1.3.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.3.1.tgz#ba4ae5fa908f7d8b96b0ec8df0665aca2d8695a4" @@ -31,6 +56,72 @@ resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== +"@slack/client@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@slack/client/-/client-5.0.1.tgz#57a5d4d977e3763f44a4dca321a7dbb73c6473af" + integrity sha512-rU3x3pVhKq+9gt2sDdQI6toYc9BmLCDU9UYpnGhlHWV+ebHXepftMLOuZqjt2inK9XLzz5XqJYKdsyfbCuwiJA== + dependencies: + "@slack/logger" "^1.0.0" + "@slack/rtm-api" "^5.0.1" + "@slack/types" "^1.0.0" + "@slack/web-api" "^5.0.1" + "@slack/webhook" "^5.0.0" + +"@slack/logger@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@slack/logger/-/logger-1.0.0.tgz#e529974c7111f8a62d794a79cd807eee1628088b" + integrity sha512-QDYhQR/58xKfB5iquvQwfpxPsmKPP/5SuDp8hRhZeUluCHsP1qBCOc3sW2Xb3cydxK0PAEnkLbBJf/ezsGwtlA== + dependencies: + "@types/node" ">=8.9.0" + +"@slack/rtm-api@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@slack/rtm-api/-/rtm-api-5.0.1.tgz#7663f418336c86c9f081890f0d3b4ce8f521d2a3" + integrity sha512-M8qcWssFg9SmNUSkxDE230ahl+toRJKRG76PluGL6EqlPcbLqzJYpwPBTPLq6WADYo6yNd6WGGQ4Qtzw/b7rvw== + dependencies: + "@slack/logger" "^1.0.0" + "@slack/web-api" "^5.0.1" + "@types/node" ">=8.9.0" + "@types/p-queue" "^2.3.2" + "@types/ws" "^5.1.1" + eventemitter3 "^3.1.0" + finity "^0.5.4" + p-cancelable "^1.1.0" + p-queue "^2.4.2" + ws "^5.2.0" + +"@slack/types@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@slack/types/-/types-1.0.0.tgz#1dc7a63b293c4911e474197585c3feda012df17a" + integrity sha512-IktC4uD/CHfLQcSitKSmjmRu4a6+Nf/KzfS6dTgUlDzENhh26l8aESKAuIpvYD5VOOE6NxDDIAdPJOXBvUGxlg== + +"@slack/web-api@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@slack/web-api/-/web-api-5.0.1.tgz#f46ecd2dd8b8104144082c079a4f53ec7737f327" + integrity sha512-L2Nc8P+NjXH1yqnsNhqxsrbpW3Qv+//9X5PQqcM3bctDmvmwTuhuM1X208RVD2avhnC89aghY5PssyaayWj5sA== + dependencies: + "@slack/logger" "^1.0.0" + "@slack/types" "^1.0.0" + "@types/form-data" "^2.2.1" + "@types/is-stream" "^1.1.0" + "@types/node" ">=8.9.0" + "@types/p-queue" "^2.3.2" + axios "^0.18.0" + eventemitter3 "^3.1.0" + form-data "^2.3.3" + is-stream "^1.1.0" + p-queue "^2.4.2" + p-retry "^4.0.0" + +"@slack/webhook@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@slack/webhook/-/webhook-5.0.0.tgz#0044a3940afc16cbc607c71acdffddb9e9d4f161" + integrity sha512-cDj3kz3x9z9271xPNzlwb90DpKTYybG2OWPJHigJL8FegR80rzQyD0v4bGuStGGkHbAYDKE2BMpJambR55hnSg== + dependencies: + "@slack/types" "^1.0.0" + "@types/node" ">=8.9.0" + axios "^0.18.0" + "@types/async-lock@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.1.tgz#81f218213bebcc5f740efe9648272c774a2e4b4b" @@ -99,6 +190,11 @@ dependencies: "@types/node" "*" +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + "@types/express-serve-static-core@*": version "4.16.1" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.1.tgz#35df7b302299a4ab138a643617bd44078e74d44e" @@ -116,7 +212,7 @@ "@types/express-serve-static-core" "*" "@types/serve-static" "*" -"@types/form-data@*": +"@types/form-data@*", "@types/form-data@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" integrity sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ== @@ -135,6 +231,13 @@ dependencies: http-status-codes "*" +"@types/is-stream@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@types/is-stream/-/is-stream-1.1.0.tgz#b84d7bb207a210f2af9bed431dc0fbe9c4143be1" + integrity sha512-jkZatu4QVbR60mpIzjINmtS1ZF4a/FqdTUTBeQDVOQ2PYyidtwFKr0B5G6ERukKwliq+7mIXvxyppwzG5EgRYg== + dependencies: + "@types/node" "*" + "@types/joi@^14.3.2": version "14.3.2" resolved "https://registry.yarnpkg.com/@types/joi/-/joi-14.3.2.tgz#eff771f0b19698b8e6e7c6fe6b625e07e2618fe9" @@ -167,11 +270,21 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.5.tgz#011eece9d3f839a806b63973e228f85967b79ed3" integrity sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q== +"@types/node@>=8.9.0": + version "12.6.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.1.tgz#d5544f6de0aae03eefbb63d5120f6c8be0691946" + integrity sha512-rp7La3m845mSESCgsJePNL/JQyhkOJA6G4vcwvVgkDAwHhGdq5GCumxmPjEk1MZf+8p5ZQAUE7tqgQRQTXN7uQ== + "@types/node@^10.11.7", "@types/node@^10.3.5": version "10.12.27" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.27.tgz#eb3843f15d0ba0986cc7e4d734d2ee8b50709ef8" integrity sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg== +"@types/p-queue@^2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@types/p-queue/-/p-queue-2.3.2.tgz#16bc5fece69ef85efaf2bce8b13f3ebe39c5a1c8" + integrity sha512-eKAv5Ql6k78dh3ULCsSBxX6bFNuGjTmof5Q/T6PiECDq0Yf8IIn46jCyp3RJvCi8owaEmm3DZH1PEImjBMd/vQ== + "@types/pg-types@*": version "1.11.4" resolved "https://registry.yarnpkg.com/@types/pg-types/-/pg-types-1.11.4.tgz#8d7c59fb509ce3dca3f8bae589252051c639a9a8" @@ -192,7 +305,7 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/request@^2.48.1": +"@types/request@^2.0.3", "@types/request@^2.48.1": version "2.48.1" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.1.tgz#e402d691aa6670fbbff1957b15f1270230ab42fa" integrity sha512-ZgEZ1TiD+KGA9LiAAPPJL68Id2UWfeSO62ijSXZjFJArVV+2pKcsVHmrcu+1oiE3q6eDGiFiSolRc4JHoerBBg== @@ -202,6 +315,11 @@ "@types/node" "*" "@types/tough-cookie" "*" +"@types/retry@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + "@types/semver@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45" @@ -282,6 +400,14 @@ dependencies: "@types/node" "*" +"@types/ws@^5.1.1": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-5.1.2.tgz#f02d3b1cd46db7686734f3ce83bdf46c49decd64" + integrity sha512-NkTXUKTYdXdnPE2aUUbGOXE1XfMK527SCvU/9bj86kyFF6kZ9ZnOQ3mK5jADn98Y2vEUD/7wKDgZa7Qst2wYOg== + dependencies: + "@types/events" "*" + "@types/node" "*" + JSONStream@^1.3.1: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -629,6 +755,11 @@ assertion-error@^1.1.0: resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== + async-lock@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.1.4.tgz#863aff9d5c243f75034349be7df9c3ceb7a54254" @@ -654,6 +785,14 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +axios@^0.18.0: + version "0.18.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3" + integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g== + dependencies: + follow-redirects "1.5.10" + is-buffer "^2.0.2" + babel-code-frame@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -1041,19 +1180,19 @@ codechain-primitives@^1.0.0: rlp "^2.1.0" codechain-primitives@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/codechain-primitives/-/codechain-primitives-1.0.1.tgz#86b397ec379f52ae01daeaf74e29712083a48a87" - integrity sha512-XKgGwB9JzE3/43IEgroRHIjESJ4NiFc1Ee7qucqSuDhUx5DQtm4uQJreJvy5/rBcQMaDPTYcfx6UiavCfhx3+g== + version "1.0.2" + resolved "https://registry.yarnpkg.com/codechain-primitives/-/codechain-primitives-1.0.2.tgz#2e44c7ba776dbe9d3473bf68c817572e0185a8a3" + integrity sha512-PSnXHIoR6EOhoMk4hjPttWGovcJXPYIgUj5De78Q3f5+yah6OPbJR4v82L+MCYOmD5+LvDF50mUzyOAAq+JNcg== dependencies: bignumber.js "^7.2.1" blakejs "^1.1.0" bn.js "^4.11.8" buffer "^5.2.1" + crypto-js "^3.1.9-1" elliptic "^6.4.1" hmac-drbg "^1.0.1" lodash "^4.17.11" node-forge "^0.7.6" - ripemd160 "^2.0.2" rlp "^2.1.0" codechain-sdk@^1.2.0: @@ -1073,7 +1212,7 @@ codechain-sdk@^1.2.0: "codechain-stakeholder-sdk@https://github.com/majecty/codechain-stakeholder-sdk-js#dist": version "0.1.0" - resolved "https://github.com/majecty/codechain-stakeholder-sdk-js#625a96fea22363e6179e968fe963bbeac2ccd52f" + resolved "https://github.com/majecty/codechain-stakeholder-sdk-js#b55c5ed82672c023bcd60b6412281d450ac222db" dependencies: cli-table3 "^0.5.1" codechain-primitives "^1.0.1" @@ -1252,6 +1391,11 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" +crypto-js@^3.1.9-1: + version "3.1.9-1" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.9-1.tgz#fda19e761fc077e01ffbfdc6e9fdfc59e8806cd8" + integrity sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg= + cycle@1.0.x: version "1.0.3" resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" @@ -1285,6 +1429,13 @@ debug@3.2.6, debug@^3.0.1, debug@^3.1.0: dependencies: ms "^2.1.1" +debug@=3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1309,6 +1460,11 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deepmerge@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + define-properties@^1.1.1, define-properties@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -1565,6 +1721,11 @@ event-emitter@^0.3.5: d "1" es5-ext "~0.10.14" +eventemitter3@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -1688,6 +1849,11 @@ find-up@3.0.0, find-up@^3.0.0: dependencies: locate-path "^3.0.0" +finity@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/finity/-/finity-0.5.4.tgz#f2a8a9198e8286467328ec32c8bfcc19a2229c11" + integrity sha512-3l+5/1tuw616Lgb0QBimxfdd2TqaDGpfCBpfX6EqtFmqUV3FtQnVEX4Aa62DagYEqnsTIjZcTfbq9msDbXYgyA== + flat@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" @@ -1700,6 +1866,13 @@ fmt@^1.1.0: resolved "https://registry.yarnpkg.com/fmt/-/fmt-1.1.0.tgz#e5f81ee412b1c9cf1f65ec9646d9eb27ce9a75a5" integrity sha512-RJcbgbg7MWnMijZnexn/SUXxz7pkOWBORoylniUUHzOyhT4aKdQ5oEXyXuXTQUbf/CcKArp3N5NpWMYlez25tw== +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -1731,6 +1904,15 @@ form-data@^2.3.1, form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +form-data@^2.3.3: + version "2.5.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.0.tgz#094ec359dc4b55e7d62e0db4acd76e89fe874d37" + integrity sha512-WXieX3G/8side6VIqx44ablyULoGruSde5PNTxoUyo5CeyAMX6nVWUd0rgist/EuX655cjhUhTo1Fo3tRYqbcA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + format-util@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.3.tgz#032dca4a116262a12c43f4c3ec8566416c5b2d95" @@ -2047,7 +2229,7 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@~2.0.3: +is-buffer@^2.0.2, is-buffer@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== @@ -2877,6 +3059,11 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-cancelable@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -2906,6 +3093,19 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-queue@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-2.4.2.tgz#03609826682b743be9a22dba25051bd46724fc34" + integrity sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng== + +p-retry@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.1.0.tgz#9ce7cef2069e84bf590df3b8ec18d740109338d6" + integrity sha512-oepllyG9gX1qH4Sm20YAKxg1GA7L7puhvGnTfimi31P07zSIj7SDV6YtuAx9nbJF51DES+2CIIRkXs8GKqWJxA== + dependencies: + "@types/retry" "^0.12.0" + retry "^0.12.0" + p-try@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" @@ -3362,6 +3562,11 @@ retry-as-promised@^2.3.2: bluebird "^3.4.6" debug "^2.6.9" +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + ripemd160@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -4204,6 +4409,13 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + xtend@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"