Compare commits

..
7 Commits
Author SHA1 Message Date
Chris Troutner fd6f58fd45 Merge pull request #31 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Added additional comments
2020-10-07 10:53:01 -07:00
Chris Troutner e8b2f88ff5 fix(decodeOpReturn): Added additional comments 2020-10-07 08:07:06 -07:00
Chris Troutner 4a11db7c45 Merge pull request #29 from kaellis/master
add internal caching for slp.tokenUtxoDetails to reduce duplicate calls
2020-10-07 08:02:08 -07:00
Ken Ellis 1f41b67e3b add internal caching for slp.tokenUtxoDetails to reduce duplicate calls 2020-10-01 09:33:06 -04:00
Chris Troutner 054fb9c14e Merge pull request #28 from Permissionless-Software-Foundation/ct-unstable
Improvements to hydrateUtxos()
2020-09-28 19:33:20 -07:00
Chris Troutner 1fd4095dcb fix(hydateUtxos): Refined integration test 2020-09-28 19:30:06 -07:00
Chris Troutner 0eb1f74ba1 fix(hydrateUtxos): fixing documentation for the function 2020-09-28 19:18:27 -07:00
2 changed files with 79 additions and 11 deletions
+63 -10
View File
@@ -1,10 +1,10 @@
const axios = require("axios")
const slpParser = require("slp-parser")
const Script = require("../script")
const scriptLib = new Script()
// const Script = require("../script")
// const scriptLib = new Script()
const BigNumber = require("bignumber.js")
// const BigNumber = require("bignumber.js")
let _this
@@ -662,6 +662,9 @@ class Utils {
* Similar to decodeOpReturn(), except decodeOpReturn2() uses the slp-parser
* library maintained by JT Freeman. Outputs have slightly different format.
*
* 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
@@ -694,7 +697,21 @@ class Utils {
* }
*/
// Reimplementation of decodeOpReturn() using slp-parser.
async decodeOpReturn(txid) {
async decodeOpReturn(txid, cache = null) {
// The cache object is an in-memory cache (JS Object) that can be passed
// into this function. It helps if multiple vouts from the same TXID are
// being evaluated. In that case, it can significantly reduce the number
// of API calls.
// To use: add the output of this function to the cache object:
// cache[txid] = returnValue
// Then pass that cache object back into this function every time its called.
if (cache) {
if (!(cache instanceof Object))
throw new Error(`decodeOpReturn cache parameter must be Object`)
const cachedVal = cache[txid]
if (cachedVal) return cachedVal
}
try {
// Validate the txid input.
if (!txid || txid === "" || typeof txid !== "string")
@@ -746,6 +763,8 @@ class Utils {
}
// console.log(`tokenData: ${JSON.stringify(tokenData, null, 2)}`)
if (cache) cache[txid] = tokenData
return tokenData
} catch (error) {
// console.log('decodeOpReturn error: ', error)
@@ -813,6 +832,10 @@ class Utils {
// CT 5/31/20: Refactored to use slp-parse library.
async tokenUtxoDetails(utxos) {
try {
// utxo list may have duplicate tx_hash, varying tx_pos
// only need to call decodeOpReturn once for those
const decodeOpReturnCache = {}
const cachedTxValidation = {}
// Throw error if input is not an array.
if (!Array.isArray(utxos)) throw new Error(`Input must be an array.`)
@@ -870,7 +893,7 @@ class Utils {
// If there is no OP_RETURN, mark the UTXO as false.
let slpData = false
try {
slpData = await this.decodeOpReturn(utxo.txid)
slpData = await this.decodeOpReturn(utxo.txid, decodeOpReturnCache)
// console.log(`slpData: ${JSON.stringify(slpData, null, 2)}`)
} catch (err) {
// console.log(`error from decodeOpReturn(${utxo.txid}): `, err)
@@ -955,7 +978,10 @@ class Utils {
// If UTXO passes validation, then return formatted token data.
else {
const genesisData = await this.decodeOpReturn(slpData.tokenId)
const genesisData = await this.decodeOpReturn(
slpData.tokenId,
decodeOpReturnCache
)
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
// Minting Baton
@@ -1003,7 +1029,10 @@ class Utils {
// If UTXO passes validation, then return formatted token data.
else {
const genesisData = await this.decodeOpReturn(slpData.tokenId)
const genesisData = await this.decodeOpReturn(
slpData.tokenId,
decodeOpReturnCache
)
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
// console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
@@ -1030,7 +1059,11 @@ class Utils {
// Finally, validate the SLP txid with SLPDB.
if (outAry[i].tokenType) {
const isValid = await this.validateTxid(utxo.txid)
var isValid = cachedTxValidation[utxo.txid]
if (isValid == null) {
isValid = await this.validateTxid(utxo.txid)
cachedTxValidation[utxo.txid] = isValid
}
// console.log(`isValid: ${JSON.stringify(isValid, null, 2)}`)
outAry[i].isValid = isValid[0].valid
@@ -1111,7 +1144,17 @@ class Utils {
* "satoshis": 546,
* "txid": "8ec01d851d9df9fb4b4331275e2ff680257c224100d0081cec6fbeedf982f738",
* "vout": 1,
* "isValid": false
* "utxoType": "token",
* "transactionType": "send",
* "tokenId": "a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2",
* "tokenTicker": "TROUT",
* "tokenName": "Trout's test token",
* "tokenDocumentUrl": "troutsblog.com",
* "tokenDocumentHash": "",
* "decimals": 2,
* "tokenType": 1,
* "tokenQty": 10,
* "isValid": true
* }
* ],
* "address": "bitcoincash:qpjdrs8qruzh8xvusdfmutjx62awcepnhyperm3g89"
@@ -1136,7 +1179,17 @@ class Utils {
* "satoshis": 546,
* "txid": "a72db6a0883ecb8e379f317231b2571e41e041b7b1107e3e54c2e0b3386ac6ca",
* "vout": 1,
* "isValid": false
* "utxoType": "token",
* "transactionType": "send",
* "tokenId": "6201f3efe486c577433622817b99645e1d473cd3882378f9a0efc128ab839a82",
* "tokenTicker": "VALENTINE",
* "tokenName": "Valentine day token",
* "tokenDocumentUrl": "fullstack.cash",
* "tokenDocumentHash": "",
* "decimals": 2,
* "tokenType": 1,
* "tokenQty": 5,
* "isValid": true
* }
* ],
* "address": "bitcoincash:qzygn28zpgeemnptkn26xzyuzzfu9l8f9vfvq7kptk"
+16 -1
View File
@@ -582,7 +582,7 @@ describe(`#SLP`, () => {
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Test the general structure of the output.
assert.isArray(result.slpUtxos)
@@ -590,6 +590,21 @@ describe(`#SLP`, () => {
assert.equal(result.slpUtxos[0].utxos.length, 1)
assert.equal(result.slpUtxos[1].utxos.length, 1)
assert.equal(result.slpUtxos[2].utxos.length, 2)
try {
// Test the expected values.
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
assert.equal(result.slpUtxos[1].utxos[0].isValid, true)
assert.equal(result.slpUtxos[1].utxos[0].tokenTicker, "TROUT")
assert.equal(result.slpUtxos[2].utxos[0].isValid, false)
assert.equal(result.slpUtxos[2].utxos[1].isValid, true)
assert.equal(result.slpUtxos[2].utxos[1].tokenTicker, "VALENTINE")
} catch (err) {
console.error(
'The hydrateUtxos call may hitting rate limits, or SLPDB may be having issues if "isValid" results are "null"'
)
console.log("Error: ", err)
}
})
})
})