trac-peer 0.1.56 → 0.1.57
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 +1 -1
- package/src/api.js +18 -21
- package/src/feature.js +16 -12
- package/src/functions.js +55 -16
- package/src/index.js +65 -26
- package/src/protocol.js +25 -25
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -105,41 +105,38 @@ export class ProtocolApi{
|
|
|
105
105
|
* @param signature
|
|
106
106
|
* @param nonce
|
|
107
107
|
* @param sim
|
|
108
|
-
* @returns {Promise<boolean>}
|
|
108
|
+
* @returns {Promise<boolean|object>}
|
|
109
109
|
*/
|
|
110
110
|
async tx(tx, prepared_command, address, signature, nonce, sim = false ){
|
|
111
111
|
if(false === this.api_tx_exposed) throw new Error('Transactions not exposed in API.');
|
|
112
|
+
if(this.getPeerValidatorAddress() === null) throw new Error('Peer not connected to a validator.');
|
|
112
113
|
if(typeof prepared_command !== 'object') throw new Error('prepared_command must be an object.');
|
|
113
|
-
if(typeof prepared_command.type !== 'string')
|
|
114
|
-
if(prepared_command.value === undefined)
|
|
114
|
+
if(typeof prepared_command.type !== 'string') throw new Error('prepared_command.type must exist and be a string.');
|
|
115
|
+
if(prepared_command.value === undefined) throw new Error('prepared_command.value is missing.');
|
|
115
116
|
if(b4a.byteLength(jsonStringify(prepared_command)) > this.peer.protocol_instance.txMaxBytes()) throw new Error('prepared_command too large.');
|
|
116
|
-
if(b4a.byteLength(jsonStringify(address))
|
|
117
|
-
if(b4a.byteLength(jsonStringify(signature))
|
|
118
|
-
if(b4a.byteLength(jsonStringify(nonce))
|
|
119
|
-
if(b4a.toString(b4a.from(signature, '
|
|
120
|
-
if(b4a.toString(b4a.from(address, '
|
|
117
|
+
if(b4a.byteLength(jsonStringify(address)) !== 64) throw new Error('Address length invalid.');
|
|
118
|
+
if(b4a.byteLength(jsonStringify(signature)) !== 128) throw new Error('Signature length invalid.');
|
|
119
|
+
if(b4a.byteLength(jsonStringify(nonce)) !== 64) throw new Error('Nonce length invalid.');
|
|
120
|
+
if(b4a.toString(b4a.from(signature, 'utf8'), 'hex') !== signature) throw new Error('Invalid signature.');
|
|
121
|
+
if(b4a.toString(b4a.from(address, 'utf8'), 'hex') !== address) throw new Error('Invalid address.');
|
|
122
|
+
if(b4a.toString(b4a.from(nonce, 'utf8'), 'hex') !== nonce) throw new Error('Invalid nonce.');
|
|
121
123
|
const verified = this.peer.wallet.verify(signature, tx + nonce, address);
|
|
122
124
|
if(false === verified) throw new Error('Invalid signature.');
|
|
123
125
|
const content_hash = await this.peer.createHash('sha256', this.peer.protocol_instance.safeJsonStringify(prepared_command));
|
|
124
126
|
let _tx = await this.generateTx(address, content_hash, nonce);
|
|
125
127
|
if(tx !== _tx) throw new Error('Invalid TX.');
|
|
126
|
-
|
|
127
|
-
this.peer.protocol_instance.surrogate_tx = { tx : ''+tx, nonce : ''+nonce, signature : ''+signature, address : ''+address };
|
|
128
|
+
const surrogate = { tx : _tx, nonce : ''+nonce, signature : ''+signature, address : ''+address };
|
|
128
129
|
let res = false;
|
|
129
130
|
try{
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this.peer.protocol_instance.sim = true;
|
|
133
|
-
}
|
|
134
|
-
const subject = { command : prepared_command.value, validator : ''+this.getPeerValidatorAddress() };
|
|
135
|
-
res = await this.peer.protocol_instance.tx(subject);
|
|
131
|
+
const subject = { command : prepared_command.value, validator : this.getPeerValidatorAddress() };
|
|
132
|
+
res = await this.peer.protocol_instance.tx(subject, sim === true, surrogate);
|
|
136
133
|
} catch(e){ console.log(e) }
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
if(res !== false) {
|
|
135
|
+
const err = this.peer.protocol_instance.getError(res);
|
|
136
|
+
if (null !== err) {
|
|
137
|
+
console.log(err.message);
|
|
138
|
+
}
|
|
140
139
|
}
|
|
141
|
-
this.peer.protocol_instance.sim = false;
|
|
142
|
-
this.peer.protocol_instance.surrogate_tx = null;
|
|
143
140
|
return res;
|
|
144
141
|
}
|
|
145
142
|
|
package/src/feature.js
CHANGED
|
@@ -20,18 +20,22 @@ class Feature {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
async append(key, value){
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
if(this.peer.base.writable){
|
|
24
|
+
const nonce = this.peer.protocol_instance.generateNonce();
|
|
25
|
+
const hash = this.peer.wallet.sign(JSON.stringify(value) + nonce);
|
|
26
|
+
await this.peer.base.append({ type: 'feature', key: this.key + '_' + key, value : {
|
|
27
|
+
dispatch : {
|
|
28
|
+
type : this.key + '_feature',
|
|
29
|
+
key : key,
|
|
30
|
+
hash : hash,
|
|
31
|
+
value : value,
|
|
32
|
+
nonce : nonce,
|
|
33
|
+
address : this.peer.wallet.publicKey
|
|
34
|
+
}
|
|
35
|
+
}});
|
|
36
|
+
} else {
|
|
37
|
+
console.log('Peer running features not writable.');
|
|
38
|
+
}
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
async start(options = {}) {
|
package/src/functions.js
CHANGED
|
@@ -334,30 +334,69 @@ export async function removeWriter(input, peer){
|
|
|
334
334
|
}
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
export async function joinValidator(input, peer){
|
|
338
|
+
const splitted = peer.protocol_instance.parseArgs(input)
|
|
339
|
+
const address = ''+splitted.address;
|
|
340
|
+
const validator = await peer.msb.base.view.get(address);
|
|
341
|
+
if(validator === null || false === validator.value.isWriter || true === validator.value.isIndexer){
|
|
342
|
+
throw new Error('Invalid validator address.');
|
|
343
|
+
}
|
|
344
|
+
const result = await peer.isValidatorAvailable(address);
|
|
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
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
337
380
|
export async function tx(input, peer){
|
|
338
381
|
const splitted = peer.protocol_instance.parseArgs(input);
|
|
382
|
+
let res = false;
|
|
339
383
|
if(splitted.command === undefined){
|
|
340
|
-
|
|
341
|
-
} else if(splitted.sim === undefined &&
|
|
342
|
-
|
|
343
|
-
throw new Error('No validator available: Please wait for your peer to find an available one before transacting or pass the public key of a known one that is online.');
|
|
344
|
-
}
|
|
345
|
-
splitted['validator'] = peer.validator;
|
|
346
|
-
} else if(splitted.sim !== undefined && splitted.validator !== undefined){
|
|
347
|
-
throw new Error('Validator flag not allowed when simulating a transaction.');
|
|
384
|
+
res = new Error('Missing option. Please use the --command flag.');
|
|
385
|
+
} else if(splitted.sim === undefined && peer.validator === null){
|
|
386
|
+
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.');
|
|
348
387
|
}
|
|
349
|
-
let
|
|
388
|
+
let sim = false;
|
|
350
389
|
try{
|
|
351
390
|
if(splitted.sim !== undefined && parseInt(splitted.sim) === 1){
|
|
352
|
-
|
|
353
|
-
peer.protocol_instance.sim = true;
|
|
391
|
+
sim = true;
|
|
354
392
|
}
|
|
355
|
-
res = await peer.protocol_instance.tx(splitted);
|
|
393
|
+
res = await peer.protocol_instance.tx(splitted, sim);
|
|
356
394
|
} catch(e){ console.log(e) }
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
395
|
+
if(res !== false){
|
|
396
|
+
const err = peer.protocol_instance.getError(res);
|
|
397
|
+
if(null !== err){
|
|
398
|
+
console.log(err.message);
|
|
399
|
+
}
|
|
360
400
|
}
|
|
361
|
-
peer.protocol_instance.sim = false;
|
|
362
401
|
return res;
|
|
363
402
|
}
|
package/src/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
addWriter, addAdmin, setAutoAddWriters, setChatStatus, setMod, deleteMessage,
|
|
16
16
|
enableWhitelist, postMessage, jsonStringify, visibleLength, setNick,
|
|
17
17
|
muteStatus, setWhitelistStatus, updateAdmin, tx, safeClone, jsonParse,
|
|
18
|
-
pinMessage
|
|
18
|
+
pinMessage, joinValidator, removeWriter
|
|
19
19
|
} from "./functions.js";
|
|
20
20
|
import Check from "./check.js";
|
|
21
21
|
export {default as Protocol} from "./protocol.js";
|
|
@@ -124,7 +124,8 @@ export class Peer extends ReadyResource {
|
|
|
124
124
|
let _err = null;
|
|
125
125
|
if(null !== err) {
|
|
126
126
|
if(err.constructor.name === 'UnknownContractOperationType') continue;
|
|
127
|
-
|
|
127
|
+
const _err_msg = parseInt(err.message);
|
|
128
|
+
_err = isNaN(_err_msg) ? ''+err.message : _err_msg;
|
|
128
129
|
}
|
|
129
130
|
let len = await batch.get('txl');
|
|
130
131
|
if(null === len) {
|
|
@@ -132,12 +133,13 @@ export class Peer extends ReadyResource {
|
|
|
132
133
|
} else {
|
|
133
134
|
len = len.value;
|
|
134
135
|
}
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
const dta = {};
|
|
137
|
+
dta['val'] = safeClone(op.value.dispatch);
|
|
138
|
+
dta['err'] = _err;
|
|
139
|
+
dta['tx'] = post_tx.value.tx;
|
|
140
|
+
dta['ipk'] = post_tx.value.ipk;
|
|
141
|
+
dta['wp'] = post_tx.value.wp;
|
|
142
|
+
await batch.put('txi/'+len, dta);
|
|
141
143
|
await batch.put('txl', len + 1);
|
|
142
144
|
await batch.put('tx/'+post_tx.value.tx, len);
|
|
143
145
|
let ulen = await batch.get('utxl/'+post_tx.value.ipk);
|
|
@@ -229,7 +231,7 @@ export class Peer extends ReadyResource {
|
|
|
229
231
|
const verified = _this.wallet.verify(op.hash, str_msg + op.nonce, admin.value);
|
|
230
232
|
if(true === verified){
|
|
231
233
|
const writerKey = b4a.from(op.key, 'hex');
|
|
232
|
-
base.addWriter(writerKey, { isIndexer : true });
|
|
234
|
+
await base.addWriter(writerKey, { isIndexer : true });
|
|
233
235
|
await batch.put('sh/'+op.hash, '');
|
|
234
236
|
console.log(`Indexer added: ${op.key}`);
|
|
235
237
|
}
|
|
@@ -245,9 +247,9 @@ export class Peer extends ReadyResource {
|
|
|
245
247
|
const verified = _this.wallet.verify(op.hash, str_msg + op.nonce, admin.value);
|
|
246
248
|
if(true === verified){
|
|
247
249
|
const writerKey = b4a.from(op.key, 'hex');
|
|
248
|
-
base.addWriter(writerKey, { isIndexer : false });
|
|
250
|
+
await base.addWriter(writerKey, { isIndexer : false });
|
|
249
251
|
await batch.put('sh/'+op.hash, '');
|
|
250
|
-
console.log(`Writer added: ${
|
|
252
|
+
console.log(`Writer added: ${writerKey}`);
|
|
251
253
|
}
|
|
252
254
|
}
|
|
253
255
|
} else if (op.type === 'removeWriter') {
|
|
@@ -261,7 +263,7 @@ export class Peer extends ReadyResource {
|
|
|
261
263
|
const verified = _this.wallet.verify(op.hash, str_msg + op.nonce, admin.value);
|
|
262
264
|
if(true === verified){
|
|
263
265
|
const writerKey = b4a.from(op.key, 'hex');
|
|
264
|
-
base.removeWriter(writerKey);
|
|
266
|
+
await base.removeWriter(writerKey);
|
|
265
267
|
await batch.put('sh/'+op.hash, '');
|
|
266
268
|
console.log(`Writer removed: ${op.key}`);
|
|
267
269
|
}
|
|
@@ -302,7 +304,7 @@ export class Peer extends ReadyResource {
|
|
|
302
304
|
const banned = await batch.get('bnd/'+op.key);
|
|
303
305
|
if(null === banned && null !== auto_add_writers && auto_add_writers.value === 'on'){
|
|
304
306
|
const writerKey = b4a.from(op.key, 'hex');
|
|
305
|
-
base.addWriter(writerKey, { isIndexer : false });
|
|
307
|
+
await base.addWriter(writerKey, { isIndexer : false });
|
|
306
308
|
}
|
|
307
309
|
console.log(`Writer auto added: ${op.key}`);
|
|
308
310
|
} else if (op.type === 'addAdmin') {
|
|
@@ -585,6 +587,25 @@ export class Peer extends ReadyResource {
|
|
|
585
587
|
}
|
|
586
588
|
});
|
|
587
589
|
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)
|
|
588
609
|
}
|
|
589
610
|
|
|
590
611
|
async initContract(){
|
|
@@ -694,10 +715,10 @@ export class Peer extends ReadyResource {
|
|
|
694
715
|
const msb_tx = await view_session.get(tx);
|
|
695
716
|
await view_session.close();
|
|
696
717
|
if(null !== msb_tx){
|
|
697
|
-
msb_tx['dispatch'] = this.protocol_instance.prepared_transactions_content[tx].dispatch;
|
|
698
718
|
msb_tx['msbsl'] = msbsl;
|
|
719
|
+
msb_tx['dispatch'] = this.protocol_instance.prepared_transactions_content[tx].dispatch;
|
|
699
720
|
msb_tx['ipk'] = this.protocol_instance.prepared_transactions_content[tx].ipk;
|
|
700
|
-
msb_tx['wp'] = this.validator;
|
|
721
|
+
msb_tx['wp'] = this.protocol_instance.prepared_transactions_content[tx].validator;
|
|
701
722
|
delete this.tx_pool[tx];
|
|
702
723
|
delete this.protocol_instance.prepared_transactions_content[tx];
|
|
703
724
|
await this.base.append({ type: 'tx', key: tx, value: msb_tx });
|
|
@@ -754,11 +775,12 @@ export class Peer extends ReadyResource {
|
|
|
754
775
|
poll: 5000
|
|
755
776
|
});
|
|
756
777
|
console.log('');
|
|
757
|
-
console.log('
|
|
758
|
-
console.log('#
|
|
778
|
+
console.log('######################################################################################');
|
|
779
|
+
console.log('# Peer Address: ', this.wallet.publicKey, '#');
|
|
759
780
|
this.writerLocalKey = b4a.toString(this.base.local.key, 'hex');
|
|
760
|
-
console.log('#
|
|
761
|
-
console.log('
|
|
781
|
+
console.log('# Peer Writer: ', this.writerLocalKey, '#');
|
|
782
|
+
console.log('######################################################################################');
|
|
783
|
+
console.log('');
|
|
762
784
|
console.log(`isIndexer: ${this.base.isIndexer}`);
|
|
763
785
|
console.log(`isWriter: ${this.base.writable}`);
|
|
764
786
|
console.log('');
|
|
@@ -855,6 +877,10 @@ export class Peer extends ReadyResource {
|
|
|
855
877
|
const lengthdagSystem = this.base.system.core.length;
|
|
856
878
|
console.log('wallet.address:', this.wallet !== null ? this.wallet.publicKey : 'unset');
|
|
857
879
|
console.log('hypermall.writerKey:', this.writerLocalKey);
|
|
880
|
+
const admin = await this.base.view.get('admin')
|
|
881
|
+
console.log(`admin: ${admin !== null ? admin.value : 'unset'}`);
|
|
882
|
+
console.log(`isIndexer: ${this.base.isIndexer}`);
|
|
883
|
+
console.log(`isWriter: ${this.base.writable}`);
|
|
858
884
|
console.log('swarm.connections.size:', this.swarm.connections.size);
|
|
859
885
|
console.log('base.view.core.signedLength:', this.base.view.core.signedLength);
|
|
860
886
|
console.log("base.signedLength", this.base.signedLength);
|
|
@@ -871,16 +897,12 @@ export class Peer extends ReadyResource {
|
|
|
871
897
|
}
|
|
872
898
|
}
|
|
873
899
|
|
|
874
|
-
|
|
875
|
-
if(this.readline_instance === null || (global.Pear !== undefined && global.Pear.config.options.type === 'desktop')) return;
|
|
876
|
-
|
|
877
|
-
const rl = this.readline_instance;
|
|
878
|
-
|
|
900
|
+
printHelp(){
|
|
879
901
|
console.log('Node started. Available commands:');
|
|
880
902
|
console.log(' ');
|
|
881
903
|
console.log('- Setup Commands:');
|
|
882
904
|
console.log('- /add_admin | Works only once and only on bootstrap node! Enter a wallet address to assign admin rights: \'/add_admin --address "<address>"\'.');
|
|
883
|
-
console.log('- /update_admin | Existing admins may transfer admin ownership. Enter "null" as address to waive admin rights for this peer entirely: \'/
|
|
905
|
+
console.log('- /update_admin | Existing admins may transfer admin ownership. Enter "null" as address to waive admin rights for this peer entirely: \'/update_admin --address "<address>"\'.');
|
|
884
906
|
console.log('- /add_indexer | Only admin. Enter a peer writer key to get included as indexer for this network: \'/add_indexer --key "<key>"\'.');
|
|
885
907
|
console.log('- /add_writer | Only admin. Enter a peer writer key to get included as writer for this network: \'/add_writer --key "<key>"\'.');
|
|
886
908
|
console.log('- /remove_writer | Only admin. Enter a peer writer key to get removed as writer or indexer for this network: \'/remove_writer --key "<key>"\'.');
|
|
@@ -898,18 +920,31 @@ export class Peer extends ReadyResource {
|
|
|
898
920
|
console.log('- /set_whitelist_status | Only admin. Add/remove users to/from the chat whitelist: \'/set_whitelist_status --user "<address>" --status 1\'.');
|
|
899
921
|
console.log(' ');
|
|
900
922
|
console.log('- System Commands:');
|
|
901
|
-
console.log('- /tx | Perform a contract transaction. The command flag contains contract commands
|
|
923
|
+
console.log('- /tx | Perform a contract transaction. The command flag contains contract commands (format is protocol dependent): \'/tx --command "<string>"\'. To simulate a tx, additionally use \'--sim 1\'.');
|
|
924
|
+
console.log('- /join_validator | Try to connect to a specific validator with its MSB address: \'/join_validator --address "<address>"\'.');
|
|
902
925
|
console.log('- /stats | check system properties such as writer key, DAG, etc.');
|
|
903
926
|
console.log('- /get_keys | prints your public and private keys. Be careful and never share your private key!');
|
|
904
927
|
console.log('- /exit | Exit the program');
|
|
928
|
+
console.log('- /help | This help text');
|
|
905
929
|
|
|
906
930
|
this.protocol_instance.printOptions();
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
async interactiveMode() {
|
|
934
|
+
if(this.readline_instance === null || (global.Pear !== undefined && global.Pear.config.options.type === 'desktop')) return;
|
|
935
|
+
|
|
936
|
+
const rl = this.readline_instance;
|
|
937
|
+
|
|
938
|
+
this.printHelp();
|
|
907
939
|
|
|
908
940
|
rl.on('line', async (input) => {
|
|
909
941
|
switch (input) {
|
|
910
942
|
case '/stats':
|
|
911
943
|
await this.verifyDag();
|
|
912
944
|
break;
|
|
945
|
+
case '/help':
|
|
946
|
+
await this.printHelp();
|
|
947
|
+
break;
|
|
913
948
|
case '/exit':
|
|
914
949
|
console.log('Exiting...');
|
|
915
950
|
rl.close();
|
|
@@ -925,6 +960,8 @@ export class Peer extends ReadyResource {
|
|
|
925
960
|
await tx(input, this);
|
|
926
961
|
} else if (input.startsWith('/add_indexer') || input.startsWith('/add_writer')) {
|
|
927
962
|
await addWriter(input, this);
|
|
963
|
+
} else if (input.startsWith('/remove_writer')) {
|
|
964
|
+
await removeWriter(input, this);
|
|
928
965
|
} else if (input.startsWith('/add_admin')) {
|
|
929
966
|
await addAdmin(input, this);
|
|
930
967
|
} else if (input.startsWith('/update_admin')) {
|
|
@@ -949,6 +986,8 @@ export class Peer extends ReadyResource {
|
|
|
949
986
|
await enableWhitelist(input, this);
|
|
950
987
|
} else if (input.startsWith('/set_whitelist_status')) {
|
|
951
988
|
await setWhitelistStatus(input, this);
|
|
989
|
+
} else if (input.startsWith('/join_validator')) {
|
|
990
|
+
await joinValidator(input, this);
|
|
952
991
|
} else {
|
|
953
992
|
await this.protocol_instance.customCommand(input);
|
|
954
993
|
}
|
package/src/protocol.js
CHANGED
|
@@ -17,8 +17,6 @@ class Protocol{
|
|
|
17
17
|
this.safeClone = safeClone;
|
|
18
18
|
this.prepared_transactions_content = {};
|
|
19
19
|
this.features = {};
|
|
20
|
-
this.sim = false;
|
|
21
|
-
this.surrogate_tx = null;
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
featMaxBytes(){
|
|
@@ -102,31 +100,27 @@ class Protocol{
|
|
|
102
100
|
return await this.peer.createHash('sha256', await this.peer.createHash('sha256', tx));
|
|
103
101
|
}
|
|
104
102
|
|
|
105
|
-
async simulateTransaction(obj){
|
|
103
|
+
async simulateTransaction(validator_pub_key, obj, surrogate = null){
|
|
106
104
|
const storage = new SimStorage(this.peer);
|
|
107
|
-
const null_hex = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
108
105
|
let nonce = this.generateNonce();
|
|
109
106
|
const content_hash = await this.peer.createHash('sha256', this.safeJsonStringify(obj));
|
|
110
|
-
let tx = await this.generateTx(this.peer.bootstrap, this.peer.msb.bootstrap,
|
|
111
|
-
this.peer.writerLocalKey,
|
|
107
|
+
let tx = await this.generateTx(this.peer.bootstrap, this.peer.msb.bootstrap, validator_pub_key,
|
|
108
|
+
this.peer.writerLocalKey, surrogate !== null ? surrogate.address : this.peer.wallet.publicKey, content_hash, nonce);
|
|
112
109
|
const op = {
|
|
113
110
|
type : 'tx',
|
|
114
111
|
key : tx,
|
|
115
112
|
value : {
|
|
116
113
|
dispatch : obj,
|
|
117
114
|
value : {
|
|
118
|
-
ipk :
|
|
119
|
-
wp :
|
|
115
|
+
ipk : surrogate !== null ? surrogate.address : this.peer.wallet.publicKey,
|
|
116
|
+
wp : validator_pub_key
|
|
120
117
|
}
|
|
121
118
|
}
|
|
122
119
|
}
|
|
123
120
|
return await this.peer.contract_instance.execute(op, storage);
|
|
124
121
|
}
|
|
125
122
|
|
|
126
|
-
async broadcastTransaction(validator_pub_key, obj){
|
|
127
|
-
if(true === this.sim) {
|
|
128
|
-
return await this.simulateTransaction(obj);
|
|
129
|
-
}
|
|
123
|
+
async broadcastTransaction(validator_pub_key, obj, sim = false, surrogate = null){
|
|
130
124
|
if(this.peer.validator_stream !== null &&
|
|
131
125
|
this.peer.wallet.publicKey !== null &&
|
|
132
126
|
this.peer.wallet.secretKey !== null &&
|
|
@@ -134,15 +128,18 @@ class Protocol{
|
|
|
134
128
|
obj.type !== undefined &&
|
|
135
129
|
obj.value !== undefined)
|
|
136
130
|
{
|
|
131
|
+
if(true === sim) {
|
|
132
|
+
return await this.simulateTransaction(validator_pub_key, obj, surrogate);
|
|
133
|
+
}
|
|
137
134
|
|
|
138
135
|
let tx, signature, nonce, publicKey;
|
|
139
136
|
const content_hash = await this.peer.createHash('sha256', this.safeJsonStringify(obj));
|
|
140
137
|
|
|
141
|
-
if(
|
|
142
|
-
nonce =
|
|
143
|
-
tx =
|
|
144
|
-
signature =
|
|
145
|
-
publicKey =
|
|
138
|
+
if(surrogate !== null) {
|
|
139
|
+
nonce = surrogate.nonce;
|
|
140
|
+
tx = surrogate.tx;
|
|
141
|
+
signature = surrogate.signature;
|
|
142
|
+
publicKey = surrogate.address;
|
|
146
143
|
} else {
|
|
147
144
|
nonce = this.generateNonce();
|
|
148
145
|
tx = await this.generateTx(this.peer.bootstrap, this.peer.msb.bootstrap, validator_pub_key,
|
|
@@ -151,7 +148,7 @@ class Protocol{
|
|
|
151
148
|
publicKey = this.peer.wallet.publicKey;
|
|
152
149
|
}
|
|
153
150
|
|
|
154
|
-
|
|
151
|
+
const _tx = {
|
|
155
152
|
op: 'pre-tx',
|
|
156
153
|
tx: tx,
|
|
157
154
|
is: signature,
|
|
@@ -162,12 +159,14 @@ class Protocol{
|
|
|
162
159
|
in : nonce,
|
|
163
160
|
bs : this.peer.bootstrap,
|
|
164
161
|
mbs : this.peer.msb.bootstrap
|
|
165
|
-
}
|
|
166
|
-
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
this.peer.emit('tx', _tx);
|
|
165
|
+
this.prepared_transactions_content[tx] = { dispatch : obj, ipk : publicKey, validator : validator_pub_key };
|
|
166
|
+
return _tx;
|
|
167
167
|
} else {
|
|
168
168
|
throw Error('broadcastTransaction(writer, obj): Cannot prepare transaction. Please make sure inputs and local writer are set.');
|
|
169
169
|
}
|
|
170
|
-
return true;
|
|
171
170
|
}
|
|
172
171
|
|
|
173
172
|
async tokenizeInput(input){
|
|
@@ -190,15 +189,16 @@ class Protocol{
|
|
|
190
189
|
return null;
|
|
191
190
|
}
|
|
192
191
|
|
|
193
|
-
async tx(subject){
|
|
192
|
+
async tx(subject, sim = false, surrogate = null){
|
|
193
|
+
if(this.peer.validator_stream === null) throw new Error('HyperMallProtocol::tx(): No validator available.');
|
|
194
194
|
const obj = this.mapTxCommand(subject.command);
|
|
195
195
|
if(null !== obj) {
|
|
196
|
-
return await this.broadcastTransaction(
|
|
196
|
+
return await this.broadcastTransaction(this.peer.validator,{
|
|
197
197
|
type : obj.type,
|
|
198
198
|
value : obj.value
|
|
199
|
-
});
|
|
199
|
+
}, sim, surrogate);
|
|
200
200
|
}
|
|
201
|
-
|
|
201
|
+
throw new Error('HyperMallProtocol::tx(): command not found.');
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
async customCommand(input){ }
|