From 76271c8fcb1d988843756666d29151bfe9617e71 Mon Sep 17 00:00:00 2001 From: kenshin-samourai Date: Tue, 23 Jun 2020 15:31:01 +0200 Subject: [PATCH] add support of strict_mode_vouts to pushtx endpoint --- lib/errors.js | 3 ++- pushtx/pushtx-processor.js | 47 ++++++++++++++++++++++++++++++++++++++ pushtx/pushtx-rest-api.js | 30 ++++++++++++++++++++---- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/lib/errors.js b/lib/errors.js index 10b4a92..b8bef58 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -75,6 +75,7 @@ module.exports = { pushtx: { NLOCK_MISMATCH: 'nLockTime in script does not match nLockTime in transaction', SCHEDULED_TOO_FAR: 'nLockTime is set to far in the future', - SCHEDULED_BAD_ORDER: 'Order of hop and nLockTime values must be consistent' + SCHEDULED_BAD_ORDER: 'Order of hop and nLockTime values must be consistent', + VIOLATION_STRICT_MODE_VOUTS: 'VIOLATION_STRICT_MODE_VOUTS' } } diff --git a/pushtx/pushtx-processor.js b/pushtx/pushtx-processor.js index cfe0ecb..dc78968 100644 --- a/pushtx/pushtx-processor.js +++ b/pushtx/pushtx-processor.js @@ -8,11 +8,20 @@ const bitcoin = require('bitcoinjs-lib') const zmq = require('zeromq') const Logger = require('../lib/logger') const errors = require('../lib/errors') +const db = require('../lib/db/mysql-db-wrapper') const RpcClient = require('../lib/bitcoind-rpc/rpc-client') const network = require('../lib/bitcoin/network') +const activeNet = network.network const keys = require('../keys')[network.key] const status = require('./status') +let Sources +if (network.key == 'bitcoin') { + Sources = require('../lib/remote-importer/sources-mainnet') +} else { + Sources = require('../lib/remote-importer/sources-testnet') +} + /** * A singleton providing a wrapper @@ -25,6 +34,7 @@ class PushTxProcessor { */ constructor() { this.notifSock = null + this.sources = new Sources() // Initialize the rpc client this.rpcClient = new RpcClient() } @@ -38,6 +48,43 @@ class PushTxProcessor { this.notifSock.bindSync(config.uriSocket) } + /** + * Enforce a strict verification mode on a list of outputs + * @param {string} rawtx - raw bitcoin transaction in hex format + * @param {array} vouts - output indices (integer) + * @returns {array} returns the indices of the faulty outputs + */ + async enforceStrictModeVouts(rawtx, vouts) { + const faultyOutputs = [] + const addrMap = {} + let tx + try { + tx = bitcoin.Transaction.fromHex(rawtx) + } catch(e) { + throw errors.tx.PARSE + } + // Check in db if addresses are known and have been used + for (let vout of vouts) { + if (vout >= tx.outs.length) + throw errors.txout.VOUT + const output = tx.outs[vout] + const address = bitcoin.address.fromOutputScript(output.script, activeNet) + const nbTxs = await db.getAddressNbTransactions(address) + if (nbTxs == null || nbTxs > 0) + faultyOutputs.push(vout) + else + addrMap[address] = vout + } + // Checks with indexer if addresses are known and have been used + if (keys.indexer.active != 'local_bitcoind') { + const results = await this.sources.getAddresses(Object.keys(addrMap)) + for (let r of results) + if (r.ntx > 0) + faultyOutputs.push(addrMap[r.address]) + } + return faultyOutputs + } + /** * Push transactions to the Bitcoin network * @param {string} rawtx - raw bitcoin transaction in hex format diff --git a/pushtx/pushtx-rest-api.js b/pushtx/pushtx-rest-api.js index 7c9dcbd..dd7aa87 100644 --- a/pushtx/pushtx-rest-api.js +++ b/pushtx/pushtx-rest-api.js @@ -152,6 +152,31 @@ class PushTxRestApi { if (!validator.isHexadecimal(query.tx)) return this._traceError(res, errors.body.INVDATA) + if (query.strict_mode_vouts) { + const outs = query.strict_mode_vouts.split('|') + if (outs.length > 0) { + let faults + for (let item of outs) { + if (!validator.isInt(item)) + return this._traceError(res, errors.body.INVDATA) + } + try { + const indices = outs.map(v => parseInt(v, 10)) + faults = await pushTxProcessor.enforceStrictModeVouts(query.tx, indices) + } catch(e) { + this._traceError(res, e) + } + if (faults.length > 0) { + return this._traceError(res, { + 'message': JSON.stringify({ + 'message': faults, + 'code': errors.pushtx.VIOLATION_STRICT_MODE_VOUTS + }) + }) + } + } + } + try { const txid = await pushTxProcessor.pushTx(query.tx) HttpServer.sendOkData(res, txid) @@ -198,10 +223,7 @@ class PushTxRestApi { if (msg.code && msg.message) { Logger.error(null, 'PushTx : Error ' + msg.code + ': ' + msg.message) - ret = { - message: msg.message, - code: msg.code - } + ret = msg } else { Logger.error(err.message, 'PushTx : ') ret = err.message