From 388a3ee53bb607c68180d3d0ebeefee70ea6ac83 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Sat, 10 Oct 2020 09:03:14 -0700 Subject: [PATCH] fix(validate2Single): Added alternative SLP TXID validator --- config/index.js | 4 +- package-lock.json | 34 ++++++++++++++ package.json | 2 + src/routes/v3/slp.js | 93 +++++++++++++++++++++++++++++++++++--- test/v3/integration/slp.js | 6 +++ 5 files changed, 132 insertions(+), 7 deletions(-) diff --git a/config/index.js b/config/index.js index 2f47cea..542ffb1 100644 --- a/config/index.js +++ b/config/index.js @@ -3,7 +3,9 @@ */ const config = { - apiTokenSecret: process.env.TOKENSECRET ? process.env.TOKENSECRET : 'secret-jwt-token' + apiTokenSecret: process.env.TOKENSECRET + ? process.env.TOKENSECRET + : 'secret-jwt-token' } module.exports = config diff --git a/package-lock.json b/package-lock.json index 710a89e..9f858c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -810,6 +810,11 @@ "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz", "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==" }, + "@types/big.js": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-4.0.5.tgz", + "integrity": "sha512-D9KFrAt05FDSqLo7PU9TDHfDgkarlwdkuwFsg7Zm4xl62tTNaz+zN+Tkcdx2wGLBbSMf8BnoMhOVeUGUaJfLKg==" + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -2238,6 +2243,14 @@ "safe-buffer": "^5.0.1" } }, + "bitcoin-rpc-promise-retry": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bitcoin-rpc-promise-retry/-/bitcoin-rpc-promise-retry-1.3.0.tgz", + "integrity": "sha512-xhldBhYwiUNY4spzkXXcU9LEq+nbSKJ5tvYWEUe/XTCe1VYoe8tEb5jJq4MBA2d+5egiUOA+P1QTTYm1FqPtOg==", + "requires": { + "bitcoind-rpc": "^0.8.0" + } + }, "bitcoincash-ops": { "version": "github:christroutner/bitcoincash-ops#0041f2d945aa0e893fbbb5c2ebdf6254f6ff0555", "from": "github:christroutner/bitcoincash-ops" @@ -2268,6 +2281,11 @@ "wif": "^2.0.1" } }, + "bitcoind-rpc": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/bitcoind-rpc/-/bitcoind-rpc-0.8.1.tgz", + "integrity": "sha512-NfhykAT/x/P1SOiog8UzltvTiv6A6d2X5VWJ3UjGeAqFLXv+IYHy+E4fFCBmgQRyIb1EIcyIZK1SVpSOGRHsaw==" + }, "bitcoinjs-message": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/bitcoinjs-message/-/bitcoinjs-message-2.1.3.tgz", @@ -15279,6 +15297,22 @@ "bignumber.js": "^9.0.0" } }, + "slp-validate": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/slp-validate/-/slp-validate-1.2.2.tgz", + "integrity": "sha512-V6XV44qup2gssw4+7ETGoK5eDdvs9UwTA5/bbyk3NhQzQzMq64hDlySJi8qC1R3pkFMbqoFslHUMbZKTm7VVQA==", + "requires": { + "@types/big.js": "^4.0.5", + "big.js": "5.2.2" + }, + "dependencies": { + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + } + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", diff --git a/package.json b/package.json index ae22554..d8dff62 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@psf/bch-js": "^3.6.3", "apidoc": "^0.23.0", "axios": "^0.19.0", + "bitcoin-rpc-promise-retry": "^1.3.0", "bitcore-lib-cash": "^8.20.3", "body-parser": "^1.18.3", "cookie-parser": "~1.4.3", @@ -55,6 +56,7 @@ "pg": "^8.0.0", "pg-hstore": "^2.3.2", "rate-limiter-flexible": "^2.0.0", + "slp-validate": "^1.2.2", "winston": "^3.2.1", "winston-daily-rotate-file": "^4.0.0" }, diff --git a/src/routes/v3/slp.js b/src/routes/v3/slp.js index 8452722..24695e2 100644 --- a/src/routes/v3/slp.js +++ b/src/routes/v3/slp.js @@ -10,9 +10,16 @@ const routeUtils = new RouteUtils() const Slpdb = require('./services/slpdb') +// slp-validate dependencies. Used to validate SLP TXIDs independent of SLPDB. +const slpValidate = require('slp-validate') +const ValidatorType1 = slpValidate.ValidatorType1 +const RpcClient = require('bitcoin-rpc-promise-retry') +const RPC_CONNECTION_STRING = `http://${process.env.RPC_USERNAME}:${process.env.RPC_PASSWORD}@${process.env.RPC_IP}` + // const strftime = require('strftime') const wlogger = require('../../util/winston-logging') +// Instantiate a local copy of bch-js using the local REST API server. const LOCAL_RESTURL = process.env.LOCAL_RESTURL ? process.env.LOCAL_RESTURL : 'https://api.fullstack.cash/v3/' @@ -51,6 +58,7 @@ class Slp { constructor () { _this = this + // Encapsulate external libraries. _this.axios = axios _this.routeUtils = routeUtils _this.BigNumber = BigNumber @@ -58,6 +66,16 @@ class Slp { _this.rawTransactions = rawTransactions _this.slpdb = new Slpdb() + // Instantiate and encapsulate slp-validate and dependencies. + _this.rpc = new RpcClient(RPC_CONNECTION_STRING) + _this.slpValidator = new ValidatorType1({ + getRawTransaction: async txid => { + const rawTx = await _this.rpc.getRawTransaction(txid) + // console.log(`rawTx: ${JSON.stringify(rawTx, null, 2)}`) + return rawTx + } + }) + _this.router = router _this.router.get('/', _this.root) @@ -83,6 +101,7 @@ class Slp { ) _this.router.post('/generateSendOpReturn', _this.generateSendOpReturn) _this.router.post('/hydrateUtxos', _this.hydrateUtxos) + _this.router.get('/validateTxid2/:txid', _this.validate2Single) } // DRY error handler. @@ -1062,7 +1081,7 @@ class Slp { * @api {get} /slp/validateTxid/{txid} Validate single SLP transaction by txid. * @apiName Validate single SLP transaction by txid. * @apiGroup SLP - * @apiDescription Validate single SLP transaction by txid. + * @apiDescription Validate single SLP transaction by txid, using SLPDB. * * * @apiExample Example usage: @@ -1135,11 +1154,73 @@ class Slp { } } - // Returns a Boolean if the input TXID is a valid SLP TXID. - // async function isValidSlpTxid (txid) { - // const isValid = await slpValidator.isValidSlpTxid(txid) - // return isValid - // } + /** + * @api {get} /slp/validateTxid2/{txid} Validate single SLP transaction by txid. + * @apiName Validate single SLP transaction by txid. + * @apiGroup SLP + * @apiDescription Validate single SLP transaction by txid, using slp-validate. + * Slower, less efficient method of validating an SLP TXID using the slp-validate + * npm library. This method is independent of SLPDB and can be used when + * SLPDB return 'null' values. + * + * + * @apiExample Example usage: + * curl -X GET "https://api.fullstack.cash/v3/slp/validateTxid2/f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a" -H "accept:application/json" + * + * + */ + async validate2Single (req, res, next) { + try { + const txid = req.params.txid + + // Validate input + if (!txid || txid === '') { + res.status(400) + return res.json({ error: 'txid can not be empty' }) + } + + wlogger.debug( + 'Executing slp/validate2Single/:txid with this txid: ', + txid + ) + + // Get the raw transaction from the full node. + try { + await _this.slpValidator.getRawTransaction(txid) + } catch (err) { + wlogger.error(`err in slp.js/validate2Single() with getRawTransaction(${txid}): `, err) + return _this.errorHandler(err, res) + } + + // false by default. + let isValid = false + + // Validat the TXID. + try { + isValid = await _this.slpValidator.isValidSlpTxid({ txid }) + // console.log('isValid: ', isValid) + } catch (error) { + console.log(error) + isValid = false + } + + // Default return value. + const result = { + txid: txid, + valid: false + } + + // Build result. + result.valid = isValid + + res.status(200) + return res.json(result) + } catch (err) { + wlogger.error('Error in slp.ts/validate2Single().', err) + + return _this.errorHandler(err, res) + } + } /** * @api {get} /slp/txDetails/{txid} SLP transaction details. diff --git a/test/v3/integration/slp.js b/test/v3/integration/slp.js index 279d077..6425de5 100644 --- a/test/v3/integration/slp.js +++ b/test/v3/integration/slp.js @@ -213,4 +213,10 @@ describe('#slp', () => { assert.equal(result.slpUtxos[2].utxos.length, 2) }) }) + + // describe('#validate2Single', () => { + // it('should validate a known valid TXID', async () => { + // + // }) + // }) })