@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.
- package/.github/workflows/ci.yml +27 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/turtlecoin-utils.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/.travis.yml +11 -0
- package/CONTRIBUTING.md +3 -0
- package/LICENSE +674 -0
- package/README.md +203 -0
- package/config.json +7 -0
- package/docs/.nojekyll +0 -0
- package/docs/CNAME +1 -0
- package/docs/assets/css/main.css +2321 -0
- package/docs/assets/images/icons.png +0 -0
- package/docs/assets/images/icons@2x.png +0 -0
- package/docs/assets/images/widgets.png +0 -0
- package/docs/assets/images/widgets@2x.png +0 -0
- package/docs/assets/js/main.js +1 -0
- package/docs/assets/js/search.js +3 -0
- package/docs/classes/address.html +964 -0
- package/docs/classes/addressprefix.html +431 -0
- package/docs/classes/block.html +965 -0
- package/docs/classes/blocktemplate.html +695 -0
- package/docs/classes/cryptonote.html +1137 -0
- package/docs/classes/ed25519.keypair.html +400 -0
- package/docs/classes/ed25519.keys.html +373 -0
- package/docs/classes/extranoncetag.extranoncedata.html +454 -0
- package/docs/classes/extranoncetag.extranoncepaymentid.html +453 -0
- package/docs/classes/extranoncetag.iextranonce.html +347 -0
- package/docs/classes/extratag.extramergedmining.html +494 -0
- package/docs/classes/extratag.extranonce.html +530 -0
- package/docs/classes/extratag.extrapadding.html +456 -0
- package/docs/classes/extratag.extrapublickey.html +460 -0
- package/docs/classes/extratag.iextratag.html +355 -0
- package/docs/classes/levinpacket.html +674 -0
- package/docs/classes/levinpayloads.handshake.html +731 -0
- package/docs/classes/levinpayloads.ilevinpayload.html +318 -0
- package/docs/classes/levinpayloads.liteblock.html +494 -0
- package/docs/classes/levinpayloads.missingtransactions.html +494 -0
- package/docs/classes/levinpayloads.newblock.html +540 -0
- package/docs/classes/levinpayloads.newtransactions.html +402 -0
- package/docs/classes/levinpayloads.peerentry.html +610 -0
- package/docs/classes/levinpayloads.ping.html +450 -0
- package/docs/classes/levinpayloads.rawblock.html +344 -0
- package/docs/classes/levinpayloads.requestchain.html +402 -0
- package/docs/classes/levinpayloads.requestgetobjects.html +448 -0
- package/docs/classes/levinpayloads.requesttxpool.html +402 -0
- package/docs/classes/levinpayloads.responsechain.html +494 -0
- package/docs/classes/levinpayloads.responsegetobjects.html +540 -0
- package/docs/classes/levinpayloads.timedsync.html +540 -0
- package/docs/classes/multisig.html +930 -0
- package/docs/classes/multisigmessage.html +694 -0
- package/docs/classes/parentblock.html +347 -0
- package/docs/classes/transaction.html +925 -0
- package/docs/classes/transactioninputs.coinbaseinput.html +390 -0
- package/docs/classes/transactioninputs.itransactioninput.html +321 -0
- package/docs/classes/transactioninputs.keyinput.html +459 -0
- package/docs/classes/transactionoutputs.itransactionoutput.html +317 -0
- package/docs/classes/transactionoutputs.keyoutput.html +422 -0
- package/docs/enums/extranoncetag.noncetagtype.html +246 -0
- package/docs/enums/extratag.extratagtype.html +280 -0
- package/docs/enums/levinprotocol.commandtype.html +391 -0
- package/docs/enums/transactioninputs.inputtype.html +246 -0
- package/docs/enums/transactionoutputs.outputtype.html +229 -0
- package/docs/globals.html +238 -0
- package/docs/index.html +271 -0
- package/docs/interfaces/interfaces.config.html +590 -0
- package/docs/interfaces/interfaces.daemonblocktemplateresponse.html +323 -0
- package/docs/interfaces/interfaces.generatedinput.html +304 -0
- package/docs/interfaces/interfaces.generatedoutput.html +285 -0
- package/docs/interfaces/interfaces.inputkeys.html +304 -0
- package/docs/interfaces/interfaces.ipreparedtransaction.html +268 -0
- package/docs/interfaces/interfaces.output.html +399 -0
- package/docs/interfaces/interfaces.preparedringsignature.html +377 -0
- package/docs/interfaces/interfaces.preparedtransaction.html +329 -0
- package/docs/interfaces/interfaces.randomoutput.html +285 -0
- package/docs/interfaces/interfaces.transactionrecipient.html +285 -0
- package/docs/interfaces/multisiginterfaces.partialkeyimage.html +277 -0
- package/docs/interfaces/multisiginterfaces.partialsigningkey.html +277 -0
- package/docs/modules/ed25519.html +195 -0
- package/docs/modules/extranoncetag.html +208 -0
- package/docs/modules/extratag.html +216 -0
- package/docs/modules/interfaces.html +231 -0
- package/docs/modules/levinpayloads.html +247 -0
- package/docs/modules/levinprotocol.html +191 -0
- package/docs/modules/multisiginterfaces.html +195 -0
- package/docs/modules/transactioninputs.html +208 -0
- package/docs/modules/transactionoutputs.html +204 -0
- package/index.d.ts +417 -0
- package/index.js +1508 -0
- package/lib/base58.js +220 -0
- package/lib/biginteger.js +1591 -0
- package/lib/blocktemplate.js +408 -0
- package/lib/crypto.js +19698 -0
- package/lib/mnemonic.js +1204 -0
- package/lib/nacl-fast-cn.js +608 -0
- package/lib/ringsigs.js +24262 -0
- package/lib/sha3.js +477 -0
- package/package.json +58 -0
- package/src/Address.ts +433 -0
- package/src/AddressPrefix.ts +117 -0
- package/src/Block.ts +556 -0
- package/src/BlockTemplate.ts +289 -0
- package/src/Common.ts +105 -0
- package/src/Config.ts +66 -0
- package/src/CryptoNote.ts +1072 -0
- package/src/LevinPacket.ts +366 -0
- package/src/Multisig.ts +600 -0
- package/src/MultisigMessage.ts +374 -0
- package/src/ParentBlock.ts +39 -0
- package/src/Transaction.ts +628 -0
- package/src/Types/ED25519.ts +187 -0
- package/src/Types/IExtraNonce.ts +225 -0
- package/src/Types/IExtraTag.ts +507 -0
- package/src/Types/ITransaction.ts +230 -0
- package/src/Types/ITransactionInput.ts +190 -0
- package/src/Types/ITransactionOutput.ts +108 -0
- package/src/Types/LevinPayloads.ts +1576 -0
- package/src/Types/MultisigInterfaces.ts +65 -0
- package/src/Types/PortableStorage.ts +289 -0
- package/src/Types.ts +36 -0
- package/src/index.ts +36 -0
- package/test/template.json +6 -0
- package/test/test.js +1457 -0
- package/tests/blocktemplate.json +6 -0
- package/tests/tests.js +215 -0
- package/tsconfig.json +15 -0
- package/tslint.json +36 -0
- package/typedoc.json +10 -0
- 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
|
+
}
|