@leofcoin/chain 1.3.10 → 1.3.11

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/dist/chain.js CHANGED
@@ -5,10 +5,11 @@ var _BN = require('bn.js');
5
5
  require('@ethersproject/bytes');
6
6
  var logger = require('@ethersproject/logger');
7
7
  require('@ethersproject/bignumber');
8
- var node_crypto = require('node:crypto');
9
- var node_path = require('node:path');
8
+ var crypto = require('crypto');
9
+ var path = require('path');
10
10
  var EasyWorker = require('@vandeurenglenn/easy-worker');
11
11
  var codecFormatInterface = require('@leofcoin/codec-format-interface');
12
+ var pako = require('pako');
12
13
  var MultiWallet = require('@leofcoin/multi-wallet');
13
14
  var index = require('@leofcoin/codec-format-interface/dist/index');
14
15
  var bs32 = require('@vandeurenglenn/base32');
@@ -17,6 +18,7 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
17
18
 
18
19
  var _BN__default = /*#__PURE__*/_interopDefaultLegacy(_BN);
19
20
  var EasyWorker__default = /*#__PURE__*/_interopDefaultLegacy(EasyWorker);
21
+ var pako__default = /*#__PURE__*/_interopDefaultLegacy(pako);
20
22
  var MultiWallet__default = /*#__PURE__*/_interopDefaultLegacy(MultiWallet);
21
23
  var bs32__default = /*#__PURE__*/_interopDefaultLegacy(bs32);
22
24
 
@@ -24,17 +26,17 @@ var contractFactory$2 = "ihny2gqg6c6mwy5mhbrs5ulkkozsgwtk5vuz5krjidouy4mbwfdbjnb
24
26
  var nativeToken$2 = "ihny2gqhoockyg7yg4n5bpxuldahfavpqnmpoe2bn4ivnxmk7redc2ltwkb";
25
27
  var nameService$2 = "ihny2gqgztp3vj6qy7fgrfer7y5c5hxnp6imdz6v5spi4edkwtm5fkd5z2h";
26
28
  var validators$2 = "ihny2gqh4e2pr4pbtpkamhj3htsvuoydy3wotaudoeaktgcdwmoij66pecp";
27
- var addresses = {
29
+ var addresses$1 = {
28
30
  contractFactory: contractFactory$2,
29
31
  nativeToken: nativeToken$2,
30
32
  nameService: nameService$2,
31
33
  validators: validators$2
32
34
  };
33
35
 
34
- const contractFactory$1 = addresses.contractFactory;
35
- const nameService$1 = addresses.nameService;
36
- const nativeToken$1 = addresses.nativeToken;
37
- const validators$1 = addresses.validators;
36
+ const contractFactory$1 = addresses$1.contractFactory;
37
+ const nameService$1 = addresses$1.nameService;
38
+ const nativeToken$1 = addresses$1.nativeToken;
39
+ const validators$1 = addresses$1.validators;
38
40
 
39
41
  const version$1 = "bignumber/5.6.2";
40
42
 
@@ -134,7 +136,7 @@ message BlockMessage {
134
136
  }
135
137
  `;
136
138
 
137
- class BlockMessage extends codecFormatInterface.FormatInterface {
139
+ class BlockMessage$1 extends codecFormatInterface.FormatInterface {
138
140
  get keys() {
139
141
  return ['index', 'previousHash', 'timestamp', 'reward', 'fees', 'transactions', 'validators']
140
142
  }
@@ -251,7 +253,7 @@ class Machine {
251
253
  };
252
254
  pubsub.subscribe('machine.ready', machineReady);
253
255
 
254
- this.worker = await new EasyWorker__default["default"](node_path.join(__dirname, './workers/machine-worker.js'), {serialization: 'advanced', type:'module'});
256
+ this.worker = await new EasyWorker__default["default"](path.join(__dirname, './workers/machine-worker.js'), {serialization: 'advanced', type:'module'});
255
257
  this.worker.onmessage(this.#onmessage.bind(this));
256
258
 
257
259
  // const blocks = await blockStore.values()
@@ -278,7 +280,7 @@ class Machine {
278
280
  async #runContract(contractMessage) {
279
281
  const hash = await contractMessage.hash;
280
282
  return new Promise((resolve, reject) => {
281
- const id = node_crypto.randomBytes(20).toString('hex');
283
+ const id = crypto.randomBytes(20).toString('hex');
282
284
  const onmessage = message => {
283
285
  pubsub.unsubscribe(id, onmessage);
284
286
  if (message?.error) reject(message.error);
@@ -319,14 +321,13 @@ class Machine {
319
321
  message = await contractStore.get(parameters[0]);
320
322
  message = await new ContractMessage(message);
321
323
  }
322
- console.log(message);
323
324
  if (!this.#contracts[await message.hash]) await this.#runContract(message);
324
325
  }
325
326
  } catch (error) {
326
327
  throw new Error(`contract deployment failed for ${parameters[0]}\n${error.message}`)
327
328
  }
328
329
  return new Promise((resolve, reject) => {
329
- const id = node_crypto.randomBytes(20).toString('hex');
330
+ const id = crypto.randomBytes(20).toString('hex');
330
331
  const onmessage = message => {
331
332
  pubsub.unsubscribe(id, onmessage);
332
333
  if (message?.error) reject(message.error);
@@ -356,7 +357,7 @@ class Machine {
356
357
 
357
358
  get(contract, method, parameters) {
358
359
  return new Promise((resolve, reject) => {
359
- const id = node_crypto.randomBytes(20).toString();
360
+ const id = crypto.randomBytes(20).toString();
360
361
  const onmessage = message => {
361
362
  pubsub.unsubscribe(id, onmessage);
362
363
  resolve(message);
@@ -433,24 +434,397 @@ const calculateFee = async transaction => {
433
434
  return Number.parseFloat(fee.toString()).toFixed(decimals)
434
435
  };
435
436
 
437
+ class State {
438
+ constructor() {
439
+ // return this.#init()
440
+ }
441
+
442
+ // async #init() {
443
+ // const state = await stateStore.get()
444
+ // for (const [key, value] of Object.entries(state)) {
445
+ //
446
+ // }
447
+ //
448
+ // return this
449
+ // }
450
+
451
+ async put(key, value, isCompressed = true) {
452
+ value = isCompressed ? value : await pako__default["default"].deflate(value);
453
+ await stateStore.put(key, value);
454
+ }
455
+
456
+ async get(key, isCompressed = true) {
457
+ const value = await stateStore.get(key);
458
+ return isCompressed = pako__default["default"].inflate(value)
459
+ }
460
+
461
+ updateState(block) {
462
+ // block.decoded.index
463
+ // this.#isUpdateNeeded()
464
+ }
465
+ }
466
+
467
+ class Protocol {
468
+ limit = 1800
469
+ }
470
+
471
+ class Transaction extends Protocol {
472
+ constructor() {
473
+ super();
474
+ }
475
+
476
+ /**
477
+ *
478
+ * @param {Address[]} transactions
479
+ * @returns transactions to include
480
+ */
481
+ async getTransactions (transactions) {
482
+ return new Promise(async (resolve, reject) => {
483
+ let size = 0;
484
+ const _transactions = [];
485
+
486
+
487
+ await Promise.all(transactions
488
+ .map(async tx => {
489
+ tx = await new TransactionMessage(tx);
490
+ size += tx.encoded.length;
491
+ if (!formatBytes(size).includes('MB') || formatBytes(size).includes('MB') && Number(formatBytes(size).split(' MB')[0]) <= 0.75) _transactions.push({...tx.decoded, hash: await tx.hash});
492
+ else resolve(_transactions);
493
+ }));
494
+
495
+ return resolve(_transactions)
496
+ })
497
+
498
+ }
499
+
500
+ /**
501
+ *
502
+ * @param {Transaction[]} transactions An array containing Transactions
503
+ * @returns {TransactionMessage}
504
+ */
505
+ async promiseTransactions(transactions) {
506
+ transactions = await Promise.all(transactions.map(tx => new TransactionMessage(tx)));
507
+ return transactions
508
+ }
509
+
510
+ /**
511
+ *
512
+ * @param {Transaction[]} transactions An array containing Transactions
513
+ * @returns {Object} {transaction.decoded, transaction.hash}
514
+ */
515
+ async promiseTransactionsContent(transactions) {
516
+ transactions = await Promise.all(transactions.map(tx => new Promise(async (resolve, reject) => {
517
+ resolve({ ...tx.decoded, hash: await tx.hash });
518
+ })));
519
+
520
+ return transactions
521
+ }
522
+
523
+ /**
524
+ * When a nonce isn't found for an address fallback to just checking the transactionnPoolStore
525
+ * @param {Address} address
526
+ * @returns {Number} nonce
527
+ */
528
+ async #getNonceFallback(address) {
529
+ let transactions = await transactionPoolStore.values();
530
+ transactions = await this.promiseTransactions(transactions);
531
+ transactions = transactions.filter(tx => tx.decoded.from === address);
532
+ transactions = await this.promiseTransactionsContent(transactions);
533
+
534
+ if (this.lastBlock?.hash && transactions.length === 0 && this.lastBlock.hash !== '0x0') {
535
+
536
+ let block = await peernet.get(this.lastBlock.hash);
537
+ block = await new BlockMessage(block);
538
+
539
+ // for (let tx of block.decoded?.transactions) {
540
+ // tx = await peernet.get(tx, 'transaction')
541
+ // transactions.push(new TransactionMessage(tx))
542
+ // }
543
+ transactions = transactions.filter(tx => tx.from === address);
544
+ while (transactions.length === 0 && block.decoded.index !== 0 && block.decoded.previousHash !== '0x0') {
545
+ block = await blockStore.get(block.decoded.previousHash);
546
+ block = await new BlockMessage(block);
547
+ transactions = block.decoded.transactions.filter(tx => tx.from === address);
548
+ }
549
+
550
+ }
551
+ if (transactions.length === 0) return 0
552
+
553
+ transactions = transactions.sort((a, b) => a.timestamp - b.timestamp);
554
+ return transactions[transactions.length - 1].nonce
555
+ }
556
+
557
+ /**
558
+ * Get amount of transactions by address
559
+ * @param {Address} address The address to get the nonce for
560
+ * @returns {Number} nonce
561
+ */
562
+ async getNonce(address) {
563
+ if (!await accountsStore.has(address)) {
564
+ const nonce = await this.#getNonceFallback(address);
565
+ await accountsStore.put(address, new TextEncoder().encode(String(nonce)));
566
+ }
567
+ // todo: are those in the pool in cluded also ? they need to be included!!!
568
+ let nonce = await accountsStore.get(address);
569
+ nonce = new TextDecoder().decode(nonce);
570
+ return Number(nonce)
571
+ }
572
+
573
+ /**
574
+ * whenever method = createContract params should hold the contract hash
575
+ *
576
+ * example: [hash]
577
+ * createTransaction('0x0', 'createContract', [hash])
578
+ *
579
+ * @param {String} to - the contract address for the contract to interact with
580
+ * @param {String} method - the method/function to run
581
+ * @param {Array} params - array of paramters to apply to the contract method
582
+ * @param {Number} nonce - total transaction count [optional]
583
+ */
584
+ async createTransaction(to, method, parameters, nonce, signature) {
585
+ return this.createTransactionFrom(peernet.selectedAccount, to, method, parameters, nonce)
586
+ }
587
+
588
+ /**
589
+ *
590
+ * @param {Transaction} transaction
591
+ * @param {String} transaction.from address
592
+ * @param {String} transaction.to address
593
+ * @param {Object} transaction.params {}
594
+ * @param {String} transaction.params.method get, call
595
+ * @param {Buffer} transaction.params.data
596
+ * @returns
597
+ */
598
+ async createTransactionHash(transaction) {
599
+ // todo: validate
600
+ const peernetHash = await new index.CodecHash(transaction, {name: 'transaction-message'});
601
+ return peernetHash.digest
602
+ }
603
+
604
+ /**
605
+ * @param {Transaction} transaction
606
+ * @param {object} wallet any wallet/signer that supports sign(RAWtransaction)
607
+ */
608
+ async #signTransaction (transaction, wallet) {
609
+ return wallet.sign(await this.createTransactionHash(transaction))
610
+ }
611
+
612
+ /**
613
+ *
614
+ * @param {RawTransaction} transaction
615
+ * @param {Signer} signer
616
+ * @returns {Transaction} a signed transaction
617
+ */
618
+ async signTransaction(transaction, signer) {
619
+ let identity = await walletStore.get('identity');
620
+ identity = JSON.parse(new TextDecoder().decode(identity));
621
+ const wallet = new MultiWallet__default["default"](peernet.network);
622
+ wallet.recover(identity.mnemonic);
623
+ const account = wallet.account(0).external(0);
624
+ transaction.signature = await this.#signTransaction(transaction, account);
625
+ transaction.signature = bs32__default["default"].encode(transaction.signature);
626
+ return transaction
627
+ }
628
+
629
+ /**
630
+ *
631
+ * @param {Transaction} transaction
632
+ * @param {Address} transaction.from
633
+ * @param {Address} transaction.to
634
+ * @param {String} transaction.method
635
+ * @param {Array} transaction.params
636
+ * @param {Number} transaction.nonce
637
+ *
638
+ * @returns {RawTransaction} transaction
639
+ */
640
+ async ensureNonce(transaction) {
641
+ if (!transaction.from) transaction.from = peernet.selectedAccount;
642
+ transaction.timestamp = Date.now();
643
+
644
+ if (transaction.nonce === undefined) {
645
+ transaction.nonce = await this.getNonce(transaction.from);
646
+ } else {
647
+ let nonce = await accountsStore.get(transaction.from);
648
+ nonce = new TextDecoder().decode(nonce);
649
+ if (transaction.nonce < nonce) throw new Error(`a transaction with a higher nonce already exists`)
650
+ if (transaction.nonce === nonce) throw new Error(`a transaction with the same nonce already exists`)
651
+ }
652
+ return transaction
653
+ }
654
+
655
+ /**
656
+ * every tx done is trough contracts so no need for amount
657
+ * data is undefined when nothing is returned
658
+ * error is thrown on error so undefined data doesn't mean there is an error...
659
+ *
660
+ * @param {Address} from - the sender address
661
+ * @param {Address} to - the contract address for the contract to interact with
662
+ * @param {String} method - the method/function to run
663
+ * @param {Array} params - array of paramters to apply to the contract method
664
+ * @param {Number} nonce - total transaction count [optional]
665
+ */
666
+ async createTransactionFrom(from, to, method, parameters, nonce) {
667
+ try {
668
+ const rawTransaction = await this.ensureNonce({from, to, nonce, method, params: parameters});
669
+ const transaction = await this.signTransaction(rawTransaction, from);
670
+ const message = await new TransactionMessage(transaction);
671
+
672
+ let data;
673
+ const wait = () => new Promise(async (resolve, reject) => {
674
+ if (pubsub.subscribers[`transaction.completed.${await message.hash}`]) {
675
+ const result = pubsub.subscribers[`transaction.completed.${await message.hash}`].value;
676
+ result.status === 'fulfilled' ? resolve(await result.hash) : reject({hash: await result.hash, error: result.error});
677
+ } else {
678
+ const completed = async result => {
679
+ result.status === 'fulfilled' ? resolve(await result.hash) : reject({hash: await result.hash, error: result.error});
680
+
681
+ setTimeout(async () => {
682
+ pubsub.unsubscribe(`transaction.completed.${await message.hash}`, completed);
683
+ }, 10_000);
684
+ };
685
+ pubsub.subscribe(`transaction.completed.${await message.hash}`, completed);
686
+ }
687
+ });
688
+ await transactionPoolStore.put(await message.hash, message.encoded);
689
+ peernet.publish('add-transaction', message.encoded);
690
+ return {hash: await message.hash, data, fee: await calculateFee(message.decoded), wait, message}
691
+ } catch (error) {
692
+ console.log(error);
693
+ throw error
694
+ }
695
+ }
696
+ }
697
+
698
+ /**
699
+ * @extends {Transaction}
700
+ */
701
+ class Contract extends Transaction {
702
+ constructor() {
703
+ super();
704
+ }
705
+
706
+ /**
707
+ *
708
+ * @param {Address} creator
709
+ * @param {String} contract
710
+ * @param {Array} constructorParameters
711
+ * @returns lib.createContractMessage
712
+ */
713
+ async createContractMessage(creator, contract, constructorParameters = []) {
714
+ return createContractMessage(creator, contract, constructorParameters)
715
+ }
716
+
717
+ /**
718
+ *
719
+ * @param {Address} creator
720
+ * @param {String} contract
721
+ * @param {Array} constructorParameters
722
+ * @returns {Address}
723
+ */
724
+ async createContractAddress(creator, contract, constructorParameters = []) {
725
+ contract = await this.createContractMessage(creator, contract, constructorParameters);
726
+ return contract.hash
727
+ }
728
+
729
+ /**
730
+ *
731
+ * @param {String} contract
732
+ * @param {Array} parameters
733
+ * @returns
734
+ */
735
+ async deployContract(contract, constructorParameters = []) {
736
+ const message = await createContractMessage(peernet.selectedAccount, contract, constructorParameters);
737
+ try {
738
+ await contractStore.put(await message.hash, message.encoded);
739
+ } catch (error) {
740
+ throw error
741
+ }
742
+ return this.createTransactionFrom(peernet.selectedAccount, addresses.contractFactory, 'registerContract', [await message.hash])
743
+ }
744
+
745
+ }
746
+
436
747
  globalThis.BigNumber = utils.BigNumber;
437
748
 
438
749
  // check if browser or local
439
- class Chain {
750
+ class Chain extends Contract {
751
+ /** {Address[]} */
440
752
  #validators = []
753
+ /** {Block[]} */
441
754
  #blocks = []
755
+
442
756
  #machine
757
+ /** {Boolean} */
443
758
  #runningEpoch = false
759
+
760
+ /** {Boolean} */
444
761
  #chainSyncing = false
762
+
763
+ /** {Number} */
764
+ #totalSize = 0
765
+
766
+ /**
767
+ * {Block} {index, hash, previousHash}
768
+ */
445
769
  #lastBlock = {index: 0, hash: '0x0', previousHash: '0x0'}
770
+
771
+ /**
772
+ * amount the native token has been iteracted with
773
+ */
774
+ #nativeCalls = 0
775
+
776
+ /**
777
+ * amount the native token has been iteracted with
778
+ */
779
+ #nativeTransfers = 0
780
+
781
+ /**
782
+ * amount of native token burned
783
+ * {Number}
784
+ */
785
+ #nativeBurns = 0
786
+
787
+ /**
788
+ * amount of native tokens minted
789
+ * {Number}
790
+ */
791
+ #nativeMints = 0
792
+
793
+ /**
794
+ * total amount of transactions
795
+ * {Number}
796
+ */
797
+ #totalTransactions = 0
798
+
446
799
  #participants = []
447
800
  #participating = false
448
801
  #jail = []
449
802
 
450
803
  constructor() {
804
+ super();
451
805
  return this.#init()
452
806
  }
453
807
 
808
+ get nativeMints() {
809
+ return this.#nativeMints
810
+ }
811
+
812
+ get nativeBurns() {
813
+ return this.#nativeBurns
814
+ }
815
+
816
+ get nativeTransfers() {
817
+ return this.#nativeTransfers
818
+ }
819
+
820
+ get totalTransactions() {
821
+ return this.#totalTransactions
822
+ }
823
+
824
+ get totalSize() {
825
+ return this.#totalSize
826
+ }
827
+
454
828
  get lib() {
455
829
  return lib
456
830
  }
@@ -460,7 +834,7 @@ class Chain {
460
834
  }
461
835
 
462
836
  get nativeToken() {
463
- return addresses.nativeToken
837
+ return addresses$1.nativeToken
464
838
  }
465
839
 
466
840
  get validators() {
@@ -480,10 +854,9 @@ class Chain {
480
854
  async #runEpoch() {
481
855
  this.#runningEpoch = true;
482
856
  console.log('epoch');
483
- const validators = await this.staticCall(addresses.validators, 'validators');
857
+ const validators = await this.staticCall(addresses$1.validators, 'validators');
484
858
  console.log(validators);
485
859
  if (!validators[peernet.selectedAccount]?.active) return
486
- debug(`validator ${peernet.selectedAccount} active`);
487
860
  const start = Date.now();
488
861
  try {
489
862
  await this.#createBlock();
@@ -502,16 +875,16 @@ class Chain {
502
875
  async #setup() {
503
876
 
504
877
  const contracts = [{
505
- address: addresses.contractFactory,
878
+ address: addresses$1.contractFactory,
506
879
  message: contractFactoryMessage
507
880
  }, {
508
- address: addresses.nativeToken,
881
+ address: addresses$1.nativeToken,
509
882
  message: nativeTokenMessage
510
883
  }, {
511
- address: addresses.validators,
884
+ address: addresses$1.validators,
512
885
  message: validatorsMessage
513
886
  }, {
514
- address: addresses.nameService,
887
+ address: addresses$1.nameService,
515
888
  message: nameServiceMessage
516
889
  }];
517
890
 
@@ -569,7 +942,7 @@ class Chain {
569
942
 
570
943
  if (latest.hash && latest.hash !== '0x0') {
571
944
  latest = await peernet.get(latest.hash, block);
572
- latest = await new BlockMessage(latest);
945
+ latest = await new BlockMessage$1(latest);
573
946
  }
574
947
 
575
948
  return latest
@@ -579,11 +952,13 @@ class Chain {
579
952
  // this.node = await new Node()
580
953
  this.#participants = [];
581
954
  this.#participating = false;
582
- const initialized = await contractStore.has(addresses.contractFactory);
955
+ const initialized = await contractStore.has(addresses$1.contractFactory);
583
956
  if (!initialized) await this.#setup();
584
957
 
585
958
 
586
959
  this.utils = { BigNumber: utils.BigNumber, formatUnits: utils.formatUnits, parseUnits: utils.parseUnits };
960
+
961
+ this.state = new State();
587
962
 
588
963
  try {
589
964
  let localBlock;
@@ -596,7 +971,7 @@ class Chain {
596
971
  localBlock = new TextDecoder().decode(localBlock);
597
972
  if (localBlock && localBlock !== '0x0') {
598
973
  localBlock = await peernet.get(localBlock, 'block');
599
- localBlock = await new BlockMessage(localBlock);
974
+ localBlock = await new BlockMessage$1(localBlock);
600
975
  this.#lastBlock = {...localBlock.decoded, hash: await localBlock.hash};
601
976
  } else {
602
977
  const latestBlock = await this.#getLatestBlock();
@@ -667,16 +1042,6 @@ class Chain {
667
1042
 
668
1043
  #epochTimeout
669
1044
 
670
- async #addTransaction(transaction) {
671
- try {
672
- transaction = await new TransactionMessage(transaction);
673
- const has = await transactionPoolStore.has(await transaction.hash);
674
- if (!has) await transactionPoolStore.put(await transaction.hash, transaction.encoded);
675
- if (this.#participating && !this.#runningEpoch) this.#runEpoch();
676
- } catch {
677
- throw new Error('invalid transaction')
678
- }
679
- }
680
1045
 
681
1046
  async #lastBlockHandler() {
682
1047
  return new peernet.protos['peernet-response']({response: { hash: this.#lastBlock?.hash, index: this.#lastBlock?.index }})
@@ -685,9 +1050,10 @@ async #lastBlockHandler() {
685
1050
  async resolveBlock(hash) {
686
1051
  if (!hash) throw new Error(`expected hash, got: ${hash}`)
687
1052
  let block = await peernet.get(hash, 'block');
688
- block = await new BlockMessage(block);
1053
+ block = await new BlockMessage$1(block);
689
1054
  if (!await peernet.has(hash, 'block')) await peernet.put(hash, block.encoded, 'block');
690
1055
  const size = block.encoded.length > 0 ? block.encoded.length : block.encoded.byteLength;
1056
+ this.#totalSize += size;
691
1057
  block = {...block.decoded, hash};
692
1058
  if (this.#blocks[block.index] && this.#blocks[block.index].hash !== block.hash) throw `invalid block ${hash} @${block.index}`
693
1059
  this.#blocks[block.index] = block;
@@ -713,51 +1079,40 @@ async resolveBlock(hash) {
713
1079
  }
714
1080
  }
715
1081
 
1082
+ /**
1083
+ *
1084
+ * @param {Block[]} blocks
1085
+ */
716
1086
  async #loadBlocks(blocks) {
717
1087
  for (const block of blocks) {
718
1088
  if (block && !block.loaded) {
719
1089
  for (const transaction of block.transactions) {
720
1090
  try {
721
1091
  await this.#machine.execute(transaction.to, transaction.method, transaction.params);
722
-
1092
+ if (transaction.to === nativeToken$1) {
1093
+ this.#nativeCalls += 1;
1094
+ if (transaction.method === 'burn') this.#nativeBurns += 1;
1095
+ if (transaction.method === 'mint') this.#nativeMints += 1;
1096
+ if (transaction.method === 'transfer') this.#nativeTransfers += 1;
1097
+ }
1098
+ this.#totalTransactions += 1;
723
1099
  } catch (error) {
724
1100
  console.log(error);
725
1101
  }
726
1102
  }
727
1103
  this.#blocks[block.index].loaded = true;
728
- console.log(`loaded block: ${block.hash} @${block.index}`);
729
- // let message = await peernet.get(block.hash, 'block')
730
-
731
- // const compressed = pako.deflate(message);
732
- // const result = pako.inflate(compressed);
733
- // console.log(result.length, compressed.length);
734
- //
735
- // console.log(result.length - compressed.length);
736
-
737
- // message = new BlockMessage(message)
738
- // for (const transaction of message.decoded.transactions) {
739
- // try {
740
- // await this.#machine.execute(transaction.to, transaction.method, transaction.params)
741
- //
742
- // } catch (e) {
743
- // // console.log(e);
744
- // }
745
- // }
746
- // block.loaded = true
1104
+ debug(`loaded block: ${block.hash} @${block.index}`);
747
1105
  }
748
1106
  }
749
1107
  }
750
1108
 
751
1109
  async #executeTransaction({hash, from, to, method, params, nonce}) {
752
- console.log(hash, from);
753
1110
  try {
754
1111
  let result = await this.#machine.execute(to, method, params, from, nonce);
755
1112
  // if (!result) result = this.#machine.state
756
- console.log({result});
757
1113
  pubsub.publish(`transaction.completed.${hash}`, {status: 'fulfilled', hash});
758
1114
  return result || 'no state change'
759
1115
  } catch (error) {
760
- console.log(error);
761
1116
  pubsub.publish(`transaction.completed.${hash}`, {status: 'fail', hash, error: error});
762
1117
  throw error
763
1118
  }
@@ -765,26 +1120,10 @@ async resolveBlock(hash) {
765
1120
 
766
1121
  async #addBlock(block) {
767
1122
  // console.log(block);
768
- const blockMessage = await new BlockMessage(new Uint8Array(Object.values(block)));
769
- // if (!Buffer.isBuffer(block)) block = Buffer.from(block, 'hex')
770
- // const transactionJob = async transaction => {
771
- // try {
772
- // transaction = await transactionPoolStore.get(transaction)
773
- // } catch (e) {
774
- // try {
775
- // transaction = await peernet.get(transaction, 'transaction')
776
- // } catch (e) {
777
- // console.warn(`couldn't resolve ${transaction}`);
778
- // }
779
- // }
780
- // transaction = new TransactionMessage(transaction)
781
- // return transaction
782
- // }
1123
+ const blockMessage = await new BlockMessage$1(new Uint8Array(Object.values(block)));
783
1124
  await Promise.all(blockMessage.decoded.transactions
784
1125
  .map(async transaction => transactionPoolStore.delete(await transaction.hash)));
785
1126
  const hash = await blockMessage.hash;
786
- // let transactions = blockMessage.decoded.transactions.map(tx => transactionJob(tx))
787
- // transactions = await Promise.all(transactions)
788
1127
 
789
1128
  await blockStore.put(hash, blockMessage.encoded);
790
1129
 
@@ -827,6 +1166,7 @@ async resolveBlock(hash) {
827
1166
  async #updateState(message) {
828
1167
  const hash = await message.hash;
829
1168
  this.#lastBlock = { hash, ...message.decoded };
1169
+ await this.state.updateState(message);
830
1170
  await chainStore.put('lastBlock', hash);
831
1171
  }
832
1172
 
@@ -840,14 +1180,8 @@ async resolveBlock(hash) {
840
1180
  // peerReputation(peerId)
841
1181
  // {bandwith: {up, down}, uptime}
842
1182
  this.#participating = true;
843
- if (!await this.staticCall(addresses.validators, 'has', [address])) await this.createTransactionFrom(address, addresses.validators, 'addValidator', [address]);
1183
+ if (!await this.staticCall(addresses$1.validators, 'has', [address])) await this.createTransactionFrom(address, addresses$1.validators, 'addValidator', [address]);
844
1184
  if (await this.hasTransactionToHandle() && !this.#runningEpoch) await this.#runEpoch();
845
-
846
- // const runEpoch = () => setTimeout(async () => {
847
- // if (await this.hasTransactionToHandle() && !this.#runningEpoch) await this.#runEpoch()
848
- // runEpoch()
849
- // }, 5000)
850
- // runEpoch()
851
1185
  }
852
1186
 
853
1187
  calculateFee(transaction) {
@@ -857,25 +1191,6 @@ async resolveBlock(hash) {
857
1191
  return (transaction.encoded.length / 1024) / 1e-6
858
1192
  }
859
1193
 
860
- async getTransactions (transactions) {
861
- return new Promise(async (resolve, reject) => {
862
- let size = 0;
863
- const _transactions = [];
864
-
865
-
866
- await Promise.all(transactions
867
- .map(async tx => {
868
- tx = await new TransactionMessage(tx);
869
- size += tx.encoded.length;
870
- if (!formatBytes(size).includes('MB') || formatBytes(size).includes('MB') && Number(formatBytes(size).split(' MB')[0]) <= 0.75) _transactions.push({...tx.decoded, hash: await tx.hash});
871
- else resolve(_transactions);
872
- }));
873
-
874
- return resolve(_transactions)
875
- })
876
-
877
- }
878
-
879
1194
  // todo filter tx that need to wait on prev nonce
880
1195
  async #createBlock(limit = 1800) {
881
1196
  // vote for transactions
@@ -893,7 +1208,7 @@ async resolveBlock(hash) {
893
1208
 
894
1209
  // exclude failing tx
895
1210
  transactions = await this.getTransactions(transactions.slice(0, transactions.length < 1800 ? transactions.length : 1800));
896
- console.log(transactions);
1211
+
897
1212
  transactions = transactions.sort((a, b) => a.nonce - b.nonce);
898
1213
  for (let transaction of transactions) {
899
1214
  try {
@@ -901,15 +1216,14 @@ console.log(transactions);
901
1216
  block.transactions.push(transaction);
902
1217
  block.fees += Number(calculateFee(transaction));
903
1218
  await accountsStore.put(transaction.from, new TextEncoder().encode(String(transaction.nonce)));
904
- } catch (error) {
905
- console.log(error);
1219
+ } catch {
906
1220
  transaction = await new TransactionMessage(transaction);
907
1221
  await transactionPoolStore.delete(await transaction.hash);
908
1222
  }
909
1223
  }
910
1224
  // don't add empty block
911
1225
  if (block.transactions.length === 0) return
912
- const validators = await this.staticCall(addresses.validators, 'validators');
1226
+ const validators = await this.staticCall(addresses$1.validators, 'validators');
913
1227
  console.log({validators});
914
1228
  // block.validators = Object.keys(block.validators).reduce((set, key) => {
915
1229
  // if (block.validators[key].active) {
@@ -984,7 +1298,7 @@ console.log(transactions);
984
1298
  .map(async transaction => transactionPoolStore.delete(await transaction.hash)));
985
1299
 
986
1300
 
987
- let blockMessage = await new BlockMessage(block);
1301
+ let blockMessage = await new BlockMessage$1(block);
988
1302
  const hash = await blockMessage.hash;
989
1303
 
990
1304
 
@@ -1002,58 +1316,18 @@ console.log(transactions);
1002
1316
  // transactionStore.put(message.hash, message.encoded)
1003
1317
  }
1004
1318
 
1005
- async promiseTransactions(transactions) {
1006
- transactions = await Promise.all(transactions.map(tx => new TransactionMessage(tx)));
1007
- return transactions
1008
- }
1009
-
1010
- async promiseTransactionsContent(transactions) {
1011
- transactions = await Promise.all(transactions.map(tx => new Promise(async (resolve, reject) => {
1012
- resolve({ ...tx.decoded, hash: await tx.hash });
1013
- })));
1014
-
1015
- return transactions
1016
- }
1017
-
1018
- async #getNonceFallback(address) {
1019
- let transactions = await transactionPoolStore.values();
1020
- transactions = await this.promiseTransactions(transactions);
1021
- transactions = transactions.filter(tx => tx.decoded.from === address);
1022
- transactions = await this.promiseTransactionsContent(transactions);
1023
-
1024
- if (this.lastBlock?.hash && transactions.length === 0 && this.lastBlock.hash !== '0x0') {
1025
-
1026
- let block = await peernet.get(this.lastBlock.hash);
1027
- block = await new BlockMessage(block);
1028
-
1029
- // for (let tx of block.decoded?.transactions) {
1030
- // tx = await peernet.get(tx, 'transaction')
1031
- // transactions.push(new TransactionMessage(tx))
1032
- // }
1033
- transactions = transactions.filter(tx => tx.from === address);
1034
- while (transactions.length === 0 && block.decoded.index !== 0 && block.decoded.previousHash !== '0x0') {
1035
- block = await blockStore.get(block.decoded.previousHash);
1036
- block = await new BlockMessage(block);
1037
- transactions = block.decoded.transactions.filter(tx => tx.from === address);
1038
- }
1039
-
1040
- }
1041
- if (transactions.length === 0) return 0
1042
-
1043
- transactions = transactions.sort((a, b) => a.timestamp - b.timestamp);
1044
- return transactions[transactions.length - 1].nonce
1045
- }
1319
+
1046
1320
 
1047
- async getNonce(address) {
1048
- if (!await accountsStore.has(address)) {
1049
- const nonce = await this.#getNonceFallback(address);
1050
- await accountsStore.put(address, new TextEncoder().encode(String(nonce)));
1321
+ async #addTransaction(transaction) {
1322
+ try {
1323
+ transaction = await new TransactionMessage(transaction);
1324
+ const has = await transactionPoolStore.has(await transaction.hash);
1325
+ if (!has) await transactionPoolStore.put(await transaction.hash, transaction.encoded);
1326
+ if (this.#participating && !this.#runningEpoch) this.#runEpoch();
1327
+ } catch {
1328
+ throw new Error('invalid transaction')
1051
1329
  }
1052
- let nonce = await accountsStore.get(address);
1053
- nonce = new TextDecoder().decode(nonce);
1054
- return Number(nonce)
1055
1330
  }
1056
-
1057
1331
  /**
1058
1332
  * whenever method = createContract params should hold the contract hash
1059
1333
  *
@@ -1065,72 +1339,9 @@ console.log(transactions);
1065
1339
  * @param {Array} params - array of paramters to apply to the contract method
1066
1340
  * @param {Number} nonce - total transaction count [optional]
1067
1341
  */
1068
- async createTransaction(to, method, parameters, nonce, signature) {
1342
+ async createTransaction(to, method, parameters, nonce, signature) {
1069
1343
  return this.createTransactionFrom(peernet.selectedAccount, to, method, parameters, nonce)
1070
- }
1071
-
1072
-
1073
-
1074
- /**
1075
- *
1076
- * @param {Transaction} transaction
1077
- * @param {String} transaction.from address
1078
- * @param {String} transaction.to address
1079
- * @param {Object} transaction.params {}
1080
- * @param {String} transaction.params.method get, call
1081
- * @param {Buffer} transaction.params.data
1082
- * @returns
1083
- */
1084
- async createTransactionHash(transaction) {
1085
- // todo: validate
1086
- const peernetHash = await new index.CodecHash(transaction, {name: 'transaction-message'});
1087
- return peernetHash.digest
1088
- }
1089
-
1090
- /**
1091
- * @param {Transaction} transaction
1092
- * @param {object} wallet any wallet/signer that supports sign(RAWtransaction)
1093
- */
1094
- async #signTransaction (transaction, wallet) {
1095
- return wallet.sign(await this.createTransactionHash(transaction))
1096
- }
1097
-
1098
- async signTransaction(transaction, signer) {
1099
- let identity = await walletStore.get('identity');
1100
- identity = JSON.parse(new TextDecoder().decode(identity));
1101
- const wallet = new MultiWallet__default["default"](peernet.network);
1102
- wallet.recover(identity.mnemonic);
1103
- const account = wallet.account(0).external(0);
1104
- transaction.signature = await this.#signTransaction(transaction, account);
1105
- transaction.signature = bs32__default["default"].encode(transaction.signature);
1106
- return transaction
1107
- }
1108
-
1109
- /**
1110
- *
1111
- * @param {Transaction} transaction
1112
- * @param {Address} transaction.from
1113
- * @param {Address} transaction.to
1114
- * @param {String} transaction.method
1115
- * @param {Array} transaction.params
1116
- * @param {Number} transaction.nonce
1117
- *
1118
- * @returns {RawTransaction} transaction
1119
- */
1120
- async createRawTransaction(transaction) {
1121
- if (!transaction.from) transaction.from = peernet.selectedAccount;
1122
- transaction.timestamp = Date.now();
1123
-
1124
- if (transaction.nonce === undefined) {
1125
- transaction.nonce = await this.getNonce(transaction.from);
1126
- } else {
1127
- let nonce = await accountsStore.get(transaction.from);
1128
- nonce = new TextDecoder().decode(nonce);
1129
- if (transaction.nonce < nonce) throw new Error(`a transaction with a higher nonce already exists`)
1130
- if (transaction.nonce === nonce) throw new Error(`a transaction with the same nonce already exists`)
1131
- }
1132
- return transaction
1133
- }
1344
+ }
1134
1345
  /**
1135
1346
  * every tx done is trough contracts so no need for amount
1136
1347
  * data is undefined when nothing is returned
@@ -1142,83 +1353,10 @@ async #signTransaction (transaction, wallet) {
1142
1353
  * @param {Array} params - array of paramters to apply to the contract method
1143
1354
  * @param {Number} nonce - total transaction count [optional]
1144
1355
  */
1145
- async createTransactionFrom(from, to, method, parameters, nonce) {
1146
-
1147
- try {
1148
-
1149
- const rawTransaction = await this.createRawTransaction({from, to, nonce, method, params: parameters});
1150
- const transaction = await this.signTransaction(rawTransaction, from);
1151
- const message = await new TransactionMessage(transaction);
1152
-
1153
- let data;
1154
- // await transactionPoolStore.put(message.hash, new TextEncoder().encode(JSON.stringify({signature, message: message.encoded})))
1155
- const wait = () => new Promise(async (resolve, reject) => {
1156
- if (pubsub.subscribers[`transaction.completed.${await message.hash}`]) {
1157
- const result = pubsub.subscribers[`transaction.completed.${await message.hash}`].value;
1158
- result.status === 'fulfilled' ? resolve(await result.hash) : reject({hash: await result.hash, error: result.error});
1159
- } else {
1160
- const completed = async result => {
1161
- result.status === 'fulfilled' ? resolve(await result.hash) : reject({hash: await result.hash, error: result.error});
1162
-
1163
- setTimeout(async () => {
1164
- pubsub.unsubscribe(`transaction.completed.${await message.hash}`, completed);
1165
- }, 10_000);
1166
- };
1167
- pubsub.subscribe(`transaction.completed.${await message.hash}`, completed);
1168
- }
1169
-
1170
-
1171
- });
1172
-
1173
- await transactionPoolStore.put(await message.hash, message.encoded);
1174
- peernet.publish('add-transaction', message.encoded);
1175
- this.#addTransaction(message.encoded);
1176
- debug('creating tx');
1177
- return {hash: await message.hash, data, fee: await calculateFee(message.decoded), wait}
1178
- } catch (error) {
1179
- console.log(error);
1180
- throw error
1181
- }
1182
-
1183
- }
1184
-
1185
- /**
1186
- *
1187
- * @param {Address} creator
1188
- * @param {String} contract
1189
- * @param {Array} constructorParameters
1190
- * @returns lib.createContractMessage
1191
- */
1192
- async createContractMessage(creator, contract, constructorParameters = []) {
1193
- return createContractMessage(creator, contract, constructorParameters)
1194
- }
1195
-
1196
- /**
1197
- *
1198
- * @param {Address} creator
1199
- * @param {String} contract
1200
- * @param {Array} constructorParameters
1201
- * @returns {Address}
1202
- */
1203
- async createContractAddress(creator, contract, constructorParameters = []) {
1204
- contract = await this.createContractMessage(creator, contract, constructorParameters);
1205
- return contract.hash
1206
- }
1207
-
1208
- /**
1209
- *
1210
- * @param {String} contract
1211
- * @param {Array} parameters
1212
- * @returns
1213
- */
1214
- async deployContract(contract, constructorParameters = []) {
1215
- const message = await createContractMessage(peernet.selectedAccount, contract, constructorParameters);
1216
- try {
1217
- await contractStore.put(await message.hash, message.encoded);
1218
- } catch (error) {
1219
- throw error
1220
- }
1221
- return this.createTransactionFrom(peernet.selectedAccount, addresses.contractFactory, 'registerContract', [await message.hash])
1356
+ async createTransactionFrom(from, to, method, parameters, nonce) {
1357
+ const event = await super.createTransactionFrom(from, to, method, parameters, nonce);
1358
+ this.#addTransaction(event.message.encoded);
1359
+ return event
1222
1360
  }
1223
1361
 
1224
1362
  /**
@@ -1281,19 +1419,19 @@ async #signTransaction (transaction, wallet) {
1281
1419
  }
1282
1420
 
1283
1421
  mint(to, amount) {
1284
- return this.call(addresses.nativeToken, 'mint', [to, amount])
1422
+ return this.call(addresses$1.nativeToken, 'mint', [to, amount])
1285
1423
  }
1286
1424
 
1287
1425
  transfer(from, to, amount) {
1288
- return this.call(addresses.nativeToken, 'transfer', [from, to, amount])
1426
+ return this.call(addresses$1.nativeToken, 'transfer', [from, to, amount])
1289
1427
  }
1290
1428
 
1291
1429
  get balances() {
1292
- return this.staticCall(addresses.nativeToken, 'balances')
1430
+ return this.staticCall(addresses$1.nativeToken, 'balances')
1293
1431
  }
1294
1432
 
1295
1433
  get contracts() {
1296
- return this.staticCall(addresses.contractFactory, 'contracts')
1434
+ return this.staticCall(addresses$1.contractFactory, 'contracts')
1297
1435
  }
1298
1436
 
1299
1437
  deleteAll() {
@@ -1310,7 +1448,7 @@ async #signTransaction (transaction, wallet) {
1310
1448
  * @example chain.lookup('myCoolContractName') // qmqsfddfdgfg...
1311
1449
  */
1312
1450
  lookup(name) {
1313
- return this.call(addresses.nameService, 'lookup', [name])
1451
+ return this.call(addresses$1.nameService, 'lookup', [name])
1314
1452
  }
1315
1453
  }
1316
1454