Compare commits

...
13 Commits
Author SHA1 Message Date
Chris Troutner 626d27033e Merge pull request #96 from Permissionless-Software-Foundation/ct-unstable
fix(typo): Fixing typo in IPFS class
2021-02-03 17:41:29 -08:00
Chris Troutner ce2ee3fc1b fix(typo): Fixing typo in IPFS class 2021-02-03 17:38:43 -08:00
Chris Troutner 4768dcadc6 Merge pull request #95 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs): Updating the server that handles bch-ipfs file uploads
2021-02-03 15:42:47 -08:00
Chris Troutner 5fef09edbf fix(ipfs): Updating the server that handles bch-ipfs file uploads 2021-02-03 15:40:38 -08:00
Chris Troutner 37109cd7ef Merge pull request #94 from Permissionless-Software-Foundation/ct-unstable
fix(getTxDataSlp): Adding prototype function
2021-01-30 14:43:13 -08:00
Chris Troutner 83d523260d fix(getTxDataSlp): Adding prototype function 2021-01-30 14:40:46 -08:00
Chris Troutner 8768a810c7 Merge pull request #93 from Permissionless-Software-Foundation/ct-unstable
RawTransactions.getTxData() returns tx info with vin addresses
2021-01-29 12:49:50 -08:00
Chris Troutner 8832bfc8df fix(decodeOpReturn): Fixing documentation 2021-01-29 12:47:22 -08:00
Chris Troutner a5208110b9 feat(getTxData): RawTransactions.getTxData() returns tx info with vin addresses 2021-01-29 12:43:02 -08:00
Chris Troutner 99ad7cd87f fix(_getInputAddrs): Added private function with tests get tx input addrs 2021-01-29 12:11:23 -08:00
Chris Troutner 68ae084fb0 Merge pull request #92 from Permissionless-Software-Foundation/ct-unstable
Merging documentation changes from @uncletammy
2021-01-29 07:20:32 -08:00
Chris Troutner b0b0e17abc Merge pull request #91 from uncletammy/master
Corrects example usages for HDNode.Mnemonic.toSeed method
2021-01-29 07:11:57 -08:00
Nicholas Crumrine a54306e382 corrects example usages for HDNode.toSeed method 2021-01-28 15:24:03 -06:00
8 changed files with 411 additions and 39 deletions
+2 -2
View File
@@ -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/ 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/testnet",
"test:temp": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#sort0ConfTxs' test/integration/",
"test:temp2": "mocha --timeout=30000 -g '#sortConfTxs' test/unit/",
"test:temp": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#getTxDataSlp' test/integration/",
"test:temp2": "mocha --timeout=30000 -g '#getTxData' 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",
+22 -22
View File
@@ -19,7 +19,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* bchjs.HDNode.fromSeed(seedBuffer);
*
@@ -28,7 +28,7 @@ class HDNode {
* // create mnemonic from entropy
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* bchjs.HDNode.fromSeed(seedBuffer);
*/
@@ -54,7 +54,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to legacy address
@@ -66,7 +66,7 @@ class HDNode {
* // create mnemonic from entropy
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to cash address
@@ -88,7 +88,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to cash address
@@ -100,7 +100,7 @@ class HDNode {
* // create mnemonic from entropy
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to cash address
@@ -121,7 +121,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.SLP.HDNode.fromSeed(seedBuffer);
* // to cash address
@@ -133,7 +133,7 @@ class HDNode {
* // create mnemonic from entropy
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.SLP.HDNode.fromSeed(seedBuffer);
* // to cash address
@@ -156,7 +156,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to WIF
@@ -168,7 +168,7 @@ class HDNode {
* // create mnemonic from entropy
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to WIF
@@ -190,7 +190,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to extended public key
@@ -202,7 +202,7 @@ class HDNode {
* // create mnemonic from entropy
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to extended public key
@@ -224,7 +224,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to extended private key
@@ -236,7 +236,7 @@ class HDNode {
* // create mnemonic from entropy
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // to extended private key
@@ -258,7 +258,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create root seed buffer from mnemonic
* let rootSeed= bchjs.Mnemonic.toSeed(mnemonic);
* let rootSeed= await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from root seed
* let hdNode = bchjs.HDNode.fromSeed(rootSeed);
* // create public key buffer from HDNode
@@ -269,7 +269,7 @@ class HDNode {
* // create mnemonic from entropy
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // create public key buffer from HDNode
@@ -290,7 +290,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create root seed buffer from mnemonic
* let rootSeed= bchjs.Mnemonic.toSeed(mnemonic);
* let rootSeed= await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from root seed
* let hdNode = bchjs.HDNode.fromSeed(rootSeed);
* // create public key buffer from HDNode
@@ -302,7 +302,7 @@ class HDNode {
* // create mnemonic from entropy
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // create public key buffer from HDNode
@@ -370,7 +370,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // derive hardened child HDNode
@@ -391,7 +391,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // derive unhardened child HDNode
@@ -412,7 +412,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create seed buffer from mnemonic
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create HDNode from seed buffer
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
* // derive hardened child HDNode
@@ -615,7 +615,7 @@ class HDNode {
* // create mnemonic
* let mnemonic = bchjs.Mnemonic.generate(128);
* // create root seed buffer
* let rootSeedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
* let rootSeedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
* // create master hd node
* let masterHDNode = bchjs.HDNode.fromSeed(rootSeedBuffer);
* // derive child node
+1 -1
View File
@@ -14,7 +14,7 @@ class IPFS {
constructor (config) {
this.IPFS_API = process.env.IPFS_API
? process.env.IPFS_API
: 'https://ipfs-api.fullstack.cash'
: 'https://ipfs-file-upload.fullstackcash.nl'
// : `http://localhost:5001`
// Default options when calling axios.
+179
View File
@@ -1,5 +1,7 @@
const axios = require('axios')
const SlpUtils = require('./slp/utils')
let _this
class RawTransactions {
@@ -27,6 +29,9 @@ class RawTransactions {
// Encapsulate dependencies
this.axios = axios
// Dependencies
this.slpUtils = new SlpUtils(config)
_this = this
}
@@ -289,6 +294,180 @@ class RawTransactions {
}
}
// Given verbose transaction details, this function retrieves the transaction
// data for the inputs (the parent transactions). It returns an array of
// objects. Each object corresponds to a transaction input, and contains
// the address that generated that input UTXO.
//
// Assumes a single TX. Does not yet work with an array of TXs.
// This function returns an array of objects, each object if formated as follows:
// {
// vin: 0, // The position of the input for the given txid
// address: bitcoincash:qzhrpmu7nruyfcemeanqh5leuqcnf6zkjq4qm9nqh0
// }
async _getInputAddrs (txDetails) {
try {
const retArray = [] // Return array
for (let i = 0; i < txDetails.vin.length; i++) {
// The first input represents the sender of the BCH or tokens.
const vin = txDetails.vin[i]
const inputTxid = vin.txid
const inputVout = vin.vout
// Get the TX details for the input, in order to retrieve the address of
// the sender.
const txDetailsParent = await this.getRawTransaction(inputTxid, true)
// console.log(
// `txDetailsParent: ${JSON.stringify(txDetailsParent, null, 2)}`
// )
// The vout from the previous tx that represents the sender.
const voutSender = txDetailsParent.vout[inputVout]
retArray.push({
vin: i,
address: voutSender.scriptPubKey.addresses[0]
})
}
return retArray
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api RawTransactions.getTxData() getTxData()
* @apiName getTxData
* @apiGroup RawTransactions
* @apiDescription
* Returns an object of transaction data, including addresses for input UTXOs.
*
* This function is equivalent to running `getRawTransaction (txid, true)`,
* execept the `vin` array will be populated with an `address` property that
* contains the `bitcoincash:` address of the sender for each input.
*
* This function will only work with a single txid. It does not yet support an
* array of TXIDs.
*
* @apiExample Example usage:
* (async () => {
* try {
* let txData = await bchjs.RawTransactions.getTxData("0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098");
* console.log(txData);
* } catch(error) {
* console.error(error)
* }
* })()
*/
// Equivalent to running: async getRawTransaction (txid, verbose = true)
// Only handles a single TXID (not arrays).
// Appends the BCH address to the inputs of the transaction.
async getTxData (txid) {
try {
if (typeof txid !== 'string') {
throw new Error('Input must be a string or array of strings.')
}
// Get the TX details for the transaction under consideration.
const txDetails = await this.getRawTransaction(txid, true)
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
const inAddrs = await this._getInputAddrs(txDetails)
// console.log(`inAddrs: ${JSON.stringify(inAddrs, null, 2)}`)
// Add the input address to the transaction data.
for (let i = 0; i < inAddrs.length; i++) {
txDetails.vin[i].address = inAddrs[i].address
}
return txDetails
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
// Wraps getTxData(), but also appends SLP token information to each input
// and output of the transaction. This is a very API-heavy call.
// Returns false if the txid is not an SLP transaction.
//
// Warning! This is a prototype function and the output can change at any time
// without reflecting a change in the semantic version. DO NOT USE IN PRODUCTION.
async getTxDataSlp (txid) {
try {
if (typeof txid !== 'string') {
throw new Error('Input must be a string or array of strings.')
}
const txDetails = await this.getTxData(txid)
// First get the token information for the output. If that fails, then
// this is not an SLP transaction, and this method can return false.
let outTokenData
try {
outTokenData = await this.slpUtils.decodeOpReturn(txid)
// console.log(`outTokenData: ${JSON.stringify(outTokenData, null, 2)}`)
// Add token information to the tx details object.
txDetails.tokenTxType = outTokenData.txType
txDetails.tokenId = outTokenData.tokenId
// Add the token quantity to each output.
for (let i = 0; i < outTokenData.amounts.length; i++) {
txDetails.vout[i + 1].tokenQty = outTokenData.amounts[i]
}
// Loop through each input and retrieve the token data.
for (let i = 0; i < txDetails.vin.length; i++) {
const thisVin = txDetails.vin[i]
try {
// If decodeOpReturn() throws an error, then this input is not
// from an SLP transaction and can be ignored.
const inTokenData = await this.slpUtils.decodeOpReturn(thisVin.txid)
// console.log(
// `vin[${i}] tokenData: ${JSON.stringify(inTokenData, null, 2)}`
// )
// Get the appropriate vout token amount. This may throw an error,
// which means this Vin is not actually a token UTXO, it was just
// associated with a previous token TX.
const tokenQty = inTokenData.amounts[thisVin.vout - 1]
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
if (tokenQty) {
thisVin.tokenQty = tokenQty
// txDetails.vin[i].tokenQty = tokenQty
} else {
thisVin.tokenQty = null
}
} catch (err) {
// console.log('catch 2: ', err)
// If decodeOpReturn() throws an error, then this input is not
// from an SLP transaction and can be ignored.
// thisVin.tokenQty = null
thisVin.tokenQty = null
continue
}
// console.log(
// `2: txDetails.vin[i]: ${JSON.stringify(txDetails.vin[i], null, 2)}`
// )
}
} catch (err) {
// console.log('catch 1: ', err)
return false
}
return txDetails
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api RawTransactions.sendRawTransaction() sendRawTransaction()
* @apiName sendRawTransaction
+4 -7
View File
@@ -883,18 +883,14 @@ class Utils {
* @api SLP.Utils.decodeOpReturn() decodeOpReturn()
* @apiName decodeOpReturn
* @apiGroup SLP Utils
* @apiDescription Retrieves transactions data from a txid and decodes the SLP OP_RETURN data.
* @apiDescription
* Retrieves transactions data from a txid and decodes the SLP OP_RETURN data.
*
* Similar to decodeOpReturn(), except decodeOpReturn2() uses the slp-parser
* library maintained by JT Freeman. Outputs have slightly different format.
* Throws an error if given a non-SLP txid.
*
* If optional associative array parameter cache is used, will cache and
* reuse responses for the same input.
*
* Throws an error if given a non-SLP txid.
*
* In a future version of bch-js, this method will replace the origonal
* decodeOpReturn() method.
*
* @apiExample Example usage:
*
@@ -921,6 +917,7 @@ class Utils {
* "99883300000000"
* ]
* }
*
*/
// Reimplementation of decodeOpReturn() using slp-parser.
async decodeOpReturn (txid, cache = null) {
+55 -3
View File
@@ -230,7 +230,7 @@ describe('#rawtransaction', () => {
below expect error messages returned from the server, but at least test
that the server is responding on those endpoints, and responds consistently.
*/
describe('sendRawTransaction', () => {
describe('#sendRawTransaction', () => {
it('should throw error on array size rate limit', async () => {
try {
const dataMock =
@@ -238,9 +238,9 @@ describe('#rawtransaction', () => {
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.RawTransactions.sendRawTransaction(data)
await bchjs.RawTransactions.sendRawTransaction(data)
console.log(`result: ${util.inspect(result)}`)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
@@ -248,6 +248,58 @@ describe('#rawtransaction', () => {
}
})
})
describe('#_getInputAddrs', () => {
it('should return an array of input addresses', async () => {
// const txid = '32233db13f2ae6d82b6262f335643dccf09fc0bcfcef4bc3fbe023355f02e112'
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txDetails = await bchjs.RawTransactions.getRawTransaction(txid, true)
const result = await bchjs.RawTransactions._getInputAddrs(txDetails)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result.length, 1)
assert.property(result[0], 'vin')
assert.property(result[0], 'address')
})
})
describe('#getTxData', () => {
it('should return tx data with input addresses', async () => {
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const result = await bchjs.RawTransactions.getTxData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result.vin[0], 'address')
})
})
describe('#getTxDataSlp', () => {
it('should return tx data with SLP information', async () => {
const txid = 'b438855cfcab64516b44097d7212df9cdb99226c8d7c7ab504d35fcfd834cb5b'
const result = await bchjs.RawTransactions.getTxDataSlp(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result.vin[0], 'address')
assert.property(result.vin[0], 'tokenQty')
assert.equal(result.vin[0].tokenQty, null)
assert.equal(result.vin[1].tokenQty, '100000000000')
})
it('should handle non-slp tx', async () => {
const txid = '04a6aca328af2445327015895b8da9766093b1989b52e477559759eb8072fc0a'
const result = await bchjs.RawTransactions.getTxDataSlp(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, false)
})
})
})
function sleep (ms) {
+62
View File
@@ -0,0 +1,62 @@
/*
Mocking data for the RawTransactions unit tests.
*/
const mockTx = {
txid: '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3',
vin: [
{
txid: '8a6b3b70569270f0bdbf68fd12a410aef8f7bf044bc88ab02386a1572024b2bd',
vout: 0,
scriptSig: {
asm:
'3044022035c42f5b10d412445c5ecc5feea42c7f885c433669306c699da0f687216c61d5022018c81cd0ea68101cf3cbe0af67165fca1ce3d667be69d0c9329f0679bbee6ba0[ALL|FORKID] 030152eb20beaa692daaa1a27596dcc98cc06ccbc6eec23d6182a08c7bdaa29ea9',
hex:
'473044022035c42f5b10d412445c5ecc5feea42c7f885c433669306c699da0f687216c61d5022018c81cd0ea68101cf3cbe0af67165fca1ce3d667be69d0c9329f0679bbee6ba04121030152eb20beaa692daaa1a27596dcc98cc06ccbc6eec23d6182a08c7bdaa29ea9'
},
sequence: 4294967295
}
]
}
const mockParentTx1 = {
vout: [
{
value: 0.04199959,
n: 0,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 d5258a73b5c8f94c939d7fe96f78ce97906083be OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914d5258a73b5c8f94c939d7fe96f78ce97906083be88ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qr2jtznnkhy0jnynn4l7jmmce6teqcyrhc8herhlgt']
}
},
{
value: 1.66296161,
n: 1,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 5e95c308c25c74c64c5ffe44a60a4d9b35743e90 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a9145e95c308c25c74c64c5ffe44a60a4d9b35743e9088ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qp0ftscgcfw8f3jvtllyffs2fkdn2ap7jqreakn4ye']
}
}
]
}
const mockGetInputAddrsOutput = [
{
vin: 0,
address: 'bitcoincash:qr2jtznnkhy0jnynn4l7jmmce6teqcyrhc8herhlgt'
}
]
module.exports = {
mockTx,
mockParentTx1,
mockGetInputAddrsOutput
}
+86 -4
View File
@@ -5,6 +5,7 @@
// Public npm libraries
const assert = require('assert')
const assert2 = require('chai').assert
const axios = require('axios')
const sinon = require('sinon')
// const nock = require("nock") // HTTP mocking
@@ -18,16 +19,19 @@ let bchjs
// const util = require("util")
// util.inspect.defaultOptions = { depth: 1 }
const mockData = require('./fixtures/rawtransaction-mock')
describe('#RawTransactions', () => {
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
bchjs = new BCHJS()
})
describe('#decodeRawTransaction', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
afterEach(() => sandbox.restore())
describe('#decodeRawTransaction', () => {
it('should decode raw transaction', done => {
const data = {
txid:
@@ -132,4 +136,82 @@ describe('#RawTransactions', () => {
// assert.strictEqual(data, result.data)
// })
})
describe('#_getInputAddrs', () => {
it('should return an array of input addresses', async () => {
sandbox
.stub(bchjs.RawTransactions, 'getRawTransaction')
.resolves(mockData.mockParentTx1)
const result = await bchjs.RawTransactions._getInputAddrs(mockData.mockTx)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert2.isArray(result)
assert2.equal(result.length, 1)
assert2.property(result[0], 'vin')
assert2.property(result[0], 'address')
})
it('should catch and throw and error', async () => {
try {
sandbox
.stub(bchjs.RawTransactions, 'getRawTransaction')
.rejects(new Error('test error'))
await bchjs.RawTransactions._getInputAddrs(mockData.mockTx)
assert.fail('Unexpected result')
} catch (err) {
// console.log(err)
assert2.equal(err.message, 'test error')
}
})
})
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)
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const result = await bchjs.RawTransactions.getTxData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert2.property(result.vin[0], 'address')
})
it('should throw an error for a non-txid input', async () => {
try {
await bchjs.RawTransactions.getTxData(1234)
assert.fail('Unexpected result')
} catch (err) {
// console.log(err)
assert2.include(err.message, 'Input must be a string or array of strings')
}
})
it('should catch and throw an error', async () => {
try {
// Force a network error.
sandbox
.stub(bchjs.RawTransactions, 'getRawTransaction')
.rejects(new Error('test error'))
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
await bchjs.RawTransactions.getTxData(txid)
assert.fail('Unexpected result')
} catch (err) {
// console.log(err)
assert2.equal(err.message, 'test error')
}
})
})
})