Compare commits

...
30 Commits
Author SHA1 Message Date
Chris Troutner 44bac45c32 Updating README 2021-08-08 18:42:04 -07:00
Chris Troutner 95ee8054be Merge pull request #165 from Permissionless-Software-Foundation/ct-unstable
fix(Transactions.get()): Adding extra error handling for rate limits
2021-08-08 18:40:43 -07:00
Chris Troutner 547b28cac8 fix(Transactions.get()): Adding extra error handling for rate limits 2021-08-08 18:38:46 -07:00
Chris Troutner 40ba334a41 Merge pull request #163 from Permissionless-Software-Foundation/ct-unstable
fix(validateTxid3): Throwing an error when rate limit encountered.
2021-08-08 18:06:52 -07:00
Chris Troutner ffd8ccaf2b fix(validateTxid3): Throwing an error when rate limit encountered. 2021-08-08 18:04:39 -07:00
Chris Troutner 9a16c0c6d6 Merge pull request #162 from Permissionless-Software-Foundation/ct-unstable
fix(raw-transaction): Fixing JWT token bug
2021-08-07 12:48:00 -07:00
Chris Troutner 52a891fd78 fix(raw-transaction): Fixing JWT token bug 2021-08-07 12:41:24 -07:00
Chris Troutner c09df08429 fix(npm): Ran npm audit fix 2021-07-16 15:56:36 -07:00
Chris Troutner 4dc88c0af3 Merge pull request #160 from Permissionless-Software-Foundation/ct-unstable
fix(transactions): Adding better error messages
2021-07-16 15:20:12 -07:00
Chris Troutner 85caa9556b fix(transactions): Adding better error messages 2021-07-16 15:18:35 -07:00
Chris Troutner bbdc417eb2 Merge pull request #159 from Permissionless-Software-Foundation/ct-unstable
Updating README
2021-07-12 19:57:47 -07:00
Chris Troutner cc3bc002e7 Updating README 2021-07-12 19:52:29 -07:00
Chris Troutner a75e1ab633 Merge pull request #158 from Permissionless-Software-Foundation/ct-unstable
fix(dsproof): Adding documentation
2021-06-22 15:49:17 -07:00
Chris Troutner 8c5f1e2274 fix(dsproof): Adding documentation 2021-06-22 15:47:22 -07:00
Chris Troutner c30e76c942 Merge pull request #157 from Permissionless-Software-Foundation/dh-dsproof
feat(DSProof): Added DSProof to bch-js
2021-06-22 12:28:40 -07:00
Chris Troutner a575621c50 Fixing ABC integration tests 2021-06-22 12:24:29 -07:00
Daniel Gonzalez d3a0c5948a feat(DSProof): Added DSProof to bch-js 2021-06-19 22:40:16 -04:00
Chris Troutner 61bb509195 Merge pull request #156 from Permissionless-Software-Foundation/ct-unstable
fix(raw-transactions): Adding better error handling for rate-limits
2021-06-19 10:43:24 -07:00
Chris Troutner a18e549694 fix(raw-transactions): Adding better error handling for rate-limits 2021-06-19 10:41:49 -07:00
Chris Troutner 7d53f47d8a Merge pull request #155 from Permissionless-Software-Foundation/ct-unstable
fix(error): Adding additional rate limit error handling
2021-06-19 10:09:51 -07:00
Chris Troutner e8e615795d fix(error): Adding additional rate limit error handling 2021-06-19 10:08:28 -07:00
Chris Troutner 5759b096d5 Merge pull request #153 from Permissionless-Software-Foundation/ct-unstable
fix(errors): Throwing rate limit errors as Error objects
2021-06-19 09:44:11 -07:00
Chris Troutner 5b300f68b2 fix(errors): Throwing rate limit errors as Error objects 2021-06-19 09:42:36 -07:00
Chris Troutner 3cce6f9754 Merge pull request #152 from Permissionless-Software-Foundation/ct-unstable
fix(testnet): Fixing testnet integration test
2021-06-18 09:43:06 -07:00
Chris Troutner 3da04d9327 fix(testnet): Fixing testnet integration test 2021-06-18 09:32:07 -07:00
Chris Troutner 79091815a2 Merge pull request #151 from Permissionless-Software-Foundation/ct-unstable
fix(Electrumx): Fixing integration test
2021-06-17 07:19:55 -07:00
Chris Troutner 258144d26d fix(Electrumx): Fixing integration test 2021-06-17 07:16:48 -07:00
Chris Troutner 4c4a45841b Merge pull request #150 from Permissionless-Software-Foundation/ct-unstable
fix(package.json): Using /v5 in npm scripts
2021-06-16 19:17:14 -07:00
Chris Troutner 010afd10a3 Merge branch 'master' into ct-unstable 2021-06-16 19:13:03 -07:00
Chris Troutner 82b4d2ab9e fix(package.json): Using /v5 in npm scripts 2021-06-16 19:12:48 -07:00
18 changed files with 329 additions and 76 deletions
+5 -5
View File
@@ -35,15 +35,15 @@ const BCHJS = require("@psf/bch-js")
let bchjs = new BCHJS() // Defaults to BCHN network.
// testnet
bchjs = new BCHJS({ restURL: 'https://testnet3.fullstack.cash/v4/' })
bchjs = new BCHJS({ restURL: 'https://testnet3.fullstack.cash/v5/' })
```
This library is intended to be paired with
the [bch-api](https://github.com/Permissionless-Software-Foundation/bch-api) REST API, and the infrastructure provided by [FullStack.cash](https://fullstack.cash). The `restURL` property can be changed to work with different Bitcoin Cash networks:
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v4/
- ABC Mainnet REST API server: https://abc.fullstack.cash/v4/
- Testnet3 REST API server: https://testnet3.fullstack.cash/v4/
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v5/
- ABC Mainnet REST API server: https://abc.fullstack.cash/v5/
- Testnet3 REST API server: https://testnet3.fullstack.cash/v5/
- Check server status: https://metrics.fullstack.cash
### API Key
@@ -57,7 +57,7 @@ rate limits when interacting with the back end server. See [this article](https:
```
const BCHJS = require("@psf/bch-js")
let bchjs = new BCHJS({
restURL: 'https://bchn.fullstack.cash/v3/',
restURL: 'https://bchn.fullstack.cash/v5/',
apiToken: 'eyJhbGciO...' // Your JWT token here.
})
```
+23 -20
View File
@@ -4437,9 +4437,9 @@
}
},
"node_modules/glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
@@ -6977,12 +6977,15 @@
}
},
"node_modules/normalize-url": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.3.0.tgz",
"integrity": "sha512-9/nOVLYYe/dO/eJeQUNaGUF4m4Z5E7cb9oNTKabH+bNf19mqj60txTcveQxL0GlcWLXCxkOu2/LwL8oW0idIDA==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.3.1.tgz",
"integrity": "sha512-K1c7+vaAP+Yh5bOGmA10PGPpp+6h7WZrl7GwqKhUflBc9flU9pzG27DDeB9+iuhZkE3BJZOcgN1P/2sS5pqrWw==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/npm": {
@@ -6990,6 +6993,7 @@
"resolved": "https://registry.npmjs.org/npm/-/npm-6.14.13.tgz",
"integrity": "sha512-SRl4jJi0EBHY2xKuu98FLRMo3VhYQSA6otyLnjSEiHoSG/9shXCFNJy9tivpUJvtkN9s6VDdItHa5Rn+fNBzag==",
"bundleDependencies": [
"JSONStream",
"abbrev",
"ansicolors",
"ansistyles",
@@ -7030,7 +7034,6 @@
"init-package-json",
"is-cidr",
"json-parse-better-errors",
"JSONStream",
"lazy-property",
"libcipm",
"libnpm",
@@ -7081,11 +7084,11 @@
"qrcode-terminal",
"query-string",
"qw",
"read",
"read-cmd-shim",
"read-installed",
"read-package-json",
"read-package-tree",
"read",
"readable-stream",
"readdir-scoped-modules",
"request",
@@ -15249,9 +15252,9 @@
"dev": true
},
"node_modules/trim-newlines": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz",
"integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
"integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
"dev": true,
"engines": {
"node": ">=8"
@@ -19747,9 +19750,9 @@
}
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
@@ -21809,9 +21812,9 @@
}
},
"normalize-url": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.3.0.tgz",
"integrity": "sha512-9/nOVLYYe/dO/eJeQUNaGUF4m4Z5E7cb9oNTKabH+bNf19mqj60txTcveQxL0GlcWLXCxkOu2/LwL8oW0idIDA==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.3.1.tgz",
"integrity": "sha512-K1c7+vaAP+Yh5bOGmA10PGPpp+6h7WZrl7GwqKhUflBc9flU9pzG27DDeB9+iuhZkE3BJZOcgN1P/2sS5pqrWw==",
"dev": true
},
"npm": {
@@ -28284,9 +28287,9 @@
"dev": true
},
"trim-newlines": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz",
"integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
"integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
"dev": true
},
"trim-off-newlines": {
+11 -11
View File
@@ -11,19 +11,19 @@
"scripts": {
"test": "nyc mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
"test:integration": "npm run test:integration:bchn",
"test:integration:nft": "export RESTURL=https://bchn.fullstack.cash/v4/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 -g '#nft1' test/integration/chains/bchn/slp.js",
"test:integration:abc": "export RESTURL=https://abc.fullstack.cash/v4/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:bchn": "export RESTURL=https://bchn.fullstack.cash/v4/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:nft": "export RESTURL=https://bchn.fullstack.cash/v5/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 -g '#nft1' test/integration/chains/bchn/slp.js",
"test:integration:abc": "export RESTURL=https://abc.fullstack.cash/v5/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:bchn": "export RESTURL=https://bchn.fullstack.cash/v5/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:testnet": "IS_USING_FREE_TIER=true mocha --timeout 30000 test/integration/chains/testnet/",
"test:integration:local:abc": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:local:bchn": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v4/ mocha --timeout 30000 test/integration/chains/testnet",
"test:integration:decatur:bchn": "export RESTURL=http://192.168.0.36:3000/v4/ && mocha --timeout 30000 test/integration/",
"test:integration:temp:bchn": "export RESTURL=http://157.90.174.219:3000/v4/ && mocha --timeout 30000 test/integration/",
"test:temp": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 -g '#Encryption' test/integration/",
"test:integration:local:abc": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:local:bchn": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v5/ mocha --timeout 30000 test/integration/chains/testnet",
"test:integration:decatur:bchn": "export RESTURL=http://192.168.0.36:3000/v5/ && mocha --timeout 30000 test/integration/",
"test:integration:temp:bchn": "export RESTURL=http://157.90.174.219:3000/v5/ && mocha --timeout 30000 test/integration/",
"test:temp": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 -g '#Encryption' test/integration/",
"test:temp2": "mocha --timeout=30000 -g '#TransactionLib' test/unit/",
"test:temp3": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#Transaction' test/integration/",
"test:temp4": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 -g '#decodeOpReturn' test/integration/",
"test:temp3": "export RESTURL=https://bchn.fullstack.cash/v5/ && mocha --timeout 30000 -g '#DSProof' test/integration/chains/",
"test:temp4": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 -g '#decodeOpReturn' test/integration/",
"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",
+3
View File
@@ -32,6 +32,7 @@ const IPFS = require('./ipfs')
const Encryption = require('./encryption')
const Utxo = require('./utxo')
const Transaction = require('./transaction')
const DSProof = require('./dsproof')
// Indexers
const Ninsight = require('./ninsight')
@@ -115,6 +116,8 @@ class BCHJS {
this.IPFS = new IPFS()
this.Utxo = new Utxo(libConfig)
this.Transaction = new Transaction(libConfig)
this.DSProof = new DSProof(libConfig)
}
}
+81
View File
@@ -0,0 +1,81 @@
const axios = require('axios')
let _this
class DSProof {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
this.axios = axios
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
}
/**
* @api DSProof.getDSProof() getDSProof()
* @apiName getDSProof
* @apiGroup DSProof
* @apiDescription Checks if a transaction generated a double-spend proof.
*
* If a double-spend is attempted, one of the transactions will generate a
* 'double spend proof'. This call can be used to check if a transaction
* generated such a proof.
*
* Merchants should wait 3-5 seconds after receiving notification of a
* transaction before calling this endpoint, to see if the TXID generated a
* proof. If this method returns no data, then the TX can be considered 'safe'
* and not a double spend. If proof data is returned by this method, then
* the transaction generated a proof and can be considered a 'double spend'.
*
* @apiExample Example usage:
* (async () => {
* try {
* const txid = 'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
* const result = await bchjs.DSProof.getDSProof(txid)
* console.log(result);
* } catch(error) {
* console.error(error)
* }
* })()
*
* // returns
* null
*/
async getDSProof (txid) {
try {
if (!txid) {
throw new Error('txid is required')
}
if (txid.length !== 64) {
throw new Error(`txid must be of length 64 (not ${txid.length})`)
}
const response = await _this.axios.get(
`${this.restURL}dsproof/getdsproof/${txid}`,
_this.axiosOptions
)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
}
module.exports = DSProof
+26 -18
View File
@@ -1,6 +1,6 @@
const axios = require('axios')
let _this
// let _this
class RawTransactions {
constructor (config) {
@@ -27,7 +27,7 @@ class RawTransactions {
// Encapsulate dependencies
this.axios = axios
_this = this
// this = this
}
/**
@@ -98,7 +98,7 @@ class RawTransactions {
if (typeof hex === 'string') {
const response = await axios.get(
`${this.restURL}rawtransactions/decodeRawTransaction/${hex}`,
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -111,7 +111,7 @@ class RawTransactions {
data: {
hexes: hex
},
headers: _this.axiosOptions.headers
headers: this.axiosOptions.headers
}
const response = await axios(options)
@@ -120,7 +120,8 @@ class RawTransactions {
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
if (error.error) throw new Error(error.error)
else if (error.response && error.response.data) throw error.response.data
else throw error
}
}
@@ -165,7 +166,7 @@ class RawTransactions {
if (typeof script === 'string') {
const response = await axios.get(
`${this.restURL}rawtransactions/decodeScript/${script}`,
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -176,7 +177,7 @@ class RawTransactions {
data: {
hexes: script
},
headers: _this.axiosOptions.headers
headers: this.axiosOptions.headers
}
const response = await axios(options)
@@ -185,7 +186,8 @@ class RawTransactions {
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
if (error.error) throw new Error(error.error)
else if (error.response && error.response.data) throw error.response.data
else throw error
}
}
@@ -259,7 +261,7 @@ class RawTransactions {
if (typeof txid === 'string') {
const response = await axios.get(
`${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`,
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -272,7 +274,7 @@ class RawTransactions {
verbose: verbose,
usrObj // pass user data when making an internal call.
},
headers: _this.axiosOptions.headers
headers: this.axiosOptions.headers
}
const response = await axios(options)
@@ -281,7 +283,8 @@ class RawTransactions {
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
if (error.error) throw new Error(error.error)
else if (error.response && error.response.data) throw error.response.data
else throw error
}
}
@@ -326,7 +329,8 @@ class RawTransactions {
return retArray
} catch (error) {
if (error.response && error.response.data) throw error.response.data
if (error.error) throw new Error(error.error)
else if (error.response && error.response.data) throw error.response.data
else throw error
}
}
@@ -361,7 +365,9 @@ class RawTransactions {
async getTxData (txid) {
try {
if (typeof txid !== 'string') {
throw new Error('Input must be a string or array of strings.')
throw new Error(
'Input to raw-transaction.js/getTxData() must be a string containg a TXID.'
)
}
// Get the TX details for the transaction under consideration.
@@ -379,7 +385,8 @@ class RawTransactions {
return txDetails
} catch (error) {
if (error.response && error.response.data) throw error.response.data
if (error.error) throw new Error(error.error)
else if (error.response && error.response.data) throw error.response.data
else throw error
}
}
@@ -422,7 +429,7 @@ class RawTransactions {
if (typeof hex === 'string') {
const response = await this.axios.get(
`${this.restURL}rawtransactions/sendRawTransaction/${hex}`,
_this.axiosOptions
this.axiosOptions
)
if (response.data === '66: insufficient priority') {
@@ -443,16 +450,17 @@ class RawTransactions {
data: {
hexes: hex
},
headers: _this.axiosOptions.headers
headers: this.axiosOptions.headers
}
const response = await _this.axios(options)
const response = await this.axios(options)
return response.data
}
throw new Error('Input hex must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
if (error.error) throw new Error(error.error)
else if (error.response && error.response.data) throw error.response.data
else throw error
}
}
+8
View File
@@ -680,6 +680,14 @@ class Utils {
return validatedTxids
} catch (error) {
// console.log('validateTxid3 error: ', error)
// This case handles rate limit errors.
if (error.response && error.response.data && error.response.data.error) {
throw new Error(error.response.data.error)
}
// Not sure if this can be safely deprecated?
if (error.response && error.response.data) throw error.response.data
throw error
}
+16 -2
View File
@@ -37,7 +37,9 @@ class Transaction {
async get (txid) {
try {
if (typeof txid !== 'string') {
throw new Error('Input must be a string or array of strings.')
throw new Error(
'Input to Transaction.get() must be a string containing a TXID.'
)
}
const txDetails = await this.rawTransaction.getTxData(txid)
@@ -129,6 +131,11 @@ class Transaction {
} catch (err) {
// console.log('Error: ', err)
// This case handles rate limit errors.
if (err.response && err.response.data && err.response.data.error) {
throw new Error(err.response.data.error)
}
// If decoding the op_return fails, then it's not an SLP transaction,
// and the non-hyrated TX details can be returned.
return txDetails
@@ -136,7 +143,14 @@ class Transaction {
return txDetails
} catch (err) {
console.error('Error in transactions.js/get()')
// console.error('Error in transactions.js/get(): ', err)
// This case handles rate limit errors.
if (err.response && err.response.data && err.response.data.error) {
throw new Error(err.response.data.error)
}
if (err.error) throw new Error(err.error)
throw err
}
}
+5 -5
View File
@@ -28,7 +28,7 @@ class Util {
}
/**
* @api util.floor8() floor8()
* @api Util.floor8() floor8()
* @apiName floor8
* @apiGroup Util
* @apiDescription Round a number down to 8 decimal places.
@@ -63,7 +63,7 @@ class Util {
}
/**
* @api util.floor2() floor2()
* @api Util.floor2() floor2()
* @apiName floor2
* @apiGroup Util
* @apiDescription Round a number down to 2 decimal places.
@@ -98,7 +98,7 @@ class Util {
}
/**
* @api util.chunk20() chunk20()
* @api Util.chunk20() chunk20()
* @apiName chunk20
* @apiGroup Util
* @apiDescription chunk up an array into multiple arrays of 20 elements each.
@@ -151,7 +151,7 @@ class Util {
}
/**
* @api util.sleep() sleep()
* @api Util.sleep() sleep()
* @apiName sleep
* @apiGroup Util
* @apiDescription Promise-based delay.
@@ -175,7 +175,7 @@ class Util {
}
/**
* @api util.validateAddress() validateAddress()
* @api Util.validateAddress() validateAddress()
* @apiName Validate Address.
* @apiGroup Util
* @apiDescription Return information about the given bitcoin address.
+2
View File
@@ -276,6 +276,8 @@ class UTXO {
return retAry
} catch (err) {
console.error('Error in bchjs.utxo.get()')
if (err.error) throw new Error(err.error)
throw err
}
}
+25
View File
@@ -0,0 +1,25 @@
/*
Integration tests for bchjs dsproof library.
*/
const assert = require('chai').assert
const BCHJS = require('../../../../src/bch-js')
const bchjs = new BCHJS()
describe('#DSProof', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await bchjs.Util.sleep(1000)
})
describe('#getDSProof', () => {
it('should get TX info from the full node', async () => {
const txid =
'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
const result = await bchjs.DSProof.getDSProof(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, null)
})
})
})
+13 -5
View File
@@ -68,7 +68,9 @@ describe('#ElectrumX', () => {
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
for (let i = 0; i < 25; i++) {
addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
}
// const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${util.inspect(result)}`)
@@ -121,7 +123,9 @@ describe('#ElectrumX', () => {
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
for (let i = 0; i < 25; i++) {
addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
}
const result = await bchjs.Electrumx.balance(addr)
@@ -175,7 +179,9 @@ describe('#ElectrumX', () => {
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
for (let i = 0; i < 25; i++) {
addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
}
const result = await bchjs.Electrumx.transactions(addr)
@@ -236,7 +242,9 @@ describe('#ElectrumX', () => {
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
for (let i = 0; i < 25; i++) {
addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
}
await bchjs.Electrumx.unconfirmed(addr)
// console.log(`result: ${util.inspect(result)}`)
@@ -355,7 +363,7 @@ describe('#ElectrumX', () => {
assert.property(err, 'success')
assert.equal(err.success, false)
assert.include(
err.error,
err.error.error,
'the transaction was rejected by network rules'
)
}
+3 -1
View File
@@ -359,10 +359,12 @@ describe('#ElectrumX', () => {
try {
await bchjs.Electrumx.broadcast(txHex)
} catch (err) {
// console.log('err: ', err)
assert.property(err, 'success')
assert.equal(err.success, false)
assert.include(
err.error,
err.error.error,
'the transaction was rejected by network rules'
)
}
+8 -3
View File
@@ -251,9 +251,13 @@ describe('#rawtransaction', () => {
describe('#_getInputAddrs', () => {
it('should return an array of input addresses', async () => {
// const txid = '32233db13f2ae6d82b6262f335643dccf09fc0bcfcef4bc3fbe023355f02e112'
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txid =
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txDetails = await bchjs.RawTransactions.getRawTransaction(txid, true)
const txDetails = await bchjs.RawTransactions.getRawTransaction(
txid,
true
)
const result = await bchjs.RawTransactions._getInputAddrs(txDetails)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
@@ -268,7 +272,8 @@ describe('#rawtransaction', () => {
describe('#getTxData', () => {
it('should return tx data with input addresses', async () => {
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txid =
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const result = await bchjs.RawTransactions.getTxData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
+66
View File
@@ -0,0 +1,66 @@
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
// Unit under test (uut)
const BCHJS = require('../../src/bch-js')
const mockData = require('./fixtures/dsproof-mock')
let bchjs
const txid = 'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
describe('#DSProof', () => {
let sandbox
beforeEach(() => {
bchjs = new BCHJS()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('#getDSProof', () => {
it('should throw error if input is not provided', async () => {
try {
await bchjs.DSProof.getDSProof()
assert.equal(false, true, 'unexpected error')
} catch (err) {
assert.include(err.message, 'txid is required')
}
})
it('should throw error txid is invalid', async () => {
try {
await bchjs.DSProof.getDSProof('txid')
assert.equal(false, true, 'unexpected error')
} catch (err) {
assert.include(err.message, 'txid must be of length 64')
}
})
it('should handle error', async () => {
try {
sandbox.stub(bchjs.DSProof.axios, 'get').throws(new Error('test error'))
await bchjs.DSProof.getDSProof(txid)
assert.equal(false, true, 'unexpected error')
} catch (err) {
assert.include(err.message, 'test error')
}
})
it('should get double spend proof', async () => {
try {
sandbox
.stub(bchjs.DSProof.axios, 'get')
.resolves({ data: mockData.dsproof })
const result = await bchjs.DSProof.getDSProof(txid)
assert.property(result, 'dspid')
assert.property(result, 'txid')
assert.property(result, 'outpoint')
assert.property(result, 'path')
assert.property(result, 'descendants')
assert.property(result.outpoint, 'txid')
assert.property(result.outpoint, 'vout')
} catch (error) {
assert.equal(false, true, 'unexpected error')
}
})
})
})
+19
View File
@@ -0,0 +1,19 @@
/*
Mock data used for unit testing.
*/
const dsproof = {
dspid: '6234fff2a9dbcaa50e2c50d74e1d725a2bed1757d7a05a2db7a82df659554397',
txid: 'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e',
outpoint: {
txid: '17ebef34f7e9a0692317dd6fbb43ffccff45b7d688a2a754dbccfc5e6d93ce3e',
vout: 1
},
path: ['ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'],
descendants: [
'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
]
}
module.exports = {
dsproof
}
+14 -5
View File
@@ -171,10 +171,15 @@ describe('#RawTransactions', () => {
describe('#getTxData', () => {
it('should return tx data with input addresses', async () => {
// Mock dependencies
sandbox.stub(bchjs.RawTransactions, 'getRawTransaction').resolves(mockData.mockTx)
sandbox.stub(bchjs.RawTransactions, '_getInputAddrs').resolves(mockData.mockGetInputAddrsOutput)
sandbox
.stub(bchjs.RawTransactions, 'getRawTransaction')
.resolves(mockData.mockTx)
sandbox
.stub(bchjs.RawTransactions, '_getInputAddrs')
.resolves(mockData.mockGetInputAddrsOutput)
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txid =
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const result = await bchjs.RawTransactions.getTxData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
@@ -190,7 +195,10 @@ describe('#RawTransactions', () => {
} catch (err) {
// console.log(err)
assert2.include(err.message, 'Input must be a string or array of strings')
assert2.include(
err.message,
'Input to raw-transaction.js/getTxData() must be a string containg a TXID.'
)
}
})
@@ -201,7 +209,8 @@ describe('#RawTransactions', () => {
.stub(bchjs.RawTransactions, 'getRawTransaction')
.rejects(new Error('test error'))
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txid =
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
await bchjs.RawTransactions.getTxData(txid)
+1 -1
View File
@@ -25,7 +25,7 @@ describe('#TransactionLib', () => {
} catch (err) {
assert.include(
err.message,
'Input must be a string or array of strings.'
'Input to Transaction.get() must be a string containing a TXID.'
)
}
})