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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "trac-peer",
3
3
  "main": "src/index.js",
4
- "version": "0.1.56",
4
+ "version": "0.1.57",
5
5
  "type": "module",
6
6
  "dependencies": {
7
7
  "assert": "npm:bare-node-assert",
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') throw new Error('prepared_command.type must exist and be a string.');
114
- if(prepared_command.value === undefined) throw new Error('prepared_command.value is missing.');
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)) > 64) throw new Error('Address too large.');
117
- if(b4a.byteLength(jsonStringify(signature)) > 128) throw new Error('Signature too large.');
118
- if(b4a.byteLength(jsonStringify(nonce)) > 256) throw new Error('Nonce too large.');
119
- if(b4a.toString(b4a.from(signature, 'hex'), 'hex') !== signature) throw new Error('Invalid signature.');
120
- if(b4a.toString(b4a.from(address, 'hex'), 'hex') !== address) throw new Error('Invalid 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
- while(null !== this.peer.protocol_instance.surrogate_tx) await this.peer.sleep(3);
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
- if(true === sim){
131
- while(true === this.peer.protocol_instance.sim) await this.peer.sleep(3);
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
- const err = this.peer.protocol_instance.getError(res);
138
- if(null !== err){
139
- console.log(err.message);
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
- const nonce = this.peer.protocol_instance.generateNonce();
24
- const hash = this.peer.wallet.sign(JSON.stringify(value) + nonce);
25
- await this.peer.base.append({ type: 'feature', key: this.key + '_' + key, value : {
26
- dispatch : {
27
- type : this.key + '_feature',
28
- key : key,
29
- hash : hash,
30
- value : value,
31
- nonce : nonce,
32
- address : this.peer.wallet.publicKey
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
- throw new Error('Missing option. Please use the --command flag.');
341
- } else if(splitted.sim === undefined && splitted.validator === undefined){
342
- if(peer.validator === null){
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 res = false;
388
+ let sim = false;
350
389
  try{
351
390
  if(splitted.sim !== undefined && parseInt(splitted.sim) === 1){
352
- while(true === peer.protocol_instance.sim) await peer.sleep(3);
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
- const err = peer.protocol_instance.getError(res);
358
- if(null !== err){
359
- console.log(err.message);
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
- _err = ''+err.message;
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 cloned = safeClone(op.value.dispatch);
136
- cloned['err'] = _err;
137
- cloned['tx'] = post_tx.value.tx;
138
- cloned['ipk'] = post_tx.value.ipk;
139
- cloned['wp'] = post_tx.value.wp;
140
- await batch.put('txi/'+len, cloned);
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: ${op.key}`);
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('# Hypermall Address: ', this.wallet.publicKey, '#');
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('# Hypermall Writer: ', this.writerLocalKey, '#');
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
- async interactiveMode() {
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: \'/add_admin --address "<address>"\'.');
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 in json format: \'/tx --command "<string, content depends on the protocol>"\'. To try broadcasting to a specific validator, use the validator flag and pass the validator public key: --validator "<validator public key>". To simulate a tx, you must leave out the \'--validator\' flag and use \'--sim 1\' instead.');
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, null_hex,
111
- this.peer.writerLocalKey, this.surrogate_tx !== null ? this.surrogate_tx.address : this.peer.wallet.publicKey, content_hash, nonce);
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 : this.surrogate_tx !== null ? this.surrogate_tx.address : this.peer.wallet.publicKey,
119
- wp : null_hex
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(this.surrogate_tx !== null) {
142
- nonce = this.surrogate_tx.nonce;
143
- tx = this.surrogate_tx.tx;
144
- signature = this.surrogate_tx.signature;
145
- publicKey = this.surrogate_tx.address;
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
- this.peer.emit('tx', {
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
- this.prepared_transactions_content[tx] = { dispatch : obj, ipk : publicKey };
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(subject.validator,{
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
- return new Error('HyperMallProtocol::tx(): command not found.');
201
+ throw new Error('HyperMallProtocol::tx(): command not found.');
202
202
  }
203
203
 
204
204
  async customCommand(input){ }