feat(waterfallValidateTxid): SLP.Utils.waterfallValidateTxid(txid)

This commit is contained in:
Chris Troutner
2021-02-08 17:10:32 -08:00
parent 687b5bca02
commit 3b873b6064
3 changed files with 126 additions and 19 deletions
+1 -1
View File
@@ -17,7 +17,7 @@
"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 '#waterfallValidateTxid' test/integration/",
"test:temp2": "mocha --timeout=30000 -g '#getTxData' test/unit/",
"test:temp2": "mocha --timeout=30000 -g '#waterfallValidateTxid' 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",
+41 -16
View File
@@ -1426,18 +1426,43 @@ class Utils {
}
}
// This function aggregates all the available SLP token validation sources.
// It starts with the fastest, most-efficient source first, and continues
// to other validation sources until the txid is validated (true or false).
// If the txid goes through all sources and can't be validated, it will
// return null.
//
// Validation sources from most efficient to least efficient:
// - SLPDB whitelist
// - SLPDB general
// - slp-api
//
// Currently only supports a single txid at a time.
/**
* @api SLP.Utils.waterfallValidateTxid() waterfallValidateTxid()
* @apiName waterfallValidateTxid
* @apiGroup SLP Utils
* @apiDescription Use multiple validators to validate an SLP TXID.
*
* This function aggregates all the available SLP token validation sources.
* It starts with the fastest, most-efficient source first, and continues
* to other validation sources until the txid is validated (true or false).
* If the txid goes through all sources and can't be validated, it will
* return null.
*
* Validation sources from most efficient to least efficient:
* - SLPDB with whitelist filter
* - SLPDB general purpose
* - slp-api
*
* Currently only supports a single txid at a time.
*
* @apiExample Example usage:
*
* // validate single SLP txid
* (async () => {
* try {
* let validated = await bchjs.SLP.Utils.waterfallValidateTxid(
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
* );
* console.log(validated);
* } catch (error) {
* console.error(error);
* }
* })();
*
* // returns
* true
*/
async waterfallValidateTxid (txid) {
try {
const cachedTxValidation = {}
@@ -1471,7 +1496,7 @@ class Utils {
const whitelistResult = await this.validateTxid3(txid)
// console.log(
// `whitelist-SLPDB for ${txid}: ${JSON.stringify(
// isValid,
// whitelistResult,
// null,
// 2
// )}`
@@ -1491,11 +1516,11 @@ class Utils {
// Try the general SLPDB, if the whitelist returned null.
const generalResult = await this.validateTxid(txid)
// console.log(
// `validateTxid() isValid: ${JSON.stringify(isValid, null, 2)}`
// `validateTxid() isValid: ${JSON.stringify(generalResult, null, 2)}`
// )
// Safely retrieve the returned value.
if (generalResult[0] === null) isValid = generalResult[0].valid
if (generalResult[0] !== null) isValid = generalResult[0].valid
// Exit if isValid is not null.
if (isValid !== null) {
@@ -1513,7 +1538,7 @@ class Utils {
/* exit quietly */
}
// console.log(
// `slp-validate isValid: ${JSON.stringify(isValid, null, 2)}`
// `slpValidateResult: ${JSON.stringify(slpValidateResult, null, 2)}`
// )
// Exit if isValid is not null.
+84 -2
View File
@@ -1855,7 +1855,8 @@ describe('#SLP Utils', () => {
.throws({ error: 'TXID not found' })
}
const txid = 'd284e71227ec89f714b964d8eda595be6392bebd2fac46082bc5a9ce6fb7b33e'
const txid =
'd284e71227ec89f714b964d8eda595be6392bebd2fac46082bc5a9ce6fb7b33e'
await uut.Utils.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
@@ -1875,7 +1876,8 @@ describe('#SLP Utils', () => {
.resolves({ data: mockData.mockTxDetails })
}
const txid = '9dbaaafc48c49a21beabada8de632009288a2cd52eecefd0c00edcffca9955d0'
const txid =
'9dbaaafc48c49a21beabada8de632009288a2cd52eecefd0c00edcffca9955d0'
const result = await uut.Utils.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
@@ -2055,6 +2057,86 @@ describe('#SLP Utils', () => {
*/
})
describe('#waterfallValidateTxid', () => {
// This test ensures that the whitelist SLPDB is called before the
// general purpose SLPDB.
it('should call validateTxid3() first', async () => {
const txid = 'fakeTxid'
const retVal = [{ txid, valid: true }]
// Use stubs to force the desired code path.
sandbox.stub(uut.Utils, 'validateTxid3').resolves(retVal)
sandbox
.stub(uut.Utils, 'validateTxid')
.rejects(new Error('Unexpected code path'))
sandbox
.stub(uut.Utils, 'validateTxid2')
.rejects(new Error('Unexpected code path'))
const result = await uut.Utils.waterfallValidateTxid(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, true)
})
// This test ensures that the general purpose SLPDB is called after the
// whitelist SLPDB, but before slp-api.
it('should call validateTxid() second', async () => {
const txid = 'fakeTxid'
const retVal1 = [{ txid, valid: null }]
const retVal2 = [{ txid, valid: true }]
// Use stubs to force the desired code path.
sandbox.stub(uut.Utils, 'validateTxid3').resolves(retVal1)
sandbox.stub(uut.Utils, 'validateTxid').resolves(retVal2)
sandbox
.stub(uut.Utils, 'validateTxid2')
.rejects(new Error('Unexpected code path'))
const result = await uut.Utils.waterfallValidateTxid(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, true)
})
// This test ensures that slp-api is called if both SLPDBs return null.
it('should call slp-api last', async () => {
const txid = 'fakeTxid'
const retVal1 = [{ txid, valid: null }]
// Use stubs to force the desired code path.
sandbox.stub(uut.Utils, 'validateTxid3').resolves(retVal1)
sandbox.stub(uut.Utils, 'validateTxid').resolves(retVal1)
sandbox.stub(uut.Utils, 'validateTxid2').resolves({ isValid: true })
const result = await uut.Utils.waterfallValidateTxid(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, true)
})
it('catches and throws an error', async () => {
try {
const txid = 'fakeTxid'
// Force an error
sandbox
.stub(uut.Utils, 'validateTxid3')
.rejects(new Error('fake error'))
await await uut.Utils.waterfallValidateTxid(txid)
assert.fail('Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(err.message, 'fake error')
}
})
})
describe('#getWhitelist', () => {
it('should return the list', async () => {
sandbox