@leocuvee/turtlecoin-utils 0.0.14

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.
Files changed (132) hide show
  1. package/.github/workflows/ci.yml +27 -0
  2. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  3. package/.idea/inspectionProfiles/Project_Default.xml +7 -0
  4. package/.idea/misc.xml +6 -0
  5. package/.idea/modules.xml +8 -0
  6. package/.idea/turtlecoin-utils.iml +12 -0
  7. package/.idea/vcs.xml +6 -0
  8. package/.travis.yml +11 -0
  9. package/CONTRIBUTING.md +3 -0
  10. package/LICENSE +674 -0
  11. package/README.md +203 -0
  12. package/config.json +7 -0
  13. package/docs/.nojekyll +0 -0
  14. package/docs/CNAME +1 -0
  15. package/docs/assets/css/main.css +2321 -0
  16. package/docs/assets/images/icons.png +0 -0
  17. package/docs/assets/images/icons@2x.png +0 -0
  18. package/docs/assets/images/widgets.png +0 -0
  19. package/docs/assets/images/widgets@2x.png +0 -0
  20. package/docs/assets/js/main.js +1 -0
  21. package/docs/assets/js/search.js +3 -0
  22. package/docs/classes/address.html +964 -0
  23. package/docs/classes/addressprefix.html +431 -0
  24. package/docs/classes/block.html +965 -0
  25. package/docs/classes/blocktemplate.html +695 -0
  26. package/docs/classes/cryptonote.html +1137 -0
  27. package/docs/classes/ed25519.keypair.html +400 -0
  28. package/docs/classes/ed25519.keys.html +373 -0
  29. package/docs/classes/extranoncetag.extranoncedata.html +454 -0
  30. package/docs/classes/extranoncetag.extranoncepaymentid.html +453 -0
  31. package/docs/classes/extranoncetag.iextranonce.html +347 -0
  32. package/docs/classes/extratag.extramergedmining.html +494 -0
  33. package/docs/classes/extratag.extranonce.html +530 -0
  34. package/docs/classes/extratag.extrapadding.html +456 -0
  35. package/docs/classes/extratag.extrapublickey.html +460 -0
  36. package/docs/classes/extratag.iextratag.html +355 -0
  37. package/docs/classes/levinpacket.html +674 -0
  38. package/docs/classes/levinpayloads.handshake.html +731 -0
  39. package/docs/classes/levinpayloads.ilevinpayload.html +318 -0
  40. package/docs/classes/levinpayloads.liteblock.html +494 -0
  41. package/docs/classes/levinpayloads.missingtransactions.html +494 -0
  42. package/docs/classes/levinpayloads.newblock.html +540 -0
  43. package/docs/classes/levinpayloads.newtransactions.html +402 -0
  44. package/docs/classes/levinpayloads.peerentry.html +610 -0
  45. package/docs/classes/levinpayloads.ping.html +450 -0
  46. package/docs/classes/levinpayloads.rawblock.html +344 -0
  47. package/docs/classes/levinpayloads.requestchain.html +402 -0
  48. package/docs/classes/levinpayloads.requestgetobjects.html +448 -0
  49. package/docs/classes/levinpayloads.requesttxpool.html +402 -0
  50. package/docs/classes/levinpayloads.responsechain.html +494 -0
  51. package/docs/classes/levinpayloads.responsegetobjects.html +540 -0
  52. package/docs/classes/levinpayloads.timedsync.html +540 -0
  53. package/docs/classes/multisig.html +930 -0
  54. package/docs/classes/multisigmessage.html +694 -0
  55. package/docs/classes/parentblock.html +347 -0
  56. package/docs/classes/transaction.html +925 -0
  57. package/docs/classes/transactioninputs.coinbaseinput.html +390 -0
  58. package/docs/classes/transactioninputs.itransactioninput.html +321 -0
  59. package/docs/classes/transactioninputs.keyinput.html +459 -0
  60. package/docs/classes/transactionoutputs.itransactionoutput.html +317 -0
  61. package/docs/classes/transactionoutputs.keyoutput.html +422 -0
  62. package/docs/enums/extranoncetag.noncetagtype.html +246 -0
  63. package/docs/enums/extratag.extratagtype.html +280 -0
  64. package/docs/enums/levinprotocol.commandtype.html +391 -0
  65. package/docs/enums/transactioninputs.inputtype.html +246 -0
  66. package/docs/enums/transactionoutputs.outputtype.html +229 -0
  67. package/docs/globals.html +238 -0
  68. package/docs/index.html +271 -0
  69. package/docs/interfaces/interfaces.config.html +590 -0
  70. package/docs/interfaces/interfaces.daemonblocktemplateresponse.html +323 -0
  71. package/docs/interfaces/interfaces.generatedinput.html +304 -0
  72. package/docs/interfaces/interfaces.generatedoutput.html +285 -0
  73. package/docs/interfaces/interfaces.inputkeys.html +304 -0
  74. package/docs/interfaces/interfaces.ipreparedtransaction.html +268 -0
  75. package/docs/interfaces/interfaces.output.html +399 -0
  76. package/docs/interfaces/interfaces.preparedringsignature.html +377 -0
  77. package/docs/interfaces/interfaces.preparedtransaction.html +329 -0
  78. package/docs/interfaces/interfaces.randomoutput.html +285 -0
  79. package/docs/interfaces/interfaces.transactionrecipient.html +285 -0
  80. package/docs/interfaces/multisiginterfaces.partialkeyimage.html +277 -0
  81. package/docs/interfaces/multisiginterfaces.partialsigningkey.html +277 -0
  82. package/docs/modules/ed25519.html +195 -0
  83. package/docs/modules/extranoncetag.html +208 -0
  84. package/docs/modules/extratag.html +216 -0
  85. package/docs/modules/interfaces.html +231 -0
  86. package/docs/modules/levinpayloads.html +247 -0
  87. package/docs/modules/levinprotocol.html +191 -0
  88. package/docs/modules/multisiginterfaces.html +195 -0
  89. package/docs/modules/transactioninputs.html +208 -0
  90. package/docs/modules/transactionoutputs.html +204 -0
  91. package/index.d.ts +417 -0
  92. package/index.js +1508 -0
  93. package/lib/base58.js +220 -0
  94. package/lib/biginteger.js +1591 -0
  95. package/lib/blocktemplate.js +408 -0
  96. package/lib/crypto.js +19698 -0
  97. package/lib/mnemonic.js +1204 -0
  98. package/lib/nacl-fast-cn.js +608 -0
  99. package/lib/ringsigs.js +24262 -0
  100. package/lib/sha3.js +477 -0
  101. package/package.json +58 -0
  102. package/src/Address.ts +433 -0
  103. package/src/AddressPrefix.ts +117 -0
  104. package/src/Block.ts +556 -0
  105. package/src/BlockTemplate.ts +289 -0
  106. package/src/Common.ts +105 -0
  107. package/src/Config.ts +66 -0
  108. package/src/CryptoNote.ts +1072 -0
  109. package/src/LevinPacket.ts +366 -0
  110. package/src/Multisig.ts +600 -0
  111. package/src/MultisigMessage.ts +374 -0
  112. package/src/ParentBlock.ts +39 -0
  113. package/src/Transaction.ts +628 -0
  114. package/src/Types/ED25519.ts +187 -0
  115. package/src/Types/IExtraNonce.ts +225 -0
  116. package/src/Types/IExtraTag.ts +507 -0
  117. package/src/Types/ITransaction.ts +230 -0
  118. package/src/Types/ITransactionInput.ts +190 -0
  119. package/src/Types/ITransactionOutput.ts +108 -0
  120. package/src/Types/LevinPayloads.ts +1576 -0
  121. package/src/Types/MultisigInterfaces.ts +65 -0
  122. package/src/Types/PortableStorage.ts +289 -0
  123. package/src/Types.ts +36 -0
  124. package/src/index.ts +36 -0
  125. package/test/template.json +6 -0
  126. package/test/test.js +1457 -0
  127. package/tests/blocktemplate.json +6 -0
  128. package/tests/tests.js +215 -0
  129. package/tsconfig.json +15 -0
  130. package/tslint.json +36 -0
  131. package/typedoc.json +10 -0
  132. package/webpack.config.js +15 -0
@@ -0,0 +1,1576 @@
1
+ // Copyright (c) 2018-2020, The TurtleCoin Developers
2
+ //
3
+ // Please see the included LICENSE file for more information.
4
+
5
+ import {BigInteger, PortableStorage, StorageType} from '../Types';
6
+ import {Reader, Writer} from 'bytestream-helper';
7
+ import {Block} from '../Block';
8
+ import {Transaction} from '../Transaction';
9
+
10
+ /** @ignore */
11
+ export enum SIZES {
12
+ KEY = 32,
13
+ PEER_ID = 8,
14
+ NETWORK_ID = 16,
15
+ }
16
+
17
+ export namespace LevinPayloads {
18
+
19
+ /**
20
+ * Represents a Raw Block For Levin Based Payloads
21
+ */
22
+ export class RawBlock {
23
+ /**
24
+ * The block
25
+ */
26
+ public block: Block = new Block();
27
+ /**
28
+ * The transactions in the block
29
+ */
30
+ public transactions: Transaction[] = [];
31
+
32
+ /**
33
+ * Constructs a new raw block given the supplied values
34
+ * @param block
35
+ * @param transactions
36
+ */
37
+ constructor(block?: Block, transactions?: Transaction[]) {
38
+ if (block) {
39
+ this.block = block;
40
+ }
41
+
42
+ if (transactions) {
43
+ this.transactions = transactions;
44
+ }
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Represents a peer entry in the peer list
50
+ */
51
+ export class PeerEntry {
52
+
53
+ /**
54
+ * The peer IP address
55
+ */
56
+ public get ip(): string {
57
+ return int2ip(this.m_ip);
58
+ }
59
+
60
+ public set ip(value: string) {
61
+ this.m_ip = ip2int(value);
62
+ }
63
+
64
+ /**
65
+ * The peer's port number
66
+ */
67
+ public get port(): number {
68
+ return this.m_port;
69
+ }
70
+
71
+ public set port(value: number) {
72
+ this.m_port = value;
73
+ }
74
+
75
+ /**
76
+ * The peer ID
77
+ */
78
+ public get id(): string {
79
+ return this.m_id;
80
+ }
81
+
82
+ public set id(value: string) {
83
+ const reader = new Reader(value);
84
+
85
+ if (reader.length !== 8) {
86
+ throw new RangeError('Invalid id supplied');
87
+ }
88
+
89
+ this.m_id = reader.hex(SIZES.PEER_ID);
90
+ }
91
+
92
+ /**
93
+ * The last seen datetime of the peer
94
+ */
95
+ public get last_seen(): Date {
96
+ return this.m_last_seen;
97
+ }
98
+
99
+ public set last_seen(value: Date) {
100
+ this.m_last_seen = value;
101
+ }
102
+
103
+ /**
104
+ * Creates a new peer entry instance using the supplied data
105
+ * @param data the raw data of the peer entry
106
+ * @returns a new instance of the object
107
+ */
108
+ public static from(data: Reader | Buffer | string): PeerEntry {
109
+ const reader = new Reader(data);
110
+
111
+ if (reader.length !== 24) {
112
+ throw new RangeError('Invalid data length');
113
+ }
114
+
115
+ const ip = int2ip(reader.uint32_t().toJSNumber());
116
+ const port = reader.uint32_t().toJSNumber();
117
+ const id = reader.hex(SIZES.PEER_ID);
118
+
119
+ const last_seen = reader.time_t(true);
120
+
121
+ return new PeerEntry(ip, port, id, last_seen);
122
+ }
123
+
124
+ protected m_ip: number = 0;
125
+ protected m_port: number = 0;
126
+ protected m_id: string = ''.padStart(16, '0');
127
+ protected m_last_seen: Date = new Date();
128
+
129
+ /**
130
+ * Constructs a new peer entry using the supplied values
131
+ * @param ip the peer ip address
132
+ * @param port the peer port
133
+ * @param id the peer id
134
+ * @param last_seen the date the peer was last seen
135
+ */
136
+ constructor(ip: string, port: number, id: string, last_seen: Date) {
137
+ this.m_ip = ip2int(ip);
138
+ this.m_port = port;
139
+
140
+ const reader = new Reader(id);
141
+
142
+ if (reader.length !== 8) {
143
+ throw new RangeError('Invalid id supplied');
144
+ }
145
+
146
+ this.m_id = reader.hex(SIZES.PEER_ID);
147
+ this.m_last_seen = last_seen;
148
+ }
149
+
150
+ /**
151
+ * The Buffer representation of the peer entry
152
+ * @returns the buffer representation of the object
153
+ */
154
+ public toBuffer(): Buffer {
155
+ const writer = new Writer();
156
+
157
+ writer.uint32_t(this.m_ip);
158
+
159
+ writer.uint32_t(this.m_port);
160
+
161
+ writer.hex(this.m_id);
162
+
163
+ writer.time_t(this.m_last_seen, true);
164
+
165
+ return writer.buffer;
166
+ }
167
+
168
+ /**
169
+ * The hexadecimal (blob) representation of the peer entry
170
+ * @returns the hexadecimal (blob) representation of the object
171
+ */
172
+ public toString(): string {
173
+ return this.toBuffer().toString('hex');
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Abstract object for all Levin Payloads
179
+ */
180
+ export abstract class ILevinPayload {
181
+ public abstract toBuffer(): Buffer;
182
+
183
+ public abstract toString(): string;
184
+ }
185
+
186
+ /** @ignore */
187
+ export class LevinPayload implements ILevinPayload {
188
+ public toBuffer(): Buffer {
189
+ return Buffer.alloc(0);
190
+ }
191
+
192
+ public toString(): string {
193
+ return this.toBuffer().toString('hex');
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Represents a handshake payload
199
+ */
200
+ export class Handshake implements ILevinPayload {
201
+
202
+ /**
203
+ * The network ID
204
+ */
205
+ public get network_id(): string {
206
+ return this.m_network_id;
207
+ }
208
+
209
+ public set network_id(value: string) {
210
+ const reader = new Reader(value);
211
+ if (reader.length !== 16) {
212
+ throw new Error('Invalid network id length');
213
+ }
214
+
215
+ this.m_network_id = reader.hex(SIZES.NETWORK_ID);
216
+ }
217
+
218
+ /**
219
+ * The protocol version supported
220
+ */
221
+ public get version(): number {
222
+ return this.m_version;
223
+ }
224
+
225
+ public set version(value: number) {
226
+ this.m_version = value;
227
+ }
228
+
229
+ /**
230
+ * The current date and time
231
+ */
232
+ public get local_time(): Date {
233
+ return this.m_local_time;
234
+ }
235
+
236
+ public set local_time(value: Date) {
237
+ this.m_local_time = value;
238
+ }
239
+
240
+ /**
241
+ * Our port number for p2p traffic
242
+ */
243
+ public get my_port(): number {
244
+ return this.m_my_port;
245
+ }
246
+
247
+ public set my_port(value: number) {
248
+ this.m_my_port = value;
249
+ }
250
+
251
+ /**
252
+ * Our peer ID
253
+ */
254
+ public get peer_id(): string {
255
+ return this.m_peer_id;
256
+ }
257
+
258
+ public set peer_id(value: string) {
259
+ const reader = new Reader(value);
260
+ if (reader.length !== 8) {
261
+ throw new Error('Invalid peer id length');
262
+ }
263
+
264
+ this.m_peer_id = reader.hex(SIZES.PEER_ID);
265
+ }
266
+
267
+ /**
268
+ * Our current blockchain height
269
+ */
270
+ public get current_height(): number {
271
+ return this.m_current_height;
272
+ }
273
+
274
+ public set current_height(value: number) {
275
+ this.m_current_height = value;
276
+ }
277
+
278
+ /**
279
+ * The top block hash that we know about
280
+ */
281
+ public get top_id(): string {
282
+ return this.m_top_id;
283
+ }
284
+
285
+ public set top_id(value: string) {
286
+ const reader = new Reader(value);
287
+ if (reader.length !== SIZES.KEY) {
288
+ throw new Error('Invalid top id length');
289
+ }
290
+
291
+ this.m_top_id = reader.bytes(SIZES.KEY).toString('hex');
292
+ }
293
+
294
+ /**
295
+ * Our list of locally known peers
296
+ */
297
+ public get local_peerlist(): PeerEntry[] {
298
+ return this.m_local_peerlist;
299
+ }
300
+
301
+ public set local_peerlist(value: PeerEntry[]) {
302
+ this.m_local_peerlist = value;
303
+ }
304
+
305
+ /**
306
+ * Creates a new instance of the object using the supplied data found in the levin packet
307
+ * @param data the data contained for the payload in the levin packet
308
+ * @returns a new instance of the object
309
+ */
310
+ public static from(data: Reader | Buffer | string): Handshake {
311
+ const payload = PortableStorage.from(data);
312
+
313
+ const result = new Handshake();
314
+
315
+ result.network_id = (payload.get('node_data') as PortableStorage).get('network_id') as string;
316
+
317
+ result.version =
318
+ ((payload.get('node_data') as PortableStorage).get('version') as BigInteger.BigInteger)
319
+ .toJSNumber();
320
+
321
+ const lt =
322
+ ((payload.get('node_data') as PortableStorage).get('local_time') as BigInteger.BigInteger)
323
+ .toString(16)
324
+ .padStart(16, '0');
325
+
326
+ result.local_time = (new Reader(lt)).time_t(true);
327
+
328
+ result.my_port =
329
+ ((payload.get('node_data') as PortableStorage).get('my_port') as BigInteger.BigInteger)
330
+ .toJSNumber();
331
+
332
+ result.peer_id =
333
+ ((payload.get('node_data') as PortableStorage).get('peer_id') as BigInteger.BigInteger)
334
+ .toString(16).padStart(16, '0');
335
+
336
+ result.current_height =
337
+ ((payload.get('payload_data') as PortableStorage).get('current_height') as BigInteger.BigInteger)
338
+ .toJSNumber();
339
+
340
+ result.top_id = (payload.get('payload_data') as PortableStorage).get('top_id') as string;
341
+
342
+ if (payload.exists('local_peerlist')) {
343
+ const peerlist = (payload.get('local_peerlist')) as Buffer;
344
+
345
+ const reader = new Reader(peerlist);
346
+
347
+ if (reader.length % 24 !== 0) {
348
+ throw new Error('Error parsing local_peer list');
349
+ }
350
+
351
+ while (reader.unreadBytes > 0) {
352
+ result.local_peerlist.push(PeerEntry.from(reader.bytes(24)));
353
+ }
354
+ }
355
+
356
+ return result;
357
+ }
358
+
359
+ private m_network_id: string = ''.padStart(32, '0');
360
+ private m_version: number = 0;
361
+ private m_local_time: Date = new Date();
362
+ private m_my_port: number = 0;
363
+ private m_peer_id: string = ''.padStart(16, '0');
364
+ private m_current_height: number = 0;
365
+ private m_top_id: string = ''.padStart(64, '0');
366
+ private m_local_peerlist: PeerEntry[] = [];
367
+
368
+ /**
369
+ * Provides the Buffer representation of the object
370
+ * @returns the buffer representation of the object
371
+ */
372
+ public toBuffer(): Buffer {
373
+ const node_data = new PortableStorage();
374
+ node_data.set('network_id', this.network_id, StorageType.STRING);
375
+ node_data.set('version', BigInteger(this.version), StorageType.UINT8);
376
+ node_data.set('peer_id', BigInteger(this.peer_id, 16), StorageType.UINT64);
377
+
378
+ const writer = new Writer();
379
+ writer.time_t(this.local_time, true);
380
+
381
+ node_data.set('local_time', BigInteger(writer.blob, 16), StorageType.UINT64);
382
+ node_data.set('my_port', BigInteger(this.my_port), StorageType.UINT32);
383
+
384
+ const payload_data = new PortableStorage();
385
+ payload_data.set('current_height', BigInteger(this.current_height), StorageType.UINT32);
386
+ payload_data.set('top_id', this.top_id, StorageType.STRING);
387
+
388
+ const payload = new PortableStorage();
389
+
390
+ payload.set('node_data', node_data, StorageType.OBJECT);
391
+ payload.set('payload_data', payload_data, StorageType.OBJECT);
392
+
393
+ const peerList = new Writer();
394
+ this.local_peerlist.forEach((peer) => peerList.write(peer.toBuffer()));
395
+
396
+ if (peerList.length !== 0) {
397
+ payload.set('local_peerlist', peerList.buffer.toString('hex'), StorageType.STRING);
398
+ }
399
+
400
+ return payload.toBuffer();
401
+ }
402
+
403
+ /**
404
+ * Provides the hexadecimal (blob) representation of the object
405
+ * @returns the hexadecimal (blob) representation of the object
406
+ */
407
+ public toString(): string {
408
+ return this.toBuffer().toString('hex');
409
+ }
410
+ }
411
+
412
+ export class LiteBlock implements ILevinPayload {
413
+
414
+ /**
415
+ * The block template a as block
416
+ */
417
+ public get blockTemplate(): Block {
418
+ return this.m_blockTemplate;
419
+ }
420
+
421
+ public set blockTemplate(value: Block) {
422
+ this.m_blockTemplate = value;
423
+ }
424
+
425
+ /**
426
+ * The current blockchain height
427
+ */
428
+ public get current_blockchain_height(): number {
429
+ return this.m_current_blockchain_height;
430
+ }
431
+
432
+ public set current_blockchain_height(value: number) {
433
+ this.m_current_blockchain_height = value;
434
+ }
435
+
436
+ /**
437
+ * The hops from the originating node
438
+ */
439
+ public get hop(): number {
440
+ return this.m_hop;
441
+ }
442
+
443
+ public set hop(value: number) {
444
+ this.m_hop = value;
445
+ }
446
+
447
+ /**
448
+ * Creates a new instance of the object using the supplied data found in the levin packet
449
+ * @param data the data contained for the payload in the levin packet
450
+ * @returns a new instance of the object
451
+ */
452
+ public static from(data: Reader | Buffer | string): LiteBlock {
453
+ const payload = PortableStorage.from(data);
454
+
455
+ const result = new LiteBlock();
456
+
457
+ result.current_blockchain_height =
458
+ (payload.get('current_blockchain_height') as BigInteger.BigInteger).toJSNumber();
459
+ result.hop = (payload.get('hop') as BigInteger.BigInteger).toJSNumber();
460
+ result.blockTemplate = Block.from((payload.get('blockTemplate') as string));
461
+
462
+ return result;
463
+ }
464
+
465
+ private m_blockTemplate: Block = new Block();
466
+ private m_current_blockchain_height: number = 0;
467
+ private m_hop: number = 0;
468
+
469
+ /**
470
+ * Provides the Buffer representation of the object
471
+ * @returns the buffer representation of the object
472
+ */
473
+ public toBuffer(): Buffer {
474
+ const payload = new PortableStorage();
475
+
476
+ payload.set('current_blockchain_height', BigInteger(this.current_blockchain_height), StorageType.UINT32);
477
+ payload.set('hop', BigInteger(this.hop), StorageType.UINT32);
478
+ payload.set('blockTemplate', this.blockTemplate.toString(), StorageType.STRING);
479
+
480
+ return payload.toBuffer();
481
+ }
482
+
483
+ /**
484
+ * Provides the hexadecimal (blob) representation of the object
485
+ * @returns the hexadecimal (blob) representation of the object
486
+ */
487
+ public toString(): string {
488
+ return this.toBuffer().toString('hex');
489
+ }
490
+ }
491
+
492
+ export class MissingTransactions implements ILevinPayload {
493
+
494
+ /**
495
+ * The current blockchain height
496
+ */
497
+ public get current_blockchain_height(): number {
498
+ return this.m_current_blockchain_height;
499
+ }
500
+
501
+ public set current_blockchain_height(value: number) {
502
+ this.m_current_blockchain_height = value;
503
+ }
504
+
505
+ /**
506
+ * The block hash containing for which we need the transactions
507
+ */
508
+ public get blockHash(): string {
509
+ return this.m_blockHash;
510
+ }
511
+
512
+ public set blockHash(value: string) {
513
+ const reader = new Reader(value);
514
+ if (reader.length !== SIZES.KEY) {
515
+ throw new Error('Invalid hash supplied');
516
+ }
517
+
518
+ this.m_blockHash = reader.hash();
519
+ }
520
+
521
+ /**
522
+ * The list of missing transaction hashes we need
523
+ */
524
+ public get missing_txs(): string[] {
525
+ return this.m_missing_txs;
526
+ }
527
+
528
+ public set missing_txs(value: string[]) {
529
+ const tmp: string[] = [];
530
+
531
+ value.forEach((v) => {
532
+ const reader = new Reader(v);
533
+
534
+ if (v.length !== SIZES.KEY) {
535
+ throw new Error('Invalid hash supplied');
536
+ }
537
+
538
+ tmp.push(reader.hash());
539
+ });
540
+
541
+ this.m_missing_txs = tmp;
542
+ }
543
+
544
+ /**
545
+ * Creates a new instance of the object using the supplied data found in the levin packet
546
+ * @param data the data contained for the payload in the levin packet
547
+ * @returns a new instance of the object
548
+ */
549
+ public static from(data: Reader | Buffer | string): MissingTransactions {
550
+ const payload = PortableStorage.from(data);
551
+
552
+ const result = new MissingTransactions();
553
+
554
+ result.current_blockchain_height =
555
+ (payload.get('current_blockchain_height') as BigInteger.BigInteger).toJSNumber();
556
+ result.blockHash = payload.get('blockHash') as string;
557
+
558
+ if (payload.exists('missing_txs')) {
559
+ const reader = new Reader(payload.get('missing_txs') as string);
560
+
561
+ if (reader.length % SIZES.KEY) {
562
+ throw new RangeError('Invalid missing_tx data');
563
+ }
564
+
565
+ while (reader.unreadBytes > 0) {
566
+ result.missing_txs.push(reader.hash());
567
+ }
568
+ }
569
+
570
+ return result;
571
+ }
572
+
573
+ private m_blockHash: string = ''.padStart(64, '0');
574
+ private m_current_blockchain_height: number = 0;
575
+ private m_missing_txs: string[] = [];
576
+
577
+ /**
578
+ * Provides the Buffer representation of the object
579
+ * @returns the buffer representation of the object
580
+ */
581
+ public toBuffer(): Buffer {
582
+ const payload = new PortableStorage();
583
+
584
+ payload.set('current_blockchain_height', BigInteger(this.current_blockchain_height), StorageType.UINT32);
585
+ payload.set('blockHash', this.blockHash, StorageType.STRING);
586
+
587
+ const writer = new Writer();
588
+
589
+ this.missing_txs.forEach((tx) => writer.hash(tx));
590
+
591
+ payload.set('missing_txs', writer.buffer.toString('hex'), StorageType.STRING);
592
+
593
+ return payload.toBuffer();
594
+ }
595
+
596
+ /**
597
+ * Provides the hexadecimal (blob) representation of the object
598
+ * @returns the hexadecimal (blob) representation of the object
599
+ */
600
+ public toString(): string {
601
+ return this.toBuffer().toString('hex');
602
+ }
603
+ }
604
+
605
+ export class NewBlock implements ILevinPayload {
606
+
607
+ /**
608
+ * The new block
609
+ */
610
+ public get block(): Block {
611
+ return this.m_block;
612
+ }
613
+
614
+ public set block(value: Block) {
615
+ this.m_block = value;
616
+ }
617
+
618
+ /**
619
+ * The transactions in the new block
620
+ */
621
+ public get transactions(): Transaction[] {
622
+ return this.m_transactions;
623
+ }
624
+
625
+ public set transactions(value: Transaction[]) {
626
+ this.m_transactions = value;
627
+ }
628
+
629
+ /**
630
+ * The current blockchain height
631
+ */
632
+ public get current_blockchain_height(): number {
633
+ return this.m_current_blockchain_height;
634
+ }
635
+
636
+ public set current_blockchain_height(value: number) {
637
+ this.m_current_blockchain_height = value;
638
+ }
639
+
640
+ /**
641
+ * The number of hops from the originating node
642
+ */
643
+ public get hop(): number {
644
+ return this.m_hop;
645
+ }
646
+
647
+ public set hop(value: number) {
648
+ this.m_hop = value;
649
+ }
650
+
651
+ /**
652
+ * Creates a new instance of the object using the supplied data found in the levin packet
653
+ * @param data the data contained for the payload in the levin packet
654
+ * @returns a new instance of the object
655
+ */
656
+ public static from(data: Reader | Buffer | string): NewBlock {
657
+ const payload = PortableStorage.from(data);
658
+
659
+ const result = new NewBlock();
660
+
661
+ if (payload.exists('block')) {
662
+ const blockPayload = (payload.get('block') as PortableStorage);
663
+
664
+ result.block = Block.from((blockPayload.get('block') as string));
665
+
666
+ if (blockPayload.exists('txs')) {
667
+ (blockPayload.get('txs') as string[]).forEach((tx) => {
668
+ result.transactions.push(Transaction.from(tx));
669
+ });
670
+ }
671
+ }
672
+
673
+ result.current_blockchain_height =
674
+ (payload.get('current_blockchain_height') as BigInteger.BigInteger).toJSNumber();
675
+ result.hop = (payload.get('hop') as BigInteger.BigInteger).toJSNumber();
676
+
677
+ return result;
678
+ }
679
+
680
+ private m_block: Block = new Block();
681
+ private m_transactions: Transaction[] = [];
682
+ private m_current_blockchain_height: number = 0;
683
+ private m_hop: number = 0;
684
+
685
+ /**
686
+ * Provides the Buffer representation of the object
687
+ * @returns the buffer representation of the object
688
+ */
689
+ public toBuffer(): Buffer {
690
+ const payload = new PortableStorage();
691
+
692
+ const blockPayload = new PortableStorage();
693
+
694
+ blockPayload.set('block', this.block.toString(), StorageType.STRING);
695
+
696
+ if (this.transactions.length !== 0) {
697
+ const txs: string[] = [];
698
+
699
+ this.transactions.forEach((tx) => {
700
+ txs.push(tx.toString());
701
+ });
702
+
703
+ blockPayload.set('txs', txs, StorageType.STRING_ARRAY);
704
+ }
705
+
706
+ payload.set('block', blockPayload, StorageType.OBJECT);
707
+ payload.set('current_blockchain_height', BigInteger(this.current_blockchain_height), StorageType.UINT32);
708
+ payload.set('hop', BigInteger(this.hop), StorageType.UINT32);
709
+
710
+ return payload.toBuffer();
711
+ }
712
+
713
+ /**
714
+ * Provides the hexadecimal (blob) representation of the object
715
+ * @returns the hexadecimal (blob) representation of the object
716
+ */
717
+ public toString(): string {
718
+ return this.toBuffer().toString('hex');
719
+ }
720
+ }
721
+
722
+ export class NewTransactions implements ILevinPayload {
723
+
724
+ /**
725
+ * The new transactions in the packet
726
+ */
727
+ public get transactions(): Transaction[] {
728
+ return this.m_transactions;
729
+ }
730
+
731
+ public set transactions(value: Transaction[]) {
732
+ this.m_transactions = value;
733
+ }
734
+
735
+ /**
736
+ * Creates a new instance of the object using the supplied data found in the levin packet
737
+ * @param data the data contained for the payload in the levin packet
738
+ * @returns a new instance of the object
739
+ */
740
+ public static from(data: Reader | Buffer | string): NewTransactions {
741
+ const payload = PortableStorage.from(data);
742
+
743
+ const result = new NewTransactions();
744
+
745
+ if (payload.exists('txs')) {
746
+ (payload.get('txs') as string[])
747
+ .forEach((tx) => result.transactions.push(Transaction.from(tx)));
748
+ }
749
+
750
+ return result;
751
+ }
752
+
753
+ private m_transactions: Transaction[] = [];
754
+
755
+ /**
756
+ * Provides the Buffer representation of the object
757
+ * @returns the buffer representation of the object
758
+ */
759
+ public toBuffer(): Buffer {
760
+ const payload = new PortableStorage();
761
+
762
+ const txs: string[] = [];
763
+
764
+ this.transactions.forEach((tx) => txs.push(tx.toString()));
765
+
766
+ payload.set('txs', txs, StorageType.STRING_ARRAY);
767
+
768
+ return payload.toBuffer();
769
+ }
770
+
771
+ /**
772
+ * Provides the hexadecimal (blob) representation of the object
773
+ * @returns the hexadecimal (blob) representation of the object
774
+ */
775
+ public toString(): string {
776
+ return this.toBuffer().toString('hex');
777
+ }
778
+ }
779
+
780
+ export class Ping implements ILevinPayload {
781
+
782
+ /**
783
+ * The current ping status message
784
+ * Usually 'OK'
785
+ */
786
+ public get status(): string {
787
+ return this.m_status;
788
+ }
789
+
790
+ public set status(value: string) {
791
+ this.m_status = value;
792
+ }
793
+
794
+ /**
795
+ * The peer ID
796
+ */
797
+ public get peer_id(): string {
798
+ return this.m_peer_id;
799
+ }
800
+
801
+ public set peer_id(value: string) {
802
+ const reader = new Reader(value);
803
+ if (reader.length !== 8) {
804
+ throw new Error('Invalid peer id length');
805
+ }
806
+
807
+ this.m_peer_id = reader.hex(SIZES.PEER_ID);
808
+ }
809
+
810
+ /**
811
+ * Creates a new instance of the object using the supplied data found in the levin packet
812
+ * @param data the data contained for the payload in the levin packet
813
+ * @returns a new instance of the object
814
+ */
815
+ public static from(data: Reader | Buffer | string): Ping {
816
+ const payload = PortableStorage.from(data);
817
+
818
+ const result = new Ping();
819
+
820
+ if (payload.exists('peer_id')) {
821
+ result.peer_id = (payload.get('peer_id') as BigInteger.BigInteger)
822
+ .toString(16).padStart(16, '0');
823
+ }
824
+
825
+ if (payload.exists('status')) {
826
+ result.status = Buffer.from(payload.get('status') as string, 'hex').toString();
827
+ }
828
+
829
+ return result;
830
+ }
831
+
832
+ private m_status: string = '';
833
+ private m_peer_id: string = ''.padStart(16, '0');
834
+
835
+ /**
836
+ * Provides the Buffer representation of the object
837
+ * @returns the buffer representation of the object
838
+ */
839
+ public toBuffer(): Buffer {
840
+ const payload = new PortableStorage();
841
+
842
+ if (this.status.length !== 0) {
843
+ payload.set('status', Buffer.from(this.status).toString('hex'), StorageType.STRING);
844
+ }
845
+
846
+ if (this.peer_id !== ''.padStart(16, '0')) {
847
+ payload.set('peer_id', BigInteger(this.peer_id, 16), StorageType.UINT64);
848
+ }
849
+
850
+ return payload.toBuffer();
851
+ }
852
+
853
+ /**
854
+ * Provides the hexadecimal (blob) representation of the object
855
+ * @returns the hexadecimal (blob) representation of the object
856
+ */
857
+ public toString(): string {
858
+ return this.toBuffer().toString('hex');
859
+ }
860
+ }
861
+
862
+ export class RequestChain implements ILevinPayload {
863
+
864
+ /**
865
+ * A list of known block IDs in descending order (genesis block last)
866
+ */
867
+ public get block_ids(): string[] {
868
+ return this.m_block_ids;
869
+ }
870
+
871
+ public set block_ids(value: string[]) {
872
+ const tmp: string[] = [];
873
+
874
+ value.forEach((v) => {
875
+ const reader = new Reader(v);
876
+
877
+ if (v.length !== SIZES.KEY) {
878
+ throw new Error('Invalid hash supplied');
879
+ }
880
+
881
+ tmp.push(reader.hash());
882
+ });
883
+
884
+ this.m_block_ids = tmp;
885
+ }
886
+
887
+ /**
888
+ * Creates a new instance of the object using the supplied data found in the levin packet
889
+ * @param data the data contained for the payload in the levin packet
890
+ * @returns a new instance of the object
891
+ */
892
+ public static from(data: Reader | Buffer | string): RequestChain {
893
+ const payload = PortableStorage.from(data);
894
+
895
+ const result = new RequestChain();
896
+
897
+ if (payload.exists('block_ids')) {
898
+ const reader = new Reader(payload.get('block_ids') as string);
899
+
900
+ if (reader.length % 32 !== 0) {
901
+ throw new Error('Error parsing block ids');
902
+ }
903
+
904
+ while (reader.unreadBytes > 0) {
905
+ result.block_ids.push(reader.hash());
906
+ }
907
+ }
908
+
909
+ return result;
910
+ }
911
+
912
+ private m_block_ids: string[] = [];
913
+
914
+ /**
915
+ * Provides the Buffer representation of the object
916
+ * @returns the buffer representation of the object
917
+ */
918
+ public toBuffer(): Buffer {
919
+ const payload = new PortableStorage();
920
+
921
+ const writer = new Writer();
922
+
923
+ this.block_ids.forEach((hash) => writer.hash(hash));
924
+
925
+ payload.set('block_ids', writer.buffer.toString('hex'), StorageType.STRING);
926
+
927
+ return payload.toBuffer();
928
+ }
929
+
930
+ /**
931
+ * Provides the hexadecimal (blob) representation of the object
932
+ * @returns the hexadecimal (blob) representation of the object
933
+ */
934
+ public toString(): string {
935
+ return this.toBuffer().toString('hex');
936
+ }
937
+ }
938
+
939
+ export class RequestGetObjects implements ILevinPayload {
940
+
941
+ /**
942
+ * A list of block hashes we would like the data for
943
+ */
944
+ public get blocks(): string[] {
945
+ return this.m_transactions;
946
+ }
947
+
948
+ public set blocks(value: string[]) {
949
+ const tmp: string[] = [];
950
+
951
+ value.forEach((v) => {
952
+ const reader = new Reader(v);
953
+
954
+ if (v.length !== SIZES.KEY) {
955
+ throw new Error('Invalid hash supplied');
956
+ }
957
+
958
+ tmp.push(reader.hash());
959
+ });
960
+
961
+ this.m_blocks = tmp;
962
+ }
963
+
964
+ /**
965
+ * A list of transaction hashes we would like the data for
966
+ */
967
+ public get transactions(): string[] {
968
+ return this.m_blocks;
969
+ }
970
+
971
+ public set transactions(value: string[]) {
972
+ const tmp: string[] = [];
973
+
974
+ value.forEach((v) => {
975
+ const reader = new Reader(v);
976
+
977
+ if (v.length !== SIZES.KEY) {
978
+ throw new Error('Invalid hash supplied');
979
+ }
980
+
981
+ tmp.push(reader.hash());
982
+ });
983
+
984
+ this.m_transactions = tmp;
985
+ }
986
+
987
+ /**
988
+ * Creates a new instance of the object using the supplied data found in the levin packet
989
+ * @param data the data contained for the payload in the levin packet
990
+ * @returns a new instance of the object
991
+ */
992
+ public static from(data: Reader | Buffer | string): RequestGetObjects {
993
+ const payload = PortableStorage.from(data);
994
+
995
+ const result = new RequestGetObjects();
996
+
997
+ if (payload.exists('blocks')) {
998
+ const reader = new Reader(payload.get('blocks') as string);
999
+
1000
+ if (reader.length % 32 !== 0) {
1001
+ throw new Error('Error parsing txs');
1002
+ }
1003
+
1004
+ while (reader.unreadBytes > 0) {
1005
+ result.blocks.push(reader.hash());
1006
+ }
1007
+ }
1008
+
1009
+ if (payload.exists('txs')) {
1010
+ const reader = new Reader(payload.get('txs') as string);
1011
+
1012
+ if (reader.length % 32 !== 0) {
1013
+ throw new Error('Error parsing txs');
1014
+ }
1015
+
1016
+ while (reader.unreadBytes > 0) {
1017
+ result.transactions.push(reader.hash());
1018
+ }
1019
+ }
1020
+
1021
+ return result;
1022
+ }
1023
+
1024
+ private m_transactions: string[] = [];
1025
+ private m_blocks: string[] = [];
1026
+
1027
+ /**
1028
+ * Provides the Buffer representation of the object
1029
+ * @returns the buffer representation of the object
1030
+ */
1031
+ public toBuffer(): Buffer {
1032
+ const payload = new PortableStorage();
1033
+
1034
+ const writer = new Writer();
1035
+
1036
+ if (this.transactions.length !== 0) {
1037
+ this.transactions.forEach((tx) => writer.hash(tx));
1038
+
1039
+ payload.set('txs', writer.buffer.toString('hex'), StorageType.STRING);
1040
+ }
1041
+
1042
+ if (this.blocks.length !== 0) {
1043
+ this.blocks.forEach((tx) => writer.hash(tx));
1044
+
1045
+ payload.set('blocks', writer.buffer.toString('hex'), StorageType.STRING);
1046
+ }
1047
+
1048
+ return payload.toBuffer();
1049
+ }
1050
+
1051
+ /**
1052
+ * Provides the hexadecimal (blob) representation of the object
1053
+ * @returns the hexadecimal (blob) representation of the object
1054
+ */
1055
+ public toString(): string {
1056
+ return this.toBuffer().toString('hex');
1057
+ }
1058
+ }
1059
+
1060
+ export class RequestTXPool implements ILevinPayload {
1061
+
1062
+ /**
1063
+ * A list of transaction hashes we need data for in the pool
1064
+ */
1065
+ public get transactions(): string[] {
1066
+ return this.m_transactions;
1067
+ }
1068
+
1069
+ public set transactions(value: string[]) {
1070
+ const tmp: string[] = [];
1071
+
1072
+ value.forEach((v) => {
1073
+ const reader = new Reader(v);
1074
+
1075
+ if (v.length !== SIZES.KEY) {
1076
+ throw new Error('Invalid hash supplied');
1077
+ }
1078
+
1079
+ tmp.push(reader.hash());
1080
+ });
1081
+
1082
+ this.m_transactions = tmp;
1083
+ }
1084
+
1085
+ /**
1086
+ * Creates a new instance of the object using the supplied data found in the levin packet
1087
+ * @param data the data contained for the payload in the levin packet
1088
+ * @returns a new instance of the object
1089
+ */
1090
+ public static from(data: Reader | Buffer | string): RequestTXPool {
1091
+ const payload = PortableStorage.from(data);
1092
+
1093
+ const result = new RequestTXPool();
1094
+
1095
+ if (payload.exists('txs')) {
1096
+ const reader = new Reader(payload.get('txs') as string);
1097
+
1098
+ if (reader.length % 32 !== 0) {
1099
+ throw new Error('Error parsing txs');
1100
+ }
1101
+
1102
+ while (reader.unreadBytes > 0) {
1103
+ result.transactions.push(reader.hash());
1104
+ }
1105
+ }
1106
+
1107
+ return result;
1108
+ }
1109
+
1110
+ private m_transactions: string[] = [];
1111
+
1112
+ /**
1113
+ * Provides the Buffer representation of the object
1114
+ * @returns the buffer representation of the object
1115
+ */
1116
+ public toBuffer(): Buffer {
1117
+ const payload = new PortableStorage();
1118
+
1119
+ const writer = new Writer();
1120
+
1121
+ this.transactions.forEach((tx) => writer.hash(tx));
1122
+
1123
+ payload.set('txs', writer.buffer.toString('hex'), StorageType.STRING);
1124
+
1125
+ return payload.toBuffer();
1126
+ }
1127
+
1128
+ /**
1129
+ * Provides the hexadecimal (blob) representation of the object
1130
+ * @returns the hexadecimal (blob) representation of the object
1131
+ */
1132
+ public toString(): string {
1133
+ return this.toBuffer().toString('hex');
1134
+ }
1135
+ }
1136
+
1137
+ export class ResponseChain implements ILevinPayload {
1138
+
1139
+ /**
1140
+ * The block hashes that we know about in descending order
1141
+ */
1142
+ public get block_ids(): string[] {
1143
+ return this.m_block_ids;
1144
+ }
1145
+
1146
+ public set block_ids(value: string[]) {
1147
+ const tmp: string[] = [];
1148
+
1149
+ value.forEach((v) => {
1150
+ const reader = new Reader(v);
1151
+
1152
+ if (v.length !== SIZES.KEY) {
1153
+ throw new Error('Invalid hash supplied');
1154
+ }
1155
+
1156
+ tmp.push(reader.hash());
1157
+ });
1158
+
1159
+ this.m_block_ids = tmp;
1160
+ }
1161
+
1162
+ /**
1163
+ * the starting height of the response data
1164
+ */
1165
+ public get start_height(): number {
1166
+ return this.m_start_height;
1167
+ }
1168
+
1169
+ public set start_height(value: number) {
1170
+ this.m_start_height = value;
1171
+ }
1172
+
1173
+ /**
1174
+ * The current network height we have observed
1175
+ */
1176
+ public get total_height(): number {
1177
+ return this.m_total_height;
1178
+ }
1179
+
1180
+ public set total_height(value: number) {
1181
+ this.m_total_height = value;
1182
+ }
1183
+
1184
+ /**
1185
+ * Creates a new instance of the object using the supplied data found in the levin packet
1186
+ * @param data the data contained for the payload in the levin packet
1187
+ * @returns a new instance of the object
1188
+ */
1189
+ public static from(data: Reader | Buffer | string): ResponseChain {
1190
+ const payload = PortableStorage.from(data);
1191
+
1192
+ const result = new ResponseChain();
1193
+
1194
+ result.start_height = (payload.get('start_height') as BigInteger.BigInteger)
1195
+ .toJSNumber();
1196
+
1197
+ result.total_height = (payload.get('total_height') as BigInteger.BigInteger)
1198
+ .toJSNumber();
1199
+
1200
+ if (payload.exists('m_block_ids')) {
1201
+ const reader = new Reader(payload.get('m_block_ids') as string);
1202
+
1203
+ if (reader.length % 32 !== 0) {
1204
+ throw new Error('Error parsing block ids');
1205
+ }
1206
+
1207
+ while (reader.unreadBytes > 0) {
1208
+ result.block_ids.push(reader.hash());
1209
+ }
1210
+ }
1211
+
1212
+ return result;
1213
+ }
1214
+
1215
+ private m_start_height: number = 0;
1216
+ private m_total_height: number = 0;
1217
+ private m_block_ids: string[] = [];
1218
+
1219
+ /**
1220
+ * Provides the Buffer representation of the object
1221
+ * @returns the buffer representation of the object
1222
+ */
1223
+ public toBuffer(): Buffer {
1224
+ const payload = new PortableStorage();
1225
+
1226
+ payload.set('start_height', BigInteger(this.start_height), StorageType.UINT32);
1227
+
1228
+ payload.set('total_height', BigInteger(this.total_height), StorageType.UINT32);
1229
+
1230
+ const writer = new Writer();
1231
+
1232
+ this.block_ids.forEach((hash) => writer.hash(hash));
1233
+
1234
+ payload.set('m_block_ids', writer.buffer.toString('hex'), StorageType.STRING);
1235
+
1236
+ return payload.toBuffer();
1237
+ }
1238
+
1239
+ /**
1240
+ * Provides the hexadecimal (blob) representation of the object
1241
+ * @returns the hexadecimal (blob) representation of the object
1242
+ */
1243
+ public toString(): string {
1244
+ return this.toBuffer().toString('hex');
1245
+ }
1246
+ }
1247
+
1248
+ export class ResponseGetObjects implements ILevinPayload {
1249
+
1250
+ /**
1251
+ * A list of transactions in the response
1252
+ */
1253
+ public get transactions(): Transaction[] {
1254
+ return this.m_transactions;
1255
+ }
1256
+
1257
+ public set transactions(value: Transaction[]) {
1258
+ this.m_transactions = value;
1259
+ }
1260
+
1261
+ /**
1262
+ * A list of hashes that we cannot find in our copy of the blockchain
1263
+ */
1264
+ public get missed_ids(): string[] {
1265
+ return this.m_missed_ids;
1266
+ }
1267
+
1268
+ public set missed_ids(value: string[]) {
1269
+ this.m_missed_ids = value;
1270
+ }
1271
+
1272
+ /**
1273
+ * The current blockchain height
1274
+ */
1275
+ public get current_blockchain_height(): number {
1276
+ return this.m_current_blockchain_height;
1277
+ }
1278
+
1279
+ public set current_blockchain_height(value: number) {
1280
+ this.m_current_blockchain_height = value;
1281
+ }
1282
+
1283
+ /**
1284
+ * A list of blocks in the response
1285
+ */
1286
+ public get blocks(): RawBlock[] {
1287
+ return this.m_raw_blocks;
1288
+ }
1289
+
1290
+ public set blocks(value: RawBlock[]) {
1291
+ this.m_raw_blocks = value;
1292
+ }
1293
+
1294
+ /**
1295
+ * Creates a new instance of the object using the supplied data found in the levin packet
1296
+ * @param data the data contained for the payload in the levin packet
1297
+ * @returns a new instance of the object
1298
+ */
1299
+ public static from(data: Reader | Buffer | string): ResponseGetObjects {
1300
+ const payload = PortableStorage.from(data);
1301
+
1302
+ const result = new ResponseGetObjects();
1303
+
1304
+ if (payload.exists('txs')) {
1305
+ (payload.get('txs') as string[])
1306
+ .forEach((tx) => result.transactions.push(Transaction.from(tx)));
1307
+ }
1308
+
1309
+ if (payload.exists('blocks')) {
1310
+ (payload.get('blocks') as PortableStorage[])
1311
+ .forEach((block: PortableStorage) => {
1312
+ const l_block = Block.from(block.get('block') as string);
1313
+
1314
+ const l_txs: Transaction[] = [];
1315
+
1316
+ if (block.exists('txs')) {
1317
+ (block.get('txs') as string[])
1318
+ .forEach((tx) => {
1319
+ l_txs.push(Transaction.from(tx));
1320
+ });
1321
+ }
1322
+
1323
+ result.blocks.push(new RawBlock(l_block, l_txs));
1324
+ });
1325
+ }
1326
+
1327
+ if (payload.exists('missed_ids')) {
1328
+ const reader = new Reader(payload.get('missed_ids') as string);
1329
+
1330
+ if (reader.length % 32 !== 0) {
1331
+ throw new Error('Cannot parsed missed_ids');
1332
+ }
1333
+
1334
+ while (reader.unreadBytes) {
1335
+ result.missed_ids.push(reader.hash());
1336
+ }
1337
+ }
1338
+
1339
+ if (payload.exists('current_blockchain_height')) {
1340
+ result.current_blockchain_height =
1341
+ (payload.get('current_blockchain_height') as BigInteger.BigInteger).toJSNumber();
1342
+ }
1343
+
1344
+ return result;
1345
+ }
1346
+
1347
+ private m_transactions: Transaction[] = [];
1348
+ private m_raw_blocks: RawBlock[] = [];
1349
+ private m_missed_ids: string[] = [];
1350
+ private m_current_blockchain_height: number = 0;
1351
+
1352
+ /**
1353
+ * Provides the Buffer representation of the object
1354
+ * @returns the buffer representation of the object
1355
+ */
1356
+ public toBuffer(): Buffer {
1357
+ const payload = new PortableStorage();
1358
+
1359
+ if (this.transactions.length !== 0) {
1360
+ const txs: string[] = [];
1361
+
1362
+ this.transactions.forEach((tx) => txs.push(tx.toString()));
1363
+
1364
+ payload.set('txs', txs, StorageType.STRING_ARRAY);
1365
+ }
1366
+
1367
+ if (this.blocks.length !== 0) {
1368
+ const blocks: PortableStorage[] = [];
1369
+
1370
+ this.blocks.forEach((rawBlock) => {
1371
+ const block = new PortableStorage();
1372
+
1373
+ block.set('block', rawBlock.block.toString(), StorageType.STRING);
1374
+
1375
+ const txs: string[] = [];
1376
+
1377
+ rawBlock.transactions.forEach((tx) => txs.push(tx.toString()));
1378
+
1379
+ if (txs.length !== 0) {
1380
+ block.set('txs', txs, StorageType.STRING_ARRAY);
1381
+ }
1382
+
1383
+ blocks.push(block);
1384
+ });
1385
+
1386
+ payload.set('blocks', blocks, StorageType.OBJECT_ARRAY);
1387
+ }
1388
+
1389
+ if (this.missed_ids.length !== 0) {
1390
+ const writer = new Writer();
1391
+
1392
+ this.missed_ids.forEach((id) => writer.hash(id));
1393
+
1394
+ payload.set('missed_ids', writer.buffer.toString('hex'), StorageType.STRING);
1395
+ }
1396
+
1397
+ payload.set('current_blockchain_height', BigInteger(this.current_blockchain_height), StorageType.UINT32);
1398
+
1399
+ return payload.toBuffer();
1400
+ }
1401
+
1402
+ /**
1403
+ * Provides the hexadecimal (blob) representation of the object
1404
+ * @returns the hexadecimal (blob) representation of the object
1405
+ */
1406
+ public toString(): string {
1407
+ return this.toBuffer().toString('hex');
1408
+ }
1409
+ }
1410
+
1411
+ export class TimedSync implements ILevinPayload {
1412
+
1413
+ /**
1414
+ * The current time of the node
1415
+ */
1416
+ public get local_time(): Date {
1417
+ return this.m_local_time;
1418
+ }
1419
+
1420
+ public set local_time(value: Date) {
1421
+ this.m_local_time = value;
1422
+ }
1423
+
1424
+ /**
1425
+ * The current height of the node
1426
+ */
1427
+ public get current_height(): number {
1428
+ return this.m_current_height;
1429
+ }
1430
+
1431
+ public set current_height(value: number) {
1432
+ this.m_current_height = value;
1433
+ }
1434
+
1435
+ /**
1436
+ * The last known block hash of the node
1437
+ */
1438
+ public get top_id(): string {
1439
+ return this.m_top_id;
1440
+ }
1441
+
1442
+ public set top_id(value: string) {
1443
+ const reader = new Reader(value);
1444
+ if (reader.length !== SIZES.KEY) {
1445
+ throw new Error('Invalid top id length');
1446
+ }
1447
+
1448
+ this.m_top_id = reader.hash();
1449
+ }
1450
+
1451
+ /**
1452
+ * The list of locally known peers
1453
+ */
1454
+ public get local_peerlist(): PeerEntry[] {
1455
+ return this.m_local_peerlist;
1456
+ }
1457
+
1458
+ public set local_peerlist(value: PeerEntry[]) {
1459
+ this.m_local_peerlist = value;
1460
+ }
1461
+
1462
+ /**
1463
+ * Creates a new instance of the object using the supplied data found in the levin packet
1464
+ * @param data the data contained for the payload in the levin packet
1465
+ * @returns a new instance of the object
1466
+ */
1467
+ public static from(data: Reader | Buffer | string): TimedSync {
1468
+ const payload = PortableStorage.from(data);
1469
+
1470
+ const result = new TimedSync();
1471
+
1472
+ if (payload.exists('local_time')) {
1473
+ const lt = (payload.get('local_time') as BigInteger.BigInteger)
1474
+ .toString(16)
1475
+ .padStart(16, '0');
1476
+
1477
+ result.local_time = (new Reader(lt)).time_t(true);
1478
+ }
1479
+
1480
+ result.current_height =
1481
+ ((payload.get('payload_data') as PortableStorage).get('current_height') as BigInteger.BigInteger)
1482
+ .toJSNumber();
1483
+
1484
+ result.top_id = (payload.get('payload_data') as PortableStorage).get('top_id') as string;
1485
+
1486
+ if (payload.exists('local_peerlist')) {
1487
+ const peerlist = (payload.get('local_peerlist')) as Buffer;
1488
+
1489
+ const reader = new Reader(peerlist);
1490
+
1491
+ if (reader.length % 24 !== 0) {
1492
+ throw new Error('Error parsing local_peer list');
1493
+ }
1494
+
1495
+ while (reader.unreadBytes > 0) {
1496
+ result.local_peerlist.push(PeerEntry.from(reader.bytes(24)));
1497
+ }
1498
+ }
1499
+
1500
+ return result;
1501
+ }
1502
+
1503
+ private m_local_time: Date = new Date(0);
1504
+ private m_current_height: number = 0;
1505
+ private m_top_id: string = ''.padStart(64, '0');
1506
+ private m_local_peerlist: PeerEntry[] = [];
1507
+
1508
+ /**
1509
+ * Provides the Buffer representation of the object
1510
+ * @returns the buffer representation of the object
1511
+ */
1512
+ public toBuffer(): Buffer {
1513
+ const payload = new PortableStorage();
1514
+
1515
+ if (this.local_time.getTime() !== 0) {
1516
+ const writer = new Writer();
1517
+ writer.time_t(this.local_time, true);
1518
+
1519
+ payload.set('local_time', BigInteger(writer.blob, 16), StorageType.UINT64);
1520
+ }
1521
+
1522
+ const payload_data = new PortableStorage();
1523
+ payload_data.set('current_height', BigInteger(this.current_height), StorageType.UINT32);
1524
+ payload_data.set('top_id', this.top_id, StorageType.STRING);
1525
+
1526
+ payload.set('payload_data', payload_data, StorageType.OBJECT);
1527
+
1528
+ const peerList = new Writer();
1529
+ this.local_peerlist.forEach((peer) => peerList.write(peer.toBuffer()));
1530
+
1531
+ if (peerList.length !== 0) {
1532
+ payload.set('local_peerlist', peerList.buffer.toString('hex'), StorageType.STRING);
1533
+ }
1534
+
1535
+ return payload.toBuffer();
1536
+ }
1537
+
1538
+ /**
1539
+ * Provides the hexadecimal (blob) representation of the object
1540
+ * @returns the hexadecimal (blob) representation of the object
1541
+ */
1542
+ public toString(): string {
1543
+ return this.toBuffer().toString('hex');
1544
+ }
1545
+ }
1546
+ }
1547
+
1548
+ /** @ignore */
1549
+ export function int2ip(ipInt: number): string {
1550
+ if (ipInt > 4294967295) {
1551
+ throw new Error('Integer value exceeds 32-bit bounds');
1552
+ }
1553
+
1554
+ return ((ipInt >>> 24) + '.' + (ipInt >> 16 & 255) + '.' + (ipInt >> 8 & 255) + '.' + (ipInt & 255));
1555
+ }
1556
+
1557
+ /** @ignore */
1558
+ export function ip2int(ip: string): number {
1559
+ const tmp = ip.split('.');
1560
+
1561
+ if (tmp.length !== 4) {
1562
+ throw new Error('Does not appear to be a valid IP address');
1563
+ }
1564
+
1565
+ tmp.forEach((octet) => {
1566
+ if (isNaN(parseInt(octet, 10))) {
1567
+ throw new Error('Non-numeric value found in octet');
1568
+ }
1569
+
1570
+ if (parseInt(octet, 10) > 255 || parseInt(octet, 10) < 0) {
1571
+ throw new Error('Invalid value found in octet');
1572
+ }
1573
+ });
1574
+
1575
+ return tmp.reduce((ipInt, octet) => (ipInt << 8) + parseInt(octet, 10), 0) >>> 0;
1576
+ }