@dashevo/dash-spv 0.23.0-dev.10
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/.eslintignore +2 -0
- package/.eslintrc.json +7 -0
- package/LICENSE +21 -0
- package/README.md +7 -0
- package/config/config.js +51 -0
- package/index.js +7 -0
- package/lib/blockstore.js +56 -0
- package/lib/consensus.js +65 -0
- package/lib/merkleproofs.js +21 -0
- package/lib/spvchain.js +339 -0
- package/lib/utils.js +62 -0
- package/package.json +27 -0
- package/test/data/headers.js +216 -0
- package/test/data/merkleproofs.js +36 -0
- package/test/data/rawHeaders.js +5531 -0
- package/test/index.js +455 -0
package/test/index.js
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
const { MerkleBlock, Transaction } = require('@dashevo/dashcore-lib');
|
|
2
|
+
const Blockchain = require('../lib/spvchain');
|
|
3
|
+
const utils = require('../lib/utils');
|
|
4
|
+
const merkleProofs = require('../lib/merkleproofs');
|
|
5
|
+
const consensus = require('../lib/consensus');
|
|
6
|
+
const {
|
|
7
|
+
testnet, testnet2, testnet3, mainnet, badRawHeaders,
|
|
8
|
+
} = require('./data/rawHeaders');
|
|
9
|
+
const headers = require('./data/headers');
|
|
10
|
+
const merkleData = require('./data/merkleproofs');
|
|
11
|
+
|
|
12
|
+
let chain = null;
|
|
13
|
+
let merkleBlock = null;
|
|
14
|
+
let merkleBlock2 = null;
|
|
15
|
+
|
|
16
|
+
require('should');
|
|
17
|
+
|
|
18
|
+
describe('SPV-DASH (forks & re-orgs) deserialized headers', () => {
|
|
19
|
+
before(() => {
|
|
20
|
+
chain = new Blockchain('devnet');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should get 26 testnet headers', () => {
|
|
24
|
+
headers.length.should.equal(26);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should contain 1 branch when chain is initialised with genesis block', () => {
|
|
28
|
+
chain.getAllBranches().length.should.equal(1);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should contain genesis hash', () => {
|
|
32
|
+
chain.getTipHash().should.equal('00000bafbc94add76cb75e2ec92894837288a481e5c005f6563d91623bf8bc2c');
|
|
33
|
+
chain.getLongestChain().length.should.equal(1);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should still contain a branch of 1 when first header is added', () => {
|
|
37
|
+
chain.addHeader(headers[0]);
|
|
38
|
+
chain.getAllBranches().length.should.equal(1);
|
|
39
|
+
chain.getLongestChain().length.should.equal(2);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should discard adding of duplicate block', () => {
|
|
43
|
+
chain.addHeader(headers[0]);
|
|
44
|
+
chain.getOrphans().length.should.equal(0);
|
|
45
|
+
chain.getLongestChain().length.should.equal(2);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should create 1 orphan', () => {
|
|
49
|
+
chain.addHeader(headers[2]);
|
|
50
|
+
chain.getOrphans().length.should.equal(1);
|
|
51
|
+
chain.getLongestChain().length.should.equal(2);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should connect the orphan by adding its parent', () => {
|
|
55
|
+
chain.addHeader(headers[1]);
|
|
56
|
+
chain.getOrphans().length.should.equal(0);
|
|
57
|
+
chain.getAllBranches().length.should.equal(1);
|
|
58
|
+
chain.getLongestChain().length.should.equal(4);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should add remaining test headers', () => {
|
|
62
|
+
chain.addHeaders(headers.slice(3, 24));
|
|
63
|
+
chain.getOrphans().length.should.equal(0);
|
|
64
|
+
chain.getAllBranches().length.should.equal(1);
|
|
65
|
+
chain.getLongestChain().length.should.equal(25);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('not add an invalid header', () => {
|
|
69
|
+
chain.addHeader(headers[25]);
|
|
70
|
+
chain.getLongestChain().length.should.equal(25);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should throw an error if some of the headers is invalid', (done) => {
|
|
74
|
+
try {
|
|
75
|
+
chain.addHeaders([headers[25], headers[10]]);
|
|
76
|
+
done(new Error('SPV chain failed to throw an error on invalid block'));
|
|
77
|
+
} catch (e) {
|
|
78
|
+
e.message.should.equal('Some headers are invalid');
|
|
79
|
+
done();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('SPV-DASH (forks & re-orgs) serialized raw headers for mainnet', () => {
|
|
85
|
+
before(() => {
|
|
86
|
+
chain = new Blockchain('mainnet', 10000, utils.normalizeHeader(mainnet[0]));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should get 2000 mainnet headers', () => {
|
|
90
|
+
mainnet.length.should.equal(2000);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should contain 1 branch when chain is initialised with genesis block', () => {
|
|
94
|
+
chain.getAllBranches().length.should.equal(1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should contain start hash', () => {
|
|
98
|
+
chain.getTipHash().should.equal('000000000000002b8a8363ce87b4c48087ff8a997a8102097102bed001ebc531');
|
|
99
|
+
chain.getLongestChain().length.should.equal(1);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should still contain a branch of 1 when first header is added', () => {
|
|
103
|
+
chain.addHeader(mainnet[1]);
|
|
104
|
+
chain.getAllBranches().length.should.equal(1);
|
|
105
|
+
chain.getLongestChain().length.should.equal(2);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should discard addding of duplicate block', () => {
|
|
109
|
+
chain.addHeader(mainnet[1]);
|
|
110
|
+
chain.getOrphans().length.should.equal(0);
|
|
111
|
+
chain.getLongestChain().length.should.equal(2);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should create 1 orphan', () => {
|
|
115
|
+
chain.addHeader(mainnet[3]);
|
|
116
|
+
chain.getOrphans().length.should.equal(1);
|
|
117
|
+
chain.getLongestChain().length.should.equal(2);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should connect the orphan by adding its parent', () => {
|
|
121
|
+
chain.addHeader(mainnet[2]);
|
|
122
|
+
chain.getOrphans().length.should.equal(0);
|
|
123
|
+
chain.getAllBranches().length.should.equal(1);
|
|
124
|
+
chain.getLongestChain().length.should.equal(4);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('SPV-DASH (addHeaders) add many headers for testnet', () => {
|
|
129
|
+
before(() => {
|
|
130
|
+
chain = new Blockchain('testnet', 10000, utils.normalizeHeader(testnet[0]));
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should add the 1st 250 testnet headers', () => {
|
|
134
|
+
chain.addHeaders(testnet.slice(1, 250));
|
|
135
|
+
chain.getOrphans().length.should.equal(0);
|
|
136
|
+
chain.getAllBranches().length.should.equal(1);
|
|
137
|
+
chain.getLongestChain().length.should.equal(250);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should add the next 250 (250 - 500) testnet headers', () => {
|
|
141
|
+
chain.addHeaders(testnet.slice(250, 500));
|
|
142
|
+
chain.getOrphans().length.should.equal(0);
|
|
143
|
+
chain.getAllBranches().length.should.equal(1);
|
|
144
|
+
chain.getLongestChain().length.should.equal(500);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should add the 1st 250 testnet2 headers', () => {
|
|
148
|
+
chain = new Blockchain('testnet', 10000, utils.normalizeHeader(testnet2[0]));
|
|
149
|
+
chain.addHeaders(testnet2.slice(1, 250));
|
|
150
|
+
chain.getOrphans().length.should.equal(0);
|
|
151
|
+
chain.getAllBranches().length.should.equal(1);
|
|
152
|
+
chain.getLongestChain().length.should.equal(250);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should add the next 250 (250 - 500) testnet2 headers', () => {
|
|
156
|
+
chain.addHeaders(testnet2.slice(250, 500));
|
|
157
|
+
chain.getOrphans().length.should.equal(0);
|
|
158
|
+
chain.getAllBranches().length.should.equal(1);
|
|
159
|
+
chain.getLongestChain().length.should.equal(500);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should add the 1st 250 testnet3 headers', () => {
|
|
163
|
+
chain = new Blockchain('testnet', 10000, utils.normalizeHeader(testnet3[0]));
|
|
164
|
+
chain.addHeaders(testnet3.slice(1, 250));
|
|
165
|
+
chain.getOrphans().length.should.equal(0);
|
|
166
|
+
chain.getAllBranches().length.should.equal(1);
|
|
167
|
+
chain.getLongestChain().length.should.equal(250);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should add the next 250 (250 - 500) testnet3 headers', () => {
|
|
171
|
+
chain.addHeaders(testnet3.slice(250, 500));
|
|
172
|
+
chain.getOrphans().length.should.equal(0);
|
|
173
|
+
chain.getAllBranches().length.should.equal(1);
|
|
174
|
+
chain.getLongestChain().length.should.equal(500);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should not add an invalid header', () => {
|
|
178
|
+
chain.addHeader(testnet[499]);
|
|
179
|
+
chain.getLongestChain().length.should.equal(500);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('should orphan and not add invalid but consistent headers', () => {
|
|
183
|
+
chain.addHeaders([badRawHeaders[0], badRawHeaders[1]]);
|
|
184
|
+
chain.getOrphanChunks().length.should.equal(1);
|
|
185
|
+
chain.getLongestChain().length.should.equal(500);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should throw an error if some of the headers are inconsistent', (done) => {
|
|
189
|
+
try {
|
|
190
|
+
chain.addHeaders([badRawHeaders[0], badRawHeaders[2]]);
|
|
191
|
+
done(new Error('SPV chain failed to throw an error on invalid block'));
|
|
192
|
+
} catch (e) {
|
|
193
|
+
e.message.should.equal('Some headers are invalid');
|
|
194
|
+
done();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('SPV-DASH (addHeaders) add testnet headers out of order', () => {
|
|
200
|
+
before(() => {
|
|
201
|
+
chain = new Blockchain('testnet', 10000, utils.normalizeHeader(testnet[0]));
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should add the 1st 100 testnet headers', () => {
|
|
205
|
+
chain.addHeaders(testnet.slice(1, 100));
|
|
206
|
+
chain.getOrphans().length.should.equal(0);
|
|
207
|
+
chain.getAllBranches().length.should.equal(1);
|
|
208
|
+
chain.getOrphanChunks().length.should.equal(0);
|
|
209
|
+
chain.getLongestChain().length.should.equal(100);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('should orphan testnet headers 200 - 300', () => {
|
|
213
|
+
chain.addHeaders(testnet.slice(200, 300));
|
|
214
|
+
chain.getOrphans().length.should.equal(0);
|
|
215
|
+
chain.getAllBranches().length.should.equal(1);
|
|
216
|
+
chain.getOrphanChunks().length.should.equal(1);
|
|
217
|
+
chain.getLongestChain().length.should.equal(100);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('should orphan testnet headers 400 - 500', () => {
|
|
221
|
+
chain.addHeaders(testnet.slice(400, 500));
|
|
222
|
+
chain.getOrphans().length.should.equal(0);
|
|
223
|
+
chain.getAllBranches().length.should.equal(1);
|
|
224
|
+
chain.getOrphanChunks().length.should.equal(2);
|
|
225
|
+
chain.getLongestChain().length.should.equal(100);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should reconnect orphaned chunks (testnet headers 1 - 100 and 200 - 300)', () => {
|
|
229
|
+
chain.addHeaders(testnet.slice(100, 200));
|
|
230
|
+
chain.getOrphans().length.should.equal(0);
|
|
231
|
+
chain.getAllBranches().length.should.equal(1);
|
|
232
|
+
chain.getOrphanChunks().length.should.equal(1);
|
|
233
|
+
chain.getLongestChain().length.should.equal(300);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should reconnect orphaned chunks (testnet headers 1 - 300 and 400 - 500)', () => {
|
|
237
|
+
chain.addHeaders(testnet.slice(300, 400));
|
|
238
|
+
chain.getOrphans().length.should.equal(0);
|
|
239
|
+
chain.getAllBranches().length.should.equal(1);
|
|
240
|
+
chain.getOrphanChunks().length.should.equal(0);
|
|
241
|
+
chain.getLongestChain().length.should.equal(500);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe('SPV-DASH (addHeaders) add many headers for mainnet', () => {
|
|
246
|
+
before(() => {
|
|
247
|
+
chain = new Blockchain('mainnet', 10000, utils.normalizeHeader(mainnet[0]));
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should add the 1st 500 mainnet headers', () => {
|
|
251
|
+
chain.addHeaders(mainnet.slice(1, 500));
|
|
252
|
+
chain.getOrphans().length.should.equal(0);
|
|
253
|
+
chain.getAllBranches().length.should.equal(1);
|
|
254
|
+
chain.getLongestChain().length.should.equal(500);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should add the next 500 (500 - 1000) mainnet headers', () => {
|
|
258
|
+
chain.addHeaders(mainnet.slice(500, 1000));
|
|
259
|
+
chain.getOrphans().length.should.equal(0);
|
|
260
|
+
chain.getAllBranches().length.should.equal(1);
|
|
261
|
+
chain.getLongestChain().length.should.equal(1000);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('should add the next 500 (1000 - 1500) mainnet headers', () => {
|
|
265
|
+
chain.addHeaders(mainnet.slice(1000, 1500));
|
|
266
|
+
chain.getOrphans().length.should.equal(0);
|
|
267
|
+
chain.getAllBranches().length.should.equal(1);
|
|
268
|
+
chain.getLongestChain().length.should.equal(1500);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should not add an invalid header', () => {
|
|
272
|
+
chain.addHeader(mainnet[499]);
|
|
273
|
+
chain.getLongestChain().length.should.equal(1500);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should orphan and not add invalid but consistent headers', () => {
|
|
277
|
+
chain.addHeaders([badRawHeaders[0], badRawHeaders[1]]);
|
|
278
|
+
chain.getOrphanChunks().length.should.equal(1);
|
|
279
|
+
chain.getLongestChain().length.should.equal(1500);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('should throw an error if some of the headers are inconsistent', (done) => {
|
|
283
|
+
try {
|
|
284
|
+
chain.addHeaders([badRawHeaders[0], badRawHeaders[2]]);
|
|
285
|
+
done(new Error('SPV chain failed to throw an error on invalid block'));
|
|
286
|
+
} catch (e) {
|
|
287
|
+
e.message.should.equal('Some headers are invalid');
|
|
288
|
+
done();
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
describe('SPV-DASH (addHeaders) add mainnet headers out of order', () => {
|
|
294
|
+
before(() => {
|
|
295
|
+
chain = new Blockchain('mainnet', 10000, utils.normalizeHeader(mainnet[0]));
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should add the 1st 100 mainnet headers', () => {
|
|
299
|
+
chain.addHeaders(mainnet.slice(1, 100));
|
|
300
|
+
chain.getOrphans().length.should.equal(0);
|
|
301
|
+
chain.getAllBranches().length.should.equal(1);
|
|
302
|
+
chain.getOrphanChunks().length.should.equal(0);
|
|
303
|
+
chain.getLongestChain().length.should.equal(100);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should orphan mainnet headers 200 - 300', () => {
|
|
307
|
+
chain.addHeaders(mainnet.slice(200, 300));
|
|
308
|
+
chain.getOrphans().length.should.equal(0);
|
|
309
|
+
chain.getAllBranches().length.should.equal(1);
|
|
310
|
+
chain.getOrphanChunks().length.should.equal(1);
|
|
311
|
+
chain.getLongestChain().length.should.equal(100);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('should orphan mainnet headers 400 - 500', () => {
|
|
315
|
+
chain.addHeaders(mainnet.slice(400, 500));
|
|
316
|
+
chain.getOrphans().length.should.equal(0);
|
|
317
|
+
chain.getAllBranches().length.should.equal(1);
|
|
318
|
+
chain.getOrphanChunks().length.should.equal(2);
|
|
319
|
+
chain.getLongestChain().length.should.equal(100);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should reconnect orphaned chunks (mainnet headers 1 - 100 and 200 - 300)', () => {
|
|
323
|
+
chain.addHeaders(mainnet.slice(100, 200));
|
|
324
|
+
chain.getOrphans().length.should.equal(0);
|
|
325
|
+
chain.getAllBranches().length.should.equal(1);
|
|
326
|
+
chain.getOrphanChunks().length.should.equal(1);
|
|
327
|
+
chain.getLongestChain().length.should.equal(300);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('should reconnect orphaned chunks (mainnet headers 1 - 300 and 400 - 500)', () => {
|
|
331
|
+
chain.addHeaders(mainnet.slice(300, 400));
|
|
332
|
+
chain.getOrphans().length.should.equal(0);
|
|
333
|
+
chain.getAllBranches().length.should.equal(1);
|
|
334
|
+
chain.getOrphanChunks().length.should.equal(0);
|
|
335
|
+
chain.getLongestChain().length.should.equal(500);
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
let genesisHash = null;
|
|
340
|
+
describe('Blockstore', () => {
|
|
341
|
+
before(() => {
|
|
342
|
+
chain = new Blockchain('testnet', 10);
|
|
343
|
+
genesisHash = chain.getTipHash();
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should add 9 headers', (done) => {
|
|
347
|
+
chain.addHeaders(headers.slice(0, 9));
|
|
348
|
+
chain.getLongestChain().length.should.equal(10);
|
|
349
|
+
chain.getHeader(genesisHash)
|
|
350
|
+
.then((header) => {
|
|
351
|
+
header.hash.should.equal(genesisHash);
|
|
352
|
+
header.should.have.property('children');
|
|
353
|
+
done();
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('should move 1 block to the blockstore', (done) => {
|
|
358
|
+
chain.addHeaders(headers.slice(9, 10));
|
|
359
|
+
chain.getLongestChain().length.should.equal(10);
|
|
360
|
+
chain.getHeader(genesisHash)
|
|
361
|
+
.then((header) => {
|
|
362
|
+
header.hash.should.equal(genesisHash);
|
|
363
|
+
header.should.not.have.property('children');
|
|
364
|
+
done();
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// TODO:
|
|
370
|
+
// Create scenarios where chain splits occur to form competing branches
|
|
371
|
+
// Difficult with current chain provided by chainmanager as this is actually hardcoded
|
|
372
|
+
// Dash testnet headers which requires significant CPU power to create forked chains from
|
|
373
|
+
|
|
374
|
+
describe('MerkleProofs', () => {
|
|
375
|
+
it('should validate tx inclusion in merkleblock', () => {
|
|
376
|
+
merkleBlock = new MerkleBlock(merkleData.merkleBlock);
|
|
377
|
+
const validTx = 'c5e85bfa5c0279433f8b4d33fe67f726d7fef1625506cb93554d0170e2bfaf45';
|
|
378
|
+
const invalidTx = `${validTx.substring(0, validTx.length - 1)}0`;
|
|
379
|
+
merkleProofs.validateTxProofs(merkleBlock, [validTx]).should.equal(true);
|
|
380
|
+
merkleProofs.validateTxProofs(merkleBlock, [invalidTx]).should.equal(false);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
describe('Transaction validation', () => {
|
|
385
|
+
before(() => {
|
|
386
|
+
chain = new Blockchain('testnet', 10000, utils.normalizeHeader(testnet[0]));
|
|
387
|
+
chain.addHeaders(testnet.slice(1, 500));
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
beforeEach(() => {
|
|
391
|
+
merkleBlock = new MerkleBlock(Buffer.from(merkleData.rawMerkleBlock, 'hex'));
|
|
392
|
+
merkleBlock2 = new MerkleBlock(Buffer.from(merkleData.rawMerkleBlock2, 'hex'));
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('should throw an error if wrong type is passed', async () => {
|
|
396
|
+
const validTx = '7262476912a96b9a6226cfa3a8f231ba3e2b1f75c396e88367e532c79c43c95b';
|
|
397
|
+
const invalid = Buffer.from(validTx);
|
|
398
|
+
try {
|
|
399
|
+
await consensus.areValidTransactions(invalid, merkleBlock, chain);
|
|
400
|
+
throw new Error('Transaction validation failed to throw an error');
|
|
401
|
+
} catch (e) {
|
|
402
|
+
e.message.should.equal('Please check that transactions parameter is a non-empty array');
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it('should throw an error if empty transactions array', async () => {
|
|
407
|
+
const transactions = [];
|
|
408
|
+
try {
|
|
409
|
+
await consensus.areValidTransactions(transactions, merkleBlock, chain);
|
|
410
|
+
throw new Error('Transaction validation failed to throw an error');
|
|
411
|
+
} catch (e) {
|
|
412
|
+
e.message.should.equal('Please check that transactions parameter is a non-empty array');
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it('should not validate an array of raw transactions for a merkleblock that was generated with a filter containing only one of them', async () => {
|
|
417
|
+
const validTx = new Transaction('020000000100de7192338db34fe9bb25f34122893d94f3b43bd4c881e37924c8e95a068cc8000000006b483045022100b185b4b86b613e3ffc796db90f95dc88f82561c50ba49fa610d8090f61f38ff002201473466bddee2672ed0dba75b81c07bdade734441e005c8c7fdf12a039ff9312012102bdfedbfe6ea05de8094d18442e08c98ebd695acf489f1bdf68fe1e3aff6f488effffffff010000000000000000016a00000000');
|
|
418
|
+
const validTx2 = new Transaction('0200000001ccc68ff58b7b02247f3e05440ab7fc7c8c599453de4a49e35393981890a1e984010000006b483045022100e141365c4916fa09d03aac58f215b926b777a3acec918a6becdbb03d59d28d9f02204edc1ce68d596e28e55f114c67a270302d488707e754af1261fdfc043891651c012102d5b7c0dfb2fd9591a4a98555ce806e17842f401979f2e0cc0689c91d6ca9ef87feffffff025d4c0000000000001976a9146d14b25994e4036d70eeafd4a706640337db5a5e88ac409c0000000000001976a9148b4a9da5a46c7b89b26b649bac8e34e7aa5aa63188acc2260000');
|
|
419
|
+
const transactions = [];
|
|
420
|
+
transactions.push(validTx);
|
|
421
|
+
transactions.push(validTx2);
|
|
422
|
+
const result = await consensus.areValidTransactions(transactions, merkleBlock, chain);
|
|
423
|
+
result.should.equal(false);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('should validate an array of raw transactions for a merkleblock that was generated with a filter containing both of them', async () => {
|
|
427
|
+
const validTx = new Transaction('020000000100de7192338db34fe9bb25f34122893d94f3b43bd4c881e37924c8e95a068cc8000000006b483045022100b185b4b86b613e3ffc796db90f95dc88f82561c50ba49fa610d8090f61f38ff002201473466bddee2672ed0dba75b81c07bdade734441e005c8c7fdf12a039ff9312012102bdfedbfe6ea05de8094d18442e08c98ebd695acf489f1bdf68fe1e3aff6f488effffffff010000000000000000016a00000000');
|
|
428
|
+
const validTx2 = new Transaction('0200000001ccc68ff58b7b02247f3e05440ab7fc7c8c599453de4a49e35393981890a1e984010000006b483045022100e141365c4916fa09d03aac58f215b926b777a3acec918a6becdbb03d59d28d9f02204edc1ce68d596e28e55f114c67a270302d488707e754af1261fdfc043891651c012102d5b7c0dfb2fd9591a4a98555ce806e17842f401979f2e0cc0689c91d6ca9ef87feffffff025d4c0000000000001976a9146d14b25994e4036d70eeafd4a706640337db5a5e88ac409c0000000000001976a9148b4a9da5a46c7b89b26b649bac8e34e7aa5aa63188acc2260000');
|
|
429
|
+
const transactions = [];
|
|
430
|
+
transactions.push(validTx);
|
|
431
|
+
transactions.push(validTx2);
|
|
432
|
+
const result = await consensus.areValidTransactions(transactions, merkleBlock2, chain);
|
|
433
|
+
result.should.equal(true);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('should not validate an array of transactions hashes for a merkleblock that was generated with a filter containing only one of them', async () => {
|
|
437
|
+
const validTxHash = '7262476912a96b9a6226cfa3a8f231ba3e2b1f75c396e88367e532c79c43c95b';
|
|
438
|
+
const validTxHash2 = '3f3517ee8fa95621fe8abdd81c1e0dfb50e21dd4c5a3c01eee2c47cf664821b6';
|
|
439
|
+
const transactions = [];
|
|
440
|
+
transactions.push(validTxHash);
|
|
441
|
+
transactions.push(validTxHash2);
|
|
442
|
+
const result = await consensus.areValidTransactions(transactions, merkleBlock, chain);
|
|
443
|
+
result.should.equal(false);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it('should validate an array of transactions hashes for a merkleblock that was generated with a filter containing both of them', async () => {
|
|
447
|
+
const validTxHash = '7262476912a96b9a6226cfa3a8f231ba3e2b1f75c396e88367e532c79c43c95b';
|
|
448
|
+
const validTxHash2 = '3f3517ee8fa95621fe8abdd81c1e0dfb50e21dd4c5a3c01eee2c47cf664821b6';
|
|
449
|
+
const transactions = [];
|
|
450
|
+
transactions.push(validTxHash);
|
|
451
|
+
transactions.push(validTxHash2);
|
|
452
|
+
const result = await consensus.areValidTransactions(transactions, merkleBlock2, chain);
|
|
453
|
+
result.should.equal(true);
|
|
454
|
+
});
|
|
455
|
+
});
|