trac-peer 0.1.57 → 0.1.59
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/package.json +3 -1
- package/src/api.js +234 -15
- package/src/functions.js +2 -35
- package/src/index.js +17 -121
- package/src/protocol.js +4 -4
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trac-peer",
|
|
3
3
|
"main": "src/index.js",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.59",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"assert": "npm:bare-node-assert",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"brittle": "3.0.0",
|
|
38
38
|
"buffer": "npm:bare-node-buffer",
|
|
39
39
|
"child_process": "npm:bare-node-child-process",
|
|
40
|
+
"compact-encoding": "^2.16.1",
|
|
40
41
|
"console": "npm:bare-node-console",
|
|
41
42
|
"corestore": "7.4.1",
|
|
42
43
|
"crypto": "npm:bare-node-crypto",
|
|
@@ -60,6 +61,7 @@
|
|
|
60
61
|
"path": "npm:bare-node-path",
|
|
61
62
|
"pear-interface": "1.0.0",
|
|
62
63
|
"process": "npm:bare-node-process",
|
|
64
|
+
"protomux": "^3.10.1",
|
|
63
65
|
"protomux-wakeup": "^2.2.1",
|
|
64
66
|
"readline": "npm:bare-node-readline",
|
|
65
67
|
"ready-resource": "^1.0.0",
|
package/src/api.js
CHANGED
|
@@ -2,6 +2,14 @@ import b4a from "b4a";
|
|
|
2
2
|
import {jsonStringify} from "./functions.js";
|
|
3
3
|
|
|
4
4
|
export class ProtocolApi{
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Exposes read and write functions.
|
|
8
|
+
* May be extended by contract protocol instances.
|
|
9
|
+
*
|
|
10
|
+
* @param peer
|
|
11
|
+
* @param options
|
|
12
|
+
*/
|
|
5
13
|
constructor(peer, options = {}) {
|
|
6
14
|
this.peer = peer;
|
|
7
15
|
this.api_tx_exposed = options.api_tx_exposed === true;
|
|
@@ -9,30 +17,57 @@ export class ProtocolApi{
|
|
|
9
17
|
this.options = options;
|
|
10
18
|
}
|
|
11
19
|
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @returns {null|string}
|
|
23
|
+
*/
|
|
12
24
|
getPeerValidatorAddress(){
|
|
13
|
-
return this.peer.validator;
|
|
25
|
+
return this.peer.msb.getNetwork().validator;
|
|
14
26
|
}
|
|
15
27
|
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @returns {null|string}
|
|
31
|
+
*/
|
|
16
32
|
getPeerBootstrap(){
|
|
17
33
|
return this.peer.bootstrap;
|
|
18
34
|
}
|
|
19
35
|
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @returns {null|string}
|
|
39
|
+
*/
|
|
20
40
|
getPeerMsbBootstrap(){
|
|
21
41
|
return this.peer.msb.bootstrap;
|
|
22
42
|
}
|
|
23
43
|
|
|
44
|
+
/**
|
|
45
|
+
*
|
|
46
|
+
* @returns {null|string}
|
|
47
|
+
*/
|
|
24
48
|
getPeerWriterKey(){
|
|
25
49
|
return this.peer.writerLocalKey;
|
|
26
50
|
}
|
|
27
51
|
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
* @returns {string}
|
|
55
|
+
*/
|
|
28
56
|
generateNonce(){
|
|
29
57
|
return this.peer.protocol_instance.generateNonce();
|
|
30
58
|
}
|
|
31
59
|
|
|
32
|
-
|
|
60
|
+
/**
|
|
61
|
+
* @throws Error
|
|
62
|
+
* @param msg
|
|
63
|
+
* @param address
|
|
64
|
+
* @param reply_to
|
|
65
|
+
* @param attachments
|
|
66
|
+
* @returns {{dispatch: {type: string, msg: string, address, attachments: *[], deleted_by: null, reply_to: (number|null), pinned: boolean, pin_id: null}}}
|
|
67
|
+
*/
|
|
68
|
+
prepareMessage(msg, address, reply_to = null, attachments = []){
|
|
33
69
|
if(typeof msg !== 'string') throw new Error('Msg must be a string');
|
|
34
|
-
if(b4a.byteLength(jsonStringify(address))
|
|
35
|
-
if(b4a.byteLength(jsonStringify(reply_to)) > 256) throw new Error('Reply to too large.');
|
|
70
|
+
if(b4a.byteLength(jsonStringify(address)) !== 66) throw new Error('Address too large.');
|
|
36
71
|
if(reply_to !== null && isNaN(parseInt(reply_to))) throw new Error('Reply to not a number.');
|
|
37
72
|
if(false === Array.isArray(attachments)) throw new Error('attachments must be an array.');
|
|
38
73
|
if(attachments.length > 20) throw new Error('Too many attachments');
|
|
@@ -54,8 +89,36 @@ export class ProtocolApi{
|
|
|
54
89
|
return prepared;
|
|
55
90
|
}
|
|
56
91
|
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
* @returns {boolean}
|
|
95
|
+
*/
|
|
96
|
+
msgExposed(){
|
|
97
|
+
return true === this.api_msg_exposed;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* To post a message, an ed25519 signature has to be provided over the given message + nonce.
|
|
102
|
+
*
|
|
103
|
+
* Signing steps:
|
|
104
|
+
*
|
|
105
|
+
* let address = your_ed25519_wallet.getAccountAddress()
|
|
106
|
+
* let nonce = api.generateNonce()
|
|
107
|
+
* let prepared_message = api.prepareMessage("my message", address)
|
|
108
|
+
* let signature = your_ed25519_wallet.sign(JSON.stringify(prepared_message) + nonce)
|
|
109
|
+
* let result = api.post(prepared_message, signature, nonce)
|
|
110
|
+
*
|
|
111
|
+
* Note: new messages can be read from this api's msg functions.
|
|
112
|
+
*
|
|
113
|
+
* @throws Error
|
|
114
|
+
* @param prepared_message
|
|
115
|
+
* @param signature
|
|
116
|
+
* @param nonce
|
|
117
|
+
* @returns {Promise<void>}
|
|
118
|
+
*/
|
|
57
119
|
async post(prepared_message, signature, nonce){
|
|
58
|
-
if(
|
|
120
|
+
if(true !== this.api_msg_exposed) throw new Error('Posting messages not exposed in API.');
|
|
121
|
+
if(this.peer.base.writable === false) throw new Error('Peer is not writable.');
|
|
59
122
|
if(b4a.byteLength(jsonStringify(prepared_message)) > this.peer.protocol_instance.msgMaxBytes()) throw new Error('Prepared message too large.');
|
|
60
123
|
if(typeof prepared_message !== 'object') throw new Error('Prepared message must be an object generated with api.prepareMessage().');
|
|
61
124
|
if(prepared_message.dispatch === undefined || prepared_message.dispatch.type === undefined ||
|
|
@@ -66,6 +129,8 @@ export class ProtocolApi{
|
|
|
66
129
|
if(prepared_message.dispatch.type !== 'msg') throw new Error('Invalid type.');
|
|
67
130
|
if(typeof prepared_message.dispatch.msg !== 'string') throw new Error('Msg must be a string');
|
|
68
131
|
if(b4a.toString(b4a.from(prepared_message.dispatch.address, 'hex'), 'hex') !== prepared_message.dispatch.address) throw new Error('Invalid address.');
|
|
132
|
+
if(b4a.toString(b4a.from(signature, 'hex'), 'hex') !== signature) throw new Error('Invalid signature.');
|
|
133
|
+
if(b4a.toString(b4a.from(nonce, 'hex'), 'hex') !== nonce) throw new Error('Invalid nonce.');
|
|
69
134
|
if(false === Array.isArray(prepared_message.dispatch.attachments)) throw new Error('attachments must be an array.');
|
|
70
135
|
if(prepared_message.dispatch.attachments.length > 20) throw new Error('Too many attachments');
|
|
71
136
|
for(let i = 0; i < prepared_message.dispatch.attachments.length; i++){
|
|
@@ -80,25 +145,52 @@ export class ProtocolApi{
|
|
|
80
145
|
await this.peer.base.append({type: 'msg', value: prepared_message, hash : signature, nonce: nonce });
|
|
81
146
|
}
|
|
82
147
|
|
|
148
|
+
/**
|
|
149
|
+
* @throws Error
|
|
150
|
+
* @param address
|
|
151
|
+
* @param command_hash
|
|
152
|
+
* @param nonce
|
|
153
|
+
* @returns {Promise<*>}
|
|
154
|
+
*/
|
|
83
155
|
async generateTx(address, command_hash, nonce) {
|
|
156
|
+
if(this.getPeerValidatorAddress() === null) throw new Error('Peer not connected to a validator.');
|
|
84
157
|
return await this.peer.protocol_instance.generateTx(this.getPeerBootstrap(),
|
|
85
158
|
this.getPeerMsbBootstrap(), this.getPeerValidatorAddress(), this.getPeerWriterKey(),
|
|
86
159
|
address, command_hash, nonce);
|
|
87
160
|
}
|
|
88
161
|
|
|
162
|
+
/**
|
|
163
|
+
*
|
|
164
|
+
* @param command
|
|
165
|
+
* @returns {*}
|
|
166
|
+
*/
|
|
89
167
|
prepareTxCommand(command){
|
|
90
168
|
return this.peer.protocol_instance.mapTxCommand(command);
|
|
91
169
|
}
|
|
92
170
|
|
|
93
171
|
/**
|
|
94
|
-
*
|
|
172
|
+
*
|
|
173
|
+
* @returns {boolean}
|
|
174
|
+
*/
|
|
175
|
+
txExposed(){
|
|
176
|
+
return true === this.api_tx_exposed;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* To broadcast a TX, an ed25519 signature has to be provided over the given tx + nonce.
|
|
95
181
|
*
|
|
96
182
|
* Signing steps:
|
|
183
|
+
*
|
|
184
|
+
* let address = your_ed25519_wallet.getAccountAddress()
|
|
97
185
|
* let nonce = api.generateNonce()
|
|
98
186
|
* let tx_hash = api.generateTx(address, a_sha256_function(JSON.stringify(api.prepareTxCommand(command))), nonce)
|
|
99
|
-
* let signature =
|
|
100
|
-
*
|
|
187
|
+
* let signature = your_ed25519_wallet.sign(tx + nonce)
|
|
188
|
+
* // simulating
|
|
189
|
+
* let sim_result = api.tx(tx_hash, api.prepareTxCommand(command), address, signature, nonce, true)
|
|
190
|
+
* // broadcasting
|
|
191
|
+
* let result = api.tx(tx_hash, api.prepareTxCommand(command), address, signature, nonce)
|
|
101
192
|
*
|
|
193
|
+
* @throws Error
|
|
102
194
|
* @param tx
|
|
103
195
|
* @param prepared_command
|
|
104
196
|
* @param address
|
|
@@ -108,18 +200,19 @@ export class ProtocolApi{
|
|
|
108
200
|
* @returns {Promise<boolean|object>}
|
|
109
201
|
*/
|
|
110
202
|
async tx(tx, prepared_command, address, signature, nonce, sim = false ){
|
|
111
|
-
if(
|
|
203
|
+
if(true !== this.api_tx_exposed) throw new Error('Transactions not exposed in API.');
|
|
204
|
+
if(this.peer.base.writable === false) throw new Error('Peer is not writable.');
|
|
112
205
|
if(this.getPeerValidatorAddress() === null) throw new Error('Peer not connected to a validator.');
|
|
113
206
|
if(typeof prepared_command !== 'object') throw new Error('prepared_command must be an object.');
|
|
114
207
|
if(typeof prepared_command.type !== 'string') throw new Error('prepared_command.type must exist and be a string.');
|
|
115
208
|
if(prepared_command.value === undefined) throw new Error('prepared_command.value is missing.');
|
|
116
209
|
if(b4a.byteLength(jsonStringify(prepared_command)) > this.peer.protocol_instance.txMaxBytes()) throw new Error('prepared_command too large.');
|
|
117
|
-
if(b4a.byteLength(jsonStringify(address)) !==
|
|
118
|
-
if(b4a.byteLength(jsonStringify(signature)) !==
|
|
119
|
-
if(b4a.byteLength(jsonStringify(nonce)) !==
|
|
120
|
-
if(b4a.toString(b4a.from(
|
|
121
|
-
if(b4a.toString(b4a.from(
|
|
122
|
-
if(b4a.toString(b4a.from(nonce, '
|
|
210
|
+
if(b4a.byteLength(jsonStringify(address)) !== 66) throw new Error('Address length invalid.');
|
|
211
|
+
if(b4a.byteLength(jsonStringify(signature)) !== 130) throw new Error('Signature length invalid.');
|
|
212
|
+
if(b4a.byteLength(jsonStringify(nonce)) !== 66) throw new Error('Nonce length invalid.');
|
|
213
|
+
if(b4a.toString(b4a.from(address, 'hex'), 'hex') !== address) throw new Error('Invalid address.');
|
|
214
|
+
if(b4a.toString(b4a.from(signature, 'hex'), 'hex') !== signature) throw new Error('Invalid signature.');
|
|
215
|
+
if(b4a.toString(b4a.from(nonce, 'hex'), 'hex') !== nonce) throw new Error('Invalid nonce.');
|
|
123
216
|
const verified = this.peer.wallet.verify(signature, tx + nonce, address);
|
|
124
217
|
if(false === verified) throw new Error('Invalid signature.');
|
|
125
218
|
const content_hash = await this.peer.createHash('sha256', this.peer.protocol_instance.safeJsonStringify(prepared_command));
|
|
@@ -140,6 +233,11 @@ export class ProtocolApi{
|
|
|
140
233
|
return res;
|
|
141
234
|
}
|
|
142
235
|
|
|
236
|
+
/**
|
|
237
|
+
*
|
|
238
|
+
* @param signed
|
|
239
|
+
* @returns {Promise<null>}
|
|
240
|
+
*/
|
|
143
241
|
async getAdmin(signed = true){
|
|
144
242
|
let res = null;
|
|
145
243
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('admin');
|
|
@@ -148,6 +246,11 @@ export class ProtocolApi{
|
|
|
148
246
|
return null;
|
|
149
247
|
}
|
|
150
248
|
|
|
249
|
+
/**
|
|
250
|
+
*
|
|
251
|
+
* @param signed
|
|
252
|
+
* @returns {Promise<boolean|null>}
|
|
253
|
+
*/
|
|
151
254
|
async getWhitelistEnabled(signed = true){
|
|
152
255
|
let res = null;
|
|
153
256
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('wlst');
|
|
@@ -156,6 +259,12 @@ export class ProtocolApi{
|
|
|
156
259
|
return false;
|
|
157
260
|
}
|
|
158
261
|
|
|
262
|
+
/**
|
|
263
|
+
*
|
|
264
|
+
* @param address
|
|
265
|
+
* @param signed
|
|
266
|
+
* @returns {Promise<boolean|null>}
|
|
267
|
+
*/
|
|
159
268
|
async getWhitelistStatus(address, signed = true){
|
|
160
269
|
let res = null;
|
|
161
270
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('wl/'+address);
|
|
@@ -164,6 +273,12 @@ export class ProtocolApi{
|
|
|
164
273
|
return false;
|
|
165
274
|
}
|
|
166
275
|
|
|
276
|
+
/**
|
|
277
|
+
*
|
|
278
|
+
* @param address
|
|
279
|
+
* @param signed
|
|
280
|
+
* @returns {Promise<boolean|null>}
|
|
281
|
+
*/
|
|
167
282
|
async getModStatus(address, signed = true){
|
|
168
283
|
let res = null;
|
|
169
284
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('mod/'+address);
|
|
@@ -172,6 +287,12 @@ export class ProtocolApi{
|
|
|
172
287
|
return false;
|
|
173
288
|
}
|
|
174
289
|
|
|
290
|
+
/**
|
|
291
|
+
*
|
|
292
|
+
* @param address
|
|
293
|
+
* @param signed
|
|
294
|
+
* @returns {Promise<boolean|null>}
|
|
295
|
+
*/
|
|
175
296
|
async getMuteStatus(address, signed = true){
|
|
176
297
|
let res = null;
|
|
177
298
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('mtd/'+address);
|
|
@@ -180,6 +301,11 @@ export class ProtocolApi{
|
|
|
180
301
|
return false;
|
|
181
302
|
}
|
|
182
303
|
|
|
304
|
+
/**
|
|
305
|
+
*
|
|
306
|
+
* @param signed
|
|
307
|
+
* @returns {Promise<boolean>}
|
|
308
|
+
*/
|
|
183
309
|
async getAutoAddWritersStatus(signed = true){
|
|
184
310
|
let res = null;
|
|
185
311
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('auto_add_writers');
|
|
@@ -190,6 +316,11 @@ export class ProtocolApi{
|
|
|
190
316
|
return false;
|
|
191
317
|
}
|
|
192
318
|
|
|
319
|
+
/**
|
|
320
|
+
*
|
|
321
|
+
* @param signed
|
|
322
|
+
* @returns {Promise<boolean>}
|
|
323
|
+
*/
|
|
193
324
|
async getChatStatus(signed = true){
|
|
194
325
|
let res = null;
|
|
195
326
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('chat_status');
|
|
@@ -200,6 +331,12 @@ export class ProtocolApi{
|
|
|
200
331
|
return false;
|
|
201
332
|
}
|
|
202
333
|
|
|
334
|
+
/**
|
|
335
|
+
*
|
|
336
|
+
* @param nick
|
|
337
|
+
* @param signed
|
|
338
|
+
* @returns {Promise<null>}
|
|
339
|
+
*/
|
|
203
340
|
async getAddressFromNick(nick, signed = true){
|
|
204
341
|
let res = null;
|
|
205
342
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('kcin/'+nick);
|
|
@@ -207,6 +344,12 @@ export class ProtocolApi{
|
|
|
207
344
|
return res;
|
|
208
345
|
}
|
|
209
346
|
|
|
347
|
+
/**
|
|
348
|
+
*
|
|
349
|
+
* @param address
|
|
350
|
+
* @param signed
|
|
351
|
+
* @returns {Promise<null>}
|
|
352
|
+
*/
|
|
210
353
|
async getNick(address, signed = true){
|
|
211
354
|
let res = null;
|
|
212
355
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('nick/'+address);
|
|
@@ -214,6 +357,11 @@ export class ProtocolApi{
|
|
|
214
357
|
return res;
|
|
215
358
|
}
|
|
216
359
|
|
|
360
|
+
/**
|
|
361
|
+
*
|
|
362
|
+
* @param signed
|
|
363
|
+
* @returns {Promise<number>}
|
|
364
|
+
*/
|
|
217
365
|
async getPinnedMessageLength(signed = true){
|
|
218
366
|
let res = null;
|
|
219
367
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('pnl');
|
|
@@ -222,6 +370,12 @@ export class ProtocolApi{
|
|
|
222
370
|
return res;
|
|
223
371
|
}
|
|
224
372
|
|
|
373
|
+
/**
|
|
374
|
+
*
|
|
375
|
+
* @param index
|
|
376
|
+
* @param signed
|
|
377
|
+
* @returns {Promise<null>}
|
|
378
|
+
*/
|
|
225
379
|
async getPinnedMessage(index, signed = true){
|
|
226
380
|
let res = null;
|
|
227
381
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('pni/'+parseInt(index));
|
|
@@ -232,6 +386,11 @@ export class ProtocolApi{
|
|
|
232
386
|
return await this.getMessage(res.msg, signed);
|
|
233
387
|
}
|
|
234
388
|
|
|
389
|
+
/**
|
|
390
|
+
*
|
|
391
|
+
* @param signed
|
|
392
|
+
* @returns {Promise<number>}
|
|
393
|
+
*/
|
|
235
394
|
async getDeletedMessageLength(signed = true){
|
|
236
395
|
let res = null;
|
|
237
396
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('delml');
|
|
@@ -240,6 +399,12 @@ export class ProtocolApi{
|
|
|
240
399
|
return res;
|
|
241
400
|
}
|
|
242
401
|
|
|
402
|
+
/**
|
|
403
|
+
*
|
|
404
|
+
* @param index
|
|
405
|
+
* @param signed
|
|
406
|
+
* @returns {Promise<null>}
|
|
407
|
+
*/
|
|
243
408
|
async getDeletedMessage(index, signed = true){
|
|
244
409
|
let res = null;
|
|
245
410
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('delm/'+parseInt(index));
|
|
@@ -250,6 +415,11 @@ export class ProtocolApi{
|
|
|
250
415
|
return await this.getMessage(res, signed);
|
|
251
416
|
}
|
|
252
417
|
|
|
418
|
+
/**
|
|
419
|
+
*
|
|
420
|
+
* @param signed
|
|
421
|
+
* @returns {Promise<number>}
|
|
422
|
+
*/
|
|
253
423
|
async getMessageLength(signed = true){
|
|
254
424
|
let res = null;
|
|
255
425
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('msgl');
|
|
@@ -258,6 +428,12 @@ export class ProtocolApi{
|
|
|
258
428
|
return res;
|
|
259
429
|
}
|
|
260
430
|
|
|
431
|
+
/**
|
|
432
|
+
*
|
|
433
|
+
* @param index
|
|
434
|
+
* @param signed
|
|
435
|
+
* @returns {Promise<null>}
|
|
436
|
+
*/
|
|
261
437
|
async getMessage(index, signed = true){
|
|
262
438
|
let res = null;
|
|
263
439
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('msg/'+parseInt(index));
|
|
@@ -265,6 +441,12 @@ export class ProtocolApi{
|
|
|
265
441
|
return res;
|
|
266
442
|
}
|
|
267
443
|
|
|
444
|
+
/**
|
|
445
|
+
*
|
|
446
|
+
* @param address
|
|
447
|
+
* @param signed
|
|
448
|
+
* @returns {Promise<number>}
|
|
449
|
+
*/
|
|
268
450
|
async getUserMessageLength(address, signed = true){
|
|
269
451
|
let res = null;
|
|
270
452
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('umsgl/'+address);
|
|
@@ -273,6 +455,13 @@ export class ProtocolApi{
|
|
|
273
455
|
return res;
|
|
274
456
|
}
|
|
275
457
|
|
|
458
|
+
/**
|
|
459
|
+
*
|
|
460
|
+
* @param address
|
|
461
|
+
* @param index
|
|
462
|
+
* @param signed
|
|
463
|
+
* @returns {Promise<null>}
|
|
464
|
+
*/
|
|
276
465
|
async getUserMessage(address, index, signed = true){
|
|
277
466
|
let res = null;
|
|
278
467
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('umsg/'+address+'/'+parseInt(index));
|
|
@@ -283,6 +472,11 @@ export class ProtocolApi{
|
|
|
283
472
|
return await this.getMessage(res, signed);
|
|
284
473
|
}
|
|
285
474
|
|
|
475
|
+
/**
|
|
476
|
+
*
|
|
477
|
+
* @param signed
|
|
478
|
+
* @returns {Promise<number>}
|
|
479
|
+
*/
|
|
286
480
|
async getTxLength(signed = true){
|
|
287
481
|
let res = null;
|
|
288
482
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('txl');
|
|
@@ -291,6 +485,12 @@ export class ProtocolApi{
|
|
|
291
485
|
return res;
|
|
292
486
|
}
|
|
293
487
|
|
|
488
|
+
/**
|
|
489
|
+
*
|
|
490
|
+
* @param index
|
|
491
|
+
* @param signed
|
|
492
|
+
* @returns {Promise<null>}
|
|
493
|
+
*/
|
|
294
494
|
async getTx(index, signed = true){
|
|
295
495
|
let res = null;
|
|
296
496
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('txi/'+parseInt(index));
|
|
@@ -298,6 +498,12 @@ export class ProtocolApi{
|
|
|
298
498
|
return res;
|
|
299
499
|
}
|
|
300
500
|
|
|
501
|
+
/**
|
|
502
|
+
*
|
|
503
|
+
* @param tx
|
|
504
|
+
* @param signed
|
|
505
|
+
* @returns {Promise<null>}
|
|
506
|
+
*/
|
|
301
507
|
async getTxData(tx, signed = true){
|
|
302
508
|
let index = null;
|
|
303
509
|
if(true === signed) index = await this.peer.protocol_instance.getSigned('tx/'+tx);
|
|
@@ -308,6 +514,12 @@ export class ProtocolApi{
|
|
|
308
514
|
return null;
|
|
309
515
|
}
|
|
310
516
|
|
|
517
|
+
/**
|
|
518
|
+
*
|
|
519
|
+
* @param address
|
|
520
|
+
* @param signed
|
|
521
|
+
* @returns {Promise<number>}
|
|
522
|
+
*/
|
|
311
523
|
async getUserTxLength(address, signed = true){
|
|
312
524
|
let res = null;
|
|
313
525
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('utxl/'+address);
|
|
@@ -316,6 +528,13 @@ export class ProtocolApi{
|
|
|
316
528
|
return res;
|
|
317
529
|
}
|
|
318
530
|
|
|
531
|
+
/**
|
|
532
|
+
*
|
|
533
|
+
* @param address
|
|
534
|
+
* @param index
|
|
535
|
+
* @param signed
|
|
536
|
+
* @returns {Promise<null>}
|
|
537
|
+
*/
|
|
319
538
|
async getUserTx(address, index, signed = true){
|
|
320
539
|
let res = null;
|
|
321
540
|
if(true === signed) res = await this.peer.protocol_instance.getSigned('utxi/'+address+'/'+parseInt(index));
|
package/src/functions.js
CHANGED
|
@@ -341,40 +341,7 @@ export async function joinValidator(input, peer){
|
|
|
341
341
|
if(validator === null || false === validator.value.isWriter || true === validator.value.isIndexer){
|
|
342
342
|
throw new Error('Invalid validator address.');
|
|
343
343
|
}
|
|
344
|
-
|
|
345
|
-
if(result === null) {
|
|
346
|
-
console.log('Validator not available');
|
|
347
|
-
} else {
|
|
348
|
-
let existing_stream = undefined;
|
|
349
|
-
if(peer.msb.getSwarm().peers.has(address)){
|
|
350
|
-
const peerInfo = peer.msb.getSwarm().peers.get(address)
|
|
351
|
-
existing_stream = peer.msb.getSwarm()._allConnections.get(peerInfo.publicKey)
|
|
352
|
-
}
|
|
353
|
-
if(existing_stream !== undefined){
|
|
354
|
-
peer.validator_stream = existing_stream;
|
|
355
|
-
peer.validator = address;
|
|
356
|
-
peer.validator_stream.on('close', () => {
|
|
357
|
-
peer.validator_stream = null;
|
|
358
|
-
peer.validator = null;
|
|
359
|
-
console.log('Validator stream closed', address);
|
|
360
|
-
});
|
|
361
|
-
console.log('Validator stream established', address);
|
|
362
|
-
} else {
|
|
363
|
-
peer.validator_stream = peer.msb.getSwarm().dht.connect(b4a.from(address, 'hex'));
|
|
364
|
-
peer.validator = address;
|
|
365
|
-
peer.validator_stream.on('open', () => {
|
|
366
|
-
console.log('Validator stream established', address);
|
|
367
|
-
});
|
|
368
|
-
peer.validator_stream.on('close', () => {
|
|
369
|
-
peer.validator_stream = null;
|
|
370
|
-
peer.validator = null;
|
|
371
|
-
});
|
|
372
|
-
peer.validator_stream.on('error', (error) => {
|
|
373
|
-
peer.validator_stream = null;
|
|
374
|
-
peer.validator = null;
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
}
|
|
344
|
+
await peer.tryConnection(address);
|
|
378
345
|
}
|
|
379
346
|
|
|
380
347
|
export async function tx(input, peer){
|
|
@@ -382,7 +349,7 @@ export async function tx(input, peer){
|
|
|
382
349
|
let res = false;
|
|
383
350
|
if(splitted.command === undefined){
|
|
384
351
|
res = new Error('Missing option. Please use the --command flag.');
|
|
385
|
-
} else if(splitted.sim === undefined && peer.validator === null){
|
|
352
|
+
} else if(splitted.sim === undefined && peer.msb.getNetwork().validator === null){
|
|
386
353
|
res = new Error('No validator available: Please wait for your peer to find an available one or use joinValidator to connect to a specific one.');
|
|
387
354
|
}
|
|
388
355
|
let sim = false;
|
package/src/index.js
CHANGED
|
@@ -11,6 +11,8 @@ import Corestore from 'corestore';
|
|
|
11
11
|
import w from 'protomux-wakeup';
|
|
12
12
|
import BlindPairing from 'blind-pairing'
|
|
13
13
|
const wakeup = new w();
|
|
14
|
+
import Protomux from 'protomux'
|
|
15
|
+
import c from 'compact-encoding'
|
|
14
16
|
import {
|
|
15
17
|
addWriter, addAdmin, setAutoAddWriters, setChatStatus, setMod, deleteMessage,
|
|
16
18
|
enableWhitelist, postMessage, jsonStringify, visibleLength, setNick,
|
|
@@ -44,6 +46,7 @@ export class Peer extends ReadyResource {
|
|
|
44
46
|
this.contract = options.contract || null;
|
|
45
47
|
this.wallet = options.wallet || null;
|
|
46
48
|
this.features = options.features || [];
|
|
49
|
+
this.custom_validators = options.custom_validators || [];
|
|
47
50
|
this.protocol_instance = null;
|
|
48
51
|
this.contract_instance = null;
|
|
49
52
|
this.channel = b4a.alloc(32).fill(options.channel) || null;
|
|
@@ -56,8 +59,6 @@ export class Peer extends ReadyResource {
|
|
|
56
59
|
this.check = new Check();
|
|
57
60
|
this.dhtBootstrap = ['116.202.214.149:10001', '157.180.12.214:10001', 'node1.hyperdht.org:49737', 'node2.hyperdht.org:49737', 'node3.hyperdht.org:49737'];
|
|
58
61
|
this.invite = null;
|
|
59
|
-
this.validator = null;
|
|
60
|
-
this.validator_stream = null;
|
|
61
62
|
this.readline_instance = null;
|
|
62
63
|
this.enable_interactive_mode = options.enable_interactive_mode !== false;
|
|
63
64
|
if(this.enable_interactive_mode !== false){
|
|
@@ -506,69 +507,10 @@ export class Peer extends ReadyResource {
|
|
|
506
507
|
}
|
|
507
508
|
|
|
508
509
|
async sendTx(msg){
|
|
509
|
-
if(this.validator_stream === null) return;
|
|
510
|
+
if(this.msb.getNetwork().validator_stream === null) return;
|
|
510
511
|
let _msg = safeClone(msg);
|
|
511
512
|
if(_msg['ts'] !== undefined) delete _msg['ts'];
|
|
512
|
-
try{
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
async isValidatorAvailable(address){
|
|
516
|
-
if(null === this.msb.getSwarm()) return null;
|
|
517
|
-
let writer_key = null;
|
|
518
|
-
|
|
519
|
-
this.msb.getSwarm().joinPeer(b4a.from(address, 'hex'))
|
|
520
|
-
|
|
521
|
-
let existing_stream = undefined;
|
|
522
|
-
|
|
523
|
-
if(this.msb.getSwarm().peers.has(address)){
|
|
524
|
-
const peerInfo = this.msb.getSwarm().peers.get(address)
|
|
525
|
-
existing_stream = this.msb.getSwarm()._allConnections.get(peerInfo.publicKey)
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
if(existing_stream !== undefined){
|
|
529
|
-
existing_stream.on('message', (msg) => {
|
|
530
|
-
try{
|
|
531
|
-
const response = jsonParse(b4a.toString(msg, 'utf-8'));
|
|
532
|
-
if(response.op === 'writer_key' && response.key !== undefined){
|
|
533
|
-
writer_key = response.key;
|
|
534
|
-
}
|
|
535
|
-
}catch(e){}
|
|
536
|
-
});
|
|
537
|
-
existing_stream.on('open', function () { });
|
|
538
|
-
existing_stream.on('close', () => { });
|
|
539
|
-
existing_stream.on('error', (error) => { });
|
|
540
|
-
await existing_stream.send(b4a.from(jsonStringify('get_writer_key')));
|
|
541
|
-
let i = 0;
|
|
542
|
-
while(null === writer_key){
|
|
543
|
-
if(i >= 1_000) break;
|
|
544
|
-
await this.sleep(10);
|
|
545
|
-
i += 10;
|
|
546
|
-
}
|
|
547
|
-
return writer_key;
|
|
548
|
-
} else {
|
|
549
|
-
const stream = this.msb.getSwarm().dht.connect(b4a.from(address, 'hex'))
|
|
550
|
-
stream.on('connect', async function () {
|
|
551
|
-
await stream.send(b4a.from(jsonStringify('get_writer_key')));
|
|
552
|
-
});
|
|
553
|
-
stream.on('message', (msg) => {
|
|
554
|
-
try{
|
|
555
|
-
const response = jsonParse(b4a.toString(msg, 'utf-8'));
|
|
556
|
-
if(response.op === 'writer_key' && response.key !== undefined){
|
|
557
|
-
writer_key = response.key;
|
|
558
|
-
}
|
|
559
|
-
}catch(e){}
|
|
560
|
-
});
|
|
561
|
-
stream.on('open', function () { });
|
|
562
|
-
stream.on('close', () => { });
|
|
563
|
-
stream.on('error', (error) => { });
|
|
564
|
-
let i = 0;
|
|
565
|
-
while(null === writer_key){
|
|
566
|
-
if(i >= 5_000) break;
|
|
567
|
-
await this.sleep(10);
|
|
568
|
-
i += 10;
|
|
569
|
-
}
|
|
570
|
-
return writer_key;
|
|
571
|
-
}
|
|
513
|
+
try{ this.msb.getNetwork().validator_stream.messenger.send(_msg); } catch(e){ }
|
|
572
514
|
}
|
|
573
515
|
|
|
574
516
|
async _open() {
|
|
@@ -587,25 +529,6 @@ export class Peer extends ReadyResource {
|
|
|
587
529
|
}
|
|
588
530
|
});
|
|
589
531
|
this.updater();
|
|
590
|
-
|
|
591
|
-
// test
|
|
592
|
-
const pins = this.protocol_instance;
|
|
593
|
-
const command = '';
|
|
594
|
-
|
|
595
|
-
const prepared_command = pins.api.prepareTxCommand(command);
|
|
596
|
-
let nonce = pins.api.generateNonce();
|
|
597
|
-
|
|
598
|
-
let tx_hash = pins.api.generateTx(
|
|
599
|
-
this.wallet.publicKey, await this.createHash('sha256', JSON.stringify(prepared_command)), nonce
|
|
600
|
-
)
|
|
601
|
-
|
|
602
|
-
console.log('TX Hash', tx_hash)
|
|
603
|
-
|
|
604
|
-
const signature = this.wallet.sign(tx_hash + nonce)
|
|
605
|
-
|
|
606
|
-
const res = await pins.api.tx(tx_hash, prepared_command, this.wallet.publicKey, signature, nonce)
|
|
607
|
-
|
|
608
|
-
console.log('TX Res', res)
|
|
609
532
|
}
|
|
610
533
|
|
|
611
534
|
async initContract(){
|
|
@@ -633,7 +556,7 @@ export class Peer extends ReadyResource {
|
|
|
633
556
|
|
|
634
557
|
async validator_observer(){
|
|
635
558
|
while(true){
|
|
636
|
-
if(this.msb.getSwarm() !== null && this.validator_stream === null) {
|
|
559
|
+
if(this.msb.getSwarm() !== null && this.msb.getNetwork().validator_stream === null) {
|
|
637
560
|
console.log('Looking for available validators, please wait...');
|
|
638
561
|
const _this = this;
|
|
639
562
|
let length = await this.msb.base.view.get('wrl');
|
|
@@ -642,50 +565,23 @@ export class Peer extends ReadyResource {
|
|
|
642
565
|
} else {
|
|
643
566
|
length = length.value;
|
|
644
567
|
}
|
|
568
|
+
if(this.custom_validators.length !== 0){
|
|
569
|
+
length = this.custom_validators.length;
|
|
570
|
+
}
|
|
645
571
|
async function findSome(){
|
|
646
|
-
if(_this.validator_stream !== null) return;
|
|
572
|
+
if(_this.msb.getNetwork().validator_stream !== null) return;
|
|
647
573
|
const rnd_index = Math.floor(Math.random() * length);
|
|
648
574
|
let validator = await _this.msb.base.view.get('wri/' + rnd_index);
|
|
649
|
-
if(_this.
|
|
575
|
+
if(_this.custom_validators.length !== 0){
|
|
576
|
+
validator = { value : _this.custom_validators[rnd_index] };
|
|
577
|
+
console.log('Trying custom validator', validator.value);
|
|
578
|
+
}
|
|
579
|
+
if(_this.msb.getNetwork().validator_stream !== null) return;
|
|
650
580
|
if (null !== validator) {
|
|
651
581
|
validator = await _this.msb.base.view.get(validator.value);
|
|
652
|
-
if(_this.validator_stream !== null) return;
|
|
582
|
+
if(_this.msb.getNetwork().validator_stream !== null) return;
|
|
653
583
|
if(null !== validator && false !== validator.value.isWriter && false === validator.value.isIndexer) {
|
|
654
|
-
|
|
655
|
-
if(_this.validator_stream !== null) return;
|
|
656
|
-
if (null !== result) {
|
|
657
|
-
await _this.sleep(100);
|
|
658
|
-
if(_this.validator_stream !== null) return;
|
|
659
|
-
let existing_stream = undefined;
|
|
660
|
-
if(_this.msb.getSwarm().peers.has(validator.value.pub)){
|
|
661
|
-
const peerInfo = _this.msb.getSwarm().peers.get(validator.value.pub)
|
|
662
|
-
existing_stream = _this.msb.getSwarm()._allConnections.get(peerInfo.publicKey)
|
|
663
|
-
}
|
|
664
|
-
if(existing_stream !== undefined){
|
|
665
|
-
_this.validator_stream = existing_stream;
|
|
666
|
-
_this.validator = validator.value.pub;
|
|
667
|
-
_this.validator_stream.on('close', () => {
|
|
668
|
-
_this.validator_stream = null;
|
|
669
|
-
_this.validator = null;
|
|
670
|
-
console.log('Validator stream closed', validator.value.pub);
|
|
671
|
-
});
|
|
672
|
-
console.log('Validator stream established', validator.value.pub);
|
|
673
|
-
} else {
|
|
674
|
-
_this.validator_stream = _this.msb.getSwarm().dht.connect(b4a.from(validator.value.pub, 'hex'));
|
|
675
|
-
_this.validator = validator.value.pub;
|
|
676
|
-
_this.validator_stream.on('open', () => {
|
|
677
|
-
console.log('Validator stream established', validator.value.pub);
|
|
678
|
-
});
|
|
679
|
-
_this.validator_stream.on('close', () => {
|
|
680
|
-
_this.validator_stream = null;
|
|
681
|
-
_this.validator = null;
|
|
682
|
-
});
|
|
683
|
-
_this.validator_stream.on('error', (error) => {
|
|
684
|
-
_this.validator_stream = null;
|
|
685
|
-
_this.validator = null;
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
}
|
|
584
|
+
await _this.msb.tryConnection(validator.value.pub, 'validator');
|
|
689
585
|
}
|
|
690
586
|
}
|
|
691
587
|
}
|
package/src/protocol.js
CHANGED
|
@@ -121,7 +121,7 @@ class Protocol{
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
async broadcastTransaction(validator_pub_key, obj, sim = false, surrogate = null){
|
|
124
|
-
if(this.peer.validator_stream !== null &&
|
|
124
|
+
if(this.peer.msb.getNetwork().validator_stream !== null &&
|
|
125
125
|
this.peer.wallet.publicKey !== null &&
|
|
126
126
|
this.peer.wallet.secretKey !== null &&
|
|
127
127
|
this.base.localWriter !== null &&
|
|
@@ -190,10 +190,10 @@ class Protocol{
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
async tx(subject, sim = false, surrogate = null){
|
|
193
|
-
if(this.peer.validator_stream === null) throw new Error('HyperMallProtocol::tx(): No validator available.');
|
|
193
|
+
if(this.peer.msb.getNetwork().validator_stream === null) throw new Error('HyperMallProtocol::tx(): No validator available.');
|
|
194
194
|
const obj = this.mapTxCommand(subject.command);
|
|
195
|
-
if(null !== obj) {
|
|
196
|
-
return await this.broadcastTransaction(this.peer.validator,{
|
|
195
|
+
if(null !== obj && typeof obj.type === 'string' && obj.value !== undefined) {
|
|
196
|
+
return await this.broadcastTransaction(this.peer.msb.getNetwork().validator,{
|
|
197
197
|
type : obj.type,
|
|
198
198
|
value : obj.value
|
|
199
199
|
}, sim, surrogate);
|