psf-bch-api 1.2.0 → 1.3.0
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.
- package/.env-local +9 -0
- package/bin/server.js +2 -1
- package/package.json +4 -1
- package/src/adapters/fulcrum-api.js +124 -0
- package/src/adapters/full-node-rpc.js +2 -6
- package/src/adapters/index.js +4 -0
- package/src/adapters/slp-indexer-api.js +124 -0
- package/src/config/env/common.js +21 -24
- package/src/controllers/rest-api/fulcrum/controller.js +563 -0
- package/src/controllers/rest-api/fulcrum/router.js +64 -0
- package/src/controllers/rest-api/full-node/blockchain/controller.js +4 -4
- package/src/controllers/rest-api/full-node/mining/controller.js +99 -0
- package/src/controllers/rest-api/full-node/mining/router.js +52 -0
- package/src/controllers/rest-api/full-node/rawtransactions/controller.js +333 -0
- package/src/controllers/rest-api/full-node/rawtransactions/router.js +58 -0
- package/src/controllers/rest-api/index.js +19 -3
- package/src/controllers/rest-api/slp/controller.js +218 -0
- package/src/controllers/rest-api/slp/router.js +55 -0
- package/src/controllers/timer-controller.js +1 -1
- package/src/use-cases/fulcrum-use-cases.js +155 -0
- package/src/use-cases/full-node-mining-use-cases.js +28 -0
- package/src/use-cases/full-node-rawtransactions-use-cases.js +121 -0
- package/src/use-cases/index.js +8 -0
- package/src/use-cases/slp-use-cases.js +321 -0
- package/test/unit/controllers/blockchain-controller-unit.js +2 -3
- package/test/unit/controllers/fulcrum-controller-unit.js +481 -0
- package/test/unit/controllers/mining-controller-unit.js +139 -0
- package/test/unit/controllers/rawtransactions-controller-unit.js +388 -0
- package/test/unit/controllers/rest-api-index-unit.js +59 -3
- package/test/unit/controllers/slp-controller-unit.js +312 -0
- package/test/unit/use-cases/fulcrum-use-cases-unit.js +297 -0
- package/test/unit/use-cases/full-node-mining-use-cases-unit.js +84 -0
- package/test/unit/use-cases/full-node-rawtransactions-use-cases-unit.js +267 -0
- package/test/unit/use-cases/slp-use-cases-unit.js +296 -0
- package/src/entities/event.js +0 -71
- package/test/integration/api/event-integration.js +0 -250
- package/test/integration/api/req-integration.js +0 -173
- package/test/integration/api/subscription-integration.js +0 -198
- package/test/integration/use-cases/manage-subscription-integration.js +0 -163
- package/test/integration/use-cases/publish-event-integration.js +0 -104
- package/test/integration/use-cases/query-events-integration.js +0 -95
- package/test/unit/entities/event-unit.js +0 -139
- /package/src/controllers/rest-api/full-node/blockchain/{index.js → router.js} +0 -0
- /package/src/controllers/rest-api/full-node/control/{index.js → router.js} +0 -0
- /package/src/controllers/rest-api/full-node/dsproof/{index.js → router.js} +0 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Unit tests for FulcrumRESTController.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { assert } from 'chai'
|
|
6
|
+
import sinon from 'sinon'
|
|
7
|
+
|
|
8
|
+
import FulcrumRESTController from '../../../src/controllers/rest-api/fulcrum/controller.js'
|
|
9
|
+
import {
|
|
10
|
+
createMockRequest,
|
|
11
|
+
createMockResponse
|
|
12
|
+
} from '../mocks/controller-mocks.js'
|
|
13
|
+
|
|
14
|
+
// Valid mainnet cash address for testing
|
|
15
|
+
const VALID_MAINNET_ADDRESS = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
|
|
16
|
+
|
|
17
|
+
describe('#fulcrum-controller.js', () => {
|
|
18
|
+
let sandbox
|
|
19
|
+
let mockUseCases
|
|
20
|
+
let mockAdapters
|
|
21
|
+
let uut
|
|
22
|
+
|
|
23
|
+
const createFulcrumUseCaseStubs = () => ({
|
|
24
|
+
getBalance: sandbox.stub().resolves({ balance: 1000 }),
|
|
25
|
+
getBalances: sandbox.stub().resolves({ balances: [] }),
|
|
26
|
+
getUtxos: sandbox.stub().resolves({ utxos: [] }),
|
|
27
|
+
getUtxosBulk: sandbox.stub().resolves({ utxos: [] }),
|
|
28
|
+
getTransactionDetails: sandbox.stub().resolves({ txid: 'abc' }),
|
|
29
|
+
getTransactionDetailsBulk: sandbox.stub().resolves({ transactions: [] }),
|
|
30
|
+
broadcastTransaction: sandbox.stub().resolves({ txid: 'abc' }),
|
|
31
|
+
getBlockHeaders: sandbox.stub().resolves({ headers: [] }),
|
|
32
|
+
getBlockHeadersBulk: sandbox.stub().resolves({ headers: [] }),
|
|
33
|
+
getTransactions: sandbox.stub().resolves({ transactions: [] }),
|
|
34
|
+
getTransactionsBulk: sandbox.stub().resolves({ transactions: [] }),
|
|
35
|
+
getMempool: sandbox.stub().resolves({ mempool: [] }),
|
|
36
|
+
getMempoolBulk: sandbox.stub().resolves({ mempool: [] })
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
sandbox = sinon.createSandbox()
|
|
41
|
+
mockAdapters = {
|
|
42
|
+
fullNode: {
|
|
43
|
+
validateArraySize: sandbox.stub().returns(true)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
mockUseCases = {
|
|
47
|
+
fulcrum: createFulcrumUseCaseStubs()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
uut = new FulcrumRESTController({
|
|
51
|
+
adapters: mockAdapters,
|
|
52
|
+
useCases: mockUseCases
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
sandbox.restore()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('#constructor()', () => {
|
|
61
|
+
it('should require adapters', () => {
|
|
62
|
+
assert.throws(() => {
|
|
63
|
+
// eslint-disable-next-line no-new
|
|
64
|
+
new FulcrumRESTController({ useCases: mockUseCases })
|
|
65
|
+
}, /Adapters library required/)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('should require fulcrum use cases', () => {
|
|
69
|
+
assert.throws(() => {
|
|
70
|
+
// eslint-disable-next-line no-new
|
|
71
|
+
new FulcrumRESTController({ adapters: mockAdapters, useCases: {} })
|
|
72
|
+
}, /Fulcrum use cases required/)
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe('#root()', () => {
|
|
77
|
+
it('should return service status', async () => {
|
|
78
|
+
const req = createMockRequest()
|
|
79
|
+
const res = createMockResponse()
|
|
80
|
+
|
|
81
|
+
await uut.root(req, res)
|
|
82
|
+
|
|
83
|
+
assert.equal(res.statusValue, 200)
|
|
84
|
+
assert.deepEqual(res.jsonData, { status: 'fulcrum' })
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
describe('#getBalance()', () => {
|
|
89
|
+
it('should return balance on success', async () => {
|
|
90
|
+
const req = createMockRequest({
|
|
91
|
+
params: { address: VALID_MAINNET_ADDRESS }
|
|
92
|
+
})
|
|
93
|
+
const res = createMockResponse()
|
|
94
|
+
|
|
95
|
+
await uut.getBalance(req, res)
|
|
96
|
+
|
|
97
|
+
assert.equal(res.statusValue, 200)
|
|
98
|
+
assert.deepEqual(res.jsonData, { balance: 1000 })
|
|
99
|
+
assert.isTrue(mockUseCases.fulcrum.getBalance.calledOnce)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('should return error if address is array', async () => {
|
|
103
|
+
const req = createMockRequest({
|
|
104
|
+
params: { address: [] }
|
|
105
|
+
})
|
|
106
|
+
const res = createMockResponse()
|
|
107
|
+
|
|
108
|
+
await uut.getBalance(req, res)
|
|
109
|
+
|
|
110
|
+
assert.equal(res.statusValue, 400)
|
|
111
|
+
assert.property(res.jsonData, 'error')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('should handle errors via handleError', async () => {
|
|
115
|
+
const error = new Error('failure')
|
|
116
|
+
error.status = 503
|
|
117
|
+
mockUseCases.fulcrum.getBalance.rejects(error)
|
|
118
|
+
const req = createMockRequest({
|
|
119
|
+
params: { address: VALID_MAINNET_ADDRESS }
|
|
120
|
+
})
|
|
121
|
+
const res = createMockResponse()
|
|
122
|
+
|
|
123
|
+
await uut.getBalance(req, res)
|
|
124
|
+
|
|
125
|
+
assert.equal(res.statusValue, 503)
|
|
126
|
+
assert.deepEqual(res.jsonData, { error: 'failure' })
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
describe('#balanceBulk()', () => {
|
|
131
|
+
it('should return error if addresses is not array', async () => {
|
|
132
|
+
const req = createMockRequest({
|
|
133
|
+
body: { addresses: 'not-an-array' }
|
|
134
|
+
})
|
|
135
|
+
const res = createMockResponse()
|
|
136
|
+
|
|
137
|
+
await uut.balanceBulk(req, res)
|
|
138
|
+
|
|
139
|
+
assert.equal(res.statusValue, 400)
|
|
140
|
+
assert.property(res.jsonData, 'error')
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('should validate array size and call use case', async () => {
|
|
144
|
+
const req = createMockRequest({
|
|
145
|
+
body: { addresses: [VALID_MAINNET_ADDRESS] }
|
|
146
|
+
})
|
|
147
|
+
const res = createMockResponse()
|
|
148
|
+
|
|
149
|
+
await uut.balanceBulk(req, res)
|
|
150
|
+
|
|
151
|
+
assert.equal(res.statusValue, 200)
|
|
152
|
+
assert.isTrue(mockAdapters.fullNode.validateArraySize.calledOnce)
|
|
153
|
+
assert.isTrue(mockUseCases.fulcrum.getBalances.calledOnce)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('should return error if array size invalid', async () => {
|
|
157
|
+
mockAdapters.fullNode.validateArraySize.returns(false)
|
|
158
|
+
const req = createMockRequest({
|
|
159
|
+
body: { addresses: [VALID_MAINNET_ADDRESS] }
|
|
160
|
+
})
|
|
161
|
+
const res = createMockResponse()
|
|
162
|
+
|
|
163
|
+
await uut.balanceBulk(req, res)
|
|
164
|
+
|
|
165
|
+
assert.equal(res.statusValue, 400)
|
|
166
|
+
assert.equal(res.jsonData.error, 'Array too large.')
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
describe('#getUtxos()', () => {
|
|
171
|
+
it('should return utxos on success', async () => {
|
|
172
|
+
const req = createMockRequest({
|
|
173
|
+
params: { address: VALID_MAINNET_ADDRESS }
|
|
174
|
+
})
|
|
175
|
+
const res = createMockResponse()
|
|
176
|
+
|
|
177
|
+
await uut.getUtxos(req, res)
|
|
178
|
+
|
|
179
|
+
assert.equal(res.statusValue, 200)
|
|
180
|
+
assert.deepEqual(res.jsonData, { utxos: [] })
|
|
181
|
+
assert.isTrue(mockUseCases.fulcrum.getUtxos.calledOnce)
|
|
182
|
+
})
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
describe('#utxosBulk()', () => {
|
|
186
|
+
it('should validate array and call use case', async () => {
|
|
187
|
+
const req = createMockRequest({
|
|
188
|
+
body: { addresses: [VALID_MAINNET_ADDRESS] }
|
|
189
|
+
})
|
|
190
|
+
const res = createMockResponse()
|
|
191
|
+
|
|
192
|
+
await uut.utxosBulk(req, res)
|
|
193
|
+
|
|
194
|
+
assert.equal(res.statusValue, 200)
|
|
195
|
+
assert.isTrue(mockUseCases.fulcrum.getUtxosBulk.calledOnce)
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
describe('#getTransactionDetails()', () => {
|
|
200
|
+
it('should return transaction details on success', async () => {
|
|
201
|
+
const txid = 'a'.repeat(64)
|
|
202
|
+
const req = createMockRequest({
|
|
203
|
+
params: { txid }
|
|
204
|
+
})
|
|
205
|
+
const res = createMockResponse()
|
|
206
|
+
|
|
207
|
+
await uut.getTransactionDetails(req, res)
|
|
208
|
+
|
|
209
|
+
assert.equal(res.statusValue, 200)
|
|
210
|
+
assert.deepEqual(res.jsonData, { txid: 'abc' })
|
|
211
|
+
assert.isTrue(mockUseCases.fulcrum.getTransactionDetails.calledOnce)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('should return error if txid is not string', async () => {
|
|
215
|
+
const req = createMockRequest({
|
|
216
|
+
params: { txid: 123 }
|
|
217
|
+
})
|
|
218
|
+
const res = createMockResponse()
|
|
219
|
+
|
|
220
|
+
await uut.getTransactionDetails(req, res)
|
|
221
|
+
|
|
222
|
+
assert.equal(res.statusValue, 400)
|
|
223
|
+
assert.property(res.jsonData, 'error')
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
describe('#transactionDetailsBulk()', () => {
|
|
228
|
+
it('should validate array and call use case', async () => {
|
|
229
|
+
const req = createMockRequest({
|
|
230
|
+
body: { txids: ['a'.repeat(64)], verbose: true }
|
|
231
|
+
})
|
|
232
|
+
const res = createMockResponse()
|
|
233
|
+
|
|
234
|
+
await uut.transactionDetailsBulk(req, res)
|
|
235
|
+
|
|
236
|
+
assert.equal(res.statusValue, 200)
|
|
237
|
+
assert.isTrue(mockUseCases.fulcrum.getTransactionDetailsBulk.calledOnce)
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('should default verbose to true', async () => {
|
|
241
|
+
const req = createMockRequest({
|
|
242
|
+
body: { txids: ['a'.repeat(64)] }
|
|
243
|
+
})
|
|
244
|
+
const res = createMockResponse()
|
|
245
|
+
|
|
246
|
+
await uut.transactionDetailsBulk(req, res)
|
|
247
|
+
|
|
248
|
+
assert.isTrue(
|
|
249
|
+
mockUseCases.fulcrum.getTransactionDetailsBulk.calledWithMatch({
|
|
250
|
+
txids: ['a'.repeat(64)],
|
|
251
|
+
verbose: true
|
|
252
|
+
})
|
|
253
|
+
)
|
|
254
|
+
})
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
describe('#broadcastTransaction()', () => {
|
|
258
|
+
it('should broadcast transaction on success', async () => {
|
|
259
|
+
const req = createMockRequest({
|
|
260
|
+
body: { txHex: '010203' }
|
|
261
|
+
})
|
|
262
|
+
const res = createMockResponse()
|
|
263
|
+
|
|
264
|
+
await uut.broadcastTransaction(req, res)
|
|
265
|
+
|
|
266
|
+
assert.equal(res.statusValue, 200)
|
|
267
|
+
assert.deepEqual(res.jsonData, { txid: 'abc' })
|
|
268
|
+
assert.isTrue(mockUseCases.fulcrum.broadcastTransaction.calledOnce)
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it('should return error if txHex is not string', async () => {
|
|
272
|
+
const req = createMockRequest({
|
|
273
|
+
body: { txHex: 123 }
|
|
274
|
+
})
|
|
275
|
+
const res = createMockResponse()
|
|
276
|
+
|
|
277
|
+
await uut.broadcastTransaction(req, res)
|
|
278
|
+
|
|
279
|
+
assert.equal(res.statusValue, 400)
|
|
280
|
+
assert.property(res.jsonData, 'error')
|
|
281
|
+
})
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
describe('#getBlockHeaders()', () => {
|
|
285
|
+
it('should return block headers on success', async () => {
|
|
286
|
+
const req = createMockRequest({
|
|
287
|
+
params: { height: '100' },
|
|
288
|
+
query: { count: '2' }
|
|
289
|
+
})
|
|
290
|
+
const res = createMockResponse()
|
|
291
|
+
|
|
292
|
+
await uut.getBlockHeaders(req, res)
|
|
293
|
+
|
|
294
|
+
assert.equal(res.statusValue, 200)
|
|
295
|
+
assert.isTrue(
|
|
296
|
+
mockUseCases.fulcrum.getBlockHeaders.calledWithMatch({
|
|
297
|
+
height: 100,
|
|
298
|
+
count: 2
|
|
299
|
+
})
|
|
300
|
+
)
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
it('should default count to 1', async () => {
|
|
304
|
+
const req = createMockRequest({
|
|
305
|
+
params: { height: '100' }
|
|
306
|
+
})
|
|
307
|
+
const res = createMockResponse()
|
|
308
|
+
|
|
309
|
+
await uut.getBlockHeaders(req, res)
|
|
310
|
+
|
|
311
|
+
assert.isTrue(
|
|
312
|
+
mockUseCases.fulcrum.getBlockHeaders.calledWithMatch({
|
|
313
|
+
height: 100,
|
|
314
|
+
count: 1
|
|
315
|
+
})
|
|
316
|
+
)
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('should return error if height is invalid', async () => {
|
|
320
|
+
const req = createMockRequest({
|
|
321
|
+
params: { height: 'invalid' }
|
|
322
|
+
})
|
|
323
|
+
const res = createMockResponse()
|
|
324
|
+
|
|
325
|
+
await uut.getBlockHeaders(req, res)
|
|
326
|
+
|
|
327
|
+
assert.equal(res.statusValue, 400)
|
|
328
|
+
assert.property(res.jsonData, 'error')
|
|
329
|
+
})
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
describe('#blockHeadersBulk()', () => {
|
|
333
|
+
it('should validate heights array and call use case', async () => {
|
|
334
|
+
const req = createMockRequest({
|
|
335
|
+
body: { heights: [{ height: 100, count: 2 }] }
|
|
336
|
+
})
|
|
337
|
+
const res = createMockResponse()
|
|
338
|
+
|
|
339
|
+
await uut.blockHeadersBulk(req, res)
|
|
340
|
+
|
|
341
|
+
assert.equal(res.statusValue, 200)
|
|
342
|
+
assert.isTrue(mockUseCases.fulcrum.getBlockHeadersBulk.calledOnce)
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
it('should return error if heights is not array', async () => {
|
|
346
|
+
const req = createMockRequest({
|
|
347
|
+
body: { heights: 'not-an-array' }
|
|
348
|
+
})
|
|
349
|
+
const res = createMockResponse()
|
|
350
|
+
|
|
351
|
+
await uut.blockHeadersBulk(req, res)
|
|
352
|
+
|
|
353
|
+
assert.equal(res.statusValue, 400)
|
|
354
|
+
assert.property(res.jsonData, 'error')
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it('should validate height objects', async () => {
|
|
358
|
+
const req = createMockRequest({
|
|
359
|
+
body: { heights: [{ height: 'invalid', count: 2 }] }
|
|
360
|
+
})
|
|
361
|
+
const res = createMockResponse()
|
|
362
|
+
|
|
363
|
+
await uut.blockHeadersBulk(req, res)
|
|
364
|
+
|
|
365
|
+
assert.equal(res.statusValue, 400)
|
|
366
|
+
assert.property(res.jsonData, 'error')
|
|
367
|
+
})
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
describe('#getTransactions()', () => {
|
|
371
|
+
it('should return transactions on success', async () => {
|
|
372
|
+
const req = createMockRequest({
|
|
373
|
+
params: { address: VALID_MAINNET_ADDRESS }
|
|
374
|
+
})
|
|
375
|
+
const res = createMockResponse()
|
|
376
|
+
|
|
377
|
+
await uut.getTransactions(req, res)
|
|
378
|
+
|
|
379
|
+
assert.equal(res.statusValue, 200)
|
|
380
|
+
assert.isTrue(mockUseCases.fulcrum.getTransactions.calledOnce)
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
it('should handle allTxs from params', async () => {
|
|
384
|
+
const req = createMockRequest({
|
|
385
|
+
params: { address: VALID_MAINNET_ADDRESS, allTxs: 'true' }
|
|
386
|
+
})
|
|
387
|
+
const res = createMockResponse()
|
|
388
|
+
|
|
389
|
+
await uut.getTransactions(req, res)
|
|
390
|
+
|
|
391
|
+
assert.isTrue(
|
|
392
|
+
mockUseCases.fulcrum.getTransactions.calledWithMatch({
|
|
393
|
+
address: VALID_MAINNET_ADDRESS,
|
|
394
|
+
allTxs: true
|
|
395
|
+
})
|
|
396
|
+
)
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
it('should handle allTxs from query', async () => {
|
|
400
|
+
const req = createMockRequest({
|
|
401
|
+
params: { address: VALID_MAINNET_ADDRESS },
|
|
402
|
+
query: { allTxs: 'true' }
|
|
403
|
+
})
|
|
404
|
+
const res = createMockResponse()
|
|
405
|
+
|
|
406
|
+
await uut.getTransactions(req, res)
|
|
407
|
+
|
|
408
|
+
assert.isTrue(
|
|
409
|
+
mockUseCases.fulcrum.getTransactions.calledWithMatch({
|
|
410
|
+
allTxs: true
|
|
411
|
+
})
|
|
412
|
+
)
|
|
413
|
+
})
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
describe('#transactionsBulk()', () => {
|
|
417
|
+
it('should validate addresses and call use case', async () => {
|
|
418
|
+
const req = createMockRequest({
|
|
419
|
+
body: { addresses: [VALID_MAINNET_ADDRESS], allTxs: true }
|
|
420
|
+
})
|
|
421
|
+
const res = createMockResponse()
|
|
422
|
+
|
|
423
|
+
await uut.transactionsBulk(req, res)
|
|
424
|
+
|
|
425
|
+
assert.equal(res.statusValue, 200)
|
|
426
|
+
assert.isTrue(mockUseCases.fulcrum.getTransactionsBulk.calledOnce)
|
|
427
|
+
})
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
describe('#getMempool()', () => {
|
|
431
|
+
it('should return mempool on success', async () => {
|
|
432
|
+
const req = createMockRequest({
|
|
433
|
+
params: { address: VALID_MAINNET_ADDRESS }
|
|
434
|
+
})
|
|
435
|
+
const res = createMockResponse()
|
|
436
|
+
|
|
437
|
+
await uut.getMempool(req, res)
|
|
438
|
+
|
|
439
|
+
assert.equal(res.statusValue, 200)
|
|
440
|
+
assert.deepEqual(res.jsonData, { mempool: [] })
|
|
441
|
+
assert.isTrue(mockUseCases.fulcrum.getMempool.calledOnce)
|
|
442
|
+
})
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
describe('#mempoolBulk()', () => {
|
|
446
|
+
it('should validate addresses and call use case', async () => {
|
|
447
|
+
const req = createMockRequest({
|
|
448
|
+
body: { addresses: [VALID_MAINNET_ADDRESS] }
|
|
449
|
+
})
|
|
450
|
+
const res = createMockResponse()
|
|
451
|
+
|
|
452
|
+
await uut.mempoolBulk(req, res)
|
|
453
|
+
|
|
454
|
+
assert.equal(res.statusValue, 200)
|
|
455
|
+
assert.isTrue(mockUseCases.fulcrum.getMempoolBulk.calledOnce)
|
|
456
|
+
})
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
describe('#handleError()', () => {
|
|
460
|
+
it('should handle errors with status', async () => {
|
|
461
|
+
const error = new Error('test error')
|
|
462
|
+
error.status = 400
|
|
463
|
+
const res = createMockResponse()
|
|
464
|
+
|
|
465
|
+
uut.handleError(error, res)
|
|
466
|
+
|
|
467
|
+
assert.equal(res.statusValue, 400)
|
|
468
|
+
assert.deepEqual(res.jsonData, { error: 'test error' })
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
it('should default status to 500', async () => {
|
|
472
|
+
const error = new Error('test error')
|
|
473
|
+
const res = createMockResponse()
|
|
474
|
+
|
|
475
|
+
uut.handleError(error, res)
|
|
476
|
+
|
|
477
|
+
assert.equal(res.statusValue, 500)
|
|
478
|
+
assert.deepEqual(res.jsonData, { error: 'test error' })
|
|
479
|
+
})
|
|
480
|
+
})
|
|
481
|
+
})
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Unit tests for MiningRESTController.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { assert } from 'chai'
|
|
6
|
+
import sinon from 'sinon'
|
|
7
|
+
|
|
8
|
+
import MiningRESTController from '../../../src/controllers/rest-api/full-node/mining/controller.js'
|
|
9
|
+
import { createMockRequest, createMockResponse } from '../mocks/controller-mocks.js'
|
|
10
|
+
|
|
11
|
+
describe('#mining-controller.js', () => {
|
|
12
|
+
let sandbox
|
|
13
|
+
let mockAdapters
|
|
14
|
+
let mockUseCases
|
|
15
|
+
let uut
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
sandbox = sinon.createSandbox()
|
|
19
|
+
mockAdapters = {}
|
|
20
|
+
mockUseCases = {
|
|
21
|
+
mining: {
|
|
22
|
+
getMiningInfo: sandbox.stub().resolves({ blocks: 100, difficulty: 1.5 }),
|
|
23
|
+
getNetworkHashPS: sandbox.stub().resolves(1234567890)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
uut = new MiningRESTController({
|
|
28
|
+
adapters: mockAdapters,
|
|
29
|
+
useCases: mockUseCases
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
sandbox.restore()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
describe('#constructor()', () => {
|
|
38
|
+
it('should require adapters', () => {
|
|
39
|
+
assert.throws(() => {
|
|
40
|
+
// eslint-disable-next-line no-new
|
|
41
|
+
new MiningRESTController({ useCases: mockUseCases })
|
|
42
|
+
}, /Adapters library required/)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should require mining use cases', () => {
|
|
46
|
+
assert.throws(() => {
|
|
47
|
+
// eslint-disable-next-line no-new
|
|
48
|
+
new MiningRESTController({ adapters: mockAdapters, useCases: {} })
|
|
49
|
+
}, /Mining use cases required/)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
describe('#root()', () => {
|
|
54
|
+
it('should return mining status', async () => {
|
|
55
|
+
const req = createMockRequest()
|
|
56
|
+
const res = createMockResponse()
|
|
57
|
+
|
|
58
|
+
await uut.root(req, res)
|
|
59
|
+
|
|
60
|
+
assert.equal(res.statusValue, 200)
|
|
61
|
+
assert.deepEqual(res.jsonData, { status: 'mining' })
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
describe('#getMiningInfo()', () => {
|
|
66
|
+
it('should return mining info on success', async () => {
|
|
67
|
+
const req = createMockRequest()
|
|
68
|
+
const res = createMockResponse()
|
|
69
|
+
|
|
70
|
+
await uut.getMiningInfo(req, res)
|
|
71
|
+
|
|
72
|
+
assert.equal(res.statusValue, 200)
|
|
73
|
+
assert.deepEqual(res.jsonData, { blocks: 100, difficulty: 1.5 })
|
|
74
|
+
assert.isTrue(mockUseCases.mining.getMiningInfo.calledOnce)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should handle errors via handleError', async () => {
|
|
78
|
+
const error = new Error('failure')
|
|
79
|
+
error.status = 503
|
|
80
|
+
mockUseCases.mining.getMiningInfo.rejects(error)
|
|
81
|
+
const req = createMockRequest()
|
|
82
|
+
const res = createMockResponse()
|
|
83
|
+
|
|
84
|
+
await uut.getMiningInfo(req, res)
|
|
85
|
+
|
|
86
|
+
assert.equal(res.statusValue, 503)
|
|
87
|
+
assert.deepEqual(res.jsonData, { error: 'failure' })
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
describe('#getNetworkHashPS()', () => {
|
|
92
|
+
it('should return network hash PS with default params', async () => {
|
|
93
|
+
const req = createMockRequest()
|
|
94
|
+
const res = createMockResponse()
|
|
95
|
+
|
|
96
|
+
await uut.getNetworkHashPS(req, res)
|
|
97
|
+
|
|
98
|
+
assert.equal(res.statusValue, 200)
|
|
99
|
+
assert.equal(res.jsonData, 1234567890)
|
|
100
|
+
assert.isTrue(mockUseCases.mining.getNetworkHashPS.calledOnce)
|
|
101
|
+
assert.deepEqual(mockUseCases.mining.getNetworkHashPS.firstCall.args[0], {
|
|
102
|
+
nblocks: 120,
|
|
103
|
+
height: -1
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('should parse query params for nblocks and height', async () => {
|
|
108
|
+
const req = createMockRequest({
|
|
109
|
+
query: {
|
|
110
|
+
nblocks: '240',
|
|
111
|
+
height: '1000'
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
const res = createMockResponse()
|
|
115
|
+
|
|
116
|
+
await uut.getNetworkHashPS(req, res)
|
|
117
|
+
|
|
118
|
+
assert.equal(res.statusValue, 200)
|
|
119
|
+
assert.isTrue(mockUseCases.mining.getNetworkHashPS.calledOnce)
|
|
120
|
+
assert.deepEqual(mockUseCases.mining.getNetworkHashPS.firstCall.args[0], {
|
|
121
|
+
nblocks: 240,
|
|
122
|
+
height: 1000
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('should handle errors via handleError', async () => {
|
|
127
|
+
const error = new Error('RPC error')
|
|
128
|
+
error.status = 500
|
|
129
|
+
mockUseCases.mining.getNetworkHashPS.rejects(error)
|
|
130
|
+
const req = createMockRequest()
|
|
131
|
+
const res = createMockResponse()
|
|
132
|
+
|
|
133
|
+
await uut.getNetworkHashPS(req, res)
|
|
134
|
+
|
|
135
|
+
assert.equal(res.statusValue, 500)
|
|
136
|
+
assert.deepEqual(res.jsonData, { error: 'RPC error' })
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
})
|