From 442af30da2b4d99f8a63f8a4371c07ebeb03360b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0ev=C4=8D=C3=ADk?= Date: Mon, 5 Jul 2021 18:35:01 +0200 Subject: [PATCH 1/7] Derive additional change addresses for postmix account --- lib/bitcoin/hd-accounts-helper.js | 59 ++++++++++++++++++++-- lib/bitcoin/hd-accounts-service.js | 4 +- lib/bitcoin/parallel-address-derivation.js | 5 +- tracker/transaction.js | 3 +- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/lib/bitcoin/hd-accounts-helper.js b/lib/bitcoin/hd-accounts-helper.js index 8d51ca5..114ce05 100644 --- a/lib/bitcoin/hd-accounts-helper.js +++ b/lib/bitcoin/hd-accounts-helper.js @@ -16,6 +16,7 @@ const activeNet = network.network const keys = require('../../keys/')[network.key] const addrHelper = require('./addresses-helper') +const MAX_SAFE_INT_32 = Math.pow(2, 31) - 1; /** * A singleton providing HD Accounts helper functions @@ -32,6 +33,12 @@ class HDAccountsHelper { this.BIP84 = 2 this.LOCKED = 1<<7 + // known HD accounts + this.RICOCHET_ACCT = MAX_SAFE_INT_32; + this.POSTMIX_ACCT = MAX_SAFE_INT_32 - 1; + this.PREMIX_ACCT = MAX_SAFE_INT_32 - 2; + this.BADBANK_ACCT = MAX_SAFE_INT_32 - 3; + // Magic numbers this.MAGIC_XPUB = 0x0488b21e this.MAGIC_TPUB = 0x043587cf @@ -292,7 +299,7 @@ class HDAccountsHelper { * @param {bip32} chainNode - Parent bip32 used for derivation * @param {number} index - index to be derived * @param {number} type - type of derivation - * @returns {Promise} returns an object {address: '...', chain: , index: } + * @returns {Promise} returns an object {address: '...', chain: , index: , publicKey: } */ async deriveAddress(chain, chainNode, index, type) { // Derive M/chain/index @@ -300,7 +307,8 @@ class HDAccountsHelper { const addr = { chain: chain, - index: index + index: index, + publicKey: indexNode.publicKey } switch (type) { @@ -344,6 +352,13 @@ class HDAccountsHelper { const info = this.classify(type) + // Detect postmix account + const index = node[2].index + const threshold = Math.pow(2,31) + const hardened = (index >= threshold) + const account = hardened ? (index - threshold) : index + const isPostmixAcct = account === this.POSTMIX_ACCT + // Node at M/chain const chainNode = node[chain] @@ -355,10 +370,18 @@ class HDAccountsHelper { ) { // Few addresses to be derived or external derivation deactivated // Let's do it here - let promises = indices.map(index => { + const addresses = await Promise.all(indices.map(index => { return this.deriveAddress(chain, chainNode, index, info.type) - }) - return Promise.all(promises) + })) + + // Generate additional change address types for postmix account + if (isPostmixAcct && chain === 1) { + const additionalPostmixAddresses = this.generateAdditionalChangeAddresses(addresses) + + addresses.push(...additionalPostmixAddresses) + } + + return addresses; } else { // Many addresses to be derived @@ -375,6 +398,13 @@ class HDAccountsHelper { const msg = await this.derivationPool.exec('deriveAddresses', [data]) if (msg.status === 'ok') { + // Generate additional change address types for postmix account + if (isPostmixAcct && chain === 1) { + const additionalPostmixAddresses = this.generateAdditionalChangeAddresses(msg.addresses) + + msg.addresses.push(...additionalPostmixAddresses) + } + resolve(msg.addresses) } else { Logger.error(null, 'HdAccountsHelper : A problem was met during parallel addresses derivation') @@ -393,6 +423,25 @@ class HDAccountsHelper { } } + /** + * @description Derive additional change addresses (P2PKH & P2SH) for postmix account + * @param addresses {object[]} - list of derived addresses + * @returns {Array} - array of additional address types + */ + generateAdditionalChangeAddresses(addresses) { + const additionalPostmixAddresses = addresses.map((address) => { + const newP2PKHAddress = {...address} + const newP2SHAddress = {...address} + + newP2PKHAddress.address = addrHelper.p2pkhAddress(address.publicKey) + newP2SHAddress.address = addrHelper.p2wpkhP2shAddress(address.publicKey) + + return [newP2PKHAddress, newP2SHAddress]; + }) + + return additionalPostmixAddresses.flat() + } + } module.exports = new HDAccountsHelper() diff --git a/lib/bitcoin/hd-accounts-service.js b/lib/bitcoin/hd-accounts-service.js index f85b79d..a1f704c 100644 --- a/lib/bitcoin/hd-accounts-service.js +++ b/lib/bitcoin/hd-accounts-service.js @@ -152,8 +152,8 @@ class HDAccountsService { /** * Rescan the blockchain for a hd account * @param {string} xpub - xpub - * @param {number} gapLimit - (optional) gap limit for derivation - * @param {number} startIndex - (optional) rescan shall start from this index + * @param {number=} gapLimit - (optional) gap limit for derivation + * @param {number=} startIndex - (optional) rescan shall start from this index * @returns {Promise} */ async rescan(xpub, gapLimit, startIndex) { diff --git a/lib/bitcoin/parallel-address-derivation.js b/lib/bitcoin/parallel-address-derivation.js index da2207a..9c2bc08 100644 --- a/lib/bitcoin/parallel-address-derivation.js +++ b/lib/bitcoin/parallel-address-derivation.js @@ -25,7 +25,7 @@ const BIP84 = 2 * @param {bip32} chainNode - Parent bip32 used for derivation * @param {number} index - index to be derived * @param {number} type - type of derivation - * @returns {Promise} returns an object {address: '...', chain: , index: } + * @returns {Promise} returns an object {address: '...', chain: , index: , publicKey: } */ async function deriveAddress(chain, chainNode, index, type) { // Derive M/chain/index @@ -33,7 +33,8 @@ async function deriveAddress(chain, chainNode, index, type) { const addr = { chain: chain, - index: index + index: index, + publicKey: indexNode.publicKey } switch (type) { diff --git a/tracker/transaction.js b/tracker/transaction.js index 7bf1f69..eedd7a3 100644 --- a/tracker/transaction.js +++ b/tracker/transaction.js @@ -365,7 +365,8 @@ class Transaction { const indices = _.range(minIdx, maxIdx) const derived = await hdaHelper.deriveAddresses(xpub, chain, indices, hdType) - Array.prototype.push.apply(newAddresses, derived) + + newAddresses.push(...derived) Logger.info(`Tracker : Derived hdID(${hdAccount.hdID}) M/${chain}/${indices.join(',')}`) From 7b7fcc94c85e0e23dd1636f89a49fc5844ee8ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0ev=C4=8D=C3=ADk?= Date: Tue, 6 Jul 2021 02:31:14 +0200 Subject: [PATCH 2/7] Add test for postmix change address derivation --- test/lib/bitcoin/hd-accounts-helper-test.js | 38 +++++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/test/lib/bitcoin/hd-accounts-helper-test.js b/test/lib/bitcoin/hd-accounts-helper-test.js index 280718c..0920b64 100644 --- a/test/lib/bitcoin/hd-accounts-helper-test.js +++ b/test/lib/bitcoin/hd-accounts-helper-test.js @@ -19,6 +19,8 @@ const XPUB = 'tpubDDDAe7GgFT4fzEzKwWVA4BWo8fiJXQeGEYDTexzo2w6CK1iDoLPYkpEisXo623 const YPUB = 'upub5ELkCsSF68UnAZE7zF9CDztvHeBJiAAhwa4VxEFzZ1CfQRbpy93mkBbUZsqYVpoeEHFwY3fGh9bfftH79ZwbhjUEUBAxQj551TMxVyny4UX' const ZPUB = 'vpub5ZB1WY7AEp2G1rREpbvpS5zRTcKkenACrgaijd9sw1aYTXR4DoDLNFFcb5o8VjTZdvNkHXFq9oxDZAtfsGMcVy9qLWsNzdtZHBRbtXe87LB' +const POSTMIX_ZPUB = 'vpub5Y6cjg7GbwSLRu33XB76n3EoJZscmYSVEToLSMqD6ugAcm4rof8E9yvDiaFfhGEuyL95P9VD4A9W3JrBTZhzWSXiRyYvWFnUBAZc67X32wh' + const BIP44_VECTORS = [ [0, 0, 'mmZ5FRccGAkwfKme4JkrsmurnimDLdfmNL'], [0, 1, 'n3yomLicyrSULiNWFKHsK8erntSpJZEPV6'], @@ -61,6 +63,27 @@ const BIP84_VECTORS = [ [1, 4, 'tb1qjrnw8u2pvspm6hq3aa83ff93wevq2zyxqczewy'] ] +const POSTMIX_VECTORS = [ + [1, 0, 'tb1qv3laps2vues6nh9fkxpds3wxd0cttd9jnr0772'], + [1, 1, 'tb1qz538rwwchv2unf97g4pugv3wjwxxjaypnwz8sk'], + [1, 2, 'tb1qdm3hfvw3knzujxx24g05e30kpe7vk0ez3dk0h8'], + [1, 3, 'tb1qxn4jgg5hgl3eggvt4alvraladpwq9pj30fy5ze'], + [1, 4, 'tb1qw2ghyxhqv5ysyehq9p9xwux4zqaf0mcwm29agh'], + + [1, 0, 'mpgLz1YXDU9buy7Zn8w9w9mJtrGghiXotH'], + [1, 1, 'mhShkJxHHgzJd2WcqeaKL4spqBMe1wcaK5'], + [1, 2, 'mqdH74foDiN8hV2mmFSHnceCm7vgErd4A2'], + [1, 3, 'mkLm7vUy1rij3YicskkQJxGovnGDG6G2oj'], + [1, 4, 'mqxjZfjdSdUmecTVALzhoQBPFRNvLViMBr'], + + [1, 0, '2N5UxwLfWexxHDm5MKHoyitRLWEK8x25tiA'], + [1, 1, '2N8wnnGoJujWGrM5YLs1nC1TFuszx2vJVA9'], + [1, 2, '2NA6Ja6PM6YMuQpSQdeWofKRV9pcBbz4aii'], + [1, 3, '2NFLd63BqGzh5BtfxobuU4dpoThg9sxMPth'], + [1, 4, '2NEeziC2dc3nbf9k3fyUWBzLWbn4MTrR2mm'] + +] + const HD_TYPES_VECTORS = [ // unlocked [0, hdaHelper.BIP44, false], @@ -74,7 +97,7 @@ const HD_TYPES_VECTORS = [ describe('HdAccountsHelper', function() { - + describe('isXpub()', function() { it('should successfully detect a XPUB', function() { assert(hdaHelper.isXpub(XPUB)) @@ -117,7 +140,7 @@ describe('HdAccountsHelper', function() { const ret = hdaHelper.classify(v[0]) assert(ret.type == v[1]) assert(ret.locked == v[2]) - } + } }) }) @@ -127,7 +150,7 @@ describe('HdAccountsHelper', function() { for (const v of HD_TYPES_VECTORS) { const ret = hdaHelper.makeType(v[1], v[2]) assert(ret == v[0]) - } + } }) }) @@ -153,6 +176,15 @@ describe('HdAccountsHelper', function() { assert(addresses[0].address == v[2]) } }) + + it('should successfully derive additional change address types for postmix account', async () => { + const addresses = await hdaHelper.deriveAddresses(POSTMIX_ZPUB, 1, [0, 1, 2, 3, 4], hdaHelper.BIP84) + + POSTMIX_VECTORS.forEach((vector) => { + assert(addresses.find((addr) => addr.index === vector[1])) + assert(addresses.find((addr) => addr.address === vector[2])) + }) + }) }) From 1e68aefe482afe05890c337efc0c2cd12feb03c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0ev=C4=8D=C3=ADk?= Date: Fri, 9 Jul 2021 00:19:43 +0200 Subject: [PATCH 3/7] Add ability to import addresses for like type change for existing postmix accounts --- accounts/wallet-rest-api.js | 10 ++++++- lib/bitcoin/hd-accounts-helper.js | 44 ++++++++++++++++++------------ lib/bitcoin/hd-accounts-service.js | 29 ++++++++++++++++++++ 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/accounts/wallet-rest-api.js b/accounts/wallet-rest-api.js index 685760d..fffce1f 100644 --- a/accounts/wallet-rest-api.js +++ b/accounts/wallet-rest-api.js @@ -11,10 +11,10 @@ const walletService = require('../lib/wallet/wallet-service') const authMgr = require('../lib/auth/authorizations-manager') const HttpServer = require('../lib/http-server/http-server') const apiHelper = require('./api-helper') +const hdaService = require('../lib/bitcoin/hd-accounts-service') const debugApi = process.argv.indexOf('api-debug') > -1 - /** * Wallet API endpoints */ @@ -60,6 +60,10 @@ class WalletRestApi { // Parse params const entities = apiHelper.parseEntitiesParams(req.query) + if (req.query.importPostmixLikeTypeChange) { + await hdaService.importPostmixLikeTypeChange(entities.active.xpubs) + } + const result = await walletService.getFullWalletInfo( entities.active, entities.legacy, @@ -102,6 +106,10 @@ class WalletRestApi { // Parse params const entities = apiHelper.parseEntitiesParams(req.body) + if (req.body.importPostmixLikeTypeChange) { + await hdaService.importPostmixLikeTypeChange(entities.active.xpubs) + } + const result = await walletService.getFullWalletInfo( entities.active, entities.legacy, diff --git a/lib/bitcoin/hd-accounts-helper.js b/lib/bitcoin/hd-accounts-helper.js index 114ce05..47ddd3c 100644 --- a/lib/bitcoin/hd-accounts-helper.js +++ b/lib/bitcoin/hd-accounts-helper.js @@ -283,7 +283,7 @@ class HDAccountsHelper { /** * Get the hd node associated to an hd account * @param {string} xpub - hd account - * @returns {bip32} + * @returns {[bitcoin.bip32.BIP32Interface, bitcoin.bip32.BIP32Interface, bitcoin.bip32.BIP32Interface]} */ getNode(xpub) { if (this.isValid(xpub)) @@ -296,10 +296,10 @@ class HDAccountsHelper { * Derives an address for an hd account * @param {number} chain - chain to be derived * must have a value on [0,1] for BIP44/BIP49/BIP84 derivation - * @param {bip32} chainNode - Parent bip32 used for derivation + * @param {bitcoin.bip32.BIP32Interface} chainNode - Parent bip32 used for derivation * @param {number} index - index to be derived * @param {number} type - type of derivation - * @returns {Promise} returns an object {address: '...', chain: , index: , publicKey: } + * @returns {Promise} returns an object {address: '...', chain: , index: , publicKey: , address: string } */ async deriveAddress(chain, chainNode, index, type) { // Derive M/chain/index @@ -333,7 +333,7 @@ class HDAccountsHelper { * must have a value on [0,1] for BIP44/BIP49/BIP84 derivation * @param {number[]} indices - array of indices to be derived * @param {number} type - type of derivation - * @returns {Promise} array of {address: '...', chain: , index: } + * @returns {Promise<{ chain: number, index: number, publicKey: Buffer, address: string }[]>} array of address objects */ async deriveAddresses(xpub, chain, indices, type) { const ret = [] @@ -352,13 +352,6 @@ class HDAccountsHelper { const info = this.classify(type) - // Detect postmix account - const index = node[2].index - const threshold = Math.pow(2,31) - const hardened = (index >= threshold) - const account = hardened ? (index - threshold) : index - const isPostmixAcct = account === this.POSTMIX_ACCT - // Node at M/chain const chainNode = node[chain] @@ -375,8 +368,8 @@ class HDAccountsHelper { })) // Generate additional change address types for postmix account - if (isPostmixAcct && chain === 1) { - const additionalPostmixAddresses = this.generateAdditionalChangeAddresses(addresses) + if (this.isPostmixAcct(node) && chain === 1) { + const additionalPostmixAddresses = this._generateAdditionalChangeAddresses(addresses) addresses.push(...additionalPostmixAddresses) } @@ -399,8 +392,8 @@ class HDAccountsHelper { if (msg.status === 'ok') { // Generate additional change address types for postmix account - if (isPostmixAcct && chain === 1) { - const additionalPostmixAddresses = this.generateAdditionalChangeAddresses(msg.addresses) + if (this.isPostmixAcct(node) && chain === 1) { + const additionalPostmixAddresses = this._generateAdditionalChangeAddresses(msg.addresses) msg.addresses.push(...additionalPostmixAddresses) } @@ -425,10 +418,11 @@ class HDAccountsHelper { /** * @description Derive additional change addresses (P2PKH & P2SH) for postmix account - * @param addresses {object[]} - list of derived addresses - * @returns {Array} - array of additional address types + * @param addresses {{ chain: number, index: number, publicKey: Buffer, address: string }[]} - list of derived addresses + * @returns {{ chain: number, index: number, publicKey: Buffer, address: string }[]} - array of additional address types + * @private */ - generateAdditionalChangeAddresses(addresses) { + _generateAdditionalChangeAddresses(addresses) { const additionalPostmixAddresses = addresses.map((address) => { const newP2PKHAddress = {...address} const newP2SHAddress = {...address} @@ -442,6 +436,20 @@ class HDAccountsHelper { return additionalPostmixAddresses.flat() } + /** + * @description Detect postmix account + * @param {[bitcoin.bip32.BIP32Interface, bitcoin.bip32.BIP32Interface, bitcoin.bip32.BIP32Interface]} node - array of BIP32 node interfaces + * @returns {boolean} + */ + isPostmixAcct(node) { + const index = node[2].index + const threshold = Math.pow(2,31) + const hardened = (index >= threshold) + const account = hardened ? (index - threshold) : index + + return account === this.POSTMIX_ACCT + } + } module.exports = new HDAccountsHelper() diff --git a/lib/bitcoin/hd-accounts-service.js b/lib/bitcoin/hd-accounts-service.js index a1f704c..3de162c 100644 --- a/lib/bitcoin/hd-accounts-service.js +++ b/lib/bitcoin/hd-accounts-service.js @@ -252,6 +252,35 @@ class HDAccountsService { } } + /** + * @description + * @param {string[]} xpubs - array of xpubs + * @returns {Promise} + */ + async importPostmixLikeTypeChange(xpubs) { + const postmixAcct = xpubs.find((xpub) => { + const node = hdaHelper.getNode(xpub) + + return hdaHelper.isPostmixAcct(node) + }) + + if (!postmixAcct) return Promise.resolve() + + const postmixNode = hdaHelper.getNode(postmixAcct) + const [externalUnused, internalUnused] = await db.getHDAccountNextUnusedIndices(postmixAcct) + + const deriveRange = Array.from({ length: gap.internal }, (_, i) => i + internalUnused) + + const likeTypeChangeAddresses = await Promise.all(deriveRange.map((index) => { + return [ + hdaHelper.deriveAddress(1, postmixNode[1], index, hdaHelper.BIP44), + hdaHelper.deriveAddress(1, postmixNode[1], index, hdaHelper.BIP49) + ] + }).flat()) + + await db.addAddressesToHDAccount(postmixAcct, likeTypeChangeAddresses) + } + } module.exports = new HDAccountsService() From 840b7fa26e37b3746069158071e3af388a4750a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0ev=C4=8D=C3=ADk?= Date: Mon, 16 Aug 2021 17:16:03 +0200 Subject: [PATCH 4/7] Added util function for range generation --- lib/util.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/util.js b/lib/util.js index 8a08080..ada81b4 100644 --- a/lib/util.js +++ b/lib/util.js @@ -351,6 +351,19 @@ class Util { } } + /** + * @description Generate array of sequential numbers from start to stop + * @param {number} start + * @param {number} stop + * @param {number=} step + * @returns {number[]} + */ + static range(start, stop, step = 1) { + return Array(Math.ceil((stop - start) / step)) + .fill(start) + .map((x, y) => x + y * step) + } + } /** From 859f06c79826ca7e6e1e50c314db29280cddf37d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0ev=C4=8D=C3=ADk?= Date: Mon, 16 Aug 2021 17:17:08 +0200 Subject: [PATCH 5/7] Look back when importing postmix like-type change addresses --- lib/bitcoin/hd-accounts-service.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/bitcoin/hd-accounts-service.js b/lib/bitcoin/hd-accounts-service.js index 3de162c..5503fdd 100644 --- a/lib/bitcoin/hd-accounts-service.js +++ b/lib/bitcoin/hd-accounts-service.js @@ -4,7 +4,7 @@ */ 'use strict' -const _ = require('lodash') +const util = require('../util') const errors = require('../errors') const Logger = require('../logger') const db = require('../db/mysql-db-wrapper') @@ -141,10 +141,10 @@ class HDAccountsService { Logger.info(`HdAccountsService : Created HD Account: ${xpub}${segwit}`) - const externalPrm = hdaHelper.deriveAddresses(xpub, 0, _.range(gap.external), scheme) - const internalPrm = hdaHelper.deriveAddresses(xpub, 1, _.range(gap.internal), scheme) + const externalPrm = hdaHelper.deriveAddresses(xpub, 0, util.range(0, gap.external), scheme) + const internalPrm = hdaHelper.deriveAddresses(xpub, 1, util.range(0, gap.internal), scheme) - const addresses = _.flatten(await Promise.all([externalPrm, internalPrm])) + const addresses = (await Promise.all([externalPrm, internalPrm])).flat() return db.addAddressesToHDAccount(xpub, addresses) } @@ -269,7 +269,7 @@ class HDAccountsService { const postmixNode = hdaHelper.getNode(postmixAcct) const [externalUnused, internalUnused] = await db.getHDAccountNextUnusedIndices(postmixAcct) - const deriveRange = Array.from({ length: gap.internal }, (_, i) => i + internalUnused) + const deriveRange = util.range(Math.max(0, internalUnused - 50), internalUnused + gap.internal) const likeTypeChangeAddresses = await Promise.all(deriveRange.map((index) => { return [ From b8fb11d42a0100834a9379fc8d2cdc7a2e0f8300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0ev=C4=8D=C3=ADk?= Date: Tue, 24 Aug 2021 17:21:28 +0200 Subject: [PATCH 6/7] Fix incorrect DOJO_NODEJS_VERSION_TAG --- docker/my-dojo/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/my-dojo/.env b/docker/my-dojo/.env index 34b7099..d28e976 100644 --- a/docker/my-dojo/.env +++ b/docker/my-dojo/.env @@ -13,7 +13,7 @@ COMPOSE_CONVERT_WINDOWS_PATHS=1 DOJO_VERSION_TAG=1.10.1 DOJO_DB_VERSION_TAG=1.3.0 DOJO_BITCOIND_VERSION_TAG=1.12.0 -DOJO_NODEJS_VERSION_TAG=1.10.0 +DOJO_NODEJS_VERSION_TAG=1.10.1 DOJO_NGINX_VERSION_TAG=1.6.0 DOJO_TOR_VERSION_TAG=1.10.0 DOJO_EXPLORER_VERSION_TAG=1.7.0 From d28e487720ad931a0e1a54f06ebde58bc134446f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0ev=C4=8D=C3=ADk?= Date: Tue, 24 Aug 2021 17:23:13 +0200 Subject: [PATCH 7/7] Send Dojo version in HTTP header field --- lib/http-server/http-server.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/http-server/http-server.js b/lib/http-server/http-server.js index a384f9f..3baf71c 100644 --- a/lib/http-server/http-server.js +++ b/lib/http-server/http-server.js @@ -9,7 +9,9 @@ const sirv = require('sirv') const helmet = require('helmet') const nocache = require('nocache') const Logger = require('../logger') -const errors = require('../errors'); +const errors = require('../errors') +const network = require("../../lib/bitcoin/network") +const keys = require('../../keys')[network.key] /** @@ -57,6 +59,11 @@ class HttpServer { this.app.use('/static', sirv('../static')); + this.app.use((req, res, next) => { + res.append('X-Dojo-Version', keys.dojoVersion) + next() + }) + this.app.use(HttpServer.setJSONResponse) this.app.use(HttpServer.setConnection) }