From d475f2220f3b3399651aa408a24e33d17c6fa002 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Thu, 24 Dec 2020 09:25:35 -0800 Subject: [PATCH 1/4] feat(SLPDB status): Created bchjs.SLP.Utils.getStatus() to get health status of SLPDB --- package.json | 4 +- src/slp/utils.js | 42 +++++++++++ test/integration/slp.js | 11 +++ test/unit/fixtures/slp/mock-utils.js | 103 ++++++++++++++++++++++++++- test/unit/slp-utils.js | 15 ++++ 5 files changed, 172 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 33f881d..753b43f 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "test:integration:local": "RESTURL=http://localhost:3000/v4/ mocha --timeout 30000 test/integration", "test:integration:local:bchn": "RESTURL=http://localhost:3000/v4/ bash test/integration/test-bchn-integration.sh", "test:integration:local:testnet": "RESTURL=http://localhost:4000/v4/ mocha --timeout 30000 test/integration/testnet", - "test:temp": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 -g '#tokenUtxoDetails' test/integration/", - "test:temp2": "mocha --timeout 30000 -g '#tokenUtxoDetails' test/unit/", + "test:temp": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#getStatus' test/integration/", + "test:temp2": "mocha --timeout 30000 -g '#getStatus' test/unit/", "coverage": "nyc report --reporter=text-lcov | coveralls", "coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/", "docs": "./node_modules/.bin/apidoc -i src/ -o docs" diff --git a/src/slp/utils.js b/src/slp/utils.js index 2db1cb4..0d30eda 100644 --- a/src/slp/utils.js +++ b/src/slp/utils.js @@ -1602,6 +1602,48 @@ class Utils { else throw error } } + + /** + * @api SLP.Utils.getStatus() getStatus() + * @apiName getStatus + * @apiGroup SLP Utils + * @apiDescription Get the status and health of the SLPDB connected to bch-api. + * + * @apiExample Example usage: + * + * // Get the current blockheight of the SLPDB indexer. + * (async () => { + * try { + * let validated = await bchjs.SLP.Utils.validateTxid( + * "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb" + * ); + * console.log(validated); + * } catch (error) { + * console.error(error); + * } + * })(); + * + * // returns + * [ { txid: + * 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', + * valid: true } ] + * + */ + async getStatus(txid) { + const path = `${this.restURL}slp/status` + + try { + const response = await _this.axios.get(path, _this.axiosOptions) + // console.log( + // `getStatus response.data: ${JSON.stringify(response.data, null, 2)}` + // ) + + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + throw error + } + } } module.exports = Utils diff --git a/test/integration/slp.js b/test/integration/slp.js index 581241e..c4409f9 100644 --- a/test/integration/slp.js +++ b/test/integration/slp.js @@ -820,6 +820,17 @@ describe(`#SLP`, () => { // console.log(`result: ${JSON.stringify(result, null, 2)}`) // }) // }) + + describe("#getStatus", () => { + it("should return the current block height of the SLPDB indexer", async () => { + const result = await bchjs.SLP.Utils.getStatus() + + console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.property(result, "bchBlockHeight") + assert.property(result, "slpProcessedBlockHeight") + }) + }) }) describe("#tokentype1", () => { diff --git a/test/unit/fixtures/slp/mock-utils.js b/test/unit/fixtures/slp/mock-utils.js index af499b0..70cb550 100644 --- a/test/unit/fixtures/slp/mock-utils.js +++ b/test/unit/fixtures/slp/mock-utils.js @@ -1190,6 +1190,106 @@ const whitelist = [ } ] +const slpdbStatus = { + _id: "5fe4cd90cd2bd2000f7fe46c", + version: "1.0.0-beta-rc13", + versionHash: "bb4a805610b9e4d67c1595b716df36190c75e8b1", + deplVersionHash: null, + startCmd: "node index run", + context: "SLPDB", + lastStatusUpdate: { + utc: "Thu, 24 Dec 2020 17:19:12 GMT", + unix: 1608830352 + }, + lastIncomingTxnZmq: { + utc: "Thu, 24 Dec 2020 17:19:12 GMT", + unix: 1608830352 + }, + lastIncomingBlockZmq: { + utc: "Thu, 24 Dec 2020 16:43:38 GMT", + unix: 1608828218 + }, + lastOutgoingTxnZmq: null, + lastOutgoingBlockZmq: null, + state: "RUNNING", + stateHistory: [ + { + utc: "Mon, 07 Dec 2020 15:26:23 GMT", + state: "STARTUP_BLOCK_SYNC" + }, + { + utc: "Tue, 08 Dec 2020 19:53:04 GMT", + state: "RUNNING" + } + ], + network: "mainnet", + bchBlockHeight: 667270, + bchBlockHash: + "000000000000000003d57b35b1b6b8073c8311974e2b9a473e1bd6daa98fde53", + slpProcessedBlockHeight: 667270, + mempoolInfoBch: { + loaded: true, + size: 534, + bytes: 320552, + usage: 956384, + maxmempool: 300000000, + mempoolminfee: 0.00001, + minrelaytxfee: 0.00001 + }, + mempoolSizeSlp: 78, + tokensCount: 77976, + pastStackTraces: [ + "[Tue, 08 Dec 2020 19:35:36 GMT] MongoServerSelectionError: connection to 172.17.0.1:12301 timed out\n at Timeout._onTimeout (/home/safeuser/SLPDB/node_modules/mongodb/lib/core/sdam/topology.js:438:30)\n at listOnTimeout (internal/timers.js:554:17)\n at processTimers (internal/timers.js:497:7)", + "[Tue, 08 Dec 2020 19:35:36 GMT] MongoServerSelectionError: connection to 172.17.0.1:12301 timed out\n at Timeout._onTimeout (/home/safeuser/SLPDB/node_modules/mongodb/lib/core/sdam/topology.js:438:30)\n at listOnTimeout (internal/timers.js:554:17)\n at processTimers (internal/timers.js:497:7)" + ], + doubleSpends: [ + { + txo: + "3e377f67e9d065f02e47633d847cdb04b0679d51baccdc0feea5297529e330b5:820", + details: { + originalTxid: + "dc148149d25a546fffe0b207c62b192811c288481df5f43f1f76f67b6004f98c", + current: + "de12db60e253c378eeebb1df85153168a998db8267ec54b38589cc31348b2b8d", + time: { + utc: "Sat, 19 Dec 2020 02:25:37 GMT", + unix: 1608344737 + } + } + } + ], + reorgs: [], + mongoDbStats: { + db: "slpdb", + collections: 5, + views: 0, + objects: 2497140, + avgObjSize: 3188.778575890819, + dataSize: 7593.943150520325, + storageSize: 3357.74609375, + indexes: 71, + indexSize: 1490.14453125, + totalSize: 4847.890625, + scaleFactor: 1048576, + fsUsedSize: 74424.46484375, + fsTotalSize: 153676.98046875, + ok: 1 + }, + publicUrl: "fullstack--bchn-02", + telemetryHash: null, + system: { + loadAvg1: 0.16, + loadAvg5: 0.11, + loadAvg15: 0.04, + platform: "linux", + cpuCount: 8, + freeMem: 5780.51953125, + totalMem: 31360.8828125, + uptime: 1654085, + processUptime: 1374204.613560816 + } +} + module.exports = { mockList, mockToken, @@ -1218,5 +1318,6 @@ module.exports = { mockWhitelist, mockValidateTxid3Valid, mockValidateTxid3Invalid, - whitelist + whitelist, + slpdbStatus } diff --git a/test/unit/slp-utils.js b/test/unit/slp-utils.js index 16b09a2..33ae2f9 100644 --- a/test/unit/slp-utils.js +++ b/test/unit/slp-utils.js @@ -2161,4 +2161,19 @@ describe("#SLP Utils", () => { } }) }) + + describe("#getStatus", () => { + it("should return the current block height of the SLPDB indexer", async () => { + sandbox + .stub(uut.Utils.axios, "get") + .resolves({ data: mockData.slpdbStatus }) + + const result = await uut.Utils.getStatus() + + // console.log(`result: `, result) + + assert.property(result, "bchBlockHeight") + assert.property(result, "slpProcessedBlockHeight") + }) + }) }) From 06e2dad45cf435eff479470d18effd633115ec5d Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Thu, 24 Dec 2020 09:26:36 -0800 Subject: [PATCH 2/4] Ran npm audit fix --- package-lock.json | 16 ++++++++-------- package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 25714e3..3020105 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3962,9 +3962,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "inquirer": { "version": "3.3.0", @@ -5450,9 +5450,9 @@ "dev": true }, "npm": { - "version": "6.14.9", - "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.9.tgz", - "integrity": "sha512-yHi1+i9LyAZF1gAmgyYtVk+HdABlLy94PMIDoK1TRKWvmFQAt5z3bodqVwKvzY0s6dLqQPVsRLiwhJfNtiHeCg==", + "version": "6.14.10", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.10.tgz", + "integrity": "sha512-FT23Qy/JMA+qxEYReMOr1MY7642fKn8Onn+72LASPi872Owvmw0svm+/DXTHOC3yO9CheEO+EslyXEpdBdRtIA==", "dev": true, "requires": { "JSONStream": "^1.3.5", @@ -5538,7 +5538,7 @@ "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", "once": "~1.4.0", - "opener": "^1.5.1", + "opener": "^1.5.2", "osenv": "^0.1.5", "pacote": "^9.5.12", "path-is-inside": "~1.0.2", @@ -7718,7 +7718,7 @@ } }, "opener": { - "version": "1.5.1", + "version": "1.5.2", "bundled": true, "dev": true }, diff --git a/package.json b/package.json index 753b43f..19b5612 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "ecurve": "^1.0.6", "figlet": "^1.2.0", "git-clone": "^0.1.0", - "ini": "^1.3.5", + "ini": "^1.3.8", "mkdirp": "^0.5.1", "node-cmd": "^3.0.0", "node-emoji": "^1.8.1", From b3e224e481ffb64633c8ec8760ace69a0fdb5e8a Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Thu, 24 Dec 2020 10:06:39 -0800 Subject: [PATCH 3/4] Cleaned up integration tests --- src/slp/utils.js | 2 +- test/integration/slp.js | 134 ++++++---------------------------------- 2 files changed, 20 insertions(+), 116 deletions(-) diff --git a/src/slp/utils.js b/src/slp/utils.js index 0d30eda..2922e6a 100644 --- a/src/slp/utils.js +++ b/src/slp/utils.js @@ -438,7 +438,7 @@ class Utils { async validateTxid(txid) { const path = `${this.restURL}slp/validateTxid` - console.log(`txid: ${JSON.stringify(txid, null, 2)}`) + // console.log(`txid: ${JSON.stringify(txid, null, 2)}`) // Handle a single TXID or an array of TXIDs. let txids diff --git a/test/integration/slp.js b/test/integration/slp.js index c4409f9..faa0b8b 100644 --- a/test/integration/slp.js +++ b/test/integration/slp.js @@ -483,7 +483,10 @@ describe(`#SLP`, () => { ] const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos) - console.log(`data: ${JSON.stringify(data, null, 2)}`) + // console.log(`data: ${JSON.stringify(data, null, 2)}`) + + assert.isArray(data) + // assert.equal(data[0].isValid, null) }) }) @@ -645,51 +648,25 @@ describe(`#SLP`, () => { ] const data = await bchjs.SLP.Utils.hydrateUtxos([{ utxos: utxos }]) - console.log(`data: ${JSON.stringify(data, null, 2)}`) + // console.log(`data: ${JSON.stringify(data, null, 2)}`) + + assert.isArray(data.slpUtxos) + assert.equal(data.slpUtxos[0].isValid, null) }) }) describe("#validateTxid", () => { - /* - it("should return null on a known invalid TXID", async () => { - const txid = - "f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a" - - const result = await bchjs.SLP.Utils.validateTxid(txid) - console.log(`result: ${JSON.stringify(result, null, 2)}`) - - assert.isArray(result) - - assert.property(result[0], "txid") - assert.equal(result[0].txid, txid) - - assert.property(result[0], "valid") - assert.equal(result[0].valid, null) - }) - - it("should return true a known valid TXID", async () => { - const txid = - "3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488" - - const result = await bchjs.SLP.Utils.validateTxid(txid) - console.log(`result: ${JSON.stringify(result, null, 2)}`) - - assert.isArray(result) - - assert.property(result[0], "txid") - assert.equal(result[0].txid, txid) - - assert.property(result[0], "valid") - assert.equal(result[0].valid, true) - }) -*/ // This test is not necessary. it("should handle a null response from SLPDB", async () => { const txid = "4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419" const result = await bchjs.SLP.Utils.validateTxid(txid) - console.log(`result: ${JSON.stringify(result, null, 2)}`) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.equal(result[0].txid, txid) + // assert.equal(result[0].valid, null) }) it("should handle a null response from SLPDB", async () => { @@ -699,7 +676,11 @@ describe(`#SLP`, () => { ] const result = await bchjs.SLP.Utils.validateTxid(txid) - console.log(`result: ${JSON.stringify(result, null, 2)}`) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.equal(result[0].txid, txid[0]) + // assert.equal(result[0].valid, null) }) }) @@ -744,88 +725,11 @@ describe(`#SLP`, () => { }) }) - // describe("#validateTxid3", () => { - // it("should invalidate a known invalid TXID", async () => { - // const txid = - // "f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a" - // - // const result = await bchjs.SLP.Utils.validateTxid3(txid) - // // console.log(`result: ${JSON.stringify(result, null, 2)}`) - // - // assert.isArray(result) - // - // assert.property(result[0], "txid") - // assert.equal(result[0].txid, txid) - // - // assert.property(result[0], "valid") - // assert.equal(result[0].valid, null) - // }) - // - // it("should validate a known valid TXID", async () => { - // const txid = - // "daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd" - // - // const result = await bchjs.SLP.Utils.validateTxid3(txid) - // // console.log(`result: ${JSON.stringify(result, null, 2)}`) - // - // assert.isArray(result) - // - // assert.property(result[0], "txid") - // assert.equal(result[0].txid, txid) - // - // assert.property(result[0], "valid") - // assert.equal(result[0].valid, true) - // }) - // - // it("should handle a mix of valid, invalid, and non-SLP txs", async () => { - // const txids = [ - // // Malformed SLP tx - // "f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a", - // // Normal TX (non-SLP) - // "01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0", - // // Valid PSF SLP tx - // "daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd", - // // Valid SLP token not in whitelist - // "3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488", - // // Unprocessed SLP TX - // // "a0d6406eecfd8634158efa9314ff15b4cbf451938e9dc7b5678c46b41eabc6ed" // Mint baton - // "402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019" - // ] - // - // const result = await bchjs.SLP.Utils.validateTxid3(txids) - // // console.log(`result: ${JSON.stringify(result, null, 2)}`) - // }) - // }) - - // describe("#validateTxid", () => { - // it("should handle a mix of valid, invalid, and non-SLP txs", async () => { - // const txids = [ - // // Malformed SLP tx - // "f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a", - // // Normal TX (non-SLP) - // "01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0", - // // Valid PSF SLP tx - // "daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd", - // // Valid SLP token not in whitelist - // "3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488", - // // Unprocessed SLP TX - // // "a0d6406eecfd8634158efa9314ff15b4cbf451938e9dc7b5678c46b41eabc6ed" - // // Token send on BCHN network. - // "402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019", - // // Token send on ABC network. - // "336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d" - // ] - // - // const result = await bchjs.SLP.Utils.validateTxid(txids) - // console.log(`result: ${JSON.stringify(result, null, 2)}`) - // }) - // }) - describe("#getStatus", () => { it("should return the current block height of the SLPDB indexer", async () => { const result = await bchjs.SLP.Utils.getStatus() - console.log(`result: ${JSON.stringify(result, null, 2)}`) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.property(result, "bchBlockHeight") assert.property(result, "slpProcessedBlockHeight") From b1c3311d50e330b58e88dc06360f7f5ae90d61b8 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Thu, 24 Dec 2020 10:16:41 -0800 Subject: [PATCH 4/4] feat(Blockbook): Removing support for Blockbook indexer --- src/bch-js.js | 7 - src/blockbook.js | 132 ------------- test/integration/blockbook.js | 148 -------------- test/unit/blockbook.js | 275 --------------------------- test/unit/fixtures/blockbook-mock.js | 64 ------- 5 files changed, 626 deletions(-) delete mode 100644 src/blockbook.js delete mode 100644 test/integration/blockbook.js delete mode 100644 test/unit/blockbook.js delete mode 100644 test/unit/fixtures/blockbook-mock.js diff --git a/src/bch-js.js b/src/bch-js.js index 17be54f..0806836 100644 --- a/src/bch-js.js +++ b/src/bch-js.js @@ -34,7 +34,6 @@ const IPFS = require("./ipfs") const Encryption = require("./encryption") // Indexers -const Blockbook = require("./blockbook") const OpenBazaar = require("./openbazaar") const Ninsight = require("./ninsight") const Electrumx = require("./electrumx") @@ -80,9 +79,6 @@ class BCHJS { // console.log(`apiToken: ${this.apiToken}`) - // Populate Blockbook endpoints. - this.Blockbook = new Blockbook(libConfig) - // Populate OpenBazaar endpoints this.OpenBazaar = new OpenBazaar(libConfig) @@ -194,9 +190,6 @@ class BitboxShim { this.Mining = new Mining(libConfig) this.RawTransactions = new RawTransactions(libConfig) - // Populate Blockbook endpoints. - this.Blockbook = new Blockbook(libConfig) - // Populate OpenBazaar endpoints this.OpenBazaar = new OpenBazaar(libConfig) diff --git a/src/blockbook.js b/src/blockbook.js deleted file mode 100644 index 9494441..0000000 --- a/src/blockbook.js +++ /dev/null @@ -1,132 +0,0 @@ -/* - This library interacts with the REST API endpoints in bch-api that communicate - with the Blockbook API. - - CT 11/10/20 - These endpoints will be soon be deprecated. Blockbook is being fazed out in - favor of Fulcrum. -*/ - -const axios = require("axios") - -let _this - -class Blockbook { - constructor(config) { - this.restURL = config.restURL - this.apiToken = config.apiToken - this.authToken = config.authToken - // console.log(`Blockbook apiToken: ${this.apiToken}`) - - if (this.authToken) { - // Add Basic Authentication token to the authorization header. - this.axiosOptions = { - headers: { - authorization: this.authToken - } - } - } else { - // Add JWT token to the authorization header. - this.axiosOptions = { - headers: { - authorization: `Token ${this.apiToken}` - } - } - } - - _this = this - } - - async balance(address) { - try { - // Handle single address. - if (typeof address === "string") { - const response = await axios.get( - `${this.restURL}blockbook/balance/${address}`, - _this.axiosOptions - ) - - return response.data - - // Handle array of addresses. - } else if (Array.isArray(address)) { - const response = await axios.post( - `${this.restURL}blockbook/balance`, - { - addresses: address - }, - _this.axiosOptions - ) - - return response.data - } - - throw new Error(`Input address must be a string or array of strings.`) - } catch (error) { - if (error.response && error.response.data) throw error.response.data - else throw error - } - } - - async utxo(address) { - try { - // Handle single address. - if (typeof address === "string") { - const response = await axios.get( - `${this.restURL}blockbook/utxos/${address}`, - _this.axiosOptions - ) - return response.data - - // Handle array of addresses. - } else if (Array.isArray(address)) { - const response = await axios.post( - `${this.restURL}blockbook/utxos`, - { - addresses: address - }, - _this.axiosOptions - ) - - return response.data - } - - throw new Error(`Input address must be a string or array of strings.`) - } catch (error) { - if (error.response && error.response.data) throw error.response.data - else throw error - } - } - - async tx(txid) { - try { - // Handle single txid. - if (typeof txid === "string") { - const response = await axios.get( - `${this.restURL}blockbook/tx/${txid}`, - _this.axiosOptions - ) - return response.data - - // Handle array of addresses. - } else if (Array.isArray(txid)) { - const response = await axios.post( - `${this.restURL}blockbook/tx`, - { - txids: txid - }, - _this.axiosOptions - ) - - return response.data - } - - throw new Error(`Input txid must be a string or array of strings.`) - } catch (error) { - if (error.response && error.response.data) throw error.response.data - else throw error - } - } -} - -module.exports = Blockbook diff --git a/test/integration/blockbook.js b/test/integration/blockbook.js deleted file mode 100644 index 21f6d1b..0000000 --- a/test/integration/blockbook.js +++ /dev/null @@ -1,148 +0,0 @@ -/* - Integration tests for the Blockbook library. - -*/ - -const chai = require("chai") -const assert = chai.assert -const BCHJS = require("../../src/bch-js") -const bchjs = new BCHJS() -//const axios = require("axios") - -// Inspect utility used for debugging. -const util = require("util") -util.inspect.defaultOptions = { - showHidden: true, - colors: true, - depth: 3 -} - -describe(`#Blockbook`, () => { - beforeEach(async () => { - if (process.env.IS_USING_FREE_TIER) await sleep(1000) - }) - - describe(`#Balance`, () => { - it(`should GET balance for a single address`, async () => { - const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" - - const result = await bchjs.Blockbook.balance(addr) - //console.log(`result: ${util.inspect(result)}`) - - assert.hasAnyKeys(result, [ - "page", - "totalPages", - "itemsOnPage", - "address", - "balance", - "totalReceived", - "totalSent", - "unconfirmedBalance", - "unconfirmedTxs", - "txs", - "txids" - ]) - assert.isArray(result.txids) - }) - - it(`should POST request balances for an array of addresses`, async () => { - const addr = [ - "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", - "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" - ] - - const result = await bchjs.Blockbook.balance(addr) - //console.log(`result: ${util.inspect(result)}`) - - assert.isArray(result) - assert.hasAnyKeys(result[0], [ - "page", - "totalPages", - "itemsOnPage", - "address", - "balance", - "totalReceived", - "totalSent", - "unconfirmedBalance", - "unconfirmedTxs", - "txs", - "txids" - ]) - assert.isArray(result[0].txids) - }) - - it(`should throw error on array size rate limit`, async () => { - try { - const addr = [] - for (let i = 0; i < 25; i++) - addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf") - - const result = await bchjs.Blockbook.balance(addr) - - console.log(`result: ${util.inspect(result)}`) - assert.equal(true, false, "Unexpected result!") - } catch (err) { - assert.hasAnyKeys(err, ["error"]) - assert.include(err.error, "Array too large") - } - }) - }) - - describe(`#utxo`, () => { - it(`should GET utxos for a single address`, async () => { - const addr = "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7" - - const result = await bchjs.Blockbook.utxo(addr) - // console.log(`result: ${JSON.stringify(result, null, 2)}`) - - assert.isArray(result) - assert.hasAnyKeys(result[0], [ - "txid", - "vout", - "value", - "height", - "confirmations" - ]) - }) - - it(`should POST utxo details for an array of addresses`, async () => { - const addr = [ - "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7", - "bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr" - ] - - const result = await bchjs.Blockbook.utxo(addr) - //console.log(`result: ${JSON.stringify(result, null, 2)}`) - - assert.isArray(result) - assert.isArray(result[0]) - assert.hasAnyKeys(result[0][0], [ - "txid", - "vout", - "value", - "height", - "confirmations" - ]) - }) - - it(`should throw error on array size rate limit`, async () => { - try { - const addr = [] - for (let i = 0; i < 25; i++) - addr.push("bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr") - - const result = await bchjs.Blockbook.utxo(addr) - //console.log(`result: ${util.inspect(result)}`) - - assert.equal(true, false, "Unexpected result!") - } catch (err) { - assert.hasAnyKeys(err, ["error"]) - assert.include(err.error, "Array too large") - } - }) - }) -}) - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)) -} diff --git a/test/unit/blockbook.js b/test/unit/blockbook.js deleted file mode 100644 index 9866c81..0000000 --- a/test/unit/blockbook.js +++ /dev/null @@ -1,275 +0,0 @@ -const chai = require("chai") -const assert = chai.assert -const BCHJS = require("../../src/bch-js") -const bchjs = new BCHJS() -const axios = require("axios") -const sinon = require("sinon") - -const mockData = require("./fixtures/blockbook-mock") - -describe(`#Blockbook`, () => { - let sandbox - beforeEach(() => (sandbox = sinon.createSandbox())) - afterEach(() => sandbox.restore()) - - describe(`#Balance`, () => { - it(`should GET balance for a single address`, async () => { - // Stub the network call. - sandbox.stub(axios, "get").resolves({ data: mockData.balance }) - - const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" - - const result = await bchjs.Blockbook.balance(addr) - //console.log(`result: ${util.inspect(result)}`) - - assert.hasAnyKeys(result, [ - "page", - "totalPages", - "itemsOnPage", - "address", - "balance", - "totalReceived", - "totalSent", - "unconfirmedBalance", - "unconfirmedTxs", - "txs", - "txids" - ]) - assert.isArray(result.txids) - }) - - it(`should POST request balances for an array of addresses`, async () => { - // Stub the network call. - sandbox - .stub(axios, "post") - .resolves({ data: [mockData.balance, mockData.balance] }) - - const addr = [ - "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", - "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" - ] - - const result = await bchjs.Blockbook.balance(addr) - //console.log(`result: ${util.inspect(result)}`) - - assert.isArray(result) - assert.hasAnyKeys(result[0], [ - "page", - "totalPages", - "itemsOnPage", - "address", - "balance", - "totalReceived", - "totalSent", - "unconfirmedBalance", - "unconfirmedTxs", - "txs", - "txids" - ]) - assert.isArray(result[0].txids) - }) - - it(`should throw an error for improper input`, async () => { - try { - // Stub the network call. - sandbox - .stub(axios, "post") - .throws(`Input address must be a string or array of strings`) - - const addr = 12345 - - await bchjs.Blockbook.balance(addr) - assert.equal(true, false, "Unexpected result!") - } catch (err) { - //console.log(`err: `, err) - assert.include( - err.message, - `Input address must be a string or array of strings` - ) - } - }) - /* - it(`should throw error on array size rate limit`, async () => { - try { - // Stub the network call. - sandbox.stub(axios, "post").throws(`Array too large`) - - const addr = [] - for (let i = 0; i < 25; i++) - addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf") - - const result = await bchjs.Blockbook.balance(addr) - - console.log(`result: ${util.inspect(result)}`) - assert.equal(true, false, "Unexpected result!") - } catch (err) { - assert.hasAnyKeys(err, ["error"]) - assert.include(err.error, "Array too large") - } - }) - */ - }) - - describe(`#utxo`, () => { - it(`should GET utxos for a single address`, async () => { - // Stub the network call. - sandbox.stub(axios, "get").resolves({ data: mockData.utxo }) - - const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" - - const result = await bchjs.Blockbook.utxo(addr) - //console.log(`result: ${JSON.stringify(result, null, 2)}`) - - assert.isArray(result) - assert.hasAnyKeys(result[0], [ - "txid", - "vout", - "value", - "height", - "confirmations" - ]) - }) - - it(`should POST utxo details for an array of addresses`, async () => { - // Stub the network call. - sandbox.stub(axios, "post").resolves({ data: mockData.utxos }) - - const addr = [ - "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", - "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" - ] - - const result = await bchjs.Blockbook.utxo(addr) - //console.log(`result: ${JSON.stringify(result, null, 2)}`) - - assert.isArray(result) - assert.isArray(result[0]) - assert.hasAnyKeys(result[0][0], [ - "txid", - "vout", - "value", - "height", - "confirmations" - ]) - }) - - it(`should throw an error for improper input`, async () => { - try { - // Stub the network call. - sandbox - .stub(axios, "post") - .throws(`Input address must be a string or array of strings`) - - const addr = 12345 - - await bchjs.Blockbook.utxo(addr) - assert.equal(true, false, "Unexpected result!") - } catch (err) { - //console.log(`err: `, err) - assert.include( - err.message, - `Input address must be a string or array of strings` - ) - } - }) - /* - it(`should throw error on array size rate limit`, async () => { - try { - const addr = [] - for (let i = 0; i < 25; i++) - addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf") - - const result = await bchjs.Blockbook.utxo(addr) - - console.log(`result: ${util.inspect(result)}`) - assert.equal(true, false, "Unexpected result!") - } catch (err) { - assert.hasAnyKeys(err, ["error"]) - assert.include(err.error, "Array too large") - } - }) - */ - }) - - describe(`#tx`, () => { - it(`should GET tx details for a single txid`, async () => { - // Stub the network call. - sandbox.stub(axios, "get").resolves({ data: mockData.utxo }) - - const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" - - const result = await bchjs.Blockbook.utxo(addr) - //console.log(`result: ${JSON.stringify(result, null, 2)}`) - - assert.isArray(result) - assert.hasAnyKeys(result[0], [ - "txid", - "vout", - "value", - "height", - "confirmations" - ]) - }) - - // it(`should POST utxo details for an array of addresses`, async () => { - // // Stub the network call. - // sandbox.stub(axios, "post").resolves({ data: mockData.utxos }) - // - // const addr = [ - // "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", - // "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" - // ] - // - // const result = await bchjs.Blockbook.utxo(addr) - // //console.log(`result: ${JSON.stringify(result, null, 2)}`) - // - // assert.isArray(result) - // assert.isArray(result[0]) - // assert.hasAnyKeys(result[0][0], [ - // "txid", - // "vout", - // "value", - // "height", - // "confirmations" - // ]) - // }) - - // it(`should throw an error for improper input`, async () => { - // try { - // // Stub the network call. - // sandbox - // .stub(axios, "post") - // .throws(`Input address must be a string or array of strings`) - // - // const addr = 12345 - // - // await bchjs.Blockbook.utxo(addr) - // assert.equal(true, false, "Unexpected result!") - // } catch (err) { - // //console.log(`err: `, err) - // assert.include( - // err.message, - // `Input address must be a string or array of strings` - // ) - // } - // }) - - /* - it(`should throw error on array size rate limit`, async () => { - try { - const addr = [] - for (let i = 0; i < 25; i++) - addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf") - - const result = await bchjs.Blockbook.utxo(addr) - - console.log(`result: ${util.inspect(result)}`) - assert.equal(true, false, "Unexpected result!") - } catch (err) { - assert.hasAnyKeys(err, ["error"]) - assert.include(err.error, "Array too large") - } - }) - */ - }) -}) diff --git a/test/unit/fixtures/blockbook-mock.js b/test/unit/fixtures/blockbook-mock.js deleted file mode 100644 index 5048a31..0000000 --- a/test/unit/fixtures/blockbook-mock.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - Unit test mocks for Blockbook endpoints. -*/ - -const balance = { - page: 1, - totalPages: 1, - itemsOnPage: 1000, - address: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", - balance: "230000", - totalReceived: "6194528752", - totalSent: "6194298752", - unconfirmedBalance: "0", - unconfirmedTxs: 0, - txs: 3, - txids: [ - "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c", - "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d", - "5d95f4e6047901fc1502a9758bbdb14ce73f24662b1784d13e0217b3d37bb7a2" - ] -} - -const utxo = [ - { - txid: "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c", - vout: 0, - value: "100000", - height: 560430, - confirmations: 29321 - }, - { - txid: "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d", - vout: 0, - value: "130000", - height: 560039, - confirmations: 29712 - } -] - -const utxos = [ - [ - { - txid: "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c", - vout: 0, - value: "100000", - height: 560430, - confirmations: 29868 - }, - { - txid: "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d", - vout: 0, - value: "130000", - height: 560039, - confirmations: 30259 - } - ], - [] -] - -module.exports = { - balance, - utxo, - utxos -}