diff --git a/packages/bench-suite/lib/client/createClientWithFundedWallet.js b/packages/bench-suite/lib/client/createClientWithFundedWallet.js index 8070aae90fe..33fb6833afb 100644 --- a/packages/bench-suite/lib/client/createClientWithFundedWallet.js +++ b/packages/bench-suite/lib/client/createClientWithFundedWallet.js @@ -11,7 +11,7 @@ const createPlatformProofVerifier = require('./createPlatformProofVerifier'); * * @param {number} amount * @param {Object} config - * @param {{host: string, port: string}[]} config.seeds + * @param {RawDAPIAddress[]} config.seeds * @param {string} config.network * @param {string} config.faucetPrivateKey * @param {number} [config.skipSyncBeforeHeight] diff --git a/packages/bench-suite/lib/client/parseDAPISeedsString.js b/packages/bench-suite/lib/client/parseDAPISeedsString.js index c570feda361..924a92ff1cb 100644 --- a/packages/bench-suite/lib/client/parseDAPISeedsString.js +++ b/packages/bench-suite/lib/client/parseDAPISeedsString.js @@ -1,18 +1,13 @@ +const DAPIAddress = require('@dashevo/dapi-client/lib/dapiAddressProvider/DAPIAddress'); + /** * @param {string} seedsString - * @returns {{host: string, port: string}[]} + * @returns {RawDAPIAddress[]} */ function parseDAPISeedsString(seedsString) { return seedsString .split(',') - .map((seed) => { - const [host, port] = seed.split(':'); - - return { - host, - port, - }; - }); + .map((seed) => new DAPIAddress(seed).toJSON()); } module.exports = parseDAPISeedsString; diff --git a/packages/js-dapi-client/lib/dapiAddressProvider/ListDAPIAddressProvider.js b/packages/js-dapi-client/lib/dapiAddressProvider/ListDAPIAddressProvider.js index c13217e98d4..74fe7b2f181 100644 --- a/packages/js-dapi-client/lib/dapiAddressProvider/ListDAPIAddressProvider.js +++ b/packages/js-dapi-client/lib/dapiAddressProvider/ListDAPIAddressProvider.js @@ -1,5 +1,4 @@ const sample = (arr) => arr[Math.floor(Math.random() * arr.length)]; -const networks = require('@dashevo/dashcore-lib/lib/networks'); class ListDAPIAddressProvider { /** @@ -20,28 +19,7 @@ class ListDAPIAddressProvider { * @returns {Promise} */ async getLiveAddress() { - const liveAddresses = this.getLiveAddresses(); - - const liveAddress = sample(liveAddresses); - - if (liveAddress === undefined) { - return undefined; - } - - // This is a temporary fix for a localhost masternode. - // On macOS, internal docker IP is used to register masternode, and it's - // not really possible to bind to that address, so that workaround is introduced. - const network = networks.get(this.options.network); - if (network && network.regtestEnabled) { - const randomNodeIndex = Math.floor(Math.random() * liveAddresses.length); - - liveAddress.protocol = 'https'; - liveAddress.host = '127.0.0.1'; - liveAddress.allowSelfSignedCertificate = true; - liveAddress.port = 2443 + randomNodeIndex * 100; - } - - return liveAddress; + return sample(this.getLiveAddresses()); } /** diff --git a/packages/js-dapi-client/lib/dapiAddressProvider/SimplifiedMasternodeListDAPIAddressProvider.js b/packages/js-dapi-client/lib/dapiAddressProvider/SimplifiedMasternodeListDAPIAddressProvider.js index c6607e843eb..d6951b4581e 100644 --- a/packages/js-dapi-client/lib/dapiAddressProvider/SimplifiedMasternodeListDAPIAddressProvider.js +++ b/packages/js-dapi-client/lib/dapiAddressProvider/SimplifiedMasternodeListDAPIAddressProvider.js @@ -1,3 +1,5 @@ +const networks = require('@dashevo/dashcore-lib/lib/networks'); + const DAPIAddress = require('./DAPIAddress'); class SimplifiedMasternodeListDAPIAddressProvider { @@ -5,9 +7,11 @@ class SimplifiedMasternodeListDAPIAddressProvider { * @param {SimplifiedMasternodeListProvider} smlProvider * @param {ListDAPIAddressProvider} listDAPIAddressProvider * @param {DAPIAddress[]} addressWhiteList + * @param {DAPIClientOptions} [options] */ - constructor(smlProvider, listDAPIAddressProvider, addressWhiteList) { + constructor(smlProvider, listDAPIAddressProvider, addressWhiteList, options = {}) { this.smlProvider = smlProvider; + this.options = options; this.listDAPIAddressProvider = listDAPIAddressProvider; this.addressWhiteStrings = addressWhiteList.map((dapiAddress) => dapiAddress.toString()); } @@ -58,6 +62,18 @@ class SimplifiedMasternodeListDAPIAddressProvider { )); } + // Local (regtest) masternodes register a docker-internal IP that is not + // reachable from the host, while their gateways are published on the host's + // loopback at the registered port with a self-signed certificate. + const network = networks.get(this.options.network); + if (network && network.regtestEnabled) { + filteredAddresses.forEach((address) => { + address.setHost('127.0.0.1'); + // eslint-disable-next-line no-param-reassign + address.allowSelfSignedCertificate = true; + }); + } + this.listDAPIAddressProvider.setAddresses(filteredAddresses); return this.listDAPIAddressProvider.getLiveAddress(); diff --git a/packages/js-dapi-client/lib/dapiAddressProvider/createDAPIAddressProviderFromOptions.js b/packages/js-dapi-client/lib/dapiAddressProvider/createDAPIAddressProviderFromOptions.js index 5a02a00b58d..8e767f4ef27 100644 --- a/packages/js-dapi-client/lib/dapiAddressProvider/createDAPIAddressProviderFromOptions.js +++ b/packages/js-dapi-client/lib/dapiAddressProvider/createDAPIAddressProviderFromOptions.js @@ -94,6 +94,7 @@ function createDAPIAddressProviderFromOptions(options) { smlProvider, listDAPIAddressProvider, dapiAddressesWhiteList.map((rawAddress) => new DAPIAddress(rawAddress)), + options, ); } diff --git a/packages/js-dapi-client/lib/networkConfigs.js b/packages/js-dapi-client/lib/networkConfigs.js index e45953ac3a1..24fe3d6b0e4 100644 --- a/packages/js-dapi-client/lib/networkConfigs.js +++ b/packages/js-dapi-client/lib/networkConfigs.js @@ -40,7 +40,7 @@ module.exports = { ], }, local: { - dapiAddresses: ['127.0.0.1'], + dapiAddresses: ['127.0.0.1:2443:self-signed'], network: 'regtest', }, mainnet: { diff --git a/packages/js-dapi-client/test/unit/dapiAddressProvider/ListDAPIAddressProvider.spec.js b/packages/js-dapi-client/test/unit/dapiAddressProvider/ListDAPIAddressProvider.spec.js index 8b887a4ad78..619e4bf34c0 100644 --- a/packages/js-dapi-client/test/unit/dapiAddressProvider/ListDAPIAddressProvider.spec.js +++ b/packages/js-dapi-client/test/unit/dapiAddressProvider/ListDAPIAddressProvider.spec.js @@ -100,21 +100,15 @@ describe('ListDAPIAddressProvider', () => { expect(address).to.be.undefined(); }); - it('should return modified address for localhost node', async () => { - options = { - network: 'local', - }; - + it('should not modify addresses on regtest', async () => { listDAPIAddressProvider = new ListDAPIAddressProvider( - addresses, - options, + [new DAPIAddress('127.0.0.1:45003:no-ssl')], + { network: 'local' }, ); const liveAddress = await listDAPIAddressProvider.getLiveAddress(); - expect(liveAddress.host).to.equal('127.0.0.1'); - expect(liveAddress.protocol).to.equal('https'); - expect(liveAddress.allowSelfSignedCertificate).to.be.true(); + expect(liveAddress.toString()).to.equal('http://127.0.0.1:45003'); }); }); diff --git a/packages/js-dapi-client/test/unit/dapiAddressProvider/SimplifiedMasternodeListDAPIAddressProvider.spec.js b/packages/js-dapi-client/test/unit/dapiAddressProvider/SimplifiedMasternodeListDAPIAddressProvider.spec.js index f130795e44e..5192f449820 100644 --- a/packages/js-dapi-client/test/unit/dapiAddressProvider/SimplifiedMasternodeListDAPIAddressProvider.spec.js +++ b/packages/js-dapi-client/test/unit/dapiAddressProvider/SimplifiedMasternodeListDAPIAddressProvider.spec.js @@ -3,6 +3,7 @@ const SimplifiedMNListEntry = require('@dashevo/dashcore-lib/lib/deterministicmn const DAPIAddress = require('../../../lib/dapiAddressProvider/DAPIAddress'); const SimplifiedMasternodeListDAPIAddressProvider = require('../../../lib/dapiAddressProvider/SimplifiedMasternodeListDAPIAddressProvider'); +const ListDAPIAddressProvider = require('../../../lib/dapiAddressProvider/ListDAPIAddressProvider'); describe('SimplifiedMasternodeListDAPIAddressProvider', () => { let smlDAPIAddressProvider; @@ -196,6 +197,40 @@ describe('SimplifiedMasternodeListDAPIAddressProvider', () => { }); }); + describe('#getLiveAddress on regtest', () => { + it('should point discovered addresses to the local gateways', async () => { + const options = { network: 'local' }; + const listDAPIAddressProvider = new ListDAPIAddressProvider([], options); + + smlDAPIAddressProvider = new SimplifiedMasternodeListDAPIAddressProvider( + smlProviderMock, + listDAPIAddressProvider, + [], + options, + ); + + const expectedAddresses = validMasternodeList.map((smlEntry) => ({ + host: '127.0.0.1', + port: smlEntry.platformHTTPPort, + protocol: 'https', + allowSelfSignedCertificate: true, + proRegTxHash: smlEntry.proRegTxHash, + })); + + await smlDAPIAddressProvider.getLiveAddress(); + + const addressPool = listDAPIAddressProvider.getAllAddresses(); + expect(addressPool.map((address) => address.toJSON())).to.deep.equal(expectedAddresses); + + // A refresh reuses the same address objects, so their ban state is kept + await smlDAPIAddressProvider.getLiveAddress(); + + const refreshedPool = listDAPIAddressProvider.getAllAddresses(); + expect(refreshedPool.map((address) => address.toJSON())).to.deep.equal(expectedAddresses); + refreshedPool.forEach((address, index) => expect(address).to.equal(addressPool[index])); + }); + }); + describe('#hasLiveAddresses', () => { it('should return ListAddressProvider#hasLiveAddresses result', async () => { const result = await smlDAPIAddressProvider.hasLiveAddresses(); diff --git a/packages/js-dapi-client/test/unit/dapiAddressProvider/createDAPIAddressProviderFromOptions.spec.js b/packages/js-dapi-client/test/unit/dapiAddressProvider/createDAPIAddressProviderFromOptions.spec.js index 52710eec1bb..40e8c830cb1 100644 --- a/packages/js-dapi-client/test/unit/dapiAddressProvider/createDAPIAddressProviderFromOptions.spec.js +++ b/packages/js-dapi-client/test/unit/dapiAddressProvider/createDAPIAddressProviderFromOptions.spec.js @@ -144,6 +144,14 @@ describe('createDAPIAddressProviderFromOptions', () => { expect(result).to.be.an.instanceOf(SimplifiedMasternodeListDAPIAddressProvider); }); + it('should connect `local` network to the local gateway', async () => { + const liveAddress = await createDAPIAddressProviderFromOptions({ network: 'local' }) + .getLiveAddress(); + + expect(liveAddress.toString()).to.equal('https://127.0.0.1:2443'); + expect(liveAddress.isSelfSignedCertificateAllowed()).to.be.true(); + }); + it('should throw DAPIClientError if there is no config for a specified network', async () => { options.network = 'unknown';