@dashevo/dapi-client 0.24.0-dev.6 → 0.25.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,6 @@
1
1
  const { EventEmitter } = require('events');
2
+ const { BlockHeader } = require('@dashevo/dashcore-lib');
3
+ const GrpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes');
2
4
 
3
5
  const EVENTS = {
4
6
  BLOCK_HEADERS: 'BLOCK_HEADERS',
@@ -6,15 +8,8 @@ const EVENTS = {
6
8
  ERROR: 'error',
7
9
  };
8
10
 
9
- const COMMANDS = {
10
- HANDLE_FINISHED_STREAM: 'HANDLE_FINISHED_STREAM',
11
- HANDLE_STREAM_RETRY: 'HANDLE_STREAM_RETRY',
12
- HANDLE_STREAM_ERROR: 'HANDLE_STREAM_ERROR',
13
- };
14
-
15
11
  /**
16
12
  * @typedef BlockHeadersReaderOptions
17
- * @property {CoreMethodsFacade} [coreMethods]
18
13
  * @property {number} [maxParallelStreams]
19
14
  * @property {number} [targetBatchSize]
20
15
  * @property {number} [maxRetries]
@@ -23,10 +18,13 @@ const COMMANDS = {
23
18
  class BlockHeadersReader extends EventEmitter {
24
19
  /**
25
20
  * @param {BlockHeadersReaderOptions} options
21
+ * @param createHistoricalSyncStream
22
+ * @param createContinuousSyncStream
26
23
  */
27
- constructor(options = {}) {
24
+ constructor(options = {}, createHistoricalSyncStream, createContinuousSyncStream) {
28
25
  super();
29
- this.coreMethods = options.coreMethods;
26
+ this.createHistoricalSyncStream = createHistoricalSyncStream;
27
+ this.createContinuousSyncStream = createContinuousSyncStream;
30
28
  this.maxParallelStreams = options.maxParallelStreams;
31
29
  this.targetBatchSize = options.targetBatchSize;
32
30
  this.maxRetries = options.maxRetries;
@@ -34,9 +32,16 @@ class BlockHeadersReader extends EventEmitter {
34
32
  /**
35
33
  * Holds references to the historical streams
36
34
  *
37
- * @type {*[]}
35
+ * @type {Stream[]}
38
36
  */
39
37
  this.historicalStreams = [];
38
+
39
+ /**
40
+ * Holds reference to the continuous sync stream
41
+ *
42
+ * @type {Stream}
43
+ */
44
+ this.continuousSyncStream = null;
40
45
  }
41
46
 
42
47
  /**
@@ -48,52 +53,30 @@ class BlockHeadersReader extends EventEmitter {
48
53
  */
49
54
  async readHistorical(fromBlockHeight, toBlockHeight) {
50
55
  if (this.historicalStreams.length) {
51
- throw new Error('Historical streams are already running');
56
+ throw new Error('Historical streams are already running. Please stop them first.');
52
57
  }
53
58
 
54
- const totalAmount = toBlockHeight - fromBlockHeight + 1;
55
- if (totalAmount === 0) {
56
- return;
59
+ if (fromBlockHeight <= 0) {
60
+ throw new Error(`Invalid fromBlockHeight value: ${fromBlockHeight}`);
57
61
  }
58
62
 
59
- if (totalAmount < 0) {
63
+ const totalAmount = toBlockHeight - fromBlockHeight + 1;
64
+ if (totalAmount <= 0) {
60
65
  throw new Error(`Invalid total amount of headers to read: ${totalAmount}`);
61
66
  }
62
67
 
63
- // Resubscribe to the stream in case of error, and replace the stream in the array
64
- this.on(COMMANDS.HANDLE_STREAM_RETRY, (oldStream, newStream) => {
65
- const index = this.historicalStreams.indexOf(oldStream);
66
- this.historicalStreams[index] = newStream;
67
- });
68
-
69
- // Remove stream from the array in case of error
70
- this.on(COMMANDS.HANDLE_STREAM_ERROR, (stream, e) => {
71
- const index = this.historicalStreams.indexOf(stream);
72
- this.historicalStreams.splice(index, 1);
73
- this.emit(EVENTS.ERROR, e);
74
- });
75
-
76
- // Remove finished stream from the array and emit HISTORICAL_DATA_OBTAINED event
77
- this.on(COMMANDS.HANDLE_FINISHED_STREAM, (stream) => {
78
- const index = this.historicalStreams.indexOf(stream);
79
- this.historicalStreams.splice(index, 1);
80
- if (this.historicalStreams.length === 0) {
81
- this.emit(EVENTS.HISTORICAL_DATA_OBTAINED);
82
- }
83
- });
84
-
85
68
  const numStreams = Math.min(
86
69
  Math.max(Math.round(totalAmount / this.targetBatchSize), 1),
87
70
  this.maxParallelStreams,
88
71
  );
89
72
 
90
73
  const actualBatchSize = Math.ceil(totalAmount / numStreams);
74
+
91
75
  for (let batchIndex = 0; batchIndex < numStreams; batchIndex += 1) {
92
- const startingHeight = (batchIndex * actualBatchSize) + 1;
76
+ const startingHeight = (batchIndex * actualBatchSize) + fromBlockHeight;
93
77
  const count = Math.min(actualBatchSize, toBlockHeight - startingHeight + 1);
94
78
 
95
- const subscribeWithRetries = this.subscribeToHistoricalBatch(this.maxRetries);
96
-
79
+ const subscribeWithRetries = this.createSubscribeToHistoricalBatch(this.maxRetries);
97
80
  // eslint-disable-next-line no-await-in-loop
98
81
  const stream = await subscribeWithRetries(startingHeight, count);
99
82
  this.historicalStreams.push(stream);
@@ -101,48 +84,106 @@ class BlockHeadersReader extends EventEmitter {
101
84
  }
102
85
 
103
86
  stopReadingHistorical() {
104
- this.removeAllListeners(COMMANDS.HANDLE_STREAM_RETRY);
105
- this.removeAllListeners(COMMANDS.HANDLE_STREAM_ERROR);
106
- this.removeAllListeners(COMMANDS.HANDLE_FINISHED_STREAM);
107
- this.historicalStreams.forEach((stream) => stream.destroy());
108
- this.historicalStreams = [];
87
+ while (this.historicalStreams.length) {
88
+ const stream = this.historicalStreams.shift();
89
+ this.cancelStream(stream);
90
+ }
109
91
  }
110
92
 
111
93
  /**
112
94
  * Subscribes to continuously arriving block headers
113
95
  *
114
96
  * @param {number} fromBlockHeight
115
- * @returns {Promise<Stream>}
97
+ * @returns {Promise<ReconnectableStream>}
116
98
  */
117
99
  async subscribeToNew(fromBlockHeight) {
118
- const stream = await this.coreMethods.subscribeToBlockHeadersWithChainLocks({
119
- fromBlockHeight,
120
- });
100
+ if (this.continuousSyncStream) {
101
+ throw new Error('Continuous sync has already been started');
102
+ }
103
+
104
+ if (typeof fromBlockHeight !== 'number' || fromBlockHeight < 1) {
105
+ throw new Error(`Invalid fromBlockHeight: ${fromBlockHeight}`);
106
+ }
121
107
 
122
- stream.on('data', (data) => {
123
- const blockHeaders = data.getBlockHeaders();
108
+ // We don't know yet whether we already have header at fromBlockHeight
109
+ let lastKnownChainHeight = fromBlockHeight - 1;
110
+
111
+ const stream = await this.createContinuousSyncStream(fromBlockHeight);
112
+
113
+ const errorHandler = (e) => {
114
+ this.continuousSyncStream = null;
115
+ if (e.code === GrpcErrorCodes.CANCELLED) {
116
+ return;
117
+ }
118
+ this.emit(EVENTS.ERROR, e);
119
+ };
120
+
121
+ const dataHandler = (data) => {
122
+ const blockHeadersResponse = data.getBlockHeaders();
123
+
124
+ if (blockHeadersResponse) {
125
+ const rawHeaders = blockHeadersResponse.getHeadersList();
126
+
127
+ const headers = rawHeaders.map((header) => new BlockHeader(Buffer.from(header)));
128
+
129
+ lastKnownChainHeight += headers.length;
130
+ const batchHeadHeight = lastKnownChainHeight - headers.length + 1;
124
131
 
125
- if (blockHeaders) {
126
132
  /**
127
133
  * Kills stream in case of deliberate rejection from the outside
128
134
  *
129
135
  * @param e
130
136
  */
131
- const rejectHeaders = (e) => {
132
- stream.destroy(e);
137
+ const rejectHeaders = async (e) => {
138
+ // Don't use cancelStream there because it's going to unsubscribe from events
139
+ stream.cancel();
140
+ stream.retryOnError(e);
133
141
  };
134
142
 
135
- this.emit(EVENTS.BLOCK_HEADERS, blockHeaders.getHeadersList(), rejectHeaders);
143
+ this.emit(EVENTS.BLOCK_HEADERS, {
144
+ headers,
145
+ headHeight: batchHeadHeight,
146
+ }, rejectHeaders);
136
147
  }
137
- });
148
+ };
138
149
 
139
- stream.on('error', (e) => {
140
- this.emit(EVENTS.ERROR, e);
141
- });
150
+ const beforeReconnectHandler = (updateArguments) => {
151
+ updateArguments({
152
+ fromBlockHeight: lastKnownChainHeight,
153
+ count: 0,
154
+ });
155
+
156
+ lastKnownChainHeight -= 1;
157
+ };
142
158
 
159
+ const endHandler = () => {
160
+ this.continuousSyncStream = null;
161
+ };
162
+
163
+ stream.on('data', dataHandler);
164
+ stream.on('beforeReconnect', beforeReconnectHandler);
165
+ stream.on('error', errorHandler);
166
+ stream.on('end', endHandler);
167
+
168
+ stream.removeAllListeners = () => {
169
+ stream.removeListener('data', dataHandler);
170
+ stream.removeListener('end', endHandler);
171
+ stream.removeListener('beforeReconnect', beforeReconnectHandler);
172
+ };
173
+
174
+ this.continuousSyncStream = stream;
143
175
  return stream;
144
176
  }
145
177
 
178
+ unsubscribeFromNew() {
179
+ if (this.continuousSyncStream) {
180
+ this.cancelStream(this.continuousSyncStream);
181
+ this.continuousSyncStream = null;
182
+ }
183
+ }
184
+
185
+ // TODO: refactor whole thing with ReconnectableStream that supports
186
+ // retry on error logic
146
187
  /**
147
188
  * A HOF that returns a function to subscribe to historical block headers and chain locks
148
189
  * and handles retry logic
@@ -151,7 +192,7 @@ class BlockHeadersReader extends EventEmitter {
151
192
  * @param {number} [maxRetries=0] - maximum amount of retries
152
193
  * @returns {function(*, *): Promise<Stream>}
153
194
  */
154
- subscribeToHistoricalBatch(maxRetries = 0) {
195
+ createSubscribeToHistoricalBatch(maxRetries = 0) {
155
196
  let currentRetries = 0;
156
197
 
157
198
  /**
@@ -164,16 +205,45 @@ class BlockHeadersReader extends EventEmitter {
164
205
  const subscribeWithRetries = async (fromBlockHeight, count) => {
165
206
  let headersObtained = 0;
166
207
 
167
- const stream = await this.coreMethods.subscribeToBlockHeadersWithChainLocks({
168
- fromBlockHeight,
169
- count,
170
- });
208
+ const stream = await this.createHistoricalSyncStream(fromBlockHeight, count);
209
+
210
+ const errorHandler = (streamError) => {
211
+ if (streamError.code === GrpcErrorCodes.CANCELLED) {
212
+ // TODO: consider reworking with COMMANDS instead
213
+ // of producing a side effect that alters class state
214
+ const index = this.historicalStreams.indexOf(stream);
215
+ if (index >= 0) {
216
+ this.historicalStreams.splice(index, 1);
217
+ }
218
+ return;
219
+ }
220
+
221
+ if (currentRetries < maxRetries) {
222
+ const newFromBlockHeight = fromBlockHeight + headersObtained;
223
+ const newCount = count - headersObtained;
224
+
225
+ // TODO: do not retry in case newCount is zero
226
+ subscribeWithRetries(newFromBlockHeight, newCount)
227
+ .then((newStream) => {
228
+ const index = this.historicalStreams.indexOf(stream);
229
+ this.historicalStreams[index] = newStream;
230
+ currentRetries += 1;
231
+ }).catch((e) => {
232
+ this.stopReadingHistorical();
233
+ this.emit(EVENTS.ERROR, e);
234
+ });
235
+ } else {
236
+ this.stopReadingHistorical();
237
+ this.emit(EVENTS.ERROR, streamError);
238
+ }
239
+ };
171
240
 
172
- stream.on('data', (data) => {
241
+ const dataHandler = (data) => {
173
242
  const blockHeaders = data.getBlockHeaders();
174
243
 
175
244
  if (blockHeaders) {
176
- const headersList = blockHeaders.getHeadersList();
245
+ const headersList = blockHeaders.getHeadersList()
246
+ .map((header) => new BlockHeader(Buffer.from(header)));
177
247
 
178
248
  let rejected = false;
179
249
 
@@ -184,46 +254,58 @@ class BlockHeadersReader extends EventEmitter {
184
254
  */
185
255
  const rejectHeaders = (e) => {
186
256
  rejected = true;
187
- stream.destroy(e);
257
+ // Cancel stream and unsubscribe from all data events
258
+ // because they are going th be re-created in errorHandler
259
+ this.cancelStream(stream);
260
+ errorHandler(e);
188
261
  };
189
262
 
190
- this.emit(EVENTS.BLOCK_HEADERS, headersList, rejectHeaders);
263
+ const batchHeadHeight = fromBlockHeight + headersObtained;
264
+ this.emit(EVENTS.BLOCK_HEADERS, {
265
+ headers: headersList,
266
+ headHeight: batchHeadHeight,
267
+ }, rejectHeaders);
191
268
 
192
269
  if (!rejected) {
193
270
  headersObtained += headersList.length;
194
271
  }
195
272
  }
196
- });
273
+ };
197
274
 
198
- stream.on('error', (streamError) => {
199
- if (currentRetries < maxRetries) {
200
- const newFromBlockHeight = fromBlockHeight + headersObtained;
201
- const newCount = count - headersObtained;
202
-
203
- subscribeWithRetries(newFromBlockHeight, newCount)
204
- .then((newStream) => {
205
- currentRetries += 1;
206
- this.emit(COMMANDS.HANDLE_STREAM_RETRY, stream, newStream);
207
- }).catch((e) => {
208
- this.emit(COMMANDS.HANDLE_STREAM_ERROR, stream, e);
209
- });
210
- } else {
211
- this.emit(COMMANDS.HANDLE_STREAM_ERROR, stream, streamError);
275
+ const endHandler = () => {
276
+ const index = this.historicalStreams.indexOf(stream);
277
+ this.historicalStreams.splice(index, 1);
278
+ if (this.historicalStreams.length === 0) {
279
+ this.emit(EVENTS.HISTORICAL_DATA_OBTAINED);
212
280
  }
213
- });
281
+ };
214
282
 
215
- stream.on('end', () => {
216
- this.emit(COMMANDS.HANDLE_FINISHED_STREAM, stream);
217
- });
283
+ // TODO: consider reworking with "pasued" mode to
284
+ // control the data flow manually because SPV verification is
285
+ // resource intense and backpressure could be a problem
286
+ // also the whole thing severely affects UI responsiveness
287
+ stream.on('data', dataHandler);
288
+ stream.on('error', errorHandler);
289
+ stream.on('end', endHandler);
290
+
291
+ stream.removeAllListeners = () => {
292
+ stream.removeListener('data', dataHandler);
293
+ stream.removeListener('end', endHandler);
294
+ };
218
295
 
219
296
  return stream;
220
297
  };
221
298
 
222
299
  return subscribeWithRetries;
223
300
  }
301
+
302
+ // eslint-disable-next-line class-methods-use-this
303
+ cancelStream(stream) {
304
+ stream.removeAllListeners();
305
+ stream.cancel();
306
+ }
224
307
  }
225
308
 
226
309
  BlockHeadersReader.EVENTS = EVENTS;
227
- BlockHeadersReader.COMMANDS = COMMANDS;
228
310
 
229
311
  module.exports = BlockHeadersReader;
@@ -1,6 +1,6 @@
1
- const networks = require('@dashevo/dashcore-lib/lib/networks');
2
1
  const DAPIClientError = require('../errors/DAPIClientError');
3
2
  const BlockHeadersProvider = require('./BlockHeadersProvider');
3
+ const ReconnectableStream = require('../transport/ReconnectableStream');
4
4
 
5
5
  const validateNumber = (value, name, min = NaN, max = NaN) => {
6
6
  if (typeof value !== 'number') {
@@ -11,7 +11,7 @@ const validateNumber = (value, name, min = NaN, max = NaN) => {
11
11
  throw new DAPIClientError(`'${name}' can not be less than ${min}`);
12
12
  }
13
13
 
14
- if (!Number.isNaN(max) && value > min) {
14
+ if (!Number.isNaN(max) && value > max) {
15
15
  throw new DAPIClientError(`'${name}' can not be more than ${max}`);
16
16
  }
17
17
  };
@@ -32,45 +32,60 @@ function createBlockHeadersProviderFromOptions(options, coreMethods) {
32
32
  blockHeadersProvider = options.blockHeadersProvider;
33
33
  }
34
34
 
35
+ const createContinuousSyncStream = (fromBlockHeight) => ReconnectableStream
36
+ .create(
37
+ coreMethods.subscribeToBlockHeadersWithChainLocks,
38
+ {
39
+ maxRetriesOnError: -1,
40
+ },
41
+ )({
42
+ fromBlockHeight,
43
+ });
44
+
45
+ const createHistoricalSyncStream = (fromBlockHeight, count) => {
46
+ const { subscribeToBlockHeadersWithChainLocks } = coreMethods;
47
+ return subscribeToBlockHeadersWithChainLocks({
48
+ fromBlockHeight,
49
+ count,
50
+ });
51
+ };
52
+
35
53
  if (options.blockHeadersProviderOptions) {
54
+ const { network } = options;
55
+
36
56
  const blockHeadersProviderOptions = {
37
57
  ...BlockHeadersProvider.defaultOptions,
38
58
  ...options.blockHeadersProviderOptions,
59
+ network,
39
60
  };
40
61
 
41
62
  const {
42
- network,
43
- autoStart,
44
63
  maxParallelStreams,
45
64
  targetBatchSize,
46
65
  fromBlockHeight,
47
66
  maxRetries,
48
67
  } = blockHeadersProviderOptions;
49
68
 
50
- if (network && !networks.get(network)) {
51
- throw new DAPIClientError(`Invalid network '${options.network}'`);
52
- }
53
-
54
- if (typeof autoStart !== 'boolean') {
55
- throw new DAPIClientError('\'autoStart\' option must have boolean type');
56
- }
57
-
58
69
  validateNumber(maxParallelStreams, 'maxParallelStreams', 1);
59
70
  validateNumber(targetBatchSize, 'targetBatchSize', 1);
60
71
  validateNumber(fromBlockHeight, 'fromBlockHeight', 1);
61
- validateNumber(maxRetries, 'maxRetries', 0);
72
+ validateNumber(maxRetries, 'maxRetries', 0, 100);
62
73
 
63
74
  blockHeadersProvider = new BlockHeadersProvider(
64
75
  blockHeadersProviderOptions,
76
+ createHistoricalSyncStream,
77
+ createContinuousSyncStream,
65
78
  );
66
79
  }
67
80
 
68
81
  if (!blockHeadersProvider) {
69
- blockHeadersProvider = new BlockHeadersProvider();
82
+ blockHeadersProvider = new BlockHeadersProvider(
83
+ {},
84
+ createContinuousSyncStream,
85
+ createHistoricalSyncStream,
86
+ );
70
87
  }
71
88
 
72
- blockHeadersProvider.setCoreMethods(coreMethods);
73
-
74
89
  return blockHeadersProvider;
75
90
  }
76
91
 
package/lib/DAPIClient.js CHANGED
@@ -65,12 +65,6 @@ class DAPIClient extends EventEmitter {
65
65
  this.blockHeadersProvider.on(BlockHeadersProvider.EVENTS.ERROR, (e) => {
66
66
  this.emit(EVENTS.ERROR, e);
67
67
  });
68
-
69
- if (this.options.blockHeadersProviderOptions.autoStart) {
70
- this.blockHeadersProvider.start().catch((e) => {
71
- this.emit(EVENTS.ERROR, e);
72
- });
73
- }
74
68
  }
75
69
  }
76
70
 
@@ -10,13 +10,12 @@ class DAPIAddress {
10
10
  }
11
11
 
12
12
  if (typeof address === 'string') {
13
- const [host, httpPort, grpcPort, ssl] = address.split(':');
13
+ const [host, port, ssl] = address.split(':');
14
14
 
15
15
  // eslint-disable-next-line no-param-reassign
16
16
  address = {
17
17
  host,
18
- httpPort: httpPort ? parseInt(httpPort, 10) : DAPIAddress.DEFAULT_HTTP_PORT,
19
- grpcPort: grpcPort ? parseInt(grpcPort, 10) : DAPIAddress.DEFAULT_GRPC_PORT,
18
+ port: port ? parseInt(port, 10) : DAPIAddress.DEFAULT_PORT,
20
19
  protocol: ssl === 'no-ssl' ? 'http' : DAPIAddress.DEFAULT_PROTOCOL,
21
20
  allowSelfSignedCertificate: ssl === 'self-signed',
22
21
  };
@@ -28,8 +27,7 @@ class DAPIAddress {
28
27
 
29
28
  this.protocol = address.protocol || DAPIAddress.DEFAULT_PROTOCOL;
30
29
  this.host = address.host;
31
- this.httpPort = address.httpPort || DAPIAddress.DEFAULT_HTTP_PORT;
32
- this.grpcPort = address.grpcPort || DAPIAddress.DEFAULT_GRPC_PORT;
30
+ this.port = address.port || DAPIAddress.DEFAULT_PORT;
33
31
  this.proRegTxHash = address.proRegTxHash;
34
32
  this.allowSelfSignedCertificate = address.allowSelfSignedCertificate || false;
35
33
 
@@ -68,43 +66,22 @@ class DAPIAddress {
68
66
  }
69
67
 
70
68
  /**
71
- * Get HTTP port
69
+ * Get port
72
70
  *
73
71
  * @returns {number}
74
72
  */
75
- getHttpPort() {
76
- return this.httpPort;
73
+ getPort() {
74
+ return this.port;
77
75
  }
78
76
 
79
77
  /**
80
- * Set HTTP port
78
+ * Set port
81
79
  *
82
80
  * @param {number} port
83
81
  * @returns {DAPIAddress}
84
82
  */
85
- setHttpPort(port) {
86
- this.httpPort = port;
87
-
88
- return this;
89
- }
90
-
91
- /**
92
- * Get gRPC port
93
- *
94
- * @returns {number}
95
- */
96
- getGrpcPort() {
97
- return this.grpcPort;
98
- }
99
-
100
- /**
101
- * Set gRPC port
102
- *
103
- * @param {number} port
104
- * @returns {DAPIAddress}
105
- */
106
- setGrpcPort(port) {
107
- this.grpcPort = port;
83
+ setPort(port) {
84
+ this.port = port;
108
85
 
109
86
  return this;
110
87
  }
@@ -179,28 +156,25 @@ class DAPIAddress {
179
156
  return {
180
157
  protocol: this.getProtocol(),
181
158
  host: this.getHost(),
182
- httpPort: this.getHttpPort(),
183
- grpcPort: this.getGrpcPort(),
159
+ port: this.getPort(),
184
160
  proRegTxHash: this.getProRegTxHash(),
185
161
  allowSelfSignedCertificate: this.isSelfSignedCertificateAllowed(),
186
162
  };
187
163
  }
188
164
 
189
165
  toString() {
190
- return `${this.getProtocol()}://${this.getHost()}:${this.getHttpPort()}:${this.getGrpcPort()}`;
166
+ return `${this.getProtocol()}://${this.getHost()}:${this.getPort()}`;
191
167
  }
192
168
  }
193
169
 
194
- DAPIAddress.DEFAULT_HTTP_PORT = 3000;
195
- DAPIAddress.DEFAULT_GRPC_PORT = 3010;
196
- DAPIAddress.DEFAULT_PROTOCOL = 'http';
170
+ DAPIAddress.DEFAULT_PORT = 443;
171
+ DAPIAddress.DEFAULT_PROTOCOL = 'https';
197
172
 
198
173
  /**
199
174
  * @typedef {object} RawDAPIAddress
200
175
  * @property {string} protocol
201
176
  * @property {string} host
202
- * @property {number} [httpPort=3000]
203
- * @property {number} [grpcPort=3010]
177
+ * @property {number} [port=443]
204
178
  * @property {string} [proRegTxHash]
205
179
  * @property {bool} [selfSigned]
206
180
  */
@@ -1,4 +1,4 @@
1
- const sample = require('lodash.sample');
1
+ const sample = require('lodash/sample');
2
2
  const networks = require('@dashevo/dashcore-lib/lib/networks');
3
3
 
4
4
  class ListDAPIAddressProvider {
@@ -30,7 +30,7 @@ class ListDAPIAddressProvider {
30
30
  }
31
31
 
32
32
  // This is a temporary fix for a localhost masternode.
33
- // On mac os, internal docker IP is used to register masternode, and it's
33
+ // On macOS, internal docker IP is used to register masternode, and it's
34
34
  // not really possible to bind to that address, so that workaround is introduced.
35
35
  const network = networks.get(this.options.network);
36
36
  if (network && network.regtestEnabled) {
@@ -39,8 +39,7 @@ class ListDAPIAddressProvider {
39
39
  liveAddress.protocol = 'https';
40
40
  liveAddress.host = '127.0.0.1';
41
41
  liveAddress.allowSelfSignedCertificate = true;
42
- liveAddress.httpPort = 3000 + randomNodeIndex * 100;
43
- liveAddress.grpcPort = 3010 + randomNodeIndex * 100;
42
+ liveAddress.port = 2443 + randomNodeIndex * 100;
44
43
  }
45
44
 
46
45
  return liveAddress;
@@ -19,10 +19,15 @@ class SimplifiedMasternodeListDAPIAddressProvider {
19
19
  */
20
20
  async getLiveAddress() {
21
21
  const sml = await this.smlProvider.getSimplifiedMNList();
22
- const validMasternodeList = sml.getValidMasternodesList();
22
+ const validMasternodeList = sml.getValidMasternodesList()
23
+ // Keep only HP masternodes
24
+ .filter((smlEntry) => smlEntry.nType === 1);
23
25
 
24
26
  const addressesByRegProTxHashes = {};
27
+ let allowSelfSignedCertificate;
25
28
  this.listDAPIAddressProvider.getAllAddresses().forEach((address) => {
29
+ allowSelfSignedCertificate = address.isSelfSignedCertificateAllowed();
30
+
26
31
  if (!address.getProRegTxHash()) {
27
32
  return;
28
33
  }
@@ -36,6 +41,8 @@ class SimplifiedMasternodeListDAPIAddressProvider {
36
41
  if (!address) {
37
42
  address = new DAPIAddress({
38
43
  host: smlEntry.getIp(),
44
+ port: smlEntry.platformHTTPPort,
45
+ allowSelfSignedCertificate,
39
46
  proRegTxHash: smlEntry.proRegTxHash,
40
47
  });
41
48
  } else {
package/lib/index.js CHANGED
@@ -1,9 +1,14 @@
1
+ require('../polyfills/fetch-polyfill');
2
+
1
3
  const DAPIClient = require('./DAPIClient');
2
4
 
3
5
  const NotFoundError = require('./transport/GrpcTransport/errors/NotFoundError');
6
+ const BlockHeadersProvider = require('./BlockHeadersProvider/BlockHeadersProvider');
4
7
 
5
8
  DAPIClient.Errors = {
6
9
  NotFoundError,
7
10
  };
8
11
 
12
+ DAPIClient.BlockHeadersProvider = BlockHeadersProvider;
13
+
9
14
  module.exports = DAPIClient;